This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

vit / test / vet.test.js
11 kB 212 lines
1// SPDX-License-Identifier: MIT 2// Copyright (c) 2026 sol pbc 3 4import { describe, test, expect } from 'bun:test'; 5import { run } from './helpers.js'; 6import { mkdirSync, writeFileSync, readFileSync, existsSync, rmSync } from 'node:fs'; 7import { tmpdir } from 'node:os'; 8import { join } from 'node:path'; 9 10const noAgentEnv = { CLAUDECODE: '', GEMINI_CLI: '', CODEX_CI: '' }; 11const agentEnv = { CLAUDECODE: '1' }; 12 13describe('vit vet', () => { 14 test('shows help with [ref] argument', () => { 15 const result = run('vet --help'); 16 expect(result.stdout).toContain('[ref]'); 17 }); 18 19 test('rejects invalid ref format (human)', () => { 20 const result = run('vet not-valid', undefined, noAgentEnv); 21 expect(result.exitCode).not.toBe(0); 22 expect(result.stderr).toContain('invalid ref'); 23 }); 24 25 test('errors when no ref and no --dangerous-accept', () => { 26 const result = run('vet', undefined, noAgentEnv); 27 expect(result.exitCode).not.toBe(0); 28 expect(result.stderr).toContain('ref argument is required'); 29 }); 30 31 // --- dangerous-accept tests --- 32 33 describe('--dangerous-accept', () => { 34 test('without --confirm: prints warning, does NOT write flag', () => { 35 const tmp = join(tmpdir(), '.test-vet-da-' + Math.random().toString(36).slice(2)); 36 mkdirSync(join(tmp, '.vit'), { recursive: true }); 37 const result = run('vet --dangerous-accept', tmp, noAgentEnv); 38 expect(result.exitCode).toBe(0); 39 expect(result.stdout).toContain('WARNING'); 40 expect(result.stdout).toContain('--dangerous-accept --confirm'); 41 expect(existsSync(join(tmp, '.vit', 'dangerous-accept'))).toBe(false); 42 rmSync(tmp, { recursive: true, force: true }); 43 }); 44 45 test('with --confirm: writes flag file and .gitignore', () => { 46 const tmp = join(tmpdir(), '.test-vet-da-confirm-' + Math.random().toString(36).slice(2)); 47 mkdirSync(join(tmp, '.vit'), { recursive: true }); 48 const result = run('vet --dangerous-accept --confirm', tmp, noAgentEnv); 49 expect(result.exitCode).toBe(0); 50 expect(result.stdout).toContain('dangerous-accept enabled'); 51 expect(existsSync(join(tmp, '.vit', 'dangerous-accept'))).toBe(true); 52 const flagContent = JSON.parse(readFileSync(join(tmp, '.vit', 'dangerous-accept'), 'utf-8').trim()); 53 expect(flagContent.acceptedAt).toBeTruthy(); 54 const gitignore = readFileSync(join(tmp, '.vit', '.gitignore'), 'utf-8'); 55 expect(gitignore).toContain('dangerous-accept'); 56 rmSync(tmp, { recursive: true, force: true }); 57 }); 58 59 test('blocked when agent detected', () => { 60 const tmp = join(tmpdir(), '.test-vet-da-agent-' + Math.random().toString(36).slice(2)); 61 mkdirSync(join(tmp, '.vit'), { recursive: true }); 62 const result = run('vet --dangerous-accept', tmp, agentEnv); 63 expect(result.exitCode).toBe(1); 64 expect(result.stderr).toContain('human-only'); 65 expect(existsSync(join(tmp, '.vit', 'dangerous-accept'))).toBe(false); 66 rmSync(tmp, { recursive: true, force: true }); 67 }); 68 69 test('blocked with --confirm when agent detected', () => { 70 const tmp = join(tmpdir(), '.test-vet-da-agent-c-' + Math.random().toString(36).slice(2)); 71 mkdirSync(join(tmp, '.vit'), { recursive: true }); 72 const result = run('vet --dangerous-accept --confirm', tmp, agentEnv); 73 expect(result.exitCode).toBe(1); 74 expect(result.stderr).toContain('human-only'); 75 expect(existsSync(join(tmp, '.vit', 'dangerous-accept'))).toBe(false); 76 rmSync(tmp, { recursive: true, force: true }); 77 }); 78 79 test('running twice does not duplicate .gitignore entry', () => { 80 const tmp = join(tmpdir(), '.test-vet-da-twice-' + Math.random().toString(36).slice(2)); 81 mkdirSync(join(tmp, '.vit'), { recursive: true }); 82 run('vet --dangerous-accept --confirm', tmp, noAgentEnv); 83 run('vet --dangerous-accept --confirm', tmp, noAgentEnv); 84 const gitignore = readFileSync(join(tmp, '.vit', '.gitignore'), 'utf-8'); 85 const matches = gitignore.match(/dangerous-accept/g); 86 expect(matches.length).toBe(1); 87 rmSync(tmp, { recursive: true, force: true }); 88 }); 89 }); 90 91 // --- agent gate tests --- 92 93 describe('agent gate', () => { 94 test('agent without flags: error with sandboxed sub-agent hint', () => { 95 const result = run('vet fast-cache-invalidation', undefined, agentEnv); 96 expect(result.exitCode).toBe(1); 97 expect(result.stderr).toContain('vit vet is for operator review'); 98 expect(result.stderr).toContain('--trust --confirm'); 99 expect(result.stderr).toContain('sandboxed sub-agent'); 100 }); 101 102 test('agent with --trust but no --confirm: error', () => { 103 const result = run('vet fast-cache-invalidation --trust', undefined, agentEnv); 104 expect(result.exitCode).toBe(1); 105 expect(result.stderr).toContain('vit vet is for operator review'); 106 expect(result.stderr).toContain('--trust --confirm'); 107 }); 108 109 test('agent with --confirm but no --trust: error', () => { 110 const result = run('vet fast-cache-invalidation --confirm', undefined, agentEnv); 111 expect(result.exitCode).toBe(1); 112 expect(result.stderr).toContain('vit vet is for operator review'); 113 }); 114 115 test('agent with --trust --confirm: passes agent gate (fails at DID)', () => { 116 // Should pass agent gate but fail later at DID check 117 const configHome = join(tmpdir(), '.test-vet-tc-' + Math.random().toString(36).slice(2)); 118 mkdirSync(configHome, { recursive: true }); 119 const result = run('vet fast-cache-invalidation --trust --confirm', undefined, { ...agentEnv, XDG_CONFIG_HOME: configHome }); 120 // Should NOT contain the agent gate error 121 expect(result.stderr).not.toContain('vit vet is for operator review'); 122 rmSync(configHome, { recursive: true, force: true }); 123 }); 124 125 test('human with --trust --confirm: passes (--confirm harmless for humans)', () => { 126 const configHome = join(tmpdir(), '.test-vet-tc-human-' + Math.random().toString(36).slice(2)); 127 mkdirSync(configHome, { recursive: true }); 128 const result = run('vet fast-cache-invalidation --trust --confirm', undefined, { ...noAgentEnv, XDG_CONFIG_HOME: configHome }); 129 // Should NOT contain the agent gate error 130 expect(result.stderr).not.toContain('vit vet is for operator review'); 131 rmSync(configHome, { recursive: true, force: true }); 132 }); 133 }); 134 135 describe('--sandbox', () => { 136 test('--sandbox without agent outside agent env: error with hint', () => { 137 const result = run('vet fast-cache-invalidation --sandbox', undefined, noAgentEnv); 138 expect(result.exitCode).not.toBe(0); 139 expect(result.stderr).toContain('could not detect agent'); 140 expect(result.stderr).toContain('--sandbox claude'); 141 }); 142 143 test('--sandbox bogus: error about unknown agent', () => { 144 const result = run('vet fast-cache-invalidation --sandbox bogus', undefined, noAgentEnv); 145 expect(result.exitCode).not.toBe(0); 146 expect(result.stderr).toContain('unknown sandbox agent'); 147 }); 148 149 test('--sandbox claude accepted (passes validation, fails at DID)', () => { 150 const configHome = join(tmpdir(), '.test-vet-sb-' + Math.random().toString(36).slice(2)); 151 mkdirSync(configHome, { recursive: true }); 152 const result = run('vet fast-cache-invalidation --sandbox claude', undefined, { ...noAgentEnv, XDG_CONFIG_HOME: configHome }); 153 // Should NOT contain validation errors for sandbox agent 154 expect(result.stderr).not.toContain('unknown sandbox agent'); 155 rmSync(configHome, { recursive: true, force: true }); 156 }); 157 158 test('--sandbox codex accepted', () => { 159 const configHome = join(tmpdir(), '.test-vet-sb-codex-' + Math.random().toString(36).slice(2)); 160 mkdirSync(configHome, { recursive: true }); 161 const result = run('vet fast-cache-invalidation --sandbox codex', undefined, { ...noAgentEnv, XDG_CONFIG_HOME: configHome }); 162 expect(result.stderr).not.toContain('unknown sandbox agent'); 163 rmSync(configHome, { recursive: true, force: true }); 164 }); 165 166 test('--sandbox gemini accepted', () => { 167 const configHome = join(tmpdir(), '.test-vet-sb-gemini-' + Math.random().toString(36).slice(2)); 168 mkdirSync(configHome, { recursive: true }); 169 const result = run('vet fast-cache-invalidation --sandbox gemini', undefined, { ...noAgentEnv, XDG_CONFIG_HOME: configHome }); 170 expect(result.stderr).not.toContain('unknown sandbox agent'); 171 rmSync(configHome, { recursive: true, force: true }); 172 }); 173 174 test('--sandbox without value in agent env: auto-detects agent', () => { 175 const configHome = join(tmpdir(), '.test-vet-sb-auto-' + Math.random().toString(36).slice(2)); 176 mkdirSync(configHome, { recursive: true }); 177 const result = run('vet fast-cache-invalidation --sandbox', undefined, { ...agentEnv, XDG_CONFIG_HOME: configHome }); 178 // Should pass sandbox agent resolution (claude code → claude), fail later at DID 179 expect(result.stderr).not.toContain('could not detect agent'); 180 expect(result.stderr).not.toContain('unknown sandbox agent'); 181 rmSync(configHome, { recursive: true, force: true }); 182 }); 183 184 test('--sandbox passes agent gate (agent env + --sandbox flag)', () => { 185 const configHome = join(tmpdir(), '.test-vet-sb-gate-' + Math.random().toString(36).slice(2)); 186 mkdirSync(configHome, { recursive: true }); 187 const result = run('vet fast-cache-invalidation --sandbox claude', undefined, { ...agentEnv, XDG_CONFIG_HOME: configHome }); 188 // Should NOT contain the agent gate error 189 expect(result.stderr).not.toContain('vit vet is for operator review'); 190 rmSync(configHome, { recursive: true, force: true }); 191 }); 192 193 test('--sandbox shows in help output', () => { 194 const result = run('vet --help'); 195 expect(result.stdout).toContain('--sandbox'); 196 }); 197 198 test('--sandbox --json without agent outside agent env: JSON error', () => { 199 const result = run('vet fast-cache-invalidation --sandbox --json', undefined, noAgentEnv); 200 const parsed = JSON.parse(result.stdout); 201 expect(parsed.ok).toBe(false); 202 expect(parsed.error).toContain('could not detect agent'); 203 }); 204 205 test('--sandbox --json bogus: JSON error', () => { 206 const result = run('vet fast-cache-invalidation --sandbox bogus --json', undefined, noAgentEnv); 207 const parsed = JSON.parse(result.stdout); 208 expect(parsed.ok).toBe(false); 209 expect(parsed.error).toContain('unknown sandbox agent'); 210 }); 211 }); 212});