@vigilbase/cli 0.2.3 → 0.2.4
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/CLOUDFLARE.md +2 -2
- package/COMMANDS.md +111 -44
- package/LOCAL.md +99 -38
- package/ONE.md +1 -1
- package/README.md +215 -67
- package/dist/auth/acl.d.ts +6 -0
- package/dist/auth/acl.js +45 -0
- package/dist/auth/device-auth.js +1 -0
- package/dist/auth/provider.js +4 -4
- package/dist/auth/refresh.d.ts +5 -4
- package/dist/auth/refresh.js +82 -41
- package/dist/auth/store.d.ts +25 -0
- package/dist/auth/store.js +91 -11
- package/dist/bin.js +13 -1
- package/dist/cli.js +205 -81
- package/dist/commands/account.js +11 -7
- package/dist/commands/auth.d.ts +6 -0
- package/dist/commands/auth.js +75 -24
- package/dist/commands/billing.js +2 -2
- package/dist/commands/cloudflare.d.ts +1 -1
- package/dist/commands/cloudflare.js +31 -17
- package/dist/commands/helpers.js +3 -3
- package/dist/commands/index.d.ts +1 -0
- package/dist/commands/index.js +2 -1
- package/dist/commands/legacy-validation.d.ts +20 -0
- package/dist/commands/legacy-validation.js +77 -3
- package/dist/commands/local.js +186 -65
- package/dist/commands/one.js +16 -13
- package/dist/commands/public-tools.js +52 -27
- package/dist/commands/runs.js +5 -5
- package/dist/commands/security.d.ts +1 -1
- package/dist/commands/security.js +41 -37
- package/dist/commands/watchdog.js +5 -5
- package/dist/lib/banner.d.ts +5 -11
- package/dist/lib/banner.js +11 -31
- package/dist/lib/client.js +19 -1
- package/dist/lib/cloudflare-client.d.ts +2 -2
- package/dist/lib/config.d.ts +16 -0
- package/dist/lib/config.js +77 -19
- package/dist/lib/format.d.ts +1 -1
- package/dist/lib/format.js +75 -24
- package/dist/lib/help.js +57 -6
- package/dist/lib/network.d.ts +12 -3
- package/dist/lib/network.js +73 -9
- package/dist/lib/one-client.js +9 -2
- package/dist/lib/open-url.js +2 -1
- package/dist/lib/platform.d.ts +2 -0
- package/dist/lib/platform.js +5 -0
- package/dist/lib/progress.d.ts +18 -3
- package/dist/lib/progress.js +72 -10
- package/dist/lib/system-trust.d.ts +2 -0
- package/dist/lib/system-trust.js +6 -0
- package/dist/lib/tui.d.ts +1 -1
- package/dist/lib/tui.js +5 -7
- package/dist/local/cloudflare-checkup/cf/child-env.js +2 -4
- package/dist/local/cloudflare-checkup/cf/install.d.ts +4 -2
- package/dist/local/cloudflare-checkup/cf/install.js +55 -24
- package/dist/local/cloudflare-checkup/cf/locate.d.ts +2 -0
- package/dist/local/cloudflare-checkup/cf/locate.js +10 -1
- package/dist/local/cloudflare-checkup/cf/run-cf.d.ts +18 -3
- package/dist/local/cloudflare-checkup/cf/run-cf.js +75 -17
- package/dist/local/cloudflare-checkup/contract.d.ts +16 -9
- package/dist/local/cloudflare-checkup/contract.js +80 -14
- package/dist/local/cloudflare-checkup/errors.d.ts +34 -1
- package/dist/local/cloudflare-checkup/errors.js +36 -5
- package/dist/local/cloudflare-checkup/output.d.ts +6 -0
- package/dist/local/cloudflare-checkup/output.js +9 -0
- package/dist/local/cloudflare-checkup/snapshot-file.d.ts +6 -2
- package/dist/local/cloudflare-checkup/snapshot-file.js +25 -11
- package/dist/local/cloudflare-checkup/submit-client.js +7 -1
- package/dist/types.d.ts +2 -1
- package/esm-only.cjs +3 -0
- package/package.json +7 -4
package/README.md
CHANGED
|
@@ -28,14 +28,17 @@ supported on Windows yet; public tools and `cloudflare-checkup` still work there
|
|
|
28
28
|
|
|
29
29
|
| Reference | Covers |
|
|
30
30
|
| --- | --- |
|
|
31
|
-
| [COMMANDS.md](https://app.unpkg.com/@vigilbase/cli@0.2.
|
|
32
|
-
| [CLOUDFLARE.md](https://app.unpkg.com/@vigilbase/cli@0.2.
|
|
33
|
-
| [SECURITY.md](https://app.unpkg.com/@vigilbase/cli@0.2.
|
|
34
|
-
| [ONE.md](https://app.unpkg.com/@vigilbase/cli@0.2.
|
|
35
|
-
| [LOCAL.md](https://app.unpkg.com/@vigilbase/cli@0.2.
|
|
31
|
+
| [COMMANDS.md](https://app.unpkg.com/@vigilbase/cli@0.2.4/files/COMMANDS.md) | Core commands, aliases, global options, API mapping, sign-in, output |
|
|
32
|
+
| [CLOUDFLARE.md](https://app.unpkg.com/@vigilbase/cli@0.2.4/files/CLOUDFLARE.md) | Accounts, zones, DNS, WAF, analytics, Zero Trust, Workers/Pages, audit, checkups |
|
|
33
|
+
| [SECURITY.md](https://app.unpkg.com/@vigilbase/cli@0.2.4/files/SECURITY.md) | Incidents, logs, intelligence, analytics, assets, connections, policies, notifications, reports |
|
|
34
|
+
| [ONE.md](https://app.unpkg.com/@vigilbase/cli@0.2.4/files/ONE.md) | Customer records, billing, reports, investigations, organizations, monitoring, support |
|
|
35
|
+
| [LOCAL.md](https://app.unpkg.com/@vigilbase/cli@0.2.4/files/LOCAL.md) | `cloudflare-checkup`: verifies your work email, collects your Cloudflare configuration on your machine with Cloudflare's `cf` and uploads it after you confirm |
|
|
36
36
|
|
|
37
37
|
These files ship with the package. Built-in help: `vigilbase <command> --help`
|
|
38
|
-
or `vigilbase help <command>`; `vigilbase help <
|
|
38
|
+
or `vigilbase help <command>`; `vigilbase help <command> <subcommand>` (for
|
|
39
|
+
example `vigilbase help cf zones`) shows the same help as
|
|
40
|
+
`vigilbase cf zones --help`, and `vigilbase help <tool>` shows how to run a
|
|
41
|
+
tool. The library is ESM-only: use `import()`, not `require()`.
|
|
39
42
|
|
|
40
43
|
## Examples
|
|
41
44
|
|
|
@@ -143,7 +146,7 @@ read-only Cloudflare API token instead. When you are done:
|
|
|
143
146
|
npx @vigilbase/cli cloudflare-checkup logout # removes the read-only cf login and the cf it installed
|
|
144
147
|
```
|
|
145
148
|
|
|
146
|
-
See [LOCAL.md](https://app.unpkg.com/@vigilbase/cli@0.2.
|
|
149
|
+
See [LOCAL.md](https://app.unpkg.com/@vigilbase/cli@0.2.4/files/LOCAL.md) for
|
|
147
150
|
every step, what is uploaded and the error codes.
|
|
148
151
|
|
|
149
152
|
## Public tools and sign-in
|
|
@@ -152,51 +155,106 @@ every step, what is uploaded and the error codes.
|
|
|
152
155
|
`run security-headers|email-security` call the public API anonymously and
|
|
153
156
|
never read your saved sign-in, so an expired, broken or unreachable sign-in
|
|
154
157
|
cannot make them fail. `--public` and `--via public` force the public API for
|
|
155
|
-
|
|
158
|
+
the public tools (`security-headers`, `email-security`).
|
|
156
159
|
- **One-only scans need a sign-in.** `website-security`, `react2shell`,
|
|
157
160
|
`fortibleed-check` and any run with `--via one` go through Vigilbase One.
|
|
158
161
|
Without a usable sign-in they stop with
|
|
159
|
-
``This
|
|
162
|
+
``This command needs a Vigilbase One sign-in: run `vigilbase login`.``
|
|
163
|
+
(code `NOT_SIGNED_IN`), as every One command does. With `--public` or
|
|
164
|
+
`--via public` a One-only tool stops before any request:
|
|
165
|
+
``website-security runs only through Vigilbase One: drop --public and run `vigilbase login`.``
|
|
166
|
+
`run` with a tool name it doesn't know fails locally with
|
|
167
|
+
``Unknown tool "<name>". Run `vigilbase list` for the allowlist.``
|
|
168
|
+
(code `INVALID_ARGUMENT`).
|
|
169
|
+
- **Scan quota.** Public scans share an hourly quota of 20 scans per client IP
|
|
170
|
+
address and 20 per target (1,000 an hour overall). When it is used up,
|
|
171
|
+
vigilbase.com answers HTTP 429 (`rate_limit_exceeded`) and the CLI exits 2
|
|
172
|
+
with the delay until the quota resets (up to an hour; `retryAfterSec` in
|
|
173
|
+
JSON). The CLI never retries on its own.
|
|
160
174
|
- **`list`** reads your saved sign-in from disk only (no refresh, no network,
|
|
161
175
|
no waiting for another command) to show which tools you can run. If it can't
|
|
162
176
|
use it, it lists the tools as signed out and prints one line on stderr:
|
|
163
177
|
``Couldn't use your saved sign-in (<reason>); running anonymously. Run `vigilbase login` to fix.``
|
|
164
178
|
When the reason is an unsafe config path or credentials file, the line ends
|
|
165
179
|
with its fix instead (see [Directory checks](#directory-checks)).
|
|
166
|
-
- **`doctor`** reports a sign-in problem as its own failed `signIn` check
|
|
180
|
+
- **`doctor`** reports a sign-in problem as its own failed `signIn` check,
|
|
181
|
+
including a sign-in saved for another One origin, Identity issuer or client
|
|
182
|
+
ID: ``Saved for a different One origin, Identity issuer or client ID. Pass the matching --one-url, --auth-url and --client-id, or run `vigilbase login`.``
|
|
167
183
|
|
|
168
184
|
## Automation and output
|
|
169
185
|
|
|
170
186
|
Every command supports `-j` / `--json`. JSON goes to stdout; progress and
|
|
171
|
-
browser instructions go to stderr.
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
187
|
+
browser instructions go to stderr. Errors are JSON on stdout whenever `--json`
|
|
188
|
+
or `-j` is given, also inside a cluster of short flags (`-hj`) and as
|
|
189
|
+
`--json=…`; a `--json` after `--` is an argument, not the flag. Commands are
|
|
190
|
+
matched in any case (`vigilbase LIST` is `vigilbase list`).
|
|
191
|
+
|
|
192
|
+
Progress animations are off for `--json`, for output that isn't a terminal, in
|
|
193
|
+
CI (`CI` set to anything but `0` or `false`, in any case), with `TERM=dumb` and
|
|
194
|
+
with `VIGILBASE_CLI_NO_PROGRESS=1`. `NO_COLOR` doesn't turn them off, because
|
|
195
|
+
the spinner has no colour. The spinner fits the terminal width, and Ctrl-C
|
|
196
|
+
during a scan clears its line and exits 130. The same CI rule decides the
|
|
197
|
+
checkup's terminal UI and its colours and opening a browser (login, billing),
|
|
198
|
+
so `CI=yes` neither animates nor opens a browser.
|
|
199
|
+
|
|
200
|
+
List commands never fetch every page on their own: keep the JSON pagination
|
|
201
|
+
fields to fetch the next page. Text output shows complete identifiers: the
|
|
202
|
+
first column of `runs list` works with `runs get`, and `watchdog list` starts
|
|
203
|
+
with the target ID that `watchdog scans --target-id` takes.
|
|
204
|
+
|
|
205
|
+
Human-readable output removes terminal control sequences, bidirectional
|
|
206
|
+
overrides and invisible characters (zero-width characters, word joiners, the
|
|
207
|
+
byte order mark, U+2028/U+2029 line separators and Unicode tag characters) from
|
|
208
|
+
everything it prints, including names, tool results, skills and errors. Server
|
|
209
|
+
text in scan results never starts a line of its own: every line of a message is
|
|
210
|
+
indented. JSON keeps successful response data, with the same characters escaped
|
|
211
|
+
as `\uXXXX`, so values stay lossless.
|
|
212
|
+
|
|
213
|
+
`vigilbase --version` and `vigilbase help` print the banner only in a terminal.
|
|
214
|
+
When stdout is a pipe or a file, `--version` prints only the version number and
|
|
215
|
+
help starts at `Usage:`, so `v=$(vigilbase --version)` works in scripts. With
|
|
216
|
+
`--json`, `--version` prints `{"name":"@vigilbase/cli","version":"…"}`. The
|
|
217
|
+
banner is plain text.
|
|
182
218
|
|
|
183
219
|
| Exit code | Meaning |
|
|
184
220
|
| --- | --- |
|
|
185
|
-
| `0` | Success (including a signed-out `whoami
|
|
186
|
-
| `1` | Validation, API, network or sign-in error, or
|
|
221
|
+
| `0` | Success (including a signed-out `whoami`, and a graded scan whatever its grade) |
|
|
222
|
+
| `1` | Validation, API, network or sign-in error, or a scan that failed or couldn't be assessed |
|
|
187
223
|
| `2` | Rate limited (`HTTP 429`) |
|
|
224
|
+
| `130`, `143`, `129` | `cloudflare-checkup` cancelled by Ctrl-C (SIGINT), SIGTERM or SIGHUP (128 + the signal number) |
|
|
188
225
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
226
|
+
A graded scan exits 0 even with an F. Its first line starts with `✓` only when
|
|
227
|
+
the result's `status` is `secure` and the grade isn't F; otherwise it starts
|
|
228
|
+
with `•`. Scripts should gate on `.grade` or `.result.status` in the JSON.
|
|
229
|
+
|
|
230
|
+
Errors keep a safe status, error code and retry delay. These codes come from
|
|
231
|
+
the CLI itself:
|
|
232
|
+
|
|
233
|
+
| Code | Meaning |
|
|
234
|
+
| --- | --- |
|
|
235
|
+
| `NOT_SIGNED_IN` | A command that needs Vigilbase One has no usable sign-in |
|
|
236
|
+
| `SIGN_IN_ENDED` | Vigilbase Identity ended the saved sign-in, and `identity-credentials.json` was removed |
|
|
237
|
+
| `SIGN_IN_UNSUPPORTED` | Signing in isn't supported on Windows yet |
|
|
238
|
+
| `UNKNOWN_OPTION` | An option the CLI doesn't know, with `Did you mean --x?` when one is close |
|
|
239
|
+
| `INVALID_ARGUMENT` | A missing or unexpected option value (`--timeout needs a value.`, `--json does not take a value.`), an invalid value, an unknown subcommand or a token that isn't valid |
|
|
240
|
+
| `UNEXPECTED_REDIRECT` | An origin answered with a redirect, which the CLI never follows |
|
|
241
|
+
| `BLOCKED_PORT` | Node's fetch refuses the port (see [Troubleshooting](#troubleshooting)) |
|
|
242
|
+
| `TIMEOUT` | A request took longer than `--timeout` |
|
|
243
|
+
|
|
244
|
+
Network failures otherwise carry Node's code (for example `ENOTFOUND` or
|
|
245
|
+
`ECONNREFUSED`), and `cloudflare-checkup` has codes of its own (LOCAL.md).
|
|
246
|
+
|
|
247
|
+
When a public scan fails and vigilbase.com explains why, the CLI shows that
|
|
248
|
+
reason: `Error: <message> (<code>)` in text, and `error` plus `code` in JSON.
|
|
249
|
+
The reason is shown only when vigilbase.com sends it as a known error code, and
|
|
250
|
+
it is cleaned to one line of at most 300 characters. Anything else, and every
|
|
194
251
|
Vigilbase One error, prints a message the CLI wrote (for example
|
|
195
252
|
`You don't have access to this.` or `Request failed (HTTP <status>).`), never
|
|
196
|
-
the server's text. The exception is a
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
253
|
+
the server's text. The exception is a scan the scanner couldn't assess (for
|
|
254
|
+
example a bot verification challenge), on the public API or through One: the
|
|
255
|
+
CLI prints `✗ <tool> · <target> · n/a` and the scanner's reason, cleaned the
|
|
256
|
+
same way (code `scan_unassessed`). Hints (`Hint: …`, `hint` in JSON) are always
|
|
257
|
+
written by the CLI; COMMANDS.md lists the One errors that get one.
|
|
200
258
|
|
|
201
259
|
Commands use named One APIs and One's own authorization. They never take
|
|
202
260
|
Cloudflare or other provider secrets, delegated identity claims or an arbitrary
|
|
@@ -229,12 +287,26 @@ command arguments can show up in process listings and shell history; neither
|
|
|
229
287
|
combines with `--token-stdin`. Login checks the token with One before saving
|
|
230
288
|
it.
|
|
231
289
|
|
|
290
|
+
A token must be one value of printable ASCII (no spaces or control
|
|
291
|
+
characters), at most 16 KiB, whether it comes from `--token-stdin`, `--token`
|
|
292
|
+
or `VIGILBASE_ONE_TOKEN`. Otherwise login stops before any request with
|
|
293
|
+
`The token must be a single value of printable ASCII characters.`,
|
|
294
|
+
`The token exceeds 16 KiB.` or `The token must not be empty.` (code
|
|
295
|
+
`INVALID_ARGUMENT`); an empty `VIGILBASE_ONE_TOKEN` counts as unset. If an Identity
|
|
296
|
+
sign-in saved with other `--auth-url`, `--one-url` or `--client-id` values
|
|
297
|
+
exists, a token login or a legacy device login stops before it sends the token
|
|
298
|
+
or asks for a device code:
|
|
299
|
+
`A saved Identity sign-in belongs to <issuer> for <One origin> (client ID <id>). Pass the matching --auth-url, --one-url and --client-id, or log out with them first.`
|
|
300
|
+
|
|
232
301
|
### Where credentials are stored
|
|
233
302
|
|
|
234
303
|
Credentials live in the config directory: `VIGILBASE_CONFIG_DIR` if set,
|
|
235
304
|
otherwise `$XDG_CONFIG_HOME/vigilbase`, otherwise `~/.config/vigilbase`.
|
|
236
305
|
`VIGILBASE_CONFIG_DIR` must be an absolute path; a relative `XDG_CONFIG_HOME`
|
|
237
|
-
is ignored.
|
|
306
|
+
is ignored. A set but empty `VIGILBASE_CONFIG_DIR` doesn't fall back: when the
|
|
307
|
+
credentials are needed it is an error
|
|
308
|
+
(`VIGILBASE_CONFIG_DIR is empty. Set it to an absolute path or unset it.`). If
|
|
309
|
+
`HOME` is relative and nothing else is set, the error names `HOME`.
|
|
238
310
|
|
|
239
311
|
| File | Holds |
|
|
240
312
|
| --- | --- |
|
|
@@ -289,6 +361,11 @@ that passes the [directory checks](#directory-checks) but can't be parsed.
|
|
|
289
361
|
warning, without being revoked; an unsafe file stops logout and stays in
|
|
290
362
|
place.
|
|
291
363
|
|
|
364
|
+
With nothing saved, logout creates no directories. `logout --json` prints
|
|
365
|
+
`{success, cleared, warnings}`: `warnings` lists the warnings text mode prints
|
|
366
|
+
on stderr (an unparseable file removed without revoking, a failed legacy
|
|
367
|
+
sign-out) and is `[]` when there are none.
|
|
368
|
+
|
|
292
369
|
Saved Identity credentials belong to one issuer, client and One. If you signed
|
|
293
370
|
in with `--auth-url`, `--one-url` or `--client-id`, log out with the same
|
|
294
371
|
options; otherwise logout stops, before revoking anything, with
|
|
@@ -298,35 +375,60 @@ options; otherwise logout stops, before revoking anything, with
|
|
|
298
375
|
|
|
299
376
|
Identity access tokens last five minutes. The CLI refreshes within 60 seconds
|
|
300
377
|
of expiry, or once after a 401. The lock coordinates CLI processes, and each
|
|
301
|
-
holder rereads the file before rotating the refresh token.
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
378
|
+
holder rereads the file before rotating the refresh token.
|
|
379
|
+
|
|
380
|
+
- A command waits up to 15 seconds (or `--timeout`, if shorter) for a lock
|
|
381
|
+
held by a running command, then stops with
|
|
382
|
+
``Credentials are locked by another vigilbase command (process <pid>). If none is running, delete <path> and run `vigilbase login`.``
|
|
383
|
+
- If the command holding the lock has exited (an interrupted refresh, for
|
|
384
|
+
example after Ctrl-C), other commands stop at once with
|
|
385
|
+
``A previous vigilbase command was interrupted while it held <path>. Run `vigilbase login` to recover.``
|
|
386
|
+
`login` and `logout` replace such a lock, but never one held by a running
|
|
387
|
+
command.
|
|
388
|
+
- An empty or unreadable lock stops with
|
|
389
|
+
``<path> is damaged. Stop every vigilbase command, delete it, and run `vigilbase login`.``
|
|
390
|
+
`login` and `logout` replace one older than 30 seconds.
|
|
391
|
+
- If a refresh request gets no answer (a timeout or a dropped connection),
|
|
392
|
+
Identity may have rotated the token already, so the first error says so:
|
|
393
|
+
``The Identity refresh may not have completed (…). Run `vigilbase login` again; its token cannot be retried safely.``
|
|
394
|
+
A definite refusal (a 4xx other than `invalid_grant`) leaves the refresh
|
|
395
|
+
retryable; a 5xx counts as uncertain.
|
|
396
|
+
- An `invalid_grant` answer (for example after a browser sign-out ended the
|
|
397
|
+
session) removes `identity-credentials.json`. The command then fails with
|
|
398
|
+
``Your saved sign-in was ended by Vigilbase Identity and has been removed. Run `vigilbase login` again.``
|
|
399
|
+
(code `SIGN_IN_ENDED`), while `whoami` reports you as signed out (exit 0).
|
|
400
|
+
|
|
401
|
+
Never reuse a refresh token by hand.
|
|
310
402
|
|
|
311
403
|
### Directory checks
|
|
312
404
|
|
|
313
|
-
Commands that read or write credentials (`login`, `logout`,
|
|
314
|
-
|
|
405
|
+
Commands that read or write credentials (`login`, `logout`, every One command,
|
|
406
|
+
`--via one` and the One-only scans, and `whoami` when credentials may be there)
|
|
407
|
+
check the whole config path first:
|
|
315
408
|
|
|
316
409
|
- no component of the path may be a symbolic link;
|
|
317
410
|
- every parent directory must be owned by you or root, and not writable by its
|
|
318
411
|
group or by others unless it has the sticky bit;
|
|
319
412
|
- the config directory must be owned by you with mode `0700`;
|
|
320
413
|
- credential files must be regular files owned by you, with one hard link and
|
|
321
|
-
mode `0600
|
|
414
|
+
mode `0600`;
|
|
415
|
+
- on macOS, the config directory and credential files must have no access
|
|
416
|
+
control list (the CLI removes inherited entries from what it creates), and no
|
|
417
|
+
parent may have an ACL entry that lets another user add, remove or replace
|
|
418
|
+
its entries.
|
|
322
419
|
|
|
323
420
|
Each error names the path that failed and how to fix it, for example:
|
|
324
421
|
|
|
325
422
|
```
|
|
326
423
|
Error: /tmp is a symbolic link. Set VIGILBASE_CONFIG_DIR to a private directory without symbolic links in its path.
|
|
327
424
|
Error: /Users/jane/.config/vigilbase must have mode 0700. Run chmod 700 /Users/jane/.config/vigilbase, or set VIGILBASE_CONFIG_DIR to another directory.
|
|
425
|
+
Error: /Users/jane/.config/vigilbase has an access control list. Run chmod -N /Users/jane/.config/vigilbase, or set VIGILBASE_CONFIG_DIR to another directory.
|
|
426
|
+
Error: /Users/jane/Shared is writable by other users through its access control list. Set VIGILBASE_CONFIG_DIR to a private directory without symbolic links in its path.
|
|
328
427
|
```
|
|
329
428
|
|
|
429
|
+
Paths with spaces, quotes or other special characters are shell-quoted in the
|
|
430
|
+
suggested commands.
|
|
431
|
+
|
|
330
432
|
On macOS `/tmp` and `/var` are symbolic links, and dotfiles managers often make
|
|
331
433
|
`~/.config` one. Fix the mode with the `chmod` the error names, or point
|
|
332
434
|
`VIGILBASE_CONFIG_DIR` at a private directory of its own, for example:
|
|
@@ -341,11 +443,12 @@ files hold your refresh token.
|
|
|
341
443
|
|
|
342
444
|
Public commands don't need these checks: public scans, `describe`, `skill` and
|
|
343
445
|
`badge` never open the config directory, and work even when
|
|
344
|
-
`VIGILBASE_CONFIG_DIR` isn't absolute. `list` and `
|
|
345
|
-
anything in a directory that fails them, and only treat it as a
|
|
346
|
-
credentials file may be there: `list` then shows you as signed
|
|
347
|
-
warning,
|
|
348
|
-
|
|
446
|
+
`VIGILBASE_CONFIG_DIR` isn't absolute. `list`, `doctor` and `whoami` never
|
|
447
|
+
create or open anything in a directory that fails them, and only treat it as a
|
|
448
|
+
problem when a credentials file may be there: `list` then shows you as signed
|
|
449
|
+
out with one warning, `doctor` reports it in its `signIn` check, and `whoami`
|
|
450
|
+
fails with the error. With no saved sign-in, `list` and `doctor` carry on as
|
|
451
|
+
usual and `whoami` reports you as signed out (exit 0).
|
|
349
452
|
|
|
350
453
|
### Windows
|
|
351
454
|
|
|
@@ -367,21 +470,32 @@ work and ignore any saved credentials.
|
|
|
367
470
|
| `--client-id <id>` | `VIGILBASE_CLIENT_ID` | `vigilbase-cli` |
|
|
368
471
|
| `--timeout <ms>` | — | `60000` per request |
|
|
369
472
|
|
|
370
|
-
Origins are HTTP(S) URLs without credentials, paths, queries or fragments
|
|
371
|
-
|
|
372
|
-
`127.0.0.0/8` or `[::1]`). This applies to
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
`
|
|
376
|
-
`
|
|
473
|
+
Origins are HTTP(S) URLs without credentials, paths, queries or fragments, and
|
|
474
|
+
need HTTPS; HTTP is allowed only for loopback development (`localhost`,
|
|
475
|
+
`127.0.0.0/8` or `[::1]`). This applies to `--base-url`, `--one-url` and
|
|
476
|
+
`--auth-url`. An empty flag value (`--base-url ""`) is an error; an empty
|
|
477
|
+
environment variable counts as unset. `VIGILBASE_API_URL` and
|
|
478
|
+
`VIGILBASE_PUBLIC_URL` are older names for the public origin, used after
|
|
479
|
+
`VIGILBASE_BASE_URL` when no flag is given; errors about the public origin name
|
|
480
|
+
the variable that held the bad value.
|
|
481
|
+
|
|
482
|
+
Commands check only the origins they use. Public scans, `list`, `describe`,
|
|
483
|
+
`skill` and `badge` ignore `--one-url`, `--auth-url` and their variables, and
|
|
484
|
+
One-only commands such as `whoami` ignore the public origin. `doctor` checks
|
|
485
|
+
both.
|
|
486
|
+
|
|
487
|
+
| Environment variable | Effect |
|
|
488
|
+
| --- | --- |
|
|
489
|
+
| `VIGILBASE_CLI_NO_OPEN=1` | Never open a browser |
|
|
490
|
+
| `VIGILBASE_CLI_NO_BANNER=1` | Hide the banner |
|
|
491
|
+
| `VIGILBASE_CLI_NO_PROGRESS=1` | Turn off progress animations |
|
|
377
492
|
|
|
378
493
|
**Identity issuer.** The CLI trusts one Identity issuer: `--auth-url` /
|
|
379
494
|
`VIGILBASE_AUTH_URL` when set, otherwise `https://auth.vigilbase.com`. The
|
|
380
495
|
issuer One names must be exactly that origin, or sign-in stops before any
|
|
381
|
-
request to it. `--auth-url` accepts `https://auth.vigilbase.com`,
|
|
382
|
-
`
|
|
383
|
-
|
|
384
|
-
credentials from another issuer count as signed out.
|
|
496
|
+
request to it. `--auth-url` accepts `https://auth.vigilbase.com`, or a loopback
|
|
497
|
+
origin (`localhost`, `127.0.0.0/8` or `[::1]`) when `--one-url` is loopback
|
|
498
|
+
too. Saved Identity credentials from another issuer count as signed out.
|
|
385
499
|
|
|
386
500
|
Billing portal URLs must use HTTPS on `billing.stripe.com`. Skill downloads are
|
|
387
501
|
limited to HTTPS `vigilbase.com/agent-skills/<name>.md` (or
|
|
@@ -404,9 +518,25 @@ three checks on their own and exits 1 if any fails:
|
|
|
404
518
|
- `signIn`: whether your saved sign-in works, including a refresh if one is
|
|
405
519
|
due.
|
|
406
520
|
|
|
407
|
-
DNS, TLS, connection and timeout failures name the endpoint and the cause.
|
|
408
|
-
|
|
409
|
-
|
|
521
|
+
DNS, TLS, connection and timeout failures name the endpoint and the cause. A
|
|
522
|
+
connection failure ends with the hint ``Run `vigilbase doctor` for connectivity checks.``,
|
|
523
|
+
which `doctor` itself doesn't print. Doctor's `--json` top level includes the
|
|
524
|
+
first failing check's `code`. Use `--base-url`, `--one-url`, `--auth-url` and
|
|
525
|
+
`--timeout` to check other environments.
|
|
526
|
+
|
|
527
|
+
**Redirects and blocked ports.** The CLI never follows redirects. An origin
|
|
528
|
+
that redirects fails with code `UNEXPECTED_REDIRECT`, naming the origin it
|
|
529
|
+
redirects to and the option to set (for example
|
|
530
|
+
`… redirected (HTTP 301) to https://www.example.com. Set --base-url to that origin.`).
|
|
531
|
+
Node's fetch refuses some ports (the Fetch standard's blocked ports, such as
|
|
532
|
+
6000 and 10080); they fail with code `BLOCKED_PORT`. Use another port.
|
|
533
|
+
|
|
534
|
+
**Proxies.** The CLI uses Node's built-in fetch, which ignores `HTTP_PROXY` and
|
|
535
|
+
`HTTPS_PROXY` unless `NODE_USE_ENV_PROXY=1` is set (Node 22.21+ or 24.5+; Node
|
|
536
|
+
prints an experimental warning). Skill documents (`skill`, `describe`) are
|
|
537
|
+
fetched directly, with DNS pinned to a checked public address, and never go
|
|
538
|
+
through a proxy: on a network that allows only proxied connections, `skill`
|
|
539
|
+
fails and `describe` shows no docs.
|
|
410
540
|
|
|
411
541
|
**`Unknown command "cloudflare-checkup"`.** An older global install (0.1.x)
|
|
412
542
|
takes priority over a bare `npx @vigilbase/cli`. Update it with
|
|
@@ -419,7 +549,11 @@ pnpm 11 and later skip releases published in the last 24 hours by default
|
|
|
419
549
|
(Yarn's `npmMinimalAgeGate`, pnpm's `minimumReleaseAge`). For a day after a
|
|
420
550
|
release, `yarn dlx @vigilbase/cli` and `pnpm dlx @vigilbase/cli` run an
|
|
421
551
|
older release, and Yarn refuses the new version by number
|
|
422
|
-
(`All versions satisfying "…" are quarantined`).
|
|
552
|
+
(`All versions satisfying "…" are quarantined`). pnpm 11 runs a pinned
|
|
553
|
+
version (`pnpm dlx @vigilbase/cli@<version>`). pnpm 10.16 and later apply
|
|
554
|
+
`minimumReleaseAge` only when you set it, and then refuse a pinned version
|
|
555
|
+
released within that time with `ERR_PNPM_NO_MATURE_MATCHING_VERSION`. Use
|
|
556
|
+
`npx @vigilbase/cli`, add `--config.minimum-release-age=0` to `pnpm dlx`, or
|
|
423
557
|
wait a day.
|
|
424
558
|
|
|
425
559
|
**`Device sign-in isn't available at <origin> right now.`** Login got a 404
|
|
@@ -432,6 +566,14 @@ in.
|
|
|
432
566
|
|
|
433
567
|
**`A previous refresh has an uncertain result.`** Run `vigilbase login` again.
|
|
434
568
|
|
|
569
|
+
**`A previous vigilbase command was interrupted while it held …` or
|
|
570
|
+
`… credentials.json.lock is damaged.`** Run `vigilbase login`, or delete the
|
|
571
|
+
file as the message says (see
|
|
572
|
+
[Refresh and the credentials lock](#refresh-and-the-credentials-lock)).
|
|
573
|
+
|
|
574
|
+
**`Your saved sign-in was ended by Vigilbase Identity and has been removed.`**
|
|
575
|
+
You signed out in the browser, or the session ended. Run `vigilbase login`.
|
|
576
|
+
|
|
435
577
|
**Certificates.** On Node 22.19+ and 24.5+ the CLI adds your operating
|
|
436
578
|
system's trusted certificates, keeping Node's bundled roots and
|
|
437
579
|
`NODE_EXTRA_CA_CERTS`. This covers private CAs trusted in the macOS Keychain or
|
|
@@ -445,8 +587,14 @@ NODE_OPTIONS="${NODE_OPTIONS:+$NODE_OPTIONS }--use-system-ca" vigilbase login
|
|
|
445
587
|
```
|
|
446
588
|
|
|
447
589
|
For a private CA outside the system store, set
|
|
448
|
-
`NODE_EXTRA_CA_CERTS=/path/to/trusted-ca.pem` before starting the CLI.
|
|
449
|
-
|
|
590
|
+
`NODE_EXTRA_CA_CERTS=/path/to/trusted-ca.pem` before starting the CLI. The
|
|
591
|
+
advice to use Node 22.19+ or 24.5+ appears in TLS errors only when the running
|
|
592
|
+
Node couldn't add the operating system's certificates.
|
|
593
|
+
|
|
594
|
+
The CLI never turns certificate checks off. `NODE_TLS_REJECT_UNAUTHORIZED=0`
|
|
595
|
+
does, for every request of the process, including those that carry your One
|
|
596
|
+
sign-in; Node then prints a warning. It is not supported: use
|
|
597
|
+
`NODE_EXTRA_CA_CERTS` instead.
|
|
450
598
|
|
|
451
599
|
**Timeouts.** Use `--timeout` for slower queries; some security analytics APIs
|
|
452
600
|
take longer than the default.
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/** Remove every entry from a path the CLI just created, so it doesn't keep one inherited from its parent. */
|
|
2
|
+
export declare function stripAcl(path: string): Promise<void>;
|
|
3
|
+
/** The ACL entries of each path, in order, like ` 0: group:everyone allow read`. Empty off darwin. */
|
|
4
|
+
export declare function aclEntries(paths: string[]): Promise<string[][]>;
|
|
5
|
+
/** Whether an entry lets someone other than the current user change the directory's entries. */
|
|
6
|
+
export declare function letsOthersChangeEntries(entry: string): boolean;
|
package/dist/auth/acl.js
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { execFile } from 'node:child_process';
|
|
2
|
+
import { userInfo } from 'node:os';
|
|
3
|
+
import { promisify } from 'node:util';
|
|
4
|
+
import { platform } from '../lib/platform.js';
|
|
5
|
+
/**
|
|
6
|
+
* macOS access control lists. An allow entry grants access whatever the mode bits say, and Node's stat can't see
|
|
7
|
+
* entries, so on darwin the credentials paths are checked with /bin/ls and cleaned with /bin/chmod. Other platforms
|
|
8
|
+
* have nothing to do: Linux's chmod 0600 masks a default POSIX ACL.
|
|
9
|
+
*/
|
|
10
|
+
const run = promisify(execFile);
|
|
11
|
+
/**
|
|
12
|
+
* Directory rights that let another user add, remove or replace an entry, remove the directory, or take over its ACL
|
|
13
|
+
* or ownership (and then grant themselves the rest). The boundaries keep writeattr and writeextattr from matching.
|
|
14
|
+
*/
|
|
15
|
+
const CHANGES_ENTRIES = /\b(?:add_file|add_subdirectory|delete_child|delete|write|append|writesecurity|chown)\b/;
|
|
16
|
+
/** Remove every entry from a path the CLI just created, so it doesn't keep one inherited from its parent. */
|
|
17
|
+
export async function stripAcl(path) {
|
|
18
|
+
if (platform() !== 'darwin')
|
|
19
|
+
return;
|
|
20
|
+
await run('/bin/chmod', ['-N', path]);
|
|
21
|
+
}
|
|
22
|
+
/** The ACL entries of each path, in order, like ` 0: group:everyone allow read`. Empty off darwin. */
|
|
23
|
+
export async function aclEntries(paths) {
|
|
24
|
+
if (platform() !== 'darwin' || !paths.length)
|
|
25
|
+
return paths.map(() => []);
|
|
26
|
+
// -q prints a newline in a name as ?, -f keeps the operands' order.
|
|
27
|
+
const { stdout } = await run('/bin/ls', ['-ledqf', '--', ...paths]);
|
|
28
|
+
const entries = [];
|
|
29
|
+
for (const line of stdout.split('\n')) {
|
|
30
|
+
if (/^\s*\d+: /.test(line))
|
|
31
|
+
entries.at(-1)?.push(line.trim());
|
|
32
|
+
else if (line)
|
|
33
|
+
entries.push([]);
|
|
34
|
+
}
|
|
35
|
+
if (entries.length !== paths.length)
|
|
36
|
+
throw new Error('Unexpected /bin/ls output.');
|
|
37
|
+
return entries;
|
|
38
|
+
}
|
|
39
|
+
/** Whether an entry lets someone other than the current user change the directory's entries. */
|
|
40
|
+
export function letsOthersChangeEntries(entry) {
|
|
41
|
+
const match = /^\d+: (.+?) (?:inherited )?(allow|deny) (\S+)/.exec(entry);
|
|
42
|
+
if (!match || match[2] !== 'allow' || !CHANGES_ENTRIES.test(match[3]))
|
|
43
|
+
return false;
|
|
44
|
+
return match[1] !== `user:${userInfo().username}`;
|
|
45
|
+
}
|
package/dist/auth/device-auth.js
CHANGED
|
@@ -34,6 +34,7 @@ async function postJson(config, path, body) {
|
|
|
34
34
|
const url = provider ? (path === '/device/code' ? provider.deviceEndpoint : provider.tokenEndpoint) : `${authBase(config)}${path}`;
|
|
35
35
|
const form = provider && path === '/device/token';
|
|
36
36
|
const { response, text } = await requestText(config, url, {
|
|
37
|
+
option: provider ? '--auth-url' : '--one-url',
|
|
37
38
|
method: 'POST',
|
|
38
39
|
headers: {
|
|
39
40
|
Accept: 'application/json',
|
package/dist/auth/provider.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { DeviceAuthError } from './device-auth.js';
|
|
2
2
|
import { z } from 'zod';
|
|
3
|
-
import { DEFAULT_IDENTITY_ISSUER, parseOrigin,
|
|
3
|
+
import { DEFAULT_IDENTITY_ISSUER, parseOrigin, trustedIdentityIssuer, validateOneOrigin } from '../lib/config.js';
|
|
4
4
|
import { requestText, parseJsonResponse } from '../lib/network.js';
|
|
5
5
|
/** An issuer (discovered from One, or saved with credentials) is trusted only when its origin is exactly trustedIdentityIssuer(config). */
|
|
6
6
|
export function validateIdentityIssuer(raw, config) {
|
|
@@ -17,9 +17,9 @@ export function validateIdentityIssuer(raw, config) {
|
|
|
17
17
|
return origin;
|
|
18
18
|
throw new Error(config.identityBaseUrl
|
|
19
19
|
? `Untrusted Identity issuer ${origin}: --auth-url / VIGILBASE_AUTH_URL is ${trusted}. Set it to the issuer for this One, or unset it to use ${DEFAULT_IDENTITY_ISSUER}.`
|
|
20
|
-
: `Untrusted Identity issuer ${origin}: only ${DEFAULT_IDENTITY_ISSUER} is trusted by default.
|
|
20
|
+
: `Untrusted Identity issuer ${origin}: only ${DEFAULT_IDENTITY_ISSUER} is trusted by default. To use another issuer, pass --auth-url <issuer> or set VIGILBASE_AUTH_URL.`);
|
|
21
21
|
}
|
|
22
|
-
async function json(config, url) { const { response, text } = await requestText(config, url, { headers: { Accept: 'application/json', 'User-Agent': config.userAgent } }); return { response, body: parseJsonResponse(response, text) }; }
|
|
22
|
+
async function json(config, url) { const { response, text } = await requestText(config, url, { option: '--auth-url', headers: { Accept: 'application/json', 'User-Agent': config.userAgent } }); return { response, body: parseJsonResponse(response, text) }; }
|
|
23
23
|
export async function identityProvider(config, issuer) {
|
|
24
24
|
issuer = validateIdentityIssuer(issuer, config);
|
|
25
25
|
const { response, body } = await json(config, `${issuer}/.well-known/openid-configuration`);
|
|
@@ -42,7 +42,7 @@ export async function identityProvider(config, issuer) {
|
|
|
42
42
|
*/
|
|
43
43
|
export async function discoverAuthProvider(config) {
|
|
44
44
|
const one = validateOneOrigin(config.oneBaseUrl);
|
|
45
|
-
const { response, text } = await requestText(config, `${one}/.well-known/oauth-protected-resource`, { headers: { Accept: 'application/json', 'User-Agent': config.userAgent }, redirect: 'manual' });
|
|
45
|
+
const { response, text } = await requestText(config, `${one}/.well-known/oauth-protected-resource`, { option: '--one-url', headers: { Accept: 'application/json', 'User-Agent': config.userAgent }, redirect: 'manual' });
|
|
46
46
|
if (response.type === 'opaqueredirect' || response.status === 0 || (response.status >= 300 && response.status < 400))
|
|
47
47
|
return undefined;
|
|
48
48
|
if (response.status === 404)
|
package/dist/auth/refresh.d.ts
CHANGED
|
@@ -3,14 +3,15 @@ import type { OneCredentials } from './types.js';
|
|
|
3
3
|
export declare function boundIdentityCredentials(config: CliConfig, one: OneCredentials): boolean;
|
|
4
4
|
/** Library callers may omit or mistype timeoutMs; NaN would make the wait unbounded. */
|
|
5
5
|
export declare function credentialsLockWaitMs(timeoutMs: unknown): number;
|
|
6
|
-
/**
|
|
6
|
+
/** credentials.json.lock is held: by a running command, by one that was interrupted, or it is damaged. */
|
|
7
7
|
export declare class CredentialsLockedError extends Error {
|
|
8
|
-
constructor();
|
|
8
|
+
constructor(message: string);
|
|
9
9
|
}
|
|
10
10
|
/**
|
|
11
11
|
* credentials.json.lock guards both credentials files; CLI 0.2.0 takes the same lock.
|
|
12
|
-
*
|
|
13
|
-
*
|
|
12
|
+
* Only login and logout (`replaceDeadLock`) replace a lock whose owner has exited, or an old damaged one: a crashed
|
|
13
|
+
* refresh may have consumed the rotating token, and both start over without it. Other commands fail at once on a
|
|
14
|
+
* dead owner. With `wait` false, a held lock fails at once instead of after the lock wait.
|
|
14
15
|
*/
|
|
15
16
|
export declare function withCredentialsLock<T>(config: Pick<CliConfig, 'configDir'> & Partial<Pick<CliConfig, 'timeoutMs'>>, callback: () => Promise<T>, replaceDeadLock?: boolean, wait?: boolean): Promise<T>;
|
|
16
17
|
export declare function managedAccessToken(config: CliConfig, failedToken?: string): Promise<string | null>;
|