Ctrl K
ComunidadGuías…

internal/mcp/redact_test.go

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
package mcp

import (
	"strings"
	"testing"

	"github.com/sophotechlabs/spinoza/internal/api"
)

func TestWhichNamesReadAsSecrets(t *testing.T) {
	cases := []struct {
		name  string
		field string
		want  bool
	}{
		{name: "a password", field: "PASSWORD", want: true},
		{name: "an api key", field: "api_key", want: true},
		{name: "a bearer token", field: "AUTH_TOKEN", want: true},
		{name: "a connection string", field: "DB_CONNECTION_STRING", want: true},
		{name: "a private key", field: "tls.private_key", want: true},
		{name: "a plain setting", field: "LOG_LEVEL", want: false},
		{name: "a port", field: "HTTP_PORT", want: false},
		{name: "nothing", field: "", want: false},
	}
	for _, tc := range cases {
		t.Run(tc.name, func(t *testing.T) {
			if got := looksSecret(tc.field); got != tc.want {
				t.Fatalf("looksSecret(%q) = %v, want %v", tc.field, got, tc.want)
			}
		})
	}
}

func TestScrubbingALine(t *testing.T) {
	awsAccessKey := "AKIA" + strings.Repeat("1", 16)
	stripeToken := "sk_" + "live_" + "1234567890abcdef"
	cases := []struct {
		name string
		line string
		gone string
		kept string
	}{
		{
			name: "a bearer token",
			line: "GET /v1 Authorization: Bearer abcdef0123456789abcdef",
			gone: "abcdef0123456789abcdef",
			kept: "GET /v1",
		},
		{
			name: "a jwt",
			line: "session=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9 opened",
			gone: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9",
			kept: "opened",
		},
		{
			name: "a password assignment",
			line: "connecting with password=hunter2000 to db",
			gone: "hunter2000",
			kept: "connecting with",
		},
		{
			name: "a token in json",
			line: `{"api_token": "s3cr3t-value-here", "level": "info"}`,
			gone: "s3cr3t-value-here",
			kept: "info",
		},
		{
			name: "a private key block",
			line: pemFixture(),
			gone: "MIIabc",
			kept: "",
		},
		{
			name: "a long base64 blob",
			line: "payload " + strings.Repeat("QUJDRA", 9),
			gone: strings.Repeat("QUJDRA", 9),
			kept: "payload",
		},
		{
			name: "a standalone github token",
			line: "clone failed for ghp_1234567890abcdefghijklmnopqrstuvwxyz",
			gone: "ghp_1234567890abcdefghijklmnopqrstuvwxyz",
			kept: "clone failed",
		},
		{
			name: "a standalone slack token",
			line: "slack rejected xoxb-1234567890-abcdefghijklmnop",
			gone: "xoxb-1234567890-abcdefghijklmnop",
			kept: "slack rejected",
		},
		{
			name: "a standalone stripe token",
			line: "stripe rejected " + stripeToken,
			gone: stripeToken,
			kept: "stripe rejected",
		},
		{
			name: "a standalone gitlab token",
			line: "gitlab rejected glpat-1234567890abcdef",
			gone: "glpat-1234567890abcdef",
			kept: "gitlab rejected",
		},
		{
			name: "a standalone aws access key",
			line: "aws rejected " + awsAccessKey,
			gone: awsAccessKey,
			kept: "aws rejected",
		},
		{
			name: "a standalone google api key",
			line: "google rejected AIza1234567890abcdefghijklmn",
			gone: "AIza1234567890abcdefghijklmn",
			kept: "google rejected",
		},
		{
			name: "a standalone sendgrid token",
			line: "sendgrid rejected SG.1234567890ab.abcdefghijklmnop",
			gone: "SG.1234567890ab.abcdefghijklmnop",
			kept: "sendgrid rejected",
		},
	}
	for _, tc := range cases {
		t.Run(tc.name, func(t *testing.T) {
			result := scrub(tc.line)
			if strings.Contains(result, tc.gone) {
				t.Fatalf("scrub kept %q in %q", tc.gone, result)
			}
			if tc.kept != "" && !strings.Contains(result, tc.kept) {
				t.Fatalf("scrub lost %q from %q", tc.kept, result)
			}
			if !strings.Contains(result, hidden) {
				t.Fatalf("scrub removed the value without saying so: %q", result)
			}
		})
	}
}

func pemFixture() string {
	head := "-----BEGIN RSA " + "PRIVATE KEY-----"
	return head + "\nMIIabc\n" + strings.Replace(head, "BEGIN", "END", 1)
}

func TestScrubbingLeavesOrdinaryTextAlone(t *testing.T) {
	line := "listening on 127.0.0.1:34115, 3 workers, level=info"

	if got := scrub(line); got != line {
		t.Fatalf("scrub changed a line with no secret in it:\n got %q\nwant %q", got, line)
	}
	if got := scrub(""); got != "" {
		t.Fatalf("scrub of nothing = %q", got)
	}
}

