From f8975c7d21df0645adbd1736eab945d63b60ad3e Mon Sep 17 00:00:00 2001 From: Steve Hipwell Date: Fri, 26 Jun 2026 17:37:11 +0100 Subject: [PATCH 1/2] feat!: Replace actions env secret endpoints Signed-off-by: Steve Hipwell --- github/actions_secrets.go | 58 +++++++++++++-------------------- github/actions_secrets_test.go | 54 +++++++++++++++--------------- github/github-iterators.go | 4 +-- github/github-iterators_test.go | 8 ++--- 4 files changed, 56 insertions(+), 68 deletions(-) diff --git a/github/actions_secrets.go b/github/actions_secrets.go index f77b9e7428c..45589020f85 100644 --- a/github/actions_secrets.go +++ b/github/actions_secrets.go @@ -85,11 +85,11 @@ func (s *ActionsService) GetOrgPublicKey(ctx context.Context, org string) (*Publ // GetEnvPublicKey gets a public key that should be used for secret encryption. // -// GitHub API docs: https://docs.github.com/enterprise-server@3.7/rest/actions/secrets#get-an-environment-public-key +// GitHub API docs: https://docs.github.com/rest/actions/secrets?apiVersion=2022-11-28#get-an-environment-public-key // -//meta:operation GET /repositories/{repository_id}/environments/{environment_name}/secrets/public-key -func (s *ActionsService) GetEnvPublicKey(ctx context.Context, repoID int, env string) (*PublicKey, *Response, error) { - url := fmt.Sprintf("repositories/%v/environments/%v/secrets/public-key", repoID, env) +//meta:operation GET /repos/{owner}/{repo}/environments/{environment_name}/secrets/public-key +func (s *ActionsService) GetEnvPublicKey(ctx context.Context, owner, repo, env string) (*PublicKey, *Response, error) { + url := fmt.Sprintf("repos/%v/%v/environments/%v/secrets/public-key", owner, repo, env) return s.getPublicKey(ctx, url) } @@ -163,11 +163,11 @@ func (s *ActionsService) ListOrgSecrets(ctx context.Context, org string, opts *L // ListEnvSecrets lists all secrets available in an environment. // -// GitHub API docs: https://docs.github.com/enterprise-server@3.7/rest/actions/secrets#list-environment-secrets +// GitHub API docs: https://docs.github.com/rest/actions/secrets?apiVersion=2022-11-28#list-environment-secrets // -//meta:operation GET /repositories/{repository_id}/environments/{environment_name}/secrets -func (s *ActionsService) ListEnvSecrets(ctx context.Context, repoID int, env string, opts *ListOptions) (*Secrets, *Response, error) { - url := fmt.Sprintf("repositories/%v/environments/%v/secrets", repoID, env) +//meta:operation GET /repos/{owner}/{repo}/environments/{environment_name}/secrets +func (s *ActionsService) ListEnvSecrets(ctx context.Context, owner, repo, env string, opts *ListOptions) (*Secrets, *Response, error) { + url := fmt.Sprintf("repos/%v/%v/environments/%v/secrets", owner, repo, env) return s.listSecrets(ctx, url, opts) } @@ -208,11 +208,11 @@ func (s *ActionsService) GetOrgSecret(ctx context.Context, org, name string) (*S // GetEnvSecret gets a single environment secret without revealing its encrypted value. // -// GitHub API docs: https://docs.github.com/enterprise-server@3.7/rest/actions/secrets#get-an-environment-secret +// GitHub API docs: https://docs.github.com/rest/actions/secrets?apiVersion=2022-11-28#get-an-environment-secret // -//meta:operation GET /repositories/{repository_id}/environments/{environment_name}/secrets/{secret_name} -func (s *ActionsService) GetEnvSecret(ctx context.Context, repoID int, env, secretName string) (*Secret, *Response, error) { - url := fmt.Sprintf("repositories/%v/environments/%v/secrets/%v", repoID, env, secretName) +//meta:operation GET /repos/{owner}/{repo}/environments/{environment_name}/secrets/{secret_name} +func (s *ActionsService) GetEnvSecret(ctx context.Context, owner, repo, env, secretName string) (*Secret, *Response, error) { + url := fmt.Sprintf("repos/%v/%v/environments/%v/secrets/%v", owner, repo, env, secretName) return s.getSecret(ctx, url) } @@ -232,7 +232,7 @@ type EncryptedSecret struct { SelectedRepositoryIDs SelectedRepoIDs `json:"selected_repository_ids,omitempty"` } -func (s *ActionsService) putSecret(ctx context.Context, url string, body *EncryptedSecret) (*Response, error) { +func (s *ActionsService) putSecret(ctx context.Context, url string, body EncryptedSecret) (*Response, error) { req, err := s.client.NewRequest(ctx, "PUT", url, body) if err != nil { return nil, err @@ -246,11 +246,7 @@ func (s *ActionsService) putSecret(ctx context.Context, url string, body *Encryp // GitHub API docs: https://docs.github.com/rest/actions/secrets?apiVersion=2022-11-28#create-or-update-a-repository-secret // //meta:operation PUT /repos/{owner}/{repo}/actions/secrets/{secret_name} -func (s *ActionsService) CreateOrUpdateRepoSecret(ctx context.Context, owner, repo string, body *EncryptedSecret) (*Response, error) { - if body == nil { - return nil, errors.New("encrypted secret must be provided") - } - +func (s *ActionsService) CreateOrUpdateRepoSecret(ctx context.Context, owner, repo string, body EncryptedSecret) (*Response, error) { url := fmt.Sprintf("repos/%v/%v/actions/secrets/%v", owner, repo, body.Name) return s.putSecret(ctx, url, body) } @@ -260,26 +256,18 @@ func (s *ActionsService) CreateOrUpdateRepoSecret(ctx context.Context, owner, re // GitHub API docs: https://docs.github.com/rest/actions/secrets?apiVersion=2022-11-28#create-or-update-an-organization-secret // //meta:operation PUT /orgs/{org}/actions/secrets/{secret_name} -func (s *ActionsService) CreateOrUpdateOrgSecret(ctx context.Context, org string, body *EncryptedSecret) (*Response, error) { - if body == nil { - return nil, errors.New("encrypted secret must be provided") - } - +func (s *ActionsService) CreateOrUpdateOrgSecret(ctx context.Context, org string, body EncryptedSecret) (*Response, error) { url := fmt.Sprintf("orgs/%v/actions/secrets/%v", org, body.Name) return s.putSecret(ctx, url, body) } // CreateOrUpdateEnvSecret creates or updates a single environment secret with an encrypted value. // -// GitHub API docs: https://docs.github.com/enterprise-server@3.7/rest/actions/secrets#create-or-update-an-environment-secret +// GitHub API docs: https://docs.github.com/rest/actions/secrets?apiVersion=2022-11-28#create-or-update-an-environment-secret // -//meta:operation PUT /repositories/{repository_id}/environments/{environment_name}/secrets/{secret_name} -func (s *ActionsService) CreateOrUpdateEnvSecret(ctx context.Context, repoID int, env string, body *EncryptedSecret) (*Response, error) { - if body == nil { - return nil, errors.New("encrypted secret must be provided") - } - - url := fmt.Sprintf("repositories/%v/environments/%v/secrets/%v", repoID, env, body.Name) +//meta:operation PUT /repos/{owner}/{repo}/environments/{environment_name}/secrets/{secret_name} +func (s *ActionsService) CreateOrUpdateEnvSecret(ctx context.Context, owner, repo, env string, body EncryptedSecret) (*Response, error) { + url := fmt.Sprintf("repos/%v/%v/environments/%v/secrets/%v", owner, repo, env, body.Name) return s.putSecret(ctx, url, body) } @@ -314,11 +302,11 @@ func (s *ActionsService) DeleteOrgSecret(ctx context.Context, org, name string) // DeleteEnvSecret deletes a secret in an environment using the secret name. // -// GitHub API docs: https://docs.github.com/enterprise-server@3.7/rest/actions/secrets#delete-an-environment-secret +// GitHub API docs: https://docs.github.com/rest/actions/secrets?apiVersion=2022-11-28#delete-an-environment-secret // -//meta:operation DELETE /repositories/{repository_id}/environments/{environment_name}/secrets/{secret_name} -func (s *ActionsService) DeleteEnvSecret(ctx context.Context, repoID int, env, secretName string) (*Response, error) { - url := fmt.Sprintf("repositories/%v/environments/%v/secrets/%v", repoID, env, secretName) +//meta:operation DELETE /repos/{owner}/{repo}/environments/{environment_name}/secrets/{secret_name} +func (s *ActionsService) DeleteEnvSecret(ctx context.Context, owner, repo, env, secretName string) (*Response, error) { + url := fmt.Sprintf("repos/%v/%v/environments/%v/secrets/%v", owner, repo, env, secretName) return s.deleteSecret(ctx, url) } diff --git a/github/actions_secrets_test.go b/github/actions_secrets_test.go index 776e1b301fb..82b08077285 100644 --- a/github/actions_secrets_test.go +++ b/github/actions_secrets_test.go @@ -290,7 +290,7 @@ func TestActionsService_CreateOrUpdateRepoSecret(t *testing.T) { t.Parallel() client, mux, _ := setup(t) - input := &EncryptedSecret{ + input := EncryptedSecret{ Name: "NAME", EncryptedValue: "QIv=", KeyID: "1234", @@ -315,7 +315,7 @@ func TestActionsService_CreateOrUpdateRepoSecret(t *testing.T) { const methodName = "CreateOrUpdateRepoSecret" testBadOptions(t, methodName, func() (err error) { - _, err = client.Actions.CreateOrUpdateRepoSecret(ctx, "o", "r", nil) + _, err = client.Actions.CreateOrUpdateRepoSecret(ctx, "o", "r", EncryptedSecret{}) return err }) testBadOptions(t, methodName, func() (err error) { @@ -477,7 +477,7 @@ func TestActionsService_CreateOrUpdateOrgSecret(t *testing.T) { t.Parallel() client, mux, _ := setup(t) - input := &EncryptedSecret{ + input := EncryptedSecret{ Name: "NAME", EncryptedValue: "QIv=", KeyID: "1234", @@ -506,7 +506,7 @@ func TestActionsService_CreateOrUpdateOrgSecret(t *testing.T) { const methodName = "CreateOrUpdateOrgSecret" testBadOptions(t, methodName, func() (err error) { - _, err = client.Actions.CreateOrUpdateOrgSecret(ctx, "o", nil) + _, err = client.Actions.CreateOrUpdateOrgSecret(ctx, "o", EncryptedSecret{}) return err }) testBadOptions(t, methodName, func() (err error) { @@ -682,13 +682,13 @@ func TestActionsService_GetEnvPublicKey(t *testing.T) { t.Parallel() client, mux, _ := setup(t) - mux.HandleFunc("/repositories/1/environments/e/secrets/public-key", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/repos/o/r/environments/e/secrets/public-key", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") fmt.Fprint(w, `{"key_id":"1234","key":"2Sg8iYjAxxmI2LvUXpJjkYrMxURPc8r+dB7TJyvv1234"}`) }) ctx := t.Context() - key, _, err := client.Actions.GetEnvPublicKey(ctx, 1, "e") + key, _, err := client.Actions.GetEnvPublicKey(ctx, "o", "r", "e") if err != nil { t.Errorf("Actions.GetEnvPublicKey returned error: %v", err) } @@ -700,12 +700,12 @@ func TestActionsService_GetEnvPublicKey(t *testing.T) { const methodName = "GetEnvPublicKey" testBadOptions(t, methodName, func() (err error) { - _, _, err = client.Actions.GetEnvPublicKey(ctx, 0.0, "\n") + _, _, err = client.Actions.GetEnvPublicKey(ctx, "\n", "\n", "\n") return err }) testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { - got, resp, err := client.Actions.GetEnvPublicKey(ctx, 1, "e") + got, resp, err := client.Actions.GetEnvPublicKey(ctx, "o", "r", "e") if got != nil { t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) } @@ -723,7 +723,7 @@ func TestActionsService_GetEnvPublicKeyNumeric(t *testing.T) { }) ctx := t.Context() - key, _, err := client.Actions.GetEnvPublicKey(ctx, 1, "e") + key, _, err := client.Actions.GetEnvPublicKey(ctx, "o", "r", "e") if err != nil { t.Errorf("Actions.GetEnvPublicKey returned error: %v", err) } @@ -735,12 +735,12 @@ func TestActionsService_GetEnvPublicKeyNumeric(t *testing.T) { const methodName = "GetEnvPublicKey" testBadOptions(t, methodName, func() (err error) { - _, _, err = client.Actions.GetEnvPublicKey(ctx, 0.0, "\n") + _, _, err = client.Actions.GetEnvPublicKey(ctx, "\n", "\n", "\n") return err }) testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { - got, resp, err := client.Actions.GetEnvPublicKey(ctx, 1, "e") + got, resp, err := client.Actions.GetEnvPublicKey(ctx, "o", "r", "e") if got != nil { t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) } @@ -752,7 +752,7 @@ func TestActionsService_ListEnvSecrets(t *testing.T) { t.Parallel() client, mux, _ := setup(t) - mux.HandleFunc("/repositories/1/environments/e/secrets", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/repos/o/r/environments/e/secrets", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") testFormValues(t, r, values{"per_page": "2", "page": "2"}) fmt.Fprint(w, `{"total_count":4,"secrets":[{"name":"A","created_at":`+refTimeStr(1136178000)+`,"updated_at":`+refTimeStr(1136178001)+`},{"name":"B","created_at":`+refTimeStr(1136178002)+`,"updated_at":`+refTimeStr(1136178003)+`}]}`) @@ -760,7 +760,7 @@ func TestActionsService_ListEnvSecrets(t *testing.T) { opts := &ListOptions{Page: 2, PerPage: 2} ctx := t.Context() - secrets, _, err := client.Actions.ListEnvSecrets(ctx, 1, "e", opts) + secrets, _, err := client.Actions.ListEnvSecrets(ctx, "o", "r", "e", opts) if err != nil { t.Errorf("Actions.ListEnvSecrets returned error: %v", err) } @@ -778,12 +778,12 @@ func TestActionsService_ListEnvSecrets(t *testing.T) { const methodName = "ListEnvSecrets" testBadOptions(t, methodName, func() (err error) { - _, _, err = client.Actions.ListEnvSecrets(ctx, 0.0, "\n", opts) + _, _, err = client.Actions.ListEnvSecrets(ctx, "\n", "\n", "\n", opts) return err }) testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { - got, resp, err := client.Actions.ListEnvSecrets(ctx, 1, "e", opts) + got, resp, err := client.Actions.ListEnvSecrets(ctx, "o", "r", "e", opts) if got != nil { t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) } @@ -795,13 +795,13 @@ func TestActionsService_GetEnvSecret(t *testing.T) { t.Parallel() client, mux, _ := setup(t) - mux.HandleFunc("/repositories/1/environments/e/secrets/secret", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/repos/o/r/environments/e/secrets/secret", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") fmt.Fprint(w, `{"name":"secret","created_at":`+refTimeStr(1136178000)+`,"updated_at":`+refTimeStr(1136178001)+`}`) }) ctx := t.Context() - secret, _, err := client.Actions.GetEnvSecret(ctx, 1, "e", "secret") + secret, _, err := client.Actions.GetEnvSecret(ctx, "o", "r", "e", "secret") if err != nil { t.Errorf("Actions.GetEnvSecret returned error: %v", err) } @@ -817,12 +817,12 @@ func TestActionsService_GetEnvSecret(t *testing.T) { const methodName = "GetEnvSecret" testBadOptions(t, methodName, func() (err error) { - _, _, err = client.Actions.GetEnvSecret(ctx, 0.0, "\n", "\n") + _, _, err = client.Actions.GetEnvSecret(ctx, "\n", "\n", "\n", "\n") return err }) testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { - got, resp, err := client.Actions.GetEnvSecret(ctx, 1, "e", "secret") + got, resp, err := client.Actions.GetEnvSecret(ctx, "o", "r", "e", "secret") if got != nil { t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) } @@ -834,7 +834,7 @@ func TestActionsService_CreateOrUpdateEnvSecret(t *testing.T) { t.Parallel() client, mux, _ := setup(t) - input := &EncryptedSecret{ + input := EncryptedSecret{ Name: "secret", EncryptedValue: "QIv=", KeyID: "1234", @@ -852,23 +852,23 @@ func TestActionsService_CreateOrUpdateEnvSecret(t *testing.T) { }) ctx := t.Context() - _, err := client.Actions.CreateOrUpdateEnvSecret(ctx, 1, "e", input) + _, err := client.Actions.CreateOrUpdateEnvSecret(ctx, "o", "r", "e", input) if err != nil { t.Errorf("Actions.CreateOrUpdateEnvSecret returned error: %v", err) } const methodName = "CreateOrUpdateEnvSecret" testBadOptions(t, methodName, func() (err error) { - _, err = client.Actions.CreateOrUpdateEnvSecret(ctx, 1, "e", nil) + _, err = client.Actions.CreateOrUpdateEnvSecret(ctx, "\n", "\n", "\n", EncryptedSecret{}) return err }) testBadOptions(t, methodName, func() (err error) { - _, err = client.Actions.CreateOrUpdateEnvSecret(ctx, 0.0, "\n", input) + _, err = client.Actions.CreateOrUpdateEnvSecret(ctx, "\n", "\n", "\n", input) return err }) testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { - return client.Actions.CreateOrUpdateEnvSecret(ctx, 1, "e", input) + return client.Actions.CreateOrUpdateEnvSecret(ctx, "\n", "\n", "\n", input) }) } @@ -881,18 +881,18 @@ func TestActionsService_DeleteEnvSecret(t *testing.T) { }) ctx := t.Context() - _, err := client.Actions.DeleteEnvSecret(ctx, 1, "e", "secret") + _, err := client.Actions.DeleteEnvSecret(ctx, "o", "r", "e", "secret") if err != nil { t.Errorf("Actions.DeleteEnvSecret returned error: %v", err) } const methodName = "DeleteEnvSecret" testBadOptions(t, methodName, func() (err error) { - _, err = client.Actions.DeleteEnvSecret(ctx, 0.0, "\n", "\n") + _, err = client.Actions.DeleteEnvSecret(ctx, "\n", "\n", "\n", "\n") return err }) testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { - return client.Actions.DeleteEnvSecret(ctx, 1, "r", "secret") + return client.Actions.DeleteEnvSecret(ctx, "\n", "\n", "\n", "\n") }) } diff --git a/github/github-iterators.go b/github/github-iterators.go index db1316dab38..f31bb78572e 100644 --- a/github/github-iterators.go +++ b/github/github-iterators.go @@ -190,7 +190,7 @@ func (s *ActionsService) ListEnabledReposInOrgIter(ctx context.Context, owner st } // ListEnvSecretsIter returns an iterator that paginates through all results of ListEnvSecrets. -func (s *ActionsService) ListEnvSecretsIter(ctx context.Context, repoID int, env string, opts *ListOptions) iter.Seq2[*Secret, error] { +func (s *ActionsService) ListEnvSecretsIter(ctx context.Context, owner, repo, env string, opts *ListOptions) iter.Seq2[*Secret, error] { return func(yield func(*Secret, error) bool) { // Create a copy of opts to avoid mutating the caller's struct if opts == nil { @@ -200,7 +200,7 @@ func (s *ActionsService) ListEnvSecretsIter(ctx context.Context, repoID int, env } for { - results, resp, err := s.ListEnvSecrets(ctx, repoID, env, opts) + results, resp, err := s.ListEnvSecrets(ctx, owner, repo, env, opts) if err != nil { yield(nil, err) return diff --git a/github/github-iterators_test.go b/github/github-iterators_test.go index 634bc4618c4..64ec0d1b42b 100644 --- a/github/github-iterators_test.go +++ b/github/github-iterators_test.go @@ -396,7 +396,7 @@ func TestActionsService_ListEnvSecretsIter(t *testing.T) { } }) - iter := client.Actions.ListEnvSecretsIter(t.Context(), 0, "", nil) + iter := client.Actions.ListEnvSecretsIter(t.Context(), "\n", "\n", "\n", nil) var gotItems int for _, err := range iter { gotItems++ @@ -409,7 +409,7 @@ func TestActionsService_ListEnvSecretsIter(t *testing.T) { } opts := &ListOptions{} - iter = client.Actions.ListEnvSecretsIter(t.Context(), 0, "", opts) + iter = client.Actions.ListEnvSecretsIter(t.Context(), "\n", "\n", "\n", opts) gotItems = 0 for _, err := range iter { gotItems++ @@ -421,7 +421,7 @@ func TestActionsService_ListEnvSecretsIter(t *testing.T) { t.Errorf("client.Actions.ListEnvSecretsIter call 2 got %v items; want %v", gotItems, want) } - iter = client.Actions.ListEnvSecretsIter(t.Context(), 0, "", nil) + iter = client.Actions.ListEnvSecretsIter(t.Context(), "\n", "\n", "\n", nil) gotItems = 0 for _, err := range iter { gotItems++ @@ -433,7 +433,7 @@ func TestActionsService_ListEnvSecretsIter(t *testing.T) { t.Errorf("client.Actions.ListEnvSecretsIter call 3 got %v items; want 1 (an error)", gotItems) } - iter = client.Actions.ListEnvSecretsIter(t.Context(), 0, "", nil) + iter = client.Actions.ListEnvSecretsIter(t.Context(), "\n", "\n", "\n", nil) gotItems = 0 iter(func(item *Secret, err error) bool { gotItems++ From 871ea922c4cea8dab19ed0752a6d0607fa655565 Mon Sep 17 00:00:00 2001 From: Steve Hipwell Date: Fri, 26 Jun 2026 17:44:58 +0100 Subject: [PATCH 2/2] fixup! feat!: Replace actions env secret endpoints --- example/newreposecretwithxcrypto/main.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/example/newreposecretwithxcrypto/main.go b/example/newreposecretwithxcrypto/main.go index bfcef72d6e8..6fc32ea4fa0 100644 --- a/example/newreposecretwithxcrypto/main.go +++ b/example/newreposecretwithxcrypto/main.go @@ -143,21 +143,21 @@ func addRepoSecret(ctx context.Context, client *github.Client, owner, repo, secr return nil } -func encryptSecretWithPublicKey(publicKey *github.PublicKey, secretName, secretValue string) (*github.EncryptedSecret, error) { +func encryptSecretWithPublicKey(publicKey *github.PublicKey, secretName, secretValue string) (github.EncryptedSecret, error) { decodedPublicKey, err := base64.StdEncoding.DecodeString(publicKey.GetKey()) if err != nil { - return nil, fmt.Errorf("base64.StdEncoding.DecodeString was unable to decode public key: %v", err) + return github.EncryptedSecret{}, fmt.Errorf("base64.StdEncoding.DecodeString was unable to decode public key: %v", err) } boxKey := [32]byte(decodedPublicKey) encryptedBytes, err := box.SealAnonymous([]byte{}, []byte(secretValue), &boxKey, crypto_rand.Reader) if err != nil { - return nil, fmt.Errorf("box.SealAnonymous failed with error %w", err) + return github.EncryptedSecret{}, fmt.Errorf("box.SealAnonymous failed with error %w", err) } encryptedString := base64.StdEncoding.EncodeToString(encryptedBytes) keyID := publicKey.GetKeyID() - encryptedSecret := &github.EncryptedSecret{ + encryptedSecret := github.EncryptedSecret{ Name: secretName, KeyID: keyID, EncryptedValue: encryptedString,