Files
orca/src/shared/git-exec-mutation.ts
T
Neil 080c95940f fix(ssh): let fork-PR worktrees add their contributor remote via the relay (#15827)
* fix(ssh): let fork-PR worktrees add their contributor remote via the relay

Creating a workspace from a fork PR on an SSH host failed with "Destructive
git remote operations are not allowed via exec". The relay's git.exec
allowlist blocked every `remote` write subcommand, but SSH fork-PR creation
has to run `git remote add <fork> <url>` on the host before it can fetch and
track the contributor's branch, so the whole create aborted.

Allow exactly the two shapes that flow needs -- `remote add <name> <url>` and
`remote remove <name>` -- validated with the same remote-name and URL rules
the relay already applies to every pushTarget-carrying RPC. Everything else
(set-url, rename, prune, extra operands, flags before the action) stays
blocked, and the URL must be a github.com clone/ssh URL, so no new reach is
granted beyond what push/fetch already accept.

`remote remove` was blocked too, which silently leaked fork remotes on SSH
hosts: worktree removal swallows the cleanup error. It works again now.

A host still running an older relay gets an actionable "reconnect to deploy
the latest relay" message instead of the raw policy error.

* test(git-exec): pin remote read/write mutation classification

Misclassifying `git remote` / `remote get-url` as mutating would flush the
relay and SSH provider git read caches on every remote probe, so pin both
directions.
2026-08-21 14:44:08 -07:00

14 lines
656 B
TypeScript

const MUTATING_GIT_EXEC_SUBCOMMANDS = new Set(['clone', 'commit', 'init'])
// Why: `git remote` also serves the bare list and get-url reads, so only the
// permitted fork-remote writes may invalidate cached reads.
const MUTATING_GIT_REMOTE_ACTIONS = new Set(['add', 'remove'])
// Why: relay git.exec permits these narrow write shapes alongside read-only
// probes, so cache invalidation must distinguish them before dispatch.
export function gitExecMutatesRepository(args: readonly string[]): boolean {
if (args[0] === 'remote') {
return MUTATING_GIT_REMOTE_ACTIONS.has(args[1] ?? '')
}
return MUTATING_GIT_EXEC_SUBCOMMANDS.has(args[0] ?? '')
}