// Copyright (c) 2026 Lark Technologies Pte. Ltd. // SPDX-License-Identifier: MIT package publiccontent import ( "context" "os" "os/exec" "path/filepath" "strings" "testing" ) func TestCollectScansOnlyCurrentContributionAndMetadata(t *testing.T) { repo := t.TempDir() runGit(t, repo, "init") runGit(t, repo, "config", "user.email", "test@example.com") runGit(t, repo, "config", "user.name", "Test User") writeFile(t, filepath.Join(repo, "baseline.md"), `BASE_`+`TOKEN="baseline-only" `) runGit(t, repo, "add", "baseline.md") runGit(t, repo, "commit", "-m", "base") writeFile(t, filepath.Join(repo, "docs", "public.md"), `# Public change api_`+`key = "example-public-key" `) runGit(t, repo, "add", "docs/public.md") runGit(t, repo, "commit", "-m", "add public doc", "-m", "Change"+"-Id: I0123456789abcdef0123456789abcdef01234567") metadataPath := filepath.Join(repo, "pr-metadata.json") writeFile(t, metadataPath, `{"title":"publish public docs","body":"Reviewed`+`-on: https://review.example.test/c/project/+/123"}`) got, err := Collect(context.Background(), Options{ Repo: repo, ChangedFrom: "HEAD~1", MetadataPath: metadataPath, }) if err != nil { t.Fatalf("Collect() error = %v", err) } rules := findingRules(got) for _, want := range []string{ "public_content_generic_credential", "public_content_change_id_trailer", "public_content_reviewed_on_trailer", } { if !rules[want] { t.Fatalf("missing rule %s in findings %#v", want, got) } } for _, item := range got { if item.File == "baseline.md" { t.Fatalf("collector scanned unchanged baseline file: %#v", got) } } } func TestCollectScansOnlyChangedLinesInChangedFiles(t *testing.T) { repo := t.TempDir() runGit(t, repo, "init") runGit(t, repo, "config", "user.email", "test@example.com") runGit(t, repo, "config", "user.name", "Test User") writeFile(t, filepath.Join(repo, "docs", "workflow.md"), "SECRET_TOKEN=legacy-example\npublic baseline\n") runGit(t, repo, "add", "docs/workflow.md") runGit(t, repo, "commit", "-m", "base") writeFile(t, filepath.Join(repo, "docs", "workflow.md"), "SECRET_TOKEN=legacy-example\npublic baseline\nnew public line\n") runGit(t, repo, "add", "docs/workflow.md") runGit(t, repo, "commit", "-m", "add public line") metadataPath := filepath.Join(repo, "pr-metadata.json") writeFile(t, metadataPath, `{}`) got, err := Collect(context.Background(), Options{ Repo: repo, ChangedFrom: "HEAD~1", MetadataPath: metadataPath, }) if err != nil { t.Fatalf("Collect() error = %v", err) } for _, item := range got { if item.Rule == "public_content_generic_credential" && item.File == "docs/workflow.md" { t.Fatalf("collector scanned unchanged legacy line in changed file: %#v", got) } } } func TestCollectSemanticCandidatesStoreSanitizedReviewText(t *testing.T) { repo := t.TempDir() runGit(t, repo, "init") runGit(t, repo, "config", "user.email", "test@example.com") runGit(t, repo, "config", "user.name", "Test User") writeFile(t, filepath.Join(repo, "docs", "public.md"), "base\n") runGit(t, repo, "add", "docs/public.md") runGit(t, repo, "commit", "-m", "base") raw := "private launch plan for alpha-service rollout on Friday with SERVICE_" + "TOKEN=real-" + "secret-value" writeFile(t, filepath.Join(repo, "docs", "public.md"), "base\n"+raw+"\n") runGit(t, repo, "add", "docs/public.md") runGit(t, repo, "commit", "-m", "add semantic candidate") metadataPath := filepath.Join(repo, "pr-metadata.json") writeFile(t, metadataPath, `{}`) got, err := Collect(context.Background(), Options{ Repo: repo, ChangedFrom: "HEAD~1", MetadataPath: metadataPath, }) if err != nil { t.Fatalf("Collect() error = %v", err) } var found bool for _, item := range got { if item.Rule != "public_content_semantic_candidate" || item.File != "docs/public.md" { continue } found = true if !strings.Contains(item.Excerpt, "alpha-service rollout on Friday") { t.Fatalf("semantic candidate should include sanitized review text, got %#v", item) } if strings.Contains(item.Excerpt, "real-"+"secret-value") { t.Fatalf("semantic candidate leaked credential value: %#v", item) } if !strings.Contains(item.Excerpt, "SERVICE_TOKEN=") { t.Fatalf("semantic candidate should redact credentials in review text, got %#v", item) } if !strings.Contains(item.Excerpt, "semantic signals") || !strings.Contains(item.Excerpt, "roadmap_timing") { t.Fatalf("semantic candidate excerpt should preserve semantic signals, got %#v", item) } } if !found { t.Fatalf("missing semantic candidate in findings %#v", got) } } func TestCollectSemanticCandidatesDoNotLeakWhitespaceCredentialTail(t *testing.T) { repo := newGitRepo(t) writeFile(t, filepath.Join(repo, "docs", "public.md"), "base\n") runGit(t, repo, "add", "docs/public.md") runGit(t, repo, "commit", "-m", "base") raw := "private launch plan for internal rollout on Friday with SERVICE_" + "TOKEN=\"real " + "secret value\"" writeFile(t, filepath.Join(repo, "docs", "public.md"), "base\n"+raw+"\n") runGit(t, repo, "add", "docs/public.md") runGit(t, repo, "commit", "-m", "add semantic candidate") got := collectFromPreviousCommit(t, repo) for _, item := range got { if item.Rule != "public_content_semantic_candidate" || item.File != "docs/public.md" { continue } if strings.Contains(item.Excerpt, "secret value") || strings.Contains(item.Excerpt, "real "+"secret value") { t.Fatalf("semantic candidate leaked credential tail: %#v", item) } if !strings.Contains(item.Excerpt, "SERVICE_TOKEN=") { t.Fatalf("semantic candidate should redact full credential assignment, got %#v", item) } return } t.Fatalf("missing semantic candidate in findings %#v", got) } func TestCollectJSONBearerHeadersDoNotLeakIntoSemanticCandidates(t *testing.T) { repo := newGitRepo(t) writeFile(t, filepath.Join(repo, "docs", "public.md"), "base\n") runGit(t, repo, "add", "docs/public.md") runGit(t, repo, "commit", "-m", "base") token := "abcdefghijklmnopqrstuvwxyz" raw := "private launch plan for internal rollout on Friday with " + `{"headers":{"Authorization":"Bearer ` + token + `"}}` writeFile(t, filepath.Join(repo, "docs", "public.md"), "base\n"+raw+"\n") runGit(t, repo, "add", "docs/public.md") runGit(t, repo, "commit", "-m", "add json bearer") got := collectFromPreviousCommit(t, repo) requireFinding(t, got, "docs/public.md", "public_content_bearer_header") for _, item := range got { if item.File != "docs/public.md" { continue } if strings.Contains(item.Excerpt, token) { t.Fatalf("finding leaked JSON bearer token: %#v", item) } } } func TestCollectDetectsQuotedJSONCredentialAssignments(t *testing.T) { repo := newGitRepo(t) writeFile(t, filepath.Join(repo, "docs", "public.json"), "{}\n") runGit(t, repo, "add", "docs/public.json") runGit(t, repo, "commit", "-m", "base") writeFile(t, filepath.Join(repo, "docs", "public.json"), strings.Join([]string{ `{"access_` + `token":"real-json-token"}`, `{"client_` + `secret": "real ` + `secret value"}`, `{"tenantAccess` + `Token":"real-tenant-camel-token"}`, `{"github` + `Token":"real-github-token"}`, `{"vendorApi` + `Key":"real-vendor-key"}`, `{"slackBot` + `Token":"xoxb-real-token"}`, }, "\n")+"\n") runGit(t, repo, "add", "docs/public.json") runGit(t, repo, "commit", "-m", "add json config") got := collectFromPreviousCommit(t, repo) var count int for _, item := range got { if item.File == "docs/public.json" && item.Rule == "public_content_generic_credential" { count++ for _, forbidden := range []string{ "real-json-token", "real secret value", "real-tenant-camel-token", "real-github-token", "real-vendor-key", "xoxb-real-token", } { if strings.Contains(item.Excerpt, forbidden) { t.Fatalf("JSON credential finding leaked value %q in excerpt %q", forbidden, item.Excerpt) } } } } if count != 6 { t.Fatalf("JSON credential findings = %d, want 6: %#v", count, got) } } func TestCollectAllowsBenignJSONTokenFields(t *testing.T) { repo := newGitRepo(t) writeFile(t, filepath.Join(repo, "docs", "public.json"), "{}\n") runGit(t, repo, "add", "docs/public.json") runGit(t, repo, "commit", "-m", "base") writeFile(t, filepath.Join(repo, "docs", "public.json"), strings.Join([]string{ `{"tokenizer":"cl100k_base"}`, `{"token_count": 42}`, `{"page_token":"next"}`, `{"next_page_token":"next"}`, `{"file_token":"file-example"}`, `{"doc_token":"doc-example"}`, `{"node_token":"node-example"}`, `{"wiki_token":"wikcn_public_doc_example"}`, `{"folder_token":"folder-example"}`, `{"obj_token":"obj-example"}`, `{"spreadsheet_token":"sheet-example"}`, `{"parent_node_token":"parent-example"}`, `{"origin_node_token":"origin-example"}`, `{"drive_route_token":"route-example"}`, `{"token":""}`, `{"token":"wiki_token"}`, `{"token_url":"https://example.com/oauth/token"}`, `{"token_endpoint":"https://example.com/oauth/token"}`, `{"token_format":"Bearer"}`, `{"secret_name":"public-example-secret"}`, `{"base_token":"base-example"}`, `{"app_token":"app-example"}`, `{"sync_token":"sync-example"}`, `{"parent_token":"parent-example"}`, `{"target_token":"target-example"}`, `{"parent_file_token":"parent-file-example"}`, `{"refresh_token_expires_in": 7200}`, `{"access_token_expires_in": 7200}`, `{"token_expires_in": 7200}`, `{"token_status":"active"}`, }, "\n")+"\n") runGit(t, repo, "add", "docs/public.json") runGit(t, repo, "commit", "-m", "add benign json token fields") got := collectFromPreviousCommit(t, repo) for _, item := range got { if item.File == "docs/public.json" && item.Rule == "public_content_generic_credential" { t.Fatalf("benign JSON token field should not be credential finding: %#v", got) } } } func TestCollectDetectsAngleWrappedRealisticCredentialValues(t *testing.T) { repo := newGitRepo(t) writeFile(t, filepath.Join(repo, "docs", "config.yaml"), "base: true\n") runGit(t, repo, "add", "docs/config.yaml") runGit(t, repo, "commit", "-m", "base") stripeLike := "sk_" + "live_1234567890abcdef" patLike := "gh" + "p_1234567890abcdef1234567890abcdef1234" writeFile(t, filepath.Join(repo, "docs", "config.yaml"), strings.Join([]string{ "API_KEY: <" + stripeLike + ">", "SECRET_TOKEN: <" + patLike + ">", "CLIENT_SECRET: ", }, "\n")+"\n") runGit(t, repo, "add", "docs/config.yaml") runGit(t, repo, "commit", "-m", "add credential config") got := collectFromPreviousCommit(t, repo) var count int for _, item := range got { if item.File == "docs/config.yaml" && item.Rule == "public_content_generic_credential" { count++ } } if count != 3 { t.Fatalf("angle-wrapped realistic credential findings = %d, want 3: %#v", count, got) } } func TestCollectDetectsCredentialShapedValuesUnderBenignKeys(t *testing.T) { repo := newGitRepo(t) writeFile(t, filepath.Join(repo, "docs", "public.json"), "{}\n") runGit(t, repo, "add", "docs/public.json") runGit(t, repo, "commit", "-m", "base") stripeLike := "sk_" + "live_1234567890abcdef" patLike := "gh" + "p_1234567890abcdef1234567890abcdef1234" writeFile(t, filepath.Join(repo, "docs", "public.json"), strings.Join([]string{ `{"access_token_expires_in":"` + patLike + `"}`, `{"refresh_token_expires_in":"` + stripeLike + `"}`, `{"client_secret_status":"real-client-secret-value"}`, `{"client_secret_name":"real-client-secret-value"}`, `{"app_token":"` + patLike + `"}`, `{"sync_token":"` + stripeLike + `"}`, `{"target_token":"real-client-secret-value"}`, }, "\n")+"\n") runGit(t, repo, "add", "docs/public.json") runGit(t, repo, "commit", "-m", "add credential-shaped benign fields") got := collectFromPreviousCommit(t, repo) var count int for _, item := range got { if item.File == "docs/public.json" && item.Rule == "public_content_generic_credential" { count++ } } if count != 7 { t.Fatalf("credential-shaped benign-key findings = %d, want 7: %#v", count, got) } } func TestCollectDetectsBareIdentifierCredentialsWithMetadataSuffixes(t *testing.T) { repo := newGitRepo(t) writeFile(t, filepath.Join(repo, "docs", "config.yaml"), "base: true\n") runGit(t, repo, "add", "docs/config.yaml") runGit(t, repo, "commit", "-m", "base") writeFile(t, filepath.Join(repo, "docs", "config.yaml"), strings.Join([]string{ "API_KEY_NAME: prod_key", "CLIENT_SECRET_NAME: prod_secret", "SECRET_STATUS: prod_secret", }, "\n")+"\n") runGit(t, repo, "add", "docs/config.yaml") runGit(t, repo, "commit", "-m", "add credential config") got := collectFromPreviousCommit(t, repo) var count int for _, item := range got { if item.File == "docs/config.yaml" && item.Rule == "public_content_generic_credential" { count++ } } if count != 3 { t.Fatalf("metadata-suffixed bare credential findings = %d, want 3: %#v", count, got) } } func TestCollectDetectsAccessKeyCredentials(t *testing.T) { repo := newGitRepo(t) writeFile(t, filepath.Join(repo, "docs", "config.yaml"), "base: true\n") runGit(t, repo, "add", "docs/config.yaml") runGit(t, repo, "commit", "-m", "base") accessKey := "AK" + "IAIOSFODNN7EXAMPX" writeFile(t, filepath.Join(repo, "docs", "config.yaml"), strings.Join([]string{ "AWS_ACCESS_KEY_ID: " + accessKey, "ACCESS_KEY_ID: " + accessKey, "ACCESS_KEY: " + accessKey, }, "\n")+"\n") runGit(t, repo, "add", "docs/config.yaml") runGit(t, repo, "commit", "-m", "add access key config") got := collectFromPreviousCommit(t, repo) var count int for _, item := range got { if item.File != "docs/config.yaml" || item.Rule != "public_content_generic_credential" { continue } count++ if strings.Contains(item.Excerpt, "AKIAIOSFODNN7EXAMPX") { t.Fatalf("access key finding leaked value in excerpt %q", item.Excerpt) } } if count != 3 { t.Fatalf("access key credential findings = %d, want 3: %#v", count, got) } } func TestCollectDetectsPrivateKeyAssignments(t *testing.T) { repo := newGitRepo(t) writeFile(t, filepath.Join(repo, "docs", "config.yaml"), "base: true\n") runGit(t, repo, "add", "docs/config.yaml") runGit(t, repo, "commit", "-m", "base") privateKey := "LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0t" writeFile(t, filepath.Join(repo, "docs", "config.yaml"), strings.Join([]string{ "PRIVATE_KEY: " + privateKey, "SSH_PRIVATE_KEY: " + privateKey, "JWT_PRIVATE_KEY: " + privateKey, "SIGNING_PRIVATE_KEY: " + privateKey, }, "\n")+"\n") runGit(t, repo, "add", "docs/config.yaml") runGit(t, repo, "commit", "-m", "add private key config") got := collectFromPreviousCommit(t, repo) var count int for _, item := range got { if item.File != "docs/config.yaml" || item.Rule != "public_content_generic_credential" { continue } count++ if strings.Contains(item.Excerpt, privateKey) { t.Fatalf("private key finding leaked value in excerpt %q", item.Excerpt) } } if count != 4 { t.Fatalf("private key assignment findings = %d, want 4: %#v", count, got) } } func TestCollectDetectsCredentialValuesThatLookLikeBareIdentifiers(t *testing.T) { repo := newGitRepo(t) writeFile(t, filepath.Join(repo, "docs", "config.yaml"), "base: true\n") runGit(t, repo, "add", "docs/config.yaml") runGit(t, repo, "commit", "-m", "base") writeFile(t, filepath.Join(repo, "docs", "config.yaml"), strings.Join([]string{ "API_KEY_OPENAI: prod_key", "CLIENT_SECRET_GOOGLE: prod_secret", "TOKEN_GITHUB: github_token", "APP_PASSWORD_PROD: prod_password", }, "\n")+"\n") runGit(t, repo, "add", "docs/config.yaml") runGit(t, repo, "commit", "-m", "add credential config") got := collectFromPreviousCommit(t, repo) var count int for _, item := range got { if item.File == "docs/config.yaml" && item.Rule == "public_content_generic_credential" { count++ } } if count != 4 { t.Fatalf("bare identifier credential findings = %d, want 4: %#v", count, got) } } func TestCollectAllowsBenignUnquotedTokenFields(t *testing.T) { repo := newGitRepo(t) writeFile(t, filepath.Join(repo, "docs", "config.yaml"), "base: true\n") runGit(t, repo, "add", "docs/config.yaml") runGit(t, repo, "commit", "-m", "base") writeFile(t, filepath.Join(repo, "docs", "config.yaml"), strings.Join([]string{ "tokens: 128", "token_type: bearer", "max_tokens: 2000", "completion_tokens: 200", "prompt_tokens: 100", }, "\n")+"\n") runGit(t, repo, "add", "docs/config.yaml") runGit(t, repo, "commit", "-m", "add benign token config") got := collectFromPreviousCommit(t, repo) for _, item := range got { if item.File == "docs/config.yaml" && item.Rule == "public_content_generic_credential" { t.Fatalf("benign unquoted token field should not be credential finding: %#v", got) } } } func TestCollectDetectsCredentialPhraseBeforeEnvironmentSuffix(t *testing.T) { repo := newGitRepo(t) writeFile(t, filepath.Join(repo, "docs", "config.yaml"), "base: true\n") runGit(t, repo, "add", "docs/config.yaml") runGit(t, repo, "commit", "-m", "base") writeFile(t, filepath.Join(repo, "docs", "config.yaml"), strings.Join([]string{ "API_KEY_OPENAI: real-openai-key", "TOKEN_GITHUB: real-github-token", "CLIENT_SECRET_GOOGLE: real-google-secret", "SECRET_KEY_BASE: real-secret-key-base", "APP_PASSWORD_PROD: real-prod-password", }, "\n")+"\n") runGit(t, repo, "add", "docs/config.yaml") runGit(t, repo, "commit", "-m", "add credential config") got := collectFromPreviousCommit(t, repo) var count int for _, item := range got { if item.File != "docs/config.yaml" || item.Rule != "public_content_generic_credential" { continue } count++ for _, forbidden := range []string{ "real-openai-key", "real-github-token", "real-google-secret", "real-secret-key-base", "real-prod-password", } { if strings.Contains(item.Excerpt, forbidden) { t.Fatalf("credential finding leaked value %q in excerpt %q", forbidden, item.Excerpt) } } } if count != 5 { t.Fatalf("credential suffix variants findings = %d, want 5: %#v", count, got) } } func TestCollectDetectsPrivateKeyWhenOnlyEndIsAdded(t *testing.T) { repo := newGitRepo(t) writeFile(t, filepath.Join(repo, "docs", "key.pem"), privateKeyBegin()+"legacy-body\n") runGit(t, repo, "add", "docs/key.pem") runGit(t, repo, "commit", "-m", "base") writeFile(t, filepath.Join(repo, "docs", "key.pem"), privateKeyBegin()+"legacy-body\nnew-body\n"+privateKeyEnd()) runGit(t, repo, "add", "docs/key.pem") runGit(t, repo, "commit", "-m", "complete key") got := collectFromPreviousCommit(t, repo) requireFinding(t, got, "docs/key.pem", "public_content_private_key_block") } func TestCollectDetectsPrivateKeyWhenOnlyBeginIsAdded(t *testing.T) { repo := newGitRepo(t) writeFile(t, filepath.Join(repo, "docs", "key.pem"), "legacy-body\n"+privateKeyEnd()) runGit(t, repo, "add", "docs/key.pem") runGit(t, repo, "commit", "-m", "base") writeFile(t, filepath.Join(repo, "docs", "key.pem"), privateKeyBegin()+"legacy-body\n"+privateKeyEnd()) runGit(t, repo, "add", "docs/key.pem") runGit(t, repo, "commit", "-m", "complete key") got := collectFromPreviousCommit(t, repo) requireFinding(t, got, "docs/key.pem", "public_content_private_key_block") } func TestCollectDetectsPrivateKeyWhenOnlyBodyIsAdded(t *testing.T) { repo := newGitRepo(t) writeFile(t, filepath.Join(repo, "docs", "key.pem"), privateKeyBegin()+privateKeyEnd()) runGit(t, repo, "add", "docs/key.pem") runGit(t, repo, "commit", "-m", "base") writeFile(t, filepath.Join(repo, "docs", "key.pem"), privateKeyBegin()+"new-body\n"+privateKeyEnd()) runGit(t, repo, "add", "docs/key.pem") runGit(t, repo, "commit", "-m", "add body") got := collectFromPreviousCommit(t, repo) requireFinding(t, got, "docs/key.pem", "public_content_private_key_block") } func TestCollectIgnoresUntouchedHistoricalPrivateKey(t *testing.T) { repo := newGitRepo(t) writeFile(t, filepath.Join(repo, "docs", "key.pem"), privateKeyBegin()+"legacy-body\n"+privateKeyEnd()) runGit(t, repo, "add", "docs/key.pem") runGit(t, repo, "commit", "-m", "base") writeFile(t, filepath.Join(repo, "docs", "key.pem"), privateKeyBegin()+"legacy-body\n"+privateKeyEnd()) writeFile(t, filepath.Join(repo, "docs", "public.md"), "public docs update\n") runGit(t, repo, "add", "docs/public.md") runGit(t, repo, "commit", "-m", "docs update") got := collectFromPreviousCommit(t, repo) for _, item := range got { if item.File == "docs/key.pem" && item.Rule == "public_content_private_key_block" { t.Fatalf("collector reported untouched historical private key: %#v", got) } } } func TestCollectIgnoresDeletedPrivateKeyLine(t *testing.T) { repo := newGitRepo(t) writeFile(t, filepath.Join(repo, "docs", "key.pem"), privateKeyBegin()+"legacy-body\n"+privateKeyEnd()) runGit(t, repo, "add", "docs/key.pem") runGit(t, repo, "commit", "-m", "base") writeFile(t, filepath.Join(repo, "docs", "key.pem"), privateKeyBegin()+privateKeyEnd()) runGit(t, repo, "add", "docs/key.pem") runGit(t, repo, "commit", "-m", "remove body") got := collectFromPreviousCommit(t, repo) for _, item := range got { if item.File == "docs/key.pem" && item.Rule == "public_content_private_key_block" { t.Fatalf("collector reported delete-only private key cleanup: %#v", got) } } } func TestCollectSkipsOnlyKnownQualityGateFixtureFiles(t *testing.T) { repo := t.TempDir() runGit(t, repo, "init") runGit(t, repo, "config", "user.email", "test@example.com") runGit(t, repo, "config", "user.name", "Test User") writeFile(t, filepath.Join(repo, "README.md"), "base\n") runGit(t, repo, "add", "README.md") runGit(t, repo, "commit", "-m", "base") writeFile(t, filepath.Join(repo, "internal", "qualitygate", "publiccontent", "collect_test.go"), "SECRET_TOKEN=fixture\n") writeFile(t, filepath.Join(repo, "internal", "qualitygate", "publiccontent", "scan_test.go"), "SECRET_TOKEN=fixture\n") writeFile(t, filepath.Join(repo, "internal", "qualitygate", "publiccontent", "scan.go"), "const privateKeyFixture = \""+privateKeyBeginPrefix+privateKeyMarker+"\"\n") writeFile(t, filepath.Join(repo, "internal", "qualitygate", "publiccontent", "rules.go"), "markers := []string{\"generated with automation\"}\n") writeFile(t, filepath.Join(repo, "tests", "e2e", "new-public-workflow.test.sh"), "SECRET_TOKEN=real-leak\n") runGit(t, repo, "add", ".") runGit(t, repo, "commit", "-m", "add scanner fixtures") metadataPath := filepath.Join(repo, "pr-metadata.json") writeFile(t, metadataPath, `{}`) got, err := Collect(context.Background(), Options{ Repo: repo, ChangedFrom: "HEAD~1", MetadataPath: metadataPath, }) if err != nil { t.Fatalf("Collect() error = %v", err) } var foundOrdinaryTestLeak bool for _, item := range got { switch item.File { case "internal/qualitygate/publiccontent/collect_test.go", "internal/qualitygate/publiccontent/scan.go", "internal/qualitygate/publiccontent/scan_test.go", "internal/qualitygate/publiccontent/rules.go": t.Fatalf("collector scanned known fixture or detector implementation file: %#v", got) } if item.File == "tests/e2e/new-public-workflow.test.sh" && item.Rule == "public_content_generic_credential" { foundOrdinaryTestLeak = true } } if !foundOrdinaryTestLeak { t.Fatalf("collector should still scan ordinary test files for real leaks: %#v", got) } } func TestScanChangedFileDocumentsFixtureExclusions(t *testing.T) { excluded := []string{ "internal/qualitygate/publiccontent/collect_test.go", "internal/qualitygate/publiccontent/rules.go", "internal/qualitygate/publiccontent/scan.go", "internal/qualitygate/publiccontent/scan_test.go", } for _, file := range excluded { if scanChangedFile(file) { t.Fatalf("scanChangedFile(%q) = true, want false for detector fixture/implementation path", file) } } included := []string{ "internal/qualitygate/publiccontent/new_test.go", "tests/e2e/new-public-workflow.test.sh", "docs/public.md", } for _, file := range included { if !scanChangedFile(file) { t.Fatalf("scanChangedFile(%q) = false, want true", file) } } } func TestCollectScansAddedLinesInSpecialPathNames(t *testing.T) { repo := newGitRepo(t) writeFile(t, filepath.Join(repo, "docs", "old.md"), "base\n") runGit(t, repo, "add", ".") runGit(t, repo, "commit", "-m", "base") writeFile(t, filepath.Join(repo, "docs", "has space.md"), "SECRET_TOKEN=space-value\n") writeFile(t, filepath.Join(repo, `weird"quote.md`), "SECRET_TOKEN=quote-value\n") runGit(t, repo, "mv", "docs/old.md", "docs/new name.md") writeFile(t, filepath.Join(repo, "docs", "new name.md"), "base\nSECRET_TOKEN=rename-value\n") runGit(t, repo, "add", ".") runGit(t, repo, "commit", "-m", "add special paths") got := collectFromPreviousCommit(t, repo) requireFinding(t, got, "docs/has space.md", "public_content_generic_credential") requireFinding(t, got, `weird"quote.md`, "public_content_generic_credential") requireFinding(t, got, "docs/new name.md", "public_content_generic_credential") } func TestCollectScansBranchNameAsWarning(t *testing.T) { repo := t.TempDir() metadataPath := filepath.Join(repo, "pr-metadata.json") writeFile(t, metadataPath, `{"branch":"bot/public-doc-update"}`) got, err := Collect(context.Background(), Options{ Repo: repo, MetadataPath: metadataPath, }) if err != nil { t.Fatalf("Collect() error = %v", err) } if len(got) != 1 || got[0].Rule != "public_content_automation_branch" { t.Fatalf("branch findings = %#v", got) } } func TestCollectUsesExplicitBranchNameWhenDetached(t *testing.T) { repo := newGitRepo(t) writeFile(t, filepath.Join(repo, "README.md"), "base\n") runGit(t, repo, "add", "README.md") runGit(t, repo, "commit", "-m", "base") runGit(t, repo, "checkout", "-b", "bot/public-doc-update") writeFile(t, filepath.Join(repo, "docs.md"), "safe docs\n") runGit(t, repo, "add", "docs.md") runGit(t, repo, "commit", "-m", "docs") head := strings.TrimSpace(string(runGitOutput(t, repo, "rev-parse", "HEAD"))) runGit(t, repo, "checkout", "--detach", head) metadataPath := filepath.Join(repo, "pr-metadata.json") writeFile(t, metadataPath, `{}`) got, err := Collect(context.Background(), Options{ Repo: repo, MetadataPath: metadataPath, BranchName: "bot/public-doc-update", }) if err != nil { t.Fatalf("Collect() error = %v", err) } requireFinding(t, got, "branch", "public_content_automation_branch") } func TestCollectUsesBranchEnvironmentWhenDetached(t *testing.T) { repo := newGitRepo(t) writeFile(t, filepath.Join(repo, "README.md"), "base\n") runGit(t, repo, "add", "README.md") runGit(t, repo, "commit", "-m", "base") runGit(t, repo, "checkout", "-b", "bot/public-env-update") writeFile(t, filepath.Join(repo, "docs.md"), "safe docs\n") runGit(t, repo, "add", "docs.md") runGit(t, repo, "commit", "-m", "docs") head := strings.TrimSpace(string(runGitOutput(t, repo, "rev-parse", "HEAD"))) runGit(t, repo, "checkout", "--detach", head) t.Setenv("GITHUB_HEAD_REF", "bot/public-env-update") metadataPath := filepath.Join(repo, "pr-metadata.json") writeFile(t, metadataPath, `{}`) got, err := Collect(context.Background(), Options{ Repo: repo, MetadataPath: metadataPath, }) if err != nil { t.Fatalf("Collect() error = %v", err) } requireFinding(t, got, "branch", "public_content_automation_branch") } func TestCollectPreservesFindingAttributionForChangedLines(t *testing.T) { repo := newGitRepo(t) writeFile(t, filepath.Join(repo, "docs", "auth.md"), "intro\n") runGit(t, repo, "add", "docs/auth.md") runGit(t, repo, "commit", "-m", "base") writeFile(t, filepath.Join(repo, "docs", "auth.md"), "intro\nAuthorization: Bearer abcdefghijklmnopqrstuvwxyz\n") runGit(t, repo, "add", "docs/auth.md") runGit(t, repo, "commit", "-m", "add auth docs") got := collectFromPreviousCommit(t, repo) for _, item := range got { if item.Rule == "public_content_bearer_header" { if item.File != "docs/auth.md" || item.Line != 2 || item.Source != "file" { t.Fatalf("changed-line attribution = %#v", item) } return } } t.Fatalf("missing bearer finding: %#v", got) } func TestAppendUniqueFindingsDeduplicatesByRuleFileLineAndSource(t *testing.T) { base := []Finding{newFinding("public_content_private_key_block", "docs/key.pem", 1, "file", "private key block")} got := appendUniqueFindings(base, newFinding("public_content_private_key_block", "docs/key.pem", 1, "file", "private key block"), newFinding("public_content_private_key_block", "docs/key.pem", 2, "file", "private key block"), ) if len(got) != 2 { t.Fatalf("appendUniqueFindings len = %d, want 2: %#v", len(got), got) } } func newGitRepo(t *testing.T) string { t.Helper() repo := t.TempDir() runGit(t, repo, "init") runGit(t, repo, "config", "user.email", "test@example.com") runGit(t, repo, "config", "user.name", "Test User") return repo } func privateKeyBegin() string { return privateKeyBeginPrefix + privateKeyMarker + "\n" } func privateKeyEnd() string { return privateKeyEndPrefix + privateKeyMarker + "\n" } func collectFromPreviousCommit(t *testing.T, repo string) []Finding { t.Helper() metadataPath := filepath.Join(repo, "pr-metadata.json") writeFile(t, metadataPath, `{}`) got, err := Collect(context.Background(), Options{ Repo: repo, ChangedFrom: "HEAD~1", MetadataPath: metadataPath, }) if err != nil { t.Fatalf("Collect() error = %v", err) } return got } func requireFinding(t *testing.T, got []Finding, file, rule string) { t.Helper() for _, item := range got { if item.File == file && item.Rule == rule { return } } t.Fatalf("missing %s in %s findings: %#v", rule, file, got) } func TestCollectRequiresValidMetadataJSON(t *testing.T) { repo := t.TempDir() metadataPath := filepath.Join(repo, "pr-metadata.json") writeFile(t, metadataPath, `{"title":`) _, err := Collect(context.Background(), Options{Repo: repo, MetadataPath: metadataPath}) if err == nil || !strings.Contains(err.Error(), "public content metadata") { t.Fatalf("Collect() error = %v, want metadata parse error", err) } } func runGit(t *testing.T, repo string, args ...string) { t.Helper() if len(args) > 0 && args[0] == "commit" { args = append([]string{"commit", "--no-verify"}, args[1:]...) } cmd := exec.Command("git", args...) cmd.Dir = repo out, err := cmd.CombinedOutput() if err != nil { t.Fatalf("git %v failed: %v\n%s", args, err, out) } } func runGitOutput(t *testing.T, repo string, args ...string) []byte { t.Helper() cmd := exec.Command("git", args...) cmd.Dir = repo out, err := cmd.CombinedOutput() if err != nil { t.Fatalf("git %v failed: %v\n%s", args, err, out) } return out } func writeFile(t *testing.T, path, data string) { t.Helper() if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil { t.Fatal(err) } if err := os.WriteFile(path, []byte(data), 0o644); err != nil { t.Fatal(err) } }