Add disposable inline OpenCode reviews #3

Merged
lambadalambda merged 15 commits from fix/restore-review-tools into main 2026-08-05 10:16:25 +00:00

Summary

  • replace the separate sanitized preparer/read-only worker flow with one disposable writable rootless agent using normal coding tools
  • emit strictly validated structured review results and publish actionable findings as Forgejo inline pull-review comments
  • keep the canonical issue comment compact, reconcile ambiguous publications, preserve discussed reviews, and resume persisted publication intent after lease recovery
  • expand bounded public package/test egress and raise the coordinated review timeout budget to 50/55/65 minutes

Verification

  • go test ./...
  • go vet ./...
  • go test -race ./internal/app ./internal/store ./internal/control ./internal/forgejo ./internal/launcher
  • sh scripts/adversarial-check.sh
  • dispatcher and worker Podman image builds
  • production smoke test on PR #2: exact-head inline review publication and unanswered-review replacement on rerun

Deployment

The reviewed worktree is already deployed on ci.pleroma.com; rollback images, launcher binary, and a stopped SQLite backup were preserved.

## Summary - replace the separate sanitized preparer/read-only worker flow with one disposable writable rootless agent using normal coding tools - emit strictly validated structured review results and publish actionable findings as Forgejo inline pull-review comments - keep the canonical issue comment compact, reconcile ambiguous publications, preserve discussed reviews, and resume persisted publication intent after lease recovery - expand bounded public package/test egress and raise the coordinated review timeout budget to 50/55/65 minutes ## Verification - `go test ./...` - `go vet ./...` - `go test -race ./internal/app ./internal/store ./internal/control ./internal/forgejo ./internal/launcher` - `sh scripts/adversarial-check.sh` - dispatcher and worker Podman image builds - production smoke test on PR #2: exact-head inline review publication and unanswered-review replacement on rerun ## Deployment The reviewed worktree is already deployed on `ci.pleroma.com`; rollback images, launcher binary, and a stopped SQLite backup were preserved.
Author
Owner

/oc review

/oc review
Collaborator

OpenCode Review

