# GitHub Actions Integration
## Purpose
Rho should provide GitHub Actions that turn GitHub events into deterministic
Rho policy checks, mock-data runs, approval records, and protected executions.
The GitHub Actions are adapters. They should not own the trust model. Core
decisions belong to:
- `rho auth` for actor authorization
- `rho repo` for repo policy and PR diff checks
- `rho run` for protected execution
- `rho middleware` for approval, audit, and notification hooks
GitHub branch protection and rulesets enforce the result by requiring Rho status
checks before merge.
## Main Goals
- let admins merge ordinary and policy-changing changes
- prevent non-admins from changing policy, membership, participants, or protected
paths without admin approval
- allow unknown users to open join-request PRs without giving them broader write
power
- run submitted requests against mock data in untrusted CI
- require explicit approval before any request can run against private data
- keep every decision inspectable through files, comments, checks, and audit
artifacts
## Action Shape
Rho should follow the same packaging shape as Vouch:
```text
action/
setup-rho/
action.yml
README.md
check-pr/
action.yml
README.md
run-mock-request/
action.yml
README.md
manage-by-comment/
action.yml
README.md
run-real-request/
action.yml
README.md
```
Each action should be a composite GitHub Action that installs or invokes the
checked-out `rho` CLI. The action wrappers stay thin and pass GitHub event
metadata to Rust commands.
## Proposed Actions
### `setup-rho`
Installs or exposes the `rho` CLI for later workflow steps.
Initial implementation options:
- use the checked-out debug shim during development
- build with Cargo inside the action
- later download a release binary
### `check-pr`
Evaluates the pull request actor, changed paths, request manifests, and repo
policy.
It should call a deterministic command such as:
```bash
rho repo check-pr \
--root . \
--event "$GITHUB_EVENT_PATH" \
--base-ref "${GITHUB_BASE_REF:-main}" \
--head-sha "$GITHUB_SHA" \
--format json
```
Expected outcomes:
- `pass`: the actor and diff are allowed
- `blocked`: the actor or diff violates policy
- `pending`: admin approval is required
The action should write:
- a GitHub step output named `status`
- a concise job summary
- optional PR comments when configured
### `run-mock-request`
Runs request manifests against mock data only.
This action must run from `pull_request`, not `pull_request_target`, because it
may checkout and execute untrusted PR code. It must not receive secrets.
It should:
- validate request manifests
- validate code paths and digests
- substitute only mock dataset paths
- use `rho run` with a mock tier
- upload run manifests, stdout, stderr, and sandbox manifests as artifacts
### `manage-by-comment`
Processes admin comments on issues or PRs.
Initial comment commands:
```text
/rho approve-join
/rho approve-mock <request-id>
/rho approve-real <request-id>
/rho deny <request-id>
/rho recheck
```
The action should verify that the commenter is allowed to manage the action,
then record the approval through a Rho command such as:
```bash
rho request approve <request-id> \
--shared-root . \
--decision approve \
--actor rho://id/github/<commenter> \
--note "<comment-url>"
```
When the approval changes committed repo state, the action can either push
directly or open a PR, depending on configuration.
### `run-real-request`
Runs approved requests against private data.
This action must only run under a protected GitHub Environment or an equivalent
admin-controlled trigger. It may receive private data credentials or mount
private data, so it must never run untrusted PR code without prior Rho approval.
It should:
- re-check the approval record
- re-check the request and code digest
- use `rho run` or `rho run controlled-action`
- write audit artifacts
- publish only explicitly approved release outputs
## Actor Rules
Rho should normalize GitHub actors into Rho identities:
```text
github login: alice
rho identity: rho://id/github/alice
```
Initial roles:
- `admin`: can modify policy, membership, participants, and protected paths
- `member`: can submit normal workspace changes and mock-run requests
- `unknown`: can only submit join-request material
- `blocked`: denied for all Rho actions
The action should also treat GitHub bots explicitly. Dependabot or GitHub Apps
may be allowed for specific paths, but bot allowance must be policy-backed, not
implicit.
## Diff Rules
Initial `check-pr` path policy:
```text
admin only:
rho.yaml
rho/membership.yaml
rho/policy/**
rho/tools/**
rho/participants/**
.github/workflows/**
action/**
unknown user allowed:
rho/participants/<actor>.yaml
rho/requests/join-*.yaml
member allowed:
workspace/**
rho/requests/**
rho/messages/**
datasets/public/**
```
These should be defaults derived from committed Rho policy, not hard-coded
forever.
## Auto-Close Behavior
Rho can support Vouch-style auto-close for PRs that are clearly not allowed.
This should be an option on `check-pr`:
```yaml
with:
auto-close: true
require-member: true
```
The action should only auto-close deterministic denials, for example:
- blocked actor
- unknown actor changed admin-only paths
- non-admin changed policy or workflow files
- malformed Rho request that cannot be parsed
- request tries to reference private data from an unapproved context
The action should not auto-close cases that need human judgment. Those should
stay open with a failing or pending Rho status and a comment explaining what
approval is needed.
Safe auto-close flow:
1. evaluate PR with `rho repo check-pr`
2. receive `status: blocked` and `close_recommended: true`
3. post a short explanatory comment
4. close the PR through the GitHub API
Auto-close requires `pull-requests: write` permission and should run in a
metadata-only workflow. If a workflow uses `pull_request_target`, it must not
checkout or execute code from the untrusted PR branch.
## Recommended Workflows
### PR Policy
```yaml
name: Rho PR Policy
on:
pull_request_target:
types: [opened, reopened, synchronize, ready_for_review]
permissions:
contents: read
pull-requests: write
jobs:
policy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.base.sha }}
- uses: ./action/setup-rho
- uses: ./action/check-pr
with:
pr-number: ${{ github.event.pull_request.number }}
auto-close: true
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
```
This workflow checks metadata and base policy. It must not execute untrusted PR
code.
### Mock Request Run
```yaml
name: Rho Mock Request
on:
pull_request:
types: [opened, reopened, synchronize]
permissions:
contents: read
jobs:
mock:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: ./action/setup-rho
- uses: ./action/run-mock-request
with:
pr-number: ${{ github.event.pull_request.number }}
```
This workflow may execute PR code, so it must not receive secrets and must only
use mock data.
### Admin Comment Management
```yaml
name: Rho Manage
on:
issue_comment:
types: [created]
concurrency:
group: rho-manage
cancel-in-progress: false
permissions:
contents: write
issues: write
pull-requests: write
jobs:
manage:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: ./action/setup-rho
- uses: ./action/manage-by-comment
with:
issue-number: ${{ github.event.issue.number }}
comment-id: ${{ github.event.comment.id }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
```
## Branch Protection
GitHub enforcement should require these checks before merge:
- `Rho PR Policy`
- `Rho Mock Request` when request files or executable workspace files changed
- normal build and test CI
Admins may be listed as ruleset bypass actors if the project wants admin merges
to bypass some checks. If Rho itself needs to push, approve, or merge through
branch protection, use a private GitHub App token rather than relying on the
default `GITHUB_TOKEN`.
## Implementation Milestones
### Milestone 1: Policy Check
- add `rho repo check-pr`
- add `action/setup-rho`
- add `action/check-pr`
- add `.github/workflows/rho-pr-policy.yml`
- support pass, blocked, pending, and optional auto-close
### Milestone 2: Mock Runs
- add `action/run-mock-request`
- normalize request discovery in PRs
- run only mock-tier requests
- upload Rho run artifacts
- make mock-run status a required check
### Milestone 3: Comment Approvals
- add `action/manage-by-comment`
- support approve and deny comments
- record approvals as Rho files
- re-run policy checks after approval
### Milestone 4: Real Runs
- add `action/run-real-request`
- require protected GitHub Environment approval
- re-check digests and approval records
- execute through `rho run`
- publish only approved outputs
## Open Design Questions
- whether membership should live only in `rho/membership.yaml` or be mirrored to
GitHub teams/CODEOWNERS
- whether join requests should be PRs, issues, or either
- how much of the initial policy should be generated by `rho repo init`
- how to reconcile the current runtime `.rho/` layout with the committed `rho/`
layout used by repo initialization
- whether auto-close should be enabled by default or only explicitly configured