Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions quest/m0/kix/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,11 @@ operator-paid-hosting decisions:
keeps GitHub credentials off runners. It pushes job branches to the
enrolled repository itself, with no service forks (decided 2026-10-27,
user, in [Upstream branches](/quest/m0/kix/upstream-branches.md)).
- **Read-only CI, signed trust** (decided 2026-10-28, user, trust audit).
Enrolled repositories keep pull-request CI read-only instead of kix
shielding CI behind forks or per-push gates. Host trust comes from
maintainer signatures or an explicit approval of the exact head, never from
kix having published a commit. Landing needs a review of the exact head.
- **Ready means eligible.** After a maintainer opts in, ready quests on the
default branch may be implemented. Draft plans are not eligible. Project
pause stops new work. An explicit spawn decision can prioritize ready work
Expand Down Expand Up @@ -123,10 +128,12 @@ fixes what it finds:

- [Deploy kix.quest](/quest/m0/kix/deploy.md) - the operator registers the App and deploys the Worker with GitHub sign-in at kix.quest
- [Upstream branches](/quest/m0/kix/upstream-branches.md) - jobs publish on the enrolled repository itself, with no service forks
- [Read-only CI](/quest/m0/kix/ci-read-only.md) - enrolled repositories keep pull-request CI read-only, checked at enrollment, with every trust boundary written down
- [Operator setup](/quest/m0/kix/operator-setup.md) - pilot installations and a verified test PR on kixelated/quest and moq-dev/moq
- [App sign-in](/quest/m0/kix/app-sign-in.md) - one GitHub screen signs in and installs the App, with no separate OAuth app
- [Pick repositories](/quest/m0/kix/pick-repos.md) - after installing, the maintainer enables repositories from a list
- [Setup PR](/quest/m0/kix/setup-pr.md) - enrolling a repository without Quest makes the App open its `quest init` pull request
- [Job sandbox](/quest/m0/kix/sandbox/README.md) - untrusted PR devShells built in a VM on Linux runners, maintainer PR heads trusted, opencode sandboxed, and macOS verified
- [Web execution](/quest/m0/kix/execution.md) - spawn and iterate through the UI, ending in contribution PRs
- [Land review](/quest/m0/kix/land-review.md) - kix lands only heads with a review that counts on that exact head
- [Onboarding guide](/quest/m0/kix/guide.md) - a complete maintainer path, from runner setup through a reviewed PR
53 changes: 53 additions & 0 deletions quest/m0/kix/ci-read-only.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# [M] Require read-only pull-request CI

## Goal

Every kix trust boundary is written down, and enrolled repositories keep
pull-request CI read-only. kix publishes job branches on the repository
itself, where GitHub gives a branch's workflows the repository's secrets and
default token. So code no maintainer has reviewed must meet only a read-only
`GITHUB_TOKEN` and no write credentials. kix checks this when a repository is
enrolled and warns the maintainer about what to fix. `cloudflare/GITHUB.md`
states the trust rule for each stage of a job.

## Plan

