github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/worker/uniter/runner/jujuc/secret-add_test.go (about)

     1  // Copyright 2021 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package jujuc_test
     5  
     6  import (
     7  	"os"
     8  	"path/filepath"
     9  	"time"
    10  
    11  	"github.com/juju/cmd/v3"
    12  	"github.com/juju/cmd/v3/cmdtesting"
    13  	"github.com/juju/names/v5"
    14  	"github.com/juju/testing"
    15  	jc "github.com/juju/testing/checkers"
    16  	gc "gopkg.in/check.v1"
    17  
    18  	coresecrets "github.com/juju/juju/core/secrets"
    19  	"github.com/juju/juju/worker/uniter/runner/jujuc"
    20  )
    21  
    22  type SecretAddSuite struct {
    23  	ContextSuite
    24  }
    25  
    26  var _ = gc.Suite(&SecretAddSuite{})
    27  
    28  func (s *SecretAddSuite) TestAddSecretInvalidArgs(c *gc.C) {
    29  	hctx, _ := s.ContextSuite.NewHookContext()
    30  
    31  	for _, t := range []struct {
    32  		args []string
    33  		err  string
    34  	}{
    35  		{
    36  			args: []string{},
    37  			err:  "ERROR missing secret value or filename",
    38  		}, {
    39  			args: []string{"s3cret"},
    40  			err:  `ERROR key value "s3cret" not valid`,
    41  		}, {
    42  			args: []string{"foo=bar", "--rotate", "foo"},
    43  			err:  `ERROR rotate policy "foo" not valid`,
    44  		}, {
    45  			args: []string{"foo=bar", "--owner", "foo"},
    46  			err:  `ERROR secret owner "foo" not valid`,
    47  		}, {
    48  			args: []string{"foo=bar", "--expire", "-1h"},
    49  			err:  `ERROR negative expire duration "-1h" not valid`,
    50  		}, {
    51  			args: []string{"foo=bar", "--expire", "2022-01-01"},
    52  			err:  `ERROR expire time or duration "2022-01-01" not valid`,
    53  		},
    54  	} {
    55  		com, err := jujuc.NewCommand(hctx, "secret-add")
    56  		c.Assert(err, jc.ErrorIsNil)
    57  		ctx := cmdtesting.Context(c)
    58  		code := cmd.Main(jujuc.NewJujucCommandWrappedForTest(com), ctx, t.args)
    59  
    60  		c.Assert(code, gc.Equals, 2)
    61  		c.Assert(bufferString(ctx.Stderr), gc.Equals, t.err+"\n")
    62  	}
    63  }
    64  
    65  func ptr[T any](v T) *T {
    66  	return &v
    67  }
    68  
    69  func (s *SecretAddSuite) TestAddSecretExpireDuration(c *gc.C) {
    70  	hctx, _ := s.ContextSuite.NewHookContext()
    71  
    72  	com, err := jujuc.NewCommand(hctx, "secret-add")
    73  	c.Assert(err, jc.ErrorIsNil)
    74  
    75  	expectedExpiry := time.Now().Add(time.Hour)
    76  	ctx := cmdtesting.Context(c)
    77  	code := cmd.Main(jujuc.NewJujucCommandWrappedForTest(com), ctx, []string{
    78  		"--rotate", "daily", "--expire", "1h",
    79  		"--description", "sssshhhh",
    80  		"--label", "foobar",
    81  		"data=secret",
    82  	})
    83  
    84  	c.Assert(code, gc.Equals, 0)
    85  	val := coresecrets.NewSecretValue(map[string]string{"data": "c2VjcmV0"})
    86  	expectedArgs := &jujuc.SecretCreateArgs{
    87  		SecretUpdateArgs: jujuc.SecretUpdateArgs{
    88  			Value:        val,
    89  			RotatePolicy: ptr(coresecrets.RotateDaily),
    90  			Description:  ptr("sssshhhh"),
    91  			Label:        ptr("foobar"),
    92  		},
    93  		OwnerTag: names.NewApplicationTag("u"),
    94  	}
    95  	s.Stub.CheckCallNames(c, "UnitName", "CreateSecret")
    96  	call := s.Stub.Calls()[1]
    97  	c.Assert(call.Args, gc.HasLen, 1)
    98  	args, ok := call.Args[0].(*jujuc.SecretCreateArgs)
    99  	c.Assert(ok, jc.IsTrue)
   100  	c.Assert(args.ExpireTime, gc.NotNil)
   101  	c.Assert(args.ExpireTime.After(expectedExpiry), jc.IsTrue)
   102  	args.ExpireTime = nil
   103  	c.Assert(args, jc.DeepEquals, expectedArgs)
   104  	c.Assert(bufferString(ctx.Stdout), gc.Equals, "secret:9m4e2mr0ui3e8a215n4g\n")
   105  }
   106  
   107  func (s *SecretAddSuite) TestAddSecretExpireTimestamp(c *gc.C) {
   108  	hctx, _ := s.ContextSuite.NewHookContext()
   109  
   110  	com, err := jujuc.NewCommand(hctx, "secret-add")
   111  	c.Assert(err, jc.ErrorIsNil)
   112  
   113  	ctx := cmdtesting.Context(c)
   114  	code := cmd.Main(jujuc.NewJujucCommandWrappedForTest(com), ctx, []string{
   115  		"--rotate", "daily", "--expire", "2022-03-04T06:06:06",
   116  		"--description", "sssshhhh",
   117  		"--label", "foobar",
   118  		"data=secret",
   119  	})
   120  
   121  	c.Assert(code, gc.Equals, 0)
   122  	val := coresecrets.NewSecretValue(map[string]string{"data": "c2VjcmV0"})
   123  	expectedExpiry, err := time.Parse("2006-01-02T15:04:05", "2022-03-04T06:06:06")
   124  	c.Assert(err, jc.ErrorIsNil)
   125  	args := &jujuc.SecretCreateArgs{
   126  		SecretUpdateArgs: jujuc.SecretUpdateArgs{
   127  			Value:        val,
   128  			RotatePolicy: ptr(coresecrets.RotateDaily),
   129  			Description:  ptr("sssshhhh"),
   130  			Label:        ptr("foobar"),
   131  			ExpireTime:   ptr(expectedExpiry),
   132  		},
   133  		OwnerTag: names.NewApplicationTag("u"),
   134  	}
   135  	s.Stub.CheckCalls(c, []testing.StubCall{{FuncName: "UnitName"}, {FuncName: "CreateSecret", Args: []interface{}{args}}})
   136  	c.Assert(bufferString(ctx.Stdout), gc.Equals, "secret:9m4e2mr0ui3e8a215n4g\n")
   137  }
   138  
   139  func (s *SecretAddSuite) TestAddSecretBase64(c *gc.C) {
   140  	hctx, _ := s.ContextSuite.NewHookContext()
   141  
   142  	com, err := jujuc.NewCommand(hctx, "secret-add")
   143  	c.Assert(err, jc.ErrorIsNil)
   144  	ctx := cmdtesting.Context(c)
   145  	code := cmd.Main(jujuc.NewJujucCommandWrappedForTest(com), ctx, []string{"token#base64=key=", "--owner", "unit"})
   146  
   147  	c.Assert(code, gc.Equals, 0)
   148  	val := coresecrets.NewSecretValue(map[string]string{"token": "key="})
   149  	args := &jujuc.SecretCreateArgs{
   150  		SecretUpdateArgs: jujuc.SecretUpdateArgs{
   151  			Value: val,
   152  		},
   153  		OwnerTag: names.NewUnitTag("u/0"),
   154  	}
   155  	s.Stub.CheckCalls(c, []testing.StubCall{{FuncName: "UnitName"}, {FuncName: "CreateSecret", Args: []interface{}{args}}})
   156  	c.Assert(bufferString(ctx.Stdout), gc.Equals, "secret:9m4e2mr0ui3e8a215n4g\n")
   157  }
   158  
   159  func (s *SecretAddSuite) TestAddSecretFromFile(c *gc.C) {
   160  	data := `
   161      key: |-
   162        secret
   163      another-key: !!binary |
   164        R0lGODlhDAAMAIQAAP//9/X17unp5WZmZgAAAOfn515eXvPz7Y6OjuDg4J+fn5
   165        OTk6enp56enmlpaWNjY6Ojo4SEhP/++f/++f/++f/++f/++f/++f/++f/++f/+
   166        +f/++f/++f/++f/++f/++SH+Dk1hZGUgd2l0aCBHSU1QACwAAAAADAAMAAAFLC
   167        AgjoEwnuNAFOhpEMTRiggcz4BNJHrv/zCFcLiwMWYNG84BwwEeECcgggoBADs=`
   168  
   169  	dir := c.MkDir()
   170  	fileName := filepath.Join(dir, "secret.yaml")
   171  	err := os.WriteFile(fileName, []byte(data), os.FileMode(0644))
   172  	c.Assert(err, jc.ErrorIsNil)
   173  
   174  	hctx, _ := s.ContextSuite.NewHookContext()
   175  	com, err := jujuc.NewCommand(hctx, "secret-add")
   176  	c.Assert(err, jc.ErrorIsNil)
   177  	ctx := cmdtesting.Context(c)
   178  	code := cmd.Main(jujuc.NewJujucCommandWrappedForTest(com), ctx, []string{"token#base64=key=", "--file", fileName})
   179  
   180  	c.Assert(code, gc.Equals, 0)
   181  	val := coresecrets.NewSecretValue(map[string]string{
   182  		"token":       "key=",
   183  		"key":         "c2VjcmV0",
   184  		"another-key": `R0lGODlhDAAMAIQAAP//9/X17unp5WZmZgAAAOfn515eXvPz7Y6OjuDg4J+fn5OTk6enp56enmlpaWNjY6Ojo4SEhP/++f/++f/++f/++f/++f/++f/++f/++f/++f/++f/++f/++f/++f/++SH+Dk1hZGUgd2l0aCBHSU1QACwAAAAADAAMAAAFLCAgjoEwnuNAFOhpEMTRiggcz4BNJHrv/zCFcLiwMWYNG84BwwEeECcgggoBADs=`,
   185  	})
   186  	args := &jujuc.SecretCreateArgs{
   187  		SecretUpdateArgs: jujuc.SecretUpdateArgs{
   188  			Value: val,
   189  		},
   190  		OwnerTag: names.NewApplicationTag("u"),
   191  	}
   192  	s.Stub.CheckCalls(c, []testing.StubCall{{FuncName: "UnitName"}, {FuncName: "CreateSecret", Args: []interface{}{args}}})
   193  	c.Assert(bufferString(ctx.Stdout), gc.Equals, "secret:9m4e2mr0ui3e8a215n4g\n")
   194  }