@wrongstack/plugins 0.284.1 → 0.286.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 +18 -14
- package/dist/accessibility-auditor/index.d.ts +38 -0
- package/dist/accessibility-auditor/index.d.ts.map +1 -0
- package/dist/accessibility-auditor.d.ts +2 -40
- package/dist/accessibility-auditor.js +10 -15
- package/dist/agent-handoff/index.d.ts +35 -0
- package/dist/agent-handoff/index.d.ts.map +1 -0
- package/dist/agent-handoff.d.ts +2 -37
- package/dist/agent-handoff.js +3 -2
- package/dist/api-compatibility-gate/index.d.ts +36 -0
- package/dist/api-compatibility-gate/index.d.ts.map +1 -0
- package/dist/api-compatibility-gate.d.ts +2 -38
- package/dist/api-compatibility-gate.js +6 -6
- package/dist/auto-doc/index.d.ts +20 -0
- package/dist/auto-doc/index.d.ts.map +1 -0
- package/dist/auto-doc.d.ts +2 -22
- package/dist/auto-doc.js +5 -5
- package/dist/auto-escalate/index.d.ts +43 -0
- package/dist/auto-escalate/index.d.ts.map +1 -0
- package/dist/auto-escalate.d.ts +2 -45
- package/dist/auto-escalate.js +5 -2
- package/dist/auto-i18n-extractor/index.d.ts +34 -0
- package/dist/auto-i18n-extractor/index.d.ts.map +1 -0
- package/dist/auto-i18n-extractor.d.ts +2 -36
- package/dist/auto-i18n-extractor.js +6 -7
- package/dist/branch-guard/index.d.ts +32 -0
- package/dist/branch-guard/index.d.ts.map +1 -0
- package/dist/branch-guard.d.ts +2 -34
- package/dist/branch-guard.js +4 -4
- package/dist/catalog.d.ts +39 -0
- package/dist/catalog.d.ts.map +1 -0
- package/dist/changelog-writer/index.d.ts +71 -0
- package/dist/changelog-writer/index.d.ts.map +1 -0
- package/dist/changelog-writer.d.ts +2 -73
- package/dist/changelog-writer.js +9 -5
- package/dist/checkpoint/index.d.ts +53 -0
- package/dist/checkpoint/index.d.ts.map +1 -0
- package/dist/checkpoint.d.ts +2 -55
- package/dist/checkpoint.js +6 -6
- package/dist/code-metrics/index.d.ts +29 -0
- package/dist/code-metrics/index.d.ts.map +1 -0
- package/dist/code-metrics.d.ts +2 -31
- package/dist/code-metrics.js +13 -15
- package/dist/commit-validator/index.d.ts +31 -0
- package/dist/commit-validator/index.d.ts.map +1 -0
- package/dist/commit-validator.d.ts +2 -33
- package/dist/commit-validator.js +5 -3
- package/dist/config-validator/index.d.ts +46 -0
- package/dist/config-validator/index.d.ts.map +1 -0
- package/dist/config-validator.d.ts +2 -48
- package/dist/config-validator.js +8 -4
- package/dist/context-pins/index.d.ts +43 -0
- package/dist/context-pins/index.d.ts.map +1 -0
- package/dist/context-pins.d.ts +2 -45
- package/dist/context-pins.js +5 -5
- package/dist/cost-tracker/index.d.ts +51 -0
- package/dist/cost-tracker/index.d.ts.map +1 -0
- package/dist/cost-tracker.d.ts +2 -53
- package/dist/cost-tracker.js +4 -4
- package/dist/cron/index.d.ts +12 -0
- package/dist/cron/index.d.ts.map +1 -0
- package/dist/cron.d.ts +2 -14
- package/dist/cron.js +3 -2
- package/dist/dead-code-detector/index.d.ts +32 -0
- package/dist/dead-code-detector/index.d.ts.map +1 -0
- package/dist/dead-code-detector.d.ts +2 -34
- package/dist/dead-code-detector.js +8 -9
- package/dist/dep-guard/index.d.ts +63 -0
- package/dist/dep-guard/index.d.ts.map +1 -0
- package/dist/dep-guard.d.ts +2 -65
- package/dist/dep-guard.js +6 -2
- package/dist/dependency-vulnerability-gate/index.d.ts +33 -0
- package/dist/dependency-vulnerability-gate/index.d.ts.map +1 -0
- package/dist/dependency-vulnerability-gate.d.ts +2 -35
- package/dist/dependency-vulnerability-gate.js +5 -5
- package/dist/diff-summary/index.d.ts +34 -0
- package/dist/diff-summary/index.d.ts.map +1 -0
- package/dist/diff-summary.d.ts +2 -36
- package/dist/diff-summary.js +5 -5
- package/dist/doc-sync-guard/index.d.ts +31 -0
- package/dist/doc-sync-guard/index.d.ts.map +1 -0
- package/dist/doc-sync-guard.d.ts +2 -33
- package/dist/doc-sync-guard.js +4 -4
- package/dist/duplicate-code-detector/index.d.ts +31 -0
- package/dist/duplicate-code-detector/index.d.ts.map +1 -0
- package/dist/duplicate-code-detector.d.ts +2 -33
- package/dist/duplicate-code-detector.js +5 -5
- package/dist/error-lens/index.d.ts +65 -0
- package/dist/error-lens/index.d.ts.map +1 -0
- package/dist/error-lens.d.ts +2 -67
- package/dist/error-lens.js +5 -2
- package/dist/feature-flag-tracker/index.d.ts +36 -0
- package/dist/feature-flag-tracker/index.d.ts.map +1 -0
- package/dist/feature-flag-tracker.d.ts +2 -38
- package/dist/feature-flag-tracker.js +6 -7
- package/dist/file-watcher/index.d.ts +12 -0
- package/dist/file-watcher/index.d.ts.map +1 -0
- package/dist/file-watcher.d.ts +2 -14
- package/dist/file-watcher.js +7 -7
- package/dist/format-on-save/index.d.ts +33 -0
- package/dist/format-on-save/index.d.ts.map +1 -0
- package/dist/format-on-save.d.ts +2 -35
- package/dist/format-on-save.js +6 -6
- package/dist/git-autocommit/index.d.ts +15 -0
- package/dist/git-autocommit/index.d.ts.map +1 -0
- package/dist/git-autocommit.d.ts +2 -17
- package/dist/git-autocommit.js +5 -5
- package/dist/import-organizer/index.d.ts +50 -0
- package/dist/import-organizer/index.d.ts.map +1 -0
- package/dist/import-organizer.d.ts +2 -52
- package/dist/import-organizer.js +6 -6
- package/dist/index.d.ts +186 -64
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +992 -454
- package/dist/injection-shield/index.d.ts +47 -0
- package/dist/injection-shield/index.d.ts.map +1 -0
- package/dist/injection-shield.d.ts +2 -49
- package/dist/injection-shield.js +4 -2
- package/dist/interface-contract-guard/index.d.ts +35 -0
- package/dist/interface-contract-guard/index.d.ts.map +1 -0
- package/dist/interface-contract-guard.d.ts +2 -37
- package/dist/interface-contract-guard.js +6 -7
- package/dist/knowledge-graph/index.d.ts +43 -0
- package/dist/knowledge-graph/index.d.ts.map +1 -0
- package/dist/knowledge-graph.d.ts +2 -45
- package/dist/knowledge-graph.js +5 -5
- package/dist/license-audit-gate/index.d.ts +32 -0
- package/dist/license-audit-gate/index.d.ts.map +1 -0
- package/dist/license-audit-gate.d.ts +2 -34
- package/dist/license-audit-gate.js +6 -7
- package/dist/lint-gate/index.d.ts +31 -0
- package/dist/lint-gate/index.d.ts.map +1 -0
- package/dist/lint-gate.d.ts +2 -33
- package/dist/lint-gate.js +7 -7
- package/dist/llm-cache/index.d.ts +54 -0
- package/dist/llm-cache/index.d.ts.map +1 -0
- package/dist/llm-cache.d.ts +2 -56
- package/dist/llm-cache.js +6 -4
- package/dist/loop-breaker/index.d.ts +4 -0
- package/dist/loop-breaker/index.d.ts.map +1 -0
- package/dist/loop-breaker.d.ts +2 -5
- package/dist/loop-breaker.js +4 -4
- package/dist/migration-planner/index.d.ts +28 -0
- package/dist/migration-planner/index.d.ts.map +1 -0
- package/dist/migration-planner.d.ts +2 -30
- package/dist/migration-planner.js +5 -5
- package/dist/model-router/index.d.ts +67 -0
- package/dist/model-router/index.d.ts.map +1 -0
- package/dist/model-router.d.ts +2 -69
- package/dist/model-router.js +5 -2
- package/dist/notify-hub/index.d.ts +43 -0
- package/dist/notify-hub/index.d.ts.map +1 -0
- package/dist/notify-hub.d.ts +2 -45
- package/dist/notify-hub.js +3 -2
- package/dist/path-guard/index.d.ts +52 -0
- package/dist/path-guard/index.d.ts.map +1 -0
- package/dist/path-guard.d.ts +2 -54
- package/dist/path-guard.js +5 -2
- package/dist/performance-regression-gate/index.d.ts +31 -0
- package/dist/performance-regression-gate/index.d.ts.map +1 -0
- package/dist/performance-regression-gate.d.ts +2 -33
- package/dist/performance-regression-gate.js +5 -5
- package/dist/plugin-stack-observer/index.d.ts +33 -0
- package/dist/plugin-stack-observer/index.d.ts.map +1 -0
- package/dist/plugin-stack-observer.d.ts +2 -35
- package/dist/plugin-stack-observer.js +3 -2
- package/dist/pr-drafter/index.d.ts +33 -0
- package/dist/pr-drafter/index.d.ts.map +1 -0
- package/dist/pr-drafter.d.ts +2 -35
- package/dist/pr-drafter.js +6 -6
- package/dist/prompt-firewall/index.d.ts +55 -0
- package/dist/prompt-firewall/index.d.ts.map +1 -0
- package/dist/prompt-firewall.d.ts +2 -57
- package/dist/prompt-firewall.js +5 -2
- package/dist/refactor-suggester/index.d.ts +36 -0
- package/dist/refactor-suggester/index.d.ts.map +1 -0
- package/dist/refactor-suggester.d.ts +2 -38
- package/dist/refactor-suggester.js +16 -17
- package/dist/release-notes-generator/index.d.ts +25 -0
- package/dist/release-notes-generator/index.d.ts.map +1 -0
- package/dist/release-notes-generator.d.ts +2 -27
- package/dist/release-notes-generator.js +28 -10
- package/dist/runtime/index.d.ts +124 -0
- package/dist/runtime/index.d.ts.map +1 -0
- package/dist/runtime.d.ts +1 -0
- package/dist/runtime.js +216 -0
- package/dist/schema-evolution-guard/index.d.ts +40 -0
- package/dist/schema-evolution-guard/index.d.ts.map +1 -0
- package/dist/schema-evolution-guard.d.ts +2 -42
- package/dist/schema-evolution-guard.js +5 -5
- package/dist/secret-scanner/index.d.ts +32 -0
- package/dist/secret-scanner/index.d.ts.map +1 -0
- package/dist/secret-scanner.d.ts +2 -34
- package/dist/secret-scanner.js +3 -2
- package/dist/security-hotspot-scanner/index.d.ts +28 -0
- package/dist/security-hotspot-scanner/index.d.ts.map +1 -0
- package/dist/security-hotspot-scanner.d.ts +2 -30
- package/dist/security-hotspot-scanner.js +6 -6
- package/dist/semantic-search-indexer/index.d.ts +36 -0
- package/dist/semantic-search-indexer/index.d.ts.map +1 -0
- package/dist/semantic-search-indexer.d.ts +2 -38
- package/dist/semantic-search-indexer.js +22 -6
- package/dist/semver-bump/index.d.ts +24 -0
- package/dist/semver-bump/index.d.ts.map +1 -0
- package/dist/semver-bump.d.ts +2 -26
- package/dist/semver-bump.js +10 -8
- package/dist/session-recap/index.d.ts +48 -0
- package/dist/session-recap/index.d.ts.map +1 -0
- package/dist/session-recap.d.ts +2 -50
- package/dist/session-recap.js +6 -4
- package/dist/shell-check/index.d.ts +14 -0
- package/dist/shell-check/index.d.ts.map +1 -0
- package/dist/shell-check.d.ts +2 -16
- package/dist/shell-check.js +6 -6
- package/dist/smart-rename/index.d.ts +24 -0
- package/dist/smart-rename/index.d.ts.map +1 -0
- package/dist/smart-rename.d.ts +2 -26
- package/dist/smart-rename.js +5 -5
- package/dist/spec-linker/index.d.ts +49 -0
- package/dist/spec-linker/index.d.ts.map +1 -0
- package/dist/spec-linker.d.ts +2 -51
- package/dist/spec-linker.js +20086 -244
- package/dist/template-engine/index.d.ts +13 -0
- package/dist/template-engine/index.d.ts.map +1 -0
- package/dist/template-engine.d.ts +2 -15
- package/dist/template-engine.js +7 -7
- package/dist/test-coverage-gate/index.d.ts +35 -0
- package/dist/test-coverage-gate/index.d.ts.map +1 -0
- package/dist/test-coverage-gate.d.ts +2 -37
- package/dist/test-coverage-gate.js +5 -5
- package/dist/test-flake-detector/index.d.ts +25 -0
- package/dist/test-flake-detector/index.d.ts.map +1 -0
- package/dist/test-flake-detector.d.ts +2 -27
- package/dist/test-flake-detector.js +98 -13
- package/dist/test-generator/index.d.ts +30 -0
- package/dist/test-generator/index.d.ts.map +1 -0
- package/dist/test-generator.d.ts +2 -32
- package/dist/test-generator.js +19 -20
- package/dist/test-runner-gate/index.d.ts +35 -0
- package/dist/test-runner-gate/index.d.ts.map +1 -0
- package/dist/test-runner-gate.d.ts +2 -37
- package/dist/test-runner-gate.js +6 -6
- package/dist/todo-listener/index.d.ts +35 -0
- package/dist/todo-listener/index.d.ts.map +1 -0
- package/dist/todo-listener.d.ts +2 -37
- package/dist/todo-listener.js +3 -2
- package/dist/todo-tracker/index.d.ts +4 -0
- package/dist/todo-tracker/index.d.ts.map +1 -0
- package/dist/todo-tracker.d.ts +2 -5
- package/dist/todo-tracker.js +5 -5
- package/dist/token-budget/index.d.ts +38 -0
- package/dist/token-budget/index.d.ts.map +1 -0
- package/dist/token-budget.d.ts +2 -40
- package/dist/token-budget.js +3 -2
- package/dist/token-throttle/index.d.ts +52 -0
- package/dist/token-throttle/index.d.ts.map +1 -0
- package/dist/token-throttle.d.ts +2 -54
- package/dist/token-throttle.js +6 -2
- package/dist/type-gate/index.d.ts +35 -0
- package/dist/type-gate/index.d.ts.map +1 -0
- package/dist/type-gate.d.ts +2 -37
- package/dist/type-gate.js +236 -43
- package/package.json +10 -7
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @wrongstack/plugins — Language-agnostic runtime helper.
|
|
3
|
+
*
|
|
4
|
+
* Plugins that need to invoke a build-time or test-time tool
|
|
5
|
+
* (TypeScript's `tsc`, Node's `vitest`, Python's `pytest`, Rust's
|
|
6
|
+
* `cargo`, Go's `go test`, etc.) share this module instead of
|
|
7
|
+
* re-implementing argv/sandbox/allowlist logic.
|
|
8
|
+
*
|
|
9
|
+
* Why one module instead of three plugin-local copies?
|
|
10
|
+
* - One audit surface for security-sensitive code: arg-splitting,
|
|
11
|
+
* sandboxing, execFile-with-shell-false, maxBuffer, timeout.
|
|
12
|
+
* - Plugins stay focused on their domain (linters, type-checkers,
|
|
13
|
+
* test runners); the runtime helper owns the cross-cutting concern.
|
|
14
|
+
* - New languages opt in by adding a `LanguageRuntime` entry; the
|
|
15
|
+
* plugin layer keeps working unchanged.
|
|
16
|
+
*
|
|
17
|
+
* The public API is intentionally small:
|
|
18
|
+
* - `LanguageRuntime`: declares which language a plugin targets.
|
|
19
|
+
* - `resolveRunnerCommand(runtime, command, options)`: validate +
|
|
20
|
+
* split a user-supplied command into a safe argv array.
|
|
21
|
+
* - `sanitizeRunnerPath(value, options)`: reject paths outside
|
|
22
|
+
* the project or that start with `-` (option smuggling).
|
|
23
|
+
* - `runRunnerCommand(argv, options)`: spawn the resolved argv
|
|
24
|
+
* with `shell:false`, capture stdout/stderr/code, and apply
|
|
25
|
+
* timeout/abort.
|
|
26
|
+
* - `probeRunner(runtime, argv, options)`: cheap availability check.
|
|
27
|
+
*
|
|
28
|
+
* Anything language-specific (flag tables, default commands,
|
|
29
|
+
* output parsing) stays in the plugin that owns that language.
|
|
30
|
+
*/
|
|
31
|
+
export type LanguageId = 'typescript' | 'javascript' | 'python' | 'go' | 'rust' | 'shell' | 'ruby' | 'java' | 'kotlin' | 'dotnet' | 'generic';
|
|
32
|
+
export type PackageManagerId = 'npm' | 'pnpm' | 'yarn' | 'bun' | 'pip' | 'poetry' | 'go' | 'cargo' | 'gem' | 'maven' | 'gradle' | 'dotnet' | 'none';
|
|
33
|
+
export interface LanguageRuntime {
|
|
34
|
+
/** Stable identifier for diagnostics and logging. */
|
|
35
|
+
id: LanguageId;
|
|
36
|
+
/**
|
|
37
|
+
* Default package manager launcher if the plugin must spawn a tool
|
|
38
|
+
* (e.g. `npx vitest` or `cargo test`). `none` means the executable
|
|
39
|
+
* itself is invoked directly (no launcher).
|
|
40
|
+
*/
|
|
41
|
+
packageManager: PackageManagerId;
|
|
42
|
+
/**
|
|
43
|
+
* Executable token that must appear as the second argv element when
|
|
44
|
+
* a launcher is used (e.g. `vitest` after `pnpm exec`, `test` after
|
|
45
|
+
* `cargo`). When `subcommands.length === 0` and the package manager
|
|
46
|
+
* has no subcommand step, this is also accepted as the head token.
|
|
47
|
+
*/
|
|
48
|
+
executable: string;
|
|
49
|
+
/**
|
|
50
|
+
* Allowlisted flag values, in addition to positional arguments and
|
|
51
|
+
* file paths. `null` means "no flag allowlist enforced" — every
|
|
52
|
+
* leading-dash token is still rejected, but no flag whitelist applies.
|
|
53
|
+
*/
|
|
54
|
+
allowedFlags: ReadonlySet<string> | null;
|
|
55
|
+
/**
|
|
56
|
+
* Optional list of subcommand tokens that may follow the launcher,
|
|
57
|
+
* e.g. `['exec']` for `pnpm exec tsc`. Empty array means the runner
|
|
58
|
+
* executable must appear immediately as the second token (e.g.
|
|
59
|
+
* `cargo test`, `go test`).
|
|
60
|
+
*/
|
|
61
|
+
subcommands: readonly string[];
|
|
62
|
+
/**
|
|
63
|
+
* Default command spelling for `resolveRunnerCommand` when no
|
|
64
|
+
* custom command is supplied. Plugins can override via config.
|
|
65
|
+
*/
|
|
66
|
+
defaultCommand: string;
|
|
67
|
+
}
|
|
68
|
+
export interface ResolvedCommand {
|
|
69
|
+
cmd: string;
|
|
70
|
+
args: readonly string[];
|
|
71
|
+
display: string;
|
|
72
|
+
}
|
|
73
|
+
export interface ResolveOptions {
|
|
74
|
+
/**
|
|
75
|
+
* Project root used to sandbox absolute executable paths. Defaults
|
|
76
|
+
* to `process.cwd()`. Absolute executable paths must resolve inside
|
|
77
|
+
* this directory; relative basenames must match `LanguageRuntime.executable`.
|
|
78
|
+
*/
|
|
79
|
+
projectRoot?: string;
|
|
80
|
+
}
|
|
81
|
+
export interface RunOptions extends ResolveOptions {
|
|
82
|
+
cwd: string;
|
|
83
|
+
timeoutMs: number;
|
|
84
|
+
signal?: AbortSignal;
|
|
85
|
+
}
|
|
86
|
+
export interface RunResult {
|
|
87
|
+
code: number | null;
|
|
88
|
+
stdout: string;
|
|
89
|
+
stderr: string;
|
|
90
|
+
timedOut: boolean;
|
|
91
|
+
/** True when the executable could not be spawned (ENOENT, EPERM, …). */
|
|
92
|
+
spawnError: boolean;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Validate `value` as a sandboxed path inside the project. Returns the
|
|
96
|
+
* canonical absolute path on success, `null` on rejection (empty,
|
|
97
|
+
* outside the project, leading-dash, or longer than 4096 bytes).
|
|
98
|
+
*/
|
|
99
|
+
export declare function sanitizeRunnerPath(value: string, options?: ResolveOptions): string | null;
|
|
100
|
+
/**
|
|
101
|
+
* Resolve a user-supplied command string into an argv-style invocation
|
|
102
|
+
* using the language runtime's allowlist. Returns `null` if the command
|
|
103
|
+
* fails closed (unknown launcher, unknown subcommand, disallowed flag,
|
|
104
|
+
* metacharacters, leading-dash injection, absolute-path escape).
|
|
105
|
+
*/
|
|
106
|
+
export declare function resolveRunnerCommand(runtime: LanguageRuntime, command: string, options?: ResolveOptions): ResolvedCommand | null;
|
|
107
|
+
/**
|
|
108
|
+
* Spawn the resolved argv with `shell:false`. Always uses
|
|
109
|
+
* `execFile` (no shell, argv), captures stdout/stderr with a hard
|
|
110
|
+
* `maxBuffer`, and respects `signal` + `timeoutMs`. Plugins can layer
|
|
111
|
+
* language-specific output parsing on top of `RunResult`.
|
|
112
|
+
*/
|
|
113
|
+
export declare function runRunnerCommand(argv: readonly string[], options: RunOptions): Promise<RunResult>;
|
|
114
|
+
/**
|
|
115
|
+
* Cheap availability check. Calls the runner's `--version`-like command
|
|
116
|
+
* with a short timeout; returns true only when exit code is zero.
|
|
117
|
+
*/
|
|
118
|
+
export declare function probeRunner(runtime: LanguageRuntime, probeArg: string | undefined, options: RunOptions): Promise<boolean>;
|
|
119
|
+
/**
|
|
120
|
+
* Convenience: locate the runner binary on disk inside the project.
|
|
121
|
+
* Returns the absolute path or `null`.
|
|
122
|
+
*/
|
|
123
|
+
export declare function locateRunnerEntry(runtime: LanguageRuntime, projectRoot: string): string | null;
|
|
124
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/runtime/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAMH,MAAM,MAAM,UAAU,GAClB,YAAY,GACZ,YAAY,GACZ,QAAQ,GACR,IAAI,GACJ,MAAM,GACN,OAAO,GACP,MAAM,GACN,MAAM,GACN,QAAQ,GACR,QAAQ,GACR,SAAS,CAAC;AAEd,MAAM,MAAM,gBAAgB,GACxB,KAAK,GACL,MAAM,GACN,MAAM,GACN,KAAK,GACL,KAAK,GACL,QAAQ,GACR,IAAI,GACJ,OAAO,GACP,KAAK,GACL,OAAO,GACP,QAAQ,GACR,QAAQ,GACR,MAAM,CAAC;AAEX,MAAM,WAAW,eAAe;IAC9B,qDAAqD;IACrD,EAAE,EAAE,UAAU,CAAC;IACf;;;;OAIG;IACH,cAAc,EAAE,gBAAgB,CAAC;IACjC;;;;;OAKG;IACH,UAAU,EAAE,MAAM,CAAC;IACnB;;;;OAIG;IACH,YAAY,EAAE,WAAW,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC;IACzC;;;;;OAKG;IACH,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;IAC/B;;;OAGG;IACH,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,eAAe;IAC9B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IACxB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,cAAc;IAC7B;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,UAAW,SAAQ,cAAc;IAChD,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,OAAO,CAAC;IAClB,wEAAwE;IACxE,UAAU,EAAE,OAAO,CAAC;CACrB;AAkDD;;;;GAIG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,cAAmB,GAC3B,MAAM,GAAG,IAAI,CAKf;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,eAAe,EACxB,OAAO,EAAE,MAAM,EACf,OAAO,GAAE,cAAmB,GAC3B,eAAe,GAAG,IAAI,CAoExB;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,OAAO,EAAE,UAAU,GAClB,OAAO,CAAC,SAAS,CAAC,CAwHpB;AAED;;;GAGG;AACH,wBAAsB,WAAW,CAC/B,OAAO,EAAE,eAAe,EACxB,QAAQ,EAAE,MAAM,YAAc,EAC9B,OAAO,EAAE,UAAU,GAClB,OAAO,CAAC,OAAO,CAAC,CAQlB;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,eAAe,EACxB,WAAW,EAAE,MAAM,GAClB,MAAM,GAAG,IAAI,CAWf"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './runtime/index.js';
|
package/dist/runtime.js
ADDED
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
// src/runtime/index.ts
|
|
2
|
+
import { execFile } from "node:child_process";
|
|
3
|
+
import { existsSync } from "node:fs";
|
|
4
|
+
import { basename, isAbsolute, relative, resolve } from "node:path";
|
|
5
|
+
var META_CHARS = /["'`;&|<>\r\n]/;
|
|
6
|
+
var MAX_BUFFER_BYTES = 16 * 1024 * 1024;
|
|
7
|
+
function hasLeadingDash(arg) {
|
|
8
|
+
return arg.length > 0 && arg.startsWith("-");
|
|
9
|
+
}
|
|
10
|
+
function safeSplit(command) {
|
|
11
|
+
const trimmed = command.trim();
|
|
12
|
+
if (!trimmed || META_CHARS.test(trimmed)) return null;
|
|
13
|
+
return trimmed.split(/\s+/).filter(Boolean);
|
|
14
|
+
}
|
|
15
|
+
function withinProjectPath(projectRoot, candidate) {
|
|
16
|
+
if (candidate.length === 0 || candidate.length > 4096) return false;
|
|
17
|
+
if (hasLeadingDash(candidate)) return false;
|
|
18
|
+
const resolved = isAbsolute(candidate) ? resolve(candidate) : resolve(projectRoot, candidate);
|
|
19
|
+
const rel = relative(projectRoot, resolved);
|
|
20
|
+
return rel === "" || !rel.startsWith("..") && !isAbsolute(rel);
|
|
21
|
+
}
|
|
22
|
+
function everyFlagAllowed(allowed, args) {
|
|
23
|
+
for (const arg of args) {
|
|
24
|
+
if (!hasLeadingDash(arg)) continue;
|
|
25
|
+
if (allowed === null) return false;
|
|
26
|
+
if (!allowed.has(arg)) return false;
|
|
27
|
+
}
|
|
28
|
+
return true;
|
|
29
|
+
}
|
|
30
|
+
function sanitizeRunnerPath(value, options = {}) {
|
|
31
|
+
if (!value || hasLeadingDash(value)) return null;
|
|
32
|
+
const projectRoot = resolve(options.projectRoot ?? process.cwd());
|
|
33
|
+
if (!withinProjectPath(projectRoot, value)) return null;
|
|
34
|
+
return isAbsolute(value) ? resolve(value) : resolve(projectRoot, value);
|
|
35
|
+
}
|
|
36
|
+
function resolveRunnerCommand(runtime, command, options = {}) {
|
|
37
|
+
const tokens = safeSplit(command);
|
|
38
|
+
if (!tokens || tokens.length === 0) return null;
|
|
39
|
+
const projectRoot = resolve(options.projectRoot ?? process.cwd());
|
|
40
|
+
const launcher = runtime.packageManager;
|
|
41
|
+
const [head, second, ...rest] = tokens;
|
|
42
|
+
if (!head) return null;
|
|
43
|
+
const display = tokens.join(" ");
|
|
44
|
+
if (launcher !== "none" && tokens.length === 1 && head === launcher) {
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
if (head === runtime.executable) {
|
|
48
|
+
if (!everyFlagAllowed(runtime.allowedFlags, [second, ...rest].filter((v) => Boolean(v)))) {
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
return {
|
|
52
|
+
cmd: head,
|
|
53
|
+
args: [second, ...rest].filter((v) => Boolean(v)),
|
|
54
|
+
display
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
if (launcher !== "none" && head === launcher && runtime.subcommands.length === 0 && second === runtime.executable) {
|
|
58
|
+
if (!everyFlagAllowed(runtime.allowedFlags, rest)) return null;
|
|
59
|
+
return { cmd: head, args: [second, ...rest], display };
|
|
60
|
+
}
|
|
61
|
+
if (launcher !== "none" && head === launcher && runtime.subcommands.length > 0) {
|
|
62
|
+
const subcommand = runtime.subcommands[0];
|
|
63
|
+
const exe = rest[0];
|
|
64
|
+
if (second === subcommand && exe === runtime.executable) {
|
|
65
|
+
const tail = rest.slice(1);
|
|
66
|
+
if (!everyFlagAllowed(runtime.allowedFlags, tail)) return null;
|
|
67
|
+
return { cmd: head, args: [second, exe, ...tail], display };
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
if (isAbsolute(head)) {
|
|
71
|
+
if (!withinProjectPath(projectRoot, head)) return null;
|
|
72
|
+
const base = basename(head);
|
|
73
|
+
if (base !== runtime.executable && base !== launcher) return null;
|
|
74
|
+
if (second !== runtime.executable) return null;
|
|
75
|
+
if (!everyFlagAllowed(runtime.allowedFlags, rest)) return null;
|
|
76
|
+
return { cmd: head, args: [second, ...rest], display };
|
|
77
|
+
}
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
function runRunnerCommand(argv, options) {
|
|
81
|
+
if (argv.length === 0) {
|
|
82
|
+
return Promise.resolve({
|
|
83
|
+
code: null,
|
|
84
|
+
stdout: "",
|
|
85
|
+
stderr: "runtime helper: empty argv",
|
|
86
|
+
timedOut: false,
|
|
87
|
+
spawnError: true
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
return new Promise((resolvePromise) => {
|
|
91
|
+
const projectRoot = resolve(options.projectRoot ?? process.cwd());
|
|
92
|
+
const trimmedCwd = options.cwd.trim();
|
|
93
|
+
if (!withinProjectPath(projectRoot, trimmedCwd)) {
|
|
94
|
+
resolvePromise({
|
|
95
|
+
code: null,
|
|
96
|
+
stdout: "",
|
|
97
|
+
stderr: "runtime helper: cwd outside project",
|
|
98
|
+
timedOut: false,
|
|
99
|
+
spawnError: true
|
|
100
|
+
});
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
const timedOut = false;
|
|
104
|
+
let spawnErrored = false;
|
|
105
|
+
const stdoutChunks = [];
|
|
106
|
+
const stderrChunks = [];
|
|
107
|
+
let stdoutBytes = 0;
|
|
108
|
+
let stderrBytes = 0;
|
|
109
|
+
const child = execFile(
|
|
110
|
+
argv[0],
|
|
111
|
+
argv.slice(1),
|
|
112
|
+
{
|
|
113
|
+
cwd: trimmedCwd,
|
|
114
|
+
timeout: options.timeoutMs,
|
|
115
|
+
signal: options.signal,
|
|
116
|
+
maxBuffer: MAX_BUFFER_BYTES,
|
|
117
|
+
windowsHide: true,
|
|
118
|
+
shell: false
|
|
119
|
+
},
|
|
120
|
+
(err, stdout, stderr) => {
|
|
121
|
+
if (timedOut) {
|
|
122
|
+
resolvePromise({
|
|
123
|
+
code: null,
|
|
124
|
+
stdout: Buffer.concat([...stdoutChunks, ...Buffer.isBuffer(stdout) ? [stdout] : [Buffer.from(stdout)]]).toString("utf8"),
|
|
125
|
+
stderr: Buffer.concat([...stderrChunks, ...Buffer.isBuffer(stderr) ? [stderr] : [Buffer.from(stderr)]]).toString("utf8"),
|
|
126
|
+
timedOut: true,
|
|
127
|
+
spawnError: false
|
|
128
|
+
});
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
if (spawnErrored) {
|
|
132
|
+
resolvePromise({
|
|
133
|
+
code: 127,
|
|
134
|
+
stdout: Buffer.concat([...stdoutChunks, ...Buffer.isBuffer(stdout) ? [stdout] : [Buffer.from(stdout)]]).toString("utf8"),
|
|
135
|
+
stderr: Buffer.concat([...stderrChunks, ...Buffer.isBuffer(stderr) ? [stderr] : [Buffer.from(stderr)]]).toString("utf8"),
|
|
136
|
+
timedOut: false,
|
|
137
|
+
spawnError: true
|
|
138
|
+
});
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
if (err) {
|
|
142
|
+
const anyErr = err;
|
|
143
|
+
const code = typeof anyErr.code === "number" ? anyErr.code : 1;
|
|
144
|
+
resolvePromise({
|
|
145
|
+
code,
|
|
146
|
+
stdout: Buffer.concat([
|
|
147
|
+
...stdoutChunks,
|
|
148
|
+
...anyErr.stdout ? [Buffer.isBuffer(anyErr.stdout) ? anyErr.stdout : Buffer.from(anyErr.stdout)] : []
|
|
149
|
+
]).toString("utf8"),
|
|
150
|
+
stderr: Buffer.concat([
|
|
151
|
+
...stderrChunks,
|
|
152
|
+
...anyErr.stderr ? [Buffer.isBuffer(anyErr.stderr) ? anyErr.stderr : Buffer.from(anyErr.stderr)] : []
|
|
153
|
+
]).toString("utf8"),
|
|
154
|
+
timedOut: false,
|
|
155
|
+
spawnError: false
|
|
156
|
+
});
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
resolvePromise({
|
|
160
|
+
code: 0,
|
|
161
|
+
stdout: Buffer.concat([
|
|
162
|
+
...stdoutChunks,
|
|
163
|
+
...Buffer.isBuffer(stdout) ? [stdout] : [Buffer.from(stdout)]
|
|
164
|
+
]).toString("utf8"),
|
|
165
|
+
stderr: Buffer.concat([
|
|
166
|
+
...stderrChunks,
|
|
167
|
+
...Buffer.isBuffer(stderr) ? [stderr] : [Buffer.from(stderr)]
|
|
168
|
+
]).toString("utf8"),
|
|
169
|
+
timedOut: false,
|
|
170
|
+
spawnError: false
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
);
|
|
174
|
+
child.stdout?.on("data", (chunk) => {
|
|
175
|
+
stdoutBytes += chunk.length;
|
|
176
|
+
if (stdoutBytes <= MAX_BUFFER_BYTES) stdoutChunks.push(chunk);
|
|
177
|
+
});
|
|
178
|
+
child.stderr?.on("data", (chunk) => {
|
|
179
|
+
stderrBytes += chunk.length;
|
|
180
|
+
if (stderrBytes <= MAX_BUFFER_BYTES) stderrChunks.push(chunk);
|
|
181
|
+
});
|
|
182
|
+
child.on("error", (err) => {
|
|
183
|
+
if (err.code === "ENOENT" || err.code === "EPERM" || err.code === "EACCES") {
|
|
184
|
+
spawnErrored = true;
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
async function probeRunner(runtime, probeArg = "--version", options) {
|
|
190
|
+
const resolved = resolveRunnerCommand(runtime, `${runtime.executable} ${probeArg}`, options);
|
|
191
|
+
if (!resolved) return false;
|
|
192
|
+
const result = await runRunnerCommand([resolved.cmd, ...resolved.args], {
|
|
193
|
+
...options,
|
|
194
|
+
timeoutMs: Math.min(options.timeoutMs, 5e3)
|
|
195
|
+
});
|
|
196
|
+
return result.code === 0;
|
|
197
|
+
}
|
|
198
|
+
function locateRunnerEntry(runtime, projectRoot) {
|
|
199
|
+
const root = resolve(projectRoot);
|
|
200
|
+
const candidates = [
|
|
201
|
+
resolve(root, "node_modules", ".bin", runtime.executable),
|
|
202
|
+
resolve(root, "node_modules", ".bin", `${runtime.executable}.cmd`),
|
|
203
|
+
resolve(root, "node_modules", ".bin", `${runtime.executable}.ps1`)
|
|
204
|
+
];
|
|
205
|
+
for (const c of candidates) {
|
|
206
|
+
if (existsSync(c)) return c;
|
|
207
|
+
}
|
|
208
|
+
return null;
|
|
209
|
+
}
|
|
210
|
+
export {
|
|
211
|
+
locateRunnerEntry,
|
|
212
|
+
probeRunner,
|
|
213
|
+
resolveRunnerCommand,
|
|
214
|
+
runRunnerCommand,
|
|
215
|
+
sanitizeRunnerPath
|
|
216
|
+
};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* schema-evolution-guard plugin — guards database/API schema changes.
|
|
3
|
+
*
|
|
4
|
+
* Registers a `PostToolUse` hook on `write|edit` that scans files matching
|
|
5
|
+
* schema-related patterns for destructive changes:
|
|
6
|
+
*
|
|
7
|
+
* - DROP TABLE / DROP COLUMN (Prisma migrations, raw SQL)
|
|
8
|
+
* - NOT NULL added without a default (SQL)
|
|
9
|
+
* - Required field without a default (Prisma, TypeScript schema files)
|
|
10
|
+
* - Required field added to an OpenAPI schema (YAML/JSON)
|
|
11
|
+
*
|
|
12
|
+
* When a destructive pattern is found the plugin either injects an
|
|
13
|
+
* `additionalContext` warning or blocks the tool, depending on `failSeverity`.
|
|
14
|
+
*
|
|
15
|
+
* Tools registered:
|
|
16
|
+
* - schema_evolution_status : counters + config snapshot.
|
|
17
|
+
*
|
|
18
|
+
* Config (`config.extensions['schema-evolution-guard']`):
|
|
19
|
+
*
|
|
20
|
+
* ```jsonc
|
|
21
|
+
* {
|
|
22
|
+
* "enabled": true,
|
|
23
|
+
* "failSeverity": "warn", // "warn" | "block"
|
|
24
|
+
* "maxFindings": 5,
|
|
25
|
+
* "filePatterns": [
|
|
26
|
+
* "*.prisma",
|
|
27
|
+
* "*migration*.sql",
|
|
28
|
+
* "*openapi*.yaml",
|
|
29
|
+
* "*openapi*.json",
|
|
30
|
+
* "*schema*.ts"
|
|
31
|
+
* ]
|
|
32
|
+
* }
|
|
33
|
+
* ```
|
|
34
|
+
*
|
|
35
|
+
* @public
|
|
36
|
+
*/
|
|
37
|
+
import type { Plugin } from '@wrongstack/core';
|
|
38
|
+
declare const plugin: Plugin;
|
|
39
|
+
export default plugin;
|
|
40
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/schema-evolution-guard/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAIH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAkN/C,QAAA,MAAM,MAAM,EAAE,MAgNb,CAAC;eAEa,MAAM"}
|
|
@@ -1,42 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* schema-evolution-guard plugin — guards database/API schema changes.
|
|
5
|
-
*
|
|
6
|
-
* Registers a `PostToolUse` hook on `write|edit` that scans files matching
|
|
7
|
-
* schema-related patterns for destructive changes:
|
|
8
|
-
*
|
|
9
|
-
* - DROP TABLE / DROP COLUMN (Prisma migrations, raw SQL)
|
|
10
|
-
* - NOT NULL added without a default (SQL)
|
|
11
|
-
* - Required field without a default (Prisma, TypeScript schema files)
|
|
12
|
-
* - Required field added to an OpenAPI schema (YAML/JSON)
|
|
13
|
-
*
|
|
14
|
-
* When a destructive pattern is found the plugin either injects an
|
|
15
|
-
* `additionalContext` warning or blocks the tool, depending on `failSeverity`.
|
|
16
|
-
*
|
|
17
|
-
* Tools registered:
|
|
18
|
-
* - schema_evolution_status : counters + config snapshot.
|
|
19
|
-
*
|
|
20
|
-
* Config (`config.extensions['schema-evolution-guard']`):
|
|
21
|
-
*
|
|
22
|
-
* ```jsonc
|
|
23
|
-
* {
|
|
24
|
-
* "enabled": true,
|
|
25
|
-
* "failSeverity": "warn", // "warn" | "block"
|
|
26
|
-
* "maxFindings": 5,
|
|
27
|
-
* "filePatterns": [
|
|
28
|
-
* "*.prisma",
|
|
29
|
-
* "*migration*.sql",
|
|
30
|
-
* "*openapi*.yaml",
|
|
31
|
-
* "*openapi*.json",
|
|
32
|
-
* "*schema*.ts"
|
|
33
|
-
* ]
|
|
34
|
-
* }
|
|
35
|
-
* ```
|
|
36
|
-
*
|
|
37
|
-
* @public
|
|
38
|
-
*/
|
|
39
|
-
|
|
40
|
-
declare const plugin: Plugin;
|
|
41
|
-
|
|
42
|
-
export { plugin as default };
|
|
1
|
+
export * from './schema-evolution-guard/index.js';
|
|
2
|
+
export { default } from './schema-evolution-guard/index.js';
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import { readFileSync } from 'fs';
|
|
2
|
-
import { basename, isAbsolute, resolve, relative } from 'path';
|
|
3
|
-
|
|
4
1
|
// src/schema-evolution-guard/index.ts
|
|
2
|
+
import { readFileSync } from "node:fs";
|
|
3
|
+
import { basename, isAbsolute, relative, resolve } from "node:path";
|
|
5
4
|
var API_VERSION = "^0.1.10";
|
|
6
5
|
var state = {
|
|
7
6
|
invocationCount: 0,
|
|
@@ -315,5 +314,6 @@ ${body}${suffix}`;
|
|
|
315
314
|
}
|
|
316
315
|
};
|
|
317
316
|
var schema_evolution_guard_default = plugin;
|
|
318
|
-
|
|
319
|
-
|
|
317
|
+
export {
|
|
318
|
+
schema_evolution_guard_default as default
|
|
319
|
+
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* secret-scanner plugin — Pre-tool and post-tool hooks that block, redact,
|
|
3
|
+
* or warn about plaintext credentials flowing into or out of tools.
|
|
4
|
+
*
|
|
5
|
+
* Tools registered:
|
|
6
|
+
* - secret_scanner_status : Show which patterns are active, recent
|
|
7
|
+
* blocks/leaks, and current mode.
|
|
8
|
+
* - secret_scanner_test : Run the scanner against a user-supplied
|
|
9
|
+
* string and report which patterns matched.
|
|
10
|
+
*
|
|
11
|
+
* Hooks registered:
|
|
12
|
+
* - PreToolUse with matcher `bash|write|edit` (configurable). Default
|
|
13
|
+
* action is to BLOCK; the plugin can also auto-redact the offending
|
|
14
|
+
* fields via `HookOutcome.modifiedInput`.
|
|
15
|
+
* - PostToolUse with matcher `*` (configurable via `postToolUseMatcher`).
|
|
16
|
+
* Scans tool OUTPUT for secrets that leaked through. Since the tool
|
|
17
|
+
* has already run, the hook cannot block — instead it injects an
|
|
18
|
+
* `additionalContext` warning so the LLM knows the output contains
|
|
19
|
+
* a secret and should NOT echo it, store it, or commit it.
|
|
20
|
+
*
|
|
21
|
+
* Why a separate plugin from the built-in `DefaultSecretScrubber`?
|
|
22
|
+
* The scrubber is *output* sanitization (replace secrets with
|
|
23
|
+
* `[REDACTED:type]` before they leave the system). The scanner is
|
|
24
|
+
* *prevention* (stop the tool from running with a secret in the first
|
|
25
|
+
* place) + *detection* (flag secrets that leaked through the output).
|
|
26
|
+
* They share the same threat model but act at different points in the
|
|
27
|
+
* pipeline.
|
|
28
|
+
*/
|
|
29
|
+
import type { Plugin } from '@wrongstack/core';
|
|
30
|
+
declare const plugin: Plugin;
|
|
31
|
+
export default plugin;
|
|
32
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/secret-scanner/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAua/C,QAAA,MAAM,MAAM,EAAE,MAgOb,CAAC;eAEa,MAAM"}
|
package/dist/secret-scanner.d.ts
CHANGED
|
@@ -1,34 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* secret-scanner plugin — Pre-tool and post-tool hooks that block, redact,
|
|
5
|
-
* or warn about plaintext credentials flowing into or out of tools.
|
|
6
|
-
*
|
|
7
|
-
* Tools registered:
|
|
8
|
-
* - secret_scanner_status : Show which patterns are active, recent
|
|
9
|
-
* blocks/leaks, and current mode.
|
|
10
|
-
* - secret_scanner_test : Run the scanner against a user-supplied
|
|
11
|
-
* string and report which patterns matched.
|
|
12
|
-
*
|
|
13
|
-
* Hooks registered:
|
|
14
|
-
* - PreToolUse with matcher `bash|write|edit` (configurable). Default
|
|
15
|
-
* action is to BLOCK; the plugin can also auto-redact the offending
|
|
16
|
-
* fields via `HookOutcome.modifiedInput`.
|
|
17
|
-
* - PostToolUse with matcher `*` (configurable via `postToolUseMatcher`).
|
|
18
|
-
* Scans tool OUTPUT for secrets that leaked through. Since the tool
|
|
19
|
-
* has already run, the hook cannot block — instead it injects an
|
|
20
|
-
* `additionalContext` warning so the LLM knows the output contains
|
|
21
|
-
* a secret and should NOT echo it, store it, or commit it.
|
|
22
|
-
*
|
|
23
|
-
* Why a separate plugin from the built-in `DefaultSecretScrubber`?
|
|
24
|
-
* The scrubber is *output* sanitization (replace secrets with
|
|
25
|
-
* `[REDACTED:type]` before they leave the system). The scanner is
|
|
26
|
-
* *prevention* (stop the tool from running with a secret in the first
|
|
27
|
-
* place) + *detection* (flag secrets that leaked through the output).
|
|
28
|
-
* They share the same threat model but act at different points in the
|
|
29
|
-
* pipeline.
|
|
30
|
-
*/
|
|
31
|
-
|
|
32
|
-
declare const plugin: Plugin;
|
|
33
|
-
|
|
34
|
-
export { plugin as default };
|
|
1
|
+
export * from './secret-scanner/index.js';
|
|
2
|
+
export { default } from './secret-scanner/index.js';
|
package/dist/secret-scanner.js
CHANGED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* security-hotspot-scanner plugin — scans source code for common security
|
|
3
|
+
* anti-patterns and reports them via tools + a PostToolUse hook.
|
|
4
|
+
*
|
|
5
|
+
* Tools registered:
|
|
6
|
+
* - security_hotspot_scan : scan a file or directory for security hotspots
|
|
7
|
+
* - security_hotspot_status : config + per-session counters
|
|
8
|
+
*
|
|
9
|
+
* Hooks registered:
|
|
10
|
+
* - PostToolUse with matcher `write|edit` to warn about newly introduced hotspots.
|
|
11
|
+
*
|
|
12
|
+
* Config (`config.extensions['security-hotspot-scanner']`):
|
|
13
|
+
*
|
|
14
|
+
* ```jsonc
|
|
15
|
+
* {
|
|
16
|
+
* "enabled": true,
|
|
17
|
+
* "severity": "warn", // "warn" | "block"
|
|
18
|
+
* "maxFindings": 10,
|
|
19
|
+
* "scanOnChange": [".js", ".jsx", ".ts", ".tsx", ".mjs", ".cjs", ".py"]
|
|
20
|
+
* }
|
|
21
|
+
* ```
|
|
22
|
+
*
|
|
23
|
+
* @public
|
|
24
|
+
*/
|
|
25
|
+
import type { Plugin } from '@wrongstack/core';
|
|
26
|
+
declare const plugin: Plugin;
|
|
27
|
+
export default plugin;
|
|
28
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/security-hotspot-scanner/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAIH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAwQ/C,QAAA,MAAM,MAAM,EAAE,MAiQb,CAAC;eAEa,MAAM"}
|
|
@@ -1,30 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* security-hotspot-scanner plugin — scans source code for common security
|
|
5
|
-
* anti-patterns and reports them via tools + a PostToolUse hook.
|
|
6
|
-
*
|
|
7
|
-
* Tools registered:
|
|
8
|
-
* - security_hotspot_scan : scan a file or directory for security hotspots
|
|
9
|
-
* - security_hotspot_status : config + per-session counters
|
|
10
|
-
*
|
|
11
|
-
* Hooks registered:
|
|
12
|
-
* - PostToolUse with matcher `write|edit` to warn about newly introduced hotspots.
|
|
13
|
-
*
|
|
14
|
-
* Config (`config.extensions['security-hotspot-scanner']`):
|
|
15
|
-
*
|
|
16
|
-
* ```jsonc
|
|
17
|
-
* {
|
|
18
|
-
* "enabled": true,
|
|
19
|
-
* "severity": "warn", // "warn" | "block"
|
|
20
|
-
* "maxFindings": 10,
|
|
21
|
-
* "scanOnChange": [".js", ".jsx", ".ts", ".tsx", ".mjs", ".cjs", ".py"]
|
|
22
|
-
* }
|
|
23
|
-
* ```
|
|
24
|
-
*
|
|
25
|
-
* @public
|
|
26
|
-
*/
|
|
27
|
-
|
|
28
|
-
declare const plugin: Plugin;
|
|
29
|
-
|
|
30
|
-
export { plugin as default };
|
|
1
|
+
export * from './security-hotspot-scanner/index.js';
|
|
2
|
+
export { default } from './security-hotspot-scanner/index.js';
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import { statSync, readdirSync, readFileSync } from 'fs';
|
|
2
|
-
import { isAbsolute, resolve, relative } from 'path';
|
|
3
|
-
|
|
4
1
|
// src/security-hotspot-scanner/index.ts
|
|
2
|
+
import { readdirSync, readFileSync, statSync } from "node:fs";
|
|
3
|
+
import { isAbsolute, relative, resolve } from "node:path";
|
|
5
4
|
var API_VERSION = "^0.1.10";
|
|
6
5
|
var state = {
|
|
7
6
|
scanCount: 0,
|
|
@@ -46,7 +45,7 @@ var PATTERNS = [
|
|
|
46
45
|
{
|
|
47
46
|
type: "hardcoded_http",
|
|
48
47
|
severity: "medium",
|
|
49
|
-
regex: /http:\/\/[a-zA-Z0-9][^\s'"
|
|
48
|
+
regex: /http:\/\/[a-zA-Z0-9][^\s'")\\]*/i
|
|
50
49
|
},
|
|
51
50
|
{
|
|
52
51
|
type: "console_log_credentials",
|
|
@@ -398,5 +397,6 @@ Review or remove the risky pattern(s).`;
|
|
|
398
397
|
}
|
|
399
398
|
};
|
|
400
399
|
var security_hotspot_scanner_default = plugin;
|
|
401
|
-
|
|
402
|
-
|
|
400
|
+
export {
|
|
401
|
+
security_hotspot_scanner_default as default
|
|
402
|
+
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* semantic-search-indexer plugin — lightweight keyword-based search over
|
|
3
|
+
* project source files.
|
|
4
|
+
*
|
|
5
|
+
* The plugin builds an in-memory inverted index (no persistence, no
|
|
6
|
+
* embeddings) and exposes two tools:
|
|
7
|
+
*
|
|
8
|
+
* - `semantic_search` — ranked keyword search with TF scoring
|
|
9
|
+
* - `semantic_index_status` — index counters and configuration
|
|
10
|
+
*
|
|
11
|
+
* Files are tokenized into lowercase alphanumeric terms and indexed with
|
|
12
|
+
* per-document term frequencies. Queries are scored by summing the TF of
|
|
13
|
+
* each matched query token, then results are returned with the matching
|
|
14
|
+
* file path, score, and a handful of matched lines.
|
|
15
|
+
*
|
|
16
|
+
* Config (`config.extensions['semantic-search-indexer']`):
|
|
17
|
+
*
|
|
18
|
+
* ```jsonc
|
|
19
|
+
* {
|
|
20
|
+
* "enabled": true,
|
|
21
|
+
* "includeExtensions": [".ts", ".tsx", ".js", ".jsx"],
|
|
22
|
+
* "excludePatterns": ["node_modules", "\\.git", "dist"],
|
|
23
|
+
* "maxFileBytes": 1_000_000,
|
|
24
|
+
* "defaultLimit": 10,
|
|
25
|
+
* "minTokenLength": 2,
|
|
26
|
+
* "maxMatchesPerFile": 10,
|
|
27
|
+
* "maxFiles": 5000
|
|
28
|
+
* }
|
|
29
|
+
* ```
|
|
30
|
+
*
|
|
31
|
+
* @public
|
|
32
|
+
*/
|
|
33
|
+
import type { Plugin } from '@wrongstack/core';
|
|
34
|
+
declare const plugin: Plugin;
|
|
35
|
+
export default plugin;
|
|
36
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/semantic-search-indexer/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAKH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AA6b/C,QAAA,MAAM,MAAM,EAAE,MA6Nb,CAAC;eAEa,MAAM"}
|