Pre-launch: verify forge runner settings for fork PRs (approval gate, no docker socket, egress isolation) #415
Labels
No labels
breaking
bug
documentation
enhancement
epic
good first issue
help wanted
refactoring
resolution/duplicate
resolution/invalid
resolution/wontfix
security
severity/critical
severity/high
severity/low
severity/medium
status/abandoned
status/blocked
status/needs-decision
status/needs-info
status/needs-verification
testing
upstream
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
sixfold-space/madtea#415
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Both CI-audit passes flagged that the workflows themselves are well designed: plain
pull_request(neverpull_request_target/workflow_run), anonymous checkout with no token, and no third-partyuses:actions. So the residual CI risk once public lives in runner and forge configuration that is NOT in repo source, and it must be confirmed before accepting fork PRs. This is a tracked checklist, not a code change.Confirm, at the forge and the runner:
/var/run/docker.sockinto job containers, andRUN_FORGEJO_SMOKEis unset anywhere a fork PR can reach. (Ties to #266 and the closed #265: the code-side fix there is to droppull_requestfrom the socket-privileged smoke job, and this item is the config-side confirmation.)Acceptance: all three confirmed and noted. A comment here recording the verification is enough. This should be done before the repo starts accepting fork PRs.
Runner-side verification done (2026-07-20) for items 2 and 3. Item 1, the fork-PR approval gate in the org Actions settings, is still open. It is a forge-UI setting.
2. No docker socket, and no smoke env reachable by fork PRs - CONFIRMED. From the runner's live job-container configuration:
docker_host: "-"- no docker host is mounted into job containers, neither automount nor a URL. Job containers get no/var/run/docker.sock.privileged: false- task containers never run privileged.valid_volumesis a closed allowlist of exactly the two named Go-cache volumes the workflows declare (madtea-gomod,madtea-gobuild). A workflow cannot mount arbitrary host paths or a socket even if it asks.envs: {}), there is no environment file, andRUN_FORGEJO_SMOKEappears nowhere in the runner or its service configuration. Forge-side, the repo and org Actions variable lists are both empty (verified via the API), so nothing injects it into fork-PR jobs there either.3. Egress isolation - RE-CONFIRMED, config and behavior. The runner's network interface carries a default-reject egress ACL. Its allow rules are DNS and DHCP to the gateway, plus an explicit public-internet CIDR allowlist. Private ranges are excluded by construction: no LAN, no overlay networks. Behavioral probe from inside the runner: the public forge answers (HTTP 200), and connections toward private-network destinations time out. The known failure mode this re-check exists for, an interface rebuild silently resetting the ACL to allow, has not occurred.
Leaving the issue open on item 1 only.
Re-checked against current
mainnow the repo is public.Code side (in-repo) - confirmed safe:
pull_request. There is nopull_request_targetand noworkflow_run, so fork code never runs in a privileged context.uses:appears nowhere. Checkout is an in-containergit initplus a shallow anonymous fetch of the PR ref. The repo is public, so it needs no token.if: vars.RUN_FORGEJO_SMOKE == 'true' && github.event_name != 'pull_request', so it never queues on a fork PR. The build cache volume-mounts and the smoke job's admin-token provisioning (against a throwaway in-job Forgejo container, not the real forge) are gated offpull_requestthe same way.Runner side: the workflows target the shared
dockerrunner. So two of the three original items are now the shared-runner platform's posture rather than repo config:pull_request.Remaining item, the one control that is ours:
3. Fork-PR approval gate - confirm the repo's Actions setting requires approval before workflows run from outside or first-time contributors. This is the single most important control, and the last thing to tick before accepting fork PRs.
Everything in the repo source is verified. This stays open on item 3 only.
Decided: the fork-PR approval gate is not needed. Access is already gated at the account level.
The repository is public to read, but the forge requires authentication for anything beyond read: forking, opening a pull request, and running a workflow all need an account, and I control who has one. There is no anonymous contributor who can trigger a workflow run, so the fork / first-time-contributor approval gate that item 1 asked about is redundant with the access model.
Items 2 and 3 stay as defense-in-depth and are already confirmed: the runner exposes no docker socket, and egress is isolated. In-repo workflow code was verified safe: plain
pull_requesttriggers, nopull_request_target, no third-partyuses:.Posture: account-level access control is the gate; runner isolation contains whatever a trusted contributor's PR runs. No approval-gate toggle required. Clearing needs-decision.