Execution completed for lambadalambda/opencode-forgejo-bot at 69e8a409e573 (job #28).

Disposable writable-checkout inline review pipeline with persisted, MCP-exposed discussion snapshots. All three prior LOW findings are confirmed addressed: diff line bound raised to 8 MiB to match the diff response cap, discussion capture now normalizes one item per append (O(N) total), and enqueue/publication use separate lock classes. Build, go vet, full test suite, and adversarial-check all pass.

View the pull review with 1 finding(s).

<!-- opencode-review:v1:9e3a160b72bb99896cb0af7611a7ea5e --> <!-- opencode-reviewed-head:69e8a409e57343cfdf739c699ac00dfb7fa9c55d --> ## OpenCode Review _Execution completed for `lambadalambda/opencode-forgejo-bot` at `69e8a409e573` (job #28)._ Disposable writable-checkout inline review pipeline with persisted, MCP-exposed discussion snapshots. All three prior LOW findings are confirmed addressed: diff line bound raised to 8 MiB to match the diff response cap, discussion capture now normalizes one item per append (O(N) total), and enqueue/publication use separate lock classes. Build, go vet, full test suite, and adversarial-check all pass. [View the pull review with 1 finding(s)](https://git.pleroma.social/lambadalambda/opencode-forgejo-bot/pulls/3#issuecomment-117576).
Author
Owner

/oc rerun

/oc rerun
Author
Owner

/oc rerun

/oc rerun
Author
Owner

/oc rerun

/oc rerun
Author
Owner

/oc rerun

/oc rerun
fix: require review discussion intake
All checks were successful
opencode/review OpenCode execution completed
0ac9e7a2a8
Author
Owner

/oc rerun

/oc rerun
Author
Owner

/oc rerun

/oc rerun
fix: harden review follow-up races
Some checks reported errors
opencode/review OpenCode execution failed
1406952094
Author
Owner

/oc rerun

/oc rerun
Author
Owner

/oc rerun

/oc rerun
feat: add rootless agent identity mode
All checks were successful
opencode/review OpenCode execution completed
69e8a409e5
Author
Owner

/oc review

/oc review
opencode-bot left a comment

OpenCode Review

Disposable writable-checkout inline review pipeline with persisted, MCP-exposed discussion snapshots. All three prior LOW findings are confirmed addressed: diff line bound raised to 8 MiB to match the diff response cap, discussion capture now normalizes one item per append (O(N) total), and enqueue/publication use separate lock classes. Build, go vet, full test suite, and adversarial-check all pass.

1 finding(s) are attached to changed lines.

Overall

This PR replaces the read-only patch model with a disposable, writable-checkout OpenCode agent whose strictly-validated JSON report the dispatcher publishes as a Forgejo pull review with inline comments plus one compact canonical issue comment. ReviewReport and DiscussionSnapshot are validated strictly (unique keys, exact fields, safe paths, anchored findings, per-item and aggregate size bounds, forbidden-marker rejection, dual-position threads). The launcher resumes publication from the persisted result without a second model call; the in-container preparer checks out the exact head via anonymous HTTPS with hooks/redirects/submodules disabled and verifies advertised refs resolve to the queued full SHAs. Publication is fenced by repeated PR-freshness checks; visible output is rolled back on staleness or generation loss with background-context compensation that survives request cancellation, and inline publication reconciles ambiguous creates, parses the PR diff to confirm each anchored line is inside an added hunk, falls back to the full canonical comment on transient failure, and refuses to leave orphan reviews when cleanup fails. The discussion capture is bounded (2 s nested deadline inside a 4 s webhook budget with a 1.5 s required tail, <=4 review pages, aggregate count/size limits) and binds the snapshot to the queued SHAs via a post-capture freshness re-check. The read-only MCP server is strict (bounded requests/results, exact-field pagination, no mutation tools, no network) and re-validates the snapshot; its child environment clears ZHIPU_API_KEY. The disposable boundary is preserved: random tmpfs workspace, internal-network verification, single read-only discussion mount, random container names with forced cleanup, env-file holding only the model key. The broadened capability set and the model-key exfiltration risk are clearly documented in AGENTS.md and README. The diff parser correctly handles binary/renamed/deleted/no-newline files and rejects malformed hunks; the builder's incremental byte accounting is asserted at finish(). SQLite publication transitions use atomic CAS-style WHERE clauses keyed on state/lease/head/generation. Only one LOW refinement remains; it is not a blocker.

<!-- opencode-pull-review:v1:ffad20a1f7ed05c26d7c9bd38887121b --> <!-- opencode-pull-review-result:v1:3e1a040acd1e0c945dd17732462b4ac6 --> ## OpenCode Review Disposable writable-checkout inline review pipeline with persisted, MCP-exposed discussion snapshots. All three prior LOW findings are confirmed addressed: diff line bound raised to 8 MiB to match the diff response cap, discussion capture now normalizes one item per append (O(N) total), and enqueue/publication use separate lock classes. Build, go vet, full test suite, and adversarial-check all pass. _1 finding(s) are attached to changed lines._ ## Overall This PR replaces the read-only patch model with a disposable, writable-checkout OpenCode agent whose strictly-validated JSON report the dispatcher publishes as a Forgejo pull review with inline comments plus one compact canonical issue comment. ReviewReport and DiscussionSnapshot are validated strictly (unique keys, exact fields, safe paths, anchored findings, per-item and aggregate size bounds, forbidden-marker rejection, dual-position threads). The launcher resumes publication from the persisted result without a second model call; the in-container preparer checks out the exact head via anonymous HTTPS with hooks/redirects/submodules disabled and verifies advertised refs resolve to the queued full SHAs. Publication is fenced by repeated PR-freshness checks; visible output is rolled back on staleness or generation loss with background-context compensation that survives request cancellation, and inline publication reconciles ambiguous creates, parses the PR diff to confirm each anchored line is inside an added hunk, falls back to the full canonical comment on transient failure, and refuses to leave orphan reviews when cleanup fails. The discussion capture is bounded (2 s nested deadline inside a 4 s webhook budget with a 1.5 s required tail, <=4 review pages, aggregate count/size limits) and binds the snapshot to the queued SHAs via a post-capture freshness re-check. The read-only MCP server is strict (bounded requests/results, exact-field pagination, no mutation tools, no network) and re-validates the snapshot; its child environment clears ZHIPU_API_KEY. The disposable boundary is preserved: random tmpfs workspace, internal-network verification, single read-only discussion mount, random container names with forced cleanup, env-file holding only the model key. The broadened capability set and the model-key exfiltration risk are clearly documented in AGENTS.md and README. The diff parser correctly handles binary/renamed/deleted/no-newline files and rejects malformed hunks; the builder's incremental byte accounting is asserted at finish(). SQLite publication transitions use atomic CAS-style WHERE clauses keyed on state/lease/head/generation. Only one LOW refinement remains; it is not a blocker.
@ -52,0 +56,4 @@
}
return nil
}
if err := verifyAgentResourceEnforcement(ctx, l.cfg); err != nil {
Collaborator

[LOW] Agent uid/gid identity is not verified in the default required cgroup mode

verifyConfiguredAgentRuntime verifies the agent identity (id -u/id -g equals 1000/1000 for keep-id, or 0/0 for rootless-root) only when AgentCgroupMode is outer. In the default required mode it runs verifyAgentResourceEnforcement alone, and the resource probe script only cats cgroup files (memory.max, memory.swap.max, cpu.max, pids.max) without printing id -u/id -g. cgroup limits are independent of the in-container uid, so a worker image whose primary user is not uid 1000 (or a podman userns regression that silently alters the keep-id mapping) would pass startup verification and run reviews under an unexpected identity. The resource probe container already launches with agentIdentityArgs, so the script could validate identity at negligible cost. The outer path shows the project considers identity worth checking; the default path should too.

Suggested replacement (manual):

// Run verifyAgentIdentity unconditionally (or extend agentResourceProbeScript to also
// printf "$(id -u)\n$(id -g)" and validate it in parseAgentResourceProbe) so the
// required cgroup mode catches a misconfigured keep-id mapping before claiming work.
**[LOW] Agent uid/gid identity is not verified in the default required cgroup mode** verifyConfiguredAgentRuntime verifies the agent identity (id -u/id -g equals 1000/1000 for keep-id, or 0/0 for rootless-root) only when AgentCgroupMode is outer. In the default required mode it runs verifyAgentResourceEnforcement alone, and the resource probe script only cats cgroup files (memory.max, memory.swap.max, cpu.max, pids.max) without printing id -u/id -g. cgroup limits are independent of the in-container uid, so a worker image whose primary user is not uid 1000 (or a podman userns regression that silently alters the keep-id mapping) would pass startup verification and run reviews under an unexpected identity. The resource probe container already launches with agentIdentityArgs, so the script could validate identity at negligible cost. The outer path shows the project considers identity worth checking; the default path should too. **Suggested replacement (manual):** // Run verifyAgentIdentity unconditionally (or extend agentResourceProbeScript to also // printf "$(id -u)\n$(id -g)" and validate it in parseAgentResourceProbe) so the // required cgroup mode catches a misconfigured keep-id mapping before claiming work. <!-- opencode-pull-review-finding:v1:026932e458b5e02aef2687c345470176 -->
opencode-bot left a comment

OpenCode Review

Disposable writable-checkout inline review pipeline with persisted, MCP-exposed discussion snapshots. All three prior LOW findings are confirmed addressed: diff line bound raised to 8 MiB to match the diff response cap, discussion capture now normalizes one item per append (O(N) total), and enqueue/publication use separate lock classes. Build, go vet, full test suite, and adversarial-check all pass.

1 finding(s) are attached to changed lines.

Overall

This PR replaces the read-only patch model with a disposable, writable-checkout OpenCode agent whose strictly-validated JSON report the dispatcher publishes as a Forgejo pull review with inline comments plus one compact canonical issue comment. ReviewReport and DiscussionSnapshot are validated strictly (unique keys, exact fields, safe paths, anchored findings, per-item and aggregate size bounds, forbidden-marker rejection, dual-position threads). The launcher resumes publication from the persisted result without a second model call; the in-container preparer checks out the exact head via anonymous HTTPS with hooks/redirects/submodules disabled and verifies advertised refs resolve to the queued full SHAs. Publication is fenced by repeated PR-freshness checks; visible output is rolled back on staleness or generation loss with background-context compensation that survives request cancellation, and inline publication reconciles ambiguous creates, parses the PR diff to confirm each anchored line is inside an added hunk, falls back to the full canonical comment on transient failure, and refuses to leave orphan reviews when cleanup fails. The discussion capture is bounded (2 s nested deadline inside a 4 s webhook budget with a 1.5 s required tail, <=4 review pages, aggregate count/size limits) and binds the snapshot to the queued SHAs via a post-capture freshness re-check. The read-only MCP server is strict (bounded requests/results, exact-field pagination, no mutation tools, no network) and re-validates the snapshot; its child environment clears ZHIPU_API_KEY. The disposable boundary is preserved: random tmpfs workspace, internal-network verification, single read-only discussion mount, random container names with forced cleanup, env-file holding only the model key. The broadened capability set and the model-key exfiltration risk are clearly documented in AGENTS.md and README. The diff parser correctly handles binary/renamed/deleted/no-newline files and rejects malformed hunks; the builder's incremental byte accounting is asserted at finish(). SQLite publication transitions use atomic CAS-style WHERE clauses keyed on state/lease/head/generation. Only one LOW refinement remains; it is not a blocker.

<!-- opencode-pull-review:v1:ffad20a1f7ed05c26d7c9bd38887121b --> <!-- opencode-pull-review-result:v1:3e1a040acd1e0c945dd17732462b4ac6 --> ## OpenCode Review Disposable writable-checkout inline review pipeline with persisted, MCP-exposed discussion snapshots. All three prior LOW findings are confirmed addressed: diff line bound raised to 8 MiB to match the diff response cap, discussion capture now normalizes one item per append (O(N) total), and enqueue/publication use separate lock classes. Build, go vet, full test suite, and adversarial-check all pass. _1 finding(s) are attached to changed lines._ ## Overall This PR replaces the read-only patch model with a disposable, writable-checkout OpenCode agent whose strictly-validated JSON report the dispatcher publishes as a Forgejo pull review with inline comments plus one compact canonical issue comment. ReviewReport and DiscussionSnapshot are validated strictly (unique keys, exact fields, safe paths, anchored findings, per-item and aggregate size bounds, forbidden-marker rejection, dual-position threads). The launcher resumes publication from the persisted result without a second model call; the in-container preparer checks out the exact head via anonymous HTTPS with hooks/redirects/submodules disabled and verifies advertised refs resolve to the queued full SHAs. Publication is fenced by repeated PR-freshness checks; visible output is rolled back on staleness or generation loss with background-context compensation that survives request cancellation, and inline publication reconciles ambiguous creates, parses the PR diff to confirm each anchored line is inside an added hunk, falls back to the full canonical comment on transient failure, and refuses to leave orphan reviews when cleanup fails. The discussion capture is bounded (2 s nested deadline inside a 4 s webhook budget with a 1.5 s required tail, <=4 review pages, aggregate count/size limits) and binds the snapshot to the queued SHAs via a post-capture freshness re-check. The read-only MCP server is strict (bounded requests/results, exact-field pagination, no mutation tools, no network) and re-validates the snapshot; its child environment clears ZHIPU_API_KEY. The disposable boundary is preserved: random tmpfs workspace, internal-network verification, single read-only discussion mount, random container names with forced cleanup, env-file holding only the model key. The broadened capability set and the model-key exfiltration risk are clearly documented in AGENTS.md and README. The diff parser correctly handles binary/renamed/deleted/no-newline files and rejects malformed hunks; the builder's incremental byte accounting is asserted at finish(). SQLite publication transitions use atomic CAS-style WHERE clauses keyed on state/lease/head/generation. Only one LOW refinement remains; it is not a blocker.
@ -52,0 +56,4 @@
}
return nil
}
if err := verifyAgentResourceEnforcement(ctx, l.cfg); err != nil {
Collaborator

[LOW] Agent uid/gid identity is not verified in the default required cgroup mode

verifyConfiguredAgentRuntime verifies the agent identity (id -u/id -g equals 1000/1000 for keep-id, or 0/0 for rootless-root) only when AgentCgroupMode is outer. In the default required mode it runs verifyAgentResourceEnforcement alone, and the resource probe script only cats cgroup files (memory.max, memory.swap.max, cpu.max, pids.max) without printing id -u/id -g. cgroup limits are independent of the in-container uid, so a worker image whose primary user is not uid 1000 (or a podman userns regression that silently alters the keep-id mapping) would pass startup verification and run reviews under an unexpected identity. The resource probe container already launches with agentIdentityArgs, so the script could validate identity at negligible cost. The outer path shows the project considers identity worth checking; the default path should too.

Suggested replacement (manual):

// Run verifyAgentIdentity unconditionally (or extend agentResourceProbeScript to also
// printf "$(id -u)\n$(id -g)" and validate it in parseAgentResourceProbe) so the
// required cgroup mode catches a misconfigured keep-id mapping before claiming work.
**[LOW] Agent uid/gid identity is not verified in the default required cgroup mode** verifyConfiguredAgentRuntime verifies the agent identity (id -u/id -g equals 1000/1000 for keep-id, or 0/0 for rootless-root) only when AgentCgroupMode is outer. In the default required mode it runs verifyAgentResourceEnforcement alone, and the resource probe script only cats cgroup files (memory.max, memory.swap.max, cpu.max, pids.max) without printing id -u/id -g. cgroup limits are independent of the in-container uid, so a worker image whose primary user is not uid 1000 (or a podman userns regression that silently alters the keep-id mapping) would pass startup verification and run reviews under an unexpected identity. The resource probe container already launches with agentIdentityArgs, so the script could validate identity at negligible cost. The outer path shows the project considers identity worth checking; the default path should too. **Suggested replacement (manual):** // Run verifyAgentIdentity unconditionally (or extend agentResourceProbeScript to also // printf "$(id -u)\n$(id -g)" and validate it in parseAgentResourceProbe) so the // required cgroup mode catches a misconfigured keep-id mapping before claiming work. <!-- opencode-pull-review-finding:v1:026932e458b5e02aef2687c345470176 -->
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
lambadalambda/opencode-forgejo-bot!3
No description provided.