diff --git a/.github/workflows/_opencode-review.yml b/.github/workflows/_opencode-review.yml new file mode 100644 index 0000000..bc5190a --- /dev/null +++ b/.github/workflows/_opencode-review.yml @@ -0,0 +1,50 @@ +name: opencode-review + +on: + workflow_call: + inputs: + enabled: + type: boolean + default: false + model: + type: string + required: true + secrets: + OPENAI_API_KEY: + required: true + +permissions: + contents: read + pull-requests: read + issues: write + +concurrency: + group: opencode-review-${{ github.repository }}-${{ github.event.pull_request.number }} + cancel-in-progress: true + +jobs: + review: + if: >- + inputs.enabled && vars.OPENCODE_REVIEW_ENABLED == 'true' && + github.event_name == 'pull_request' && + github.event.pull_request.head.repo.full_name == github.repository + runs-on: ubuntu-24.04 + timeout-minutes: 20 + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: true + - uses: anomalyco/opencode/github@148842ef7cb1bc34192b3fff57d0f9721ab9c801 # v1.19.4 + env: + OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} + GITHUB_TOKEN: ${{ github.token }} + OPENCODE_CONFIG_CONTENT: '{"$schema":"https://opencode.ai/config.json","default_agent":"plan"}' + with: + model: ${{ inputs.model }} + use_github_token: true + prompt: | + Review this pull request for correctness, security, and regressions. + This is advisory only. Do not modify files, commit, push, create pull + requests, or execute repository scripts. Report findings with file + references. Clearly state missing context, failures, and validation + that was not performed; do not claim a completed review when blocked. diff --git a/README.md b/README.md index 570c10b..6dd0a15 100644 --- a/README.md +++ b/README.md @@ -121,6 +121,7 @@ recovery mechanism. Enable live mode only after a reviewed dry-run pilot. |---|---| | `opentofu.yml` | OpenTofu/Terraform CI/CD with PR validation and an environment-gated apply on every push to `main` | | `_stale-pull-requests.yml` | Dry-run-first reusable lifecycle for closing pull requests inactive for at least 30 days and deleting only recoverable eligible head branches. | +| `_opencode-review.yml` | Disabled-by-default official OpenCode V1 action; [limits and activation](docs/opencode-pr-review.md). | Same-repository PRs run tests and a credentialed plan; fork PRs run tests only. A push to `main` runs tests followed by a fresh apply, which does not reuse the PR plan. The apply job uses the caller's `environment` input (default `production`); repository owners must configure that GitHub Environment with the required protection rules. diff --git a/docs/opencode-pr-review.md b/docs/opencode-pr-review.md new file mode 100644 index 0000000..150f5c1 --- /dev/null +++ b/docs/opencode-pr-review.md @@ -0,0 +1,54 @@ +# OpenCode PR reviews + +Uses the [official V1 GitHub action](https://opencode.ai/docs/github/#pull-request-example), +as explicitly selected by the owner. No custom scripts, agents, policy generator, +JSON decoder, sticky-comment bridge, or model-specific test harness is included. + +## Interface + +Call `.github/workflows/_opencode-review.yml` at a reviewed immutable commit from +`pull_request` events (`opened`, `synchronize`, `reopened`, `ready_for_review`). +Pass `model` (`provider/model`), explicitly map `OPENAI_API_KEY`, and grant +`contents: read`, `pull-requests: read`, and `issues: write`. This credential +interface supports OpenAI models; other providers need their own secret mapping. +No OpenCode GitHub App installation or OIDC permission is required. +Checkout retains the contents-read/issues-write GitHub token for the upstream +runner's Git fetches, as required by its token-mode setup for private repositories. + +Both `enabled: true` and `OPENCODE_REVIEW_ENABLED=true` are required. The default +is disabled; required caller inputs/secrets still apply to a disabled invocation. +Fork and merge-queue events are excluded. Superseded PR runs are cancelled; the +job limit is 20 minutes. There is no custom retry or failover wrapper. Skipped or +green Actions checks do not establish completed review coverage or merge approval. + +## Accepted upstream limitations + +- Each run creates a new comment, not one sticky comment. + Cancellation/re-execution can leave partial results or duplicate comments; + failure/timeout commenting is not guaranteed. +- Upstream requires the triggering actor to have write/admin permission; + bot and Dependabot coverage is not guaranteed. +- Fork approval/review is not implemented. No `pull_request_target` credential + workaround is used. +- No chart-packaged agents/skills, exact-SHA approval/stale-result guard, + custom completion marker, output sanitizer, or completion guarantee is added. +- The action follows the current PR branch, which can move during a run. +- The action is pinned to V1 `v1.19.4`'s commit, but its installer downloads the + latest CLI and its nested cache action uses a tag. These are upstream behavior, + not a fully immutable dependency chain. + +The pinned runner ignores the action's `agent` input. The workflow uses the +documented `OPENCODE_CONFIG_CONTENT` runtime override to set `default_agent` to +`plan` instead; see [V1 configuration](https://opencode.ai/docs/config/#default-agent). +This selects an agent, not a security sandbox or isolation from repository config. +Repository configuration/plugins and provider-key exposure require a separately +authorized security pilot before enabling. The token cannot write repository +contents; provider credentials must never be exposed to untrusted execution. + +Make IT Work Cloud maintainers own this wrapper in `shared-workflows`, under +the owner's explicit selection of the limited V1 integration. `tfroot-github` owns future +generated `.github/workflows/opencode-review.yml` callers. No caller, credential, +repository setting, deployment, or enablement is delivered by this change. +Existing lint/actionlint validates the YAML; there are no bespoke review tests. +Merging, caller adoption/apply, credentials, pilot, and enablement remain separate +confirmation gates. Existing chart and abandoned bridge drafts are not shipped.