@letterblack/lbe-core 1.3.2 → 1.3.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +130 -442
  3. package/assets/runtime-boundary.svg +36 -36
  4. package/dist/cli.js +141 -0
  5. package/dist/index.js +52 -0
  6. package/{release-exec/dist → dist}/wasm.lock.json +5 -4
  7. package/package.json +23 -54
  8. package/types.d.ts +2 -175
  9. package/.githooks/pre-commit +0 -2
  10. package/.githooks/pre-push +0 -2
  11. package/CHANGELOG.md +0 -69
  12. package/Release-README.md +0 -65
  13. package/WORKSPACE.md +0 -422
  14. package/_proof.mjs +0 -246
  15. package/bin/lbe.js +0 -12
  16. package/config/identity.config.json +0 -3
  17. package/config/policy.default.json +0 -24
  18. package/dist/cli/lbe.js +0 -4274
  19. package/dist/hooks/register.cjs +0 -505
  20. package/dist/state/appendCentral.cjs +0 -87
  21. package/dist/state/index.cjs +0 -101
  22. package/exec/cli.js +0 -472
  23. package/exec/index.js +0 -2
  24. package/index.js +0 -24
  25. package/lbe.audit.jsonl +0 -46
  26. package/release/README.md +0 -216
  27. package/release/TRUST.md +0 -90
  28. package/release/exec-README.md +0 -215
  29. package/release/exec-types.d.ts +0 -50
  30. package/release-exec/LICENSE +0 -1
  31. package/release-exec/README.md +0 -215
  32. package/release-exec/assets/lbe-gates.jpg +0 -0
  33. package/release-exec/assets/lbe-gates.png +0 -0
  34. package/release-exec/assets/runtime-boundary.svg +0 -36
  35. package/release-exec/assets/story-allow.jpg +0 -0
  36. package/release-exec/assets/story-allow.png +0 -0
  37. package/release-exec/assets/story-deny.jpg +0 -0
  38. package/release-exec/assets/story-deny.png +0 -0
  39. package/release-exec/dist/cli.js +0 -2841
  40. package/release-exec/dist/index.js +0 -1835
  41. package/release-exec/hooks/register.cjs +0 -473
  42. package/release-exec/package.json +0 -35
  43. package/release-exec/types.d.ts +0 -50
  44. package/runtime/engine.js +0 -322
  45. package/runtime/lbe_engine.wasm +0 -0
  46. package/src/cli/commands/auditVerify.js +0 -36
  47. package/src/cli/commands/dryrun.js +0 -175
  48. package/src/cli/commands/health.js +0 -153
  49. package/src/cli/commands/init.js +0 -306
  50. package/src/cli/commands/integrityCheck.js +0 -57
  51. package/src/cli/commands/logs.js +0 -53
  52. package/src/cli/commands/openState.js +0 -44
  53. package/src/cli/commands/policyAdd.js +0 -8
  54. package/src/cli/commands/policyMode.js +0 -7
  55. package/src/cli/commands/policySign.js +0 -72
  56. package/src/cli/commands/proof.js +0 -122
  57. package/src/cli/commands/run.js +0 -342
  58. package/src/cli/commands/status.js +0 -73
  59. package/src/cli/commands/verify.js +0 -144
  60. package/src/cli/main.js +0 -176
  61. package/src/cli/parseArgs.js +0 -114
  62. package/src/exec/localExecutor.js +0 -289
  63. package/src/hooks/register.cjs +0 -505
  64. package/src/state/appendCentral.cjs +0 -87
  65. package/src/state/fileIndex.js +0 -140
  66. package/src/state/index.cjs +0 -101
  67. package/src/state/index.js +0 -65
  68. package/src/state/intentRegistry.js +0 -83
  69. package/src/state/migration.js +0 -112
  70. package/src/state/proofRunner.js +0 -246
  71. package/src/state/stateRoot.js +0 -40
  72. package/src/state/targetRegistry.js +0 -108
  73. package/src/state/workspaceId.js +0 -40
  74. package/src/state/workspaceRegistry.js +0 -65
  75. /package/{release-exec/dist → dist}/lbe_engine.wasm +0 -0
