@vigilbase/cli 0.2.2 → 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 +128 -42
- package/LOCAL.md +99 -38
- package/ONE.md +1 -1
- package/README.md +217 -66
- package/SECURITY.md +1 -1
- package/dist/auth/acl.d.ts +6 -0
- package/dist/auth/acl.js +45 -0
- package/dist/auth/device-auth.d.ts +3 -0
- package/dist/auth/device-auth.js +13 -3
- 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 +66 -35
- 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.d.ts +9 -0
- package/dist/lib/client.js +31 -2
- 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 +5 -1
- package/dist/lib/format.js +110 -35
- 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.d.ts +2 -0
- package/dist/lib/one-client.js +86 -12
- 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 +6 -1
- package/esm-only.cjs +3 -0
- package/package.json +7 -4
package/dist/lib/banner.js
CHANGED
|
@@ -2,11 +2,8 @@
|
|
|
2
2
|
* Compact Vigilbase flare mark + wordmark for human CLI surfaces.
|
|
3
3
|
* Static strings only — no I/O, no deps, skipped entirely in --json mode.
|
|
4
4
|
*/
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
* Left wing (full block) = terminal default fg; right wing (medium shade) = brand yellow.
|
|
8
|
-
*/
|
|
9
|
-
/** Compact flare used on help/version (keeps the first viewport short). */
|
|
5
|
+
import { isCi } from './platform.js';
|
|
6
|
+
/** Compact square Vigilbase flare (inverted V), used on help/version (keeps the first viewport short). */
|
|
10
7
|
export const VIGILBASE_ASCII_MARK = [
|
|
11
8
|
'\u2588\u2588\u2588\u2588\u2588 \u2592\u2592\u2592',
|
|
12
9
|
' \u2588\u2588\u2588\u2588 \u2592\u2592\u2592\u2592',
|
|
@@ -14,13 +11,7 @@ export const VIGILBASE_ASCII_MARK = [
|
|
|
14
11
|
' \u2588\u2592\u2592\u2592\u2592 ',
|
|
15
12
|
' \u2592\u2592\u2592 ',
|
|
16
13
|
].join('\n');
|
|
17
|
-
|
|
18
|
-
reset: '\u001b[0m',
|
|
19
|
-
dim: '\u001b[2m',
|
|
20
|
-
bold: '\u001b[1m',
|
|
21
|
-
/** Brand yellow (#f9e75e / #FFE74D family) — 256-color approximation. */
|
|
22
|
-
brand: '\u001b[38;5;221m',
|
|
23
|
-
};
|
|
14
|
+
/** Whether the checkup terminal UI (tui.ts) may colour this stream. */
|
|
24
15
|
export function shouldUseColor(stream, env = process.env) {
|
|
25
16
|
if (env.NO_COLOR != null && env.NO_COLOR !== '')
|
|
26
17
|
return false;
|
|
@@ -28,7 +19,7 @@ export function shouldUseColor(stream, env = process.env) {
|
|
|
28
19
|
return false;
|
|
29
20
|
if (env.FORCE_COLOR && env.FORCE_COLOR !== '0')
|
|
30
21
|
return true;
|
|
31
|
-
if (env
|
|
22
|
+
if (isCi(env))
|
|
32
23
|
return false;
|
|
33
24
|
return Boolean(stream?.isTTY);
|
|
34
25
|
}
|
|
@@ -39,29 +30,18 @@ export function shouldShowBanner(mode = 'text', env = process.env) {
|
|
|
39
30
|
return false;
|
|
40
31
|
return true;
|
|
41
32
|
}
|
|
42
|
-
function paintMarkLine(line, useColor) {
|
|
43
|
-
if (!useColor)
|
|
44
|
-
return line;
|
|
45
|
-
// Left wing stays terminal default fg; right wing is brand yellow.
|
|
46
|
-
return line.replace(/\u2592+/g, (run) => `${ANSI.brand}${run}${ANSI.reset}`);
|
|
47
|
-
}
|
|
48
33
|
/**
|
|
49
|
-
* Banner composition (flare + wordmark + tagline).
|
|
34
|
+
* Banner composition (flare + wordmark + tagline). Plain text: the writer strips terminal
|
|
35
|
+
* sequences from every line, so the banner carries no colour.
|
|
50
36
|
*/
|
|
51
|
-
export function renderBanner(options = {}
|
|
52
|
-
const useColor = options.useColor ?? shouldUseColor(stream, env);
|
|
37
|
+
export function renderBanner(options = {}) {
|
|
53
38
|
const tagline = options.tagline ?? 'one \u00b7 tools';
|
|
54
39
|
const version = options.version ? ` \u00b7 v${options.version}` : '';
|
|
55
|
-
|
|
56
|
-
const brand = (text) => useColor ? `${ANSI.brand}${ANSI.bold}${text}${ANSI.reset}` : text;
|
|
57
|
-
const dim = (text) => useColor ? `${ANSI.dim}${text}${ANSI.reset}` : text;
|
|
58
|
-
const painted = mark.map((line) => paintMarkLine(line, useColor));
|
|
59
|
-
const lines = painted.map((line, index) => {
|
|
40
|
+
return VIGILBASE_ASCII_MARK.split('\n').map((line, index) => {
|
|
60
41
|
if (index === 0)
|
|
61
|
-
return `${line}
|
|
42
|
+
return `${line} vigilbase`;
|
|
62
43
|
if (index === 1)
|
|
63
|
-
return `${line} ${
|
|
44
|
+
return `${line} ${tagline}${version}`;
|
|
64
45
|
return line;
|
|
65
|
-
});
|
|
66
|
-
return lines.join('\n');
|
|
46
|
+
}).join('\n');
|
|
67
47
|
}
|
package/dist/lib/client.d.ts
CHANGED
|
@@ -9,6 +9,13 @@ export declare class VigilbaseApiError extends Error {
|
|
|
9
9
|
readonly reason?: string;
|
|
10
10
|
/** CLI-authored remediation, never server text (see one-error-hints.ts). */
|
|
11
11
|
readonly hint?: string;
|
|
12
|
+
/**
|
|
13
|
+
* The message is the CLI's own text, never the server's, so formatError prints it although the
|
|
14
|
+
* error carries a body. Unmarked errors with a body print only a generic `Request failed`.
|
|
15
|
+
*/
|
|
16
|
+
readonly isCliAuthored: boolean;
|
|
17
|
+
/** The One tool run a failed scan recorded. */
|
|
18
|
+
readonly toolRunId?: string;
|
|
12
19
|
constructor(message: string, options: {
|
|
13
20
|
status: number;
|
|
14
21
|
body?: unknown;
|
|
@@ -16,6 +23,8 @@ export declare class VigilbaseApiError extends Error {
|
|
|
16
23
|
code?: string;
|
|
17
24
|
reason?: string;
|
|
18
25
|
hint?: string;
|
|
26
|
+
isCliAuthored?: boolean;
|
|
27
|
+
toolRunId?: string;
|
|
19
28
|
});
|
|
20
29
|
}
|
|
21
30
|
export declare function retryAfterSeconds(response: Response, body: unknown): number | undefined;
|
package/dist/lib/client.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import { singleLine } from './format.js';
|
|
2
|
+
import { SCAN_FAILED_MESSAGE, singleLine } from './format.js';
|
|
3
3
|
import { parseJsonResponse, requestText } from './network.js';
|
|
4
4
|
import { fetchSkillText } from './skill-fetch.js';
|
|
5
5
|
import { AGENT_API_ERROR_CODES, } from '../types.js';
|
|
@@ -12,6 +12,13 @@ export class VigilbaseApiError extends Error {
|
|
|
12
12
|
reason;
|
|
13
13
|
/** CLI-authored remediation, never server text (see one-error-hints.ts). */
|
|
14
14
|
hint;
|
|
15
|
+
/**
|
|
16
|
+
* The message is the CLI's own text, never the server's, so formatError prints it although the
|
|
17
|
+
* error carries a body. Unmarked errors with a body print only a generic `Request failed`.
|
|
18
|
+
*/
|
|
19
|
+
isCliAuthored;
|
|
20
|
+
/** The One tool run a failed scan recorded. */
|
|
21
|
+
toolRunId;
|
|
15
22
|
constructor(message, options) {
|
|
16
23
|
super(message);
|
|
17
24
|
this.name = 'VigilbaseApiError';
|
|
@@ -21,6 +28,8 @@ export class VigilbaseApiError extends Error {
|
|
|
21
28
|
this.code = options.code;
|
|
22
29
|
this.reason = options.reason;
|
|
23
30
|
this.hint = options.hint;
|
|
31
|
+
this.isCliAuthored = options.isCliAuthored ?? false;
|
|
32
|
+
this.toolRunId = options.toolRunId;
|
|
24
33
|
}
|
|
25
34
|
}
|
|
26
35
|
export function retryAfterSeconds(response, body) {
|
|
@@ -61,6 +70,7 @@ function problemReason(response, body) {
|
|
|
61
70
|
const message = singleLine(problem.data.error.message);
|
|
62
71
|
return message ? { code: code.data, message } : undefined;
|
|
63
72
|
}
|
|
73
|
+
/** `fallback` is the CLI's own message, used when com gave no reason it accepts. */
|
|
64
74
|
function publicApiError(fallback, response, body) {
|
|
65
75
|
const reason = problemReason(response, body);
|
|
66
76
|
return new VigilbaseApiError(reason?.message ?? fallback, {
|
|
@@ -69,8 +79,17 @@ function publicApiError(fallback, response, body) {
|
|
|
69
79
|
retryAfterSec: retryAfterSeconds(response, body),
|
|
70
80
|
code: reason?.code,
|
|
71
81
|
reason: reason?.message,
|
|
82
|
+
isCliAuthored: !reason,
|
|
72
83
|
});
|
|
73
84
|
}
|
|
85
|
+
const UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
86
|
+
/** com's 422 for a scan the scanner could not assess (apps/com/lib/agent/handlers.ts): it still carries the result. */
|
|
87
|
+
const unassessedScanSchema = z.object({
|
|
88
|
+
success: z.literal(false),
|
|
89
|
+
toolName: z.string(),
|
|
90
|
+
target: z.string(),
|
|
91
|
+
result: z.object({ status: z.literal('error') }).passthrough(),
|
|
92
|
+
});
|
|
74
93
|
/** The versioned public tools API. The unversioned /api/agent/tools aliases sunset on 2027-09-01. */
|
|
75
94
|
export const PUBLIC_TOOLS_PATH = '/api/v1/agent/tools';
|
|
76
95
|
/**
|
|
@@ -89,6 +108,7 @@ export class VigilbaseClient {
|
|
|
89
108
|
const url = `${this.origin}${path.startsWith('/') ? path : `/${path}`}`;
|
|
90
109
|
const { response, text } = await requestText(this.config, url, {
|
|
91
110
|
...init,
|
|
111
|
+
option: '--base-url',
|
|
92
112
|
headers: {
|
|
93
113
|
Accept: 'application/json',
|
|
94
114
|
'User-Agent': this.config.userAgent,
|
|
@@ -131,7 +151,16 @@ export class VigilbaseClient {
|
|
|
131
151
|
throw new VigilbaseApiError('Invalid tool execution response. Check the API URL or retry later.', { status: response.status });
|
|
132
152
|
}
|
|
133
153
|
if (!parsed.success) {
|
|
134
|
-
|
|
154
|
+
const unassessed = response.status === 422 ? unassessedScanSchema.safeParse(body) : null;
|
|
155
|
+
if (!unassessed?.success)
|
|
156
|
+
throw publicApiError(SCAN_FAILED_MESSAGE, response, body);
|
|
157
|
+
// A scan the scanner could not assess keeps its result, as One's route does.
|
|
158
|
+
const { toolName: name, target: scanned, result } = unassessed.data;
|
|
159
|
+
const toolRunId = typeof result.toolRunId === 'string' && UUID.test(result.toolRunId) ? result.toolRunId : undefined;
|
|
160
|
+
return {
|
|
161
|
+
success: false, toolName: name, target: scanned, grade: null, gradeScore: null, result,
|
|
162
|
+
error: null, status: 422, code: 'scan_unassessed', ...(toolRunId ? { toolRunId } : {}),
|
|
163
|
+
};
|
|
135
164
|
}
|
|
136
165
|
return parsed;
|
|
137
166
|
}
|
|
@@ -7,13 +7,13 @@ export declare const cloudflareScopeSchema: z.ZodObject<{
|
|
|
7
7
|
}, z.core.$strip>;
|
|
8
8
|
export type CloudflareScope = z.infer<typeof cloudflareScopeSchema>;
|
|
9
9
|
export declare const workspaceSectionSchema: z.ZodEnum<{
|
|
10
|
+
zones: "zones";
|
|
11
|
+
settings: "settings";
|
|
10
12
|
overview: "overview";
|
|
11
13
|
reports: "reports";
|
|
12
|
-
zones: "zones";
|
|
13
14
|
"rule-analyzer": "rule-analyzer";
|
|
14
15
|
accounts: "accounts";
|
|
15
16
|
checkups: "checkups";
|
|
16
|
-
settings: "settings";
|
|
17
17
|
}>;
|
|
18
18
|
export type WorkspaceSection = z.infer<typeof workspaceSectionSchema>;
|
|
19
19
|
export declare const accountResourceSchema: z.ZodEnum<{
|
package/dist/lib/config.d.ts
CHANGED
|
@@ -23,12 +23,15 @@ export type CliConfigLegacy = CliConfig & {
|
|
|
23
23
|
export declare function parseOrigin(raw: string, option: string): string;
|
|
24
24
|
/** Default request timeout; also used when library callers omit `timeoutMs`. */
|
|
25
25
|
export declare const DEFAULT_TIMEOUT_MS = 60000;
|
|
26
|
+
/** localhost, 127.0.0.0/8 or [::1]: the hosts every origin option accepts for local development. */
|
|
27
|
+
export declare function isLoopbackHostname(hostname: string): boolean;
|
|
26
28
|
export declare function resolvePublicBaseUrl(explicit?: string | null): string;
|
|
27
29
|
export declare function resolveOneBaseUrl(explicit?: string | null): string;
|
|
28
30
|
/** Validate at transport boundaries too: library callers may construct config objects. */
|
|
29
31
|
export declare function validateOneOrigin(raw: string): string;
|
|
30
32
|
/** Production Identity: the only issuer trusted unless --auth-url / VIGILBASE_AUTH_URL names another. */
|
|
31
33
|
export declare const DEFAULT_IDENTITY_ISSUER = "https://auth.vigilbase.com";
|
|
34
|
+
/** Internal: accepted when named explicitly, but not offered to users (it isn't deployed publicly). */
|
|
32
35
|
export declare const STAGING_IDENTITY_ISSUER = "https://identity-staging.vigilbase.com";
|
|
33
36
|
export declare function resolveIdentityBaseUrl(raw: string): string;
|
|
34
37
|
/**
|
|
@@ -38,6 +41,11 @@ export declare function resolveIdentityBaseUrl(raw: string): string;
|
|
|
38
41
|
*/
|
|
39
42
|
export declare function trustedIdentityIssuer(config: Pick<CliConfig, 'oneBaseUrl' | 'identityBaseUrl'>): string;
|
|
40
43
|
export declare function resolveClientId(explicit?: string | null): string;
|
|
44
|
+
/** Why a config directory that isn't absolute was refused, naming the variable it came from. */
|
|
45
|
+
export declare function relativeConfigDirProblem(configDir: string, env?: NodeJS.ProcessEnv): {
|
|
46
|
+
reason: string;
|
|
47
|
+
remedy: string;
|
|
48
|
+
};
|
|
41
49
|
/** The config directory, which must be absolute. */
|
|
42
50
|
export declare function resolveConfigDir(explicit?: string | null, env?: NodeJS.ProcessEnv): string;
|
|
43
51
|
export declare function createConfig(options?: {
|
|
@@ -48,6 +56,14 @@ export declare function createConfig(options?: {
|
|
|
48
56
|
identityBaseUrl?: string | null;
|
|
49
57
|
configDir?: string | null;
|
|
50
58
|
timeoutMs?: number;
|
|
59
|
+
/**
|
|
60
|
+
* Which origins to validate now; both by default. The CLI leaves out those a command never contacts, so a bad
|
|
61
|
+
* value for them cannot fail it. Every One and Identity transport validates its origin again at use.
|
|
62
|
+
*/
|
|
63
|
+
checkOrigins?: {
|
|
64
|
+
public: boolean;
|
|
65
|
+
one: boolean;
|
|
66
|
+
};
|
|
51
67
|
}): CliConfigLegacy;
|
|
52
68
|
/**
|
|
53
69
|
* Config for `vigilbase local …` and `vigilbase cloudflare-checkup`. Local
|
package/dist/lib/config.js
CHANGED
|
@@ -20,41 +20,63 @@ export function parseOrigin(raw, option) {
|
|
|
20
20
|
const timeoutSchema = z.number().int().min(1).max(2_147_483_647);
|
|
21
21
|
/** Default request timeout; also used when library callers omit `timeoutMs`. */
|
|
22
22
|
export const DEFAULT_TIMEOUT_MS = 60_000;
|
|
23
|
+
/** localhost, 127.0.0.0/8 or [::1]: the hosts every origin option accepts for local development. */
|
|
24
|
+
export function isLoopbackHostname(hostname) {
|
|
25
|
+
return hostname === 'localhost' || hostname === '[::1]' || /^127\.(?:\d{1,3}\.){2}\d{1,3}$/.test(hostname);
|
|
26
|
+
}
|
|
27
|
+
/** An option given as an empty string is a mistake (an unset shell variable), not a request for the default. */
|
|
28
|
+
function explicitValue(raw, option) {
|
|
29
|
+
if (raw === undefined || raw === null)
|
|
30
|
+
return undefined;
|
|
31
|
+
if (!raw.trim())
|
|
32
|
+
throw new Error(`${option} is empty. Pass an origin or leave the option out.`);
|
|
33
|
+
return raw.trim();
|
|
34
|
+
}
|
|
35
|
+
/** The first set value with the name it came from; blank variables count as unset. */
|
|
36
|
+
function firstSet(sources) {
|
|
37
|
+
for (const [name, value] of sources)
|
|
38
|
+
if (value?.trim())
|
|
39
|
+
return [name, value.trim()];
|
|
40
|
+
return undefined;
|
|
41
|
+
}
|
|
23
42
|
export function resolvePublicBaseUrl(explicit) {
|
|
24
|
-
const raw =
|
|
25
|
-
|
|
26
|
-
process.env.
|
|
27
|
-
process.env.
|
|
28
|
-
|
|
29
|
-
|
|
43
|
+
const [name, raw] = firstSet([
|
|
44
|
+
['--base-url', explicitValue(explicit, '--base-url')],
|
|
45
|
+
['VIGILBASE_BASE_URL', process.env.VIGILBASE_BASE_URL],
|
|
46
|
+
['VIGILBASE_API_URL', process.env.VIGILBASE_API_URL],
|
|
47
|
+
['VIGILBASE_PUBLIC_URL', process.env.VIGILBASE_PUBLIC_URL],
|
|
48
|
+
]) ?? ['--base-url', DEFAULT_PUBLIC_BASE_URL];
|
|
49
|
+
const origin = parseOrigin(raw, name);
|
|
50
|
+
const url = new URL(origin);
|
|
51
|
+
if (url.protocol !== 'https:' && !isLoopbackHostname(url.hostname)) {
|
|
52
|
+
throw new Error(`${name} requires HTTPS; HTTP is allowed only for loopback development.`);
|
|
53
|
+
}
|
|
54
|
+
return origin;
|
|
30
55
|
}
|
|
31
56
|
export function resolveOneBaseUrl(explicit) {
|
|
32
|
-
|
|
33
|
-
process.env.VIGILBASE_ONE_URL?.trim() ||
|
|
34
|
-
DEFAULT_ONE_BASE_URL;
|
|
35
|
-
return validateOneOrigin(raw);
|
|
57
|
+
return validateOneOrigin(explicitValue(explicit, '--one-url') || process.env.VIGILBASE_ONE_URL?.trim() || DEFAULT_ONE_BASE_URL);
|
|
36
58
|
}
|
|
37
59
|
/** Validate at transport boundaries too: library callers may construct config objects. */
|
|
38
60
|
export function validateOneOrigin(raw) {
|
|
39
61
|
const origin = parseOrigin(raw, '--one-url / VIGILBASE_ONE_URL');
|
|
40
62
|
const url = new URL(origin);
|
|
41
|
-
|
|
42
|
-
if (url.protocol !== 'https:' && !loopback) {
|
|
63
|
+
if (url.protocol !== 'https:' && !isLoopbackHostname(url.hostname)) {
|
|
43
64
|
throw new Error('--one-url / VIGILBASE_ONE_URL requires HTTPS; HTTP is allowed only for loopback development.');
|
|
44
65
|
}
|
|
45
66
|
return origin;
|
|
46
67
|
}
|
|
47
68
|
/** Production Identity: the only issuer trusted unless --auth-url / VIGILBASE_AUTH_URL names another. */
|
|
48
69
|
export const DEFAULT_IDENTITY_ISSUER = 'https://auth.vigilbase.com';
|
|
70
|
+
/** Internal: accepted when named explicitly, but not offered to users (it isn't deployed publicly). */
|
|
49
71
|
export const STAGING_IDENTITY_ISSUER = 'https://identity-staging.vigilbase.com';
|
|
50
72
|
const IDENTITY_OPTION = '--auth-url / VIGILBASE_AUTH_URL';
|
|
51
73
|
function isIdentityLoopback(origin) {
|
|
52
|
-
return
|
|
74
|
+
return isLoopbackHostname(new URL(origin).hostname);
|
|
53
75
|
}
|
|
54
76
|
export function resolveIdentityBaseUrl(raw) {
|
|
55
77
|
const origin = parseOrigin(raw, IDENTITY_OPTION);
|
|
56
78
|
if (origin !== DEFAULT_IDENTITY_ISSUER && origin !== STAGING_IDENTITY_ISSUER && !isIdentityLoopback(origin)) {
|
|
57
|
-
throw new Error(`${IDENTITY_OPTION} must be ${DEFAULT_IDENTITY_ISSUER}
|
|
79
|
+
throw new Error(`${IDENTITY_OPTION} must be ${DEFAULT_IDENTITY_ISSUER} or a loopback development origin.`);
|
|
58
80
|
}
|
|
59
81
|
return origin;
|
|
60
82
|
}
|
|
@@ -85,18 +107,54 @@ function configDirFromEnvironment(explicit, env) {
|
|
|
85
107
|
const custom = explicit?.trim() || env.VIGILBASE_CONFIG_DIR?.trim();
|
|
86
108
|
if (custom)
|
|
87
109
|
return custom;
|
|
110
|
+
// Set but blank: '' is not absolute, so the store rejects it rather than falling back to another directory.
|
|
111
|
+
if (env.VIGILBASE_CONFIG_DIR !== undefined)
|
|
112
|
+
return '';
|
|
88
113
|
const xdg = env.XDG_CONFIG_HOME?.trim();
|
|
89
114
|
return xdg && isAbsolute(xdg) ? join(xdg, 'vigilbase') : join(homedir(), '.config', 'vigilbase');
|
|
90
115
|
}
|
|
116
|
+
/** Why a config directory that isn't absolute was refused, naming the variable it came from. */
|
|
117
|
+
export function relativeConfigDirProblem(configDir, env = process.env) {
|
|
118
|
+
if (!configDir && env.VIGILBASE_CONFIG_DIR !== undefined) {
|
|
119
|
+
return { reason: 'VIGILBASE_CONFIG_DIR is empty', remedy: 'Set it to an absolute path or unset it.' };
|
|
120
|
+
}
|
|
121
|
+
if (env.VIGILBASE_CONFIG_DIR === undefined && !isAbsolute(homedir()) && configDir === join(homedir(), '.config', 'vigilbase')) {
|
|
122
|
+
const xdg = env.XDG_CONFIG_HOME?.trim() ? ', and a relative XDG_CONFIG_HOME is ignored' : '';
|
|
123
|
+
return { reason: `HOME (${homedir()}) is not an absolute path${xdg}`, remedy: 'Set HOME or VIGILBASE_CONFIG_DIR to an absolute path.' };
|
|
124
|
+
}
|
|
125
|
+
return { reason: `${configDir} is not an absolute path`, remedy: 'Set VIGILBASE_CONFIG_DIR to an absolute path.' };
|
|
126
|
+
}
|
|
91
127
|
/** The config directory, which must be absolute. */
|
|
92
128
|
export function resolveConfigDir(explicit, env = process.env) {
|
|
93
129
|
const configDir = configDirFromEnvironment(explicit, env);
|
|
94
|
-
if (!isAbsolute(configDir))
|
|
95
|
-
|
|
130
|
+
if (!isAbsolute(configDir)) {
|
|
131
|
+
const { reason, remedy } = relativeConfigDirProblem(configDir, env);
|
|
132
|
+
throw new Error(`${reason}. ${remedy}`);
|
|
133
|
+
}
|
|
96
134
|
return configDir;
|
|
97
135
|
}
|
|
136
|
+
/** The origin when it is valid, otherwise the value as given: left for the transport that uses it to reject. */
|
|
137
|
+
function checkedLater(resolve, raw) {
|
|
138
|
+
try {
|
|
139
|
+
return resolve();
|
|
140
|
+
}
|
|
141
|
+
catch {
|
|
142
|
+
return raw;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
98
145
|
export function createConfig(options) {
|
|
99
|
-
const
|
|
146
|
+
const checks = options?.checkOrigins ?? { public: true, one: true };
|
|
147
|
+
const explicitPublic = options?.publicBaseUrl ?? options?.baseUrl;
|
|
148
|
+
const publicBaseUrl = checks.public
|
|
149
|
+
? resolvePublicBaseUrl(explicitPublic)
|
|
150
|
+
: checkedLater(() => resolvePublicBaseUrl(explicitPublic), explicitPublic?.trim() || process.env.VIGILBASE_BASE_URL?.trim() ||
|
|
151
|
+
process.env.VIGILBASE_API_URL?.trim() || process.env.VIGILBASE_PUBLIC_URL?.trim() || DEFAULT_PUBLIC_BASE_URL);
|
|
152
|
+
const oneBaseUrl = checks.one
|
|
153
|
+
? resolveOneBaseUrl(options?.oneBaseUrl)
|
|
154
|
+
: checkedLater(() => resolveOneBaseUrl(options?.oneBaseUrl), options?.oneBaseUrl?.trim() || process.env.VIGILBASE_ONE_URL?.trim() || DEFAULT_ONE_BASE_URL);
|
|
155
|
+
const authUrl = checks.one
|
|
156
|
+
? explicitValue(options?.identityBaseUrl, '--auth-url') || process.env.VIGILBASE_AUTH_URL?.trim()
|
|
157
|
+
: options?.identityBaseUrl?.trim() || process.env.VIGILBASE_AUTH_URL?.trim();
|
|
100
158
|
const timeoutMs = options?.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
101
159
|
if (!timeoutSchema.safeParse(timeoutMs).success) {
|
|
102
160
|
throw new Error('Request timeout must be an integer between 1 and 2147483647 milliseconds.');
|
|
@@ -105,8 +163,8 @@ export function createConfig(options) {
|
|
|
105
163
|
publicBaseUrl,
|
|
106
164
|
/** Alias used by the current public tools client. */
|
|
107
165
|
baseUrl: publicBaseUrl,
|
|
108
|
-
oneBaseUrl
|
|
109
|
-
...(
|
|
166
|
+
oneBaseUrl,
|
|
167
|
+
...(authUrl ? { identityBaseUrl: checks.one ? resolveIdentityBaseUrl(authUrl) : checkedLater(() => resolveIdentityBaseUrl(authUrl), authUrl) } : {}),
|
|
110
168
|
clientId: resolveClientId(options?.clientId),
|
|
111
169
|
configDir: configDirFromEnvironment(options?.configDir, process.env),
|
|
112
170
|
userAgent: `@vigilbase/cli/${CLI_VERSION} (+https://vigilbase.com; node/${process.version})`,
|
package/dist/lib/format.d.ts
CHANGED
|
@@ -3,7 +3,9 @@ export type Writer = {
|
|
|
3
3
|
stdout: (line?: string) => void;
|
|
4
4
|
stderr: (line?: string) => void;
|
|
5
5
|
};
|
|
6
|
-
/**
|
|
6
|
+
/** A scan that ended without a result: com's copy (apps/com/lib/tools/execute-internal-scan.ts). */
|
|
7
|
+
export declare const SCAN_FAILED_MESSAGE = "The scan couldn't be completed. Try again later.";
|
|
8
|
+
/** Untrusted API data must never become terminal control sequences, bidi overrides or invisible text. */
|
|
7
9
|
export declare function sanitizeTerminal(value: string): string;
|
|
8
10
|
/** One sanitised line, cut to `maxLength` characters with an ellipsis. */
|
|
9
11
|
export declare function singleLine(value: string, maxLength?: number): string;
|
|
@@ -16,5 +18,7 @@ export declare function formatToolsList(catalog: AgentToolsCatalogResponse, mode
|
|
|
16
18
|
isAuthenticated?: boolean;
|
|
17
19
|
}): void;
|
|
18
20
|
export declare function formatToolDescription(tool: AgentToolDefinition, mode: CliOutputMode, writer: Writer, skillMarkdown?: string): void;
|
|
21
|
+
/** Whether a scan produced a result; the exit code follows it. */
|
|
22
|
+
export declare function isSuccessfulScan(result: AgentToolExecuteResponse): boolean;
|
|
19
23
|
export declare function formatExecuteResult(result: AgentToolExecuteResponse, mode: CliOutputMode, writer: Writer): void;
|
|
20
24
|
export declare function formatError(error: unknown, mode: CliOutputMode, writer: Writer): void;
|