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

     1  // Copyright 2021 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package jujuc
     5  
     6  import (
     7  	"github.com/juju/cmd/v3"
     8  	"github.com/juju/errors"
     9  	"github.com/juju/gnuflag"
    10  	"github.com/juju/names/v5"
    11  
    12  	jujucmd "github.com/juju/juju/cmd"
    13  	"github.com/juju/juju/core/secrets"
    14  )
    15  
    16  type secretGrantCommand struct {
    17  	cmd.CommandBase
    18  	ctx Context
    19  
    20  	secretURI *secrets.URI
    21  	app       string
    22  	unit      string
    23  	relation  string
    24  
    25  	relationId      int
    26  	relationIdProxy gnuflag.Value
    27  }
    28  
    29  // NewSecretGrantCommand returns a command to grant access to a secret.
    30  func NewSecretGrantCommand(ctx Context) (cmd.Command, error) {
    31  	cmd := &secretGrantCommand{ctx: ctx}
    32  	var err error
    33  	cmd.relationIdProxy, err = NewRelationIdValue(ctx, &cmd.relationId)
    34  	if err != nil {
    35  		return nil, errors.Trace(err)
    36  	}
    37  	return cmd, nil
    38  }
    39  
    40  // Info implements cmd.Command.
    41  func (c *secretGrantCommand) Info() *cmd.Info {
    42  	doc := `
    43  Grant access to view the value of a specified secret.
    44  Access is granted in the context of a relation - unless revoked
    45  earlier, once the relation is removed, so too is the access grant.
    46  
    47  By default, all units of the related application are granted access.
    48  Optionally specify a unit name to limit access to just that unit.
    49  
    50  Examples:
    51      secret-grant secret:9m4e2mr0ui3e8a215n4g -r 0 --unit mediawiki/6
    52      secret-grant secret:9m4e2mr0ui3e8a215n4g --relation db:2
    53  `
    54  	return jujucmd.Info(&cmd.Info{
    55  		Name:    "secret-grant",
    56  		Args:    "<ID>",
    57  		Purpose: "grant access to a secret",
    58  		Doc:     doc,
    59  	})
    60  }
    61  
    62  // SetFlags implements cmd.Command.
    63  func (c *secretGrantCommand) SetFlags(f *gnuflag.FlagSet) {
    64  	f.StringVar(&c.unit, "unit", "", "the unit to grant access")
    65  	f.Var(c.relationIdProxy, "r", "the relation with which to associate the grant")
    66  	f.Var(c.relationIdProxy, "relation", "the relation with which to associate the grant")
    67  }
    68  
    69  // Init implements cmd.Command.
    70  func (c *secretGrantCommand) Init(args []string) error {
    71  	if len(args) < 1 {
    72  		return errors.New("missing secret URI")
    73  	}
    74  	var err error
    75  	if c.secretURI, err = secrets.ParseURI(args[0]); err != nil {
    76  		return errors.Trace(err)
    77  	}
    78  	if c.relationId == -1 {
    79  		return errors.Errorf("no relation id specified")
    80  	}
    81  	r, err := c.ctx.Relation(c.relationId)
    82  	if err != nil {
    83  		return errors.Trace(err)
    84  	}
    85  	c.relation = r.RelationTag().Id()
    86  	c.app = r.RemoteApplicationName()
    87  	if c.unit != "" {
    88  		if !names.IsValidUnit(c.unit) {
    89  			return errors.NotValidf("unit %q", c.unit)
    90  		}
    91  		appNameForUnit, _ := names.UnitApplication(c.unit)
    92  		if appNameForUnit != c.app {
    93  			return errors.Errorf("cannot specify unit %q in relation to application %q", c.unit, c.app)
    94  		}
    95  	}
    96  	return cmd.CheckEmpty(args[1:])
    97  }
    98  
    99  // Run implements cmd.Command.
   100  func (c *secretGrantCommand) Run(_ *cmd.Context) error {
   101  	args := &SecretGrantRevokeArgs{
   102  		RelationKey: &c.relation,
   103  	}
   104  	if c.unit != "" {
   105  		args.UnitName = &c.unit
   106  	}
   107  	if c.app != "" {
   108  		args.ApplicationName = &c.app
   109  	}
   110  
   111  	return c.ctx.GrantSecret(c.secretURI, args)
   112  }