@owasp-aghast/aghast 0.8.3 → 0.9.0-rc.1

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.
Files changed (113) hide show
  1. package/config/pricing.json +39 -9
  2. package/dist/build-config.d.ts.map +1 -1
  3. package/dist/build-config.js +101 -2
  4. package/dist/build-config.js.map +1 -1
  5. package/dist/check-library.d.ts +25 -0
  6. package/dist/check-library.d.ts.map +1 -1
  7. package/dist/check-library.js +172 -1
  8. package/dist/check-library.js.map +1 -1
  9. package/dist/ci-metadata.d.ts +42 -0
  10. package/dist/ci-metadata.d.ts.map +1 -0
  11. package/dist/ci-metadata.js +131 -0
  12. package/dist/ci-metadata.js.map +1 -0
  13. package/dist/claude-code-provider.d.ts +7 -0
  14. package/dist/claude-code-provider.d.ts.map +1 -1
  15. package/dist/claude-code-provider.js +65 -1
  16. package/dist/claude-code-provider.js.map +1 -1
  17. package/dist/cli.js +4 -1
  18. package/dist/cli.js.map +1 -1
  19. package/dist/concurrency.d.ts +18 -0
  20. package/dist/concurrency.d.ts.map +1 -0
  21. package/dist/concurrency.js +39 -0
  22. package/dist/concurrency.js.map +1 -0
  23. package/dist/cost-tracker.d.ts +45 -0
  24. package/dist/cost-tracker.d.ts.map +1 -0
  25. package/dist/cost-tracker.js +56 -0
  26. package/dist/cost-tracker.js.map +1 -0
  27. package/dist/discoveries/glob-discovery.d.ts +21 -0
  28. package/dist/discoveries/glob-discovery.d.ts.map +1 -0
  29. package/dist/discoveries/glob-discovery.js +215 -0
  30. package/dist/discoveries/glob-discovery.js.map +1 -0
  31. package/dist/discoveries/script-discovery.d.ts +117 -0
  32. package/dist/discoveries/script-discovery.d.ts.map +1 -0
  33. package/dist/discoveries/script-discovery.js +593 -0
  34. package/dist/discoveries/script-discovery.js.map +1 -0
  35. package/dist/docs-url.d.ts +14 -0
  36. package/dist/docs-url.d.ts.map +1 -0
  37. package/dist/docs-url.js +17 -0
  38. package/dist/docs-url.js.map +1 -0
  39. package/dist/error-codes.d.ts +12 -1
  40. package/dist/error-codes.d.ts.map +1 -1
  41. package/dist/error-codes.js +16 -2
  42. package/dist/error-codes.js.map +1 -1
  43. package/dist/formatters/csv-formatter.d.ts +45 -0
  44. package/dist/formatters/csv-formatter.d.ts.map +1 -0
  45. package/dist/formatters/csv-formatter.js +176 -0
  46. package/dist/formatters/csv-formatter.js.map +1 -0
  47. package/dist/formatters/html-formatter.d.ts +39 -0
  48. package/dist/formatters/html-formatter.d.ts.map +1 -0
  49. package/dist/formatters/html-formatter.js +432 -0
  50. package/dist/formatters/html-formatter.js.map +1 -0
  51. package/dist/formatters/index.d.ts.map +1 -1
  52. package/dist/formatters/index.js +6 -0
  53. package/dist/formatters/index.js.map +1 -1
  54. package/dist/formatters/markdown-formatter.d.ts +61 -0
  55. package/dist/formatters/markdown-formatter.d.ts.map +1 -0
  56. package/dist/formatters/markdown-formatter.js +557 -0
  57. package/dist/formatters/markdown-formatter.js.map +1 -0
  58. package/dist/formatters/sarif-formatter.d.ts +7 -0
  59. package/dist/formatters/sarif-formatter.d.ts.map +1 -1
  60. package/dist/formatters/sarif-formatter.js +80 -0
  61. package/dist/formatters/sarif-formatter.js.map +1 -1
  62. package/dist/formatters/types.d.ts +24 -0
  63. package/dist/formatters/types.d.ts.map +1 -1
  64. package/dist/index.d.ts +4 -0
  65. package/dist/index.d.ts.map +1 -1
  66. package/dist/index.js +365 -10
  67. package/dist/index.js.map +1 -1
  68. package/dist/issue-file-writer.d.ts +21 -0
  69. package/dist/issue-file-writer.d.ts.map +1 -0
  70. package/dist/issue-file-writer.js +307 -0
  71. package/dist/issue-file-writer.js.map +1 -0
  72. package/dist/judge.d.ts +62 -0
  73. package/dist/judge.d.ts.map +1 -0
  74. package/dist/judge.js +305 -0
  75. package/dist/judge.js.map +1 -0
  76. package/dist/mock-agent-provider.d.ts +3 -0
  77. package/dist/mock-agent-provider.d.ts.map +1 -1
  78. package/dist/mock-agent-provider.js +13 -0
  79. package/dist/mock-agent-provider.js.map +1 -1
  80. package/dist/new-check.d.ts.map +1 -1
  81. package/dist/new-check.js +334 -22
  82. package/dist/new-check.js.map +1 -1
  83. package/dist/opencode-provider.d.ts.map +1 -1
  84. package/dist/opencode-provider.js +33 -0
  85. package/dist/opencode-provider.js.map +1 -1
  86. package/dist/repo-scan.d.ts +80 -0
  87. package/dist/repo-scan.d.ts.map +1 -0
  88. package/dist/repo-scan.js +250 -0
  89. package/dist/repo-scan.js.map +1 -0
  90. package/dist/result-handlers/pr-comment-handler.d.ts +136 -0
  91. package/dist/result-handlers/pr-comment-handler.d.ts.map +1 -0
  92. package/dist/result-handlers/pr-comment-handler.js +381 -0
  93. package/dist/result-handlers/pr-comment-handler.js.map +1 -0
  94. package/dist/retry.d.ts +128 -0
  95. package/dist/retry.d.ts.map +1 -0
  96. package/dist/retry.js +261 -0
  97. package/dist/retry.js.map +1 -0
  98. package/dist/runtime-config.d.ts.map +1 -1
  99. package/dist/runtime-config.js +62 -0
  100. package/dist/runtime-config.js.map +1 -1
  101. package/dist/scan-runner.d.ts +31 -22
  102. package/dist/scan-runner.d.ts.map +1 -1
  103. package/dist/scan-runner.js +145 -100
  104. package/dist/scan-runner.js.map +1 -1
  105. package/dist/semgrep-runner.js +6 -4
  106. package/dist/semgrep-runner.js.map +1 -1
  107. package/dist/stats.d.ts.map +1 -1
  108. package/dist/stats.js +4 -1
  109. package/dist/stats.js.map +1 -1
  110. package/dist/types.d.ts +149 -2
  111. package/dist/types.d.ts.map +1 -1
  112. package/dist/types.js.map +1 -1
  113. package/package.json +1 -1
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Shared cost-tracking utilities for the scan runner and judge stage.
3
+ */
4
+ import { type PricingConfig, type CostBreakdown } from './cost-calculator.js';
5
+ import { type BudgetLimits } from './budget.js';
6
+ import type { TokenUsage } from './types.js';
7
+ import type { ScanRecord } from './scan-history.js';
8
+ /**
9
+ * Tracks accumulated tokens/cost across a scan so the budget can be evaluated
10
+ * before each AI call. Mutated in place by AI invocations.
11
+ */
12
+ export interface ScanCostTracker {
13
+ pricing?: PricingConfig;
14
+ budgetLimits?: BudgetLimits;
15
+ scanHistory?: ScanRecord[];
16
+ totalTokens: number;
17
+ totalCostUsd: number;
18
+ /** Cost source from the last recorded AI call. Used for banner labelling. */
19
+ lastCostSource?: CostBreakdown['source'];
20
+ lastCostReportedBy?: CostBreakdown['reportedBy'];
21
+ lastCostCoveredBySubscription?: boolean;
22
+ /** Set true after the first warn so we don't log it repeatedly. */
23
+ warned: boolean;
24
+ /** Most recent budget action returned to the runner. */
25
+ lastAction: 'continue' | 'warn' | 'abort';
26
+ /** Reason from the most recent non-continue check. */
27
+ lastReason?: string;
28
+ }
29
+ export declare function createCostTracker(options: {
30
+ pricing?: PricingConfig;
31
+ budgetLimits?: BudgetLimits;
32
+ scanHistory?: ScanRecord[];
33
+ }): ScanCostTracker;
34
+ /**
35
+ * Record an AI call's token usage against the tracker. Called after each
36
+ * successful executeCheck().
37
+ */
38
+ export declare function recordUsage(tracker: ScanCostTracker, usage: TokenUsage | undefined, model: string): void;
39
+ /**
40
+ * Check the budget before an AI call. Logs a warning the first time the warn
41
+ * threshold is crossed; throws BudgetExceededError when the abort threshold is
42
+ * crossed.
43
+ */
44
+ export declare function preflightBudget(tracker: ScanCostTracker): void;
45
+ //# sourceMappingURL=cost-tracker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cost-tracker.d.ts","sourceRoot":"","sources":["../src/cost-tracker.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAiB,KAAK,aAAa,EAAE,KAAK,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAC7F,OAAO,EAAoC,KAAK,YAAY,EAAE,MAAM,aAAa,CAAC;AAElF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAIpD;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC9B,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,WAAW,CAAC,EAAE,UAAU,EAAE,CAAC;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,6EAA6E;IAC7E,cAAc,CAAC,EAAE,aAAa,CAAC,QAAQ,CAAC,CAAC;IACzC,kBAAkB,CAAC,EAAE,aAAa,CAAC,YAAY,CAAC,CAAC;IACjD,6BAA6B,CAAC,EAAE,OAAO,CAAC;IACxC,mEAAmE;IACnE,MAAM,EAAE,OAAO,CAAC;IAChB,wDAAwD;IACxD,UAAU,EAAE,UAAU,GAAG,MAAM,GAAG,OAAO,CAAC;IAC1C,sDAAsD;IACtD,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,wBAAgB,iBAAiB,CAAC,OAAO,EAAE;IACzC,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,WAAW,CAAC,EAAE,UAAU,EAAE,CAAC;CAC5B,GAAG,eAAe,CAUlB;AAED;;;GAGG;AACH,wBAAgB,WAAW,CACzB,OAAO,EAAE,eAAe,EACxB,KAAK,EAAE,UAAU,GAAG,SAAS,EAC7B,KAAK,EAAE,MAAM,GACZ,IAAI,CAQN;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,eAAe,GAAG,IAAI,CAmB9D"}
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Shared cost-tracking utilities for the scan runner and judge stage.
3
+ */
4
+ import { calculateCost } from './cost-calculator.js';
5
+ import { checkBudget, BudgetExceededError } from './budget.js';
6
+ import { logProgress } from './logging.js';
7
+ const TAG = 'scan';
8
+ export function createCostTracker(options) {
9
+ return {
10
+ pricing: options.pricing,
11
+ budgetLimits: options.budgetLimits,
12
+ scanHistory: options.scanHistory,
13
+ totalTokens: 0,
14
+ totalCostUsd: 0,
15
+ warned: false,
16
+ lastAction: 'continue',
17
+ };
18
+ }
19
+ /**
20
+ * Record an AI call's token usage against the tracker. Called after each
21
+ * successful executeCheck().
22
+ */
23
+ export function recordUsage(tracker, usage, model) {
24
+ if (!usage || !tracker.pricing)
25
+ return;
26
+ const cost = calculateCost(usage, model, tracker.pricing);
27
+ tracker.totalTokens += usage.totalTokens;
28
+ tracker.totalCostUsd += cost.totalCost;
29
+ tracker.lastCostSource = cost.source;
30
+ tracker.lastCostReportedBy = cost.reportedBy;
31
+ tracker.lastCostCoveredBySubscription = cost.coveredBySubscription;
32
+ }
33
+ /**
34
+ * Check the budget before an AI call. Logs a warning the first time the warn
35
+ * threshold is crossed; throws BudgetExceededError when the abort threshold is
36
+ * crossed.
37
+ */
38
+ export function preflightBudget(tracker) {
39
+ if (!tracker.budgetLimits)
40
+ return;
41
+ const status = checkBudget({
42
+ currentScanCostUsd: tracker.totalCostUsd,
43
+ currentScanTokens: tracker.totalTokens,
44
+ history: tracker.scanHistory,
45
+ }, tracker.budgetLimits);
46
+ tracker.lastAction = status.action;
47
+ tracker.lastReason = status.reason;
48
+ if (status.action === 'abort') {
49
+ throw new BudgetExceededError(status.reason ?? 'Budget limit exceeded');
50
+ }
51
+ if (status.action === 'warn' && !tracker.warned) {
52
+ tracker.warned = true;
53
+ logProgress(TAG, `Budget warning: ${status.reason ?? 'approaching limit'}`);
54
+ }
55
+ }
56
+ //# sourceMappingURL=cost-tracker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cost-tracker.js","sourceRoot":"","sources":["../src/cost-tracker.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,aAAa,EAA0C,MAAM,sBAAsB,CAAC;AAC7F,OAAO,EAAE,WAAW,EAAE,mBAAmB,EAAqB,MAAM,aAAa,CAAC;AAClF,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAI3C,MAAM,GAAG,GAAG,MAAM,CAAC;AAwBnB,MAAM,UAAU,iBAAiB,CAAC,OAIjC;IACC,OAAO;QACL,OAAO,EAAE,OAAO,CAAC,OAAO;QACxB,YAAY,EAAE,OAAO,CAAC,YAAY;QAClC,WAAW,EAAE,OAAO,CAAC,WAAW;QAChC,WAAW,EAAE,CAAC;QACd,YAAY,EAAE,CAAC;QACf,MAAM,EAAE,KAAK;QACb,UAAU,EAAE,UAAU;KACvB,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,WAAW,CACzB,OAAwB,EACxB,KAA6B,EAC7B,KAAa;IAEb,IAAI,CAAC,KAAK,IAAI,CAAC,OAAO,CAAC,OAAO;QAAE,OAAO;IACvC,MAAM,IAAI,GAAG,aAAa,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;IAC1D,OAAO,CAAC,WAAW,IAAI,KAAK,CAAC,WAAW,CAAC;IACzC,OAAO,CAAC,YAAY,IAAI,IAAI,CAAC,SAAS,CAAC;IACvC,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,MAAM,CAAC;IACrC,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC,UAAU,CAAC;IAC7C,OAAO,CAAC,6BAA6B,GAAG,IAAI,CAAC,qBAAqB,CAAC;AACrE,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAAC,OAAwB;IACtD,IAAI,CAAC,OAAO,CAAC,YAAY;QAAE,OAAO;IAClC,MAAM,MAAM,GAAG,WAAW,CACxB;QACE,kBAAkB,EAAE,OAAO,CAAC,YAAY;QACxC,iBAAiB,EAAE,OAAO,CAAC,WAAW;QACtC,OAAO,EAAE,OAAO,CAAC,WAAW;KAC7B,EACD,OAAO,CAAC,YAAY,CACrB,CAAC;IACF,OAAO,CAAC,UAAU,GAAG,MAAM,CAAC,MAAM,CAAC;IACnC,OAAO,CAAC,UAAU,GAAG,MAAM,CAAC,MAAM,CAAC;IACnC,IAAI,MAAM,CAAC,MAAM,KAAK,OAAO,EAAE,CAAC;QAC9B,MAAM,IAAI,mBAAmB,CAAC,MAAM,CAAC,MAAM,IAAI,uBAAuB,CAAC,CAAC;IAC1E,CAAC;IACD,IAAI,MAAM,CAAC,MAAM,KAAK,MAAM,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;QAChD,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;QACtB,WAAW,CAAC,GAAG,EAAE,mBAAmB,MAAM,CAAC,MAAM,IAAI,mBAAmB,EAAE,CAAC,CAAC;IAC9E,CAAC;AACH,CAAC"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Glob-based target discovery.
3
+ *
4
+ * Matches files in the repository by glob pattern (e.g. "src/routes/**\/*.ts")
5
+ * and returns each matched file as a whole-file target. Useful for checks that
6
+ * apply to entire files (e.g. "review every GraphQL resolver"), without
7
+ * requiring an external tool such as Semgrep.
8
+ *
9
+ * Spec reference: Appendix E.2.1.
10
+ */
11
+ import type { TargetDiscovery, DiscoveredTarget } from '../discovery.js';
12
+ /**
13
+ * Discover whole-file targets in `repoPath` matching `pattern`.
14
+ *
15
+ * Exposed as a named export (rather than only the registry-facing object) so
16
+ * unit tests can exercise the matching logic directly without going through
17
+ * the SecurityCheck plumbing.
18
+ */
19
+ export declare function discoverGlobTargets(pattern: string, repoPath: string, maxTargets?: number): Promise<DiscoveredTarget[]>;
20
+ export declare const globDiscovery: TargetDiscovery;
21
+ //# sourceMappingURL=glob-discovery.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"glob-discovery.d.ts","sourceRoot":"","sources":["../../src/discoveries/glob-discovery.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AASH,OAAO,KAAK,EAAE,eAAe,EAAE,gBAAgB,EAAoB,MAAM,iBAAiB,CAAC;AAmI3F;;;;;;GAMG;AACH,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,EAChB,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAoD7B;AAED,eAAO,MAAM,aAAa,EAAE,eAoC3B,CAAC"}
@@ -0,0 +1,215 @@
1
+ /**
2
+ * Glob-based target discovery.
3
+ *
4
+ * Matches files in the repository by glob pattern (e.g. "src/routes/**\/*.ts")
5
+ * and returns each matched file as a whole-file target. Useful for checks that
6
+ * apply to entire files (e.g. "review every GraphQL resolver"), without
7
+ * requiring an external tool such as Semgrep.
8
+ *
9
+ * Spec reference: Appendix E.2.1.
10
+ */
11
+ import { readdir, stat } from 'node:fs/promises';
12
+ import { createReadStream } from 'node:fs';
13
+ import { join, relative, sep } from 'node:path';
14
+ import picomatch from 'picomatch';
15
+ import { logDebug } from '../logging.js';
16
+ import { ERROR_CODES, formatError } from '../error-codes.js';
17
+ import { DEFAULT_GENERIC_PROMPT } from '../defaults.js';
18
+ const TAG = 'glob-discovery';
19
+ /**
20
+ * Skip files larger than this (in bytes) to avoid OOM when a wide glob
21
+ * (e.g. "**\/*") accidentally matches a large generated/binary file.
22
+ * Files above this threshold are excluded from the target set with a debug log.
23
+ */
24
+ const MAX_FILE_SIZE_BYTES = 10 * 1024 * 1024; // 10 MiB
25
+ /** Directories that are always skipped when walking the repository tree. */
26
+ const ALWAYS_SKIP_DIRS = new Set([
27
+ '.git',
28
+ 'node_modules',
29
+ '.venv',
30
+ 'venv',
31
+ '__pycache__',
32
+ '.tox',
33
+ '.mypy_cache',
34
+ '.pytest_cache',
35
+ 'dist',
36
+ 'build',
37
+ '.next',
38
+ '.nuxt',
39
+ '.cache',
40
+ '.idea',
41
+ '.vscode',
42
+ ]);
43
+ function buildTargetPromptEnrichment(file, endLine) {
44
+ return `\n\nTARGET FILE:
45
+
46
+ You are analyzing a specific file:
47
+ - File: ${file}
48
+ - Lines: 1-${endLine} (whole file)
49
+
50
+ You MUST:
51
+ - Analyze ONLY this specific file — do not search for or report issues in other files
52
+ - You may read other files to understand context (e.g., imports, type definitions, data flow), but only report issues in this file
53
+ - Do NOT scan the broader repository for other instances of this vulnerability pattern
54
+ `;
55
+ }
56
+ /**
57
+ * Walk a directory tree recursively and yield every file path (POSIX-normalized,
58
+ * relative to `root`). Skips well-known noise directories so glob patterns do
59
+ * not have to opt out of `node_modules`/`.git` etc. on every check.
60
+ *
61
+ * Symlinks are NOT followed: `Dirent.isDirectory()` returns true only for real
62
+ * directories, so symlinked directories (and any cycles they could form) are
63
+ * skipped. Symlinked files are also skipped (`isFile()` returns false). This
64
+ * is the safe default — there's no general way to detect a hostile cycle, and
65
+ * source repos rarely rely on symlink-to-directory for layout.
66
+ */
67
+ async function* walkFiles(root) {
68
+ async function* walk(dir) {
69
+ let entries;
70
+ try {
71
+ entries = await readdir(dir, { withFileTypes: true });
72
+ }
73
+ catch {
74
+ return;
75
+ }
76
+ for (const entry of entries) {
77
+ const full = join(dir, entry.name);
78
+ if (entry.isDirectory()) {
79
+ if (ALWAYS_SKIP_DIRS.has(entry.name))
80
+ continue;
81
+ yield* walk(full);
82
+ }
83
+ else if (entry.isFile()) {
84
+ const rel = relative(root, full).split(sep).join('/');
85
+ yield rel;
86
+ }
87
+ // Symlinks (entry.isSymbolicLink()) are intentionally skipped — see
88
+ // the function-level comment above.
89
+ }
90
+ }
91
+ yield* walk(root);
92
+ }
93
+ /**
94
+ * Count the number of lines in a file by streaming and counting `\n` bytes.
95
+ * Constant memory; safe for very large files.
96
+ *
97
+ * Returns 1 for empty files so that `endLine >= startLine` always holds.
98
+ * Returns `undefined` if the file cannot be read or exceeds `MAX_FILE_SIZE_BYTES`
99
+ * — callers should treat that as "skip this target" and log accordingly.
100
+ */
101
+ async function countLines(filePath) {
102
+ let size;
103
+ try {
104
+ const st = await stat(filePath);
105
+ size = st.size;
106
+ }
107
+ catch (err) {
108
+ logDebug(TAG, `failed to stat ${filePath} for line count: ${err instanceof Error ? err.message : String(err)}`);
109
+ return undefined;
110
+ }
111
+ if (size > MAX_FILE_SIZE_BYTES) {
112
+ logDebug(TAG, `skipping ${filePath}: size ${size} bytes exceeds limit ${MAX_FILE_SIZE_BYTES}`);
113
+ return undefined;
114
+ }
115
+ if (size === 0)
116
+ return 1;
117
+ return new Promise((resolvePromise) => {
118
+ let newlineCount = 0;
119
+ let endsWithNewline = false;
120
+ const stream = createReadStream(filePath);
121
+ stream.on('data', (chunk) => {
122
+ // Treat the stream as bytes — counting `\n` bytes is safe for UTF-8 because
123
+ // 0x0A never appears as a continuation byte of a multi-byte sequence.
124
+ const buf = typeof chunk === 'string' ? Buffer.from(chunk) : chunk;
125
+ for (let i = 0; i < buf.length; i++) {
126
+ if (buf[i] === 0x0a)
127
+ newlineCount++;
128
+ }
129
+ if (buf.length > 0)
130
+ endsWithNewline = buf[buf.length - 1] === 0x0a;
131
+ });
132
+ stream.on('error', (err) => {
133
+ logDebug(TAG, `failed to read ${filePath} for line count: ${err.message}`);
134
+ resolvePromise(undefined);
135
+ });
136
+ stream.on('end', () => {
137
+ // If the file ends with a newline, the count of \n equals the number of lines.
138
+ // If it does not, the trailing partial line adds one to the count.
139
+ const lines = endsWithNewline ? newlineCount : newlineCount + 1;
140
+ resolvePromise(lines || 1);
141
+ });
142
+ });
143
+ }
144
+ /**
145
+ * Discover whole-file targets in `repoPath` matching `pattern`.
146
+ *
147
+ * Exposed as a named export (rather than only the registry-facing object) so
148
+ * unit tests can exercise the matching logic directly without going through
149
+ * the SecurityCheck plumbing.
150
+ */
151
+ export async function discoverGlobTargets(pattern, repoPath, maxTargets) {
152
+ if (!pattern || pattern.trim() === '') {
153
+ throw new Error(formatError(ERROR_CODES.E2004, 'Glob discovery requires a non-empty "glob" pattern'));
154
+ }
155
+ const matcher = picomatch(pattern, { dot: false });
156
+ const matches = [];
157
+ for await (const rel of walkFiles(repoPath)) {
158
+ if (matcher(rel)) {
159
+ matches.push(rel);
160
+ }
161
+ }
162
+ // Sort BEFORE applying maxTargets so that the truncated subset is deterministic
163
+ // across platforms (readdir order varies by filesystem). Without this, a glob
164
+ // with maxTargets=N could analyze a different N files on Linux vs Windows vs
165
+ // macOS, making findings non-reproducible.
166
+ matches.sort();
167
+ const limited = typeof maxTargets === 'number' ? matches.slice(0, maxTargets) : matches;
168
+ // Compute line counts in parallel; drop unreadable / oversized files.
169
+ const lineCounts = await Promise.all(limited.map((rel) => countLines(join(repoPath, rel))));
170
+ const usable = [];
171
+ for (let i = 0; i < limited.length; i++) {
172
+ const endLine = lineCounts[i];
173
+ if (endLine === undefined)
174
+ continue; // unreadable / oversized — already logged
175
+ usable.push({ rel: limited[i], endLine });
176
+ }
177
+ // Surface a single summary log when files were dropped, so users debugging
178
+ // "why is my big bundle missing from the target set?" don't have to enable
179
+ // trace-level logging to find the per-file skip messages from countLines.
180
+ const skippedCount = limited.length - usable.length;
181
+ if (skippedCount > 0) {
182
+ logDebug(TAG, `${skippedCount} matched file${skippedCount === 1 ? '' : 's'} skipped (unreadable or > ${MAX_FILE_SIZE_BYTES} bytes)`);
183
+ }
184
+ return usable.map(({ rel, endLine }, idx) => ({
185
+ file: rel,
186
+ startLine: 1,
187
+ endLine,
188
+ label: `[file ${idx + 1}/${usable.length}]`,
189
+ promptEnrichment: buildTargetPromptEnrichment(rel, endLine),
190
+ }));
191
+ }
192
+ export const globDiscovery = {
193
+ name: 'glob',
194
+ defaultGenericPrompt: DEFAULT_GENERIC_PROMPT,
195
+ needsInstructions: true,
196
+ // Opted out deliberately. `supportsDiffFilter` became a required field on
197
+ // TargetDiscovery after this discovery was written (#227), and the diff
198
+ // filter is built around findings with meaningful line ranges. Glob targets
199
+ // are whole files, so filtering them has never been designed or tested for
200
+ // this shape. Opting out preserves the behaviour this discovery was built
201
+ // and tested with: a glob check scans every matching file. Enabling it later
202
+ // is a small change plus tests for the whole-file case.
203
+ supportsDiffFilter: false,
204
+ async discover(check, repoPath, _options) {
205
+ const checkTarget = check.checkTarget;
206
+ if (!checkTarget.glob) {
207
+ throw new Error(formatError(ERROR_CODES.E2004, `Check "${check.id}" uses glob discovery but has no "glob" pattern in its check definition`));
208
+ }
209
+ logDebug(TAG, `Running glob discovery for check "${check.id}": ${checkTarget.glob}`);
210
+ const targets = await discoverGlobTargets(checkTarget.glob, repoPath, checkTarget.maxTargets);
211
+ logDebug(TAG, `Discovered ${targets.length} files matching pattern`);
212
+ return targets;
213
+ },
214
+ };
215
+ //# sourceMappingURL=glob-discovery.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"glob-discovery.js","sourceRoot":"","sources":["../../src/discoveries/glob-discovery.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,117 @@
1
+ /**
2
+ * Script-based target discovery.
3
+ *
4
+ * Runs a user-provided script (`node` or `bash`) in the target repository
5
+ * and parses its stdout to produce discovery targets. Useful when target
6
+ * discovery is too custom for Semgrep / SARIF / OpenAnt — e.g. parsing an
7
+ * OpenAPI spec, querying a build manifest, walking a database schema, etc.
8
+ *
9
+ * ─── Trust model ─────────────────────────────────────────────────────────────
10
+ *
11
+ * Scripts run with the full privileges of the aghast process. They are not
12
+ * sandboxed. Treat any script referenced by a check definition as trusted
13
+ * code — only enable script-discovery checks whose script you (or your team)
14
+ * have read and audited.
15
+ *
16
+ * Defensive measures applied here:
17
+ * - Script path must resolve INSIDE the configured check folder or repo
18
+ * (no `..` escape, no absolute paths to /etc/shadow, etc.).
19
+ * - Symlink-aware: both the script path and `cwd` are realpath'd and
20
+ * re-checked against the repo root, so a symlink inside the check folder
21
+ * pointing outside the repo cannot be used to execute external code.
22
+ * - Spawned with `shell: false` and array args — no shell interpolation, no
23
+ * command injection from check-definition fields.
24
+ * - Spawned with a curated environment: only a small allow-list of neutral
25
+ * env vars (PATH, HOME, locale, temp dirs, Windows essentials) is forwarded.
26
+ * As defence-in-depth, any var matching a known-secret pattern (`*_KEY`,
27
+ * `*_TOKEN`, `*_SECRET`, `*_PASSWORD`, or `ANTHROPIC_*` / `OPENAI_*` /
28
+ * `GITHUB_*` / `AGHAST_*` / `AWS_*` / `GCP_*` / `AZURE_*` prefixes) is
29
+ * also explicitly dropped. Allow-list matching is case-insensitive so
30
+ * the Windows-style `Path` / `SystemRoot` casing works the same as POSIX
31
+ * `PATH`.
32
+ * - cwd, when supplied, must resolve (and realpath) inside the repo root.
33
+ * - Hard timeout (default 30s, configurable per check).
34
+ * - Stdout is bounded (8 MiB) to prevent memory exhaustion from runaway scripts.
35
+ * - Both the line-format and JSON-format output paths cap the number of
36
+ * parsed targets (MAX_LINE_TARGETS / MAX_JSON_TARGETS) to bound memory
37
+ * even if a script floods within the stdout cap.
38
+ * - Output is parsed as data (lines / JSON) — never `eval`-ed.
39
+ * - File paths returned by the script are validated to be relative & inside
40
+ * the repo (no `..` escape, no absolute paths) before they are forwarded
41
+ * to the AI prompt or snippet extractor.
42
+ * - On `bash` scripts, Windows is unsupported (no system bash) and a clear
43
+ * error is raised rather than silently falling back.
44
+ */
45
+ import type { TargetDiscovery } from '../discovery.js';
46
+ /**
47
+ * Build a curated environment for the spawned discovery script.
48
+ *
49
+ * Discovery scripts need to walk the repo, possibly run small helper tools,
50
+ * but they never need API credentials. We start from a minimal allow-list of
51
+ * "neutral" env vars (PATH/locale/temp dirs) and then ALSO drop any var whose
52
+ * name matches a known-secret pattern even if it slipped through. Both layers
53
+ * are defence-in-depth.
54
+ *
55
+ * Exported for testing.
56
+ */
57
+ export declare function buildScriptEnv(parent?: NodeJS.ProcessEnv): NodeJS.ProcessEnv;
58
+ interface ScriptTargetInput {
59
+ file: string;
60
+ startLine?: number;
61
+ endLine?: number;
62
+ message?: string;
63
+ snippet?: string;
64
+ }
65
+ /**
66
+ * True when `candidateAbs` lives inside `rootAbs`. Both must be absolute.
67
+ *
68
+ * Two ways to be outside, and both matter:
69
+ * - a `..` prefix, the ordinary case;
70
+ * - an absolute result, which is what `relative()` returns on Windows when
71
+ * the two paths are on different drives (`C:\repo` vs `D:\checks`).
72
+ *
73
+ * Exported so the rule can be unit-tested against Windows-style paths on any
74
+ * platform. It exists as a single function because it previously did not: two
75
+ * call sites implemented the rule separately, one omitted the absolute-path
76
+ * case, and cross-drive layouts were rejected as a result.
77
+ *
78
+ * Pass a `pathApi` of `path.win32` or `path.posix` to test either flavour.
79
+ */
80
+ export declare function isInsideRoot(rootAbs: string, candidateAbs: string, pathApi?: {
81
+ relative: (a: string, b: string) => string;
82
+ isAbsolute: (p: string) => boolean;
83
+ }): boolean;
84
+ /**
85
+ * Parse stdout into a list of discovery target inputs.
86
+ * - `lines`: one file path per non-empty, non-comment line.
87
+ * - `json-array`: a JSON array of strings (file paths) or objects.
88
+ * - `json-object`: an object with a `targets` array of strings or objects.
89
+ *
90
+ * Both `lines` and JSON formats cap parsed targets at MAX_LINE_TARGETS /
91
+ * MAX_JSON_TARGETS (100k each); the rest are dropped with a warning log.
92
+ *
93
+ * Output is treated as DATA: never eval'd, never interpolated into commands.
94
+ */
95
+ export declare function parseScriptOutput(raw: string, format: 'lines' | 'json-array' | 'json-object'): ScriptTargetInput[];
96
+ interface RunScriptResult {
97
+ stdout: string;
98
+ exitCode: number | null;
99
+ signal: NodeJS.Signals | null;
100
+ stderr: string;
101
+ }
102
+ /**
103
+ * Execute the script as a child process and capture stdout.
104
+ * - Uses `spawn` with `shell: false`: never invoke a shell, never interpolate.
105
+ * - Passes a curated env (no API keys / tokens) — see `buildScriptEnv`.
106
+ * - Bounds stdout/stderr buffers and kills the process on timeout.
107
+ */
108
+ export declare function runScript(opts: {
109
+ command: string;
110
+ args: string[];
111
+ cwd: string;
112
+ timeoutMs: number;
113
+ env?: NodeJS.ProcessEnv;
114
+ }): Promise<RunScriptResult>;
115
+ export declare const scriptDiscovery: TargetDiscovery;
116
+ export {};
117
+ //# sourceMappingURL=script-discovery.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"script-discovery.d.ts","sourceRoot":"","sources":["../../src/discoveries/script-discovery.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AAQH,OAAO,KAAK,EAAE,eAAe,EAAsC,MAAM,iBAAiB,CAAC;AAoB3F;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,CAAC,MAAM,GAAE,MAAM,CAAC,UAAwB,GAAG,MAAM,CAAC,UAAU,CA8DzF;AAED,UAAU,iBAAiB;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,YAAY,CAC1B,OAAO,EAAE,MAAM,EACf,YAAY,EAAE,MAAM,EACpB,OAAO,GAAE;IAAE,QAAQ,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC;IAAC,UAAU,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,OAAO,CAAA;CAC/D,GACzB,OAAO,CAGT;AA4GD;;;;;;;;;;GAUG;AACH,wBAAgB,iBAAiB,CAC/B,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,OAAO,GAAG,YAAY,GAAG,aAAa,GAC7C,iBAAiB,EAAE,CAsIrB;AAED,UAAU,eAAe;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC,OAAO,GAAG,IAAI,CAAC;IAC9B,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;CACzB,GAAG,OAAO,CAAC,eAAe,CAAC,CAsF3B;AAgCD,eAAO,MAAM,eAAe,EAAE,eAyM7B,CAAC"}