package/_proof.mjs DELETED
@@ -1,246 +0,0 @@
1
- // Proof matrix for LBE preload hook
2
- // Run with: node _proof.mjs
3
- // All tests use isolated temp dirs. No shared state.
4
-
5
- import fs from 'fs';
6
- import path from 'path';
7
- import os from 'os';
8
- import { spawnSync, spawn } from 'child_process';
9
- import { fileURLToPath } from 'url';
10
-
11
- const ROOT = path.dirname(fileURLToPath(import.meta.url));
12
- const HOOK = path.join(ROOT, 'src', 'hooks', 'register.cjs');
13
- const HOOK_FWD = HOOK.replace(/\\/g, '/');
14
-
15
- let passed = 0, failed = 0;
16
-
17
- function result(name, ok, detail = '') {
18
- const mark = ok ? '✓' : '✗';
19
- console.log(` ${mark} ${name}${detail ? ' — ' + detail : ''}`);
20
- if (ok) passed++; else failed++;
21
- }
22
-
23
- function tmpDir(policy = null) {
24
- const d = fs.mkdtempSync(path.join(os.tmpdir(), 'lbe-proof-'));
25
- fs.mkdirSync(path.join(d, '.lbe'), { recursive: true });
26
- fs.writeFileSync(path.join(d, '.lbe', 'policy.json'),
27
- JSON.stringify(policy || { version: 1, mode: 'observe', workspace: d, rules: [] }));
28
- return d;
29
- }
30
-
31
- function runNode(dir, code, mode = 'observe') {
32
- return spawnSync(process.execPath, ['-e', code], {
33
- encoding: 'utf8',
34
- env: {
35
- ...process.env,
36
- NODE_OPTIONS: `--require "${HOOK_FWD}"`,
37
- LBE_ROOT: dir,
38
- LBE_MODE: mode,
39
- },
40
- cwd: dir,
41
- });
42
- }
43
-
44
- function auditEntries(dir) {
45
- const f = path.join(dir, '.lbe', 'events.jsonl');
46
- if (!fs.existsSync(f)) return [];
47
- return fs.readFileSync(f, 'utf8').split('\n').filter(l => l.trim()).map(l => JSON.parse(l));
48
- }
49
-
50
- // ── 1. fs.writeFile (callback) ──────────────────────────────────────────────
51
- {
52
- const dir = tmpDir();
53
- const r = runNode(dir, `
54
- const fs = require('fs');
55
- fs.writeFile('out.txt', 'hello', err => { if (err) process.exit(1); });
56
- `);
57
- const entries = auditEntries(dir);
58
- const wrote = fs.existsSync(path.join(dir, 'out.txt'));
59
- const logged = entries.some(e => e.action === 'file_write');
60
- result('fs.writeFile', wrote && logged && r.status === 0,
61
- wrote ? (logged ? 'file written + logged' : 'file written, NOT logged') : 'file not written');
62
- }
63
-
64
- // ── 2. fs.promises.writeFile ────────────────────────────────────────────────
65
- {
66
- const dir = tmpDir();
67
- const r = runNode(dir, `
68
- const fs = require('fs');
69
- (async () => {
70
- await fs.promises.writeFile('out2.txt', 'async');
71
- })().catch(() => process.exit(1));
72
- `);
73
- // Give async time to flush
74
- const entries = auditEntries(dir);
75
- const wrote = fs.existsSync(path.join(dir, 'out2.txt'));
76
- const logged = entries.some(e => e.action === 'file_write');
77
- result('fs.promises.writeFile', wrote && logged && r.status === 0,
78
- wrote ? (logged ? 'file written + logged' : 'file written, NOT logged') : 'file not written');
79
- }
80
-
81
- // ── 3. fs.rm ────────────────────────────────────────────────────────────────
82
- {
83
- const dir = tmpDir();
84
- fs.writeFileSync(path.join(dir, 'del.txt'), 'x');
85
- const r = runNode(dir, `
86
- const fs = require('fs');
87
- fs.rm('del.txt', err => { if (err) process.exit(1); });
88
- `);
89
- const entries = auditEntries(dir);
90
- const deleted = !fs.existsSync(path.join(dir, 'del.txt'));
91
- const logged = entries.some(e => e.action === 'file_delete');
92
- result('fs.rm', deleted && logged && r.status === 0,
93
- deleted ? (logged ? 'file deleted + logged' : 'file deleted, NOT logged') : 'file not deleted');
94
- }
95
-
96
- // ── 4. fs.rename ────────────────────────────────────────────────────────────
97
- {
98
- const dir = tmpDir();
99
- fs.writeFileSync(path.join(dir, 'a.txt'), 'x');
100
- const r = runNode(dir, `
101
- const fs = require('fs');
102
- fs.rename('a.txt', 'b.txt', err => { if (err) process.exit(1); });
103
- `);
104
- const entries = auditEntries(dir);
105
- const renamed = !fs.existsSync(path.join(dir, 'a.txt')) && fs.existsSync(path.join(dir, 'b.txt'));
106
- const logged = entries.some(e => e.action === 'file_rename');
107
- result('fs.rename', renamed && logged && r.status === 0,
108
- renamed ? (logged ? 'renamed + logged' : 'renamed, NOT logged') : 'rename failed');
109
- }
110
-
111
- // ── 5. child_process.spawn ──────────────────────────────────────────────────
112
- {
113
- const dir = tmpDir();
114
- const r = runNode(dir, `
115
- const { spawn } = require('child_process');
116
- const child = spawn(process.execPath, ['--version']);
117
- let out = '';
118
- child.stdout.on('data', d => out += d);
119
- child.on('close', code => {
120
- if (code !== 0) process.exit(1);
121
- });
122
- `);
123
- const entries = auditEntries(dir);
124
- const logged = entries.some(e => e.action === 'run_shell');
125
- result('spawn', r.status === 0 && logged,
126
- logged ? 'spawn logged' : 'spawn NOT logged');
127
- }
128
-
129
- // ── 6. child_process.exec ───────────────────────────────────────────────────
130
- {
131
- const dir = tmpDir();
132
- // execSync is synchronous — quote path for Windows spaces
133
- const r = runNode(dir, `
134
- const { execSync } = require('child_process');
135
- execSync('"' + process.execPath + '" --version');
136
- `);
137
- const entries = auditEntries(dir);
138
- const logged = entries.some(e => e.action === 'run_shell');
139
- result('exec / execSync', r.status === 0 && logged,
140
- logged ? 'execSync logged' : 'execSync NOT logged');
141
- }
142
-
143
- // ── 7. observe mode — writes still execute ──────────────────────────────────
144
- {
145
- const dir = tmpDir();
146
- const r = runNode(dir, `
147
- require('fs').writeFileSync('observe.txt', 'x');
148
- `, 'observe');
149
- const entries = auditEntries(dir);
150
- const wrote = fs.existsSync(path.join(dir, 'observe.txt'));
151
- const e = entries.find(e => e.action === 'file_write');
152
- const enforced = e && e.enforced === false;
153
- result('observe mode (write executes)', wrote && enforced,
154
- wrote ? (enforced ? 'executed=true, enforced=false' : 'wrong enforced flag') : 'file not written');
155
- }
156
-
157
- // ── 8. enforce mode — deny rule blocks write ─────────────────────────────────
158
- {
159
- const dir = tmpDir();
160
- // Overwrite policy with deny-all enforce rule
161
- fs.writeFileSync(path.join(dir, '.lbe', 'policy.json'), JSON.stringify({
162
- version: 1, mode: 'enforce', workspace: dir,
163
- rules: [{ id: 'r1', effect: 'deny', type: 'path', pattern: '**', from: 'test' }]
164
- }));
165
- const r = runNode(dir, `
166
- try { require('fs').writeFileSync('blocked.txt', 'x'); }
167
- catch(e) { /* expected */ }
168
- `, 'enforce');
169
- const entries = auditEntries(dir);
170
- const notWritten = !fs.existsSync(path.join(dir, 'blocked.txt'));
171
- const e = entries.find(e => e.decision === 'deny');
172
- result('enforce mode (deny blocks)', notWritten && !!e,
173
- notWritten ? (e ? 'blocked + logged' : 'blocked, NOT logged') : 'file was written (not blocked)');
174
- }
175
-
176
- // ── 9. no recursion — one write = one audit entry ───────────────────────────
177
- {
178
- const dir = tmpDir();
179
- const r = runNode(dir, `
180
- require('fs').writeFileSync('single.txt', 'x');
181
- `);
182
- const entries = auditEntries(dir).filter(e => e.action === 'file_write' && e.path && e.path.endsWith('single.txt'));
183
- result('no recursion', entries.length === 1,
184
- `${entries.length} audit entries for 1 writeFileSync (expected 1)`);
185
- }
186
-
187
- // ── 10. status PID detection ────────────────────────────────────────────────
188
- {
189
- const dir = tmpDir();
190
- // Start a background node process with the hook
191
- const child = spawn(process.execPath, ['-e', `
192
- // keep alive for 3 seconds
193
- setTimeout(() => {}, 3000);
194
- `], {
195
- env: { ...process.env, NODE_OPTIONS: `--require "${HOOK_FWD}"`, LBE_ROOT: dir, LBE_MODE: 'observe' },
196
- cwd: dir,
197
- stdio: 'ignore',
198
- detached: false,
199
- });
200
-
201
- // Wait briefly for hook to write status file
202
- await new Promise(r => setTimeout(r, 800));
203
-
204
- const statusFile = path.join(dir, '.lbe', 'runtime', 'hook-status.json');
205
- let pidAlive = false;
206
- let statusOk = false;
207
- if (fs.existsSync(statusFile)) {
208
- const s = JSON.parse(fs.readFileSync(statusFile, 'utf8'));
209
- statusOk = true;
210
- try { process.kill(s.pid, 0); pidAlive = true; } catch (_) {}
211
- }
212
-
213
- result('status PID (alive)', statusOk && pidAlive,
214
- statusOk ? (pidAlive ? `PID ${JSON.parse(fs.readFileSync(statusFile,'utf8')).pid} alive` : 'PID dead') : 'hook-status.json missing');
215
-
216
- child.kill();
217
- await new Promise(r => setTimeout(r, 300));
218
-
219
- // After kill, PID should be gone
220
- let pidGone = false;
221
- if (fs.existsSync(statusFile)) {
222
- const s = JSON.parse(fs.readFileSync(statusFile, 'utf8'));
223
- try { process.kill(s.pid, 0); } catch (_) { pidGone = true; }
224
- }
225
- result('status PID (stale after kill)', statusOk && pidGone,
226
- pidGone ? 'PID correctly gone' : 'PID still appears alive');
227
- }
228
-
229
- // ── 11. clean workspace ──────────────────────────────────────────────────────
230
- {
231
- const dir = tmpDir();
232
- runNode(dir, `require('fs').writeFileSync('x.txt','x');`);
233
-
234
- const rootFiles = fs.readdirSync(dir);
235
- const lbeFiles = fs.existsSync(path.join(dir, '.lbe')) ? fs.readdirSync(path.join(dir, '.lbe')) : [];
236
- const badRootFiles = rootFiles.filter(f =>
237
- f !== '.lbe' && f !== 'x.txt' &&
238
- (f.startsWith('lbe') || f === 'CLAUDE.md' || f.startsWith('_lbe'))
239
- );
240
- result('clean workspace', badRootFiles.length === 0,
241
- badRootFiles.length ? 'unexpected root files: ' + badRootFiles.join(', ') : 'no LBE pollution in root');
242
- }
243
-
244
- // ── Summary ──────────────────────────────────────────────────────────────────
245
- console.log(`\n${passed + failed} tests ✓ ${passed} passed ${failed > 0 ? '✗ ' + failed + ' failed' : ''}`);
246
- if (failed > 0) process.exit(1);
package/bin/lbe.js DELETED
@@ -1,12 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- import fs from 'fs';
4
- import path from 'path';
5
- import { fileURLToPath, pathToFileURL } from 'url';
6
-
7
- const __dirname = path.dirname(fileURLToPath(import.meta.url));
8
- const distEntry = path.join(__dirname, '../dist/cli/lbe.js');
9
- const sourceEntry = path.join(__dirname, '../src/cli/main.js');
10
- const entry = fs.existsSync(distEntry) ? distEntry : sourceEntry;
11
-
12
- await import(pathToFileURL(entry).href);
@@ -1,3 +0,0 @@
1
- {
2
- "version": "0.2.0"
3
- }
@@ -1,24 +0,0 @@
1
- {
2
- "version": 1,
3
- "createdAt": "2026-06-19T00:00:00Z",
4
- "default": "DENY",
5
- "requesters": {
6
- "agent:sdk": {
7
- "allowAdapters": ["file", "shell", "noop"],
8
- "allowCommands": ["READ_FILE", "WRITE_FILE", "PATCH_FILE", "DELETE_FILE", "RUN_SHELL", "ECHO"],
9
- "filesystem": {
10
- "roots": ["."],
11
- "denyPatterns": ["**/.git/**", "**/keys/**", "**/*.key", "**/.env*"]
12
- },
13
- "exec": {
14
- "allowCmds": ["node", "echo"],
15
- "denyCmds": ["rm", "del", "format", "curl", "wget", "sudo"]
16
- }
17
- }
18
- },
19
- "security": {
20
- "maxClockSkewSec": 600,
21
- "maxPolicyCreatedAtSkewSec": 31536000,
22
- "defaultRateLimit": { "windowSec": 60, "maxRequests": 30 }
23
- }
24
- }