Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d75e737f07 | |||
| 1e3d86b604 | |||
| cc053cfede |
+26
-26
@@ -1,6 +1,6 @@
|
||||
# Dev Loop Health Check — 2026-05-15 01:33 UTC
|
||||
# Dev Loop Health Check — 2026-05-15 03:33 UTC
|
||||
|
||||
## Status: ✅ OPTIMAL
|
||||
## Status: ✅ ACTIVE WORK COMPLETED
|
||||
|
||||
### Test Results
|
||||
- All packages: **PASS** ✅ (6/6, fresh -count=1 run)
|
||||
@@ -18,33 +18,33 @@
|
||||
| llm | 81.3% |
|
||||
| review | 92.0% |
|
||||
|
||||
### Recent Activity (since last check 01:28 UTC)
|
||||
- Pulled `d0b0b0b` (dev-loop health update from 01:28 cycle)
|
||||
- No new commits from dev work
|
||||
- No open issues or PRs
|
||||
- Working tree: clean, up to date with origin/main
|
||||
### PR #138 Status
|
||||
|
||||
### Notes on Coverage
|
||||
- `cmd/review-bot` at 46.1% — main() itself at 26.5%; lowest coverage package
|
||||
- Potential: integration test harness (issue #TBD)
|
||||
- `vcs.go` adapter wrappers intentionally 0% — thin delegation, real logic tested in gitea/github packages
|
||||
- **Branch:** issue-137
|
||||
- **Feature:** feat(#137): add doc-map input for path-scoped doc injection
|
||||
- **Review status:** ✅ All 3 bots approved (sonnet, gpt, security)
|
||||
- **Review findings addressed:**
|
||||
- Fixed package comment collision in `review/docmap.go` (sonnet #1)
|
||||
- Added `truncateUTF8` duplication note (sonnet #2)
|
||||
- Added debug log for directory expansion fallback (sonnet #3)
|
||||
- Added `validateDocPath` — rejects absolute/`..` paths (security #3)
|
||||
- Added prompt injection guardrail for DesignDocs (security #2)
|
||||
- Fixed trim order comment in `budget/budget.go` (gpt #1)
|
||||
- Fixed `globMatch` comment to say `filepath.Match` (gpt nit #3)
|
||||
- Added `doc-map` and `doc-map-max-bytes` to README inputs table (gpt #2)
|
||||
- Added tests for `validateDocPath` and path traversal rejection
|
||||
- Updated CHANGELOG with security fixes
|
||||
- **Labels:** ready, self-reviewed
|
||||
- **Assignee:** aweiker
|
||||
- **Mergeable:** ✅ yes
|
||||
|
||||
### Next Phase Priorities
|
||||
1. **PR Submission (#132+)** — Enable review-bot to create PRs
|
||||
2. **`github.Client.DismissReview`** — method referenced in orphaned files, not in client.go; file issue
|
||||
3. **GitHub Enterprise Support** — Enterprise URL patterns, token scopes
|
||||
4. **Increase cmd/review-bot coverage** — integration test harness for main()
|
||||
5. **Performance & Observability** — Metrics, load testing, audit logging
|
||||
### Next Priority
|
||||
|
||||
### System Health
|
||||
- ✅ All tests passing
|
||||
- ✅ No warnings or lint issues
|
||||
- ✅ Code clean, working tree clean
|
||||
- ✅ No open issues or PRs on Gitea
|
||||
- ✅ Ready for next development cycle
|
||||
- Await merge of PR #138
|
||||
- After merge: increase cmd/review-bot coverage (46.1% → target 60%+)
|
||||
- Issue #132+: PR Submission feature
|
||||
- `github.Client.DismissReview` method referenced but missing — file issue
|
||||
|
||||
---
|
||||
|
||||
**Previous check:** 2026-05-15 01:28 UTC
|
||||
**This check:** 2026-05-15 01:33 UTC
|
||||
**Action:** NONE — healthy, no work to do
|
||||
_Dev-loop cycle complete at 03:33 UTC._
|
||||
|
||||
@@ -1383,3 +1383,126 @@ func TestFetchPatterns_MultipleRepos(t *testing.T) {
|
||||
t.Errorf("expected Elixir pipes content, got: %q", got)
|
||||
}
|
||||
}
|
||||
|
||||
// TestMainSubprocess_MissingLLMBaseURL confirms that --llm-base-url is required
|
||||
// when provider=openai (the default).
|
||||
func TestMainSubprocess_MissingLLMBaseURL(t *testing.T) {
|
||||
if os.Getenv("TEST_SUBPROCESS_MAIN") == "1" {
|
||||
flag.CommandLine = flag.NewFlagSet(os.Args[0], flag.ExitOnError)
|
||||
os.Args = []string{"review-bot",
|
||||
"--vcs-url", "https://gitea.example.com",
|
||||
"--repo", "owner/repo",
|
||||
"--pr", "1",
|
||||
"--reviewer-token", "tok",
|
||||
"--llm-model", "gpt-4",
|
||||
// --llm-base-url and --llm-api-key intentionally omitted
|
||||
}
|
||||
main()
|
||||
return
|
||||
}
|
||||
|
||||
cmd := exec.Command(os.Args[0], "-test.run=TestMainSubprocess_MissingLLMBaseURL")
|
||||
cmd.Env = append(cleanEnv(), "TEST_SUBPROCESS_MAIN=1")
|
||||
out, err := cmd.CombinedOutput()
|
||||
if err == nil {
|
||||
t.Fatal("expected non-zero exit when llm-base-url is missing")
|
||||
}
|
||||
if !strings.Contains(string(out), "llm-base-url") {
|
||||
t.Errorf("expected error mentioning llm-base-url, got: %s", out)
|
||||
}
|
||||
}
|
||||
|
||||
// TestMainSubprocess_MissingAICoreCredentials confirms that aicore-specific credentials
|
||||
// are required when provider=aicore.
|
||||
func TestMainSubprocess_MissingAICoreCredentials(t *testing.T) {
|
||||
if os.Getenv("TEST_SUBPROCESS_MAIN") == "1" {
|
||||
flag.CommandLine = flag.NewFlagSet(os.Args[0], flag.ExitOnError)
|
||||
os.Args = []string{"review-bot",
|
||||
"--vcs-url", "https://gitea.example.com",
|
||||
"--repo", "owner/repo",
|
||||
"--pr", "1",
|
||||
"--reviewer-token", "tok",
|
||||
"--llm-model", "gpt-4",
|
||||
"--llm-provider", "aicore",
|
||||
// aicore-client-id, aicore-client-secret, aicore-auth-url, aicore-api-url omitted
|
||||
}
|
||||
main()
|
||||
return
|
||||
}
|
||||
|
||||
cmd := exec.Command(os.Args[0], "-test.run=TestMainSubprocess_MissingAICoreCredentials")
|
||||
cmd.Env = append(cleanEnv(), "TEST_SUBPROCESS_MAIN=1")
|
||||
out, err := cmd.CombinedOutput()
|
||||
if err == nil {
|
||||
t.Fatal("expected non-zero exit when aicore credentials are missing")
|
||||
}
|
||||
if !strings.Contains(string(out), "AI Core credentials") {
|
||||
t.Errorf("expected error about AI Core credentials, got: %s", out)
|
||||
}
|
||||
}
|
||||
|
||||
// TestMainSubprocess_ConflictingPersonaFlags confirms that --persona and --persona-file
|
||||
// cannot be used together.
|
||||
func TestMainSubprocess_ConflictingPersonaFlags(t *testing.T) {
|
||||
if os.Getenv("TEST_SUBPROCESS_MAIN") == "1" {
|
||||
flag.CommandLine = flag.NewFlagSet(os.Args[0], flag.ExitOnError)
|
||||
os.Args = []string{"review-bot",
|
||||
"--vcs-url", "https://gitea.example.com",
|
||||
"--repo", "owner/repo",
|
||||
"--pr", "1",
|
||||
"--reviewer-token", "tok",
|
||||
"--llm-base-url", "https://api.example.com",
|
||||
"--llm-api-key", "key",
|
||||
"--llm-model", "gpt-4",
|
||||
"--persona", "security",
|
||||
"--persona-file", "custom.json",
|
||||
}
|
||||
main()
|
||||
return
|
||||
}
|
||||
|
||||
cmd := exec.Command(os.Args[0], "-test.run=TestMainSubprocess_ConflictingPersonaFlags")
|
||||
cmd.Env = append(cleanEnv(), "TEST_SUBPROCESS_MAIN=1")
|
||||
out, err := cmd.CombinedOutput()
|
||||
if err == nil {
|
||||
t.Fatal("expected non-zero exit with both --persona and --persona-file set")
|
||||
}
|
||||
if !strings.Contains(string(out), "mutually exclusive") {
|
||||
t.Errorf("expected error about mutually exclusive flags, got: %s", out)
|
||||
}
|
||||
}
|
||||
|
||||
// TestMainSubprocess_DeprecatedGiteaURLEnv confirms that GITEA_URL env var still works
|
||||
// as a deprecated fallback for VCS_URL.
|
||||
func TestMainSubprocess_DeprecatedGiteaURLEnv(t *testing.T) {
|
||||
if os.Getenv("TEST_SUBPROCESS_MAIN") == "1" {
|
||||
flag.CommandLine = flag.NewFlagSet(os.Args[0], flag.ExitOnError)
|
||||
// Set required flags but omit --vcs-url; GITEA_URL should be picked up.
|
||||
// The test will exit with an error after VCS init (no PR to fetch), but
|
||||
// the deprecation warning must appear.
|
||||
os.Args = []string{"review-bot",
|
||||
// No --vcs-url: should fall back to GITEA_URL env var
|
||||
"--repo", "owner/repo",
|
||||
"--pr", "1",
|
||||
"--reviewer-token", "tok",
|
||||
"--llm-base-url", "https://api.example.com",
|
||||
"--llm-api-key", "key",
|
||||
"--llm-model", "gpt-4",
|
||||
}
|
||||
main()
|
||||
return
|
||||
}
|
||||
|
||||
cmd := exec.Command(os.Args[0], "-test.run=TestMainSubprocess_DeprecatedGiteaURLEnv")
|
||||
// Inject GITEA_URL but NOT VCS_URL.
|
||||
env := append(cleanEnv(),
|
||||
"TEST_SUBPROCESS_MAIN=1",
|
||||
"GITEA_URL=https://gitea.example.com",
|
||||
)
|
||||
cmd.Env = env
|
||||
out, _ := cmd.CombinedOutput()
|
||||
// The process will fail (no real server), but the deprecation warning must appear.
|
||||
if !strings.Contains(string(out), "deprecated") {
|
||||
t.Errorf("expected deprecation warning for GITEA_URL, got: %s", out)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,3 +125,60 @@ func TestRunValidateURL_WithCapture(t *testing.T) {
|
||||
t.Errorf("expected error about https in stderr, got %q", errBuf.String())
|
||||
}
|
||||
}
|
||||
|
||||
// TestIsValidateError_Nil confirms that isValidateError returns false for a nil error.
|
||||
func TestIsValidateError_Nil(t *testing.T) {
|
||||
var ve *validateError
|
||||
if isValidateError(nil, &ve) {
|
||||
t.Error("isValidateError(nil, ...) should return false")
|
||||
}
|
||||
}
|
||||
|
||||
// TestValidateURL_EmptyHost confirms that a URL with no hostname returns a code-2 error.
|
||||
func TestValidateURL_EmptyHost(t *testing.T) {
|
||||
// "https://" parses fine but has no hostname.
|
||||
err := validateURL("https://")
|
||||
if err == nil {
|
||||
t.Fatal("expected error for URL with no host, got nil")
|
||||
}
|
||||
var ve *validateError
|
||||
if !isValidateError(err, &ve) {
|
||||
t.Fatalf("expected *validateError, got %T: %v", err, err)
|
||||
}
|
||||
if ve.code != 2 {
|
||||
t.Errorf("expected code 2, got %d (msg=%s)", ve.code, ve.message)
|
||||
}
|
||||
if !strings.Contains(ve.message, "no host") {
|
||||
t.Errorf("expected 'no host' in error message, got %q", ve.message)
|
||||
}
|
||||
}
|
||||
|
||||
// TestRunValidateURL_Success confirms that a resolvable public URL prints "OK" and returns 0.
|
||||
// This test requires external DNS; it is skipped in environments without network access.
|
||||
func TestRunValidateURL_Success(t *testing.T) {
|
||||
// Pre-check: validate that DNS is available before exercising the success path.
|
||||
err := validateURL("https://example.com/")
|
||||
if err != nil {
|
||||
t.Skipf("skipping success-path test: DNS unavailable or example.com blocked (%v)", err)
|
||||
}
|
||||
|
||||
var outBuf, errBuf bytes.Buffer
|
||||
origOut, origErr := outWriter, errWriter
|
||||
outWriter = &outBuf
|
||||
errWriter = &errBuf
|
||||
defer func() {
|
||||
outWriter = origOut
|
||||
errWriter = origErr
|
||||
}()
|
||||
|
||||
code := runValidateURL([]string{"https://example.com/"})
|
||||
if code != 0 {
|
||||
t.Errorf("expected exit code 0 for safe URL, got %d (stderr: %s)", code, errBuf.String())
|
||||
}
|
||||
if !strings.Contains(outBuf.String(), "OK:") {
|
||||
t.Errorf("expected 'OK:' in stdout, got %q", outBuf.String())
|
||||
}
|
||||
if errBuf.Len() != 0 {
|
||||
t.Errorf("expected no stderr for safe URL, got %q", errBuf.String())
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user