@owasp-aghast/aghast 0.8.4 → 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 (107) hide show
  1. package/dist/build-config.d.ts.map +1 -1
  2. package/dist/build-config.js +101 -2
  3. package/dist/build-config.js.map +1 -1
  4. package/dist/check-library.d.ts +25 -0
  5. package/dist/check-library.d.ts.map +1 -1
  6. package/dist/check-library.js +165 -0
  7. package/dist/check-library.js.map +1 -1
  8. package/dist/ci-metadata.d.ts +42 -0
  9. package/dist/ci-metadata.d.ts.map +1 -0
  10. package/dist/ci-metadata.js +131 -0
  11. package/dist/ci-metadata.js.map +1 -0
  12. package/dist/cli.js +4 -1
  13. package/dist/cli.js.map +1 -1
  14. package/dist/concurrency.d.ts +18 -0
  15. package/dist/concurrency.d.ts.map +1 -0
  16. package/dist/concurrency.js +39 -0
  17. package/dist/concurrency.js.map +1 -0
  18. package/dist/cost-tracker.d.ts +45 -0
  19. package/dist/cost-tracker.d.ts.map +1 -0
  20. package/dist/cost-tracker.js +56 -0
  21. package/dist/cost-tracker.js.map +1 -0
  22. package/dist/discoveries/glob-discovery.d.ts +21 -0
  23. package/dist/discoveries/glob-discovery.d.ts.map +1 -0
  24. package/dist/discoveries/glob-discovery.js +215 -0
  25. package/dist/discoveries/glob-discovery.js.map +1 -0
  26. package/dist/discoveries/script-discovery.d.ts +117 -0
  27. package/dist/discoveries/script-discovery.d.ts.map +1 -0
  28. package/dist/discoveries/script-discovery.js +593 -0
  29. package/dist/discoveries/script-discovery.js.map +1 -0
  30. package/dist/docs-url.d.ts +14 -0
  31. package/dist/docs-url.d.ts.map +1 -0
  32. package/dist/docs-url.js +17 -0
  33. package/dist/docs-url.js.map +1 -0
  34. package/dist/error-codes.d.ts +12 -1
  35. package/dist/error-codes.d.ts.map +1 -1
  36. package/dist/error-codes.js +16 -2
  37. package/dist/error-codes.js.map +1 -1
  38. package/dist/formatters/csv-formatter.d.ts +12 -1
  39. package/dist/formatters/csv-formatter.d.ts.map +1 -1
  40. package/dist/formatters/csv-formatter.js +64 -2
  41. package/dist/formatters/csv-formatter.js.map +1 -1
  42. package/dist/formatters/html-formatter.d.ts.map +1 -1
  43. package/dist/formatters/html-formatter.js +43 -3
  44. package/dist/formatters/html-formatter.js.map +1 -1
  45. package/dist/formatters/index.d.ts.map +1 -1
  46. package/dist/formatters/index.js +2 -0
  47. package/dist/formatters/index.js.map +1 -1
  48. package/dist/formatters/markdown-formatter.d.ts +61 -0
  49. package/dist/formatters/markdown-formatter.d.ts.map +1 -0
  50. package/dist/formatters/markdown-formatter.js +557 -0
  51. package/dist/formatters/markdown-formatter.js.map +1 -0
  52. package/dist/formatters/sarif-formatter.d.ts +7 -0
  53. package/dist/formatters/sarif-formatter.d.ts.map +1 -1
  54. package/dist/formatters/sarif-formatter.js +80 -0
  55. package/dist/formatters/sarif-formatter.js.map +1 -1
  56. package/dist/formatters/types.d.ts +24 -0
  57. package/dist/formatters/types.d.ts.map +1 -1
  58. package/dist/index.d.ts +4 -0
  59. package/dist/index.d.ts.map +1 -1
  60. package/dist/index.js +342 -9
  61. package/dist/index.js.map +1 -1
  62. package/dist/issue-file-writer.d.ts +21 -0
  63. package/dist/issue-file-writer.d.ts.map +1 -0
  64. package/dist/issue-file-writer.js +307 -0
  65. package/dist/issue-file-writer.js.map +1 -0
  66. package/dist/judge.d.ts +62 -0
  67. package/dist/judge.d.ts.map +1 -0
  68. package/dist/judge.js +305 -0
  69. package/dist/judge.js.map +1 -0
  70. package/dist/mock-agent-provider.d.ts +3 -0
  71. package/dist/mock-agent-provider.d.ts.map +1 -1
  72. package/dist/mock-agent-provider.js +13 -0
  73. package/dist/mock-agent-provider.js.map +1 -1
  74. package/dist/new-check.d.ts.map +1 -1
  75. package/dist/new-check.js +322 -13
  76. package/dist/new-check.js.map +1 -1
  77. package/dist/opencode-provider.d.ts.map +1 -1
  78. package/dist/opencode-provider.js +33 -0
  79. package/dist/opencode-provider.js.map +1 -1
  80. package/dist/repo-scan.d.ts +80 -0
  81. package/dist/repo-scan.d.ts.map +1 -0
  82. package/dist/repo-scan.js +250 -0
  83. package/dist/repo-scan.js.map +1 -0
  84. package/dist/result-handlers/pr-comment-handler.d.ts +136 -0
  85. package/dist/result-handlers/pr-comment-handler.d.ts.map +1 -0
  86. package/dist/result-handlers/pr-comment-handler.js +381 -0
  87. package/dist/result-handlers/pr-comment-handler.js.map +1 -0
  88. package/dist/retry.d.ts +128 -0
  89. package/dist/retry.d.ts.map +1 -0
  90. package/dist/retry.js +261 -0
  91. package/dist/retry.js.map +1 -0
  92. package/dist/runtime-config.d.ts.map +1 -1
  93. package/dist/runtime-config.js +62 -0
  94. package/dist/runtime-config.js.map +1 -1
  95. package/dist/scan-runner.d.ts +31 -22
  96. package/dist/scan-runner.d.ts.map +1 -1
  97. package/dist/scan-runner.js +145 -100
  98. package/dist/scan-runner.js.map +1 -1
  99. package/dist/semgrep-runner.js +6 -4
  100. package/dist/semgrep-runner.js.map +1 -1
  101. package/dist/stats.d.ts.map +1 -1
  102. package/dist/stats.js +4 -1
  103. package/dist/stats.js.map +1 -1
  104. package/dist/types.d.ts +149 -2
  105. package/dist/types.d.ts.map +1 -1
  106. package/dist/types.js.map +1 -1
  107. package/package.json +1 -1
