@darkhunt-security/endpoint-codex 0.9.14 → 0.9.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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "darkhunt-guard",
3
- "version": "0.9.14",
3
+ "version": "0.9.16",
4
4
  "hooks": "./hooks/hooks.json",
5
5
  "description": "Darkhunt endpoint plugin for Codex CLI \u2014 full session trace capture and PreToolUse guardrails.",
6
6
  "author": {
@@ -18872,12 +18872,27 @@ function acquireLock(scope) {
18872
18872
  }
18873
18873
  return () => rmSync(path, { force: true });
18874
18874
  }
18875
- function isAlive(pid) {
18875
+ function isAlive(pid, kill = (p, s) => {
18876
+ process.kill(p, s);
18877
+ }) {
18876
18878
  try {
18877
- process.kill(pid, 0);
18879
+ kill(pid, 0);
18878
18880
  return true;
18879
- } catch {
18880
- return false;
18881
+ } catch (err) {
18882
+ return err.code !== "ESRCH";
18883
+ }
18884
+ }
18885
+ var DEFAULT_LOCK_WAIT_MS = 60 * 1e3;
18886
+ async function acquireLockWithin(scope, timeoutMs, sleep2 = (ms) => new Promise((r) => setTimeout(r, ms)), now = Date.now) {
18887
+ const deadline = now() + timeoutMs;
18888
+ for (; ; ) {
18889
+ const release = acquireLock(scope);
18890
+ if (release)
18891
+ return release;
18892
+ const remaining = deadline - now();
18893
+ if (remaining <= 0)
18894
+ return null;
18895
+ await sleep2(Math.min(250, remaining));
18881
18896
  }
18882
18897
  }
18883
18898
 
@@ -21711,7 +21726,9 @@ function tryLoadConfig(vendor, options) {
21711
21726
  }
21712
21727
  async function runForwarder(mapper, options = {}) {
21713
21728
  const config = options.config ?? tryLoadConfig(mapper.vendor, options);
21714
- const release = acquireLock(config?.scope ?? mapper.vendor);
21729
+ const scope = config?.scope ?? mapper.vendor;
21730
+ const waited = options.lockWaitMs !== void 0 && options.lockWaitMs > 0;
21731
+ const release = waited ? await acquireLockWithin(scope, options.lockWaitMs) : acquireLock(scope);
21715
21732
  if (!release) {
21716
21733
  return {
21717
21734
  transcripts: 0,
@@ -21720,7 +21737,12 @@ async function runForwarder(mapper, options = {}) {
21720
21737
  kinds: {},
21721
21738
  warnings: [],
21722
21739
  emitted: { transcripts: 0, records: 0 },
21723
- ok: true
21740
+ lockBusy: true,
21741
+ // A caller that waited and still did not get it has had its request dropped, and
21742
+ // must not exit zero on it. One that never asked to wait was simply beaten to
21743
+ // work that is now someone else's, which is success.
21744
+ ok: !waited,
21745
+ ...waited ? { error: "another forwarder holds the lock" } : {}
21724
21746
  };
21725
21747
  }
21726
21748
  const result2 = {
@@ -22053,6 +22075,10 @@ async function runBackfill(mapper, options, say2) {
22053
22075
  const pass = (subset) => runForwarder(mapper, {
22054
22076
  paths: subset,
22055
22077
  dryRun: options.dryRun,
22078
+ // A backfill is an instruction, not an opportunistic spawn: it waits for the lock
22079
+ // that a hook-fired forwarder may hold, and treats never getting it as a failure
22080
+ // rather than reporting the `shipped 0` an up-to-date machine also prints.
22081
+ ...options.dryRun ? {} : { lockWaitMs: options.lockWaitMs ?? DEFAULT_LOCK_WAIT_MS },
22056
22082
  ...options.profile !== void 0 ? { profile: options.profile } : {},
22057
22083
  ...options.credentialsPath !== void 0 ? { credentialsPath: options.credentialsPath } : {}
22058
22084
  });
@@ -22087,7 +22113,9 @@ async function runPasses(groups, pass, say2) {
22087
22113
  total.ok = false;
22088
22114
  if (result2.error !== void 0)
22089
22115
  total.error = result2.error;
22090
- say2(`stopped in batch ${index + 1} of ${groups.length}; earlier batches are checkpointed`);
22116
+ if (result2.lockBusy === true)
22117
+ total.lockBusy = true;
22118
+ say2(result2.lockBusy === true ? `batch ${index + 1} of ${groups.length} could not start: another forwarder holds the lock` : `stopped in batch ${index + 1} of ${groups.length}; earlier batches are checkpointed`);
22091
22119
  break;
22092
22120
  }
22093
22121
  if (groups.length > 1) {
@@ -22498,6 +22526,11 @@ for (const [kind, n] of Object.entries(result.kinds).sort((a, b) => b[1] - a[1])
22498
22526
  for (const skip of result.skipped) say(`skipped ${skip}`);
22499
22527
  for (const warning of result.warnings ?? []) say(`WARNING ${warning}`);
22500
22528
  if (result.ok === false) {
22529
+ if (result.lockBusy === true) {
22530
+ say("NOT RUN \u2014 another forwarder held the lock for the whole wait");
22531
+ say("nothing was shipped; re-run when the capture lane is idle");
22532
+ process.exit(3);
22533
+ }
22501
22534
  say(`EXPORT FAILED \u2014 ${result.error}`);
22502
22535
  if (result.emitted.records > 0) {
22503
22536
  say(
@@ -66,6 +66,7 @@ var LINE_CEILING = 64 * 1024 * 1024;
66
66
 
67
67
  // packages/core/dist/forwarder/lock.js
68
68
  var STALE_MS = 5 * 60 * 1e3;
69
+ var DEFAULT_LOCK_WAIT_MS = 60 * 1e3;
69
70
 
70
71
  // node_modules/@darkhunt-security/telemetry/package.json
71
72
  var package_default = {
@@ -18872,12 +18872,27 @@ function acquireLock(scope) {
18872
18872
  }
18873
18873
  return () => rmSync(path, { force: true });
18874
18874
  }
18875
- function isAlive(pid) {
18875
+ function isAlive(pid, kill = (p, s) => {
18876
+ process.kill(p, s);
18877
+ }) {
18876
18878
  try {
18877
- process.kill(pid, 0);
18879
+ kill(pid, 0);
18878
18880
  return true;
18879
- } catch {
18880
- return false;
18881
+ } catch (err) {
18882
+ return err.code !== "ESRCH";
18883
+ }
18884
+ }
18885
+ var DEFAULT_LOCK_WAIT_MS = 60 * 1e3;
18886
+ async function acquireLockWithin(scope, timeoutMs, sleep2 = (ms) => new Promise((r) => setTimeout(r, ms)), now = Date.now) {
18887
+ const deadline = now() + timeoutMs;
18888
+ for (; ; ) {
18889
+ const release = acquireLock(scope);
18890
+ if (release)
18891
+ return release;
18892
+ const remaining = deadline - now();
18893
+ if (remaining <= 0)
18894
+ return null;
18895
+ await sleep2(Math.min(250, remaining));
18881
18896
  }
18882
18897
  }
18883
18898
 
@@ -21711,7 +21726,9 @@ function tryLoadConfig(vendor, options) {
21711
21726
  }
21712
21727
  async function runForwarder(mapper, options = {}) {
21713
21728
  const config = options.config ?? tryLoadConfig(mapper.vendor, options);
21714
- const release = acquireLock(config?.scope ?? mapper.vendor);
21729
+ const scope = config?.scope ?? mapper.vendor;
21730
+ const waited = options.lockWaitMs !== void 0 && options.lockWaitMs > 0;
21731
+ const release = waited ? await acquireLockWithin(scope, options.lockWaitMs) : acquireLock(scope);
21715
21732
  if (!release) {
21716
21733
  return {
21717
21734
  transcripts: 0,
@@ -21720,7 +21737,12 @@ async function runForwarder(mapper, options = {}) {
21720
21737
  kinds: {},
21721
21738
  warnings: [],
21722
21739
  emitted: { transcripts: 0, records: 0 },
21723
- ok: true
21740
+ lockBusy: true,
21741
+ // A caller that waited and still did not get it has had its request dropped, and
21742
+ // must not exit zero on it. One that never asked to wait was simply beaten to
21743
+ // work that is now someone else's, which is success.
21744
+ ok: !waited,
21745
+ ...waited ? { error: "another forwarder holds the lock" } : {}
21724
21746
  };
21725
21747
  }
21726
21748
  const result = {
@@ -399,6 +399,7 @@ var LINE_CEILING = 64 * 1024 * 1024;
399
399
 
400
400
  // packages/core/dist/forwarder/lock.js
401
401
  var STALE_MS = 5 * 60 * 1e3;
402
+ var DEFAULT_LOCK_WAIT_MS = 60 * 1e3;
402
403
 
403
404
  // node_modules/@darkhunt-security/telemetry/package.json
404
405
  var package_default = {
package/dist/bin/init.mjs CHANGED
@@ -58,6 +58,7 @@ var LINE_CEILING = 64 * 1024 * 1024;
58
58
 
59
59
  // packages/core/dist/forwarder/lock.js
60
60
  var STALE_MS = 5 * 60 * 1e3;
61
+ var DEFAULT_LOCK_WAIT_MS = 60 * 1e3;
61
62
 
62
63
  // node_modules/@darkhunt-security/telemetry/package.json
63
64
  var package_default = {
@@ -201,6 +201,7 @@ var LINE_CEILING = 64 * 1024 * 1024;
201
201
 
202
202
  // packages/core/dist/forwarder/lock.js
203
203
  var STALE_MS = 5 * 60 * 1e3;
204
+ var DEFAULT_LOCK_WAIT_MS = 60 * 1e3;
204
205
 
205
206
  // node_modules/@darkhunt-security/telemetry/package.json
206
207
  var package_default = {
@@ -190,6 +190,7 @@ var LINE_CEILING = 64 * 1024 * 1024;
190
190
 
191
191
  // packages/core/dist/forwarder/lock.js
192
192
  var STALE_MS = 5 * 60 * 1e3;
193
+ var DEFAULT_LOCK_WAIT_MS = 60 * 1e3;
193
194
 
194
195
  // packages/core/dist/forwarder/health.js
195
196
  import { mkdirSync as mkdirSync3, readFileSync as readFileSync4, renameSync as renameSync3, writeFileSync as writeFileSync3 } from "node:fs";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@darkhunt-security/endpoint-codex",
3
- "version": "0.9.14",
3
+ "version": "0.9.16",
4
4
  "type": "module",
5
5
  "description": "Darkhunt endpoint adapter for Codex CLI: hook codec, rollout transcript mapper, plugin manifest.",
6
6
  "bin": {