Files
portal/tools/enforce-read-path-deny.test.mjs
T

71 lines
3.8 KiB
JavaScript

import { describe, it, expect } from 'vitest';
import { decide } from './enforce-read-path-deny.mjs';
describe('enforce-read-path-deny decide()', () => {
it('allows Read on normal project file', () => {
const r = decide({ toolName: 'Read', filePath: 'docs/observer/STATUS.md' });
expect(r.block).toBe(false);
});
it('blocks Read on ~/.claude/projects/*.jsonl transcript', () => {
const r = decide({ toolName: 'Read', filePath: '~/.claude/projects/abc-session.jsonl' });
expect(r.block).toBe(true);
expect(r.reason).toMatch(/protected/i);
});
it('blocks Read on absolute /c/Users/.../.claude/projects/x.jsonl', () => {
const r = decide({ toolName: 'Read', filePath: '/c/Users/Administrator/.claude/projects/proj/session.jsonl' });
expect(r.block).toBe(true);
});
it('blocks Read on ~/.claude/runtime/*.json (runtime artifacts)', () => {
const r = decide({ toolName: 'Read', filePath: '~/.claude/runtime/router-state-x.json' });
expect(r.block).toBe(true);
});
it('blocks Read on .env', () => {
const r = decide({ toolName: 'Read', filePath: '.env' });
expect(r.block).toBe(true);
});
it('allows non-Read tool calls (no-op)', () => {
const r = decide({ toolName: 'Bash', filePath: 'whatever' });
expect(r.block).toBe(false);
});
});
// Over-block fix (2026-05-31): Smoke 5 added CLAUDE.md + memory/ + normative
// docs to the Read-deny set, which broke the legit claude-md-management /
// memory-sync workflow (Edit requires a prior Read). Read of CLAUDE.md / memory
// / Pravila has no exfil value (public-in-repo / own memory index). The genuine
// Read-exfil targets — cross-session transcripts (.jsonl) and ~/.claude/runtime
// — MUST stay blocked. Bash/PowerShell/Write protections (DEFAULT_PROTECTED_PATTERNS)
// are unchanged.
describe('enforce-read-path-deny — CLAUDE.md / memory readable (over-block fix 2026-05-31)', () => {
it('allows Read on CLAUDE.md (public-in-repo, no exfil value)', () => {
expect(decide({ toolName: 'Read', filePath: 'CLAUDE.md' }).block).toBe(false);
expect(decide({ toolName: 'Read', filePath: '/c/моя/проекты/портал crm/Документация/CLAUDE.md' }).block).toBe(false);
});
it('allows Read on MEMORY.md (own memory index under .claude/projects/<proj>/memory)', () => {
expect(decide({ toolName: 'Read', filePath: '/c/Users/Administrator/.claude/projects/crm/memory/MEMORY.md' }).block).toBe(false);
});
it('allows Read on a memory/*.md feedback file', () => {
expect(decide({ toolName: 'Read', filePath: '/c/Users/Administrator/.claude/projects/crm/memory/feedback_read_path_deny.md' }).block).toBe(false);
});
it('allows Read on a normative doc (Pravila) — needed for claude-md-management', () => {
expect(decide({ toolName: 'Read', filePath: 'docs/Pravila_raboty_Claude_v1_1.md' }).block).toBe(false);
});
it('STILL blocks Read on transcript JSONL under .claude/projects', () => {
expect(decide({ toolName: 'Read', filePath: '/c/Users/Administrator/.claude/projects/crm/session.jsonl' }).block).toBe(true);
expect(decide({ toolName: 'Read', filePath: '~/.claude/projects/abc-session.jsonl' }).block).toBe(true);
});
it('STILL blocks Read on ~/.claude/runtime artifacts', () => {
expect(decide({ toolName: 'Read', filePath: '~/.claude/runtime/router-state-x.json' }).block).toBe(true);
});
});
// Impl completion (2026-05-31, this session): exfil-pattern boundaries.
describe('enforce-read-path-deny — exfil-pattern boundaries (impl completion 2026-05-31)', () => {
it('STILL blocks Read on .env.production (secrets variant)', () => {
expect(decide({ toolName: 'Read', filePath: '.env.production' }).block).toBe(true);
});
it('allows Read on a Tooling normative doc (needed for normative sync)', () => {
expect(decide({ toolName: 'Read', filePath: 'docs/Tooling_v8_3.md' }).block).toBe(false);
});
});