mirror of
https://github.com/tiennm99/goclaw.git
synced 2026-07-30 14:25:00 +00:00
123 lines
3.1 KiB
Go
123 lines
3.1 KiB
Go
package tools
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func envContains(env []string, key string) bool {
|
|
prefix := key + "="
|
|
for _, kv := range env {
|
|
if strings.HasPrefix(kv, prefix) {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func TestScrubCredentialEnv_StripsStatic(t *testing.T) {
|
|
in := []string{
|
|
"HOME=/root",
|
|
"GH_TOKEN=secret-abc",
|
|
"GOCLAW_GATEWAY_TOKEN=goclaw-secret",
|
|
"PATH=/usr/bin",
|
|
"AWS_SECRET_ACCESS_KEY=topsecret",
|
|
"RAPIDAPI_KEY=rapid-secret",
|
|
}
|
|
out := scrubCredentialEnv(in, nil)
|
|
|
|
if envContains(out, "GH_TOKEN") {
|
|
t.Fatalf("GH_TOKEN must be scrubbed, got: %v", out)
|
|
}
|
|
if envContains(out, "AWS_SECRET_ACCESS_KEY") {
|
|
t.Fatalf("AWS_SECRET_ACCESS_KEY must be scrubbed, got: %v", out)
|
|
}
|
|
if envContains(out, "RAPIDAPI_KEY") {
|
|
t.Fatalf("RAPIDAPI_KEY must be scrubbed, got: %v", out)
|
|
}
|
|
if envContains(out, "GOCLAW_GATEWAY_TOKEN") {
|
|
t.Fatalf("GOCLAW_GATEWAY_TOKEN must be scrubbed, got: %v", out)
|
|
}
|
|
if !envContains(out, "HOME") || !envContains(out, "PATH") {
|
|
t.Fatalf("essential vars must be preserved, got: %v", out)
|
|
}
|
|
}
|
|
|
|
func TestScrubCredentialEnv_StripsDynamic(t *testing.T) {
|
|
in := []string{
|
|
"HOME=/root",
|
|
"MY_CUSTOM_SECRET=hello",
|
|
"KEEP_ME=yes",
|
|
}
|
|
out := scrubCredentialEnv(in, []string{"MY_CUSTOM_SECRET"})
|
|
|
|
if envContains(out, "MY_CUSTOM_SECRET") {
|
|
t.Fatalf("MY_CUSTOM_SECRET must be scrubbed, got: %v", out)
|
|
}
|
|
if !envContains(out, "KEEP_ME") {
|
|
t.Fatalf("KEEP_ME must be preserved, got: %v", out)
|
|
}
|
|
}
|
|
|
|
func TestScrubCredentialEnv_PreservesEssentials(t *testing.T) {
|
|
in := []string{
|
|
"HOME=/root",
|
|
"PATH=/usr/bin",
|
|
"TERM=xterm",
|
|
"LANG=en_US.UTF-8",
|
|
"USER=alice",
|
|
"TZ=UTC",
|
|
}
|
|
out := scrubCredentialEnv(in, nil)
|
|
for _, k := range []string{"HOME", "PATH", "TERM", "LANG", "USER", "TZ"} {
|
|
if !envContains(out, k) {
|
|
t.Fatalf("expected %s preserved, got: %v", k, out)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestScrubCredentialEnv_PreservesUnrelated(t *testing.T) {
|
|
in := []string{
|
|
"FOO=bar",
|
|
"RANDOM_APP_FLAG=1",
|
|
"NPM_TOKEN=leakme", // static deny-list → should be scrubbed
|
|
}
|
|
out := scrubCredentialEnv(in, nil)
|
|
if !envContains(out, "FOO") {
|
|
t.Fatalf("FOO must be preserved, got: %v", out)
|
|
}
|
|
if !envContains(out, "RANDOM_APP_FLAG") {
|
|
t.Fatalf("RANDOM_APP_FLAG must be preserved, got: %v", out)
|
|
}
|
|
if envContains(out, "NPM_TOKEN") {
|
|
t.Fatalf("NPM_TOKEN must be scrubbed (static), got: %v", out)
|
|
}
|
|
}
|
|
|
|
// Basic smoke for the JSON key extractor used to feed dynamic keys.
|
|
func TestExtractJSONTopKeys_Simple(t *testing.T) {
|
|
keys := extractJSONTopKeys([]byte(`{"GH_TOKEN":"x","GH_CONFIG_DIR":"/tmp"}`))
|
|
if len(keys) != 2 {
|
|
t.Fatalf("expected 2 keys, got %d: %v", len(keys), keys)
|
|
}
|
|
want := map[string]bool{"GH_TOKEN": true, "GH_CONFIG_DIR": true}
|
|
for _, k := range keys {
|
|
if !want[k] {
|
|
t.Fatalf("unexpected key %q", k)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestExtractJSONTopKeys_NestedIgnored(t *testing.T) {
|
|
keys := extractJSONTopKeys([]byte(`{"A":{"nested":"v"},"B":"x"}`))
|
|
if len(keys) != 2 {
|
|
t.Fatalf("expected 2 top keys, got %d: %v", len(keys), keys)
|
|
}
|
|
}
|
|
|
|
func TestExtractJSONTopKeys_Malformed(t *testing.T) {
|
|
if keys := extractJSONTopKeys([]byte(`not json`)); keys != nil {
|
|
t.Fatalf("expected nil on malformed input, got %v", keys)
|
|
}
|
|
}
|