sfscanner 0.1.0 → 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/README.md +131 -214
- package/dist/index.d.ts +4 -0
- package/dist/index.js +10766 -0
- package/dist/index.js.map +7 -0
- package/dist/main.js +4419 -7667
- package/dist/main.js.map +4 -4
- package/dist/mcp.js +3374 -6611
- package/dist/mcp.js.map +4 -4
- package/dist/scan-worker.js +11800 -0
- package/dist/scan-worker.js.map +7 -0
- package/dist/v2/arguments.d.ts +4 -3
- package/dist/v2/arguments.js +126 -17
- package/dist/v2/arguments.js.map +3 -3
- package/dist/v2/batch-runner.d.ts +7 -1
- package/dist/v2/cli-runner-internal.d.ts +28 -0
- package/dist/v2/cli-runner.d.ts +16 -22
- package/dist/v2/cli-runner.js +3524 -6872
- package/dist/v2/cli-runner.js.map +4 -4
- package/dist/v2/commands.d.ts +5 -4
- package/dist/v2/config.d.ts +1 -1
- package/dist/v2/contracts.d.ts +23 -6
- package/dist/v2/help.d.ts +8 -2
- package/dist/v2/help.js +52 -5
- package/dist/v2/help.js.map +2 -2
- package/dist/v2/metadata-output.d.ts +2 -2
- package/dist/v2/metadata-output.js +6844 -139
- package/dist/v2/metadata-output.js.map +4 -4
- package/dist/v2/metadata-validation.d.ts +1 -1
- 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/package.json +74 -67
- package/dist/v2/sarif-helpers.d.ts +0 -69
- package/dist/v2/sarif-output.d.ts +0 -40
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { CliMetadataDocumentV2 } from './commands';
|
|
1
|
+
import type { CliMetadataDocumentV2 } from './commands.js';
|
|
2
2
|
export declare function checkPlain(o: unknown): Record<string, unknown>;
|
|
3
3
|
export declare function checkDenseArray<T>(arr: unknown): T[];
|
|
4
4
|
export declare function validateDocumentShape(doc: unknown): asserts doc is CliMetadataDocumentV2;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/** Normalizes backslashes before classifying, so a Windows drive path is absolute in both forms. */
|
|
2
|
+
export declare function isAbsoluteAdmittedPathV2(value: string): boolean;
|
|
3
|
+
export declare function isAdmittedLocalPath(value: unknown): value is string;
|
|
4
|
+
export declare function isAdmittedRelativePath(value: unknown): value is string;
|
|
5
|
+
export declare function normalizeAdmittedPathV2(value: unknown, relativeOnly?: boolean): string | undefined;
|
|
6
|
+
export declare function admittedLabelV2(raw: string, baseDirectory: string): string;
|
|
7
|
+
export declare function toFsPathV2(baseDirectory: string, normalized: string): string;
|
|
8
|
+
export declare function isWithinBaseV2(target: string, baseDirectory: string): boolean;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { type ScannerLimitsV2 } from '@hub/contracts';
|
|
2
|
+
import type { CliCommandV2 } from './arguments';
|
|
3
|
+
import { type ScanConfigV2 } from './config';
|
|
4
|
+
import type { ProjectionSourceV2 } from './json-output';
|
|
5
|
+
import type { ExitCodeV2 } from './exit-reducer';
|
|
6
|
+
type ScanCommand = Extract<CliCommandV2, {
|
|
7
|
+
kind: 'scan';
|
|
8
|
+
}>;
|
|
9
|
+
export type LoadedScanConfig = Readonly<{
|
|
10
|
+
ok: true;
|
|
11
|
+
config: ScanConfigV2;
|
|
12
|
+
limitsDocument?: ScannerLimitsV2;
|
|
13
|
+
targetDocument?: unknown;
|
|
14
|
+
sources: ProjectionSourceV2;
|
|
15
|
+
}> | Readonly<{
|
|
16
|
+
ok: false;
|
|
17
|
+
exitCode: ExitCodeV2;
|
|
18
|
+
message: string;
|
|
19
|
+
}>;
|
|
20
|
+
export declare function readScanConfig(command: ScanCommand, baseDirectory: string): Promise<LoadedScanConfig>;
|
|
21
|
+
export {};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { Worker } from 'node:worker_threads';
|
|
2
|
+
import type { WorkerHostRun } from './worker-host';
|
|
3
|
+
export type ScanWorkerData = Readonly<{
|
|
4
|
+
bytes: Uint8Array;
|
|
5
|
+
profile: Readonly<{
|
|
6
|
+
id: string;
|
|
7
|
+
version: string;
|
|
8
|
+
}>;
|
|
9
|
+
target?: unknown;
|
|
10
|
+
limits?: unknown;
|
|
11
|
+
approvedDomains?: readonly string[];
|
|
12
|
+
}>;
|
|
13
|
+
export type ScanWorkerFactory = () => Worker;
|
|
14
|
+
export type ScanWorkerOptions = Readonly<{
|
|
15
|
+
timeoutMs?: number;
|
|
16
|
+
signal?: AbortSignal;
|
|
17
|
+
workerFactory?: ScanWorkerFactory;
|
|
18
|
+
}>;
|
|
19
|
+
/**
|
|
20
|
+
* `#sfscanner-worker` is the package's private imports map to the one built
|
|
21
|
+
* `dist/scan-worker.js`. `createRequire(...).resolve` uses the same native
|
|
22
|
+
* package-imports resolution as `import.meta.resolve` (unavailable in
|
|
23
|
+
* vite-node) and checks the target exists, so the same call works from the
|
|
24
|
+
* root bundle, the v2 subpath bundle, and the unbundled source tree after one
|
|
25
|
+
* build. A missing asset throws MODULE_NOT_FOUND; there is no fallback.
|
|
26
|
+
*/
|
|
27
|
+
export declare function scanWorkerUrl(): URL;
|
|
28
|
+
export declare function createScanWorker(data: ScanWorkerData): Worker;
|
|
29
|
+
export declare function runScanInWorker<T = unknown>(data: ScanWorkerData, options?: ScanWorkerOptions): Promise<WorkerHostRun<T>>;
|
package/package.json
CHANGED
|
@@ -1,67 +1,74 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "sfscanner",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "SecureFlow Scanner — Deterministic, offline security & dataflow analyzer for n8n workflows",
|
|
5
|
-
"keywords": [
|
|
6
|
-
"n8n",
|
|
7
|
-
"security",
|
|
8
|
-
"sast",
|
|
9
|
-
"sarif",
|
|
10
|
-
"scanner",
|
|
11
|
-
"workflow"
|
|
12
|
-
],
|
|
13
|
-
"repository": {
|
|
14
|
-
"type": "git",
|
|
15
|
-
"url": "git+https://github.com/jitwark/n8n-Secureflow.git"
|
|
16
|
-
},
|
|
17
|
-
"homepage": "https://github.com/jitwark/n8n-Secureflow#readme",
|
|
18
|
-
"license": "MIT",
|
|
19
|
-
"private": false,
|
|
20
|
-
"type": "module",
|
|
21
|
-
"engines": {
|
|
22
|
-
"node": ">=22 <23"
|
|
23
|
-
},
|
|
24
|
-
"main": "./dist/
|
|
25
|
-
"bin": {
|
|
26
|
-
"sfscanner": "dist/main.js",
|
|
27
|
-
"sfscanner-mcp": "dist/mcp.js"
|
|
28
|
-
},
|
|
29
|
-
"
|
|
30
|
-
"dist"
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
"
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
"
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
"
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
"
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
"
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
"
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
"
|
|
62
|
-
"
|
|
63
|
-
"
|
|
64
|
-
"
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
1
|
+
{
|
|
2
|
+
"name": "sfscanner",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "SecureFlow Scanner — Deterministic, offline security & dataflow analyzer for n8n workflows",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"n8n",
|
|
7
|
+
"security",
|
|
8
|
+
"sast",
|
|
9
|
+
"sarif",
|
|
10
|
+
"scanner",
|
|
11
|
+
"workflow"
|
|
12
|
+
],
|
|
13
|
+
"repository": {
|
|
14
|
+
"type": "git",
|
|
15
|
+
"url": "git+https://github.com/jitwark/n8n-Secureflow.git"
|
|
16
|
+
},
|
|
17
|
+
"homepage": "https://github.com/jitwark/n8n-Secureflow#readme",
|
|
18
|
+
"license": "MIT",
|
|
19
|
+
"private": false,
|
|
20
|
+
"type": "module",
|
|
21
|
+
"engines": {
|
|
22
|
+
"node": ">=22 <23"
|
|
23
|
+
},
|
|
24
|
+
"main": "./dist/index.js",
|
|
25
|
+
"bin": {
|
|
26
|
+
"sfscanner": "dist/main.js",
|
|
27
|
+
"sfscanner-mcp": "dist/mcp.js"
|
|
28
|
+
},
|
|
29
|
+
"imports": {
|
|
30
|
+
"#sfscanner-worker": "./dist/scan-worker.js"
|
|
31
|
+
},
|
|
32
|
+
"files": [
|
|
33
|
+
"dist",
|
|
34
|
+
"README.md",
|
|
35
|
+
"LICENSE",
|
|
36
|
+
"THIRD_PARTY_NOTICES.md"
|
|
37
|
+
],
|
|
38
|
+
"exports": {
|
|
39
|
+
".": {
|
|
40
|
+
"types": "./dist/index.d.ts",
|
|
41
|
+
"import": "./dist/index.js"
|
|
42
|
+
},
|
|
43
|
+
"./v2/arguments": {
|
|
44
|
+
"types": "./dist/v2/arguments.d.ts",
|
|
45
|
+
"import": "./dist/v2/arguments.js"
|
|
46
|
+
},
|
|
47
|
+
"./v2/cli-runner": {
|
|
48
|
+
"types": "./dist/v2/cli-runner.d.ts",
|
|
49
|
+
"import": "./dist/v2/cli-runner.js"
|
|
50
|
+
},
|
|
51
|
+
"./v2/help": {
|
|
52
|
+
"types": "./dist/v2/help.d.ts",
|
|
53
|
+
"import": "./dist/v2/help.js"
|
|
54
|
+
},
|
|
55
|
+
"./v2/metadata-output": {
|
|
56
|
+
"types": "./dist/v2/metadata-output.d.ts",
|
|
57
|
+
"import": "./dist/v2/metadata-output.js"
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
"scripts": {
|
|
61
|
+
"build": "node build.mjs",
|
|
62
|
+
"lint": "eslint .",
|
|
63
|
+
"test": "vitest run --config vitest.config.ts",
|
|
64
|
+
"typecheck": "tsc -p tsconfig.json --noEmit"
|
|
65
|
+
},
|
|
66
|
+
"devDependencies": {
|
|
67
|
+
"@hub/contracts": "*",
|
|
68
|
+
"@hub/scanner-core": "*",
|
|
69
|
+
"@types/node": "^22.0.0",
|
|
70
|
+
"esbuild": "^0.28.2",
|
|
71
|
+
"typescript": "^5.7.2",
|
|
72
|
+
"vitest": "^4.1.11"
|
|
73
|
+
}
|
|
74
|
+
}
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
import { type ScannerResultV2 } from '@hub/contracts/scanner-v2-result';
|
|
2
|
-
import type { SourceSpanV2, SubjectV2 } from '@hub/contracts/scanner-v2-source';
|
|
3
|
-
import type { BatchSarifInputV2, SarifV2Limits } from './sarif-output';
|
|
4
|
-
export type Bounds = {
|
|
5
|
-
rules: number;
|
|
6
|
-
results: number;
|
|
7
|
-
notifications: number;
|
|
8
|
-
taxonomies: number;
|
|
9
|
-
taxa: number;
|
|
10
|
-
tags: number;
|
|
11
|
-
flows: number;
|
|
12
|
-
steps: number;
|
|
13
|
-
};
|
|
14
|
-
export type NotifItem = {
|
|
15
|
-
code: string;
|
|
16
|
-
level: 'warning' | 'error';
|
|
17
|
-
location?: Record<string, unknown>;
|
|
18
|
-
locKey: string;
|
|
19
|
-
id?: string;
|
|
20
|
-
label?: string;
|
|
21
|
-
};
|
|
22
|
-
export type BatchId = {
|
|
23
|
-
engineId: string;
|
|
24
|
-
engineVersion: string;
|
|
25
|
-
engineBuildDigest: string;
|
|
26
|
-
profileId: string;
|
|
27
|
-
profileVersion: string;
|
|
28
|
-
rulesetId: string;
|
|
29
|
-
rulesetVersion: string;
|
|
30
|
-
rulesetDigest: string;
|
|
31
|
-
rulesetSig: string;
|
|
32
|
-
semanticsId: string;
|
|
33
|
-
semanticsVersion: string;
|
|
34
|
-
semanticsDigest: string;
|
|
35
|
-
targetContextDigest: string;
|
|
36
|
-
targetEdition: string;
|
|
37
|
-
targetDeployment: string;
|
|
38
|
-
targetRole: string;
|
|
39
|
-
targetTaskRunner: string;
|
|
40
|
-
limitsSchemaVersion: string;
|
|
41
|
-
limitsDigest: string;
|
|
42
|
-
};
|
|
43
|
-
export type InputIdentity = {
|
|
44
|
-
rawUri: unknown;
|
|
45
|
-
label: string;
|
|
46
|
-
};
|
|
47
|
-
export declare const FALLBACK: Bounds;
|
|
48
|
-
export declare const SEV_ORDER: Record<string, number>;
|
|
49
|
-
export declare const LEVELS: Record<string, 'error' | 'warning' | 'note'>;
|
|
50
|
-
export declare const ALLOWED_ERRORS: Set<string>;
|
|
51
|
-
export declare const prop: (v: unknown, k: string) => unknown;
|
|
52
|
-
export declare const inv: () => never;
|
|
53
|
-
export declare function checkResult(r: unknown): ScannerResultV2;
|
|
54
|
-
export declare function inputIdentity(value: unknown): InputIdentity;
|
|
55
|
-
export declare function extractItems(input: BatchSarifInputV2): {
|
|
56
|
-
items: readonly unknown[];
|
|
57
|
-
repoRoot?: string;
|
|
58
|
-
selRoot?: string;
|
|
59
|
-
limits?: SarifV2Limits;
|
|
60
|
-
};
|
|
61
|
-
export declare function safePath(v: unknown): v is string;
|
|
62
|
-
export declare function safeUri(raw: unknown, repoRoot?: string, selRoot?: string): string | undefined;
|
|
63
|
-
export declare function readPos(v: unknown): SourceSpanV2['start'] | undefined;
|
|
64
|
-
export declare function readSpan(source: unknown): SourceSpanV2 | undefined;
|
|
65
|
-
export declare function subjectKey(s: SubjectV2): string;
|
|
66
|
-
export declare function subjectSpan(subj: SubjectV2): SourceSpanV2 | undefined;
|
|
67
|
-
export declare function physical(uri: string, s: SourceSpanV2): Record<string, unknown>;
|
|
68
|
-
export declare function freeze<T>(v: T, seen?: WeakSet<object>): T;
|
|
69
|
-
export declare function sameId(a: BatchId, b: BatchId): boolean;
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import type { ScannerResultV2 } from '@hub/contracts/scanner-v2-result';
|
|
2
|
-
export type SarifLog = Readonly<{
|
|
3
|
-
version: '2.1.0';
|
|
4
|
-
$schema: string;
|
|
5
|
-
runs: readonly SarifRun[];
|
|
6
|
-
}>;
|
|
7
|
-
export type SarifRun = Readonly<{
|
|
8
|
-
tool: {
|
|
9
|
-
driver: Record<string, unknown>;
|
|
10
|
-
};
|
|
11
|
-
results: readonly Record<string, unknown>[];
|
|
12
|
-
invocations: readonly Record<string, unknown>[];
|
|
13
|
-
taxonomies?: readonly Record<string, unknown>[];
|
|
14
|
-
}>;
|
|
15
|
-
export type SarifV2Limits = Readonly<{
|
|
16
|
-
maxRules?: number;
|
|
17
|
-
maxResults?: number;
|
|
18
|
-
maxNotifications?: number;
|
|
19
|
-
maxTaxonomies?: number;
|
|
20
|
-
maxTaxa?: number;
|
|
21
|
-
maxTags?: number;
|
|
22
|
-
maxFlows?: number;
|
|
23
|
-
maxTraceSteps?: number;
|
|
24
|
-
}>;
|
|
25
|
-
export type BatchSarifEnvelopeV2 = Readonly<{
|
|
26
|
-
items?: readonly unknown[];
|
|
27
|
-
results?: readonly unknown[];
|
|
28
|
-
input?: Readonly<{
|
|
29
|
-
label: string;
|
|
30
|
-
uri?: string;
|
|
31
|
-
}>;
|
|
32
|
-
result?: ScannerResultV2;
|
|
33
|
-
repositoryRoot?: string;
|
|
34
|
-
selectionRoot?: string;
|
|
35
|
-
limits?: SarifV2Limits;
|
|
36
|
-
}>;
|
|
37
|
-
export type BatchSarifInputV2 = BatchSarifEnvelopeV2 | readonly unknown[];
|
|
38
|
-
export declare function buildBatchSarifV2(input: BatchSarifInputV2): SarifLog;
|
|
39
|
-
export declare function buildSarifV2(input: BatchSarifInputV2): SarifLog;
|
|
40
|
-
export declare function serializeSarifV2(input: BatchSarifInputV2): string;
|