sfscanner 0.0.0-stage → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +131 -3
- package/THIRD_PARTY_NOTICES.md +48 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +10766 -0
- package/dist/index.js.map +7 -0
- package/dist/main.js +11941 -0
- package/dist/main.js.map +7 -0
- package/dist/mcp.js +10468 -0
- package/dist/mcp.js.map +7 -0
- package/dist/scan-worker.js +11800 -0
- package/dist/scan-worker.js.map +7 -0
- package/dist/v2/arguments.d.ts +87 -0
- package/dist/v2/arguments.js +403 -0
- package/dist/v2/arguments.js.map +7 -0
- package/dist/v2/atomic-output.d.ts +34 -0
- package/dist/v2/batch-runner.d.ts +50 -0
- package/dist/v2/cli-runner-internal.d.ts +28 -0
- package/dist/v2/cli-runner.d.ts +22 -0
- package/dist/v2/cli-runner.js +10037 -0
- package/dist/v2/cli-runner.js.map +7 -0
- package/dist/v2/commands.d.ts +155 -0
- package/dist/v2/config.d.ts +16 -0
- package/dist/v2/contracts.d.ts +97 -0
- package/dist/v2/exit-reducer.d.ts +23 -0
- package/dist/v2/help.d.ts +33 -0
- package/dist/v2/help.js +325 -0
- package/dist/v2/help.js.map +7 -0
- package/dist/v2/input-read.d.ts +26 -0
- package/dist/v2/input-selection.d.ts +38 -0
- package/dist/v2/json-output.d.ts +97 -0
- package/dist/v2/metadata-output.d.ts +37 -0
- package/dist/v2/metadata-output.js +7523 -0
- package/dist/v2/metadata-output.js.map +7 -0
- package/dist/v2/metadata-validation.d.ts +4 -0
- package/dist/v2/ndjson-output.d.ts +3 -0
- package/dist/v2/path-admission.d.ts +8 -0
- package/dist/v2/scan-config-load.d.ts +21 -0
- package/dist/v2/scan-worker-host.d.ts +29 -0
- package/dist/v2/table-output.d.ts +2 -0
- package/dist/v2/worker-host.d.ts +24 -0
- package/package.json +74 -6
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import type { CliCommandV2 } from './arguments.js';
|
|
2
|
+
type CliSeverityV2 = 'CRITICAL' | 'HIGH' | 'MEDIUM' | 'LOW' | 'INFO';
|
|
3
|
+
type CliConfidenceV2 = 'LOW' | 'MEDIUM' | 'HIGH';
|
|
4
|
+
export type CliRuleSummaryV2 = Readonly<{
|
|
5
|
+
ruleId: string;
|
|
6
|
+
revision: string;
|
|
7
|
+
effect: 'SCORING' | 'REPORT_ONLY';
|
|
8
|
+
severity: CliSeverityV2;
|
|
9
|
+
confidence: CliConfidenceV2;
|
|
10
|
+
capabilityId: string;
|
|
11
|
+
evidenceSchemaId: string;
|
|
12
|
+
remediationId: string;
|
|
13
|
+
cweIds: readonly string[];
|
|
14
|
+
owaspAgenticIds: readonly string[];
|
|
15
|
+
}>;
|
|
16
|
+
export type CliArtifactIdentityV2 = Readonly<{
|
|
17
|
+
profile: {
|
|
18
|
+
id: string;
|
|
19
|
+
version: string;
|
|
20
|
+
};
|
|
21
|
+
ruleset: {
|
|
22
|
+
id: string;
|
|
23
|
+
version: string;
|
|
24
|
+
digest: string;
|
|
25
|
+
signatureStatus: 'VERIFIED' | 'UNVERIFIED';
|
|
26
|
+
};
|
|
27
|
+
semantics: {
|
|
28
|
+
id: string;
|
|
29
|
+
version: string;
|
|
30
|
+
digest: string;
|
|
31
|
+
};
|
|
32
|
+
target: {
|
|
33
|
+
edition: 'UNKNOWN';
|
|
34
|
+
deployment: 'UNKNOWN';
|
|
35
|
+
role: 'UNKNOWN';
|
|
36
|
+
taskRunner: 'UNKNOWN';
|
|
37
|
+
communityPackages: readonly never[];
|
|
38
|
+
configuration: readonly never[];
|
|
39
|
+
contextDigest: string;
|
|
40
|
+
};
|
|
41
|
+
limits: {
|
|
42
|
+
schemaVersion: 'scanner-limits-v2';
|
|
43
|
+
digest: string;
|
|
44
|
+
};
|
|
45
|
+
}>;
|
|
46
|
+
export type CliRulesDocumentV2 = Readonly<{
|
|
47
|
+
schemaVersion: 'n8n-scan-rules-v2';
|
|
48
|
+
tool: ToolV2;
|
|
49
|
+
artifacts: CliArtifactIdentityV2;
|
|
50
|
+
rules: readonly CliRuleSummaryV2[];
|
|
51
|
+
}>;
|
|
52
|
+
export type CliExplainDocumentV2 = Readonly<{
|
|
53
|
+
schemaVersion: 'n8n-scan-explain-v2';
|
|
54
|
+
tool: ToolV2;
|
|
55
|
+
artifacts: CliArtifactIdentityV2;
|
|
56
|
+
rule: CliRuleSummaryV2;
|
|
57
|
+
prose: ProseV2;
|
|
58
|
+
evidenceProperties: readonly string[];
|
|
59
|
+
provenance: {
|
|
60
|
+
packDigest: string;
|
|
61
|
+
semanticsDigest: string;
|
|
62
|
+
};
|
|
63
|
+
}>;
|
|
64
|
+
export type CliProfileSummaryV2 = Readonly<{
|
|
65
|
+
id: string;
|
|
66
|
+
version: string;
|
|
67
|
+
admitted: boolean;
|
|
68
|
+
advertised: boolean;
|
|
69
|
+
digest: string;
|
|
70
|
+
scoringPolicyVersion: string;
|
|
71
|
+
capabilities: readonly CapabilityV2[];
|
|
72
|
+
}>;
|
|
73
|
+
export type CliProfilesDocumentV2 = Readonly<{
|
|
74
|
+
schemaVersion: 'n8n-scan-profiles-v2';
|
|
75
|
+
tool: ToolV2;
|
|
76
|
+
profiles: readonly CliProfileSummaryV2[];
|
|
77
|
+
}>;
|
|
78
|
+
export type CliVersionDocumentV2 = Readonly<{
|
|
79
|
+
schemaVersion: 'n8n-scan-version-v2';
|
|
80
|
+
name: 'n8n-scan';
|
|
81
|
+
cliVersion: string;
|
|
82
|
+
engine: {
|
|
83
|
+
id: 'secureflow-scanner';
|
|
84
|
+
version: '2.0.0';
|
|
85
|
+
buildDigest: string;
|
|
86
|
+
};
|
|
87
|
+
resultSchemas: readonly ['scanner-result-v1', 'scanner-result-v2'];
|
|
88
|
+
configSchema: 'n8n-scan-config-v2';
|
|
89
|
+
rulesetDigest: string;
|
|
90
|
+
semanticsDigest: string;
|
|
91
|
+
trustStoreDigest: string;
|
|
92
|
+
mode: 'offline';
|
|
93
|
+
}>;
|
|
94
|
+
export type CliConfigValidationDocumentV2 = Readonly<{
|
|
95
|
+
schemaVersion: 'n8n-scan-config-validation-v2';
|
|
96
|
+
valid: true;
|
|
97
|
+
artifacts: CliArtifactIdentityV2;
|
|
98
|
+
}>;
|
|
99
|
+
export type CliMetadataDocumentV2 = CliRulesDocumentV2 | CliExplainDocumentV2 | CliProfilesDocumentV2 | CliVersionDocumentV2 | CliConfigValidationDocumentV2;
|
|
100
|
+
export type CliCommandResultV2 = Readonly<{
|
|
101
|
+
ok: true;
|
|
102
|
+
document: CliMetadataDocumentV2;
|
|
103
|
+
} | {
|
|
104
|
+
ok: true;
|
|
105
|
+
command: Extract<CliCommandV2, {
|
|
106
|
+
kind: 'scan';
|
|
107
|
+
}>;
|
|
108
|
+
} | {
|
|
109
|
+
ok: false;
|
|
110
|
+
code: 'USAGE';
|
|
111
|
+
message: string;
|
|
112
|
+
}>;
|
|
113
|
+
type ToolV2 = Readonly<{
|
|
114
|
+
name: 'n8n-scan';
|
|
115
|
+
version: string;
|
|
116
|
+
buildDigest: string;
|
|
117
|
+
}>;
|
|
118
|
+
type ProseV2 = Readonly<{
|
|
119
|
+
title: string;
|
|
120
|
+
message: string;
|
|
121
|
+
explanation: string;
|
|
122
|
+
whyItMatters: string;
|
|
123
|
+
possibleImpact: string;
|
|
124
|
+
remediation: string;
|
|
125
|
+
remediationSteps: readonly string[];
|
|
126
|
+
}>;
|
|
127
|
+
type CapabilityV2 = Readonly<{
|
|
128
|
+
id: string;
|
|
129
|
+
version: string;
|
|
130
|
+
required: boolean;
|
|
131
|
+
dependsOn: readonly string[];
|
|
132
|
+
ruleIds: readonly string[];
|
|
133
|
+
}>;
|
|
134
|
+
export declare function rulesDocumentV2(): CliRulesDocumentV2;
|
|
135
|
+
export declare function explainDocumentV2(ruleId: string): Readonly<{
|
|
136
|
+
ok: true;
|
|
137
|
+
document: CliExplainDocumentV2;
|
|
138
|
+
} | {
|
|
139
|
+
ok: false;
|
|
140
|
+
code: 'USAGE';
|
|
141
|
+
message: string;
|
|
142
|
+
}>;
|
|
143
|
+
export declare function profilesDocumentV2(): CliProfilesDocumentV2;
|
|
144
|
+
export declare function versionDocumentV2(): CliVersionDocumentV2;
|
|
145
|
+
export declare function validateConfigDocumentV2(input: unknown, configDirectory?: string): Readonly<{
|
|
146
|
+
ok: true;
|
|
147
|
+
document: CliConfigValidationDocumentV2;
|
|
148
|
+
} | {
|
|
149
|
+
ok: false;
|
|
150
|
+
code: 'USAGE';
|
|
151
|
+
message: string;
|
|
152
|
+
}>;
|
|
153
|
+
export declare function isAdmittedConfigPathV2(path: unknown): path is string;
|
|
154
|
+
export declare function runCommandV2(command: CliCommandV2, configInput?: unknown, configDirectory?: string): CliCommandResultV2;
|
|
155
|
+
export {};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type ScanConfigV2 } from './contracts';
|
|
2
|
+
export type ConfigLoadOptions = Readonly<{
|
|
3
|
+
configDirectory?: string;
|
|
4
|
+
cli?: unknown;
|
|
5
|
+
}>;
|
|
6
|
+
export type ConfigLoadResult = Readonly<{
|
|
7
|
+
ok: true;
|
|
8
|
+
config: ScanConfigV2;
|
|
9
|
+
} | {
|
|
10
|
+
ok: false;
|
|
11
|
+
code: 'INVALID_CONFIG';
|
|
12
|
+
errors: readonly string[];
|
|
13
|
+
}>;
|
|
14
|
+
export declare function loadExplicitConfig(input: unknown, options?: ConfigLoadOptions): ConfigLoadResult;
|
|
15
|
+
export declare function validateScanConfigV2(input: unknown): ConfigLoadResult;
|
|
16
|
+
export { ADMITTED_PROFILE_V2, BUILTIN_AUTHORITIES_V2, BUILTIN_LIMITS_AUTHORITY_V2, BUILTIN_RULESET_AUTHORITY_V2, BUILTIN_SEMANTICS_AUTHORITY_V2, CLI_TOOL_V2, DEFAULT_SCAN_CONFIG_V2, PROFILE_MANIFEST_DIGEST_V2, RULE_PACK_DIGEST_V2, SCAN_CONFIG_SCHEMA_V2, SEMANTIC_CATALOGUE_DIGEST_V2, type ScanConfigV2, } from './contracts';
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
export declare const SCAN_CONFIG_SCHEMA_V2: "n8n-scan-config-v2";
|
|
2
|
+
export type ScanFormatV2 = 'json' | 'ndjson' | 'sarif' | 'table';
|
|
3
|
+
export type ScanSeverityV2 = 'CRITICAL' | 'HIGH' | 'MEDIUM' | 'LOW' | 'INFO';
|
|
4
|
+
export type ScanConfigV2 = Readonly<{
|
|
5
|
+
schemaVersion: typeof SCAN_CONFIG_SCHEMA_V2;
|
|
6
|
+
format?: ScanFormatV2;
|
|
7
|
+
profile?: string;
|
|
8
|
+
output?: string;
|
|
9
|
+
inputs?: readonly string[];
|
|
10
|
+
configPath?: string;
|
|
11
|
+
failOn?: ScanSeverityV2;
|
|
12
|
+
requireComplete?: boolean;
|
|
13
|
+
concurrency?: number;
|
|
14
|
+
rules?: string;
|
|
15
|
+
catalogue?: string;
|
|
16
|
+
limits?: string;
|
|
17
|
+
target?: string;
|
|
18
|
+
include?: readonly string[];
|
|
19
|
+
exclude?: readonly string[];
|
|
20
|
+
approvedDomains?: readonly string[];
|
|
21
|
+
allowUnsignedDevelopmentRules?: boolean;
|
|
22
|
+
noColor?: boolean;
|
|
23
|
+
}>;
|
|
24
|
+
export declare const ADMITTED_PROFILE_V2: Readonly<{
|
|
25
|
+
id: "beta-default";
|
|
26
|
+
version: "2.0.0";
|
|
27
|
+
digest: "3ca5d69db2554383e22c44afe507cc98e381ea58a7e42aaac0ee8f7497fb4f44";
|
|
28
|
+
}>;
|
|
29
|
+
/**
|
|
30
|
+
* The profile spellings a caller may write, and the one place they are listed. Both the
|
|
31
|
+
* config loader and the MCP tool read this, so a profile cannot be admitted on one
|
|
32
|
+
* surface and refused on the other; the bare id and its `id@version` pin are the same
|
|
33
|
+
* admission, and both canonicalize to `ADMITTED_PROFILE_V2.id`.
|
|
34
|
+
*/
|
|
35
|
+
export declare const ADMITTED_PROFILE_SPECIFIERS_V2: readonly string[];
|
|
36
|
+
export declare function isAdmittedProfileSpecifierV2(value: unknown): value is string;
|
|
37
|
+
export declare const BUILTIN_AUTHORITIES_V2: Readonly<{
|
|
38
|
+
profile: Readonly<{
|
|
39
|
+
id: "beta-default";
|
|
40
|
+
version: "2.0.0";
|
|
41
|
+
digest: "3ca5d69db2554383e22c44afe507cc98e381ea58a7e42aaac0ee8f7497fb4f44";
|
|
42
|
+
}>;
|
|
43
|
+
rules: Readonly<{
|
|
44
|
+
id: "scanner-core-builtins";
|
|
45
|
+
version: "2.0.0";
|
|
46
|
+
digest: "a36d00564bbf8e8c38f05820480782cdc53fdbd3712558850066c4e3f5c3413d";
|
|
47
|
+
signatureStatus: "VERIFIED";
|
|
48
|
+
}>;
|
|
49
|
+
semantics: Readonly<{
|
|
50
|
+
id: "scanner-core-builtins";
|
|
51
|
+
version: "2.2.0";
|
|
52
|
+
digest: "bc6fdecc34e460b5b01973ef7a8ce06b27b9b100ae03b480110f11f2a63ac328";
|
|
53
|
+
}>;
|
|
54
|
+
limits: Readonly<{
|
|
55
|
+
schemaVersion: "scanner-limits-v2";
|
|
56
|
+
digest: "fca787753ca88f71cf0d174427f4ac730a7aef1c823aaf73aa1ea72af92b4077";
|
|
57
|
+
}>;
|
|
58
|
+
}>;
|
|
59
|
+
export declare const PROFILE_MANIFEST_DIGEST_V2: "3ca5d69db2554383e22c44afe507cc98e381ea58a7e42aaac0ee8f7497fb4f44";
|
|
60
|
+
export declare const BUILTIN_RULESET_AUTHORITY_V2: Readonly<{
|
|
61
|
+
id: "scanner-core-builtins";
|
|
62
|
+
version: "2.0.0";
|
|
63
|
+
digest: "a36d00564bbf8e8c38f05820480782cdc53fdbd3712558850066c4e3f5c3413d";
|
|
64
|
+
signatureStatus: "VERIFIED";
|
|
65
|
+
}>;
|
|
66
|
+
export declare const BUILTIN_SEMANTICS_AUTHORITY_V2: Readonly<{
|
|
67
|
+
id: "scanner-core-builtins";
|
|
68
|
+
version: "2.2.0";
|
|
69
|
+
digest: "bc6fdecc34e460b5b01973ef7a8ce06b27b9b100ae03b480110f11f2a63ac328";
|
|
70
|
+
}>;
|
|
71
|
+
export declare const BUILTIN_LIMITS_AUTHORITY_V2: Readonly<{
|
|
72
|
+
schemaVersion: "scanner-limits-v2";
|
|
73
|
+
digest: "fca787753ca88f71cf0d174427f4ac730a7aef1c823aaf73aa1ea72af92b4077";
|
|
74
|
+
}>;
|
|
75
|
+
export declare const RULE_PACK_DIGEST_V2: "a36d00564bbf8e8c38f05820480782cdc53fdbd3712558850066c4e3f5c3413d";
|
|
76
|
+
export declare const SEMANTIC_CATALOGUE_DIGEST_V2: "bc6fdecc34e460b5b01973ef7a8ce06b27b9b100ae03b480110f11f2a63ac328";
|
|
77
|
+
/**
|
|
78
|
+
* One tool identity for every machine surface: the JSON/NDJSON scan envelopes and the
|
|
79
|
+
* rules/explain/profiles metadata documents. The digest folds the admitted engine, profile,
|
|
80
|
+
* ruleset, and semantics authorities, so a re-pin moves every surface together instead of
|
|
81
|
+
* leaving a frozen literal behind on one of them.
|
|
82
|
+
*/
|
|
83
|
+
export declare const CLI_VERSION_V2: "0.1.0";
|
|
84
|
+
export type CliToolIdentityV2 = Readonly<{
|
|
85
|
+
name: 'n8n-scan';
|
|
86
|
+
version: string;
|
|
87
|
+
buildDigest: string;
|
|
88
|
+
}>;
|
|
89
|
+
export declare const CLI_TOOL_V2: CliToolIdentityV2;
|
|
90
|
+
export declare const DEFAULT_SCAN_CONFIG_V2: ScanConfigV2;
|
|
91
|
+
export declare const SCAN_CONFIG_V2_FIELDS: readonly ["schemaVersion", "format", "profile", "output", "inputs", "configPath", "failOn", "requireComplete", "concurrency", "rules", "catalogue", "limits", "target", "include", "exclude", "approvedDomains", "allowUnsignedDevelopmentRules", "noColor"];
|
|
92
|
+
export declare const SCAN_CONFIG_V2_MAX_STRING = 4096;
|
|
93
|
+
export declare const SCAN_CONFIG_V2_MAX_PATTERNS = 1024;
|
|
94
|
+
export declare const SCAN_CONFIG_V2_MAX_CONCURRENCY = 16;
|
|
95
|
+
export declare const SCAN_CONFIG_V2_MAX_DOMAINS = 1000;
|
|
96
|
+
export declare const DOMAIN_V2: RegExp;
|
|
97
|
+
export declare function isApprovedDomainV2(value: unknown): value is string;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { BatchResultV2 } from './batch-runner';
|
|
2
|
+
import type { ScanSeverityV2 } from './contracts';
|
|
3
|
+
export type ExitReasonV2 = 'UNDER_THRESHOLD' | 'FINDING_THRESHOLD' | 'REQUIRE_COMPLETE' | 'ITEM_FAILURE' | 'USAGE' | 'INTERNAL' | 'CANCELLED';
|
|
4
|
+
export type ExitCodeV2 = 0 | 1 | 2 | 3 | 4 | 130;
|
|
5
|
+
export type ExitReductionV2 = Readonly<{
|
|
6
|
+
reason: ExitReasonV2;
|
|
7
|
+
code: ExitCodeV2;
|
|
8
|
+
}>;
|
|
9
|
+
export type ExitReducerOptionsV2 = Readonly<{
|
|
10
|
+
failOn?: ScanSeverityV2;
|
|
11
|
+
requireComplete?: boolean;
|
|
12
|
+
interrupted?: boolean;
|
|
13
|
+
outputFailed?: boolean;
|
|
14
|
+
}>;
|
|
15
|
+
export type ExitReducerInputV2 = Readonly<{
|
|
16
|
+
batch: BatchResultV2;
|
|
17
|
+
failOn?: ScanSeverityV2;
|
|
18
|
+
requireComplete?: boolean;
|
|
19
|
+
interrupted?: boolean;
|
|
20
|
+
outputFailed?: boolean;
|
|
21
|
+
}>;
|
|
22
|
+
export declare function reduceExitV2(batch: BatchResultV2, options?: ExitReducerOptionsV2): ExitReductionV2;
|
|
23
|
+
export declare function reduceExitV2(input: ExitReducerInputV2): ExitReductionV2;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export declare const V2_COMMANDS: readonly ["scan", "rules", "explain", "profiles", "validate-config", "version"];
|
|
2
|
+
export type V2CommandName = (typeof V2_COMMANDS)[number];
|
|
3
|
+
export type V2OptionName = '--help' | '--schema' | '--format' | '--profile' | '--fail-on' | '--require-complete' | '--max-concurrency' | '--concurrency' | '--timeout' | '--output' | '--config' | '--rules' | '--catalogue' | '--limits' | '--target' | '--n8n-version' | '--edition' | '--deployment' | '--role' | '--task-runner' | '--community-package' | '--configuration' | '--approved-domain' | '--include' | '--exclude' | '--allow-unsigned-development-rules' | '--no-color';
|
|
4
|
+
export type V2HelpOption = Readonly<{
|
|
5
|
+
name: V2OptionName;
|
|
6
|
+
value: string;
|
|
7
|
+
commands: readonly V2CommandName[];
|
|
8
|
+
description: string;
|
|
9
|
+
default?: string;
|
|
10
|
+
}>;
|
|
11
|
+
export declare const V2_OPTIONS: readonly V2HelpOption[];
|
|
12
|
+
/**
|
|
13
|
+
* The published limit vocabulary, restated because a shipped declaration must not name the private,
|
|
14
|
+
* unpublished contracts workspace: a strict NodeNext consumer of the packed package fails `TS2307`
|
|
15
|
+
* on that import. The values below still come from the contract, and the two vocabularies stay
|
|
16
|
+
* exhaustive against each other at compile time.
|
|
17
|
+
*/
|
|
18
|
+
export type V2LimitName = 'maxBytes' | 'maxNodes' | 'maxEdges' | 'maxConnectionDepth' | 'maxParameterDepth' | 'maxParameterLeaves' | 'workerDeadlineMs' | 'maxSyntaxNodes' | 'maxDocumentDepth' | 'maxMembersAndElements' | 'maxRawEdges' | 'maxDuplicateKeys' | 'maxDiagnostics' | 'maxStoredSourceSpans' | 'maxSourceWork' | 'maxExpressionTokens' | 'maxCodeSyntaxNodes' | 'maxGraphOperations' | 'maxTaintStates' | 'maxTraceStepsPerFinding' | 'maxFindings' | 'maxRedactionPatches' | 'maxRedactedArtifactBytes' | 'maxEvidenceBytes' | 'maxSerializedResultBytes' | 'maxRuleOperations';
|
|
19
|
+
export declare const V2_LIMITS: Readonly<Record<V2LimitName, number>>;
|
|
20
|
+
export declare const V2_EXIT_CODES: readonly [0, 1, 2, 3, 4, 130];
|
|
21
|
+
export type V2ExitCode = (typeof V2_EXIT_CODES)[number];
|
|
22
|
+
export declare const V2_EXIT_REASONS: readonly ["CANCELLED", "INTERNAL", "USAGE", "FINDING_THRESHOLD", "REQUIRE_COMPLETE", "ITEM_FAILURE", "UNDER_THRESHOLD"];
|
|
23
|
+
export type V2ExitReason = (typeof V2_EXIT_REASONS)[number];
|
|
24
|
+
export declare const V2_CANONICAL_CLAIMS: readonly ["v2 is offline and never initiates network requests (HTTP, DNS, sockets, telemetry, or remote imports).", "Labels and output identities never contain absolute paths or workflow source content.", "File output uses a same-directory temporary file and atomic replace; failures and cancellation preserve the prior file.", "beta-default@2.0.0 is admitted; beta-hardened@2.0.0 is defined but not admitted or selectable.", "No shipped path produces a redacted artifact: maxRedactionPatches and maxRedactedArtifactBytes bound redaction-v2, which is development-only and unwired.", "No shipped path admits an external rule pack: --rules and --catalogue accept only builtin, and --allow-unsigned-development-rules is refused because Ed25519 trust-store admission is deferred.", "Published on npm as sfscanner."];
|
|
25
|
+
export type V2CommandHelp = Readonly<{
|
|
26
|
+
command: V2CommandName;
|
|
27
|
+
usage: readonly string[];
|
|
28
|
+
text: string;
|
|
29
|
+
}>;
|
|
30
|
+
export declare const COMMAND_HELP_V2: Readonly<Record<V2CommandName, string>>;
|
|
31
|
+
export declare const GENERAL_HELP_V2: string;
|
|
32
|
+
export declare const HELP_TEXT_V2: string;
|
|
33
|
+
export declare function getHelpV2(command?: V2CommandName): string;
|
package/dist/v2/help.js
ADDED
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
// ../../contracts/exclusion-registry.ts
|
|
2
|
+
var ENTRY_ID_PATTERN = /^[0-9a-f]{16}$/;
|
|
3
|
+
function validateRecord(record) {
|
|
4
|
+
if (!ENTRY_ID_PATTERN.test(record.id)) {
|
|
5
|
+
throw new Error(
|
|
6
|
+
`Exclusion registry record has a malformed id "${record.id}": expected the 16-hex-character output of entryId(kind, ref, path), not a title, slug, or free-text identifier.`
|
|
7
|
+
);
|
|
8
|
+
}
|
|
9
|
+
if (!record.reason.trim()) {
|
|
10
|
+
throw new Error(`Exclusion registry record for id "${record.id}" has no reason recorded.`);
|
|
11
|
+
}
|
|
12
|
+
if (!Number.isFinite(Date.parse(record.excludedAt))) {
|
|
13
|
+
throw new Error(
|
|
14
|
+
`Exclusion registry record for id "${record.id}" has an invalid excludedAt timestamp: "${record.excludedAt}".`
|
|
15
|
+
);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
function createExclusionRegistry(records) {
|
|
19
|
+
const seen = /* @__PURE__ */ new Set();
|
|
20
|
+
for (const record of records) {
|
|
21
|
+
validateRecord(record);
|
|
22
|
+
if (seen.has(record.id)) {
|
|
23
|
+
throw new Error(`Exclusion registry has more than one record for id "${record.id}".`);
|
|
24
|
+
}
|
|
25
|
+
seen.add(record.id);
|
|
26
|
+
}
|
|
27
|
+
const frozenRecords = Object.freeze(records.map((record) => Object.freeze({ ...record })));
|
|
28
|
+
const byId = new Map(frozenRecords.map((record) => [record.id, record]));
|
|
29
|
+
return Object.freeze({
|
|
30
|
+
records: frozenRecords,
|
|
31
|
+
isExcluded: (id) => byId.has(id),
|
|
32
|
+
recordFor: (id) => byId.get(id)
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
var EMPTY_EXCLUSION_REGISTRY = createExclusionRegistry([]);
|
|
36
|
+
|
|
37
|
+
// ../../contracts/limits.ts
|
|
38
|
+
var LIMITS = {
|
|
39
|
+
maxWorkflowBytes: 1536e3,
|
|
40
|
+
maxNodes: 5e3,
|
|
41
|
+
scanTimeoutMs: 3e4,
|
|
42
|
+
packSize: 250,
|
|
43
|
+
shardSize: 2e3,
|
|
44
|
+
maxPublicFindings: 20
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
// ../../contracts/scanner-limits.ts
|
|
48
|
+
var SCANNER_LIMITS_SCHEMA_VERSION = "scanner-limits-v1";
|
|
49
|
+
var DEFAULT_SCANNER_LIMITS = Object.freeze({
|
|
50
|
+
schemaVersion: SCANNER_LIMITS_SCHEMA_VERSION,
|
|
51
|
+
maxBytes: LIMITS.maxWorkflowBytes,
|
|
52
|
+
maxNodes: LIMITS.maxNodes,
|
|
53
|
+
maxEdges: 1e4,
|
|
54
|
+
// Previously declared as a `workflow.ts` option but never wired to any
|
|
55
|
+
// production caller (see scanner-contract-and-calibration tasks.md P1.1) —
|
|
56
|
+
// this is the first real default for it.
|
|
57
|
+
maxConnectionDepth: 64,
|
|
58
|
+
maxParameterDepth: 64,
|
|
59
|
+
maxParameterLeaves: 1e4,
|
|
60
|
+
workerDeadlineMs: LIMITS.scanTimeoutMs
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
// ../../contracts/scanner-limits-v2.ts
|
|
64
|
+
var SCANNER_LIMITS_V2_SCHEMA_VERSION = "scanner-limits-v2";
|
|
65
|
+
var SCANNER_LIMITS_V2_NUMERIC_FIELDS = [
|
|
66
|
+
"maxBytes",
|
|
67
|
+
"maxNodes",
|
|
68
|
+
"maxEdges",
|
|
69
|
+
"maxConnectionDepth",
|
|
70
|
+
"maxParameterDepth",
|
|
71
|
+
"maxParameterLeaves",
|
|
72
|
+
"workerDeadlineMs",
|
|
73
|
+
"maxSyntaxNodes",
|
|
74
|
+
"maxDocumentDepth",
|
|
75
|
+
"maxMembersAndElements",
|
|
76
|
+
"maxRawEdges",
|
|
77
|
+
"maxDuplicateKeys",
|
|
78
|
+
"maxDiagnostics",
|
|
79
|
+
"maxStoredSourceSpans",
|
|
80
|
+
"maxSourceWork",
|
|
81
|
+
"maxExpressionTokens",
|
|
82
|
+
"maxCodeSyntaxNodes",
|
|
83
|
+
"maxGraphOperations",
|
|
84
|
+
"maxTaintStates",
|
|
85
|
+
"maxTraceStepsPerFinding",
|
|
86
|
+
"maxFindings",
|
|
87
|
+
"maxRedactionPatches",
|
|
88
|
+
"maxRedactedArtifactBytes",
|
|
89
|
+
"maxEvidenceBytes",
|
|
90
|
+
"maxSerializedResultBytes",
|
|
91
|
+
"maxRuleOperations"
|
|
92
|
+
];
|
|
93
|
+
var SCANNER_LIMITS_V2_FIELDS = [
|
|
94
|
+
"schemaVersion",
|
|
95
|
+
...SCANNER_LIMITS_V2_NUMERIC_FIELDS
|
|
96
|
+
];
|
|
97
|
+
var DEFAULT_SCANNER_LIMITS_V2 = Object.freeze({
|
|
98
|
+
...DEFAULT_SCANNER_LIMITS,
|
|
99
|
+
schemaVersion: SCANNER_LIMITS_V2_SCHEMA_VERSION,
|
|
100
|
+
maxSyntaxNodes: 25e4,
|
|
101
|
+
maxDocumentDepth: 256,
|
|
102
|
+
maxMembersAndElements: 25e4,
|
|
103
|
+
maxRawEdges: 5e4,
|
|
104
|
+
maxDuplicateKeys: 1e3,
|
|
105
|
+
maxDiagnostics: 1e3,
|
|
106
|
+
maxStoredSourceSpans: 25e3,
|
|
107
|
+
maxSourceWork: 1e6,
|
|
108
|
+
maxExpressionTokens: 1e5,
|
|
109
|
+
maxCodeSyntaxNodes: 25e4,
|
|
110
|
+
maxGraphOperations: 1e6,
|
|
111
|
+
maxTaintStates: 25e4,
|
|
112
|
+
maxTraceStepsPerFinding: 100,
|
|
113
|
+
maxFindings: 5e3,
|
|
114
|
+
maxRedactionPatches: 1e4,
|
|
115
|
+
maxRedactedArtifactBytes: 1536e3,
|
|
116
|
+
maxEvidenceBytes: 1536e3,
|
|
117
|
+
maxSerializedResultBytes: 5e6,
|
|
118
|
+
maxRuleOperations: 1e6
|
|
119
|
+
});
|
|
120
|
+
var ADMITTED_LIMIT_STATES = Object.freeze({
|
|
121
|
+
maxBytes: "WIRED",
|
|
122
|
+
maxNodes: "WIRED",
|
|
123
|
+
maxEdges: "WIRED",
|
|
124
|
+
maxConnectionDepth: "WIRED",
|
|
125
|
+
maxParameterDepth: "WIRED",
|
|
126
|
+
maxParameterLeaves: "WIRED",
|
|
127
|
+
workerDeadlineMs: "WIRED",
|
|
128
|
+
maxSyntaxNodes: "WIRED",
|
|
129
|
+
maxDocumentDepth: "WIRED",
|
|
130
|
+
maxMembersAndElements: "WIRED",
|
|
131
|
+
maxRawEdges: "WIRED",
|
|
132
|
+
maxDuplicateKeys: "WIRED",
|
|
133
|
+
maxDiagnostics: "WIRED",
|
|
134
|
+
maxStoredSourceSpans: "WIRED",
|
|
135
|
+
maxSourceWork: "WIRED",
|
|
136
|
+
maxExpressionTokens: "DORMANT",
|
|
137
|
+
maxCodeSyntaxNodes: "DORMANT",
|
|
138
|
+
maxGraphOperations: "DORMANT",
|
|
139
|
+
maxTaintStates: "DORMANT",
|
|
140
|
+
maxTraceStepsPerFinding: "DORMANT",
|
|
141
|
+
maxFindings: "WIRED",
|
|
142
|
+
maxRedactionPatches: "UNWIRED",
|
|
143
|
+
maxRedactedArtifactBytes: "UNWIRED",
|
|
144
|
+
maxEvidenceBytes: "WIRED",
|
|
145
|
+
maxSerializedResultBytes: "WIRED",
|
|
146
|
+
maxRuleOperations: "WIRED"
|
|
147
|
+
});
|
|
148
|
+
var MEASURED_LIMIT_IDS = [
|
|
149
|
+
"maxBytes",
|
|
150
|
+
"maxNodes",
|
|
151
|
+
"maxEdges",
|
|
152
|
+
"maxConnectionDepth",
|
|
153
|
+
"maxParameterDepth",
|
|
154
|
+
"maxParameterLeaves",
|
|
155
|
+
"maxSyntaxNodes",
|
|
156
|
+
"maxRawEdges",
|
|
157
|
+
"maxDuplicateKeys",
|
|
158
|
+
"maxDiagnostics",
|
|
159
|
+
"maxStoredSourceSpans",
|
|
160
|
+
"maxSourceWork",
|
|
161
|
+
"maxFindings"
|
|
162
|
+
];
|
|
163
|
+
|
|
164
|
+
// src/v2/help.ts
|
|
165
|
+
var V2_COMMANDS = Object.freeze([
|
|
166
|
+
"scan",
|
|
167
|
+
"rules",
|
|
168
|
+
"explain",
|
|
169
|
+
"profiles",
|
|
170
|
+
"validate-config",
|
|
171
|
+
"version"
|
|
172
|
+
]);
|
|
173
|
+
var SCAN = Object.freeze(["scan"]);
|
|
174
|
+
var ALL = V2_COMMANDS;
|
|
175
|
+
var V2_OPTIONS = Object.freeze([
|
|
176
|
+
{ name: "--help", value: "", commands: ALL, description: "Show deterministic help for the selected v2 command." },
|
|
177
|
+
{ name: "--schema", value: "<v2>", commands: ALL, description: "Select the versioned v2 grammar." },
|
|
178
|
+
{ name: "--format", value: "<json|ndjson|sarif|table>", commands: ALL, description: "Select the output format.", default: "json for scan; json for metadata" },
|
|
179
|
+
{ name: "--profile", value: "<beta-default>", commands: SCAN, description: "Select the admitted analysis profile.", default: "beta-default" },
|
|
180
|
+
{ name: "--fail-on", value: "<CRITICAL|HIGH|MEDIUM|LOW|INFO>", commands: SCAN, description: "Fail when a finding meets or exceeds this severity.", default: "INFO" },
|
|
181
|
+
{ name: "--require-complete", value: "", commands: SCAN, description: "Treat DEGRADED analysis as a failure.", default: "false" },
|
|
182
|
+
{ name: "--max-concurrency", value: "<1..16>", commands: SCAN, description: "Bound concurrent inputs; --concurrency is an equivalent spelling.", default: "1" },
|
|
183
|
+
{ name: "--concurrency", value: "<1..16>", commands: SCAN, description: "Bound concurrent inputs; --max-concurrency is an equivalent spelling.", default: "1" },
|
|
184
|
+
{ name: "--timeout", value: "<1..2147483647>", commands: SCAN, description: "Set the per-input timeout in milliseconds.", default: "30000 (workerDeadlineMs)" },
|
|
185
|
+
{ name: "--output", value: "<local-file|->", commands: SCAN, description: "Write to a local file atomically, or use - for stdout.", default: "stdout" },
|
|
186
|
+
{ name: "--config", value: "<local-file>", commands: SCAN, description: "Load one explicit versioned config file." },
|
|
187
|
+
{ name: "--rules", value: "<builtin>", commands: SCAN, description: "Select the embedded built-in ruleset; the only admitted authority.", default: "builtin" },
|
|
188
|
+
{ name: "--catalogue", value: "<builtin>", commands: SCAN, description: "Select the embedded semantic catalogue.", default: "builtin" },
|
|
189
|
+
{ name: "--limits", value: "<local-file|builtin>", commands: SCAN, description: "Select embedded or local scanner limits.", default: "builtin" },
|
|
190
|
+
{ name: "--target", value: "<local-file>", commands: SCAN, description: "Load a local target context." },
|
|
191
|
+
{ name: "--n8n-version", value: "<semver>", commands: SCAN, description: "Set the n8n version fact." },
|
|
192
|
+
{ name: "--edition", value: "<COMMUNITY|ENTERPRISE|CLOUD|UNKNOWN>", commands: SCAN, description: "Set the deployment edition fact.", default: "UNKNOWN" },
|
|
193
|
+
{ name: "--deployment", value: "<SELF_HOSTED|CLOUD|UNKNOWN>", commands: SCAN, description: "Set the deployment fact.", default: "UNKNOWN" },
|
|
194
|
+
{ name: "--role", value: "<OWNER|ADMIN|MEMBER|UNKNOWN>", commands: SCAN, description: "Set the operator role fact.", default: "UNKNOWN" },
|
|
195
|
+
{ name: "--task-runner", value: "<LEGACY|NATIVE|UNKNOWN>", commands: SCAN, description: "Set the task-runner fact.", default: "UNKNOWN" },
|
|
196
|
+
{ name: "--community-package", value: "<package>", commands: SCAN, description: "Record a community package in target context; repeatable." },
|
|
197
|
+
{ name: "--configuration", value: "<name>", commands: SCAN, description: "Record a configuration fact; repeatable." },
|
|
198
|
+
{ name: "--approved-domain", value: "<host>", commands: SCAN, description: "Treat this hostname as approved for UNAPPROVED_DOMAIN; repeatable." },
|
|
199
|
+
{ name: "--include", value: "<posix-glob>", commands: SCAN, description: "Replace config includes with a case-sensitive POSIX glob; repeatable.", default: "**/*.json" },
|
|
200
|
+
{ name: "--exclude", value: "<posix-glob>", commands: SCAN, description: "Replace config excludes with a case-sensitive POSIX glob; repeatable.", default: ".git/**, node_modules/**" },
|
|
201
|
+
{ name: "--allow-unsigned-development-rules", value: "", commands: SCAN, description: "Refused: external rule packs are not admitted, so no pack can be selected.", default: "false" },
|
|
202
|
+
{ name: "--no-color", value: "", commands: SCAN, description: "Disable color in human output.", default: "false (also disabled for non-TTY)" }
|
|
203
|
+
]);
|
|
204
|
+
var V2_LIMITS = Object.freeze({
|
|
205
|
+
maxBytes: DEFAULT_SCANNER_LIMITS_V2.maxBytes,
|
|
206
|
+
maxNodes: DEFAULT_SCANNER_LIMITS_V2.maxNodes,
|
|
207
|
+
maxEdges: DEFAULT_SCANNER_LIMITS_V2.maxEdges,
|
|
208
|
+
maxConnectionDepth: DEFAULT_SCANNER_LIMITS_V2.maxConnectionDepth,
|
|
209
|
+
maxParameterDepth: DEFAULT_SCANNER_LIMITS_V2.maxParameterDepth,
|
|
210
|
+
maxParameterLeaves: DEFAULT_SCANNER_LIMITS_V2.maxParameterLeaves,
|
|
211
|
+
workerDeadlineMs: DEFAULT_SCANNER_LIMITS_V2.workerDeadlineMs,
|
|
212
|
+
maxSyntaxNodes: DEFAULT_SCANNER_LIMITS_V2.maxSyntaxNodes,
|
|
213
|
+
maxDocumentDepth: DEFAULT_SCANNER_LIMITS_V2.maxDocumentDepth,
|
|
214
|
+
maxMembersAndElements: DEFAULT_SCANNER_LIMITS_V2.maxMembersAndElements,
|
|
215
|
+
maxRawEdges: DEFAULT_SCANNER_LIMITS_V2.maxRawEdges,
|
|
216
|
+
maxDuplicateKeys: DEFAULT_SCANNER_LIMITS_V2.maxDuplicateKeys,
|
|
217
|
+
maxDiagnostics: DEFAULT_SCANNER_LIMITS_V2.maxDiagnostics,
|
|
218
|
+
maxStoredSourceSpans: DEFAULT_SCANNER_LIMITS_V2.maxStoredSourceSpans,
|
|
219
|
+
maxSourceWork: DEFAULT_SCANNER_LIMITS_V2.maxSourceWork,
|
|
220
|
+
maxExpressionTokens: DEFAULT_SCANNER_LIMITS_V2.maxExpressionTokens,
|
|
221
|
+
maxCodeSyntaxNodes: DEFAULT_SCANNER_LIMITS_V2.maxCodeSyntaxNodes,
|
|
222
|
+
maxGraphOperations: DEFAULT_SCANNER_LIMITS_V2.maxGraphOperations,
|
|
223
|
+
maxTaintStates: DEFAULT_SCANNER_LIMITS_V2.maxTaintStates,
|
|
224
|
+
maxTraceStepsPerFinding: DEFAULT_SCANNER_LIMITS_V2.maxTraceStepsPerFinding,
|
|
225
|
+
maxFindings: DEFAULT_SCANNER_LIMITS_V2.maxFindings,
|
|
226
|
+
maxRedactionPatches: DEFAULT_SCANNER_LIMITS_V2.maxRedactionPatches,
|
|
227
|
+
maxRedactedArtifactBytes: DEFAULT_SCANNER_LIMITS_V2.maxRedactedArtifactBytes,
|
|
228
|
+
maxEvidenceBytes: DEFAULT_SCANNER_LIMITS_V2.maxEvidenceBytes,
|
|
229
|
+
maxSerializedResultBytes: DEFAULT_SCANNER_LIMITS_V2.maxSerializedResultBytes,
|
|
230
|
+
maxRuleOperations: DEFAULT_SCANNER_LIMITS_V2.maxRuleOperations
|
|
231
|
+
});
|
|
232
|
+
function limitStateMarker(name) {
|
|
233
|
+
const state = ADMITTED_LIMIT_STATES[name];
|
|
234
|
+
if (state === "WIRED") {
|
|
235
|
+
return MEASURED_LIMIT_IDS.some((id) => id === name) ? " (enforced; usage row)" : " (enforced; no usage row)";
|
|
236
|
+
}
|
|
237
|
+
return state === "DORMANT" ? " (dormant in beta-default; hardened-only)" : " (development-only, unwired)";
|
|
238
|
+
}
|
|
239
|
+
var V2_EXIT_CODES = Object.freeze([0, 1, 2, 3, 4, 130]);
|
|
240
|
+
var V2_EXIT_REASONS = Object.freeze([
|
|
241
|
+
"CANCELLED",
|
|
242
|
+
"INTERNAL",
|
|
243
|
+
"USAGE",
|
|
244
|
+
"FINDING_THRESHOLD",
|
|
245
|
+
"REQUIRE_COMPLETE",
|
|
246
|
+
"ITEM_FAILURE",
|
|
247
|
+
"UNDER_THRESHOLD"
|
|
248
|
+
]);
|
|
249
|
+
var V2_CANONICAL_CLAIMS = Object.freeze([
|
|
250
|
+
"v2 is offline and never initiates network requests (HTTP, DNS, sockets, telemetry, or remote imports).",
|
|
251
|
+
"Labels and output identities never contain absolute paths or workflow source content.",
|
|
252
|
+
"File output uses a same-directory temporary file and atomic replace; failures and cancellation preserve the prior file.",
|
|
253
|
+
"beta-default@2.0.0 is admitted; beta-hardened@2.0.0 is defined but not admitted or selectable.",
|
|
254
|
+
"No shipped path produces a redacted artifact: maxRedactionPatches and maxRedactedArtifactBytes bound redaction-v2, which is development-only and unwired.",
|
|
255
|
+
"No shipped path admits an external rule pack: --rules and --catalogue accept only builtin, and --allow-unsigned-development-rules is refused because Ed25519 trust-store admission is deferred.",
|
|
256
|
+
"Published on npm as sfscanner."
|
|
257
|
+
]);
|
|
258
|
+
function optionLine(option, command) {
|
|
259
|
+
const value = option.name === "--format" && command !== void 0 && command !== "scan" ? "<json|table>" : option.value;
|
|
260
|
+
const syntax = value ? ` ${value}` : "";
|
|
261
|
+
const defaultText = option.default ? ` Default: ${option.default}.` : "";
|
|
262
|
+
return ` ${option.name}${syntax} ${option.description}${defaultText}`;
|
|
263
|
+
}
|
|
264
|
+
function renderCommand(command) {
|
|
265
|
+
const usage = command === "scan" ? [`sfscanner --schema v2 scan <file|directory|-> [options]`] : command === "explain" ? [`sfscanner --schema v2 explain <rule-id> [--format json|table]`] : command === "validate-config" ? [`sfscanner --schema v2 validate-config <local-file> [--format json|table]`] : [`sfscanner --schema v2 ${command} [--format json|table]`];
|
|
266
|
+
const options = V2_OPTIONS.filter((option) => option.commands.includes(command));
|
|
267
|
+
const lines = [`sfscanner v2 ${command}`, "", "Usage:", ...usage, "", "Options:", ...options.map((option) => optionLine(option, command))];
|
|
268
|
+
if (command === "scan") lines.push("", "Inputs are sorted by normalized relative label; stdin (-) cannot join a batch.");
|
|
269
|
+
if (command === "profiles") lines.push("", "beta-default is admitted. beta-hardened is defined but not admitted or selectable.");
|
|
270
|
+
if (command === "validate-config") lines.push("", "Only the explicitly supplied local config file is read.");
|
|
271
|
+
return Object.freeze({ command, usage: Object.freeze(usage), text: `${lines.join("\n")}
|
|
272
|
+
` });
|
|
273
|
+
}
|
|
274
|
+
var COMMAND_HELP_V2 = Object.freeze(
|
|
275
|
+
Object.fromEntries(V2_COMMANDS.map((command) => [command, renderCommand(command).text]))
|
|
276
|
+
);
|
|
277
|
+
var generalLines = [
|
|
278
|
+
"sfscanner \u2014 deterministic offline n8n workflow scanner (v2)",
|
|
279
|
+
"",
|
|
280
|
+
"Usage:",
|
|
281
|
+
" sfscanner --schema v2 scan <file|directory|-> [options]",
|
|
282
|
+
" sfscanner --schema v2 rules [--format json|table]",
|
|
283
|
+
" sfscanner --schema v2 explain <rule-id> [--format json|table]",
|
|
284
|
+
" sfscanner --schema v2 profiles [--format json|table]",
|
|
285
|
+
" sfscanner --schema v2 validate-config <local-file> [--format json|table]",
|
|
286
|
+
" sfscanner --schema v2 version [--format json|table]",
|
|
287
|
+
"",
|
|
288
|
+
"Commands:",
|
|
289
|
+
"Defaults:",
|
|
290
|
+
" format: json; profile: beta-default; fail-on: INFO; require-complete: false; concurrency: 1 (maximum 16); timeout: 30000ms.",
|
|
291
|
+
" include: **/*.json; exclude: .git/**, node_modules/**; rules/catalogue/limits: builtin.",
|
|
292
|
+
" target facts: edition UNKNOWN; deployment UNKNOWN; role UNKNOWN; task-runner UNKNOWN.",
|
|
293
|
+
"",
|
|
294
|
+
"Profiles:",
|
|
295
|
+
" beta-default@2.0.0: admitted and selectable.",
|
|
296
|
+
" beta-hardened@2.0.0: defined but not admitted or selectable.",
|
|
297
|
+
"",
|
|
298
|
+
"Limits:",
|
|
299
|
+
...Object.entries(V2_LIMITS).map(([name, value]) => ` ${name}=${value}${limitStateMarker(name)}`),
|
|
300
|
+
"",
|
|
301
|
+
"Exit codes and precedence:",
|
|
302
|
+
" 130 CANCELLED; 4 INTERNAL; 2 USAGE; 1 FINDING_THRESHOLD or REQUIRE_COMPLETE; 3 ITEM_FAILURE; 0 UNDER_THRESHOLD.",
|
|
303
|
+
" Pre-scan usage/configuration/admission failures emit no machine envelope and exit 2; stdout cancellation emits a valid envelope and exits 130.",
|
|
304
|
+
" When finding threshold and require-complete both fire, FINDING_THRESHOLD wins. Indeterminate never exits 0.",
|
|
305
|
+
"",
|
|
306
|
+
...V2_CANONICAL_CLAIMS
|
|
307
|
+
];
|
|
308
|
+
var GENERAL_HELP_V2 = `${generalLines.join("\n")}
|
|
309
|
+
`;
|
|
310
|
+
var HELP_TEXT_V2 = GENERAL_HELP_V2;
|
|
311
|
+
function getHelpV2(command) {
|
|
312
|
+
return command === void 0 ? GENERAL_HELP_V2 : COMMAND_HELP_V2[command];
|
|
313
|
+
}
|
|
314
|
+
export {
|
|
315
|
+
COMMAND_HELP_V2,
|
|
316
|
+
GENERAL_HELP_V2,
|
|
317
|
+
HELP_TEXT_V2,
|
|
318
|
+
V2_CANONICAL_CLAIMS,
|
|
319
|
+
V2_COMMANDS,
|
|
320
|
+
V2_EXIT_CODES,
|
|
321
|
+
V2_EXIT_REASONS,
|
|
322
|
+
V2_LIMITS,
|
|
323
|
+
V2_OPTIONS,
|
|
324
|
+
getHelpV2
|
|
325
|
+
};
|