Repository navigation
Confidence 9/10 · No issues found
🟢 Confidence 9/10 · safe to merge. Scanner, store and queue triggers are well pinned; the new /internal/dependency-scan handlers, including the admin gate, have no test, and the push dedupe reads only lockfile shas.
1 note · tests partial −1 · risk medium · 4/4 new units observable
Adds a dependency scanner that reads connected repositories' lockfiles through the existing GitHub App, runs it from the VCS sync queue on tracked-branch pushes, installation syncs and "Scan now", and serves findings and admin-only triage over a new internal API. Neither open error issue is fixed: GithubAppError gains more call sites here, and DeviceTokenRejected is untouched by the route registration in http-graph.ts.
DependencyScanner.scanreads lockfiles by GitHub blob sha and matches packages in OSV- VCS sync enqueues
dependency-scanjobs on tracked-branch pushes and installation syncs - A push scan is skipped when the last scan read the same lockfile shas
/internal/dependency-scanserves repositories, findings and admin-only triage
Findings
🔵 Note · F6 · Push dedupe ignores package.json, so yarn findings keep a stale relation
correctness · packages/backend/src/services/dependency-scan/DependencyScanner.ts:275
sameLockfiles compares only lockfile paths and blob shas, yet a yarn scan also reads package.json (line 144) to classify direct/dev. A commit that only moves a dependency between dependencies and devDependencies, or adds a workspace manifest, returns Unchanged, so findings keep the old relation until yarn.lock itself changes.
Include the scan's manifest blob shas in the unchanged check (store them on the scan row), or skip the dedupe when `selected` holds a yarn lockfile.
Fixed since the last review
- ✅
F5 · Removed repositories' findings still occupy the 500-row read before they are dropped
Production impact
Open errors in the changed files (2)
| Issue | Service | Occurrences | File |
|---|---|---|---|
| @maple/backend/vcs/GithubAppError | maple-api | 24 | packages/backend/src/services/integrations/vcs/VcsSyncService.ts |
| @maple/backend/auth/device/DeviceTokenRejected | maple-api | 3 | apps/api/src/runtime/http-graph.ts |
After this merges, Maple checks whether they stop.
Production traffic of the changed files (last 7 days)
| File | Calls/day | Busiest operations |
|---|---|---|
packages/backend/src/services/integrations/vcs/VcsSyncService.ts |
8.4k | VcsSyncService.resolveRepositoryForJob 8.2k/day, 0.0% errVcsSyncService.handleBranchEvent 218/day, 0.0% err |
Telemetry this change adds and removes (17)
- ➕ span name
DependencyScanService.connectedRepositories·packages/backend/src/services/dependency-scan/DependencyScanService.ts:114 - ➕ span name
DependencyScanner.readLockfile·packages/backend/src/services/dependency-scan/DependencyScanner.ts:196 - ➕ attribute
maple.depscan.lockfile.path·packages/backend/src/services/dependency-scan/DependencyScanner.ts:198 - ➕ attribute
maple.depscan.lockfile.kind·packages/backend/src/services/dependency-scan/DependencyScanner.ts:199 - ➕ span name
DependencyScanner.scan·packages/backend/src/services/dependency-scan/DependencyScanner.ts:226 - ➕ attribute
maple.depscan.trigger·packages/backend/src/services/dependency-scan/DependencyScanner.ts:238 - ➕ attribute
maple.depscan.lockfile_count·packages/backend/src/services/dependency-scan/DependencyScanner.ts:261 - ➕ attribute
maple.depscan.lockfiles_skipped·packages/backend/src/services/dependency-scan/DependencyScanner.ts:262 - ➕ attribute
maple.depscan.tree_truncated·packages/backend/src/services/dependency-scan/DependencyScanner.ts:263 - ➕ attribute
maple.depscan.outcome·packages/backend/src/services/dependency-scan/DependencyScanner.ts:277 - ➕ attribute
maple.depscan.scan_id·packages/backend/src/services/dependency-scan/DependencyScanner.ts:292 - ➕ attribute
maple.depscan.package_count·packages/backend/src/services/dependency-scan/DependencyScanner.ts:315 - ➕ attribute
maple.depscan.match_count·packages/backend/src/services/dependency-scan/DependencyScanner.ts:316 - ➕ span name
VcsSyncService.handleDependencyScan·packages/backend/src/services/integrations/vcs/VcsSyncService.ts:858 - ➕ attribute
maple.depscan.forwarded·packages/backend/src/services/integrations/vcs/VcsSyncService.ts:865 - ➕ span name
GithubAppClient.getRecursiveTree·packages/backend/src/services/integrations/vcs/vendor/github/GithubAppClient.ts:2165 - ➕ span name
GithubAppClient.getBlob·packages/backend/src/services/integrations/vcs/vendor/github/GithubAppClient.ts:2187
What was checked
manifestsFor/sameLockfilesand thego.sum,node_modulesexclusions inlockfile-selection.ts:47-73- Scan pushes enqueue only after the tracked-branch gate in
applyPush(VcsSyncService.ts:425) - Findings reads are org- and repository-scoped in SQL, so a removed repository's rows cannot surface
Observability coverage: 4 of 4 changes observable
| Change | Kind | Observable | Evidence |
|---|---|---|---|
| Dependency scan of one repository (queue job) | background work | yes | DependencyScanner.scan span with maple.depscan.trigger, vcs.commit.sha, maple.depscan.outcome; VcsSyncService.handleDependencyScan span |
| GitHub recursive tree and blob reads | outbound HTTP | yes | GithubAppClient.getRecursiveTree/getBlob spans over the existing authedGet client |
/internal/dependency-scan endpoints |
inbound HTTP | yes | Served by the API HTTP graph; handlers annotate orgId, maple.depscan.repository_id, result.rowCount |
| Failed scan | error path | yes | failScan records the failure on the row; [DependencyScan] scan failed structured log carries the summarized cause |
f416695 · Reply "won't fix" to dismiss a finding, or mention @maple-review-bot to ask about one.
Annotations
Check notice on line 275 in packages/backend/src/services/dependency-scan/DependencyScanner.ts
maple-review-bot / Maple / review
correctness: Push dedupe ignores `package.json`, so yarn findings keep a stale `relation`
`sameLockfiles` compares only lockfile paths and blob shas, yet a yarn scan also reads `package.json` (line 144) to classify direct/dev. A commit that only moves a dependency between `dependencies` and `devDependencies`, or adds a workspace manifest, returns `Unchanged`, so findings keep the old `relation` until `yarn.lock` itself changes.