@@ -0,0 +1,42 @@
1
+ /**
2
+ * CI/CD pipeline metadata detection (spec E.4).
3
+ *
4
+ * Detects whether aghast is running inside a known CI/CD platform and
5
+ * collects pipeline context (job URL, branch, trigger, start time) from
6
+ * platform-specific environment variables.
7
+ *
8
+ * Supported platforms: GitHub Actions, GitLab CI, CircleCI. Extending to
9
+ * new platforms means adding another collector function below.
10
+ *
11
+ * The functions only read from a supplied env object (defaulting to
12
+ * `process.env`); they never mutate it and never throw.
13
+ */
14
+ import type { CIMetadata } from './types.js';
15
+ /** Read-only env shape (process.env compatible). */
16
+ export type EnvLike = Readonly<Record<string, string | undefined>>;
17
+ /**
18
+ * Every CI/CD environment variable this module consults. Exported so test
19
+ * helpers can scrub these vars in one place and stay in sync with this
20
+ * module — adding a new var here automatically updates the hermetic test
21
+ * scrub list.
22
+ */
23
+ export declare const CI_ENV_VAR_NAMES: readonly string[];
24
+ /**
25
+ * Returns true when aghast appears to be running inside a CI/CD environment.
26
+ *
27
+ * Most CI providers set `CI=true`; we also accept platform-specific signals
28
+ * (`GITHUB_ACTIONS`, `GITLAB_CI`, `CIRCLECI`) to cover edge cases where the
29
+ * generic `CI` flag is unset but the platform-specific flag is present. All
30
+ * flags accept the literal strings `'true'` or `'1'` for parity.
31
+ */
32
+ export declare function detectCI(env?: EnvLike): boolean;
33
+ /**
34
+ * Collect CI/CD metadata from the environment. Returns `undefined` when no
35
+ * CI signals are present, or when no platform-specific fields could be
36
+ * resolved (i.e. nothing useful to report).
37
+ *
38
+ * Platform precedence: GitHub Actions → GitLab CI → CircleCI. If multiple
39
+ * sets of variables somehow coexist, the first matched platform wins.
40
+ */
41
+ export declare function collectCIMetadata(env?: EnvLike): CIMetadata | undefined;
42
+ //# sourceMappingURL=ci-metadata.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ci-metadata.d.ts","sourceRoot":"","sources":["../src/ci-metadata.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C,oDAAoD;AACpD,MAAM,MAAM,OAAO,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC;AAEnE;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,EAAE,SAAS,MAAM,EAqB7C,CAAC;AAOF;;;;;;;GAOG;AACH,wBAAgB,QAAQ,CAAC,GAAG,GAAE,OAAqB,GAAG,OAAO,CAO5D;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,GAAE,OAAqB,GAAG,UAAU,GAAG,SAAS,CAapF"}
@@ -0,0 +1,131 @@
1
+ /**
2
+ * CI/CD pipeline metadata detection (spec E.4).
3
+ *
4
+ * Detects whether aghast is running inside a known CI/CD platform and
5
+ * collects pipeline context (job URL, branch, trigger, start time) from
6
+ * platform-specific environment variables.
7
+ *
8
+ * Supported platforms: GitHub Actions, GitLab CI, CircleCI. Extending to
9
+ * new platforms means adding another collector function below.
10
+ *
11
+ * The functions only read from a supplied env object (defaulting to
12
+ * `process.env`); they never mutate it and never throw.
13
+ */
14
+ /**
15
+ * Every CI/CD environment variable this module consults. Exported so test
16
+ * helpers can scrub these vars in one place and stay in sync with this
17
+ * module — adding a new var here automatically updates the hermetic test
18
+ * scrub list.
19
+ */
20
+ export const CI_ENV_VAR_NAMES = [
21
+ // Generic
22
+ 'CI',
23
+ // GitHub Actions
24
+ 'GITHUB_ACTIONS',
25
+ 'GITHUB_SERVER_URL',
26
+ 'GITHUB_REPOSITORY',
27
+ 'GITHUB_RUN_ID',
28
+ 'GITHUB_REF_NAME',
29
+ 'GITHUB_EVENT_NAME',
30
+ 'GITHUB_RUN_STARTED_AT',
31
+ // GitLab CI
32
+ 'GITLAB_CI',
33
+ 'CI_JOB_URL',
34
+ 'CI_COMMIT_REF_NAME',
35
+ 'CI_PIPELINE_SOURCE',
36
+ 'CI_JOB_STARTED_AT',
37
+ // CircleCI
38
+ 'CIRCLECI',
39
+ 'CIRCLE_BUILD_URL',
40
+ 'CIRCLE_BRANCH',
41
+ ];
42
+ /** Returns true when the env var holds a recognised truthy CI flag value. */
43
+ function isTrueFlag(value) {
44
+ return value === 'true' || value === '1';
45
+ }
46
+ /**
47
+ * Returns true when aghast appears to be running inside a CI/CD environment.
48
+ *
49
+ * Most CI providers set `CI=true`; we also accept platform-specific signals
50
+ * (`GITHUB_ACTIONS`, `GITLAB_CI`, `CIRCLECI`) to cover edge cases where the
51
+ * generic `CI` flag is unset but the platform-specific flag is present. All
52
+ * flags accept the literal strings `'true'` or `'1'` for parity.
53
+ */
54
+ export function detectCI(env = process.env) {
55
+ return (isTrueFlag(env.CI) ||
56
+ isTrueFlag(env.GITHUB_ACTIONS) ||
57
+ isTrueFlag(env.GITLAB_CI) ||
58
+ isTrueFlag(env.CIRCLECI));
59
+ }
60
+ /**
61
+ * Collect CI/CD metadata from the environment. Returns `undefined` when no
62
+ * CI signals are present, or when no platform-specific fields could be
63
+ * resolved (i.e. nothing useful to report).
64
+ *
65
+ * Platform precedence: GitHub Actions → GitLab CI → CircleCI. If multiple
66
+ * sets of variables somehow coexist, the first matched platform wins.
67
+ */
68
+ export function collectCIMetadata(env = process.env) {
69
+ if (!detectCI(env))
70
+ return undefined;
71
+ const collectors = [
72
+ collectGitHubActions,
73
+ collectGitLabCI,
74
+ collectCircleCI,
75
+ ];
76
+ for (const collect of collectors) {
77
+ const meta = collect(env);
78
+ if (meta && hasAnyField(meta))
79
+ return meta;
80
+ }
81
+ return undefined;
82
+ }
83
+ function hasAnyField(meta) {
84
+ return Boolean(meta.jobUrl ?? meta.branch ?? meta.pipelineSource ?? meta.jobStartedAt);
85
+ }
86
+ /** GitHub Actions: builds job URL from server/repo/run-id; reads ref + event + start time. */
87
+ function collectGitHubActions(env) {
88
+ if (!isTrueFlag(env.GITHUB_ACTIONS))
89
+ return undefined;
90
+ const meta = {};
91
+ const server = env.GITHUB_SERVER_URL;
92
+ const repo = env.GITHUB_REPOSITORY;
93
+ const runId = env.GITHUB_RUN_ID;
94
+ if (server && repo && runId) {
95
+ meta.jobUrl = `${server}/${repo}/actions/runs/${runId}`;
96
+ }
97
+ if (env.GITHUB_REF_NAME)
98
+ meta.branch = env.GITHUB_REF_NAME;
99
+ if (env.GITHUB_EVENT_NAME)
100
+ meta.pipelineSource = env.GITHUB_EVENT_NAME;
101
+ if (env.GITHUB_RUN_STARTED_AT)
102
+ meta.jobStartedAt = env.GITHUB_RUN_STARTED_AT;
103
+ return meta;
104
+ }
105
+ /** GitLab CI: native fields cover all four metadata slots directly. */
106
+ function collectGitLabCI(env) {
107
+ if (!isTrueFlag(env.GITLAB_CI))
108
+ return undefined;
109
+ const meta = {};
110
+ if (env.CI_JOB_URL)
111
+ meta.jobUrl = env.CI_JOB_URL;
112
+ if (env.CI_COMMIT_REF_NAME)
113
+ meta.branch = env.CI_COMMIT_REF_NAME;
114
+ if (env.CI_PIPELINE_SOURCE)
115
+ meta.pipelineSource = env.CI_PIPELINE_SOURCE;
116
+ if (env.CI_JOB_STARTED_AT)
117
+ meta.jobStartedAt = env.CI_JOB_STARTED_AT;
118
+ return meta;
119
+ }
120
+ /** CircleCI: only job URL + branch are exposed; trigger/start time are not standard. */
121
+ function collectCircleCI(env) {
122
+ if (!isTrueFlag(env.CIRCLECI))
123
+ return undefined;
124
+ const meta = {};
125
+ if (env.CIRCLE_BUILD_URL)
126
+ meta.jobUrl = env.CIRCLE_BUILD_URL;
127
+ if (env.CIRCLE_BRANCH)
128
+ meta.branch = env.CIRCLE_BRANCH;
129
+ return meta;
130
+ }
131
+ //# sourceMappingURL=ci-metadata.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ci-metadata.js","sourceRoot":"","sources":["../src/ci-metadata.ts"],"names":[],"mappings":"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"}
package/dist/cli.js CHANGED
@@ -15,6 +15,7 @@ import { readFileSync } from 'node:fs';
15
15
  import { resolve, dirname } from 'node:path';
