The Harbourmaster shared-action trust boundary
Harbourmaster runs repository code analysis inside a GitHub Actions job that can request an AWS OIDC token and publish pull request feedback. Its workflow design therefore treats executable references, event context, and repository checkout state as parts of one trust boundary.
The design was exercised while adding Harbourmaster to
TilloTech/go pull request 76. The
review exposed several principles that apply to every consuming repository.
flowchart LR
Event["pull_request event"] --> Guard{"Same repository and not draft?"}
Guard -->|"No"| Skip["Do not run a review"]
Guard -->|"Yes"| Request{"Label absent or explicitly re-added?"}
Request -->|"No"| Skip
Request -->|"Yes"| Label["Apply harbourmaster-review label"]
Label --> Checkout["Checkout exact reviewed head SHA"]
Action["Harbourmaster action from EOS main"] --> Runner
Checkout --> Runner["Trusted Harbourmaster runner"]
Runner -->|"Scoped patch workspace"| OpenCode["OpenCode agents"]
Runner -->|"OIDC role"| Bedrock["Amazon Bedrock"]
Runner -->|"Octokit reads and verification"| GitHub["GitHub pull request"]
OpenCode -->|"Trusted local publication plugin"| GitHub
OpenCode -.->|"Raw process logs"| Runner
Bedrock -.->|"Model responses"| RunnerThe primary harbourmaster-review-editor session acts as the coordinator. It
invokes the specialist and verifier sessions, and it is the only session that
can publish to GitHub through one local publication tool configured by the
trusted action. The tool validates a runner-authored manifest, publishes the
review, applies prior-thread dispositions, and writes a private receipt.
OpenCode starts in an isolated diff directory with the trusted bundled
configuration. The code-quality reviewer alone also has read-only access to the
whole canonical checkout. Other specialists and the verifier remain limited to
the staged diff. Consumer OpenCode configuration remains untrusted review
context and cannot execute. For each editor attempt, the runner passes the
resolved GitHub token only in the OpenCode process environment. The trusted
publication plugin uses that process-level token. Specialist and verifier
sessions have no publication or GitHub tools and receive no token in their
session inputs. The runner verifies a new marked review on the exact head SHA
after OpenCode exits.
Runtime references follow repository role
Consumer repositories invoke TilloTech/eos/apps/harbourmaster@main. They
therefore receive only Harbourmaster changes that have merged to the EOS main
branch. The EOS repository invokes its local ./apps/harbourmaster action from
the pull request head so changes to Harbourmaster can be tested before merge.
The checkout action remains pinned separately because it prepares the reviewed workspace inside the OIDC-enabled job. EOS owns the transitive action dependencies inside Harbourmaster and reviews their pins before changing them.
Event and checkout identity must agree
The pull_request event supplies context to a workflow that owns both label
creation and review execution. A job guard excludes drafts and forks before
checkout or credentials are available. Automatic events run only while
harbourmaster-review is absent; explicitly re-adding that label requests
another review. When the label is already present, the job emits a warning and
fails before checkout so a required Harbourmaster check blocks the unreviewed
head. A human must remove and re-add the label to request re-review; automation
must not do so. The job receives the pull request number and exact head SHA
directly from that guarded event.
Harbourmaster verifies the checked-out Git HEAD against head_sha before
starting reviewers. This couples the review result to the code that triggered
the run and prevents a stale or implicit branch reference from changing the
review target. Consumer repositories load the Harbourmaster action from EOS
main. EOS self-reviews load the local action from the exact pull request head
so runtime changes are exercised before merge.
pull_request_target would move workflow execution into the privileged base
repository context. Combining that event with checkout of untrusted head code
would cross the intended trust boundary, so Harbourmaster consumer workflows do
not use it.
Security policy needs executable checks
The fork and draft guards, exact-head checkout, least-privilege permissions, disabled credential persistence, and runtime reference policy are security controls, not formatting conventions. Documentation records their purpose, but tests and workflow policy checks detect accidental removal or inversion.
EOS tests the shared action's packaging and its own workflow structure. A
consuming repository remains responsible for checking its workflow, including
the event, fork and draft guard, permissions, checkout SHA, and
persist-credentials: false setting.
Operator configuration belongs in operator documentation
An implementation specification can explain why an OIDC role is required, but it
is not the setup interface for repository operators. The required
HARBOURMASTER_AWS_ROLE_TO_ASSUME variable must be discoverable beside the
workflow setup, including where it is configured and what value it accepts.
This separation keeps intent records stable while allowing operational guidance to evolve with the supported action contract.
Portable records preserve traceability
Repository-relative paths and commit-anchored GitHub links remain resolvable by other contributors and CI. Machine-specific absolute paths only describe one author's checkout and weaken the connection between an implementation record and the files it references.
Cross-repository records identify both the repository and relative path, or use a permalink at the reviewed commit. This keeps the evidence behind trust decisions inspectable after the original workspace no longer exists.
EOS self-review is an invariant
Consumer repositories must load the Harbourmaster action from EOS main. EOS is
the deliberate exception: Harbourmaster must be able to test changes to its own
workflow and runtime before those changes merge.
For a same-repository, non-draft pull request in TilloTech/eos,
harbourmaster-review.yml must:
- check out the pull request head as the Harbourmaster runtime workspace;
- check out the same head SHA again at
.harbourmaster/repository; - invoke the local
./apps/harbourmasteraction; - pass
workspace_root: .harbourmaster/repository.
The action verifies that the reviewed checkout's Git HEAD equals the requested SHA before reviewer execution. Fork pull requests remain excluded by the job guard.
Consumer workflows check out the reviewed head once and invoke
TilloTech/eos/apps/harbourmaster@main. They must not copy the EOS dual
checkout or the local action path. The consumer checkout pin can differ from the
EOS pin. EOS owns the pins inside the Action.
This exception intentionally allows an EOS pull request to change code that runs
with the reviewer job's GitHub and AWS permissions. That tradeoff is limited to
branches in the EOS repository, where push access is already trusted. It must
not be generalized to consumer repositories or implemented with
pull_request_target.
The following behavior is therefore a repository invariant:
- EOS self-reviews execute the local action from the exact pull request head and
review the checkout at
.harbourmaster/repository. - Consumer reviews execute the Harbourmaster action from EOS
main. - Both paths use the native pull request job's same-repository and non-draft guard, pass the event's exact head SHA, and verify the reviewed checkout against it.
For the consumer workflow, see How to add Harbourmaster reviews to a repository. The original auth and fork decision is in AI-50.