From 3af5b9cfff03b27cb3ef5f0c795ae147a09ad5d9 Mon Sep 17 00:00:00 2001 From: Jacobo de Vera Date: Sun, 17 May 2026 22:39:08 +0100 Subject: [PATCH 1/6] Delete dead helper.ReadPassword Zero callers across the tree. cmd/login.go reads passwords directly with terminal.ReadPassword and uses appCtx.PasswordEnvVar() for the non-interactive override; this helper was superseded scaffolding. Removes the hardcoded CDT_JENKINS_PASSWORD literal from scope. --- internal/helper/password.go | 17 ----------------- 1 file changed, 17 deletions(-) delete mode 100644 internal/helper/password.go diff --git a/internal/helper/password.go b/internal/helper/password.go deleted file mode 100644 index 22e204b..0000000 --- a/internal/helper/password.go +++ /dev/null @@ -1,17 +0,0 @@ -package helper - -import ( - "os" - "syscall" - - "golang.org/x/crypto/ssh/terminal" -) - -func ReadPassword() ([]byte, error) { - passwd := os.Getenv("CDT_JENKINS_PASSWORD") - if passwd != "" { - return []byte(passwd), nil - } - - return terminal.ReadPassword(int(syscall.Stdin)) -} From 852f785ae1cbaeb85456924872c1ee03914dee1c Mon Sep 17 00:00:00 2001 From: Jacobo de Vera Date: Sun, 17 May 2026 22:39:49 +0100 Subject: [PATCH 2/6] Read debug flags from _DEBUG_FLAGS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit helper.LoadDebugFlags and helper.HasDebugFlag were reading the hardcoded CDT_DEBUG_FLAGS literal, contradicting the context's DebugFlagsEnvVar() method that was supposed to be the source of truth for the env var name. Route both reads through appCtx.DebugFlagsEnvVar() (returns _DEBUG_FLAGS — e.g. COLA_DEBUG_FLAGS for the cola binary). Fall back to an empty string when no context is initialised, so early bootstrap paths don't crash. --- internal/helper/debug-flag.go | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/internal/helper/debug-flag.go b/internal/helper/debug-flag.go index 584580c..5a1fac1 100644 --- a/internal/helper/debug-flag.go +++ b/internal/helper/debug-flag.go @@ -3,6 +3,8 @@ package helper import ( "os" "strings" + + "github.com/jdevera/command-launcher/internal/context" ) const ( @@ -13,15 +15,23 @@ const ( ) type DebugFlags struct { - ForceSelfUpdate bool // Force the self update of the CDT + ForceSelfUpdate bool // Force the self update of the launcher NoMergeStatusCheck bool // do not check merge status when querying merged changes in gerrit ShowCmdExecStdout bool // always show cmd exec stdout to console UseFileVault bool // use file vault instead of system vault } +func debugFlagsString() string { + ctx, err := context.AppContext() + if err != nil { + return "" + } + return os.Getenv(ctx.DebugFlagsEnvVar()) +} + // load all debug flags into DebugFlags struct func LoadDebugFlags() DebugFlags { - flagsString := os.Getenv("CDT_DEBUG_FLAGS") + flagsString := debugFlagsString() flags := strings.Split(flagsString, ",") debugFlags := DebugFlags{} for _, flag := range flags { @@ -41,7 +51,7 @@ func LoadDebugFlags() DebugFlags { // check if a debug flag exists func HasDebugFlag(name string) bool { - flagsString := os.Getenv("CDT_DEBUG_FLAGS") + flagsString := debugFlagsString() if flagsString == "" { return false } From 633a209d5e7d75a242f2156ecf4cba5b88b8fcf7 Mon Sep 17 00:00:00 2001 From: Jacobo de Vera Date: Sun, 17 May 2026 22:41:21 +0100 Subject: [PATCH 3/6] Read vault secrets from _VAULT_SECRET[_FILE] readSecret() was reading hardcoded CDT_VAULT_SECRET and CDT_VAULT_SECRET_FILE literals. Vault state is per-launcher (the file vault directory and cache live under the per-app tree), so the env vars that unlock that state should match the launcher the user is invoking, not stay frozen on the upstream CDT prefix. Add VaultSecretEnvVar() and VaultSecretFileEnvVar() to LauncherContext; route the two reads through them. For the cola binary the names become COLA_VAULT_SECRET and COLA_VAULT_SECRET_FILE. file-vault_test.go now initialises the context once via TestMain- style init() with appName "testvault" so the derived env var is a stable TESTVAULT_VAULT_SECRET that all three tests can target. --- internal/context/context.go | 4 ++++ internal/context/default-context.go | 8 ++++++++ internal/gvault/file-vault.go | 11 +++++++++-- internal/gvault/file-vault_test.go | 14 +++++++++++--- 4 files changed, 32 insertions(+), 5 deletions(-) diff --git a/internal/context/context.go b/internal/context/context.go index db291d8..31047ed 100644 --- a/internal/context/context.go +++ b/internal/context/context.go @@ -29,6 +29,10 @@ type LauncherContext interface { FullCmdNameEnvVar() string + VaultSecretEnvVar() string + + VaultSecretFileEnvVar() string + /* General function to get a environment variable name with prefix conventions */ EnvVarName(name string) string } diff --git a/internal/context/default-context.go b/internal/context/default-context.go index 23b47ac..bf76c45 100644 --- a/internal/context/default-context.go +++ b/internal/context/default-context.go @@ -86,6 +86,14 @@ func (ctx *defaultContext) FullCmdNameEnvVar() string { return ctx.EnvVarName("FULL_COMMAND_NAME") } +func (ctx *defaultContext) VaultSecretEnvVar() string { + return ctx.EnvVarName("VAULT_SECRET") +} + +func (ctx *defaultContext) VaultSecretFileEnvVar() string { + return ctx.EnvVarName("VAULT_SECRET_FILE") +} + func (ctx *defaultContext) EnvVarName(name string) string { return fmt.Sprintf("%s_%s", ctx.prefix(), name) } diff --git a/internal/gvault/file-vault.go b/internal/gvault/file-vault.go index b98e0b4..26cf68a 100644 --- a/internal/gvault/file-vault.go +++ b/internal/gvault/file-vault.go @@ -11,6 +11,8 @@ import ( "io/ioutil" "os" "path/filepath" + + "github.com/jdevera/command-launcher/internal/context" ) type Dico map[string]string @@ -153,8 +155,13 @@ func (fv *FileVault) encrypt(data []byte) ([]byte, error) { } func readSecret() ([]byte, error) { + ctx, err := context.AppContext() + if err != nil { + return []byte{}, err + } + // first get the secret from environment variable - secret := os.Getenv("CDT_VAULT_SECRET") + secret := os.Getenv(ctx.VaultSecretEnvVar()) if secret != "" { hash := sha256.Sum256([]byte(secret)) return hash[:], nil @@ -173,7 +180,7 @@ func readSecret() ([]byte, error) { } // get the secret file from environment variable - secretFile := os.Getenv("CDT_VAULT_SECRET_FILE") + secretFile := os.Getenv(ctx.VaultSecretFileEnvVar()) if secretFile == "" { secretFile = filepath.Join(sshDir, "id_rsa") } diff --git a/internal/gvault/file-vault_test.go b/internal/gvault/file-vault_test.go index f777d99..4d3f066 100644 --- a/internal/gvault/file-vault_test.go +++ b/internal/gvault/file-vault_test.go @@ -3,10 +3,18 @@ package vault import ( "fmt" "testing" + + "github.com/jdevera/command-launcher/internal/context" ) +func init() { + context.InitContext("testvault", "1.0.0", "1") +} + +const vaultSecretEnv = "TESTVAULT_VAULT_SECRET" + func TestVault_Init(t *testing.T) { - t.Setenv("CDT_VAULT_SECRET", "very_secret") + t.Setenv(vaultSecretEnv, "very_secret") _, err := CreateVault("unit-test") if err != nil { @@ -15,7 +23,7 @@ func TestVault_Init(t *testing.T) { } func TestVault_WriteRead(t *testing.T) { - t.Setenv("CDT_VAULT_SECRET", "very_secret") + t.Setenv(vaultSecretEnv, "very_secret") fv, err := CreateVault("unit-test") if err != nil { @@ -38,7 +46,7 @@ func TestVault_WriteRead(t *testing.T) { } func TestVault_MultiWriteRead(t *testing.T) { - t.Setenv("CDT_VAULT_SECRET", "very_secret") + t.Setenv(vaultSecretEnv, "very_secret") fv, err := CreateVault("unit-test") if err != nil { From 358d66a440fb237d8a68601e8f63473fe824e990 Mon Sep 17 00:00:00 2001 From: Jacobo de Vera Date: Sun, 17 May 2026 22:41:53 +0100 Subject: [PATCH 4/6] Drop CDT_VAULT_SECRET from workflow env block Vault tests now own their env var lifecycle via t.Setenv against a known-initialised context (TESTVAULT_VAULT_SECRET), so no test relies on an inherited shell variable any more. The hardcoded CDT_* literal here was the last reference to the upstream prefix in CI. --- .github/workflows/go.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 034eef7..78c17af 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -7,9 +7,6 @@ on: pull_request: branches: [ 'main', 'v*.*.*', 'remote-registry' ] -env: - CDT_VAULT_SECRET: very_secret - jobs: build: runs-on: ${{ matrix.os }} From 1099b25f729c646d32b75f16dbda9e9778690ebe Mon Sep 17 00:00:00 2001 From: Jacobo de Vera Date: Sun, 17 May 2026 22:49:27 +0100 Subject: [PATCH 5/6] Make consent test self-contained on vault secret TestAccessConsents flows through helper.SetSecret, which on Linux runners always picks the file vault. Vault init calls readSecret(), which after the env-var split looks up the per-app _VAULT_SECRET. The test was previously relying on the workflow's CDT_VAULT_SECRET env block to satisfy that read; with that env block gone in Bundle 4 the test crashed on CI runners that have no ~/.ssh fallback. Set the env var explicitly via t.Setenv, keyed off the context's own VaultSecretEnvVar() so the test stays correct if the derivation rule changes. Also switch the appName from "test-vault" to "testconsent" so the derived env var name has no dash. --- cmd/consent/consent_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cmd/consent/consent_test.go b/cmd/consent/consent_test.go index 5ae8a57..acffafe 100644 --- a/cmd/consent/consent_test.go +++ b/cmd/consent/consent_test.go @@ -9,7 +9,8 @@ import ( func TestAccessConsents(t *testing.T) { // TODO: we shouldn't let the secret lib depends on the context - context.InitContext("test-vault", "1.0.0", "1") + ctx := context.InitContext("testconsent", "1.0.0", "1") + t.Setenv(ctx.VaultSecretEnvVar(), "very_secret") err := saveCmdConsents("dev-group", "test-cmd", []string{ "USERNAME", "PASSWORD", "LOG_LEVEL", From 248e2723dbc4ff3a06c5533e3dc958877460a3b1 Mon Sep 17 00:00:00 2001 From: Jacobo de Vera Date: Sun, 17 May 2026 22:52:47 +0100 Subject: [PATCH 6/6] Set CL_VAULT_SECRET in integration test runner MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The integration test binary builds with appName=cl, so after the env-var split the file vault now reads CL_VAULT_SECRET rather than the inherited CDT_VAULT_SECRET from the workflow env. CI runners have no ~/.ssh fallback, so without the env var being set, every helper.GetSecret/SetSecret call on Linux fails — which broke test-consent, test-manifest, test-template and the new test-workspace suites once the workflow env block went away. Set CL_VAULT_SECRET in the test runner itself so the integration tests are self-contained on this dimension regardless of how CI is configured. Safe on macOS / Windows where keyring is preferred. --- test/integration.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/integration.sh b/test/integration.sh index fafaaf1..2e90550 100755 --- a/test/integration.sh +++ b/test/integration.sh @@ -25,6 +25,9 @@ go build -o $OUTPUT_DIR/cl -ldflags='-X main.version=integration-test -X main.bu # specify the app home export CL_HOME=$OUTPUT_DIR/home +# unlock the file vault without depending on ~/.ssh existing (CI runners don't have one) +export CL_VAULT_SECRET=very_secret + if [ $# -ne 0 ]; then # in case pass test as arguments, run test from the arguments for test in "$@"; do