open source is social v-it.org
0
fork

Configure Feed

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

learn: replace CLAUDE_SKIP_PERMISSIONS with trust-gate

Remove all references to CLAUDE_SKIP_PERMISSIONS env var and
process.argv --dangerously-skip-permissions check. Replace with
shouldBypassVet() from trust-gate module.

Error messages now include dangerous-accept hint when agent detected.
--user install still always requires explicit vetting regardless of
dangerous-accept.

Breaking change: CLAUDE_SKIP_PERMISSIONS=1 no longer bypasses vet.
This is intentional — one mechanism (the flag file) replaces the
env var that was never auto-set by Claude Code anyway.

Tests updated: removed skip-perms tests, added dangerous-accept
bypass tests, verified env var no longer works.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

+63 -46
+12 -7
src/cmd/learn.js
··· 8 8 import { SKILL_COLLECTION } from '../lib/constants.js'; 9 9 import { restoreAgent } from '../lib/oauth.js'; 10 10 import { readFollowing, readLog, appendLog } from '../lib/vit-dir.js'; 11 - import { requireAgent } from '../lib/agent.js'; 11 + import { requireAgent, detectCodingAgent } from '../lib/agent.js'; 12 + import { shouldBypassVet } from '../lib/trust-gate.js'; 12 13 import { isSkillRef, nameFromSkillRef, isValidSkillRef } from '../lib/skill-ref.js'; 13 14 import { mark, name } from '../lib/brand.js'; 14 15 import { resolvePds, listRecordsFromPds } from '../lib/pds.js'; ··· 69 70 } 70 71 71 72 if (!isUserInstall && !trustedEntry) { 72 - // Project-level: requires vet UNLESS skip-perms 73 - // Check if running in skip-perms mode (dangerously-skip-permissions) 74 - const skipPerms = process.env.CLAUDE_SKIP_PERMISSIONS === '1' || 75 - process.argv.includes('--dangerously-skip-permissions'); 76 - if (!skipPerms) { 73 + // Project-level: requires vet UNLESS dangerous-accept 74 + const trustGate = shouldBypassVet(); 75 + if (!trustGate.bypass) { 77 76 console.error(`skill '${ref}' is not yet vetted.`); 78 77 console.error(`ask the user to vet it first:`); 79 78 console.error(''); ··· 82 81 console.error('after reviewing, they can trust it with:'); 83 82 console.error(''); 84 83 console.error(` vit vet ${ref} --trust`); 84 + if (detectCodingAgent()) { 85 + console.error(''); 86 + console.error('or, to trust all items without review:'); 87 + console.error(''); 88 + console.error(' vit vet --dangerous-accept --confirm'); 89 + } 85 90 process.exitCode = 1; 86 91 return; 87 92 } 88 - if (verbose) console.log('[verbose] skip-perms mode: bypassing vet for project-level install'); 93 + if (verbose) console.log(`[verbose] vet gate bypassed: ${trustGate.reason}`); 89 94 } 90 95 91 96 const did = requireDid(opts);
+51 -39
test/learn.test.js
··· 49 49 rmSync(tmp, { recursive: true, force: true }); 50 50 }); 51 51 52 - test('requires vet for project-level install without skip-perms', () => { 52 + test('requires vet for project-level install without dangerous-accept', () => { 53 53 const tmp = join(tmpdir(), '.test-learn-proj-' + Math.random().toString(36).slice(2)); 54 54 mkdirSync(join(tmp, '.vit'), { recursive: true }); 55 55 const r = run('learn skill-test --did did:plc:test123', tmp, agentEnv); ··· 58 58 rmSync(tmp, { recursive: true, force: true }); 59 59 }); 60 60 61 - test('errors when no DID configured (with skip-perms for project-level)', () => { 62 - // Use skip-perms to bypass vet, then hit DID check 63 - const configHome = join(tmpdir(), '.test-learn-config-' + Math.random().toString(36).slice(2)); 64 - mkdirSync(configHome, { recursive: true }); 65 - const r = run('learn skill-test', '/tmp', { ...agentEnv, XDG_CONFIG_HOME: configHome, CLAUDE_SKIP_PERMISSIONS: '1' }); 66 - expect(r.exitCode).not.toBe(0); 67 - expect(r.stderr).toContain('no DID configured'); 68 - rmSync(configHome, { recursive: true, force: true }); 69 - }); 61 + // --- trust gate tests --- 70 62 71 - test('trust gate: vet check happens before network call', () => { 72 - // Even with a valid DID, should fail at vet check 73 - const tmp = join(tmpdir(), '.test-learn-trust-' + Math.random().toString(36).slice(2)); 74 - mkdirSync(join(tmp, '.vit'), { recursive: true }); 75 - const r = run('learn skill-test --did did:plc:test123', tmp, agentEnv); 76 - expect(r.exitCode).not.toBe(0); 77 - expect(r.stderr).toContain('not yet vetted'); 78 - expect(r.stderr).toContain('vit vet skill-test'); 79 - rmSync(tmp, { recursive: true, force: true }); 80 - }); 63 + describe('trust gate', () => { 64 + test('CLAUDE_SKIP_PERMISSIONS env var no longer bypasses vet', () => { 65 + const tmp = join(tmpdir(), '.test-learn-noskip-' + Math.random().toString(36).slice(2)); 66 + mkdirSync(join(tmp, '.vit'), { recursive: true }); 67 + const r = run('learn skill-test --did did:plc:test123', tmp, { ...agentEnv, CLAUDE_SKIP_PERMISSIONS: '1' }); 68 + expect(r.exitCode).not.toBe(0); 69 + // Should STILL fail at vet check — env var no longer works 70 + expect(r.stderr).toContain('not yet vetted'); 71 + rmSync(tmp, { recursive: true, force: true }); 72 + }); 81 73 82 - test('trust gate: skip-perms bypasses vet for project-level', () => { 83 - // With skip-perms, should pass vet and fail at auth 84 - const tmp = join(tmpdir(), '.test-learn-skip-' + Math.random().toString(36).slice(2)); 85 - mkdirSync(join(tmp, '.vit'), { recursive: true }); 86 - const r = run('learn skill-test --did did:plc:test123', tmp, { ...agentEnv, CLAUDE_SKIP_PERMISSIONS: '1' }); 87 - expect(r.exitCode).not.toBe(0); 88 - // Should NOT fail at vet check 89 - expect(r.stderr).not.toContain('not yet vetted'); 90 - rmSync(tmp, { recursive: true, force: true }); 91 - }); 74 + test('dangerous-accept bypasses vet for project-level install', () => { 75 + const tmp = join(tmpdir(), '.test-learn-da-' + Math.random().toString(36).slice(2)); 76 + mkdirSync(join(tmp, '.vit'), { recursive: true }); 77 + writeFileSync(join(tmp, '.vit', 'dangerous-accept'), JSON.stringify({ acceptedAt: '2026-03-26T14:30:00.000Z' })); 78 + const r = run('learn skill-test --did did:plc:test123', tmp, agentEnv); 79 + // Should bypass vet check — will fail later at auth, NOT at vet 80 + expect(r.stderr).not.toContain('not yet vetted'); 81 + rmSync(tmp, { recursive: true, force: true }); 82 + }); 92 83 93 - test('trust gate: skip-perms does NOT bypass vet for --user', () => { 94 - const tmp = join(tmpdir(), '.test-learn-skip-user-' + Math.random().toString(36).slice(2)); 95 - mkdirSync(join(tmp, '.vit'), { recursive: true }); 96 - const r = run('learn skill-test --user --did did:plc:test123', tmp, { ...agentEnv, CLAUDE_SKIP_PERMISSIONS: '1' }); 97 - expect(r.exitCode).not.toBe(0); 98 - // Should STILL fail at vet check for --user 99 - expect(r.stderr).toContain('not yet vetted'); 100 - expect(r.stderr).toContain('user-wide install requires vetting'); 101 - rmSync(tmp, { recursive: true, force: true }); 84 + test('dangerous-accept does NOT bypass vet for --user install', () => { 85 + const tmp = join(tmpdir(), '.test-learn-da-user-' + Math.random().toString(36).slice(2)); 86 + mkdirSync(join(tmp, '.vit'), { recursive: true }); 87 + writeFileSync(join(tmp, '.vit', 'dangerous-accept'), JSON.stringify({ acceptedAt: '2026-03-26T14:30:00.000Z' })); 88 + const r = run('learn skill-test --user --did did:plc:test123', tmp, agentEnv); 89 + expect(r.exitCode).not.toBe(0); 90 + // Should STILL fail at vet check for --user 91 + expect(r.stderr).toContain('not yet vetted'); 92 + expect(r.stderr).toContain('user-wide install requires vetting'); 93 + rmSync(tmp, { recursive: true, force: true }); 94 + }); 95 + 96 + test('error includes dangerous-accept hint when agent detected', () => { 97 + const tmp = join(tmpdir(), '.test-learn-hint-' + Math.random().toString(36).slice(2)); 98 + mkdirSync(join(tmp, '.vit'), { recursive: true }); 99 + const r = run('learn skill-test --did did:plc:test123', tmp, agentEnv); 100 + expect(r.exitCode).not.toBe(0); 101 + expect(r.stderr).toContain('vit vet --dangerous-accept --confirm'); 102 + rmSync(tmp, { recursive: true, force: true }); 103 + }); 104 + 105 + test('vet check happens before network call', () => { 106 + const tmp = join(tmpdir(), '.test-learn-trust-' + Math.random().toString(36).slice(2)); 107 + mkdirSync(join(tmp, '.vit'), { recursive: true }); 108 + const r = run('learn skill-test --did did:plc:test123', tmp, agentEnv); 109 + expect(r.exitCode).not.toBe(0); 110 + expect(r.stderr).toContain('not yet vetted'); 111 + expect(r.stderr).toContain('vit vet skill-test'); 112 + rmSync(tmp, { recursive: true, force: true }); 113 + }); 102 114 }); 103 115 });