github.com/google/go-github/v60@v60.0.0/github/actions_secrets.go (about)

     1  // Copyright 2020 The go-github AUTHORS. All rights reserved.
     2  //
     3  // Use of this source code is governed by a BSD-style
     4  // license that can be found in the LICENSE file.
     5  
     6  package github
     7  
     8  import (
     9  	"context"
    10  	"encoding/json"
    11  	"fmt"
    12  	"strconv"
    13  )
    14  
    15  // PublicKey represents the public key that should be used to encrypt secrets.
    16  type PublicKey struct {
    17  	KeyID *string `json:"key_id"`
    18  	Key   *string `json:"key"`
    19  }
    20  
    21  // UnmarshalJSON implements the json.Unmarshaler interface.
    22  // This ensures GitHub Enterprise versions which return a numeric key id
    23  // do not error out when unmarshaling.
    24  func (p *PublicKey) UnmarshalJSON(data []byte) error {
    25  	var pk struct {
    26  		KeyID interface{} `json:"key_id"`
    27  		Key   *string     `json:"key"`
    28  	}
    29  
    30  	if err := json.Unmarshal(data, &pk); err != nil {
    31  		return err
    32  	}
    33  
    34  	p.Key = pk.Key
    35  
    36  	switch v := pk.KeyID.(type) {
    37  	case nil:
    38  		return nil
    39  	case string:
    40  		p.KeyID = &v
    41  	case float64:
    42  		p.KeyID = String(strconv.FormatFloat(v, 'f', -1, 64))
    43  	default:
    44  		return fmt.Errorf("unable to unmarshal %T as a string", v)
    45  	}
    46  
    47  	return nil
    48  }
    49  
    50  func (s *ActionsService) getPublicKey(ctx context.Context, url string) (*PublicKey, *Response, error) {
    51  	req, err := s.client.NewRequest("GET", url, nil)
    52  	if err != nil {
    53  		return nil, nil, err
    54  	}
    55  
    56  	pubKey := new(PublicKey)
    57  	resp, err := s.client.Do(ctx, req, pubKey)
    58  	if err != nil {
    59  		return nil, resp, err
    60  	}
    61  
    62  	return pubKey, resp, nil
    63  }
    64  
    65  // GetRepoPublicKey gets a public key that should be used for secret encryption.
    66  //
    67  // GitHub API docs: https://docs.github.com/rest/actions/secrets#get-a-repository-public-key
    68  //
    69  //meta:operation GET /repos/{owner}/{repo}/actions/secrets/public-key
    70  func (s *ActionsService) GetRepoPublicKey(ctx context.Context, owner, repo string) (*PublicKey, *Response, error) {
    71  	url := fmt.Sprintf("repos/%v/%v/actions/secrets/public-key", owner, repo)
    72  	return s.getPublicKey(ctx, url)
    73  }
    74  
    75  // GetOrgPublicKey gets a public key that should be used for secret encryption.
    76  //
    77  // GitHub API docs: https://docs.github.com/rest/actions/secrets#get-an-organization-public-key
    78  //
    79  //meta:operation GET /orgs/{org}/actions/secrets/public-key
    80  func (s *ActionsService) GetOrgPublicKey(ctx context.Context, org string) (*PublicKey, *Response, error) {
    81  	url := fmt.Sprintf("orgs/%v/actions/secrets/public-key", org)
    82  	return s.getPublicKey(ctx, url)
    83  }
    84  
    85  // GetEnvPublicKey gets a public key that should be used for secret encryption.
    86  //
    87  // GitHub API docs: https://docs.github.com/rest/actions/secrets#get-an-environment-public-key
    88  //
    89  //meta:operation GET /repositories/{repository_id}/environments/{environment_name}/secrets/public-key
    90  func (s *ActionsService) GetEnvPublicKey(ctx context.Context, repoID int, env string) (*PublicKey, *Response, error) {
    91  	url := fmt.Sprintf("repositories/%v/environments/%v/secrets/public-key", repoID, env)
    92  	return s.getPublicKey(ctx, url)
    93  }
    94  
    95  // Secret represents a repository action secret.
    96  type Secret struct {
    97  	Name                    string    `json:"name"`
    98  	CreatedAt               Timestamp `json:"created_at"`
    99  	UpdatedAt               Timestamp `json:"updated_at"`
   100  	Visibility              string    `json:"visibility,omitempty"`
   101  	SelectedRepositoriesURL string    `json:"selected_repositories_url,omitempty"`
   102  }
   103  
   104  // Secrets represents one item from the ListSecrets response.
   105  type Secrets struct {
   106  	TotalCount int       `json:"total_count"`
   107  	Secrets    []*Secret `json:"secrets"`
   108  }
   109  
   110  func (s *ActionsService) listSecrets(ctx context.Context, url string, opts *ListOptions) (*Secrets, *Response, error) {
   111  	u, err := addOptions(url, opts)
   112  	if err != nil {
   113  		return nil, nil, err
   114  	}
   115  
   116  	req, err := s.client.NewRequest("GET", u, nil)
   117  	if err != nil {
   118  		return nil, nil, err
   119  	}
   120  
   121  	secrets := new(Secrets)
   122  	resp, err := s.client.Do(ctx, req, &secrets)
   123  	if err != nil {
   124  		return nil, resp, err
   125  	}
   126  
   127  	return secrets, resp, nil
   128  }
   129  
   130  // ListRepoSecrets lists all secrets available in a repository
   131  // without revealing their encrypted values.
   132  //
   133  // GitHub API docs: https://docs.github.com/rest/actions/secrets#list-repository-secrets
   134  //
   135  //meta:operation GET /repos/{owner}/{repo}/actions/secrets
   136  func (s *ActionsService) ListRepoSecrets(ctx context.Context, owner, repo string, opts *ListOptions) (*Secrets, *Response, error) {
   137  	url := fmt.Sprintf("repos/%v/%v/actions/secrets", owner, repo)
   138  	return s.listSecrets(ctx, url, opts)
   139  }
   140  
   141  // ListRepoOrgSecrets lists all organization secrets available in a repository
   142  // without revealing their encrypted values.
   143  //
   144  // GitHub API docs: https://docs.github.com/rest/actions/secrets#list-repository-organization-secrets
   145  //
   146  //meta:operation GET /repos/{owner}/{repo}/actions/organization-secrets
   147  func (s *ActionsService) ListRepoOrgSecrets(ctx context.Context, owner, repo string, opts *ListOptions) (*Secrets, *Response, error) {
   148  	url := fmt.Sprintf("repos/%v/%v/actions/organization-secrets", owner, repo)
   149  	return s.listSecrets(ctx, url, opts)
   150  }
   151  
   152  // ListOrgSecrets lists all secrets available in an organization
   153  // without revealing their encrypted values.
   154  //
   155  // GitHub API docs: https://docs.github.com/rest/actions/secrets#list-organization-secrets
   156  //
   157  //meta:operation GET /orgs/{org}/actions/secrets
   158  func (s *ActionsService) ListOrgSecrets(ctx context.Context, org string, opts *ListOptions) (*Secrets, *Response, error) {
   159  	url := fmt.Sprintf("orgs/%v/actions/secrets", org)
   160  	return s.listSecrets(ctx, url, opts)
   161  }
   162  
   163  // ListEnvSecrets lists all secrets available in an environment.
   164  //
   165  // GitHub API docs: https://docs.github.com/rest/actions/secrets#list-environment-secrets
   166  //
   167  //meta:operation GET /repositories/{repository_id}/environments/{environment_name}/secrets
   168  func (s *ActionsService) ListEnvSecrets(ctx context.Context, repoID int, env string, opts *ListOptions) (*Secrets, *Response, error) {
   169  	url := fmt.Sprintf("repositories/%v/environments/%v/secrets", repoID, env)
   170  	return s.listSecrets(ctx, url, opts)
   171  }
   172  
   173  func (s *ActionsService) getSecret(ctx context.Context, url string) (*Secret, *Response, error) {
   174  	req, err := s.client.NewRequest("GET", url, nil)
   175  	if err != nil {
   176  		return nil, nil, err
   177  	}
   178  
   179  	secret := new(Secret)
   180  	resp, err := s.client.Do(ctx, req, secret)
   181  	if err != nil {
   182  		return nil, resp, err
   183  	}
   184  
   185  	return secret, resp, nil
   186  }
   187  
   188  // GetRepoSecret gets a single repository secret without revealing its encrypted value.
   189  //
   190  // GitHub API docs: https://docs.github.com/rest/actions/secrets#get-a-repository-secret
   191  //
   192  //meta:operation GET /repos/{owner}/{repo}/actions/secrets/{secret_name}
   193  func (s *ActionsService) GetRepoSecret(ctx context.Context, owner, repo, name string) (*Secret, *Response, error) {
   194  	url := fmt.Sprintf("repos/%v/%v/actions/secrets/%v", owner, repo, name)
   195  	return s.getSecret(ctx, url)
   196  }
   197  
   198  // GetOrgSecret gets a single organization secret without revealing its encrypted value.
   199  //
   200  // GitHub API docs: https://docs.github.com/rest/actions/secrets#get-an-organization-secret
   201  //
   202  //meta:operation GET /orgs/{org}/actions/secrets/{secret_name}
   203  func (s *ActionsService) GetOrgSecret(ctx context.Context, org, name string) (*Secret, *Response, error) {
   204  	url := fmt.Sprintf("orgs/%v/actions/secrets/%v", org, name)
   205  	return s.getSecret(ctx, url)
   206  }
   207  
   208  // GetEnvSecret gets a single environment secret without revealing its encrypted value.
   209  //
   210  // GitHub API docs: https://docs.github.com/rest/actions/secrets#get-an-environment-secret
   211  //
   212  //meta:operation GET /repositories/{repository_id}/environments/{environment_name}/secrets/{secret_name}
   213  func (s *ActionsService) GetEnvSecret(ctx context.Context, repoID int, env, secretName string) (*Secret, *Response, error) {
   214  	url := fmt.Sprintf("repositories/%v/environments/%v/secrets/%v", repoID, env, secretName)
   215  	return s.getSecret(ctx, url)
   216  }
   217  
   218  // SelectedRepoIDs are the repository IDs that have access to the actions secrets.
   219  type SelectedRepoIDs []int64
   220  
   221  // EncryptedSecret represents a secret that is encrypted using a public key.
   222  //
   223  // The value of EncryptedValue must be your secret, encrypted with
   224  // LibSodium (see documentation here: https://libsodium.gitbook.io/doc/bindings_for_other_languages)
   225  // using the public key retrieved using the GetPublicKey method.
   226  type EncryptedSecret struct {
   227  	Name                  string          `json:"-"`
   228  	KeyID                 string          `json:"key_id"`
   229  	EncryptedValue        string          `json:"encrypted_value"`
   230  	Visibility            string          `json:"visibility,omitempty"`
   231  	SelectedRepositoryIDs SelectedRepoIDs `json:"selected_repository_ids,omitempty"`
   232  }
   233  
   234  func (s *ActionsService) putSecret(ctx context.Context, url string, eSecret *EncryptedSecret) (*Response, error) {
   235  	req, err := s.client.NewRequest("PUT", url, eSecret)
   236  	if err != nil {
   237  		return nil, err
   238  	}
   239  
   240  	return s.client.Do(ctx, req, nil)
   241  }
   242  
   243  // CreateOrUpdateRepoSecret creates or updates a repository secret with an encrypted value.
   244  //
   245  // GitHub API docs: https://docs.github.com/rest/actions/secrets#create-or-update-a-repository-secret
   246  //
   247  //meta:operation PUT /repos/{owner}/{repo}/actions/secrets/{secret_name}
   248  func (s *ActionsService) CreateOrUpdateRepoSecret(ctx context.Context, owner, repo string, eSecret *EncryptedSecret) (*Response, error) {
   249  	url := fmt.Sprintf("repos/%v/%v/actions/secrets/%v", owner, repo, eSecret.Name)
   250  	return s.putSecret(ctx, url, eSecret)
   251  }
   252  
   253  // CreateOrUpdateOrgSecret creates or updates an organization secret with an encrypted value.
   254  //
   255  // GitHub API docs: https://docs.github.com/rest/actions/secrets#create-or-update-an-organization-secret
   256  //
   257  //meta:operation PUT /orgs/{org}/actions/secrets/{secret_name}
   258  func (s *ActionsService) CreateOrUpdateOrgSecret(ctx context.Context, org string, eSecret *EncryptedSecret) (*Response, error) {
   259  	url := fmt.Sprintf("orgs/%v/actions/secrets/%v", org, eSecret.Name)
   260  	return s.putSecret(ctx, url, eSecret)
   261  }
   262  
   263  // CreateOrUpdateEnvSecret creates or updates a single environment secret with an encrypted value.
   264  //
   265  // GitHub API docs: https://docs.github.com/rest/actions/secrets#create-or-update-an-environment-secret
   266  //
   267  //meta:operation PUT /repositories/{repository_id}/environments/{environment_name}/secrets/{secret_name}
   268  func (s *ActionsService) CreateOrUpdateEnvSecret(ctx context.Context, repoID int, env string, eSecret *EncryptedSecret) (*Response, error) {
   269  	url := fmt.Sprintf("repositories/%v/environments/%v/secrets/%v", repoID, env, eSecret.Name)
   270  	return s.putSecret(ctx, url, eSecret)
   271  }
   272  
   273  func (s *ActionsService) deleteSecret(ctx context.Context, url string) (*Response, error) {
   274  	req, err := s.client.NewRequest("DELETE", url, nil)
   275  	if err != nil {
   276  		return nil, err
   277  	}
   278  
   279  	return s.client.Do(ctx, req, nil)
   280  }
   281  
   282  // DeleteRepoSecret deletes a secret in a repository using the secret name.
   283  //
   284  // GitHub API docs: https://docs.github.com/rest/actions/secrets#delete-a-repository-secret
   285  //
   286  //meta:operation DELETE /repos/{owner}/{repo}/actions/secrets/{secret_name}
   287  func (s *ActionsService) DeleteRepoSecret(ctx context.Context, owner, repo, name string) (*Response, error) {
   288  	url := fmt.Sprintf("repos/%v/%v/actions/secrets/%v", owner, repo, name)
   289  	return s.deleteSecret(ctx, url)
   290  }
   291  
   292  // DeleteOrgSecret deletes a secret in an organization using the secret name.
   293  //
   294  // GitHub API docs: https://docs.github.com/rest/actions/secrets#delete-an-organization-secret
   295  //
   296  //meta:operation DELETE /orgs/{org}/actions/secrets/{secret_name}
   297  func (s *ActionsService) DeleteOrgSecret(ctx context.Context, org, name string) (*Response, error) {
   298  	url := fmt.Sprintf("orgs/%v/actions/secrets/%v", org, name)
   299  	return s.deleteSecret(ctx, url)
   300  }
   301  
   302  // DeleteEnvSecret deletes a secret in an environment using the secret name.
   303  //
   304  // GitHub API docs: https://docs.github.com/rest/actions/secrets#delete-an-environment-secret
   305  //
   306  //meta:operation DELETE /repositories/{repository_id}/environments/{environment_name}/secrets/{secret_name}
   307  func (s *ActionsService) DeleteEnvSecret(ctx context.Context, repoID int, env, secretName string) (*Response, error) {
   308  	url := fmt.Sprintf("repositories/%v/environments/%v/secrets/%v", repoID, env, secretName)
   309  	return s.deleteSecret(ctx, url)
   310  }
   311  
   312  // SelectedReposList represents the list of repositories selected for an organization secret.
   313  type SelectedReposList struct {
   314  	TotalCount   *int          `json:"total_count,omitempty"`
   315  	Repositories []*Repository `json:"repositories,omitempty"`
   316  }
   317  
   318  func (s *ActionsService) listSelectedReposForSecret(ctx context.Context, url string, opts *ListOptions) (*SelectedReposList, *Response, error) {
   319  	u, err := addOptions(url, opts)
   320  	if err != nil {
   321  		return nil, nil, err
   322  	}
   323  
   324  	req, err := s.client.NewRequest("GET", u, nil)
   325  	if err != nil {
   326  		return nil, nil, err
   327  	}
   328  
   329  	result := new(SelectedReposList)
   330  	resp, err := s.client.Do(ctx, req, result)
   331  	if err != nil {
   332  		return nil, resp, err
   333  	}
   334  
   335  	return result, resp, nil
   336  }
   337  
   338  // ListSelectedReposForOrgSecret lists all repositories that have access to a secret.
   339  //
   340  // GitHub API docs: https://docs.github.com/rest/actions/secrets#list-selected-repositories-for-an-organization-secret
   341  //
   342  //meta:operation GET /orgs/{org}/actions/secrets/{secret_name}/repositories
   343  func (s *ActionsService) ListSelectedReposForOrgSecret(ctx context.Context, org, name string, opts *ListOptions) (*SelectedReposList, *Response, error) {
   344  	url := fmt.Sprintf("orgs/%v/actions/secrets/%v/repositories", org, name)
   345  	return s.listSelectedReposForSecret(ctx, url, opts)
   346  }
   347  
   348  func (s *ActionsService) setSelectedReposForSecret(ctx context.Context, url string, ids SelectedRepoIDs) (*Response, error) {
   349  	type repoIDs struct {
   350  		SelectedIDs SelectedRepoIDs `json:"selected_repository_ids"`
   351  	}
   352  
   353  	req, err := s.client.NewRequest("PUT", url, repoIDs{SelectedIDs: ids})
   354  	if err != nil {
   355  		return nil, err
   356  	}
   357  
   358  	return s.client.Do(ctx, req, nil)
   359  }
   360  
   361  // SetSelectedReposForOrgSecret sets the repositories that have access to a secret.
   362  //
   363  // GitHub API docs: https://docs.github.com/rest/actions/secrets#set-selected-repositories-for-an-organization-secret
   364  //
   365  //meta:operation PUT /orgs/{org}/actions/secrets/{secret_name}/repositories
   366  func (s *ActionsService) SetSelectedReposForOrgSecret(ctx context.Context, org, name string, ids SelectedRepoIDs) (*Response, error) {
   367  	url := fmt.Sprintf("orgs/%v/actions/secrets/%v/repositories", org, name)
   368  	return s.setSelectedReposForSecret(ctx, url, ids)
   369  }
   370  
   371  func (s *ActionsService) addSelectedRepoToSecret(ctx context.Context, url string) (*Response, error) {
   372  	req, err := s.client.NewRequest("PUT", url, nil)
   373  	if err != nil {
   374  		return nil, err
   375  	}
   376  
   377  	return s.client.Do(ctx, req, nil)
   378  }
   379  
   380  // AddSelectedRepoToOrgSecret adds a repository to an organization secret.
   381  //
   382  // GitHub API docs: https://docs.github.com/rest/actions/secrets#add-selected-repository-to-an-organization-secret
   383  //
   384  //meta:operation PUT /orgs/{org}/actions/secrets/{secret_name}/repositories/{repository_id}
   385  func (s *ActionsService) AddSelectedRepoToOrgSecret(ctx context.Context, org, name string, repo *Repository) (*Response, error) {
   386  	url := fmt.Sprintf("orgs/%v/actions/secrets/%v/repositories/%v", org, name, *repo.ID)
   387  	return s.addSelectedRepoToSecret(ctx, url)
   388  }
   389  
   390  func (s *ActionsService) removeSelectedRepoFromSecret(ctx context.Context, url string) (*Response, error) {
   391  	req, err := s.client.NewRequest("DELETE", url, nil)
   392  	if err != nil {
   393  		return nil, err
   394  	}
   395  
   396  	return s.client.Do(ctx, req, nil)
   397  }
   398  
   399  // RemoveSelectedRepoFromOrgSecret removes a repository from an organization secret.
   400  //
   401  // GitHub API docs: https://docs.github.com/rest/actions/secrets#remove-selected-repository-from-an-organization-secret
   402  //
   403  //meta:operation DELETE /orgs/{org}/actions/secrets/{secret_name}/repositories/{repository_id}
   404  func (s *ActionsService) RemoveSelectedRepoFromOrgSecret(ctx context.Context, org, name string, repo *Repository) (*Response, error) {
   405  	url := fmt.Sprintf("orgs/%v/actions/secrets/%v/repositories/%v", org, name, *repo.ID)
   406  	return s.removeSelectedRepoFromSecret(ctx, url)
   407  }