Add ability to set environments secrets
This commit is contained in:
parent
d396674e12
commit
32856c987d
3 changed files with 78 additions and 3 deletions
|
|
@ -90,6 +90,15 @@ func putOrgSecret(client *api.Client, host string, pk *PubKey, opts SetOptions,
|
|||
return putSecret(client, host, path, payload)
|
||||
}
|
||||
|
||||
func putEnvSecret(client *api.Client, pk *PubKey, repo ghrepo.Interface, envName string, secretName, eValue string) error {
|
||||
payload := SecretPayload{
|
||||
EncryptedValue: eValue,
|
||||
KeyID: pk.ID,
|
||||
}
|
||||
path := fmt.Sprintf("repos/%s/environments/%s/secrets/%s", ghrepo.FullName(repo), envName, secretName)
|
||||
return putSecret(client, repo.RepoHost(), path, payload)
|
||||
}
|
||||
|
||||
func putRepoSecret(client *api.Client, pk *PubKey, repo ghrepo.Interface, secretName, eValue string) error {
|
||||
payload := SecretPayload{
|
||||
EncryptedValue: eValue,
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ type SetOptions struct {
|
|||
|
||||
SecretName string
|
||||
OrgName string
|
||||
EnvName string
|
||||
Body string
|
||||
Visibility string
|
||||
RepositoryNames []string
|
||||
|
|
@ -48,7 +49,7 @@ func NewCmdSet(f *cmdutil.Factory, runF func(*SetOptions) error) *cobra.Command
|
|||
cmd := &cobra.Command{
|
||||
Use: "set <secret-name>",
|
||||
Short: "Create or update secrets",
|
||||
Long: "Locally encrypt a new or updated secret at either the repository or organization level and send it to GitHub for storage.",
|
||||
Long: "Locally encrypt a new or updated secret at either the repository, environment, or organization level and send it to GitHub for storage.",
|
||||
Example: heredoc.Doc(`
|
||||
Paste secret in prompt
|
||||
$ gh secret set MYSECRET
|
||||
|
|
@ -59,6 +60,9 @@ func NewCmdSet(f *cmdutil.Factory, runF func(*SetOptions) error) *cobra.Command
|
|||
Use file as secret value
|
||||
$ gh secret set MYSECRET < file.json
|
||||
|
||||
Set environment level secret
|
||||
$ gh secret set MYSECRET -bval --env=anEnv
|
||||
|
||||
Set organization level secret visible to entire organization
|
||||
$ gh secret set MYSECRET -bval --org=anOrg --visibility=all
|
||||
|
||||
|
|
@ -75,6 +79,10 @@ func NewCmdSet(f *cmdutil.Factory, runF func(*SetOptions) error) *cobra.Command
|
|||
// support `-R, --repo` override
|
||||
opts.BaseRepo = f.BaseRepo
|
||||
|
||||
if err := cmdutil.MutuallyExclusive("specify only one of `--org` or `--env`", opts.OrgName != "", opts.EnvName != ""); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
opts.SecretName = args[0]
|
||||
|
||||
err := validSecretName(opts.SecretName)
|
||||
|
|
@ -115,7 +123,8 @@ func NewCmdSet(f *cmdutil.Factory, runF func(*SetOptions) error) *cobra.Command
|
|||
return setRun(opts)
|
||||
},
|
||||
}
|
||||
cmd.Flags().StringVarP(&opts.OrgName, "org", "o", "", "List secrets for an organization")
|
||||
cmd.Flags().StringVarP(&opts.OrgName, "org", "o", "", "Set a secret for an organization")
|
||||
cmd.Flags().StringVarP(&opts.EnvName, "env", "e", "", "Set a secret for an organization")
|
||||
cmd.Flags().StringVarP(&opts.Visibility, "visibility", "v", "private", "Set visibility for an organization secret: `all`, `private`, or `selected`")
|
||||
cmd.Flags().StringSliceVarP(&opts.RepositoryNames, "repos", "r", []string{}, "List of repository names for `selected` visibility")
|
||||
cmd.Flags().StringVarP(&opts.Body, "body", "b", "", "A value for the secret. Reads from STDIN if not specified.")
|
||||
|
|
@ -136,6 +145,7 @@ func setRun(opts *SetOptions) error {
|
|||
client := api.NewClientFromHTTP(c)
|
||||
|
||||
orgName := opts.OrgName
|
||||
envName := opts.EnvName
|
||||
|
||||
var baseRepo ghrepo.Interface
|
||||
if orgName == "" {
|
||||
|
|
@ -175,7 +185,11 @@ func setRun(opts *SetOptions) error {
|
|||
if orgName != "" {
|
||||
err = putOrgSecret(client, host, pk, *opts, encoded)
|
||||
} else {
|
||||
err = putRepoSecret(client, pk, baseRepo, opts.SecretName, encoded)
|
||||
if envName != "" {
|
||||
err = putEnvSecret(client, pk, baseRepo, envName, opts.SecretName, encoded)
|
||||
} else {
|
||||
err = putRepoSecret(client, pk, baseRepo, opts.SecretName, encoded)
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to set secret: %w", err)
|
||||
|
|
|
|||
|
|
@ -100,6 +100,17 @@ func TestNewCmdSet(t *testing.T) {
|
|||
OrgName: "",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "env",
|
||||
cli: `cool_secret -b"a secret" -eRelease`,
|
||||
wants: SetOptions{
|
||||
SecretName: "cool_secret",
|
||||
Visibility: shared.Private,
|
||||
Body: "a secret",
|
||||
OrgName: "",
|
||||
EnvName: "Release",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "vis all",
|
||||
cli: `cool_secret --org coolOrg -b"cool" -vall`,
|
||||
|
|
@ -160,6 +171,7 @@ func TestNewCmdSet(t *testing.T) {
|
|||
assert.Equal(t, tt.wants.Body, gotOpts.Body)
|
||||
assert.Equal(t, tt.wants.Visibility, gotOpts.Visibility)
|
||||
assert.Equal(t, tt.wants.OrgName, gotOpts.OrgName)
|
||||
assert.Equal(t, tt.wants.EnvName, gotOpts.EnvName)
|
||||
assert.ElementsMatch(t, tt.wants.RepositoryNames, gotOpts.RepositoryNames)
|
||||
})
|
||||
}
|
||||
|
|
@ -204,6 +216,46 @@ func Test_setRun_repo(t *testing.T) {
|
|||
assert.Equal(t, payload.EncryptedValue, "UKYUCbHd0DJemxa3AOcZ6XcsBwALG9d4bpB8ZT0gSV39vl3BHiGSgj8zJapDxgB2BwqNqRhpjC4=")
|
||||
}
|
||||
|
||||
func Test_setRun_env(t *testing.T) {
|
||||
reg := &httpmock.Registry{}
|
||||
|
||||
reg.Register(httpmock.REST("GET", "repos/owner/repo/actions/secrets/public-key"),
|
||||
httpmock.JSONResponse(PubKey{ID: "123", Key: "CDjXqf7AJBXWhMczcy+Fs7JlACEptgceysutztHaFQI="}))
|
||||
|
||||
reg.Register(httpmock.REST("PUT", "repos/owner/repo/environments/development/secrets/cool_secret"), httpmock.StatusStringResponse(201, `{}`))
|
||||
|
||||
io, _, _, _ := iostreams.Test()
|
||||
|
||||
opts := &SetOptions{
|
||||
HttpClient: func() (*http.Client, error) {
|
||||
return &http.Client{Transport: reg}, nil
|
||||
},
|
||||
Config: func() (config.Config, error) { return config.NewBlankConfig(), nil },
|
||||
BaseRepo: func() (ghrepo.Interface, error) {
|
||||
return ghrepo.FromFullName("owner/repo")
|
||||
},
|
||||
EnvName: "development",
|
||||
IO: io,
|
||||
SecretName: "cool_secret",
|
||||
Body: "a secret",
|
||||
// Cribbed from https://github.com/golang/crypto/commit/becbf705a91575484002d598f87d74f0002801e7
|
||||
RandomOverride: bytes.NewReader([]byte{5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5}),
|
||||
}
|
||||
|
||||
err := setRun(opts)
|
||||
assert.NoError(t, err)
|
||||
|
||||
reg.Verify(t)
|
||||
|
||||
data, err := ioutil.ReadAll(reg.Requests[1].Body)
|
||||
assert.NoError(t, err)
|
||||
var payload SecretPayload
|
||||
err = json.Unmarshal(data, &payload)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, payload.KeyID, "123")
|
||||
assert.Equal(t, payload.EncryptedValue, "UKYUCbHd0DJemxa3AOcZ6XcsBwALG9d4bpB8ZT0gSV39vl3BHiGSgj8zJapDxgB2BwqNqRhpjC4=")
|
||||
}
|
||||
|
||||
func Test_setRun_org(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue