Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions review-enrichment/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,28 @@ The engine can send `analyzers: ["secret", "actionPin"]` to run a subset. If the
full registry. An explicit empty array runs no analyzers; the engine uses that fail-closed shape when an
operator-configured analyzer list contains no valid names.

## Analyzer manifests

Analyzer runtime metadata lives in `src/analyzers/registry.ts` as `AnalyzerDescriptor` entries. New analyzer work
should prefer the modular shape introduced for `dependency` and `secret`:

| File | Purpose |
| ----------------------------------------- | -------------------------------------------------------------- |
| `src/analyzers/<name>/descriptor.ts` | Analyzer name, title, category, cost, requirements, docs, run function, and optional renderer. |
| `src/analyzers/<name>.ts` | Pure scanner helpers and the analyzer implementation. |
| `test/<name>.test.ts` | Focused tests for scanner behavior, rendering, and degradation. |

Descriptors are the extension point future REES runtime work will use for profiles, docs generation, scheduler cost
classes, per-analyzer limits, and self-host configuration. When adding or migrating an analyzer:

- Keep the public analyzer name stable; it is what `REES_ANALYZERS` and the engine request body use.
- Put operator-facing metadata in the descriptor: `category`, `cost`, `defaultEnabled`, `requires`, `limits`, and
`docs`.
- Keep renderer output public-safe. Never include tokens, request bodies, diffs, raw prompts, comments, or private
config values.
- Make external-call analyzers fail open and respect the orchestrator abort signal when the scanner supports it.
- Prefer a focused analyzer test file instead of expanding the shared `enrichment.test.ts` mega-test.

The engine also sends `budget.timeoutMs` with one second of headroom below `REES_TIMEOUT_MS`, so REES can return a
partial/degraded brief before the caller aborts the HTTP request. If Railway is still running an older REES build,
temporarily raise the engine-side `REES_TIMEOUT_MS` above the REES analyzer budget, or set `REES_ANALYZERS` to a
Expand Down
49 changes: 49 additions & 0 deletions review-enrichment/src/analyzers/dependency/descriptor.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import type { AnalyzerDescriptor } from "../types.js";
import { scanDependencies } from "../dependency-scan.js";
import { SEVERITY_RANK } from "../../render-helpers.js";

export const dependencyAnalyzer: AnalyzerDescriptor<"dependency"> = {
name: "dependency",
title: "Dependency vulnerabilities",
category: "supply-chain",
cost: "registry",
defaultEnabled: true,
requires: ["files", "public-network"],
limits: {
maxManifestFiles: 20,
maxPatchLinesPerFile: 500,
maxDependencyQueries: 25,
},
docs: {
summary: "Checks changed direct dependency versions against OSV.dev.",
looksAt:
"Added or upgraded dependencies in package.json, requirements.txt, and go.mod diffs.",
reports:
"Known CVEs with severity, advisory id, summary, and fixed version when OSV publishes one.",
network: "Calls OSV.dev. No GitHub token required.",
notes:
"Manifest-only by design; use lockfileDrift for transitive lockfile changes.",
},
run: (req, { signal }) => scanDependencies(req, fetch, { signal }),
render: (deps, { safeCodeSpan, promptText }) => {
const lines: string[] = [];
if (!deps.length) return lines;
lines.push("### Dependency vulnerabilities (OSV.dev)");
const flat = deps
.flatMap((dep) => dep.cves.map((cve) => ({ dep, cve })))
.sort(
(a, b) =>
(SEVERITY_RANK[a.cve.severity] ?? 4) -
(SEVERITY_RANK[b.cve.severity] ?? 4),
);
for (const { dep, cve } of flat) {
const fix = cve.fixedIn
? ` — fixed in ${safeCodeSpan(cve.fixedIn)}`
: "";
lines.push(
`- ${safeCodeSpan(`${dep.package}@${dep.to}`)} (${dep.ecosystem}): **${cve.severity}** ${safeCodeSpan(cve.id)} — ${promptText(cve.summary)}${fix}`,
);
}
return lines;
},
};
Loading
Loading