Skip to content

Commit a6c7fd4

Browse files
committed
chore: update docs
1 parent ed3308a commit a6c7fd4

1 file changed

Lines changed: 23 additions & 3 deletions

File tree

  • services/apps/git_integration/src/crowdgit/services/vulnerability_scanner

services/apps/git_integration/src/crowdgit/services/vulnerability_scanner/README.md

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,14 @@ The binary follows the same **subprocess + JSON stdout** pattern used by the `so
2020

2121
## Key design decisions
2222

23-
### OSV Scanner returns a non-nil error when vulnerabilities are found
23+
### OSV Scanner uses sentinel errors for expected outcomes
2424

25-
This is counterintuitive but intentional — OSV Scanner behaves like `grep`: it returns a non-zero/error when it finds matches. We treat this as success and only propagate the error if no results came back alongside it.
25+
OSV Scanner returns sentinel errors for two non-failure cases:
26+
27+
- `ErrVulnerabilitiesFound` — the scanner found vulnerabilities. Like `grep` returning exit code 1 on a match, this is an expected outcome. We treat it as success and surface the results normally.
28+
- `ErrNoPackagesFound` — the repo contains no scannable package manifests (e.g. a pure C or shell project). This is not a failure — the scanner ran correctly and determined there is nothing to check. The scan record gets status `no_packages_found` and the Python side does not treat it as an error.
29+
30+
Any other non-nil error from the scanner is a real failure.
2631

2732
### Vulnerability identity: (repo_url, vulnerability_id, package_name, source_path)
2833

@@ -59,9 +64,19 @@ On each scan, rather than deleting all previous findings and inserting fresh one
5964

6065
This preserves history. You can tell when a vulnerability was first detected, when it was last seen, and when it went away — without needing a separate audit log. It also makes it cheap to compute `new_count` (rows that were truly inserted, not updated) and `resolved_count` (rows still carrying the newly-set `resolved_at` after the upsert pass).
6166

67+
### Transitive dependency scanning
68+
69+
By default the scanner resolves the full transitive dependency graph, not just direct dependencies declared in lockfiles. This catches vulnerabilities in indirect deps that the project never explicitly references.
70+
71+
Transitive scanning is expensive for repos with large or deep package ecosystems — projects like ML frameworks with hundreds of transitive Python dependencies can exhaust the 3-minute scan timeout. The scanner handles this automatically:
72+
73+
1. **First scan**: attempt with transitive=true. If it times out, retry immediately with transitive=false (direct deps only). The result of whichever mode succeeded is stored.
74+
2. **Subsequent scans**: reuse the same mode as the previous completed scan (`transitive_deps_scanned` stored per scan record). This avoids flip-flopping between modes and keeps results comparable across scans.
75+
76+
6277
### Scan tracking
6378

64-
Every invocation creates a row in `vulnerability_scans` before the scan starts (status: running) and updates it on completion with duration, counts, and any error. This makes it possible to detect stalled or crashed scans and gives a simple history of scan health per repo.
79+
Every invocation creates a row in `vulnerability_scans` before the scan starts (status: `running`) and updates it on completion with duration, counts, and any error. Terminal statuses are `success`, `no_packages_found`, and `failure`. This makes it possible to detect stalled or crashed scans and gives a simple history of scan health per repo.
6580

6681
## Building
6782

@@ -85,3 +100,8 @@ Output is a JSON object on stdout:
85100
```json
86101
{ "status": "success", "error_code": null, "error_message": null }
87102
```
103+
104+
On repos with no scannable package manifests:
105+
```json
106+
{ "status": "no_packages_found", "error_code": null, "error_message": null }
107+
```

0 commit comments

Comments
 (0)