Files
ARTEX/server/env_scrub_test.go
BaaRai 69831f5cdf fix(security): apply New options so the secret scrub actually runs
New accepted opts ...Option but never called them, so scrubSecrets stayed
false in the binary and ScrubSecretEnv was unreachable: the protection merged
in #136 never engaged. The unit test passed because it called the scrub
function directly instead of going through New.

Apply the options in the constructor and add a test that builds a Server
through New with WithSecretScrub and asserts the secrets are gone. Verified to
fail without the loop.
2026-11-03 23:47:49 +01:00

66 lines
1.8 KiB
Go

package server
import (
"context"
"os"
"os/exec"
"strings"
"testing"
)
// A child process spawned after startup must not see the startup secrets, while
// other variables still pass through.
func TestScrubSecretEnvHidesSecretsFromChildren(t *testing.T) {
sh, err := exec.LookPath("sh")
if err != nil {
t.Skip("no sh in PATH")
}
for _, k := range secretEnv {
t.Setenv(k, "leak-"+k)
}
t.Setenv("ARTEX_SCRUB_KEEP", "kept")
ScrubSecretEnv()
out, err := exec.Command(sh, "-c", "env").Output()
if err != nil {
t.Fatal(err)
}
env := "\n" + string(out)
for _, k := range secretEnv {
if strings.Contains(env, "\n"+k+"=") {
t.Errorf("%s still reaches child processes", k)
}
}
if !strings.Contains(env, "\nARTEX_SCRUB_KEEP=kept\n") {
t.Errorf("non-secret variable did not reach the child process")
}
}
// New must apply the options it receives. An earlier version accepted
// ...Option and never called them, so the binary kept the secrets in the
// environment while the unit test above still passed.
func TestNewAppliesSecretScrubOption(t *testing.T) {
// t.Setenv restores both after the test: the scrub unsets them for the rest
// of this process, and later tests still need the DSN.
if dsn := os.Getenv("ARTEX_PG_DSN"); dsn != "" {
t.Setenv("ARTEX_PG_DSN", dsn)
}
t.Setenv("ANTHROPIC_API_KEY", "scrub-probe")
t.Setenv("OPENAI_API_KEY", "scrub-probe")
m, err := NewManager(t.TempDir(), "")
if err != nil {
t.Skipf("no manager: %v", err)
}
t.Cleanup(func() { m.Close() })
ctx, cancel := context.WithCancel(context.Background())
cancel()
_ = New(ctx, m, t.TempDir(), t.TempDir(), t.TempDir(), WithSecretScrub())
if os.Getenv("ANTHROPIC_API_KEY") != "" || os.Getenv("OPENAI_API_KEY") != "" {
t.Fatal("New did not apply WithSecretScrub: the secrets are still in the environment")
}
}