/** * _sandbox + _errors 单测 */ const path = require('path'); const { ToolValidationError, ToolSandboxError, ToolMissingDependencyError, } = require('../../../src/tools/devloop/_errors'); const sandbox = require('../../../src/tools/devloop/_sandbox'); describe('errors', () => { it('ToolValidationError carries field + reason', () => { const e = new ToolValidationError('html', 'too short'); expect(e.name).toBe('ToolValidationError'); expect(e.field).toBe('html'); expect(e.reason).toBe('too short'); expect(e.message).toContain('too short'); }); it('ToolSandboxError reports agent + path', () => { const e = new ToolSandboxError('/etc/passwd', 'coder'); expect(e.name).toBe('ToolSandboxError'); expect(e.path).toBe('/etc/passwd'); expect(e.agent).toBe('coder'); }); it('ToolMissingDependencyError names missing dep', () => { const e = new ToolMissingDependencyError('ctx.pid'); expect(e.message).toMatch(/ctx\.pid/); }); }); describe('_sandbox', () => { const ctx = { agent: 'coder', projectDir: '/tmp/my-proj', unit_id: 'u-be-auth', }; it('matches exact file pattern', () => { expect(sandbox.matchesPattern( '/tmp/my-proj/timeline.ndjson', 'timeline.ndjson', ctx )).toBe(true); }); it('matches /** glob prefix', () => { expect(sandbox.matchesPattern( '/tmp/my-proj/prd/feature/login.html', 'prd/**', ctx )).toBe(true); }); it('matches /** root itself', () => { expect(sandbox.matchesPattern( '/tmp/my-proj/prd', 'prd/**', ctx )).toBe(true); }); it('substitutes {unitId} placeholder', () => { expect(sandbox.matchesPattern( '/tmp/my-proj/units/u-be-auth/code/server.js', 'units/{unitId}/code/**', ctx )).toBe(true); }); it('rejects paths outside projectDir', () => { expect(sandbox.matchesPattern( '/etc/passwd', 'prd/**', ctx )).toBe(false); }); it('isWithinAllowList allows when any pattern matches', () => { expect(sandbox.isWithinAllowList( '/tmp/my-proj/units/u-be-auth/contract.json', ['prd/**', 'units/{unitId}/contract.json'], ctx )).toBe(true); }); it('assertWritable throws ToolSandboxError on violation', () => { expect(() => sandbox.assertWritable( '/etc/passwd', ['prd/**'], ctx )).toThrow(ToolSandboxError); }); it('assertWritable is silent on allowed path', () => { expect(() => sandbox.assertWritable( '/tmp/my-proj/prd/index.html', ['prd/**'], ctx )).not.toThrow(); }); });