func TestEveryLineIsScrubbed(t *testing.T) {
	result := scrubLines([]string{"password=letmein1", "all good"})

	if strings.Contains(result[0], "letmein1") {
		t.Fatalf("the first line kept its secret: %q", result[0])
	}
	if result[1] != "all good" {
		t.Fatalf("the second line changed: %q", result[1])
	}
}

func TestASecretGivesUpKeysAndSizesOnly(t *testing.T) {
	entries := []api.DataEntry{
		{Key: "password", Value: "hunter2", Bytes: 7},
		{Key: "keystore", Value: "AAEC", Bytes: 3, Binary: true},
	}

	result := keysOnly(entries)

	expected := []dataKey{
		{Key: "password", Bytes: 7},
		{Key: "keystore", Bytes: 3, Binary: true},
	}
	if len(result) != len(expected) {
		t.Fatalf("keys = %v, want %v", result, expected)
	}
	for i, want := range expected {
		if result[i] != want {
			t.Fatalf("key %d = %+v, want %+v", i, result[i], want)
		}
	}
}

func TestTheRawDocumentIsWithheldForASecretAndScrubbedOtherwise(t *testing.T) {
	document := "apiVersion: v1\ndata:\n  password: aHVudGVyMg==\n"

	if got := safeYAML("Secret", document); got != "" {
		t.Fatalf("a Secret gave up its document: %q", got)
	}
	scrubbed := safeYAML("ConfigMap", "env:\n  - name: TOKEN\n    value: not-a-real-value\n")
	if strings.Contains(scrubbed, "not-a-real-value") {
		t.Fatalf("a ConfigMap document kept a token: %q", scrubbed)
	}
	plain := safeYAML("Deployment", "spec:\n  replicas: 3\n")
	if plain != "spec:\n  replicas: 3\n" {
		t.Fatalf("an ordinary document was altered: %q", plain)
	}
}

func TestOnlySecretsCarrySecrets(t *testing.T) {
	if !carriesSecrets("Secret") {
		t.Fatal("a Secret must be treated as carrying secrets")
	}
	if carriesSecrets("ConfigMap") {
		t.Fatal("a ConfigMap is not withheld; its values are not secret by kind")
	}
}

func TestScrubbingNestedYAML(t *testing.T) {
	cases := []struct {
		name string
		body string
		gone string
	}{
		{
			name: "a nested token",
			body: "auth:\n  token: not-a-real-value\n",
			gone: "not-a-real-value",
		},
		{
			name: "an env pair across two lines",
			body: "env:\n  - name: DB_PASSWORD\n    value: hunter2000\n",
			gone: "hunter2000",
		},
		{
			name: "an env pair with a quoted name",
			body: `env:` + "\n" + `  - name: "API_TOKEN"` + "\n" + `    value: not-a-real-value` + "\n",
			gone: "not-a-real-value",
		},
	}
	for _, tc := range cases {
		t.Run(tc.name, func(t *testing.T) {
			if got := scrub(tc.body); strings.Contains(got, tc.gone) {
				t.Fatalf("scrub kept %q in %q", tc.gone, got)
			}
		})
	}
}

func TestStructuredUnknownCredentialFieldsAreRedacted(t *testing.T) {
	body := `ordinary: visible
nested:
  license: license-value
  key: key-value
  url: https://user:[email protected]/path
  cookie: cookie-value
  code: authorization-code
`

	got := scrubStructuredYAML(body)

	for _, secret := range []string{
		"license-value",
		"key-value",
		"https://user:[email protected]/path",
		"cookie-value",
		"authorization-code",
	} {
		if strings.Contains(got, secret) {
			t.Fatalf("structured output kept %q in %q", secret, got)
		}
	}
	if !strings.Contains(got, "ordinary: visible") {
		t.Fatalf("ordinary field was lost: %q", got)
	}
	if strings.Count(got, hidden) != 5 {
		t.Fatalf("redactions = %d, want 5 in %q", strings.Count(got, hidden), got)
	}
}

func TestAnEnvPairWithAnInnocentNameSurvives(t *testing.T) {
	body := "env:\n  - name: LOG_LEVEL\n    value: debug\n"

	if got := scrub(body); got != body {
		t.Fatalf("scrub changed an ordinary env pair:\n got %q\nwant %q", got, body)
	}
}

func TestAParentKeyIsNotMistakenForAValue(t *testing.T) {
	body := "auth:\n  mode: oidc\n"

	if got := scrub(body); !strings.Contains(got, "mode: oidc") {
		t.Fatalf("scrub ate a value that is not a secret: %q", got)
	}
}

func TestLabelsAreScrubbedLikeEverythingElse(t *testing.T) {
	result := scrubMap(map[string]string{
		"app":          "web",
		"auth-token":   "not-a-real-value",
		"release-note": "deployed with password=letmein1",
	})

	if result["app"] != "web" {
		t.Fatalf("an ordinary label changed: %q", result["app"])
	}
	if result["auth-token"] != hidden {
		t.Fatalf("a secret-shaped label kept its value: %q", result["auth-token"])
	}
	if strings.Contains(result["release-note"], "letmein1") {
		t.Fatalf("a label value kept a secret: %q", result["release-note"])
	}
	if scrubMap(nil) != nil {
		t.Fatal("no labels became an empty map rather than nothing")
	}
}