Files
orca/src/shared/git-exec-mutation.test.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

28 lines
964 B
TypeScript

import { describe, expect, it } from 'vitest'
import { gitExecMutatesRepository } from './git-exec-mutation'
describe('gitExecMutatesRepository', () => {
it.each([
[['remote', 'add', 'pr-contributor-orca', 'https://github.com/contributor/orca.git']],
[['remote', 'remove', 'pr-contributor-orca']],
[['clone', '--', 'https://github.com/stablyai/orca.git', 'orca']],
[['commit', '--allow-empty', '-m', 'Initial commit']],
[['init']]
])('treats %j as mutating', (args) => {
expect(gitExecMutatesRepository(args)).toBe(true)
})
it.each([
// Why: these run on read-heavy paths; misclassifying them would flush the
// git read cache on every remote probe.
[['remote']],
[['remote', '-v']],
[['remote', 'get-url', 'origin']],
[['remote', 'show', 'origin']],
[['rev-parse', '--show-toplevel']],
[[]]
])('treats %j as read-only', (args) => {
expect(gitExecMutatesRepository(args)).toBe(false)
})
})