mirror of
https://github.com/NanmiCoder/cc-haha
synced 2026-07-16 13:03:31 +08:00
Contributors and coding agents need one local command that both reports and enforces the quality contract. This change turns the PR gate into the shared verification entrypoint, adds path-selected local lanes, tightens coverage accounting around changed lines, and documents the repair loop in contributor and agent-facing guidance. Constraint: Ordinary PR verification must stay non-live and runnable without provider credentials Constraint: Coverage policy updates in this commit require maintainer approval before push/merge Rejected: Keep quality guidance only in docs | agents need executable scripts and AGENTS.md instructions to follow the loop consistently Confidence: high Scope-risk: broad Directive: Do not bypass `bun run verify` for production changes; fix failed lanes and coverage reports instead of lowering thresholds Tested: bun run check:policy Tested: ALLOW_CLI_CORE_CHANGE=1 ALLOW_COVERAGE_BASELINE_CHANGE=1 bun run verify Not-tested: live provider baseline; no provider credentials were required for this non-live PR gate
48 lines
2.3 KiB
TypeScript
48 lines
2.3 KiB
TypeScript
import { describe, expect, test } from 'bun:test'
|
|
import {
|
|
BINARY_HIJACK_VARS,
|
|
getFirstWordPrefix,
|
|
getSimpleCommandPrefix,
|
|
matchWildcardPattern,
|
|
stripAllLeadingEnvVars,
|
|
stripSafeWrappers,
|
|
stripWrappersFromArgv,
|
|
} from './bashPermissions'
|
|
|
|
describe('bash permission command normalization', () => {
|
|
test('extracts stable prefixes only through safe env vars', () => {
|
|
expect(getSimpleCommandPrefix('NODE_ENV=production npm run build')).toBe('npm run')
|
|
expect(getSimpleCommandPrefix('MY_VAR=value npm run build')).toBeNull()
|
|
expect(getSimpleCommandPrefix('git commit -m "fix"')).toBe('git commit')
|
|
expect(getSimpleCommandPrefix('chmod 755 file')).toBeNull()
|
|
})
|
|
|
|
test('uses first-word fallback without suggesting broad shell wrappers', () => {
|
|
expect(getFirstWordPrefix('python3 script.py 2>&1 | tail -20')).toBe('python3')
|
|
expect(getFirstWordPrefix('bash -c "rm -rf /tmp/x"')).toBeNull()
|
|
expect(getFirstWordPrefix('./script.sh')).toBeNull()
|
|
})
|
|
|
|
test('strips only safe wrappers and leading safe env assignments', () => {
|
|
expect(stripSafeWrappers('RUST_LOG=debug timeout -k 5s --signal TERM 10s nohup nice -n 5 -- git status')).toBe('git status')
|
|
expect(stripSafeWrappers('timeout -k$(id) 10s ls')).toBe('timeout -k$(id) 10s ls')
|
|
expect(stripSafeWrappers('timeout 10s FOO=bar npm test')).toBe('FOO=bar npm test')
|
|
})
|
|
|
|
test('normalizes wrapper argv with the same safety boundary', () => {
|
|
expect(stripWrappersFromArgv(['timeout', '--signal', 'TERM', '10s', 'nohup', 'git', 'status'])).toEqual(['git', 'status'])
|
|
expect(stripWrappersFromArgv(['timeout', '--signal', '$(id)', '10s', 'ls'])).toEqual(['timeout', '--signal', '$(id)', '10s', 'ls'])
|
|
expect(stripWrappersFromArgv(['nice', '-n', '5', '--', 'git', 'status'])).toEqual(['git', 'status'])
|
|
})
|
|
|
|
test('strips arbitrary leading env vars for deny matching but keeps binary hijack vars', () => {
|
|
expect(stripAllLeadingEnvVars('FOO=bar TOKEN="safe value" claude --help')).toBe('claude --help')
|
|
expect(stripAllLeadingEnvVars('PATH=/tmp/bin claude --help', BINARY_HIJACK_VARS)).toBe('PATH=/tmp/bin claude --help')
|
|
})
|
|
|
|
test('matches wildcard permission patterns consistently', () => {
|
|
expect(matchWildcardPattern('git *', 'git status --short')).toBe(true)
|
|
expect(matchWildcardPattern('git commit', 'git status')).toBe(false)
|
|
})
|
|
})
|