Repository navigation
feat(wfctl): add audit repo quality gate command - #543
Conversation
Add `wfctl audit repo` subcommand that runs portable, cross-platform quality gate checks on repository files before PR push/merge: - non_portable_path: detects non-ASCII, control chars, Windows-invalid chars - unsafe_path_traversal: detects ../ path traversal - unsafe_absolute_path: detects absolute paths - missing_doc_frontmatter: warns on structured docs without YAML frontmatter - malformed_frontmatter: errors on unclosed frontmatter delimiters - index_drift: warns on plan files not referenced in INDEX.md Supports --json for machine-readable output (CI/MCP/agents), --strict mode, and project config via .wfctl.yaml audit section for enabling/disabling checks and ignore patterns. Agent-Logs-Url: https://github.com/GoCodeAlone/workflow/sessions/9157fc90-89fe-4a16-bab7-1105b087f9b6 Co-authored-by: intel352 <[email protected]>
There was a problem hiding this comment.
Pull request overview
Adds wfctl audit repo, a repository-level quality gate under the existing wfctl audit command tree, intended for local/CI use to detect unsafe/non-portable paths and documentation/index hygiene issues.
Changes:
- Adds a new
audit repoimplementation with JSON/plaintext output, strict mode, and.wfctl.yaml-based configuration (checks + ignores). - Wires the new
reposubject into thewfctl auditrouter/usage output. - Documents the new command, flags, check codes, and config format in
docs/WFCTL.md.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 11 comments.
| File | Description |
|---|---|
| docs/WFCTL.md | Documents wfctl audit repo, its flags, built-in checks, and .wfctl.yaml config shape |
| cmd/wfctl/repo_audit.go | Implements repo scanning, checks, config loading, and report rendering |
| cmd/wfctl/repo_audit_test.go | Adds unit tests for routing, output modes, strict mode, ignores, and individual checks |
| cmd/wfctl/audit.go | Routes wfctl audit repo and updates audit usage/help text |
| data, err := os.ReadFile(configPath) | ||
| if err != nil { | ||
| return cfg | ||
| } | ||
|
|
||
| var raw struct { | ||
| Audit repoAuditConfig `yaml:"audit"` | ||
| } | ||
| if err := yaml.Unmarshal(data, &raw); err != nil { | ||
| return cfg | ||
| } |
| func TestRunAuditRepoStrictMode(t *testing.T) { | ||
| dir := t.TempDir() | ||
| writeRepoAuditFile(t, filepath.Join(dir, "file:name.txt"), "content\n") | ||
|
|
||
| var out bytes.Buffer | ||
| err := runAuditWithOutput([]string{"repo", "--dir", dir, "--strict"}, &out) | ||
| if err == nil { | ||
| t.Fatal("expected strict mode to fail on warnings") | ||
| } |
| func TestRunAuditRepoConfigIgnores(t *testing.T) { | ||
| dir := t.TempDir() | ||
| writeRepoAuditFile(t, filepath.Join(dir, "file:name.txt"), "content\n") | ||
| writeRepoAuditFile(t, filepath.Join(dir, ".wfctl.yaml"), `audit: | ||
| ignores: | ||
| - "file:name.txt" | ||
| `) | ||
|
|
| func TestRunAuditRepoConfigDisableCheck(t *testing.T) { | ||
| dir := t.TempDir() | ||
| writeRepoAuditFile(t, filepath.Join(dir, "file:name.txt"), "content\n") | ||
| writeRepoAuditFile(t, filepath.Join(dir, ".wfctl.yaml"), `audit: | ||
| checks: | ||
| portable_paths: false | ||
| `) | ||
|
|
|
@copilot apply changes based on the comments in this thread Also address all failing linter issues https://github.com/GoCodeAlone/workflow/actions/runs/25364420657/job/74374726883?pr=543 |
- Fix nilerr lint: WalkDir callback records ERROR finding instead of silently swallowing per-entry errors - Fix comment: update "Skip hidden directories" to "common noise directories" - Use path.Match (slash-based) in isIgnored to fix Windows path matching - Remove unsafe_paths from walk (WalkDir never yields ../ or absolute paths; checkUnsafePath stays as a pure validator for config strings) - Fix loadRepoAuditConfig: return error when config file exists but fails to parse; only silently skip missing default config - Update --config flag description to document actual resolution behavior - Skip symlinks in doc frontmatter check via d.Type().IsRegular() - Fix tests: eliminate file:name.txt (Windows-invalid) filesystem creation; use checkPortablePath directly or index_drift/frontmatter triggers instead; add TestRunAuditRepoConfigParseError - Update docs to remove unsafe_paths and align --config default description Agent-Logs-Url: https://github.com/GoCodeAlone/workflow/sessions/87e90e21-01ab-438d-ad51-f9a16eba4b93 Co-authored-by: intel352 <[email protected]>
Addressed all review comments in commit
|
⏱ Benchmark Results✅ No significant performance regressions detected. benchstat comparison (baseline → PR)
|
Implements
wfctl audit repo— a local/CI quality gate that catches portable-path, safety, and documentation issues before PR push/merge, as outlined in the design issue.Changes
cmd/wfctl/repo_audit.go— Core implementation with 6 built-in checks:non_portable_path— non-ASCII, control chars, Windows-invalid charsunsafe_path_traversal/unsafe_absolute_path— directory traversal and absolute pathsmissing_doc_frontmatter/malformed_frontmatter— structured docs without valid YAML frontmatterindex_drift— plan files missing fromdocs/plans/INDEX.mdcmd/wfctl/repo_audit_test.go— 12 tests covering checks, JSON output, strict mode, config ignores, and flag handlingcmd/wfctl/audit.go— Wirerepointo existing audit routerdocs/WFCTL.md— Document command, flags, check codes, and config formatUsage
Project-level config via
.wfctl.yaml:Design choices
--jsonuses stable lower-case field names matching existingaudit plans/audit pluginsoutput shape.git,node_modules,vendor,.nextautomatically