Skip to content
TilloTech Docs

AI-50: GitHub auth and fork pull request policy

Status

Accepted for the pilot slice.

This record keeps the original decision. Live operator rules are in How to add Harbourmaster reviews to a repository and the GitHub Action reference.

Implementation after the pilot slice changed these parts:

  • The workflow skips fork pull requests before checkout. They do not run a read-only review.
  • Dependabot has no extra skip rule. A same-repository Dependabot pull request can start a review.
  • The trusted OpenCode publish_review plugin publishes the advisory review. The TypeScript runner verifies the marked review and the private receipt.

Decision

Harbourmaster will run the pilot from GitHub Actions using either the workflow GITHUB_TOKEN for same-repository pull requests or a GitHub App installation token for org-wide rollout. All GitHub reads and writes must stay behind the Octokit provider layer. Reviewer runtime code receives only provider-neutral pull request context and review results.

The pilot starts in comment-only mode. Harbourmaster publishes one pull request review containing the summary and any mappable inline findings. It must not approve, request changes, merge, label, close, or otherwise mutate repository state during this slice.

Consumer repositories run TilloTech/eos/apps/harbourmaster@main, using the latest Harbourmaster version merged to EOS. EOS self-reviews are an explicit exception: same-repository, non-draft EOS pull requests run the local action from the exact pull request head so Harbourmaster changes can be tested before merge. This invariant does not apply to consumer repositories.

Fork and Dependabot behavior

Fork pull requests are skipped by the supported workflow before checkout. The runner also skips fork pull requests by policy. They do not run read-only context construction or OpenCode review execution.

Dependabot pull requests from the same repository are not forks. They have no extra skip rule and can start a review unless a separate workflow guard excludes them.

The safe boundary is:

  • The supported workflow skips fork and draft pull requests before checkout, dependency installation, OIDC, or action execution.
  • Do not run pull_request_target against untrusted head code.
  • Do not let OpenCode call GitHub APIs directly.
  • Load Harbourmaster agents and plugins only from the trusted bundled runtime configuration. Repository-owned .opencode files are review context, not executable reviewer configuration.
  • The trusted publish_review plugin publishes the advisory review after the runner validates it.

Required GitHub permissions

Same-repository pilot workflows should request the minimum permissions needed for the enabled phase:

yaml
permissions:
  contents: read
  pull-requests: write
  issues: write

contents: read is required to load repository context. pull-requests: write lets the review job apply harbourmaster-review and create PR reviews. issues: write lets the job create the repository label when it is missing and supports issue comment reads for duplicate suppression. Harbourmaster itself must not add or remove labels; only the workflow label step does.

GitHub App installations need the same repository permissions:

  • Contents: read
  • Pull requests: read and write
  • Issues: read

The supported workflow still uses GITHUB_TOKEN with issues: write to create the harbourmaster-review label. That label step does not use the App token.

Future checks or status reporting must add only the specific permission needed by that feature.

OpenCode runtime policy

OpenCode is the reviewer runtime, not the GitHub publisher.

  • Credentials are passed through explicitly named environment variables owned by the runtime boundary.
  • CI uses Harbourmaster's bundled OpenCode configuration and never executes agents or plugins from the repository being reviewed.
  • The reviewed repository is passed as an explicit absolute workspace root.
  • The canonical workspace path must remain inside a separately supplied trusted boundary such as GITHUB_WORKSPACE; symlink escapes are rejected.
  • OpenCode starts in an isolated diff directory. Before it starts, the trusted runner writes review-index.json, shared-pr-context.txt, and review-discussion.txt.
  • review-index.json records the repository root, exact base and head, changed paths, statuses, rename paths, patch paths, and per-hunk base, head, and patch-line ranges. A missing patch path is null.
  • The editor keeps the required publication and lifecycle context inline. It invokes spawn_reviewers directly and cannot write or copy review context.
  • Specialists and the verifier may use only the read-only tools read, glob, grep, and list. A session-bound read_more tool can continue a truncated repository result.
  • The code-quality reviewer receives the canonical checkout root in its prompt and can inspect that checkout alongside the staged diff material. Other specialists and the verifier can inspect only the staged diff material.
  • The pinned OpenCode runtime enforces external-directory permissions. A per-run override grants the code-quality reviewer access to the canonical checkout root. All other external-directory access remains denied.
  • A trusted hook canonicalizes paths for read, glob, grep, and list and rejects symlink escapes before those tools access files.
  • Shell, mutation, network, and nested-agent access remain denied.
  • Harbourmaster contract tests verify these permissions. OpenCode upgrades must preserve this permission contract before the pin moves.
  • Repository files and instructions are untrusted review context and cannot override Harbourmaster safety, tool, scope, validation, or publication rules.
  • Findings remain limited to behavior introduced by the pull request and must be anchored to changed lines even when repository context supplies evidence.
  • Reviewers must start with the index, inspect every relevant changed patch, search callers, read source ranges, and read tests when the role permits those reads. Missing or truncated results do not prove that no finding exists.
  • The SDK server may be owned-per-run for CI isolation or shared-external for local development. CI should prefer owned-per-run.
  • Sessions are scoped to one PR review run and may be shared only across reviewer agents within that run.
  • OpenCode output must be validated into the provider-neutral review result schema before any Octokit publishing step.

pull_request_target policy

Harbourmaster must not use pull_request_target for executing untrusted pull request code. A future trusted maintainer workflow may use pull_request_target only to publish previously generated, validated artifacts from a trusted source, and only if it avoids checking out or executing the untrusted head ref.

Consequences

This keeps the pilot safe and reviewable: GitHub permissions are narrow, publishing remains centralized in Octokit, and OpenCode can be swapped or tested behind the runtime contract without leaking provider-specific fields into reviewer logic.