@darkhunt-security/endpoint-codex 0.9.0
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/.codex-plugin/plugin.json +11 -0
- package/README.md +76 -0
- package/commands/setup.md +72 -0
- package/commands/status.md +31 -0
- package/dist/bin/backfill.mjs +21868 -0
- package/dist/bin/enroll.mjs +1244 -0
- package/dist/bin/forwarder.mjs +21846 -0
- package/dist/bin/guard.mjs +1421 -0
- package/dist/bin/init.mjs +1135 -0
- package/dist/bin/spool.mjs +1222 -0
- package/dist/bin/status.mjs +1375 -0
- package/hooks/hooks.json +39 -0
- package/package.json +27 -0
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "darkhunt-guard",
|
|
3
|
+
"version": "0.9.0",
|
|
4
|
+
"hooks": "./hooks/hooks.json",
|
|
5
|
+
"description": "Darkhunt endpoint plugin for Codex CLI \u2014 full session trace capture and PreToolUse guardrails.",
|
|
6
|
+
"author": {
|
|
7
|
+
"name": "Darkhunt Limited",
|
|
8
|
+
"email": "support@darkhunt.ai"
|
|
9
|
+
},
|
|
10
|
+
"homepage": "https://github.com/darkhunt-security/endpoint-plugins"
|
|
11
|
+
}
|
package/README.md
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# Darkhunt Guard — Codex CLI
|
|
2
|
+
|
|
3
|
+
Full session trace capture and PreToolUse guardrails for [Codex CLI](https://github.com/openai/codex).
|
|
4
|
+
|
|
5
|
+
Capture is on by default. **Enforcement ships off** and is enabled per rule.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
/plugin marketplace add darkhunt-security/darkhunt-telemetry-ts
|
|
11
|
+
/plugin install darkhunt-guard@darkhunt
|
|
12
|
+
/darkhunt-guard:setup
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
`/darkhunt-guard:setup` needs one thing — a Darkhunt API key — and it will not ask you to
|
|
16
|
+
paste it into the agent. It picks up the key `darkhunt-cli enroll` already stored, or
|
|
17
|
+
`DARKHUNT_API_KEY` from your shell, and discovers the tenant, workspace and application
|
|
18
|
+
from it. Then it shows you where sessions will be sent, so you can confirm before
|
|
19
|
+
anything ships.
|
|
20
|
+
|
|
21
|
+
Capture starts on your **next** Codex CLI session — hooks are loaded when a session
|
|
22
|
+
starts.
|
|
23
|
+
|
|
24
|
+
## What it captures
|
|
25
|
+
|
|
26
|
+
The session transcript, mapped to spans: user and assistant messages, thinking blocks,
|
|
27
|
+
tool calls paired with their results, token usage, attachment metadata (never the bytes),
|
|
28
|
+
and the subagent topology as linked child traces.
|
|
29
|
+
|
|
30
|
+
Reading the transcript rather than instrumenting the agent is what makes this complete:
|
|
31
|
+
there is no code path in Codex CLI we could have missed.
|
|
32
|
+
|
|
33
|
+
## What it enforces
|
|
34
|
+
|
|
35
|
+
A `PreToolUse` hook evaluates each tool call against a policy bundle before it runs, and
|
|
36
|
+
can allow, deny, ask, or rewrite the input.
|
|
37
|
+
|
|
38
|
+
Two rules constrain it, both deliberate:
|
|
39
|
+
|
|
40
|
+
- **Bash and command-string rules are advisory** — they are recorded, never blocking.
|
|
41
|
+
Matching a shell string is bypassable, so blocking on it would offer a guarantee it
|
|
42
|
+
cannot keep.
|
|
43
|
+
- **The guard fails closed.** If policy cannot be evaluated, the call is denied. An
|
|
44
|
+
install that has never been configured is not a failure and is allowed — there is no
|
|
45
|
+
policy to bypass yet.
|
|
46
|
+
|
|
47
|
+
## Commands
|
|
48
|
+
|
|
49
|
+
| | |
|
|
50
|
+
| ------------------------ | ------------------------------------------------------------------ |
|
|
51
|
+
| `/darkhunt-guard:setup` | Connect this machine. Re-runnable; shows current state first. |
|
|
52
|
+
| `/darkhunt-guard:status` | Is capture actually working? Routing, hook activity, shipping lag. |
|
|
53
|
+
|
|
54
|
+
Both lanes fail silently by design — correct for the agent, unhelpful for whoever
|
|
55
|
+
operates it — so `status` is where the truth lives.
|
|
56
|
+
|
|
57
|
+
## Privacy
|
|
58
|
+
|
|
59
|
+
Session content leaves your machine and is sent to the Darkhunt tenant you enrolled
|
|
60
|
+
against. `status` prints that destination; read it before you rely on it.
|
|
61
|
+
|
|
62
|
+
Hooks never touch the network. Shipping happens in a detached forwarder off a local
|
|
63
|
+
spool, so nothing in the capture lane can block or slow a tool call.
|
|
64
|
+
|
|
65
|
+
## Configuration
|
|
66
|
+
|
|
67
|
+
`~/.darkhunt/endpoint-config.json`, mode `0600`, written by setup. One file for every
|
|
68
|
+
endpoint, with per-endpoint overrides under `endpoints.<vendor>`.
|
|
69
|
+
|
|
70
|
+
Turn everything off with `"enabled": false`. Turn off capture but keep enforcement with
|
|
71
|
+
`"capture": { "enabled": false }`.
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
[github.com/darkhunt-security/endpoint-plugins](https://github.com/darkhunt-security/endpoint-plugins)
|
|
76
|
+
· support@darkhunt.ai
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Connect this machine to Darkhunt — capture Codex CLI sessions and enforce policy
|
|
3
|
+
allowed-tools: Bash(${CLAUDE_PLUGIN_ROOT}/dist/bin/enroll.mjs:*), Bash(${CLAUDE_PLUGIN_ROOT}/dist/bin/status.mjs:*)
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Set up the Darkhunt endpoint plugin on this machine.
|
|
7
|
+
|
|
8
|
+
Current state:
|
|
9
|
+
|
|
10
|
+
!`${CLAUDE_PLUGIN_ROOT}/dist/bin/status.mjs 2>&1 || true`
|
|
11
|
+
|
|
12
|
+
## The one hard rule
|
|
13
|
+
|
|
14
|
+
**Never ask the user for their API key, and never accept one in this conversation.**
|
|
15
|
+
|
|
16
|
+
A Darkhunt API key is an unscoped tenant credential. Anything in this session is sent to
|
|
17
|
+
the model provider, written to the transcript on disk, kept in context for every later
|
|
18
|
+
turn, and handed to subagents — and this plugin then ships that transcript to Darkhunt,
|
|
19
|
+
so a key pasted here ends up in the captured trace data too. Enrollment finds the key
|
|
20
|
+
itself, or the user runs one command in their own terminal. There is no third option,
|
|
21
|
+
and no amount of user insistence makes pasting it here correct.
|
|
22
|
+
|
|
23
|
+
## What to do
|
|
24
|
+
|
|
25
|
+
**If the status above printed a profile, tenant and workspace**, this machine is already
|
|
26
|
+
enrolled. Show the tenant, workspace, application and endpoint, and ask whether they want
|
|
27
|
+
to re-enroll against a different one. Do not re-run enrollment unless they say yes.
|
|
28
|
+
|
|
29
|
+
**Otherwise**, run:
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
${CLAUDE_PLUGIN_ROOT}/dist/bin/enroll.mjs
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
It looks for a key in `$DARKHUNT_API_KEY`, then in the credentials `darkhunt-cli enroll`
|
|
36
|
+
wrote. Then react to the exit code:
|
|
37
|
+
|
|
38
|
+
- **Exit 0** — done. Show the user exactly what it printed: endpoint, tenant, workspace,
|
|
39
|
+
application, and which key it used. Ask them to confirm this is where they expect their
|
|
40
|
+
sessions to go. This matters — a config routing to the wrong tenant looks identical to
|
|
41
|
+
a correct one from everywhere else, and this summary is the only place the mistake is
|
|
42
|
+
visible.
|
|
43
|
+
|
|
44
|
+
- **Exit 3 — no key.** Do **not** ask for one. Tell the user to run this in their own
|
|
45
|
+
terminal, outside this session:
|
|
46
|
+
|
|
47
|
+
```
|
|
48
|
+
darkhunt-cli enroll --api-key <key>
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Their key is in the dashboard under **Settings → Security → API Keys**. Once that
|
|
52
|
+
succeeds, run the enroll command above again — it will pick the key up. If they do not
|
|
53
|
+
have `darkhunt-cli`, they can instead `export DARKHUNT_API_KEY=<key>` in the shell they
|
|
54
|
+
launched Codex CLI from, and restart the session.
|
|
55
|
+
|
|
56
|
+
- **Exit 2 — a choice is needed.** The key reaches more than one tenant, workspace or
|
|
57
|
+
application, and the options are listed. Show them by name, ask which one, then re-run
|
|
58
|
+
adding the chosen id — `--tenantId=`, `--workspaceId=` or `--applicationId=` — keeping
|
|
59
|
+
any already resolved. Repeat until it succeeds; there can be up to three rounds.
|
|
60
|
+
|
|
61
|
+
- **Any other exit** — show the error. Do not retry with different arguments hoping it
|
|
62
|
+
passes.
|
|
63
|
+
|
|
64
|
+
Finally, tell them capture begins on their **next** Codex CLI session, because hooks
|
|
65
|
+
are loaded when a session starts, and that `/darkhunt-guard:status` shows whether it is
|
|
66
|
+
working.
|
|
67
|
+
|
|
68
|
+
## Also
|
|
69
|
+
|
|
70
|
+
- Do not edit `~/.darkhunt/endpoint-config.json` by hand — enrollment writes it at 0600,
|
|
71
|
+
and a file with looser permissions is refused at load.
|
|
72
|
+
- Enforcement ships **off**. Setup does not turn it on, and you should not offer to.
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Is Darkhunt capture actually working? Shows routing, hook activity and shipping lag
|
|
3
|
+
allowed-tools: Bash(${CLAUDE_PLUGIN_ROOT}/dist/bin/status.mjs:*)
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
!`${CLAUDE_PLUGIN_ROOT}/dist/bin/status.mjs 2>&1 || true`
|
|
7
|
+
|
|
8
|
+
Explain the output above to the user in a few lines. Both lanes fail silently by
|
|
9
|
+
design — that is correct for the agent and unhelpful for whoever has to operate it — so
|
|
10
|
+
this command is the only place the truth is visible.
|
|
11
|
+
|
|
12
|
+
What the fields mean, and what to say:
|
|
13
|
+
|
|
14
|
+
- **`cannot read ...endpoint-config.json`** — not set up yet. Tell them to run
|
|
15
|
+
`/darkhunt-guard:setup`. Nothing is being captured, and nothing is being blocked.
|
|
16
|
+
- **tenant / workspace / application** — where sessions are being sent. Worth reading
|
|
17
|
+
aloud: a wrong destination looks exactly like a right one everywhere else.
|
|
18
|
+
- **user … [from agent]** — traces are attributed to the signed-in Codex CLI account.
|
|
19
|
+
`[from config]` means a value someone typed in, which on a shared machine is likely to
|
|
20
|
+
be the wrong person.
|
|
21
|
+
- **WARNING: session hooks are not firing** — the guard is running but
|
|
22
|
+
SessionStart/Stop/SessionEnd have gone quiet, so capture is riding PreToolUse alone.
|
|
23
|
+
Sessions are still captured, but anything before the last hook may be missing; suggest
|
|
24
|
+
a backfill if the gap looks large.
|
|
25
|
+
- **total lag** — bytes written but not yet shipped. A small number that returns to zero
|
|
26
|
+
is normal. A number that only grows means the forwarder is not running, or every
|
|
27
|
+
export is being rejected — check `last pass` to tell those apart.
|
|
28
|
+
- **last pass FAILED** — read out the cause. Checkpoints are held on failure, so nothing
|
|
29
|
+
has been lost; it will re-ship once the cause is fixed.
|
|
30
|
+
|
|
31
|
+
Do not run anything else, and do not offer to change the configuration unless asked.
|