16
16
  import { fileURLToPath } from 'node:url';
17
17
  import { ERROR_CODES, formatError, formatFatalError } from './error-codes.js';
18
+ import { docsFooter } from './docs-url.js';
18
19
  // Signal to subcommand modules that they're being imported, not run directly
19
20
  process.env._AGHAST_CLI = '1';
20
21
  const USAGE = `Usage: aghast <command> [options]
@@ -29,7 +30,9 @@ Options:
29
30
  --help Show this help message
30
31
  --version Show version number
31
32
 
32
- Run 'aghast <command> --help' for more information on a command.`;
33
+ Run 'aghast <command> --help' for more information on a command.
34
+
35
+ ${docsFooter()}`;
33
36
  function getVersion() {
34
37
  const require = createRequire(import.meta.url);
35
38
  const pkg = require('../package.json');
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Shared concurrency utilities for the scan runner and judge stage.
3
+ */
4
+ /** Handle for signaling abort to mapWithConcurrency workers. */
5
+ export interface AbortHandle {
6
+ aborted: boolean;
7
+ reason?: Error;
8
+ }
9
+ /**
10
+ * Run an async function over items with bounded concurrency.
11
+ * Spawns min(concurrency, items.length) workers that pull from a shared index.
12
+ * Results are written to a pre-allocated array to preserve input order.
13
+ *
14
+ * If abortHandle is provided, workers stop picking up new items once
15
+ * abortHandle.aborted is set to true. In-flight items complete naturally.
16
+ */
17
+ export declare function mapWithConcurrency<T, R>(items: T[], concurrency: number, fn: (item: T, index: number) => Promise<R>, abortHandle?: AbortHandle): Promise<R[]>;
18
+ //# sourceMappingURL=concurrency.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"concurrency.d.ts","sourceRoot":"","sources":["../src/concurrency.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,gEAAgE;AAChE,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,KAAK,CAAC;CAChB;AAED;;;;;;;GAOG;AACH,wBAAsB,kBAAkB,CAAC,CAAC,EAAE,CAAC,EAC3C,KAAK,EAAE,CAAC,EAAE,EACV,WAAW,EAAE,MAAM,EACnB,EAAE,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,EAC1C,WAAW,CAAC,EAAE,WAAW,GACxB,OAAO,CAAC,CAAC,EAAE,CAAC,CA6Bd"}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Shared concurrency utilities for the scan runner and judge stage.
3
+ */
4
+ /**
5
+ * Run an async function over items with bounded concurrency.
6
+ * Spawns min(concurrency, items.length) workers that pull from a shared index.
7
+ * Results are written to a pre-allocated array to preserve input order.
8
+ *
9
+ * If abortHandle is provided, workers stop picking up new items once
10
+ * abortHandle.aborted is set to true. In-flight items complete naturally.
11
+ */
12
+ export async function mapWithConcurrency(items, concurrency, fn, abortHandle) {
13
+ const results = new Array(items.length);
14
+ let nextIndex = 0;
15
+ async function worker() {
16
+ while (nextIndex < items.length) {
17
+ if (abortHandle?.aborted)
18
+ break;
19
+ // Safe without atomics: Node.js is single-threaded, so nextIndex++ is
20
+ // not interleaved — each worker awaits before looping, yielding to the
21
+ // event loop where the next worker reads and increments the same variable.
22
+ const i = nextIndex++;
23
+ results[i] = await fn(items[i], i);
24
+ }
25
+ }
26
+ const workerCount = Math.min(concurrency, items.length);
27
+ const workers = [];
28
+ for (let w = 0; w < workerCount; w++) {
29
+ workers.push(worker());
30
+ }
31
+ // Use allSettled so in-flight items complete before we propagate errors
32
+ const settled = await Promise.allSettled(workers);
33
+ const firstRejection = settled.find((r) => r.status === 'rejected');
34
+ if (firstRejection && firstRejection.status === 'rejected') {
35
+ throw firstRejection.reason;
36
+ }
37
+ return results;
38
+ }
39
+ //# sourceMappingURL=concurrency.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"concurrency.js","sourceRoot":"","sources":["../src/concurrency.ts"],"names":[],"mappings":"AAAA;;GAEG;AAQH;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,KAAU,EACV,WAAmB,EACnB,EAA0C,EAC1C,WAAyB;IAEzB,MAAM,OAAO,GAAG,IAAI,KAAK,CAAI,KAAK,CAAC,MAAM,CAAC,CAAC;IAC3C,IAAI,SAAS,GAAG,CAAC,CAAC;IAElB,KAAK,UAAU,MAAM;QACnB,OAAO,SAAS,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC;YAChC,IAAI,WAAW,EAAE,OAAO;gBAAE,MAAM;YAChC,sEAAsE;YACtE,uEAAuE;YACvE,2EAA2E;YAC3E,MAAM,CAAC,GAAG,SAAS,EAAE,CAAC;YACtB,OAAO,CAAC,CAAC,CAAC,GAAG,MAAM,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QACrC,CAAC;IACH,CAAC;IAED,MAAM,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,WAAW,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IACxD,MAAM,OAAO,GAAoB,EAAE,CAAC;IACpC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,WAAW,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;IACzB,CAAC;IAED,wEAAwE;IACxE,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;IAClD,MAAM,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,UAAU,CAAC,CAAC;IACpE,IAAI,cAAc,IAAI,cAAc,CAAC,MAAM,KAAK,UAAU,EAAE,CAAC;QAC3D,MAAM,cAAc,CAAC,MAAM,CAAC;IAC9B,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC"}
@@ -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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"}