Decided 2026-10-28 (user, /quest-plan trust audit started from
kixelated/quest#246's Codex Security P1):

- **Rule over gates.** Read-only CI replaces a service fork or a per-push
review gate as the answer to agent-written code reaching CI. Fork PRs
already get no secrets; same-repository branches need the repository's own
settings to match. The guide states the rule for agents
([kixelated/quest#263](https://github.com/kixelated/quest/pull/263)).
- **Check and warn, don't refuse.** At enrollment, and on the project's
settings page, kix reports each problem it finds:
- the default workflow token can write;
- Actions secrets at repository level;
- an environment with secrets but no protected-branch deployment policy.

Jobs still run. Check which App permission reads secret and environment
metadata; adding one is an operator step in `cloudflare/GITHUB.md`.
- **Runner claims are the owner's attestation.** Jobs go only to the
requester's own runners, so a runner's self-declared `vm` flag and its
request to mark a PR ready are its owner's statements. kix doesn't verify
them. Under read-only CI, a runner marking its PR ready starts only harmless
CI.
- Rewrite `cloudflare/GITHUB.md`'s trust section as a stage-by-stage table:
intake, job creation, routing, devShell, agent run, publication, CI, review,
and land. For each stage, name what is trusted and why. Fix the
contradiction between `cloudflare/README.md` ("route only to Linux runners
that declare VM builds") and the root README (every runner refuses untrusted
jobs).
- `SETUP.md` recommends the same settings when a repository adopts Quest,
beside its advice to skip CI on drafts.
- The pilot repositories pass the check before contributors are invited:
kixelated/quest's `land` environment was limited to `main` on 2026-10-28,
and moq-dev/moq tracks its fix in
[read-only secrets](https://github.com/moq-dev/moq/blob/main/quest/m0/ci/read-only-secrets.md).

## Related

- [Operator setup](/quest/m0/kix/operator-setup.md) - pilot repositories should pass this check
- [Land review](/quest/m0/kix/land-review.md) - the land stage's trust rule
- [Head approval](/quest/m0/kix/sandbox/head-approval.md) - the devShell stage's trust rule for heads without signatures
36 changes: 36 additions & 0 deletions quest/m0/kix/land-review.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# [M] Land only reviewed heads

## Goal

kix lands a PR only when the exact head being landed has a review that counts
under the repository's review policy. This covers both an inbox merge and a
merge job's `land` publication. A maintainer's earlier merge pick alone never
lands a head that a runner published or changed since the last review. When
landing waits, kix says why.

## Plan

Decided 2026-10-28 (user, /quest-plan trust audit):

- Today a merge job lands a runner-published head on the maintainer's earlier
pick, bounded only by branch rules. kixelated/quest's `main` requires no
reviews, so nothing enforces the review policy at that point.
- Apply the guide's rule: a review counts only on the head being landed. The
only exemptions are a conflict-free base merge and a reviewer's patch applied
unchanged. Where a repository's policy names whose review counts (for
kixelated/quest, a Codex review or 👍 on the head, in `CONTRIBUTING.md`),
follow it. Otherwise require a review from someone other than the PR's
author and the App.
- Defer to GitHub branch protection only where it enforces the same
current-head rule: it requires approval of the most recent push, or it
dismisses stale approvals. Protection that accepts an approval of an older
head does not count; keep kix's exact-head check there.
- Test landing with a review of an older head, with a conflict-free base merge
since the review, with a hand-resolved conflict since the review, with only
an AI comment from the author's account, and under protection that requires
reviews without dismissing stale ones.

## Related

- [Web execution](/quest/m0/kix/execution.md) - merge jobs this rule gates
- [Require read-only pull-request CI](/quest/m0/kix/ci-read-only.md) - the trust model this completes
1 change: 1 addition & 0 deletions quest/m0/kix/sandbox/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ Shipped in [kixelated/quest#212](https://github.com/kixelated/quest/pull/212)

- [Claude Code pin](/quest/m0/kix/sandbox/claude-pin.md) - the runner's pinned Claude Code moves to the version the sandbox docs describe
- [Trusted PR heads](/quest/m0/kix/sandbox/trust.md) - PR heads whose commits all come from maintainers or kix jobs run on any runner
- [Head approval](/quest/m0/kix/sandbox/head-approval.md) - a maintainer approves an exact head, such as one kix pushed, for host runners
- [opencode sandboxing](/quest/m0/kix/sandbox/opencode.md) - opencode jobs' commands run in the same sandbox as Claude Code's
- [macOS sandbox](/quest/m0/kix/sandbox/macos.md) - the boundary verified under Seatbelt, then the answer-approval gate removed
- [Ubuntu AppArmor](/quest/m0/kix/sandbox/apparmor.md) - the sandbox starts on stock Ubuntu, or the runner refuses at startup
Expand Down
34 changes: 34 additions & 0 deletions quest/m0/kix/sandbox/head-approval.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# [M] Approve a PR head for host runners

## Goal

A maintainer can approve one exact PR head in kix, so its iterate and merge
jobs run on any runner even though not every commit carries a maintainer
signature. The common case is a head kix itself pushed. The approval covers
only that SHA. It lapses when the head moves, and kix rechecks the approver's
current maintain or admin role each time it relies on the approval.

## Plan

Decided 2026-10-28 (user, /quest-plan trust audit, from Codex Security's P1 on
[kixelated/quest#243](https://github.com/kixelated/quest/pull/243)):

- **Publication is not trust.** kix publishes whatever the runner sends. A
prompt-injected agent or a compromised runner could therefore publish a
`flake.nix` that host Nix evaluates outside the sandbox. So "kix pushed it"
never grants host trust. [Trusted PR heads](/quest/m0/kix/sandbox/trust.md)
trusts only commits signed by current maintainers and drops the publication
ledger.
- This quest adds the explicit path. Show the approval as a decision item
linking GitHub's compare view of the commits beyond the default branch.
Record the approver, the SHA, and the time. Recheck the approval at job
creation and at assignment, as trust classification does.
- GitHub's PR approvals can't serve: the maintainer usually authors these
PRs, and can't approve their own.
- Test approval of a kix-pushed head, a head that moves after approval, an
approver who loses the role, and an approval from someone who isn't a
maintainer.

## Required

- [Trusted PR heads](/quest/m0/kix/sandbox/trust.md) - signature-only host trust, which this extends
Loading