From f8975c7d21df0645adbd1736eab945d63b60ad3e Mon Sep 17 00:00:00 2001 From: Steve Hipwell Date: Fri, 26 Jun 2026 17:37:11 +0100 Subject: [PATCH 1/6] 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/6] 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, From 44f57f842a0502fac99b36265b653826ee1a3251 Mon Sep 17 00:00:00 2001 From: Steve Hipwell Date: Mon, 29 Jun 2026 09:45:29 +0100 Subject: [PATCH 3/6] fixup! feat!: Replace actions env secret endpoints --- example/newreposecretwithxcrypto/main.go | 24 ++++++++---------------- github/actions_secrets_test.go | 6 +++--- github/github-iterators.go | 2 +- github/github-iterators_test.go | 8 ++++---- 4 files changed, 16 insertions(+), 24 deletions(-) diff --git a/example/newreposecretwithxcrypto/main.go b/example/newreposecretwithxcrypto/main.go index 6fc32ea4fa0..7258079d201 100644 --- a/example/newreposecretwithxcrypto/main.go +++ b/example/newreposecretwithxcrypto/main.go @@ -131,28 +131,15 @@ func addRepoSecret(ctx context.Context, client *github.Client, owner, repo, secr return err } - encryptedSecret, err := encryptSecretWithPublicKey(publicKey, secretName, secretValue) - if err != nil { - return err - } - - if _, err := client.Actions.CreateOrUpdateRepoSecret(ctx, owner, repo, encryptedSecret); err != nil { - return fmt.Errorf("client.Actions.CreateOrUpdateRepoSecret returned error: %v", err) - } - - return nil -} - -func encryptSecretWithPublicKey(publicKey *github.PublicKey, secretName, secretValue string) (github.EncryptedSecret, error) { decodedPublicKey, err := base64.StdEncoding.DecodeString(publicKey.GetKey()) if err != nil { - return github.EncryptedSecret{}, fmt.Errorf("base64.StdEncoding.DecodeString was unable to decode public key: %v", err) + return 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 github.EncryptedSecret{}, fmt.Errorf("box.SealAnonymous failed with error %w", err) + return fmt.Errorf("box.SealAnonymous failed with error %w", err) } encryptedString := base64.StdEncoding.EncodeToString(encryptedBytes) @@ -162,5 +149,10 @@ func encryptSecretWithPublicKey(publicKey *github.PublicKey, secretName, secretV KeyID: keyID, EncryptedValue: encryptedString, } - return encryptedSecret, nil + + if _, err := client.Actions.CreateOrUpdateRepoSecret(ctx, owner, repo, encryptedSecret); err != nil { + return fmt.Errorf("client.Actions.CreateOrUpdateRepoSecret returned error: %v", err) + } + + return nil } diff --git a/github/actions_secrets_test.go b/github/actions_secrets_test.go index 82b08077285..350e7aba1e6 100644 --- a/github/actions_secrets_test.go +++ b/github/actions_secrets_test.go @@ -717,7 +717,7 @@ func TestActionsService_GetEnvPublicKeyNumeric(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"}`) }) @@ -840,7 +840,7 @@ func TestActionsService_CreateOrUpdateEnvSecret(t *testing.T) { KeyID: "1234", } - 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, "PUT") testHeader(t, r, "Content-Type", "application/json") want := EncryptedSecret{ @@ -876,7 +876,7 @@ func TestActionsService_DeleteEnvSecret(t *testing.T) { t.Parallel() client, mux, _ := setup(t) - mux.HandleFunc("/repositories/1/environments/e/secrets/secret", func(_ http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/repos/o/r/environments/e/secrets/secret", func(_ http.ResponseWriter, r *http.Request) { testMethod(t, r, "DELETE") }) diff --git a/github/github-iterators.go b/github/github-iterators.go index f31bb78572e..dc2841ba541 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, owner, repo, env string, opts *ListOptions) iter.Seq2[*Secret, error] { +func (s *ActionsService) ListEnvSecretsIter(ctx context.Context, owner string, repo string, 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 { diff --git a/github/github-iterators_test.go b/github/github-iterators_test.go index 64ec0d1b42b..233c57b6c1a 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(), "\n", "\n", "\n", nil) + iter := client.Actions.ListEnvSecretsIter(t.Context(), "", "", "", 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(), "\n", "\n", "\n", opts) + iter = client.Actions.ListEnvSecretsIter(t.Context(), "", "", "", 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(), "\n", "\n", "\n", nil) + iter = client.Actions.ListEnvSecretsIter(t.Context(), "", "", "", 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(), "\n", "\n", "\n", nil) + iter = client.Actions.ListEnvSecretsIter(t.Context(), "", "", "", nil) gotItems = 0 iter(func(item *Secret, err error) bool { gotItems++ From 2c8137a106737f58c5a6301d3753ff15150690c7 Mon Sep 17 00:00:00 2001 From: Steve Hipwell Date: Mon, 29 Jun 2026 12:33:54 +0100 Subject: [PATCH 4/6] fixup! feat!: Replace actions env secret endpoints --- github/actions_secrets.go | 12 ++++++++++++ github/actions_secrets_test.go | 6 +++--- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/github/actions_secrets.go b/github/actions_secrets.go index 45589020f85..40701ead4e4 100644 --- a/github/actions_secrets.go +++ b/github/actions_secrets.go @@ -247,6 +247,10 @@ func (s *ActionsService) putSecret(ctx context.Context, url string, body Encrypt // //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.Name == "" { + return nil, errors.New("secret name must be provided") + } + url := fmt.Sprintf("repos/%v/%v/actions/secrets/%v", owner, repo, body.Name) return s.putSecret(ctx, url, body) } @@ -257,6 +261,10 @@ func (s *ActionsService) CreateOrUpdateRepoSecret(ctx context.Context, owner, re // //meta:operation PUT /orgs/{org}/actions/secrets/{secret_name} func (s *ActionsService) CreateOrUpdateOrgSecret(ctx context.Context, org string, body EncryptedSecret) (*Response, error) { + if body.Name == "" { + return nil, errors.New("secret name must be provided") + } + url := fmt.Sprintf("orgs/%v/actions/secrets/%v", org, body.Name) return s.putSecret(ctx, url, body) } @@ -267,6 +275,10 @@ func (s *ActionsService) CreateOrUpdateOrgSecret(ctx context.Context, org string // //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) { + if body.Name == "" { + return nil, errors.New("secret name must be provided") + } + url := fmt.Sprintf("repos/%v/%v/environments/%v/secrets/%v", owner, repo, env, body.Name) return s.putSecret(ctx, url, body) } diff --git a/github/actions_secrets_test.go b/github/actions_secrets_test.go index 350e7aba1e6..1fb81c0b728 100644 --- a/github/actions_secrets_test.go +++ b/github/actions_secrets_test.go @@ -859,7 +859,7 @@ func TestActionsService_CreateOrUpdateEnvSecret(t *testing.T) { const methodName = "CreateOrUpdateEnvSecret" testBadOptions(t, methodName, func() (err error) { - _, err = client.Actions.CreateOrUpdateEnvSecret(ctx, "\n", "\n", "\n", EncryptedSecret{}) + _, err = client.Actions.CreateOrUpdateEnvSecret(ctx, "o", "r", "e", EncryptedSecret{}) return err }) testBadOptions(t, methodName, func() (err error) { @@ -868,7 +868,7 @@ func TestActionsService_CreateOrUpdateEnvSecret(t *testing.T) { }) testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { - return client.Actions.CreateOrUpdateEnvSecret(ctx, "\n", "\n", "\n", input) + return client.Actions.CreateOrUpdateEnvSecret(ctx, "o", "r", "e", input) }) } @@ -893,6 +893,6 @@ func TestActionsService_DeleteEnvSecret(t *testing.T) { }) testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { - return client.Actions.DeleteEnvSecret(ctx, "\n", "\n", "\n", "\n") + return client.Actions.DeleteEnvSecret(ctx, "o", "r", "e", "secret") }) } From 2401f38b84b7337810fbaef4a04f0fffce34c521 Mon Sep 17 00:00:00 2001 From: Steve Hipwell Date: Mon, 29 Jun 2026 22:17:31 +0100 Subject: [PATCH 5/6] fixup! feat!: Replace actions env secret endpoints --- github/actions_secrets.go | 293 ++++++++++++++++++++------------ github/actions_secrets_test.go | 85 ++++----- github/github-accessors.go | 48 ++++++ github/github-accessors_test.go | 51 ++++++ 4 files changed, 317 insertions(+), 160 deletions(-) diff --git a/github/actions_secrets.go b/github/actions_secrets.go index 40701ead4e4..52ff020890d 100644 --- a/github/actions_secrets.go +++ b/github/actions_secrets.go @@ -8,7 +8,6 @@ package github import ( "context" "encoding/json" - "errors" "fmt" "strconv" ) @@ -108,8 +107,15 @@ type Secrets struct { Secrets []*Secret `json:"secrets"` } -func (s *ActionsService) listSecrets(ctx context.Context, url string, opts *ListOptions) (*Secrets, *Response, error) { - u, err := addOptions(url, opts) +// ListRepoSecrets lists all secrets available in a repository +// without revealing their encrypted values. +// +// GitHub API docs: https://docs.github.com/rest/actions/secrets?apiVersion=2022-11-28#list-repository-secrets +// +//meta:operation GET /repos/{owner}/{repo}/actions/secrets +func (s *ActionsService) ListRepoSecrets(ctx context.Context, owner, repo string, opts *ListOptions) (*Secrets, *Response, error) { + u := fmt.Sprintf("repos/%v/%v/actions/secrets", owner, repo) + u, err := addOptions(u, opts) if err != nil { return nil, nil, err } @@ -128,17 +134,6 @@ func (s *ActionsService) listSecrets(ctx context.Context, url string, opts *List return secrets, resp, nil } -// ListRepoSecrets lists all secrets available in a repository -// without revealing their encrypted values. -// -// GitHub API docs: https://docs.github.com/rest/actions/secrets?apiVersion=2022-11-28#list-repository-secrets -// -//meta:operation GET /repos/{owner}/{repo}/actions/secrets -func (s *ActionsService) ListRepoSecrets(ctx context.Context, owner, repo string, opts *ListOptions) (*Secrets, *Response, error) { - url := fmt.Sprintf("repos/%v/%v/actions/secrets", owner, repo) - return s.listSecrets(ctx, url, opts) -} - // ListRepoOrgSecrets lists all organization secrets available in a repository // without revealing their encrypted values. // @@ -146,8 +141,24 @@ func (s *ActionsService) ListRepoSecrets(ctx context.Context, owner, repo string // //meta:operation GET /repos/{owner}/{repo}/actions/organization-secrets func (s *ActionsService) ListRepoOrgSecrets(ctx context.Context, owner, repo string, opts *ListOptions) (*Secrets, *Response, error) { - url := fmt.Sprintf("repos/%v/%v/actions/organization-secrets", owner, repo) - return s.listSecrets(ctx, url, opts) + u := fmt.Sprintf("repos/%v/%v/actions/organization-secrets", owner, repo) + u, err := addOptions(u, opts) + if err != nil { + return nil, nil, err + } + + req, err := s.client.NewRequest(ctx, "GET", u, nil) + if err != nil { + return nil, nil, err + } + + var secrets *Secrets + resp, err := s.client.Do(req, &secrets) + if err != nil { + return nil, resp, err + } + + return secrets, resp, nil } // ListOrgSecrets lists all secrets available in an organization @@ -157,8 +168,24 @@ func (s *ActionsService) ListRepoOrgSecrets(ctx context.Context, owner, repo str // //meta:operation GET /orgs/{org}/actions/secrets func (s *ActionsService) ListOrgSecrets(ctx context.Context, org string, opts *ListOptions) (*Secrets, *Response, error) { - url := fmt.Sprintf("orgs/%v/actions/secrets", org) - return s.listSecrets(ctx, url, opts) + u := fmt.Sprintf("orgs/%v/actions/secrets", org) + u, err := addOptions(u, opts) + if err != nil { + return nil, nil, err + } + + req, err := s.client.NewRequest(ctx, "GET", u, nil) + if err != nil { + return nil, nil, err + } + + var secrets *Secrets + resp, err := s.client.Do(req, &secrets) + if err != nil { + return nil, resp, err + } + + return secrets, resp, nil } // ListEnvSecrets lists all secrets available in an environment. @@ -167,23 +194,24 @@ func (s *ActionsService) ListOrgSecrets(ctx context.Context, org string, opts *L // //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) -} + u := fmt.Sprintf("repos/%v/%v/environments/%v/secrets", owner, repo, env) + u, err := addOptions(u, opts) + if err != nil { + return nil, nil, err + } -func (s *ActionsService) getSecret(ctx context.Context, url string) (*Secret, *Response, error) { - req, err := s.client.NewRequest(ctx, "GET", url, nil) + req, err := s.client.NewRequest(ctx, "GET", u, nil) if err != nil { return nil, nil, err } - var secret *Secret - resp, err := s.client.Do(req, &secret) + var secrets *Secrets + resp, err := s.client.Do(req, &secrets) if err != nil { return nil, resp, err } - return secret, resp, nil + return secrets, resp, nil } // GetRepoSecret gets a single repository secret without revealing its encrypted value. @@ -192,8 +220,20 @@ func (s *ActionsService) getSecret(ctx context.Context, url string) (*Secret, *R // //meta:operation GET /repos/{owner}/{repo}/actions/secrets/{secret_name} func (s *ActionsService) GetRepoSecret(ctx context.Context, owner, repo, name string) (*Secret, *Response, error) { - url := fmt.Sprintf("repos/%v/%v/actions/secrets/%v", owner, repo, name) - return s.getSecret(ctx, url) + u := fmt.Sprintf("repos/%v/%v/actions/secrets/%v", owner, repo, name) + + req, err := s.client.NewRequest(ctx, "GET", u, nil) + if err != nil { + return nil, nil, err + } + + var secret *Secret + resp, err := s.client.Do(req, &secret) + if err != nil { + return nil, resp, err + } + + return secret, resp, nil } // GetOrgSecret gets a single organization secret without revealing its encrypted value. @@ -202,8 +242,20 @@ func (s *ActionsService) GetRepoSecret(ctx context.Context, owner, repo, name st // //meta:operation GET /orgs/{org}/actions/secrets/{secret_name} func (s *ActionsService) GetOrgSecret(ctx context.Context, org, name string) (*Secret, *Response, error) { - url := fmt.Sprintf("orgs/%v/actions/secrets/%v", org, name) - return s.getSecret(ctx, url) + u := fmt.Sprintf("orgs/%v/actions/secrets/%v", org, name) + + req, err := s.client.NewRequest(ctx, "GET", u, nil) + if err != nil { + return nil, nil, err + } + + var secret *Secret + resp, err := s.client.Do(req, &secret) + if err != nil { + return nil, resp, err + } + + return secret, resp, nil } // GetEnvSecret gets a single environment secret without revealing its encrypted value. @@ -212,8 +264,20 @@ func (s *ActionsService) GetOrgSecret(ctx context.Context, org, name string) (*S // //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) + u := fmt.Sprintf("repos/%v/%v/environments/%v/secrets/%v", owner, repo, env, secretName) + + req, err := s.client.NewRequest(ctx, "GET", u, nil) + if err != nil { + return nil, nil, err + } + + var secret *Secret + resp, err := s.client.Do(req, &secret) + if err != nil { + return nil, resp, err + } + + return secret, resp, nil } // SelectedRepoIDs are the repository IDs that have access to the actions secrets. @@ -232,13 +296,28 @@ type EncryptedSecret struct { SelectedRepositoryIDs SelectedRepoIDs `json:"selected_repository_ids,omitempty"` } -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 - } +// OrgSecretRequest represents a request to create or update a secret for an +// organization. +// +// The value of EncryptedValue must be your secret, encrypted with +// LibSodium (see documentation here: https://libsodium.gitbook.io/doc/bindings_for_other_languages) +// using the public key retrieved using the GetPublicKey method. +type OrgSecretRequest struct { + KeyID string `json:"key_id"` + EncryptedValue string `json:"encrypted_value"` + Visibility string `json:"visibility,omitempty"` + SelectedRepositoryIDs []int64 `json:"selected_repository_ids,omitzero"` +} - return s.client.Do(req, nil) +// SecretRequest represents a request to create or update a secret for a +// repository or a repository environment. +// +// The value of EncryptedValue must be your secret, encrypted with +// LibSodium (see documentation here: https://libsodium.gitbook.io/doc/bindings_for_other_languages) +// using the public key retrieved using the GetPublicKey method. +type SecretRequest struct { + KeyID string `json:"key_id"` + EncryptedValue string `json:"encrypted_value"` } // CreateOrUpdateRepoSecret creates or updates a repository secret with an encrypted value. @@ -246,13 +325,15 @@ func (s *ActionsService) putSecret(ctx context.Context, url string, body Encrypt // 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.Name == "" { - return nil, errors.New("secret name must be provided") +func (s *ActionsService) CreateOrUpdateRepoSecret(ctx context.Context, owner, repo, name string, body SecretRequest) (*Response, error) { + u := fmt.Sprintf("repos/%v/%v/actions/secrets/%v", owner, repo, name) + + req, err := s.client.NewRequest(ctx, "PUT", u, body) + if err != nil { + return nil, err } - url := fmt.Sprintf("repos/%v/%v/actions/secrets/%v", owner, repo, body.Name) - return s.putSecret(ctx, url, body) + return s.client.Do(req, nil) } // CreateOrUpdateOrgSecret creates or updates an organization secret with an encrypted value. @@ -260,13 +341,15 @@ 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.Name == "" { - return nil, errors.New("secret name must be provided") +func (s *ActionsService) CreateOrUpdateOrgSecret(ctx context.Context, org, name string, body OrgSecretRequest) (*Response, error) { + u := fmt.Sprintf("orgs/%v/actions/secrets/%v", org, name) + + req, err := s.client.NewRequest(ctx, "PUT", u, body) + if err != nil { + return nil, err } - url := fmt.Sprintf("orgs/%v/actions/secrets/%v", org, body.Name) - return s.putSecret(ctx, url, body) + return s.client.Do(req, nil) } // CreateOrUpdateEnvSecret creates or updates a single environment secret with an encrypted value. @@ -274,17 +357,10 @@ func (s *ActionsService) CreateOrUpdateOrgSecret(ctx context.Context, org string // GitHub API docs: https://docs.github.com/rest/actions/secrets?apiVersion=2022-11-28#create-or-update-an-environment-secret // //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) { - if body.Name == "" { - return nil, errors.New("secret name must be provided") - } +func (s *ActionsService) CreateOrUpdateEnvSecret(ctx context.Context, owner, repo, env, name string, body SecretRequest) (*Response, error) { + u := fmt.Sprintf("repos/%v/%v/environments/%v/secrets/%v", owner, repo, env, name) - url := fmt.Sprintf("repos/%v/%v/environments/%v/secrets/%v", owner, repo, env, body.Name) - return s.putSecret(ctx, url, body) -} - -func (s *ActionsService) deleteSecret(ctx context.Context, url string) (*Response, error) { - req, err := s.client.NewRequest(ctx, "DELETE", url, nil) + req, err := s.client.NewRequest(ctx, "PUT", u, body) if err != nil { return nil, err } @@ -298,8 +374,14 @@ func (s *ActionsService) deleteSecret(ctx context.Context, url string) (*Respons // //meta:operation DELETE /repos/{owner}/{repo}/actions/secrets/{secret_name} func (s *ActionsService) DeleteRepoSecret(ctx context.Context, owner, repo, name string) (*Response, error) { - url := fmt.Sprintf("repos/%v/%v/actions/secrets/%v", owner, repo, name) - return s.deleteSecret(ctx, url) + u := fmt.Sprintf("repos/%v/%v/actions/secrets/%v", owner, repo, name) + + req, err := s.client.NewRequest(ctx, "DELETE", u, nil) + if err != nil { + return nil, err + } + + return s.client.Do(req, nil) } // DeleteOrgSecret deletes a secret in an organization using the secret name. @@ -308,8 +390,14 @@ func (s *ActionsService) DeleteRepoSecret(ctx context.Context, owner, repo, name // //meta:operation DELETE /orgs/{org}/actions/secrets/{secret_name} func (s *ActionsService) DeleteOrgSecret(ctx context.Context, org, name string) (*Response, error) { - url := fmt.Sprintf("orgs/%v/actions/secrets/%v", org, name) - return s.deleteSecret(ctx, url) + u := fmt.Sprintf("orgs/%v/actions/secrets/%v", org, name) + + req, err := s.client.NewRequest(ctx, "DELETE", u, nil) + if err != nil { + return nil, err + } + + return s.client.Do(req, nil) } // DeleteEnvSecret deletes a secret in an environment using the secret name. @@ -318,8 +406,14 @@ func (s *ActionsService) DeleteOrgSecret(ctx context.Context, org, name string) // //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) + u := fmt.Sprintf("repos/%v/%v/environments/%v/secrets/%v", owner, repo, env, secretName) + + req, err := s.client.NewRequest(ctx, "DELETE", u, nil) + if err != nil { + return nil, err + } + + return s.client.Do(req, nil) } // SelectedReposList represents the list of repositories selected for an organization secret. @@ -328,8 +422,14 @@ type SelectedReposList struct { Repositories []*Repository `json:"repositories,omitempty"` } -func (s *ActionsService) listSelectedReposForSecret(ctx context.Context, url string, opts *ListOptions) (*SelectedReposList, *Response, error) { - u, err := addOptions(url, opts) +// ListSelectedReposForOrgSecret lists all repositories that have access to a secret. +// +// GitHub API docs: https://docs.github.com/rest/actions/secrets?apiVersion=2022-11-28#list-selected-repositories-for-an-organization-secret +// +//meta:operation GET /orgs/{org}/actions/secrets/{secret_name}/repositories +func (s *ActionsService) ListSelectedReposForOrgSecret(ctx context.Context, org, name string, opts *ListOptions) (*SelectedReposList, *Response, error) { + u := fmt.Sprintf("orgs/%v/actions/secrets/%v/repositories", org, name) + u, err := addOptions(u, opts) if err != nil { return nil, nil, err } @@ -348,41 +448,19 @@ func (s *ActionsService) listSelectedReposForSecret(ctx context.Context, url str return result, resp, nil } -// ListSelectedReposForOrgSecret lists all repositories that have access to a secret. -// -// GitHub API docs: https://docs.github.com/rest/actions/secrets?apiVersion=2022-11-28#list-selected-repositories-for-an-organization-secret -// -//meta:operation GET /orgs/{org}/actions/secrets/{secret_name}/repositories -func (s *ActionsService) ListSelectedReposForOrgSecret(ctx context.Context, org, name string, opts *ListOptions) (*SelectedReposList, *Response, error) { - url := fmt.Sprintf("orgs/%v/actions/secrets/%v/repositories", org, name) - return s.listSelectedReposForSecret(ctx, url, opts) -} - -func (s *ActionsService) setSelectedReposForSecret(ctx context.Context, url string, ids SelectedRepoIDs) (*Response, error) { - type repoIDs struct { - SelectedIDs SelectedRepoIDs `json:"selected_repository_ids"` - } - - req, err := s.client.NewRequest(ctx, "PUT", url, repoIDs{SelectedIDs: ids}) - if err != nil { - return nil, err - } - - return s.client.Do(req, nil) -} - // SetSelectedReposForOrgSecret sets the repositories that have access to a secret. // // GitHub API docs: https://docs.github.com/rest/actions/secrets?apiVersion=2022-11-28#set-selected-repositories-for-an-organization-secret // //meta:operation PUT /orgs/{org}/actions/secrets/{secret_name}/repositories -func (s *ActionsService) SetSelectedReposForOrgSecret(ctx context.Context, org, name string, ids SelectedRepoIDs) (*Response, error) { - url := fmt.Sprintf("orgs/%v/actions/secrets/%v/repositories", org, name) - return s.setSelectedReposForSecret(ctx, url, ids) -} +func (s *ActionsService) SetSelectedReposForOrgSecret(ctx context.Context, org, name string, ids []int64) (*Response, error) { + u := fmt.Sprintf("orgs/%v/actions/secrets/%v/repositories", org, name) + + type repoIDs struct { + SelectedIDs []int64 `json:"selected_repository_ids"` + } -func (s *ActionsService) addSelectedRepoToSecret(ctx context.Context, url string) (*Response, error) { - req, err := s.client.NewRequest(ctx, "PUT", url, nil) + req, err := s.client.NewRequest(ctx, "PUT", u, repoIDs{SelectedIDs: ids}) if err != nil { return nil, err } @@ -395,17 +473,10 @@ func (s *ActionsService) addSelectedRepoToSecret(ctx context.Context, url string // GitHub API docs: https://docs.github.com/rest/actions/secrets?apiVersion=2022-11-28#add-selected-repository-to-an-organization-secret // //meta:operation PUT /orgs/{org}/actions/secrets/{secret_name}/repositories/{repository_id} -func (s *ActionsService) AddSelectedRepoToOrgSecret(ctx context.Context, org, name string, repo *Repository) (*Response, error) { - if repo == nil { - return nil, errors.New("repository must be provided") - } +func (s *ActionsService) AddSelectedRepoToOrgSecret(ctx context.Context, org, name string, repoID int64) (*Response, error) { + u := fmt.Sprintf("orgs/%v/actions/secrets/%v/repositories/%v", org, name, repoID) - url := fmt.Sprintf("orgs/%v/actions/secrets/%v/repositories/%v", org, name, *repo.ID) - return s.addSelectedRepoToSecret(ctx, url) -} - -func (s *ActionsService) removeSelectedRepoFromSecret(ctx context.Context, url string) (*Response, error) { - req, err := s.client.NewRequest(ctx, "DELETE", url, nil) + req, err := s.client.NewRequest(ctx, "PUT", u, nil) if err != nil { return nil, err } @@ -418,11 +489,13 @@ func (s *ActionsService) removeSelectedRepoFromSecret(ctx context.Context, url s // GitHub API docs: https://docs.github.com/rest/actions/secrets?apiVersion=2022-11-28#remove-selected-repository-from-an-organization-secret // //meta:operation DELETE /orgs/{org}/actions/secrets/{secret_name}/repositories/{repository_id} -func (s *ActionsService) RemoveSelectedRepoFromOrgSecret(ctx context.Context, org, name string, repo *Repository) (*Response, error) { - if repo == nil { - return nil, errors.New("repository must be provided") +func (s *ActionsService) RemoveSelectedRepoFromOrgSecret(ctx context.Context, org, name string, repoID int64) (*Response, error) { + u := fmt.Sprintf("orgs/%v/actions/secrets/%v/repositories/%v", org, name, repoID) + + req, err := s.client.NewRequest(ctx, "DELETE", u, nil) + if err != nil { + return nil, err } - url := fmt.Sprintf("orgs/%v/actions/secrets/%v/repositories/%v", org, name, *repo.ID) - return s.removeSelectedRepoFromSecret(ctx, url) + return s.client.Do(req, nil) } diff --git a/github/actions_secrets_test.go b/github/actions_secrets_test.go index 1fb81c0b728..5860996e32c 100644 --- a/github/actions_secrets_test.go +++ b/github/actions_secrets_test.go @@ -290,41 +290,36 @@ func TestActionsService_CreateOrUpdateRepoSecret(t *testing.T) { t.Parallel() client, mux, _ := setup(t) - input := EncryptedSecret{ - Name: "NAME", - EncryptedValue: "QIv=", + input := SecretRequest{ KeyID: "1234", + EncryptedValue: "QIv=", } mux.HandleFunc("/repos/o/r/actions/secrets/NAME", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "PUT") testHeader(t, r, "Content-Type", "application/json") - want := EncryptedSecret{ - EncryptedValue: "QIv=", + want := SecretRequest{ KeyID: "1234", + EncryptedValue: "QIv=", } testJSONBody(t, r, want) w.WriteHeader(http.StatusCreated) }) ctx := t.Context() - _, err := client.Actions.CreateOrUpdateRepoSecret(ctx, "o", "r", input) + _, err := client.Actions.CreateOrUpdateRepoSecret(ctx, "o", "r", "NAME", input) if err != nil { t.Errorf("Actions.CreateOrUpdateRepoSecret returned error: %v", err) } const methodName = "CreateOrUpdateRepoSecret" testBadOptions(t, methodName, func() (err error) { - _, err = client.Actions.CreateOrUpdateRepoSecret(ctx, "o", "r", EncryptedSecret{}) - return err - }) - testBadOptions(t, methodName, func() (err error) { - _, err = client.Actions.CreateOrUpdateRepoSecret(ctx, "\n", "\n", input) + _, err = client.Actions.CreateOrUpdateRepoSecret(ctx, "\n", "\n", "\n", input) return err }) testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { - return client.Actions.CreateOrUpdateRepoSecret(ctx, "o", "r", input) + return client.Actions.CreateOrUpdateRepoSecret(ctx, "o", "r", "NAME", input) }) } @@ -477,45 +472,40 @@ func TestActionsService_CreateOrUpdateOrgSecret(t *testing.T) { t.Parallel() client, mux, _ := setup(t) - input := EncryptedSecret{ - Name: "NAME", - EncryptedValue: "QIv=", + input := OrgSecretRequest{ KeyID: "1234", + EncryptedValue: "QIv=", Visibility: "selected", - SelectedRepositoryIDs: SelectedRepoIDs{1296269, 1269280}, + SelectedRepositoryIDs: []int64{1296269, 1269280}, } mux.HandleFunc("/orgs/o/actions/secrets/NAME", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "PUT") testHeader(t, r, "Content-Type", "application/json") - want := EncryptedSecret{ - EncryptedValue: "QIv=", + want := OrgSecretRequest{ KeyID: "1234", + EncryptedValue: "QIv=", Visibility: "selected", - SelectedRepositoryIDs: SelectedRepoIDs{1296269, 1269280}, + SelectedRepositoryIDs: []int64{1296269, 1269280}, } testJSONBody(t, r, want) w.WriteHeader(http.StatusCreated) }) ctx := t.Context() - _, err := client.Actions.CreateOrUpdateOrgSecret(ctx, "o", input) + _, err := client.Actions.CreateOrUpdateOrgSecret(ctx, "o", "NAME", input) if err != nil { t.Errorf("Actions.CreateOrUpdateOrgSecret returned error: %v", err) } const methodName = "CreateOrUpdateOrgSecret" testBadOptions(t, methodName, func() (err error) { - _, err = client.Actions.CreateOrUpdateOrgSecret(ctx, "o", EncryptedSecret{}) - return err - }) - testBadOptions(t, methodName, func() (err error) { - _, err = client.Actions.CreateOrUpdateOrgSecret(ctx, "\n", input) + _, err = client.Actions.CreateOrUpdateOrgSecret(ctx, "\n", "\n", input) return err }) testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { - return client.Actions.CreateOrUpdateOrgSecret(ctx, "o", input) + return client.Actions.CreateOrUpdateOrgSecret(ctx, "o", "NAME", input) }) } @@ -564,13 +554,13 @@ func TestActionsService_SetSelectedReposForOrgSecret(t *testing.T) { t.Parallel() client, mux, _ := setup(t) - input := SelectedRepoIDs{64780797} + input := []int64{64780797} mux.HandleFunc("/orgs/o/actions/secrets/NAME/repositories", func(_ http.ResponseWriter, r *http.Request) { testMethod(t, r, "PUT") testHeader(t, r, "Content-Type", "application/json") testJSONBody(t, r, struct { - SelectedIDs SelectedRepoIDs `json:"selected_repository_ids"` + SelectedIDs []int64 `json:"selected_repository_ids"` }{ SelectedIDs: input, }) @@ -601,25 +591,25 @@ func TestActionsService_AddSelectedRepoToOrgSecret(t *testing.T) { testMethod(t, r, "PUT") }) - repo := &Repository{ID: Ptr(int64(1234))} + repoID := int64(1234) ctx := t.Context() - _, err := client.Actions.AddSelectedRepoToOrgSecret(ctx, "o", "NAME", repo) + _, err := client.Actions.AddSelectedRepoToOrgSecret(ctx, "o", "NAME", repoID) if err != nil { t.Errorf("Actions.AddSelectedRepoToOrgSecret returned error: %v", err) } const methodName = "AddSelectedRepoToOrgSecret" testBadOptions(t, methodName, func() (err error) { - _, err = client.Actions.AddSelectedRepoToOrgSecret(ctx, "o", "NAME", nil) + _, err = client.Actions.AddSelectedRepoToOrgSecret(ctx, "o", "NAME", 0) return err }) testBadOptions(t, methodName, func() (err error) { - _, err = client.Actions.AddSelectedRepoToOrgSecret(ctx, "\n", "\n", repo) + _, err = client.Actions.AddSelectedRepoToOrgSecret(ctx, "\n", "\n", repoID) return err }) testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { - return client.Actions.AddSelectedRepoToOrgSecret(ctx, "o", "NAME", repo) + return client.Actions.AddSelectedRepoToOrgSecret(ctx, "o", "NAME", repoID) }) } @@ -631,25 +621,25 @@ func TestActionsService_RemoveSelectedRepoFromOrgSecret(t *testing.T) { testMethod(t, r, "DELETE") }) - repo := &Repository{ID: Ptr(int64(1234))} + repoID := int64(1234) ctx := t.Context() - _, err := client.Actions.RemoveSelectedRepoFromOrgSecret(ctx, "o", "NAME", repo) + _, err := client.Actions.RemoveSelectedRepoFromOrgSecret(ctx, "o", "NAME", repoID) if err != nil { t.Errorf("Actions.RemoveSelectedRepoFromOrgSecret returned error: %v", err) } const methodName = "RemoveSelectedRepoFromOrgSecret" testBadOptions(t, methodName, func() (err error) { - _, err = client.Actions.RemoveSelectedRepoFromOrgSecret(ctx, "o", "NAME", nil) + _, err = client.Actions.RemoveSelectedRepoFromOrgSecret(ctx, "o", "NAME", 0) return err }) testBadOptions(t, methodName, func() (err error) { - _, err = client.Actions.RemoveSelectedRepoFromOrgSecret(ctx, "\n", "\n", repo) + _, err = client.Actions.RemoveSelectedRepoFromOrgSecret(ctx, "\n", "\n", repoID) return err }) testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { - return client.Actions.RemoveSelectedRepoFromOrgSecret(ctx, "o", "NAME", repo) + return client.Actions.RemoveSelectedRepoFromOrgSecret(ctx, "o", "NAME", repoID) }) } @@ -834,41 +824,36 @@ func TestActionsService_CreateOrUpdateEnvSecret(t *testing.T) { t.Parallel() client, mux, _ := setup(t) - input := EncryptedSecret{ - Name: "secret", - EncryptedValue: "QIv=", + input := SecretRequest{ KeyID: "1234", + EncryptedValue: "QIv=", } mux.HandleFunc("/repos/o/r/environments/e/secrets/secret", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "PUT") testHeader(t, r, "Content-Type", "application/json") - want := EncryptedSecret{ - EncryptedValue: "QIv=", + want := SecretRequest{ KeyID: "1234", + EncryptedValue: "QIv=", } testJSONBody(t, r, want) w.WriteHeader(http.StatusCreated) }) ctx := t.Context() - _, err := client.Actions.CreateOrUpdateEnvSecret(ctx, "o", "r", "e", input) + _, err := client.Actions.CreateOrUpdateEnvSecret(ctx, "o", "r", "e", "secret", 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, "o", "r", "e", EncryptedSecret{}) - return err - }) - testBadOptions(t, methodName, func() (err error) { - _, err = client.Actions.CreateOrUpdateEnvSecret(ctx, "\n", "\n", "\n", input) + _, err = client.Actions.CreateOrUpdateEnvSecret(ctx, "\n", "\n", "\n", "\n", input) return err }) testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { - return client.Actions.CreateOrUpdateEnvSecret(ctx, "o", "r", "e", input) + return client.Actions.CreateOrUpdateEnvSecret(ctx, "o", "r", "e", "secret", input) }) } diff --git a/github/github-accessors.go b/github/github-accessors.go index b55d3667a6e..07a3ffeb9e2 100644 --- a/github/github-accessors.go +++ b/github/github-accessors.go @@ -25830,6 +25830,38 @@ func (o *OrgBlockEvent) GetSender() *User { return o.Sender } +// GetEncryptedValue returns the EncryptedValue field. +func (o *OrgSecretRequest) GetEncryptedValue() string { + if o == nil { + return "" + } + return o.EncryptedValue +} + +// GetKeyID returns the KeyID field. +func (o *OrgSecretRequest) GetKeyID() string { + if o == nil { + return "" + } + return o.KeyID +} + +// GetSelectedRepositoryIDs returns the SelectedRepositoryIDs slice if it's non-nil, nil otherwise. +func (o *OrgSecretRequest) GetSelectedRepositoryIDs() []int64 { + if o == nil || o.SelectedRepositoryIDs == nil { + return nil + } + return o.SelectedRepositoryIDs +} + +// GetVisibility returns the Visibility field. +func (o *OrgSecretRequest) GetVisibility() string { + if o == nil { + return "" + } + return o.Visibility +} + // GetDisabledOrgs returns the DisabledOrgs field if it's non-nil, zero value otherwise. func (o *OrgStats) GetDisabledOrgs() int { if o == nil || o.DisabledOrgs == nil { @@ -38350,6 +38382,22 @@ func (s *Secret) GetVisibility() string { return s.Visibility } +// GetEncryptedValue returns the EncryptedValue field. +func (s *SecretRequest) GetEncryptedValue() string { + if s == nil { + return "" + } + return s.EncryptedValue +} + +// GetKeyID returns the KeyID field. +func (s *SecretRequest) GetKeyID() string { + if s == nil { + return "" + } + return s.KeyID +} + // GetSecrets returns the Secrets slice if it's non-nil, nil otherwise. func (s *Secrets) GetSecrets() []*Secret { if s == nil || s.Secrets == nil { diff --git a/github/github-accessors_test.go b/github/github-accessors_test.go index c28c9832d70..e892c742bf6 100644 --- a/github/github-accessors_test.go +++ b/github/github-accessors_test.go @@ -32473,6 +32473,41 @@ func TestOrgBlockEvent_GetSender(tt *testing.T) { o.GetSender() } +func TestOrgSecretRequest_GetEncryptedValue(tt *testing.T) { + tt.Parallel() + o := &OrgSecretRequest{} + o.GetEncryptedValue() + o = nil + o.GetEncryptedValue() +} + +func TestOrgSecretRequest_GetKeyID(tt *testing.T) { + tt.Parallel() + o := &OrgSecretRequest{} + o.GetKeyID() + o = nil + o.GetKeyID() +} + +func TestOrgSecretRequest_GetSelectedRepositoryIDs(tt *testing.T) { + tt.Parallel() + zeroValue := []int64{} + o := &OrgSecretRequest{SelectedRepositoryIDs: zeroValue} + o.GetSelectedRepositoryIDs() + o = &OrgSecretRequest{} + o.GetSelectedRepositoryIDs() + o = nil + o.GetSelectedRepositoryIDs() +} + +func TestOrgSecretRequest_GetVisibility(tt *testing.T) { + tt.Parallel() + o := &OrgSecretRequest{} + o.GetVisibility() + o = nil + o.GetVisibility() +} + func TestOrgStats_GetDisabledOrgs(tt *testing.T) { tt.Parallel() var zeroValue int @@ -48086,6 +48121,22 @@ func TestSecret_GetVisibility(tt *testing.T) { s.GetVisibility() } +func TestSecretRequest_GetEncryptedValue(tt *testing.T) { + tt.Parallel() + s := &SecretRequest{} + s.GetEncryptedValue() + s = nil + s.GetEncryptedValue() +} + +func TestSecretRequest_GetKeyID(tt *testing.T) { + tt.Parallel() + s := &SecretRequest{} + s.GetKeyID() + s = nil + s.GetKeyID() +} + func TestSecrets_GetSecrets(tt *testing.T) { tt.Parallel() zeroValue := []*Secret{} From c5598904825ad52a20b1fa45ef4f3e39a9027714 Mon Sep 17 00:00:00 2001 From: Steve Hipwell Date: Mon, 29 Jun 2026 22:31:32 +0100 Subject: [PATCH 6/6] fixup! feat!: Replace actions env secret endpoints --- example/newreposecretwithxcrypto/main.go | 5 ++--- github/actions_secrets.go | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/example/newreposecretwithxcrypto/main.go b/example/newreposecretwithxcrypto/main.go index 7258079d201..4aab60f62e9 100644 --- a/example/newreposecretwithxcrypto/main.go +++ b/example/newreposecretwithxcrypto/main.go @@ -144,13 +144,12 @@ func addRepoSecret(ctx context.Context, client *github.Client, owner, repo, secr encryptedString := base64.StdEncoding.EncodeToString(encryptedBytes) keyID := publicKey.GetKeyID() - encryptedSecret := github.EncryptedSecret{ - Name: secretName, + req := github.SecretRequest{ KeyID: keyID, EncryptedValue: encryptedString, } - if _, err := client.Actions.CreateOrUpdateRepoSecret(ctx, owner, repo, encryptedSecret); err != nil { + if _, err := client.Actions.CreateOrUpdateRepoSecret(ctx, owner, repo, secretName, req); err != nil { return fmt.Errorf("client.Actions.CreateOrUpdateRepoSecret returned error: %v", err) } diff --git a/github/actions_secrets.go b/github/actions_secrets.go index 52ff020890d..5c4eb19168d 100644 --- a/github/actions_secrets.go +++ b/github/actions_secrets.go @@ -305,7 +305,7 @@ type EncryptedSecret struct { type OrgSecretRequest struct { KeyID string `json:"key_id"` EncryptedValue string `json:"encrypted_value"` - Visibility string `json:"visibility,omitempty"` + Visibility string `json:"visibility"` SelectedRepositoryIDs []int64 `json:"selected_repository_ids,omitzero"` }