Skip to content

Commit d55d686

Browse files
authored
chore: use user token for attestation commands (#1900)
Signed-off-by: Jose I. Paris <jiparis@chainloop.dev>
1 parent c3e699c commit d55d686

File tree

2 files changed

+46
-34
lines changed

2 files changed

+46
-34
lines changed

app/cli/cmd/attestation.go

-10
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,12 @@ package cmd
1717

1818
import (
1919
"fmt"
20-
"os"
2120
"strings"
2221

2322
"github.com/spf13/cobra"
2423
)
2524

2625
var (
27-
attAPIToken string
2826
useAttestationRemoteState bool
2927
attestationLocalStatePath string
3028
GracefulExit bool
@@ -57,14 +55,6 @@ func newAttestationCmd() *cobra.Command {
5755
},
5856
}
5957

60-
cmd.PersistentFlags().StringVarP(&attAPIToken, "token", "t", "", fmt.Sprintf("auth token. NOTE: You can also use the env variable %s", tokenEnvVarName))
61-
// We do not use viper in this case because we do not want this token to be saved in the config file
62-
// Instead we load the env variable manually
63-
if attAPIToken == "" {
64-
// Check first the new env variable
65-
attAPIToken = os.Getenv(tokenEnvVarName)
66-
}
67-
6858
cmd.PersistentFlags().Bool("remote-state", false, "Store the attestation state remotely (preview feature)")
6959
// We do not need this flag in all the attestation subcommands just in init, but we don't want to remove it to not to break current integrations
7060
cobra.CheckErr(cmd.PersistentFlags().MarkHidden("remote-state"))

app/cli/cmd/root.go

+46-24
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,11 @@ var (
4848
defaultCPAPI = "api.cp.chainloop.dev:443"
4949
defaultCASAPI = "api.cas.chainloop.dev:443"
5050
apiToken string
51+
flagYes bool
5152
)
5253

5354
const (
55+
// preference to use an API token if available
5456
useAPIToken = "withAPITokenAuth"
5557
appName = "chainloop"
5658
//nolint:gosec
@@ -60,6 +62,8 @@ const (
6062
apiTokenAudience = "api-token-auth.chainloop"
6163
// Follow the convention stated on https://consoledonottrack.com/
6264
doNotTrackEnv = "DO_NOT_TRACK"
65+
66+
trueString = "true"
6367
)
6468

6569
var telemetryWg sync.WaitGroup
@@ -108,7 +112,7 @@ func NewRootCmd(l zerolog.Logger) *cobra.Command {
108112
logger.Warn().Msg("API contacted in insecure mode")
109113
}
110114

111-
apiToken, err := loadControlplaneAuthToken(cmd)
115+
token, isUserToken, err := loadControlplaneAuthToken(cmd)
112116
if err != nil {
113117
return err
114118
}
@@ -124,8 +128,9 @@ func NewRootCmd(l zerolog.Logger) *cobra.Command {
124128
controlplaneURL := viper.GetString(confOptions.controlplaneAPI.viperKey)
125129

126130
// If no organization is set in local configuration, we load it from server and save it
127-
if viper.GetString(confOptions.organization.viperKey) == "" {
128-
conn, err := grpcconn.New(controlplaneURL, apiToken, opts...)
131+
orgName := viper.GetString(confOptions.organization.viperKey)
132+
if orgName == "" {
133+
conn, err := grpcconn.New(controlplaneURL, token, opts...)
129134
if err != nil {
130135
return err
131136
}
@@ -139,11 +144,19 @@ func NewRootCmd(l zerolog.Logger) *cobra.Command {
139144
}
140145

141146
// reload the connection now that we have the org name
142-
if orgName := viper.GetString(confOptions.organization.viperKey); orgName != "" {
147+
orgName = viper.GetString(confOptions.organization.viperKey)
148+
if orgName != "" {
143149
opts = append(opts, grpcconn.WithOrgName(orgName))
144150
}
145151

146-
conn, err := grpcconn.New(controlplaneURL, apiToken, opts...)
152+
// Warn users when the session is interactive, and the operation is supposed to use an API token instead
153+
if isAPITokenPreferred(cmd) && isUserToken && !flagYes {
154+
if !confirmationPrompt(fmt.Sprintf("This command is will run against the organization %q", orgName)) {
155+
return errors.New("command canceled by user")
156+
}
157+
}
158+
159+
conn, err := grpcconn.New(controlplaneURL, token, opts...)
147160
if err != nil {
148161
return err
149162
}
@@ -165,7 +178,7 @@ func NewRootCmd(l zerolog.Logger) *cobra.Command {
165178
go func() {
166179
// For telemetry reasons we parse the token to know the type of token is being used when executing the CLI
167180
// Once we have the token type we can send it to the telemetry service by injecting it on the context
168-
token, err := parseToken(apiToken)
181+
token, err := parseToken(token)
169182
if err != nil {
170183
logger.Debug().Err(err).Msg("parsing token for telemetry")
171184
return
@@ -229,6 +242,9 @@ func NewRootCmd(l zerolog.Logger) *cobra.Command {
229242
rootCmd.PersistentFlags().StringP(confOptions.organization.flagName, "n", "", "organization name")
230243
cobra.CheckErr(viper.BindPFlag(confOptions.organization.viperKey, rootCmd.PersistentFlags().Lookup(confOptions.organization.flagName)))
231244

245+
// Do not ask for confirmation
246+
rootCmd.PersistentFlags().BoolVarP(&flagYes, "yes", "y", false, "Skip confirmation")
247+
232248
rootCmd.AddCommand(newWorkflowCmd(), newAuthCmd(), NewVersionCmd(),
233249
newAttestationCmd(), newArtifactCmd(), newConfigCmd(),
234250
newIntegrationCmd(), newOrganizationCmd(), newCASBackendCmd(),
@@ -261,7 +277,7 @@ func init() {
261277

262278
// isTelemetryDisabled checks if the telemetry is disabled by the user or if we are running a development version
263279
func isTelemetryDisabled() bool {
264-
return os.Getenv(doNotTrackEnv) == "1" || os.Getenv(doNotTrackEnv) == "true" || Version == devVersion
280+
return os.Getenv(doNotTrackEnv) == "1" || os.Getenv(doNotTrackEnv) == trueString || Version == devVersion
265281
}
266282

267283
func initLogger(logger zerolog.Logger) (zerolog.Logger, error) {
@@ -334,36 +350,38 @@ func cleanup(conn *grpc.ClientConn) error {
334350
// 2.2 Load the token from the environment variable and from the auth login config file
335351
// 2.3 if they both exist, we default to the user token
336352
// 2.4 otherwise to the one that's set
337-
func loadControlplaneAuthToken(cmd *cobra.Command) (string, error) {
338-
// If the CMD uses a robot account instead of the regular auth token we override it
339-
if _, ok := cmd.Annotations[useAPIToken]; ok {
340-
if attAPIToken == "" {
341-
return "", newGracefulError(ErrAttestationTokenRequired)
342-
}
353+
func loadControlplaneAuthToken(cmd *cobra.Command) (string, bool, error) {
354+
// Load the APIToken from the env variable
355+
apiTokenFromVar := os.Getenv(tokenEnvVarName)
343356

344-
return attAPIToken, nil
357+
// Load the user token from the config file
358+
userToken := viper.GetString(confOptions.authToken.viperKey)
359+
360+
apiTokenFromFlagOrVar := apiToken
361+
if apiTokenFromFlagOrVar == "" {
362+
apiTokenFromFlagOrVar = apiTokenFromVar
363+
}
364+
365+
// Prefer to use the API token if the command can use it, and it's provided (i.e. attestations)
366+
if isAPITokenPreferred(cmd) && apiTokenFromFlagOrVar != "" {
367+
return apiTokenFromFlagOrVar, false, nil
345368
}
346369

347370
// Now we check explicitly provided API token via the flag
348371
if apiToken != "" {
349372
logger.Info().Msg("API token provided to the command line")
350-
return apiToken, nil
373+
return apiToken, false, nil
351374
}
352375

353-
// Load the user token from the config file
354-
userToken := viper.GetString(confOptions.authToken.viperKey)
355-
// Load the APIToken from the env variable
356-
// Instead we load the env variable manually
357-
apiTokenFromVar := os.Getenv(tokenEnvVarName)
358-
// If both the user authentication and the API token are set, we default to user authentication
376+
// If both the user authentication and the API token en var are set, we default to user authentication
359377
if userToken != "" && apiTokenFromVar != "" {
360378
logger.Warn().Msgf("Both user credentials and $%s set. Ignoring $%s.", tokenEnvVarName, tokenEnvVarName)
361-
return userToken, nil
379+
return userToken, true, nil
362380
} else if apiTokenFromVar != "" {
363-
return apiTokenFromVar, nil
381+
return apiTokenFromVar, false, nil
364382
}
365383

366-
return userToken, nil
384+
return userToken, true, nil
367385
}
368386

369387
// parseToken the token and return the type of token. At the moment in Chainloop we have 3 types of tokens:
@@ -499,3 +517,7 @@ func setLocalOrganization(orgName string) error {
499517
viper.Set(confOptions.organization.viperKey, orgName)
500518
return viper.WriteConfig()
501519
}
520+
521+
func isAPITokenPreferred(cmd *cobra.Command) bool {
522+
return cmd.Annotations[useAPIToken] == trueString
523+
}

0 commit comments

Comments
 (0)