Config policies (16 files): alert_routing, architecture_pressure, backlog, cost_weights, data_governance, incident_escalation, incident_intelligence, network_allowlist, nodes_registry, observability_sources, rbac_tools_matrix, release_gate, risk_attribution, risk_policy, slo_policy, tool_limits, tools_rollout Ops (22 files): Caddyfile, calendar compose, grafana voice dashboard, deployments/incidents logs, runbooks for alerts/audit/backlog/incidents/sofiia/voice, cron jobs, scripts (alert_triage, audit_cleanup, migrate_*, governance, schedule), task_registry, voice alerts/ha/latency/policy Docs (30+ files): HUMANIZED_STEPAN v2.7-v3 changelogs and runbooks, NODA1/NODA2 status and setup, audit index and traces, backlog, incident, supervisor, tools, voice, opencode, release, risk, aistalk, spacebot Made-with: Cursor
204 lines
5.6 KiB
Markdown
204 lines
5.6 KiB
Markdown
# dependency_scanner_tool
|
|
|
|
Scans Python and Node.js dependencies for known vulnerabilities, outdated packages, and license policy violations.
|
|
Integrates as **Gate 3** in `release_check`.
|
|
|
|
---
|
|
|
|
## Purpose
|
|
|
|
| Concern | Source A | Source B |
|
|
|---|---|---|
|
|
| **Vulnerabilities** | OSV.dev database (online or cached) | Pinned deps from lock files |
|
|
| **Outdated packages** | Fixed versions in OSV findings | Current versions in lock files |
|
|
| **License policy** | Configured deny/warn list | Package metadata (limited in MVP) |
|
|
|
|
---
|
|
|
|
## RBAC
|
|
|
|
| Entitlement | Grants |
|
|
|---|---|
|
|
| `tools.deps.read` | Run scan (agent_cto, agent_oncall) |
|
|
| `tools.deps.gate` | Gate execution in release_check (agent_cto only) |
|
|
|
|
---
|
|
|
|
## Limits (`config/tool_limits.yml`)
|
|
|
|
| Param | Value |
|
|
|---|---|
|
|
| `timeout_ms` | 45 000 ms |
|
|
| `max_chars_in` | 3 000 |
|
|
| `max_bytes_out` | 1 048 576 (1 MB) |
|
|
| `rate_limit_rpm` | 5 |
|
|
| `concurrency` | 1 |
|
|
|
|
---
|
|
|
|
## Invocation
|
|
|
|
```json
|
|
{
|
|
"tool": "dependency_scanner_tool",
|
|
"action": "scan",
|
|
"targets": ["python", "node"],
|
|
"vuln_mode": "offline_cache",
|
|
"fail_on": ["CRITICAL", "HIGH"],
|
|
"timeout_sec": 40
|
|
}
|
|
```
|
|
|
|
### Parameters
|
|
|
|
| Param | Type | Default | Description |
|
|
|---|---|---|---|
|
|
| `action` | string | — | Must be `"scan"` |
|
|
| `targets` | array | `["python","node"]` | Ecosystems to scan |
|
|
| `vuln_mode` | string | `"offline_cache"` | `"online"` queries api.osv.dev; `"offline_cache"` uses local cache only |
|
|
| `fail_on` | array | `["CRITICAL","HIGH"]` | Severity levels that block release |
|
|
| `timeout_sec` | number | `40` | Hard wall-clock timeout |
|
|
|
|
---
|
|
|
|
## Response
|
|
|
|
```json
|
|
{
|
|
"pass": true,
|
|
"summary": "✅ Dependency scan PASSED. 120 deps scanned, 0 vulns found.",
|
|
"stats": {
|
|
"ecosystems": ["PyPI", "npm"],
|
|
"files_scanned": 4,
|
|
"deps_total": 120,
|
|
"deps_pinned": 115,
|
|
"deps_unresolved": 3,
|
|
"vulns_total": 0,
|
|
"by_severity": {"CRITICAL": 0, "HIGH": 0, "MEDIUM": 0, "LOW": 0, "UNKNOWN": 0},
|
|
"outdated_total": 0
|
|
},
|
|
"vulnerabilities": [],
|
|
"outdated": [],
|
|
"licenses": [],
|
|
"recommendations": []
|
|
}
|
|
```
|
|
|
|
### Vulnerability object
|
|
|
|
```json
|
|
{
|
|
"id": "GHSA-35jh-r3h4-6jhm",
|
|
"ecosystem": "npm",
|
|
"package": "lodash",
|
|
"version": "4.17.20",
|
|
"severity": "HIGH",
|
|
"fixed_versions": ["4.17.21"],
|
|
"aliases": ["CVE-2021-23337"],
|
|
"evidence": {"file": "services/render-pptx-worker/package-lock.json", "details": "lodash==4.17.20"},
|
|
"recommendation": "Upgrade lodash from 4.17.20 to 4.17.21"
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Pass / Fail Rule
|
|
|
|
| Condition | Result |
|
|
|---|---|
|
|
| Any `CRITICAL` or `HIGH` vuln found | `pass=false` (gate blocks) |
|
|
| Any denied license found | `pass=false` |
|
|
| `MEDIUM` vulns only | `pass=true`, added to recommendations |
|
|
| `UNKNOWN` severity (cache miss) | `pass=true`, recommendation to populate cache |
|
|
|
|
---
|
|
|
|
## Supported Manifest Files
|
|
|
|
### Python (priority order)
|
|
1. `poetry.lock` — fully resolved versions
|
|
2. `Pipfile.lock` — resolved versions
|
|
3. `requirements*.txt` — only `==` pinned lines are scanned; unpinned noted
|
|
4. `pyproject.toml` — declared deps listed (no version resolution)
|
|
|
|
### Node.js (priority order)
|
|
1. `package-lock.json` (npm v2/v3)
|
|
2. `pnpm-lock.yaml`
|
|
3. `yarn.lock`
|
|
4. `package.json` — only if no lock file present
|
|
|
|
---
|
|
|
|
## Vulnerability Sources
|
|
|
|
### OSV.dev
|
|
|
|
**Online mode** (`vuln_mode=online`):
|
|
- Queries `https://api.osv.dev/v1/querybatch` in batches of 100
|
|
- Requires entry in `config/network_allowlist.yml` (`dependency_scanner_tool.hosts: api.osv.dev`)
|
|
- New results are cached to `ops/cache/osv_cache.json`
|
|
|
|
**Offline cache mode** (`vuln_mode=offline_cache`, default):
|
|
- Reads from `ops/cache/osv_cache.json` only
|
|
- Cache misses → severity `UNKNOWN` (not blocking by default)
|
|
- No outbound network calls
|
|
|
|
**Cache format** (`ops/cache/osv_cache.json`):
|
|
```json
|
|
{
|
|
"version": 1,
|
|
"updated_at": "...",
|
|
"entries": {
|
|
"PyPI:requests:2.31.0": {"vulns": [], "cached_at": "..."},
|
|
"npm:lodash:4.17.20": {"vulns": [...], "cached_at": "..."}
|
|
}
|
|
}
|
|
```
|
|
Cache key: `{ecosystem}:{normalized_name}:{version}`
|
|
|
|
---
|
|
|
|
## Security
|
|
|
|
- **Read-only**: scans lock files; no writes (except optional cache update in online mode)
|
|
- **Evidence redaction**: secrets/tokens masked before inclusion in report
|
|
- **No payload logging**: only hash of dep list + counts logged to audit trail
|
|
- **Path traversal protection**: excluded dirs (`node_modules`, `.git`, `.venv`, etc.)
|
|
- **Size limits**: max 80 files, 2000 deps, 500 vulns enforced in code
|
|
|
|
---
|
|
|
|
## Integration in release_check
|
|
|
|
Gate order: `pr_review` → `config_lint` → **`dependency_scan`** → `contract_diff` → `threat_model` → `smoke` → `drift`
|
|
|
|
`release_check` inputs related to this gate:
|
|
|
|
| Input | Type | Default | Description |
|
|
|---|---|---|---|
|
|
| `run_deps` | boolean | `true` | Enable dependency scan gate |
|
|
| `deps_targets` | array | `["python","node"]` | Ecosystems |
|
|
| `deps_vuln_mode` | string | `"offline_cache"` | OSV mode |
|
|
| `deps_fail_on` | array | `["CRITICAL","HIGH"]` | Blocking severity |
|
|
| `deps_timeout_sec` | number | `40` | Timeout |
|
|
|
|
---
|
|
|
|
## Outdated Analysis (lockfile_only mode)
|
|
|
|
In MVP, "latest version" is inferred from OSV `fixed_versions` only (no registry lookup).
|
|
An upgrade is recommended if a fixed version > current version exists in an OSV finding.
|
|
|
|
Full latest-version lookup (PyPI/npm registry) is planned as an optional enhancement.
|
|
|
|
---
|
|
|
|
## Extending the Cache
|
|
|
|
To refresh the offline cache:
|
|
1. Set `vuln_mode: online` in a controlled environment with outbound access to `api.osv.dev`
|
|
2. Run `dependency_scanner_tool` — new entries are merged into `ops/cache/osv_cache.json`
|
|
3. Commit the updated cache file
|
|
|
|
Or use `ops/scripts/refresh_osv_cache.py` (planned).
|