You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Rewrites the codebase from JavaScript to TypeScript for improved type safety and developer experience. No behavioral changes; deployment, configuration schema, and all external interfaces are identical.
5. Partial-clone head and merge-base SHAs with `--filter=blob:none` (`src/fetcher.ts` → `setupRepo`)
78
82
6. Diff the two commits to get changed file paths (`getChangedFiles`) and per-file changed line ranges (`getChangedLineRanges`)
79
83
7. Sparse-checkout only the changed files - blobs fetched on demand (`checkoutFiles`)
80
-
8. Load per-repo config via `src/config.js` → `loadScanConfig`
81
-
9. Run scanners in parallel via `src/dispatcher.js` → `dispatch()`
82
-
10. Validate finding locations against the actual file content (`src/location-validator.js` → `validateFindingLocations`)
83
-
11. Suppress findings that have a `// SECURITY:` comment at the merge base (`src/suppressor.js` → `suppressFindings`)
84
-
12. Filter to actionable findings; stamp each with a deterministic `_findingId` (`LAYNE-xxxxxxxxxxxxxxxx`) via `src/exception-approvals.js` → `generateFindingId`
85
-
13. Convert findings to annotations via `src/reporter.js` → `buildAnnotations()`
84
+
8. Load per-repo config via `src/config.ts` → `loadScanConfig`
85
+
9. Run scanners in parallel via `src/dispatcher.ts` → `dispatch()`
86
+
10. Validate finding locations against the actual file content (`src/location-validator.ts` → `validateFindingLocations`)
87
+
11. Suppress findings that have a `// SECURITY:` comment at the merge base (`src/suppressor.ts` → `suppressFindings`)
88
+
12. Filter to actionable findings; stamp each with a deterministic `_findingId` (`LAYNE-xxxxxxxxxxxxxxxx`) via `src/exception-approvals.ts` → `generateFindingId`
89
+
13. Convert findings to annotations via `src/reporter.ts` → `buildAnnotations()`
86
90
14. If `exceptionApprovers` is configured: load stored exceptions from Redis (`loadExceptions`), remove stale ones whose flagged line changed (`filterStaleExceptions`), resolve approvals that survived a line-number shift via rebase (`resolveDriftedExceptions`), then call `buildExceptionSummary` to potentially override conclusion to `success`
87
91
15. Complete Check Run
88
-
16. Post PR comment if `comment.enabled` via `src/commenter.js` → `postComment`
89
-
17. Apply/remove PR labels via `src/github.js` → `ensureLabelsExist` + `setLabels`
90
-
18. Notify via `src/notifiers/index.js` → `notify()` (always fires on exception approval; otherwise only when finding count increases)
92
+
16. Post PR comment if `comment.enabled` via `src/commenter.ts` → `postComment`
93
+
17. Apply/remove PR labels via `src/github.ts` → `ensureLabelsExist` + `setLabels`
94
+
18. Notify via `src/notifiers/index.ts` → `notify()` (always fires on exception approval; otherwise only when finding count increases)
91
95
19. Clean up workspace in `finally`
92
96
93
97
**Scanners (`src/adapters/`):**
94
-
-`semgrep.js` - runs `semgrep scan --config auto --json`; exit code 1 = findings found (not an error); maps ERROR→high, WARNING→medium, INFO→low
95
-
-`trufflehog.js` - runs `trufflehog filesystem --json --no-update`; exit code 183 = secrets found (not an error); batched at 200 files to stay under ARG_MAX; all findings are severity `high`
96
-
-`claude.js` - calls the Anthropic API to detect malicious intent; **disabled by default**, opt in per repo; skips binary files; caps files at 50 KB; batches at 100 KB per API call; errors are caught and logged without failing the scan. Supports two modes (configured per-repo in `config/layne.json`):
98
+
-`semgrep.ts` - runs `semgrep scan --config auto --json`; exit code 1 = findings found (not an error); maps ERROR→high, WARNING→medium, INFO→low
99
+
-`trufflehog.ts` - runs `trufflehog filesystem --json --no-update`; exit code 183 = secrets found (not an error); batched at 200 files to stay under ARG_MAX; all findings are severity `high`
100
+
-`claude.ts` - calls the Anthropic API to detect malicious intent; **disabled by default**, opt in per repo; skips binary files; caps files at 50 KB; batches at 100 KB per API call; errors are caught and logged without failing the scan. Supports two modes (configured per-repo in `config/layne.json`):
97
101
-**Prompt mode** (default): single `messages.create` call with a system prompt; use `claude.prompt` to override
98
102
-**Skill mode**: uses the Anthropic [API Skills beta](https://platform.claude.com/docs/en/build-with-claude/skills-guide) - adds a `code_execution` tool + an uploaded skill to each batch call, enabling runtime decoding, registry lookups, and richer static analysis; set `claude.skill: { id, version }` to enable; handles `pause_turn` continuations automatically (up to 10 turns per batch)
99
103
@@ -113,21 +117,21 @@ Two separate Node.js processes:
113
117
114
118
| Module | Purpose |
115
119
|--------|---------|
116
-
|`src/config.js`| Loads and merges `config/layne.json`; cached after first read |
117
-
|`src/github.js`| Check Run CRUD + label management (`ensureLabelsExist`, `setLabels`) |
118
-
|`src/metrics.js`| Prometheus metric definitions; exports no-op stubs when `METRICS_ENABLED` is not `true`|
-`trigger`: controls when scanning fires - `pull_request` (default, immediate) or `workflow_run` (deferred until a named CI workflow completes); global default → per-repo override
@@ -141,7 +145,7 @@ Key points for code navigation:
141
145
142
146
## Metrics
143
147
144
-
-`src/metrics.js` exports real prom-client objects when `METRICS_ENABLED=true`, silent no-op stubs otherwise
148
+
-`src/metrics.ts` exports real prom-client objects when `METRICS_ENABLED=true`, silent no-op stubs otherwise
145
149
- No `if (METRICS_ENABLED)` guards needed at call sites - stubs absorb all calls
146
150
- Worker: metrics HTTP server + BullMQ queue poller (15 s interval) started only when enabled
147
151
- Server: `GET /metrics` route registered only when enabled
@@ -150,9 +154,11 @@ Key points for code navigation:
150
154
## Testing conventions
151
155
152
156
- Tests use Vitest with ESM (`"type": "module"` in package.json)
153
-
-`src/__tests__/setup.js` sets all required env vars before each test file; `ANTHROPIC_API_KEY` and `METRICS_ENABLED` are intentionally not set - adapters and metrics are mocked
157
+
- All test files are TypeScript (`.ts`); imports use `.js` extensions (NodeNext resolution)
158
+
-`src/__tests__/setup.ts` sets all required env vars before each test file; `ANTHROPIC_API_KEY` and `METRICS_ENABLED` are intentionally not set - adapters and metrics are mocked
154
159
- External dependencies (`@octokit/auth-app`, `@octokit/rest`, `bullmq`, `ioredis`, `@anthropic-ai/sdk`, `prom-client`) are always mocked - no live connections in tests
155
-
-`src/metrics.js` is mocked in worker and server tests with `vi.fn()` stubs; tested in isolation in `src/__tests__/metrics.test.js`
160
+
-`src/metrics.ts` is mocked in worker and server tests with `vi.fn()` stubs; tested in isolation in `src/__tests__/metrics.test.ts`
156
161
-`processJob` and `dispatch` are exported specifically for unit testing without live infrastructure
157
162
- Tests import modules with `await import(...)` after `vi.mock()` calls to handle ESM module caching
158
163
- The `@anthropic-ai/sdk` mock uses a regular `function` constructor (not an arrow function) because `new Anthropic()` must be constructable
164
+
- Typed mock call access pattern: `(mockFn as ReturnType<typeof vi.fn>).mock.calls[0] as [T1, T2]`
0 commit comments