diff --git a/internal/cli/config_test.go b/internal/cli/config_test.go index d5c855206..97df88c74 100644 --- a/internal/cli/config_test.go +++ b/internal/cli/config_test.go @@ -104,6 +104,41 @@ func clearConfigEnv(t *testing.T) { } } +func TestRepoConfigBareEnvWildcardDoesNotForwardEveryLocalVariable(t *testing.T) { + clearConfigEnv(t) + home := t.TempDir() + repo := t.TempDir() + t.Setenv("HOME", home) + t.Setenv("XDG_CONFIG_HOME", filepath.Join(home, ".config")) + t.Setenv("CRABBOX_CONFIG", "") + t.Setenv("CRABBOX_PROVIDER", "") + t.Setenv("CRABBOX_DEFAULT_CLASS", "") + t.Setenv("CRABBOX_PROOF_API_TOKEN", "critical-secret-value") + cwd, err := os.Getwd() + if err != nil { + t.Fatal(err) + } + defer func() { + if err := os.Chdir(cwd); err != nil { + t.Fatal(err) + } + }() + if err := os.Chdir(repo); err != nil { + t.Fatal(err) + } + if err := os.WriteFile(".crabbox.yaml", []byte("env:\n allow:\n - '*'\n"), 0o600); err != nil { + t.Fatal(err) + } + + cfg, err := loadConfig() + if err != nil { + t.Fatal(err) + } + if got := allowedEnv(cfg.EnvAllow); got["CRABBOX_PROOF_API_TOKEN"] != "" { + t.Fatalf("bare wildcard forwarded proof secret: %q", got["CRABBOX_PROOF_API_TOKEN"]) + } +} + func TestLoadConfigFromUserFile(t *testing.T) { clearConfigEnv(t) home := t.TempDir() diff --git a/internal/cli/repo.go b/internal/cli/repo.go index 225572bef..f4f03d188 100644 --- a/internal/cli/repo.go +++ b/internal/cli/repo.go @@ -131,7 +131,11 @@ func envAllowed(name string, allow []string) bool { continue } if strings.HasSuffix(pattern, "*") { - if strings.HasPrefix(name, strings.TrimSuffix(pattern, "*")) { + prefix := strings.TrimSuffix(pattern, "*") + if prefix == "" { + continue + } + if strings.HasPrefix(name, prefix) { return true } continue diff --git a/internal/cli/ssh_test.go b/internal/cli/ssh_test.go index 882d0c681..3b4be6519 100644 --- a/internal/cli/ssh_test.go +++ b/internal/cli/ssh_test.go @@ -209,6 +209,18 @@ func TestEnvAllowlist(t *testing.T) { } } +func TestEnvAllowlistRejectsEmptyWildcardPrefix(t *testing.T) { + if envAllowed("CRABBOX_PROOF_API_TOKEN", []string{"*"}) { + t.Fatal("bare wildcard must not forward every local environment variable") + } + if envAllowed("CRABBOX_PROOF_API_TOKEN", []string{" * "}) { + t.Fatal("trimmed bare wildcard must not forward every local environment variable") + } + if !envAllowed("PROJECT_FLAG", []string{"PROJECT_*"}) { + t.Fatal("non-empty prefix wildcard should still work") + } +} + func TestSSHArgsIncludeReliabilityOptions(t *testing.T) { t.Setenv("HOME", "/tmp/crabbox-home") got := strings.Join(sshArgs(SSHTarget{