Claude (review-harness setup) f3ee4722a8 Phase A + B (MVP) — local review harness
Implements the MVP cutline from the planning artifact:
- Phase A: skeleton + CLI dispatch + provider interface + stub model doctor
- Phase B: scanner + git probe + 12 static analyzers + reporters + pipeline
- Phase B fixtures: clean-repo, insecure-repo, degraded-repo

12 static analyzers per PROMPT.md "Suggested Static Checks For MVP":
hardcoded_paths, shell_execution, raw_sql_interpolation, broad_cors,
secret_patterns, large_files, todo_comments, missing_tests,
env_file_committed, unsafe_file_io, exposed_mutation_endpoint,
hardcoded_local_ip.

Acceptance gates passing:
- B1 (intake produces accurate counts) ✓
- B2 (insecure fixture fires ≥8 distinct check_ids — actually 11/12) ✓
- B3 (clean fixture produces 0 confirmed findings — no false positives) ✓
- B4 (scrum mode produces all 6 required markdown + JSON reports) ✓
- B5 (receipts.json marks degraded phases honestly) ✓
- F  (self-review on this repo runs without crashing) ✓ — exit 66 (degraded
  because Phase C LLM review is hardcoded skipped)

Phases C (LLM review), D (validation cross-check), E (memory + diff +
rules subcommands) deferred per the cutline. The MVP delivers the
evidence-first path; LLM is purely additive.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-30 00:56:02 -05:00

67 lines
1.3 KiB
Go

package scanner
import (
"path/filepath"
"strings"
)
// detectLanguage returns a best-effort language label based on the
// file extension. Empty string for unknown — the caller treats those
// as opaque and may still scan them for patterns.
func detectLanguage(filename string) string {
switch strings.ToLower(filepath.Ext(filename)) {
case ".go":
return "Go"
case ".rs":
return "Rust"
case ".ts", ".tsx":
return "TypeScript"
case ".js", ".jsx", ".mjs", ".cjs":
return "JavaScript"
case ".py":
return "Python"
case ".java":
return "Java"
case ".kt":
return "Kotlin"
case ".rb":
return "Ruby"
case ".php":
return "PHP"
case ".swift":
return "Swift"
case ".c", ".h":
return "C"
case ".cpp", ".cc", ".cxx", ".hpp":
return "C++"
case ".cs":
return "C#"
case ".sh", ".bash":
return "Shell"
case ".sql":
return "SQL"
case ".yaml", ".yml":
return "YAML"
case ".toml":
return "TOML"
case ".json":
return "JSON"
case ".md", ".markdown":
return "Markdown"
case ".html", ".htm":
return "HTML"
case ".css", ".scss", ".sass", ".less":
return "CSS"
}
// Special filenames without extensions
switch strings.ToLower(filename) {
case "dockerfile", "containerfile":
return "Docker"
case "makefile", "gnumakefile":
return "Make"
case "justfile":
return "Justfile"
}
return ""
}