@atbash/cli 0.5.15 → 0.6.0-dev.1
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/README.md +338 -0
- package/dist/bin/atbash.js +34 -2
- package/dist/bin/atbash.js.map +1 -1
- package/dist/commands/connect.d.ts +55 -1
- package/dist/commands/connect.js +11 -8
- package/dist/commands/connect.js.map +1 -1
- package/dist/commands/github-scan.d.ts +104 -0
- package/dist/commands/github-scan.js +1054 -0
- package/dist/commands/github-scan.js.map +1 -0
- package/dist/commands/held.js +7 -2
- package/dist/commands/held.js.map +1 -1
- package/dist/commands/history.js +4 -1
- package/dist/commands/history.js.map +1 -1
- package/dist/commands/judge-options.d.ts +21 -0
- package/dist/commands/judge-options.js +24 -0
- package/dist/commands/judge-options.js.map +1 -0
- package/dist/commands/judge.js +4 -1
- package/dist/commands/judge.js.map +1 -1
- package/dist/commands/policy.js +4 -1
- package/dist/commands/policy.js.map +1 -1
- package/dist/commands/scan.d.ts +45 -0
- package/dist/commands/scan.js +301 -0
- package/dist/commands/scan.js.map +1 -0
- package/dist/commands/setup.d.ts +151 -0
- package/dist/commands/setup.js +944 -0
- package/dist/commands/setup.js.map +1 -0
- package/dist/commands/stats.js +3 -1
- package/dist/commands/stats.js.map +1 -1
- package/dist/commands/status.js +4 -1
- package/dist/commands/status.js.map +1 -1
- package/dist/commands/tier.js +4 -1
- package/dist/commands/tier.js.map +1 -1
- package/dist/commands/tools.js +11 -4
- package/dist/commands/tools.js.map +1 -1
- package/dist/commands/whoami.js +4 -1
- package/dist/commands/whoami.js.map +1 -1
- package/dist/lib/grade-llm.d.ts +38 -0
- package/dist/lib/grade-llm.js +64 -0
- package/dist/lib/grade-llm.js.map +1 -0
- package/dist/lib/llm.d.ts +34 -0
- package/dist/lib/llm.js +101 -0
- package/dist/lib/llm.js.map +1 -0
- package/dist/lib/policy.d.ts +40 -0
- package/dist/lib/policy.js +94 -0
- package/dist/lib/policy.js.map +1 -0
- package/dist/lib/risk.d.ts +112 -0
- package/dist/lib/risk.js +288 -0
- package/dist/lib/risk.js.map +1 -0
- package/dist/lib/threats-llm.d.ts +39 -0
- package/dist/lib/threats-llm.js +72 -0
- package/dist/lib/threats-llm.js.map +1 -0
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -139,6 +139,168 @@ atbash judge 'grant admin access to CI service account'
|
|
|
139
139
|
The agent cannot retry or self-unjail. An operator must review and release at [https://atbash.ai/](https://atbash.ai/).
|
|
140
140
|
|
|
141
141
|
|
|
142
|
+
## Local scan
|
|
143
|
+
|
|
144
|
+
`atbash scan` reports what is installed on this machine. It needs no account, no pairing code and no dashboard. The report is printed in your terminal and is never uploaded.
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
# What is installed here
|
|
148
|
+
atbash scan
|
|
149
|
+
|
|
150
|
+
# Ask each MCP server what tools it actually has
|
|
151
|
+
atbash scan --introspect
|
|
152
|
+
|
|
153
|
+
# Add a draft boundary: red lines and actions that need approval
|
|
154
|
+
atbash scan --introspect --policy
|
|
155
|
+
|
|
156
|
+
# Machine-readable output
|
|
157
|
+
atbash scan --introspect --json
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
Output:
|
|
161
|
+
|
|
162
|
+
```
|
|
163
|
+
Atbash local scan
|
|
164
|
+
────────────────────────────
|
|
165
|
+
Machine : my-laptop
|
|
166
|
+
Found : 1 runtime
|
|
167
|
+
|
|
168
|
+
OpenClaw — 5 skills / plugins
|
|
169
|
+
• delete-customer-records
|
|
170
|
+
• export-crm-contacts
|
|
171
|
+
• issue-refund
|
|
172
|
+
• list-tickets
|
|
173
|
+
• send-email
|
|
174
|
+
|
|
175
|
+
Risk
|
|
176
|
+
────────────────────────────
|
|
177
|
+
Level : High (92/100)
|
|
178
|
+
Method : deterministic
|
|
179
|
+
5 authorized action paths (3 high-severity).
|
|
180
|
+
|
|
181
|
+
high delete-customer-records — destructive action
|
|
182
|
+
irreversible data/infrastructure loss
|
|
183
|
+
high export-crm-contacts — data access / egress
|
|
184
|
+
data leakage / privacy breach
|
|
185
|
+
high issue-refund — financial
|
|
186
|
+
direct financial loss
|
|
187
|
+
medium send-email — external communication
|
|
188
|
+
external message sent on the owner's behalf (monitored)
|
|
189
|
+
low list-tickets — read / research
|
|
190
|
+
low-consequence information access
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
With `--policy` it also prints a draft boundary you can edit and enforce:
|
|
194
|
+
|
|
195
|
+
```
|
|
196
|
+
Recommended boundary
|
|
197
|
+
────────────────────────────
|
|
198
|
+
Red lines (auto-deny)
|
|
199
|
+
• Never perform destructive action autonomously (e.g. delete-customer-records).
|
|
200
|
+
• Never perform data access / egress autonomously (e.g. export-crm-contacts).
|
|
201
|
+
• Never modify its own mandate, red lines, or authority.
|
|
202
|
+
|
|
203
|
+
Needs approval
|
|
204
|
+
• Require human approval before financial (e.g. issue-refund).
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
### What leaves your machine
|
|
208
|
+
|
|
209
|
+
Nothing, unless you ask for it.
|
|
210
|
+
|
|
211
|
+
| Command | Requests sent |
|
|
212
|
+
| --- | --- |
|
|
213
|
+
| `atbash scan` | none |
|
|
214
|
+
| `--introspect` | one per MCP server configured with an `http` URL, sent to that URL |
|
|
215
|
+
| `--api-key` | one, to your LLM provider |
|
|
216
|
+
| `--threats` | one, to your LLM provider |
|
|
217
|
+
|
|
218
|
+
Nothing is ever sent to Atbash. `--json` reports the actual count as `networkRequests`, so you can check it.
|
|
219
|
+
|
|
220
|
+
Credentials found in your config files are removed before anything is printed or sent. That covers `env` values, `headers`, tokens, and secrets embedded in command paths.
|
|
221
|
+
|
|
222
|
+
### Using your own LLM key
|
|
223
|
+
|
|
224
|
+
The built-in rules classify tools by name and description. Some tools match no rule. Supply your own [OpenRouter](https://openrouter.ai) key and the CLI will grade those as well. With `--threats` it also looks for risks that only appear when tools are combined, such as reading customer data and sending mail.
|
|
225
|
+
|
|
226
|
+
The key is read from the first of these that is set:
|
|
227
|
+
|
|
228
|
+
1. `--api-key <key>`
|
|
229
|
+
2. `ATBASH_SCAN_API_KEY`
|
|
230
|
+
3. `OPENROUTER_API_KEY`
|
|
231
|
+
|
|
232
|
+
On a shared machine, use an environment variable rather than `--api-key`. Command arguments are visible to other users through `ps`.
|
|
233
|
+
|
|
234
|
+
First get a key from [openrouter.ai/settings/keys](https://openrouter.ai/settings/keys). It looks like `sk-or-v1-` followed by 64 hex characters.
|
|
235
|
+
|
|
236
|
+
**macOS keychain.** The keychain stores every secret under the name "password", so the prompt says `password data for new item:`. That is where the API key goes. Do not type a login password.
|
|
237
|
+
|
|
238
|
+
```bash
|
|
239
|
+
security add-generic-password -a "$USER" -s atbash-openrouter -U -w
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
It prompts twice:
|
|
243
|
+
|
|
244
|
+
```
|
|
245
|
+
password data for new item: <- paste the sk-or-v1-... key
|
|
246
|
+
retype password for new item: <- paste it again
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
Nothing is echoed as you paste, and the two entries must match or it fails with `passwords don't match`. Check what actually got stored:
|
|
250
|
+
|
|
251
|
+
```bash
|
|
252
|
+
v=$(security find-generic-password -a "$USER" -s atbash-openrouter -w); echo "${#v} chars, starts ${v:0:9}"
|
|
253
|
+
# expect: 73 chars, starts sk-or-v1-
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
If that prints anything else, the wrong value was stored. Run the `add` command again; `-U` overwrites it.
|
|
257
|
+
|
|
258
|
+
Then use it:
|
|
259
|
+
|
|
260
|
+
```bash
|
|
261
|
+
export ATBASH_SCAN_API_KEY="$(security find-generic-password -a "$USER" -s atbash-openrouter -w)"
|
|
262
|
+
atbash scan --introspect --threats --policy
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
**Linux, or anywhere without a keychain.** Use a file only you can read:
|
|
266
|
+
|
|
267
|
+
```bash
|
|
268
|
+
mkdir -p ~/.config/atbash && chmod 700 ~/.config/atbash
|
|
269
|
+
(umask 077; touch ~/.config/atbash/openrouter.key)
|
|
270
|
+
$EDITOR ~/.config/atbash/openrouter.key # paste the key, save
|
|
271
|
+
|
|
272
|
+
export ATBASH_SCAN_API_KEY="$(cat ~/.config/atbash/openrouter.key)"
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
**CI.** Store the key as a repository secret and map it to the environment variable. Never put it in a file in the repo.
|
|
276
|
+
|
|
277
|
+
```yaml
|
|
278
|
+
- run: atbash scan --introspect --fail-on high
|
|
279
|
+
env:
|
|
280
|
+
ATBASH_SCAN_API_KEY: ${{ secrets.OPENROUTER_API_KEY }}
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
Pick a different model with `--model <id>`. The default is `z-ai/glm-5.3-flash`.
|
|
284
|
+
|
|
285
|
+
If the key is missing, wrong, or the provider is down, the scan still finishes using the built-in grading and tells you what failed. You never lose the report.
|
|
286
|
+
|
|
287
|
+
### Use in CI
|
|
288
|
+
|
|
289
|
+
`--fail-on` turns the risk level into an exit code.
|
|
290
|
+
|
|
291
|
+
```bash
|
|
292
|
+
atbash scan --introspect --fail-on high
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
| Exit code | Meaning |
|
|
296
|
+
| --- | --- |
|
|
297
|
+
| 0 | risk level is below the threshold |
|
|
298
|
+
| 1 | risk level reached the threshold |
|
|
299
|
+
| 2 | the `--fail-on` value was not `low`, `elevated` or `high` |
|
|
300
|
+
|
|
301
|
+
Run the gate without an API key. Built-in grading returns the same answer every time. Model grading varies between runs, which would make the gate flaky.
|
|
302
|
+
|
|
303
|
+
|
|
142
304
|
## End-to-end example: guarding a production deploy
|
|
143
305
|
|
|
144
306
|
A CI agent is about to apply a database migration to production. The operator policy holds all production applies for review before execution.
|
|
@@ -331,6 +493,29 @@ If any check fails — an integrity value that does not match the deployment's m
|
|
|
331
493
|
|
|
332
494
|
## Command reference
|
|
333
495
|
|
|
496
|
+
### `atbash scan`
|
|
497
|
+
|
|
498
|
+
Scan this machine and print the report here. No account and no pairing code. See [Local scan](#local-scan) for the full walkthrough.
|
|
499
|
+
|
|
500
|
+
```bash
|
|
501
|
+
npx --yes @atbash/cli scan --introspect --policy
|
|
502
|
+
```
|
|
503
|
+
|
|
504
|
+
| Flag | Description |
|
|
505
|
+
|------|-------------|
|
|
506
|
+
| `--introspect` | Ask each configured MCP server what tools it advertises. Starts stdio servers locally and contacts `http` servers at their own URL. No tool is ever called |
|
|
507
|
+
| `--policy` | Also print a draft boundary: red lines and actions that need approval |
|
|
508
|
+
| `--threats` | Also list risks that come from tools used in combination. Needs an API key |
|
|
509
|
+
| `--api-key <key>` | Your own LLM provider key. Also read from `ATBASH_SCAN_API_KEY` or `OPENROUTER_API_KEY` |
|
|
510
|
+
| `--model <id>` | Model used for grading. Default `z-ai/glm-5.3-flash` |
|
|
511
|
+
| `--fail-on <level>` | Exit 1 when the risk level reaches `low`, `elevated` or `high` |
|
|
512
|
+
| `--json` | Machine-readable output |
|
|
513
|
+
| `--home <dir>` | Home directory to scan (for testing) |
|
|
514
|
+
|
|
515
|
+
Without a key the report is produced entirely on this machine. `--threats` and
|
|
516
|
+
`--api-key` send tool names and descriptions to the provider you chose, never to
|
|
517
|
+
Atbash.
|
|
518
|
+
|
|
334
519
|
### `atbash connect <code>`
|
|
335
520
|
|
|
336
521
|
Link a machine to a hosted Atbash onboarding session. A browser can't read your disk and the Atbash server only sees its own, so this runs on the machine you want to govern, enumerates the agents / MCP tools configured there (read-only), and relays their *surface* to your onboarding session via the one-time pairing code shown in the browser.
|
|
@@ -357,6 +542,62 @@ configured MCP server processes, so it is not purely read-only even though Atbas
|
|
|
357
542
|
never invokes their tools. See [Verifying this CLI](#verifying-this-cli-before-you-run-it-humans--ai-agents)
|
|
358
543
|
and the [release checklist](RELEASE_CHECKLIST.md).
|
|
359
544
|
|
|
545
|
+
### `atbash setup`
|
|
546
|
+
|
|
547
|
+
Wire this machine's runtime to an agent you already onboarded. `connect` is the read-only half of onboarding; this is the half that **writes**. It places the agent key where every integration looks for it, installs the OpenClaw plugin, and *merges* the plugin block into your existing `~/.openclaw/openclaw.json` — the step that is easy to get wrong by hand, and whose failure mode is an agent that looks governed while enforcing nothing.
|
|
548
|
+
|
|
549
|
+
```bash
|
|
550
|
+
# Preview everything first — prints the exact file diffs, writes nothing:
|
|
551
|
+
npx --yes @atbash/cli setup --dry-run
|
|
552
|
+
|
|
553
|
+
# Point it at the key file onboarding downloaded for you:
|
|
554
|
+
npx --yes @atbash/cli setup --keys-dir ~/Downloads
|
|
555
|
+
|
|
556
|
+
# Or paste the key at a hidden prompt (nothing lands in your shell history):
|
|
557
|
+
npx --yes @atbash/cli setup
|
|
558
|
+
```
|
|
559
|
+
|
|
560
|
+
| Flag | Description |
|
|
561
|
+
|------|-------------|
|
|
562
|
+
| `-k, --key <privkey>` | Agent private key inline. Convenient, but it lands in your shell history — prefer the prompt or `--key-file` |
|
|
563
|
+
| `--key-file <path>` | Read the key from a file (`agent-keys-*.txt` from onboarding, or an existing `guard-client-key`) |
|
|
564
|
+
| `--keys-dir <dir>` | Directory holding the key file, e.g. `~/Downloads` |
|
|
565
|
+
| `--host <url>` | Deployment to check the agent's registration against |
|
|
566
|
+
| `--runtime <ids...>` | Only configure these runtimes (currently: `openclaw`) |
|
|
567
|
+
| `--dry-run` | Show which files would change, and the diffs, then exit WITHOUT writing |
|
|
568
|
+
| `-y, --yes` | Do not ask for confirmation before writing |
|
|
569
|
+
| `--no-install` | Write the key file and configs only; install no packages |
|
|
570
|
+
| `--skip-verify` | Make no network calls at all |
|
|
571
|
+
| `--allow-unrecognized-host` | Permit a `--host` outside the built-in Atbash allowlist |
|
|
572
|
+
| `--home <dir>` | Home directory to configure (for testing) |
|
|
573
|
+
|
|
574
|
+
If no key is supplied, setup looks in order at `--key`, `--key-file`, `--keys-dir`,
|
|
575
|
+
`ATBASH_AGENT_KEY`, the existing `~/.config/atbash/guard-client-key`, your
|
|
576
|
+
`atbash config`, and finally a hidden prompt that accepts **either** a key or a path.
|
|
577
|
+
Wherever it comes from, the key is written once to
|
|
578
|
+
`~/.config/atbash/guard-client-key` at `0600`, and every config setup writes
|
|
579
|
+
*references that path* rather than embedding the secret again.
|
|
580
|
+
|
|
581
|
+
**What it will not do.**
|
|
582
|
+
|
|
583
|
+
- It never transmits the private key. The only network call is a registration
|
|
584
|
+
check, and that sends the **public** key.
|
|
585
|
+
- It never writes the private key into an MCP client config. The documented
|
|
586
|
+
`@atbash/mcp` wiring carries the key as an `ATBASH_AGENT_PRIVKEY` value inside
|
|
587
|
+
files like `claude_desktop_config.json`, and that package has no key-file
|
|
588
|
+
fallback today. MCP clients are detected and the snippet is printed for you to
|
|
589
|
+
add by hand.
|
|
590
|
+
- It never edits your application source. Code-level integrations (LangChain,
|
|
591
|
+
LangGraph, AutoGen, Eliza, the SDK boundary) stay yours to write.
|
|
592
|
+
- It never rewrites a config that uses comments or trailing commas — reserializing
|
|
593
|
+
JSONC as JSON would delete your comments, so those become a printed snippet.
|
|
594
|
+
- It refuses to wire a runtime to an agent that is not registered. A machine that
|
|
595
|
+
looks governed with a plugin that can never get a verdict is the worst available
|
|
596
|
+
outcome.
|
|
597
|
+
|
|
598
|
+
Every file it changes is copied to a `.atbash-bak` alongside it first, and repeat
|
|
599
|
+
runs are idempotent.
|
|
600
|
+
|
|
360
601
|
### `atbash judge <action>`
|
|
361
602
|
|
|
362
603
|
Submit a pending action for judgment. The action string is the exact operation the agent is about to execute — a transfer, a command, a mutation.
|
|
@@ -476,6 +717,97 @@ Tool Call Details
|
|
|
476
717
|
Latency: 2340ms
|
|
477
718
|
```
|
|
478
719
|
|
|
720
|
+
### `atbash github-scan`
|
|
721
|
+
|
|
722
|
+
Read-only GitHub inventory and change-risk triage. The scanner calls GitHub's REST
|
|
723
|
+
API directly; it does not invoke the `gh` CLI and it never makes a mutating API
|
|
724
|
+
request.
|
|
725
|
+
|
|
726
|
+
```bash
|
|
727
|
+
# Use a classic/fine-grained user token or GitHub App installation token with
|
|
728
|
+
# read access to every repository and organization that should be inventoried.
|
|
729
|
+
# Set GITHUB_TOKEN or GH_TOKEN in the process environment; tokens are never
|
|
730
|
+
# accepted as command-line arguments.
|
|
731
|
+
|
|
732
|
+
atbash github-scan --owner Atbash-Ai --expect-repos 13 --since 2026-08-01 --json
|
|
733
|
+
atbash github-scan --repo Atbash-Ai/atbash-cli --branch main
|
|
734
|
+
```
|
|
735
|
+
|
|
736
|
+
`--owner` and `--repo` are repeatable. `--branch` limits branch inventory,
|
|
737
|
+
commits, and merged-PR base branch. `--since` accepts an ISO-8601 date or
|
|
738
|
+
timestamp and defaults to 30 days. Bots are excluded unless `--include-bots` is
|
|
739
|
+
set. Use `--owner` for scheduled organization audits: without it, `/user/repos`
|
|
740
|
+
intentionally inventories every owner visible to the token, which may include
|
|
741
|
+
private personal or unrelated organization repositories. `--expect-repos`
|
|
742
|
+
makes a known inventory size an exact fail-closed assertion.
|
|
743
|
+
|
|
744
|
+
The command verifies the authenticated user or GitHub App installation, records
|
|
745
|
+
OAuth scopes when GitHub supplies the `X-OAuth-Scopes` header, verifies
|
|
746
|
+
repository metadata permissions and organization visibility, and validates REST
|
|
747
|
+
pagination. A full page without a `Link` header is not accepted as terminal:
|
|
748
|
+
the scanner probes explicit sequential page numbers until a short/empty page or
|
|
749
|
+
a terminal `Link` relation is verified. Duplicate pages/items, changed filters,
|
|
750
|
+
cycles, non-sequential links, and the 1,000-page hard ceiling fail the scan.
|
|
751
|
+
This establishes completeness for the authenticated API view and selected
|
|
752
|
+
filters; it cannot prove that the token was granted access to repositories
|
|
753
|
+
GitHub never exposes to it. GitHub REST pagination is not snapshot-isolated:
|
|
754
|
+
concurrent repository changes can move items between pages. Duplicate/cycle
|
|
755
|
+
checks fail on detectable drift, but the `completeness.snapshotConsistency`
|
|
756
|
+
field explicitly records that snapshot consistency is not guaranteed; rerun a
|
|
757
|
+
scheduled audit if the organization changed during collection.
|
|
758
|
+
|
|
759
|
+
The network contract is GET-only: identity (`/user` or `/installation`),
|
|
760
|
+
repository inventory (`/user/repos` or `/installation/repositories`),
|
|
761
|
+
organization metadata, branches, closed pull requests, PR file metadata,
|
|
762
|
+
commits, commit file metadata, and commit-to-PR associations. Tests reject any
|
|
763
|
+
non-GET request across these paths.
|
|
764
|
+
|
|
765
|
+
JSON output is sorted and schema-versioned. It includes a `completeness` object,
|
|
766
|
+
rate-limit status, public/private counts, branches, recent merged PR metadata,
|
|
767
|
+
commit metadata, changed filenames, and deterministic risk flags.
|
|
768
|
+
|
|
769
|
+
Bound controls fail rather than truncate:
|
|
770
|
+
|
|
771
|
+
- `--max-repos` (default 1,000)
|
|
772
|
+
- `--max-branches` per repository (default 1,000)
|
|
773
|
+
- `--max-prs` recent closed PRs inspected per repository (default 1,000)
|
|
774
|
+
- `--max-commits` per branch (default 1,000)
|
|
775
|
+
- `--max-files` per PR or commit (default 3,000)
|
|
776
|
+
|
|
777
|
+
Lower these for tightly bounded scheduled jobs. Raise them deliberately for a
|
|
778
|
+
larger organization; exceeding any bound exits nonzero without output or state
|
|
779
|
+
advancement.
|
|
780
|
+
|
|
781
|
+
Security and limits:
|
|
782
|
+
|
|
783
|
+
- Set exactly one of `GITHUB_TOKEN` or `GH_TOKEN`; if both differ, the command
|
|
784
|
+
fails. Tokens are held in memory, sent only in the GitHub authorization
|
|
785
|
+
header, and redacted from errors.
|
|
786
|
+
- The scanner never fetches blobs, trees, patches, diffs, or private file
|
|
787
|
+
contents. It reads repository/change metadata and changed filenames. Private
|
|
788
|
+
repository names and filenames still remain sensitive; protect JSON output.
|
|
789
|
+
- Human output exposes authenticated identity, repository names/visibility,
|
|
790
|
+
aggregate counts, and risk-category names. JSON additionally exposes branch
|
|
791
|
+
names, PR titles/authors/timestamps, commit subjects/authors/timestamps, URLs,
|
|
792
|
+
changed filenames, and permission metadata. Treat either output as sensitive;
|
|
793
|
+
redirect JSON only to an access-controlled destination.
|
|
794
|
+
- The complete result is buffered before anything is printed. Authentication,
|
|
795
|
+
permission, malformed response, pagination, REST, or rate-limit failure exits
|
|
796
|
+
nonzero and emits no partial scan. The scanner writes no cursor or checkpoint,
|
|
797
|
+
so a failed run cannot advance state.
|
|
798
|
+
- Risk flags are deterministic path-based triage for Rell/contracts,
|
|
799
|
+
encryption/keys/auth, decision semantics, SDK/plugin APIs,
|
|
800
|
+
workflows/releases/dependencies, and direct commits detected on protected
|
|
801
|
+
branches. They are not semantic code analysis and are explicitly **not a full
|
|
802
|
+
SAST assessment**.
|
|
803
|
+
- Direct-commit detection asks GitHub whether a protected-branch commit belongs
|
|
804
|
+
to a merged PR. Branch rules, merge queues, force pushes, and GitHub's
|
|
805
|
+
commit-to-PR association can limit that inference.
|
|
806
|
+
- Fine-grained tokens and GitHub App installations should receive read-only
|
|
807
|
+
metadata, contents, pull-request, and organization access as applicable.
|
|
808
|
+
GitHub may not report named scopes for these token types; successful endpoint
|
|
809
|
+
access is the permission check.
|
|
810
|
+
|
|
479
811
|
### `atbash whoami` / `atbash policy show` / `atbash tier`
|
|
480
812
|
|
|
481
813
|
Inspect the current agent's identity, assigned policy, and org tier.
|
|
@@ -561,7 +893,13 @@ atbash unset endpoint
|
|
|
561
893
|
| Agent key | `--agent-key` | `ATBASH_AGENT_KEY` | `atbash set agent-key <hex>` |
|
|
562
894
|
| Org name | `--org` | `ATBASH_ORG_NAME` | `atbash set org-name <name>` |
|
|
563
895
|
| API endpoint | `--endpoint` | `ATBASH_ENDPOINT` | `atbash set endpoint <url>` |
|
|
896
|
+
| Self-hosted judge signing key | `--verify-pubkey` (judge) | `ATBASH_JUDGE_VERIFY_PUBKEY` | config key `judgeVerifyPubKey` |
|
|
564
897
|
| Blockchain RID | — | `ATBASH_BLOCKCHAIN_RID` | `atbash set rid <hex>` |
|
|
898
|
+
|
|
899
|
+
> **Self-hosted judge:** the SDK only accepts an endpoint outside the trusted allowlist
|
|
900
|
+
> when the judge's 66-hex response-signing pubkey is supplied too, so every verdict can be
|
|
901
|
+
> verified. Set `ATBASH_JUDGE_VERIFY_PUBKEY` (or `--verify-pubkey` on `judge`) together with
|
|
902
|
+
> `--endpoint`; without it a non-default endpoint is refused.
|
|
565
903
|
| Inference provider | `--provider` | `ATBASH_PROVIDER` | `atbash set provider <name>` |
|
|
566
904
|
| Model | `--model` | `ATBASH_PROVIDER_MODEL` | `atbash set model <model>` |
|
|
567
905
|
|
package/dist/bin/atbash.js
CHANGED
|
@@ -19,18 +19,46 @@ const tier_1 = require("../commands/tier");
|
|
|
19
19
|
const tools_1 = require("../commands/tools");
|
|
20
20
|
const held_1 = require("../commands/held");
|
|
21
21
|
const connect_1 = require("../commands/connect");
|
|
22
|
+
const scan_1 = require("../commands/scan");
|
|
23
|
+
const setup_1 = require("../commands/setup");
|
|
24
|
+
const github_scan_1 = require("../commands/github-scan");
|
|
22
25
|
// ── Autocomplete ────────────────────────────────────────────────
|
|
23
26
|
const commands = [
|
|
24
27
|
"judge", "whoami", "policy", "tier", "tools", "held",
|
|
25
28
|
"history", "stats", "status", "keygen", "set", "unset",
|
|
26
|
-
"wipe", "config", "connect", "help",
|
|
29
|
+
"wipe", "config", "connect", "scan", "setup", "github-scan", "help",
|
|
27
30
|
];
|
|
28
31
|
const subcommands = {
|
|
29
|
-
judge: [
|
|
32
|
+
judge: [
|
|
33
|
+
"--context",
|
|
34
|
+
"--agent-key",
|
|
35
|
+
"--provider",
|
|
36
|
+
"--model",
|
|
37
|
+
"--org",
|
|
38
|
+
"--endpoint",
|
|
39
|
+
"--timeout",
|
|
40
|
+
"--json",
|
|
41
|
+
],
|
|
30
42
|
policy: ["show"],
|
|
31
43
|
tools: ["--agent", "--org", "--count", "--json", "inspect", "count"],
|
|
32
44
|
held: ["--org", "--count", "--json", "reviews"],
|
|
33
45
|
connect: ["--host", "--home"],
|
|
46
|
+
scan: ["--home", "--introspect", "--api-key", "--model", "--threats", "--policy", "--fail-on", "--json"],
|
|
47
|
+
setup: ["--key", "--key-file", "--keys-dir", "--host", "--runtime", "--dry-run", "--yes", "--no-install", "--skip-verify", "--home"],
|
|
48
|
+
"github-scan": [
|
|
49
|
+
"--owner",
|
|
50
|
+
"--repo",
|
|
51
|
+
"--branch",
|
|
52
|
+
"--since",
|
|
53
|
+
"--expect-repos",
|
|
54
|
+
"--max-repos",
|
|
55
|
+
"--max-branches",
|
|
56
|
+
"--max-prs",
|
|
57
|
+
"--max-commits",
|
|
58
|
+
"--max-files",
|
|
59
|
+
"--include-bots",
|
|
60
|
+
"--json",
|
|
61
|
+
],
|
|
34
62
|
set: ["agent-key", "org-name", "endpoint", "rid", "provider", "model"],
|
|
35
63
|
unset: ["agent-key", "org-name", "endpoint", "rid", "provider", "model"],
|
|
36
64
|
show: ["--agent-key", "--endpoint", "--json"],
|
|
@@ -85,6 +113,10 @@ program
|
|
|
85
113
|
(0, config_cmd_1.registerConfigCommand)(program);
|
|
86
114
|
// Onboarding
|
|
87
115
|
(0, connect_1.registerConnectCommand)(program);
|
|
116
|
+
(0, scan_1.registerScanCommand)(program);
|
|
117
|
+
(0, setup_1.registerSetupCommand)(program);
|
|
118
|
+
// External scanning
|
|
119
|
+
(0, github_scan_1.registerGithubScanCommand)(program);
|
|
88
120
|
async function main() {
|
|
89
121
|
await program.parseAsync(process.argv);
|
|
90
122
|
await (0, sdk_1.shutdownTelemetry)();
|
package/dist/bin/atbash.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"atbash.js","sourceRoot":"","sources":["../../src/bin/atbash.ts"],"names":[],"mappings":";;;;;;AACA,yCAAoC;AACpC,wDAAgC;AAChC,qCAAgE;AAChE,6CAAyD;AACzD,+CAA2D;AAC3D,+CAA2D;AAC3D,iDAA6D;AAC7D,6CAAyD;AACzD,uDAA+D;AAC/D,+CAA2D;AAC3D,+CAA2D;AAC3D,2CAAuD;AACvD,6CAAyD;AACzD,2CAAuD;AACvD,iDAA6D;
|
|
1
|
+
{"version":3,"file":"atbash.js","sourceRoot":"","sources":["../../src/bin/atbash.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,38 @@
|
|
|
1
1
|
import { Command } from "commander";
|
|
2
|
+
/**
|
|
3
|
+
* `atbash connect <code>` — the local connector.
|
|
4
|
+
*
|
|
5
|
+
* A hosted Atbash onboarding page can't read your machine's filesystem, and the
|
|
6
|
+
* Atbash server only sees its own disk. This command runs on YOUR machine,
|
|
7
|
+
* enumerates the agents/MCP tools configured locally, and relays them to your
|
|
8
|
+
* onboarding session via a one-time pairing code shown in the browser.
|
|
9
|
+
*
|
|
10
|
+
* Read-only: it reads a fixed set of known agent config paths and reports the
|
|
11
|
+
* declared tool surface (server/skill NAMES) — never the secret values inside.
|
|
12
|
+
* It makes ONE outbound POST (the relay) and exits.
|
|
13
|
+
*
|
|
14
|
+
* The discovery mirrors the dashboard's src/lib/scan/discover.ts and produces
|
|
15
|
+
* the same relay-safe payload the session endpoint expects.
|
|
16
|
+
*/
|
|
17
|
+
/**
|
|
18
|
+
* Official Atbash deployments that legitimately serve the onboarding flow.
|
|
19
|
+
*
|
|
20
|
+
* The pairing screen builds `--host` from the page you opened, so every origin
|
|
21
|
+
* that can host onboarding must appear here. If production were missing, the real
|
|
22
|
+
* atbash.ai would be flagged "unrecognized destination" — a false alarm on the
|
|
23
|
+
* genuine article, which is worse than silence: it teaches people and agents to
|
|
24
|
+
* wave through the one warning that actually catches a swapped host.
|
|
25
|
+
*
|
|
26
|
+
* Matched on EXACT hostname, never a suffix — "atbash.ai.evil.com" must not pass.
|
|
27
|
+
* Deliberately not a *.vercel.app wildcard: that would bless anyone's preview.
|
|
28
|
+
*/
|
|
29
|
+
export declare const KNOWN_HOSTS: Set<string>;
|
|
30
|
+
/**
|
|
31
|
+
* Used when neither --host nor ATBASH_HOST is given. Still the dev deployment,
|
|
32
|
+
* because it is the one running the current connector API; switch this to
|
|
33
|
+
* https://atbash.ai once production serves it (KNOWN_HOSTS already allows it).
|
|
34
|
+
*/
|
|
35
|
+
export declare const DEFAULT_HOST = "https://chromia-verified-ai-dev-two.vercel.app";
|
|
2
36
|
interface DeclaredTool {
|
|
3
37
|
name: string;
|
|
4
38
|
description?: string;
|
|
@@ -36,6 +70,10 @@ declare function describeSkill(text: string | undefined, fallback: string): stri
|
|
|
36
70
|
declare function safeDescription(raw: string): string | undefined;
|
|
37
71
|
/** Walk a skills root (bounded) → declared tools. Mirrors src/lib/scan/adapters/local-skills.ts. */
|
|
38
72
|
declare function enumerateSkills(root: string, maxDepth?: number, cap?: number): DeclaredTool[];
|
|
73
|
+
export declare const MCP_CONFIGS: {
|
|
74
|
+
label: string;
|
|
75
|
+
segs: string[];
|
|
76
|
+
}[];
|
|
39
77
|
/**
|
|
40
78
|
* THE sanitization boundary. Reduce an mcpServers map to the SANITIZED structural
|
|
41
79
|
* signal the hosted scanner needs — server name, host+path of the endpoint, and
|
|
@@ -51,5 +89,21 @@ declare function enumerateSkills(root: string, maxDepth?: number, cap?: number):
|
|
|
51
89
|
declare function relaySafeServers(servers: Record<string, unknown>): Record<string, unknown>;
|
|
52
90
|
/** Enumerate the agents/MCP tools configured on this machine. Read-only. */
|
|
53
91
|
declare function discover(home: string): Agent[];
|
|
92
|
+
/**
|
|
93
|
+
* ⚠️ SECURITY INVARIANT — this returns RAW, UNSANITIZED server specs.
|
|
94
|
+
* The values here contain live secrets: url credentials, `env`, `headers`,
|
|
95
|
+
* `token`, `apiKey`, and absolute command paths. They exist ONLY so `--introspect`
|
|
96
|
+
* can reach a server locally. They MUST NEVER be put into the relay payload
|
|
97
|
+
* directly. Every path that turns these into an `Agent` MUST route them through
|
|
98
|
+
* `relaySafeServers()` first (the single sanitization boundary). If you add a new
|
|
99
|
+
* consumer, sanitize before it leaves this file. Callers today: `discover()`
|
|
100
|
+
* (sanitizes), `connect --introspect` and `atbash scan --introspect` (both local
|
|
101
|
+
* only, never relayed — scan has no relay path at all).
|
|
102
|
+
*/
|
|
103
|
+
declare function readAllMcpServers(home: string): {
|
|
104
|
+
label: string;
|
|
105
|
+
servers: Record<string, unknown>;
|
|
106
|
+
}[];
|
|
54
107
|
export declare function registerConnectCommand(program: Command): void;
|
|
55
|
-
export { discover, enumerateSkills, describeSkill, relaySafeServers, safeDescription };
|
|
108
|
+
export { discover, enumerateSkills, describeSkill, relaySafeServers, safeDescription, readAllMcpServers };
|
|
109
|
+
export type { Agent, DeclaredTool };
|
package/dist/commands/connect.js
CHANGED
|
@@ -36,12 +36,14 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
36
36
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
37
|
};
|
|
38
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.MCP_CONFIGS = exports.DEFAULT_HOST = exports.KNOWN_HOSTS = void 0;
|
|
39
40
|
exports.registerConnectCommand = registerConnectCommand;
|
|
40
41
|
exports.discover = discover;
|
|
41
42
|
exports.enumerateSkills = enumerateSkills;
|
|
42
43
|
exports.describeSkill = describeSkill;
|
|
43
44
|
exports.relaySafeServers = relaySafeServers;
|
|
44
45
|
exports.safeDescription = safeDescription;
|
|
46
|
+
exports.readAllMcpServers = readAllMcpServers;
|
|
45
47
|
const fs = __importStar(require("fs"));
|
|
46
48
|
const os = __importStar(require("os"));
|
|
47
49
|
const path = __importStar(require("path"));
|
|
@@ -77,7 +79,7 @@ const introspect_mcp_1 = require("./introspect-mcp");
|
|
|
77
79
|
* Matched on EXACT hostname, never a suffix — "atbash.ai.evil.com" must not pass.
|
|
78
80
|
* Deliberately not a *.vercel.app wildcard: that would bless anyone's preview.
|
|
79
81
|
*/
|
|
80
|
-
|
|
82
|
+
exports.KNOWN_HOSTS = new Set([
|
|
81
83
|
"atbash.ai",
|
|
82
84
|
"www.atbash.ai",
|
|
83
85
|
"chromia-verified-ai-dev-two.vercel.app",
|
|
@@ -88,7 +90,7 @@ const KNOWN_HOSTS = new Set([
|
|
|
88
90
|
* because it is the one running the current connector API; switch this to
|
|
89
91
|
* https://atbash.ai once production serves it (KNOWN_HOSTS already allows it).
|
|
90
92
|
*/
|
|
91
|
-
|
|
93
|
+
exports.DEFAULT_HOST = "https://chromia-verified-ai-dev-two.vercel.app";
|
|
92
94
|
// Discovery is intentionally bounded. A local config is untrusted input even
|
|
93
95
|
// though it lives on the operator's machine: a giant/malformed file must not turn
|
|
94
96
|
// a one-shot connector into a memory or latency sink.
|
|
@@ -196,7 +198,7 @@ function enumerateSkills(root, maxDepth = 3, cap = 400) {
|
|
|
196
198
|
walk(root, 0, path.basename(root));
|
|
197
199
|
return tools;
|
|
198
200
|
}
|
|
199
|
-
|
|
201
|
+
exports.MCP_CONFIGS = [
|
|
200
202
|
{ label: "Claude Desktop", segs: ["Library", "Application Support", "Claude", "claude_desktop_config.json"] },
|
|
201
203
|
{ label: "Claude Desktop", segs: [".config", "Claude", "claude_desktop_config.json"] },
|
|
202
204
|
{ label: "Cursor", segs: [".cursor", "mcp.json"] },
|
|
@@ -351,12 +353,13 @@ function discover(home) {
|
|
|
351
353
|
* directly. Every path that turns these into an `Agent` MUST route them through
|
|
352
354
|
* `relaySafeServers()` first (the single sanitization boundary). If you add a new
|
|
353
355
|
* consumer, sanitize before it leaves this file. Callers today: `discover()`
|
|
354
|
-
* (sanitizes) and
|
|
356
|
+
* (sanitizes), `connect --introspect` and `atbash scan --introspect` (both local
|
|
357
|
+
* only, never relayed — scan has no relay path at all).
|
|
355
358
|
*/
|
|
356
359
|
function readAllMcpServers(home) {
|
|
357
360
|
const out = [];
|
|
358
361
|
const seen = new Set();
|
|
359
|
-
for (const { label, segs } of MCP_CONFIGS) {
|
|
362
|
+
for (const { label, segs } of exports.MCP_CONFIGS) {
|
|
360
363
|
if (seen.has(label))
|
|
361
364
|
continue;
|
|
362
365
|
const cfg = readJson(home, ...segs);
|
|
@@ -407,7 +410,7 @@ function registerConnectCommand(program) {
|
|
|
407
410
|
.option("--allow-unrecognized-host", "Permit relaying to a --host that is not an official Atbash deployment (otherwise the command refuses to send)")
|
|
408
411
|
.action(async (rawCode, opts) => {
|
|
409
412
|
const home = opts.home || os.homedir();
|
|
410
|
-
const host = (opts.host || process.env.ATBASH_HOST || DEFAULT_HOST).replace(/\/+$/, "");
|
|
413
|
+
const host = (opts.host || process.env.ATBASH_HOST || exports.DEFAULT_HOST).replace(/\/+$/, "");
|
|
411
414
|
const code = rawCode.trim().toUpperCase().replace(/[^A-Z0-9-]/g, "");
|
|
412
415
|
const machine = os.hostname();
|
|
413
416
|
const dryRun = !!opts.dryRun;
|
|
@@ -427,7 +430,7 @@ function registerConnectCommand(program) {
|
|
|
427
430
|
const hostname = hostUrl ? hostUrl.hostname.toLowerCase() : "";
|
|
428
431
|
const isLoopback = /^(localhost|127\.\d+\.\d+\.\d+|\[::1\]|::1)$/.test(hostname);
|
|
429
432
|
// "Recognized" = an official Atbash deployment (or your own machine for dev).
|
|
430
|
-
const recognizedHost = KNOWN_HOSTS.has(hostname) || isLoopback;
|
|
433
|
+
const recognizedHost = exports.KNOWN_HOSTS.has(hostname) || isLoopback;
|
|
431
434
|
// Machine-readable summary for the --json path AND for any error, so an agent
|
|
432
435
|
// gets a stable, parseable description of exactly what this command is/was doing.
|
|
433
436
|
const emitJson = (extra) => console.log(JSON.stringify({
|
|
@@ -443,7 +446,7 @@ function registerConnectCommand(program) {
|
|
|
443
446
|
machine, host, endpoint, code,
|
|
444
447
|
// An agent should treat `recognizedHost: false` as a reason to stop and
|
|
445
448
|
// ask, not a detail to skim past.
|
|
446
|
-
recognizedHost, knownHosts: [...KNOWN_HOSTS],
|
|
449
|
+
recognizedHost, knownHosts: [...exports.KNOWN_HOSTS],
|
|
447
450
|
...extra,
|
|
448
451
|
}, null, 2));
|
|
449
452
|
if (!code) {
|