@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.
Files changed (2) hide show
  1. package/dist/cli.js +156 -43
  2. 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 hookFlag = "--require " + hookPath;
2688
- const nodeOptions = existing.includes(hookFlag) ? existing : (existing + " " + hookFlag).trim();
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 policy = loadPolicy();
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: " + process.cwd());
2702
- if (policy) {
2703
- console.log("mode: " + policy.mode);
2704
- console.log("rules: " + (policy.rules?.length ?? 0));
2705
- console.log("audit: " + countAudit() + " entries (.lbe/audit.jsonl)");
2706
- } else {
2707
- console.log("policy: not found \u2014 run: npx lbe-exec init");
2708
- }
2709
- const statusFile = path15.join(process.cwd(), ".lbe", "runtime", "hook-status.json");
2710
- if (!fs14.existsSync(statusFile)) {
2711
- console.log("\nhook: inactive \u2014 use: npx lbe-exec run-node ./agent.js");
2712
- break;
2713
- }
2714
- let hookStatus;
2715
- try {
2716
- hookStatus = JSON.parse(fs14.readFileSync(statusFile, "utf8"));
2717
- } catch (e) {
2718
- console.log("\nhook: status file unreadable \u2014 " + e.message);
2719
- break;
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
- let pidAlive = false;
2722
- try {
2723
- process.kill(hookStatus.pid, 0);
2724
- pidAlive = true;
2725
- } catch (_) {
2726
- }
2727
- console.log("\nhook: " + (pidAlive ? "ACTIVE" : "stale (process exited)"));
2728
- console.log("hook pid: " + hookStatus.pid + (pidAlive ? " (alive)" : " (gone)"));
2729
- console.log("hook mode: " + hookStatus.mode);
2730
- console.log("hook root: " + hookStatus.root);
2731
- console.log("hook start: " + hookStatus.started_at);
2732
- if (hookStatus.patched) {
2733
- console.log("\nPatched functions:");
2734
- for (const [fn, active] of Object.entries(hookStatus.patched)) {
2735
- console.log(" " + (active ? "\u2713" : "\u2013") + " " + fn);
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");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@letterblack/lbe-exec",
3
- "version": "1.2.14",
3
+ "version": "1.2.16",
4
4
  "description": "Local host-signed execution layer for LetterBlack LBE.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",