harden IPC: reject -prefixed git refs, cap files.read / git.log (T-104)
test / unit + widget + golden + a11y (push) Failing after 31s
test / integration_test (xvfb) (push) Has been skipped
test / bundle smoke (xvfb 5s) (push) Has been skipped
test / daemon subprocess + web WASM smoke (push) Has been skipped
test / dart doc (lib API) (push) Failing after 1m0s
test / unit + widget + golden + a11y (push) Failing after 31s
test / integration_test (xvfb) (push) Has been skipped
test / bundle smoke (xvfb 5s) (push) Has been skipped
test / daemon subprocess + web WASM smoke (push) Has been skipped
test / dart doc (lib API) (push) Failing after 1m0s
Three security fixes the consultant flagged: * git.checkout, git.push now reject branch/remote arguments starting with `-` via a top-level validateGitRef helper. `git push` also gets a `--` option terminator; checkout can't use `--` without changing semantics (it would be parsed as a pathspec), so the validator is the only line of defence there. * files.read caps responses at 10 MB so a single call can't OOM the UI on a multi-gigabyte log. * git.log caps `count` at 1000; git.diff / git.stage cap paths at 256. Excess is a userError rather than burning subprocess time. The bigger typed-schema framework (item 1 in T-104) is split out as T-120 since it needs design discussion alongside T-99. Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -227,6 +227,48 @@ void main() {
|
||||
} on GitException catch (_) {}
|
||||
});
|
||||
|
||||
test('gitPush rejects a -prefixed remote (argv-injection guard)', () async {
|
||||
try {
|
||||
await gitPush(sandbox, remote: '--upload-pack=evil', branch: 'main');
|
||||
fail('expected GitException');
|
||||
} on GitException catch (e) {
|
||||
expect(e.message, contains('remote'));
|
||||
}
|
||||
});
|
||||
|
||||
test('gitPush rejects a -prefixed branch', () async {
|
||||
try {
|
||||
await gitPush(sandbox, remote: 'origin', branch: '--exec=evil');
|
||||
fail('expected GitException');
|
||||
} on GitException catch (e) {
|
||||
expect(e.message, contains('branch'));
|
||||
}
|
||||
});
|
||||
|
||||
test('gitCheckout rejects a -prefixed branch', () async {
|
||||
try {
|
||||
await gitCheckout(sandbox, '--upload-pack=evil');
|
||||
fail('expected GitException');
|
||||
} on GitException catch (e) {
|
||||
expect(e.message, contains('branch'));
|
||||
}
|
||||
});
|
||||
|
||||
test('gitCheckout rejects an empty branch', () async {
|
||||
try {
|
||||
await gitCheckout(sandbox, '');
|
||||
fail('expected GitException');
|
||||
} on GitException catch (e) {
|
||||
expect(e.message, contains('branch'));
|
||||
}
|
||||
});
|
||||
|
||||
test('validateGitRef accepts plain refs', () {
|
||||
expect(() => validateGitRef('main', kind: 'branch'), returnsNormally);
|
||||
expect(() => validateGitRef('feature/foo', kind: 'branch'), returnsNormally);
|
||||
expect(() => validateGitRef('origin', kind: 'remote'), returnsNormally);
|
||||
});
|
||||
|
||||
test('gitPull against no remote throws GitException', () async {
|
||||
try {
|
||||
await gitPull(sandbox);
|
||||
|
||||
Reference in New Issue
Block a user