@letterblack/lbe-exec 1.2.14 → 1.2.16
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.
- package/dist/cli.js +156 -43
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -2574,11 +2574,6 @@ function loadPolicy() {
|
|
|
2574
2574
|
const p = path15.join(process.cwd(), "lbe.policy.json");
|
|
2575
2575
|
return fs14.existsSync(p) ? JSON.parse(fs14.readFileSync(p, "utf8")) : null;
|
|
2576
2576
|
}
|
|
2577
|
-
function countAudit() {
|
|
2578
|
-
const p = path15.join(process.cwd(), ".lbe", "audit.jsonl");
|
|
2579
|
-
if (!fs14.existsSync(p)) return 0;
|
|
2580
|
-
return fs14.readFileSync(p, "utf8").split("\n").filter((l) => l.trim()).length;
|
|
2581
|
-
}
|
|
2582
2577
|
function findHookPath() {
|
|
2583
2578
|
const candidates = [
|
|
2584
2579
|
path15.resolve(__dir, "../hooks/register.cjs"),
|
|
@@ -2684,8 +2679,9 @@ switch (cmd) {
|
|
|
2684
2679
|
process.exit(1);
|
|
2685
2680
|
}
|
|
2686
2681
|
const existing = process.env.NODE_OPTIONS || "";
|
|
2687
|
-
const
|
|
2688
|
-
const
|
|
2682
|
+
const hookPathFwd = hookPath.replace(/\\/g, "/");
|
|
2683
|
+
const hookFlag = '--require "' + hookPathFwd + '"';
|
|
2684
|
+
const nodeOptions = existing.includes(hookPathFwd) ? existing : (existing + " " + hookFlag).trim();
|
|
2689
2685
|
const npmArgs = rest.filter((v) => !v.startsWith("--mode") && v !== opts.mode);
|
|
2690
2686
|
const child = spawn("npm", npmArgs, {
|
|
2691
2687
|
stdio: "inherit",
|
|
@@ -2696,46 +2692,63 @@ switch (cmd) {
|
|
|
2696
2692
|
break;
|
|
2697
2693
|
}
|
|
2698
2694
|
case "status": {
|
|
2699
|
-
const
|
|
2695
|
+
const root = process.cwd();
|
|
2700
2696
|
console.log("\u2500\u2500 LBE Status \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
|
|
2701
|
-
console.log("workspace: " +
|
|
2702
|
-
|
|
2703
|
-
|
|
2704
|
-
|
|
2705
|
-
|
|
2706
|
-
|
|
2707
|
-
|
|
2708
|
-
|
|
2709
|
-
const
|
|
2710
|
-
|
|
2711
|
-
|
|
2712
|
-
|
|
2713
|
-
|
|
2714
|
-
|
|
2715
|
-
|
|
2716
|
-
|
|
2717
|
-
|
|
2718
|
-
|
|
2719
|
-
|
|
2697
|
+
console.log("workspace: " + root);
|
|
2698
|
+
const hookPath = findHookPath();
|
|
2699
|
+
console.log("hook file: " + hookPath + (fs14.existsSync(hookPath) ? " (found)" : " (MISSING)"));
|
|
2700
|
+
const lbeRoot = process.env.LBE_ROOT || "";
|
|
2701
|
+
console.log("LBE_ROOT: " + (lbeRoot || "(not set)"));
|
|
2702
|
+
const nodeOpts = process.env.NODE_OPTIONS || "";
|
|
2703
|
+
const hookInPath = nodeOpts.includes("register.cjs");
|
|
2704
|
+
console.log("NODE_OPTIONS contains hook: " + (hookInPath ? "yes" : "no"));
|
|
2705
|
+
const eventsFile = path15.join(root, ".lbe", "events.jsonl");
|
|
2706
|
+
const auditExists = fs14.existsSync(eventsFile);
|
|
2707
|
+
console.log("audit log: " + (auditExists ? eventsFile : "(none yet)"));
|
|
2708
|
+
if (auditExists) {
|
|
2709
|
+
try {
|
|
2710
|
+
const lines = fs14.readFileSync(eventsFile, "utf8").split("\n").filter((l) => l.trim());
|
|
2711
|
+
if (lines.length) {
|
|
2712
|
+
const last = JSON.parse(lines[lines.length - 1]);
|
|
2713
|
+
const ts = new Date((last.ts || 0) * 1e3).toISOString().replace("T", " ").slice(0, 19);
|
|
2714
|
+
const target = last.path || last.cmd || "?";
|
|
2715
|
+
console.log("last event: " + ts + " " + last.action + " " + target + " \u2192 " + (last.decision || "?"));
|
|
2716
|
+
} else {
|
|
2717
|
+
console.log("last event: (none)");
|
|
2718
|
+
}
|
|
2719
|
+
} catch (_) {
|
|
2720
|
+
console.log("last event: (unreadable)");
|
|
2721
|
+
}
|
|
2720
2722
|
}
|
|
2721
|
-
|
|
2722
|
-
|
|
2723
|
-
|
|
2724
|
-
|
|
2725
|
-
|
|
2726
|
-
|
|
2727
|
-
|
|
2728
|
-
|
|
2729
|
-
|
|
2730
|
-
|
|
2731
|
-
|
|
2732
|
-
|
|
2733
|
-
|
|
2734
|
-
|
|
2735
|
-
console.log("
|
|
2723
|
+
const statusFile = path15.join(root, ".lbe", "runtime", "hook-status.json");
|
|
2724
|
+
if (fs14.existsSync(statusFile)) {
|
|
2725
|
+
let h;
|
|
2726
|
+
try {
|
|
2727
|
+
h = JSON.parse(fs14.readFileSync(statusFile, "utf8"));
|
|
2728
|
+
} catch (_) {
|
|
2729
|
+
}
|
|
2730
|
+
if (h) {
|
|
2731
|
+
let pidAlive = false;
|
|
2732
|
+
try {
|
|
2733
|
+
process.kill(h.pid, 0);
|
|
2734
|
+
pidAlive = true;
|
|
2735
|
+
} catch (_) {
|
|
2736
|
+
}
|
|
2737
|
+
console.log("\nhook process: " + (pidAlive ? "ACTIVE" : "stale (process exited)"));
|
|
2738
|
+
console.log("hook pid: " + h.pid + (pidAlive ? " (alive)" : " (gone)"));
|
|
2739
|
+
console.log("hook mode: " + h.mode);
|
|
2740
|
+
console.log("hook started: " + h.started_at);
|
|
2741
|
+
if (h.patched) {
|
|
2742
|
+
console.log("\nPatched functions:");
|
|
2743
|
+
for (const [fn, active] of Object.entries(h.patched)) {
|
|
2744
|
+
console.log(" " + (active ? "\u2713" : "\u2013") + " " + fn);
|
|
2745
|
+
}
|
|
2746
|
+
}
|
|
2736
2747
|
}
|
|
2748
|
+
} else {
|
|
2749
|
+
console.log("\nhook process: inactive \u2014 run: lbe-exec run-node ./agent.js");
|
|
2750
|
+
console.log(" or: lbe-exec activate then lbe-exec shell");
|
|
2737
2751
|
}
|
|
2738
|
-
console.log("\nevents log: .lbe/events.jsonl");
|
|
2739
2752
|
break;
|
|
2740
2753
|
}
|
|
2741
2754
|
case "audit": {
|
|
@@ -2777,6 +2790,101 @@ switch (cmd) {
|
|
|
2777
2790
|
process.exit(1);
|
|
2778
2791
|
});
|
|
2779
2792
|
break;
|
|
2793
|
+
case "activate": {
|
|
2794
|
+
const hookPath = findHookPath();
|
|
2795
|
+
if (!fs14.existsSync(hookPath)) {
|
|
2796
|
+
console.error("Hook not found: " + hookPath);
|
|
2797
|
+
console.error("Run: npm install @letterblack/lbe-exec");
|
|
2798
|
+
process.exit(1);
|
|
2799
|
+
}
|
|
2800
|
+
const mode = opts.mode || "observe";
|
|
2801
|
+
const root = process.cwd();
|
|
2802
|
+
const lbeDir = path15.join(root, ".lbe");
|
|
2803
|
+
fs14.mkdirSync(lbeDir, { recursive: true });
|
|
2804
|
+
fs14.writeFileSync(path15.join(lbeDir, "activation.json"), JSON.stringify({
|
|
2805
|
+
activated: true,
|
|
2806
|
+
activatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2807
|
+
hookPath,
|
|
2808
|
+
mode,
|
|
2809
|
+
root
|
|
2810
|
+
}, null, 2) + "\n");
|
|
2811
|
+
console.log("\u2500\u2500 LBE workspace activated \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
|
|
2812
|
+
console.log("workspace: " + root);
|
|
2813
|
+
console.log("hook: " + hookPath);
|
|
2814
|
+
console.log("mode: " + mode);
|
|
2815
|
+
console.log("\nNext: open a governed shell session:");
|
|
2816
|
+
console.log(" lbe-exec shell");
|
|
2817
|
+
console.log("\nAny Node.js agent run inside that shell is intercepted.");
|
|
2818
|
+
console.log("Python, Go, native binaries, and PowerShell are NOT governed.");
|
|
2819
|
+
break;
|
|
2820
|
+
}
|
|
2821
|
+
case "shell": {
|
|
2822
|
+
const activationFile = path15.join(process.cwd(), ".lbe", "activation.json");
|
|
2823
|
+
let activation = null;
|
|
2824
|
+
if (fs14.existsSync(activationFile)) {
|
|
2825
|
+
try {
|
|
2826
|
+
activation = JSON.parse(fs14.readFileSync(activationFile, "utf8"));
|
|
2827
|
+
} catch (_) {
|
|
2828
|
+
}
|
|
2829
|
+
}
|
|
2830
|
+
const hookPath = activation && activation.hookPath || findHookPath();
|
|
2831
|
+
if (!fs14.existsSync(hookPath)) {
|
|
2832
|
+
console.error("Hook not found. Run: lbe-exec activate");
|
|
2833
|
+
process.exit(1);
|
|
2834
|
+
}
|
|
2835
|
+
const mode = opts.mode || activation && activation.mode || "observe";
|
|
2836
|
+
const root = activation && activation.root || process.cwd();
|
|
2837
|
+
const hookPathFwd = hookPath.replace(/\\/g, "/");
|
|
2838
|
+
const nodeOpts = '--require "' + hookPathFwd + '"';
|
|
2839
|
+
const shellEnv = { ...process.env, NODE_OPTIONS: nodeOpts, LBE_ROOT: root, LBE_MODE: mode };
|
|
2840
|
+
console.log("[lbe] Opening governed shell \u2014 mode: " + mode);
|
|
2841
|
+
console.log("[lbe] NODE_OPTIONS set. Node.js agents are intercepted.");
|
|
2842
|
+
console.log("[lbe] Python / Go / native binaries are NOT governed.");
|
|
2843
|
+
console.log('[lbe] Type "exit" to close.\n');
|
|
2844
|
+
let shellProc;
|
|
2845
|
+
if (process.platform === "win32") {
|
|
2846
|
+
const banner = [
|
|
2847
|
+
`$env:NODE_OPTIONS='--require "${hookPathFwd}"'`,
|
|
2848
|
+
`$env:LBE_ROOT='${root}'`,
|
|
2849
|
+
`$env:LBE_MODE='${mode}'`,
|
|
2850
|
+
`Write-Host '[lbe] Shell armed \u2014 mode: ${mode}' -ForegroundColor Green`
|
|
2851
|
+
].join("; ");
|
|
2852
|
+
shellProc = spawn(
|
|
2853
|
+
"powershell.exe",
|
|
2854
|
+
["-NoExit", "-Command", banner],
|
|
2855
|
+
{ stdio: "inherit", env: shellEnv }
|
|
2856
|
+
);
|
|
2857
|
+
} else {
|
|
2858
|
+
const sh = process.env.SHELL || "/bin/bash";
|
|
2859
|
+
shellProc = spawn(sh, [], { stdio: "inherit", env: shellEnv });
|
|
2860
|
+
}
|
|
2861
|
+
shellProc.on("close", (code) => {
|
|
2862
|
+
console.log("\n[lbe] Governed shell closed.");
|
|
2863
|
+
process.exit(code ?? 0);
|
|
2864
|
+
});
|
|
2865
|
+
break;
|
|
2866
|
+
}
|
|
2867
|
+
case "deactivate": {
|
|
2868
|
+
const root = process.cwd();
|
|
2869
|
+
const files = [
|
|
2870
|
+
path15.join(root, ".lbe", "activation.json"),
|
|
2871
|
+
path15.join(root, ".lbe", "runtime", "hook-status.json")
|
|
2872
|
+
];
|
|
2873
|
+
let removed = 0;
|
|
2874
|
+
for (const f of files) {
|
|
2875
|
+
if (fs14.existsSync(f)) {
|
|
2876
|
+
fs14.unlinkSync(f);
|
|
2877
|
+
removed++;
|
|
2878
|
+
}
|
|
2879
|
+
}
|
|
2880
|
+
if (removed) {
|
|
2881
|
+
console.log("\u2713 LBE deactivated \u2014 workspace activation files removed.");
|
|
2882
|
+
} else {
|
|
2883
|
+
console.log("Nothing to deactivate (workspace was not activated).");
|
|
2884
|
+
}
|
|
2885
|
+
console.log('Close any open "lbe-exec shell" sessions to fully disarm.');
|
|
2886
|
+
break;
|
|
2887
|
+
}
|
|
2780
2888
|
case "observe":
|
|
2781
2889
|
case "enforce":
|
|
2782
2890
|
policyModeCommand(cmd, opts).catch((e) => {
|
|
@@ -2828,6 +2936,11 @@ switch (cmd) {
|
|
|
2828
2936
|
console.log(" status Show workspace, mode, hook state, patched functions");
|
|
2829
2937
|
console.log(" audit Show unified event log (.lbe/events.jsonl)");
|
|
2830
2938
|
console.log(" policy List active policy rules");
|
|
2939
|
+
console.log(" activate Write workspace activation record (Node.js only)");
|
|
2940
|
+
console.log(" [--mode observe|enforce]");
|
|
2941
|
+
console.log(" shell Open a governed terminal (NODE_OPTIONS pre-set)");
|
|
2942
|
+
console.log(" [--mode observe|enforce]");
|
|
2943
|
+
console.log(" deactivate Remove workspace activation files");
|
|
2831
2944
|
console.log(" observe Switch to observer mode (log only, nothing blocked)");
|
|
2832
2945
|
console.log(" enforce Switch to enforcement mode (violations blocked)");
|
|
2833
2946
|
console.log(" execute Send a JSON request from stdin or --input file");
|