Skip to content

Commit d78aa2b

Browse files
authored
feat(cli): add support for env vars (#1274)
Signed-off-by: Miguel Martinez <[email protected]>
1 parent a37eb86 commit d78aa2b

File tree

4 files changed

+45
-20
lines changed

4 files changed

+45
-20
lines changed

Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -52,4 +52,4 @@ build_devel:
5252
.PHONY: build_devel_container_mages
5353
# build container images for development testing
5454
build_devel_container_mages:
55-
goreleaser release --clean --snapshot --skip-sign --skip-sbom
55+
goreleaser release --clean --snapshot --skip sign,sbom

app/cli/Dockerfile.goreleaser

+2
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
FROM golang:1.22@sha256:fcae9e0e7313c6467a7c6632ebb5e5fab99bd39bd5eb6ee34a211353e647827a AS builder
2+
RUN mkdir -p /.config/chainloop
23

34
FROM scratch
45

56
COPY ./chainloop /
67
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
8+
COPY --from=builder --chown=1001:1001 /.config/chainloop /.config/chainloop
79

810
USER 1001
911

app/cli/cmd/config.go

+4-1
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,11 @@ import (
2121

2222
// Map of all the possible configuration options that we expect viper to handle
2323
var confOptions = struct {
24-
authToken, controlplaneAPI, CASAPI, controlplaneCA, CASCA *confOpt
24+
authToken, controlplaneAPI, CASAPI, controlplaneCA, CASCA, insecure *confOpt
2525
}{
26+
insecure: &confOpt{
27+
viperKey: "api-insecure",
28+
},
2629
authToken: &confOpt{
2730
viperKey: "auth.token",
2831
},

app/cli/cmd/root.go

+38-18
Original file line numberDiff line numberDiff line change
@@ -70,22 +70,26 @@ type parsedToken struct {
7070
tokenType string
7171
}
7272

73+
// Environment variable prefix for vipers
74+
const envPrefix = "CHAINLOOP"
75+
7376
func NewRootCmd(l zerolog.Logger) *cobra.Command {
7477
rootCmd := &cobra.Command{
7578
Use: appName,
7679
Short: "Chainloop Command Line Interface",
7780
SilenceErrors: true,
7881
SilenceUsage: true,
7982
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
80-
logger.Debug().Str("path", viper.ConfigFileUsed()).Msg("using config file")
81-
8283
var err error
8384
logger, err = initLogger(l)
8485
if err != nil {
8586
return err
8687
}
8788

88-
if flagInsecure {
89+
logger.Debug().Str("path", viper.ConfigFileUsed()).Msg("using config file")
90+
91+
insecure := viper.GetBool(confOptions.insecure.viperKey)
92+
if insecure {
8993
logger.Warn().Msg("API contacted in insecure mode")
9094
}
9195

@@ -95,14 +99,15 @@ func NewRootCmd(l zerolog.Logger) *cobra.Command {
9599
}
96100

97101
var opts = []grpcconn.Option{
98-
grpcconn.WithInsecure(flagInsecure),
102+
grpcconn.WithInsecure(insecure),
99103
}
100104

101105
if caFilePath := viper.GetString(confOptions.controlplaneCA.viperKey); caFilePath != "" {
102106
opts = append(opts, grpcconn.WithCAFile(caFilePath))
103107
}
104108

105-
conn, err := grpcconn.New(viper.GetString(confOptions.controlplaneAPI.viperKey), apiToken, opts...)
109+
controlplaneURL := viper.GetString(confOptions.controlplaneAPI.viperKey)
110+
conn, err := grpcconn.New(controlplaneURL, apiToken, opts...)
106111
if err != nil {
107112
return err
108113
}
@@ -158,25 +163,28 @@ func NewRootCmd(l zerolog.Logger) *cobra.Command {
158163

159164
rootCmd.PersistentFlags().StringVarP(&flagCfgFile, "config", "c", "", "Path to an existing config file (default is $HOME/.config/chainloop/config.toml)")
160165

161-
rootCmd.PersistentFlags().String(confOptions.controlplaneAPI.flagName, defaultCPAPI, "URL for the Control Plane API")
162-
err := viper.BindPFlag(confOptions.controlplaneAPI.viperKey, rootCmd.PersistentFlags().Lookup(confOptions.controlplaneAPI.flagName))
163-
cobra.CheckErr(err)
166+
rootCmd.PersistentFlags().String(confOptions.controlplaneAPI.flagName, defaultCPAPI, fmt.Sprintf("URL for the Control Plane API ($%s)", calculateEnvVarName(confOptions.controlplaneAPI.viperKey)))
167+
cobra.CheckErr(viper.BindPFlag(confOptions.controlplaneAPI.viperKey, rootCmd.PersistentFlags().Lookup(confOptions.controlplaneAPI.flagName)))
168+
cobra.CheckErr(viper.BindEnv(confOptions.controlplaneAPI.viperKey, calculateEnvVarName(confOptions.controlplaneAPI.viperKey)))
164169

165170
// Custom CAs for the control plane
166-
rootCmd.PersistentFlags().String(confOptions.controlplaneCA.flagName, "", "CUSTOM CA file for the Control Plane API (optional)")
167-
err = viper.BindPFlag(confOptions.controlplaneCA.viperKey, rootCmd.PersistentFlags().Lookup(confOptions.controlplaneCA.flagName))
168-
cobra.CheckErr(err)
171+
rootCmd.PersistentFlags().String(confOptions.controlplaneCA.flagName, "", fmt.Sprintf("CUSTOM CA file for the Control Plane API (optional) ($%s)", calculateEnvVarName(confOptions.controlplaneCA.viperKey)))
172+
cobra.CheckErr(viper.BindPFlag(confOptions.controlplaneCA.viperKey, rootCmd.PersistentFlags().Lookup(confOptions.controlplaneCA.flagName)))
173+
cobra.CheckErr(viper.BindEnv(confOptions.controlplaneCA.viperKey, calculateEnvVarName(confOptions.controlplaneCA.viperKey)))
169174

170-
rootCmd.PersistentFlags().String(confOptions.CASAPI.flagName, defaultCASAPI, "URL for the Artifacts Content Addressable Storage (CAS)")
171-
err = viper.BindPFlag(confOptions.CASAPI.viperKey, rootCmd.PersistentFlags().Lookup(confOptions.CASAPI.flagName))
172-
cobra.CheckErr(err)
175+
rootCmd.PersistentFlags().String(confOptions.CASAPI.flagName, defaultCASAPI, fmt.Sprintf("URL for the Artifacts Content Addressable Storage API ($%s)", calculateEnvVarName(confOptions.CASAPI.viperKey)))
176+
cobra.CheckErr(viper.BindPFlag(confOptions.CASAPI.viperKey, rootCmd.PersistentFlags().Lookup(confOptions.CASAPI.flagName)))
177+
cobra.CheckErr(viper.BindEnv(confOptions.CASAPI.viperKey, calculateEnvVarName(confOptions.CASAPI.viperKey)))
173178

174179
// Custom CAs for the CAS
175-
rootCmd.PersistentFlags().String(confOptions.CASCA.flagName, "", "CUSTOM CA file for the Artifacts CAS API (optional)")
176-
err = viper.BindPFlag(confOptions.CASCA.viperKey, rootCmd.PersistentFlags().Lookup(confOptions.CASCA.flagName))
177-
cobra.CheckErr(err)
180+
rootCmd.PersistentFlags().String(confOptions.CASCA.flagName, "", fmt.Sprintf("CUSTOM CA file for the Artifacts CAS API (optional) ($%s)", calculateEnvVarName(confOptions.CASCA.viperKey)))
181+
cobra.CheckErr(viper.BindPFlag(confOptions.CASCA.viperKey, rootCmd.PersistentFlags().Lookup(confOptions.CASCA.flagName)))
182+
cobra.CheckErr(viper.BindEnv(confOptions.CASCA.viperKey, calculateEnvVarName(confOptions.CASCA.viperKey)))
183+
184+
rootCmd.PersistentFlags().BoolVarP(&flagInsecure, "insecure", "i", false, fmt.Sprintf("Skip TLS transport during connection to the control plane ($%s)", calculateEnvVarName(confOptions.insecure.viperKey)))
185+
cobra.CheckErr(viper.BindPFlag(confOptions.insecure.viperKey, rootCmd.PersistentFlags().Lookup("insecure")))
186+
cobra.CheckErr(viper.BindEnv(confOptions.insecure.viperKey, calculateEnvVarName(confOptions.insecure.viperKey)))
178187

179-
rootCmd.PersistentFlags().BoolVarP(&flagInsecure, "insecure", "i", false, "Skip TLS transport during connection to the control plane")
180188
rootCmd.PersistentFlags().BoolVar(&flagDebug, "debug", false, "Enable debug/verbose logging mode")
181189
rootCmd.PersistentFlags().StringVarP(&flagOutputFormat, "output", "o", "table", "Output format, valid options are json and table")
182190

@@ -192,6 +200,18 @@ func NewRootCmd(l zerolog.Logger) *cobra.Command {
192200
return rootCmd
193201
}
194202

203+
// this could have been done using automatic + prefix but we want to have control and know the values
204+
//
205+
// viper.AutomaticEnv()
206+
// viper.SetEnvPrefix(envPrefix)
207+
// viper.SetEnvKeyReplacer(strings.NewReplacer("-", "_", ".", "_"))
208+
func calculateEnvVarName(key string) string {
209+
// replace - with _ and . with _
210+
s := strings.ReplaceAll(key, "-", "_")
211+
s = strings.ReplaceAll(s, ".", "_")
212+
return fmt.Sprintf("%s_%s", envPrefix, strings.ToUpper(s))
213+
}
214+
195215
func init() {
196216
cobra.OnInitialize(initConfigFile)
197217
// Using the cobra.OnFinalize because the hooks don't work on error

0 commit comments

Comments
 (0)