praxis-sec 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +170 -0
- package/ai-defense/cost-protection.md +292 -0
- package/ai-defense/llm-security-checklist.md +324 -0
- package/ai-defense/prompt-injection-patterns.js +283 -0
- package/ai-defense/system-prompt-armor.md +327 -0
- package/checklists/launch-day.md +168 -0
- package/cli/agents/abom-generator.js +225 -0
- package/cli/agents/agent-attestation-agent.js +318 -0
- package/cli/agents/agent-config-scanner.js +787 -0
- package/cli/agents/agent-telemetry-agent.js +415 -0
- package/cli/agents/agentic-security-agent.js +296 -0
- package/cli/agents/agentic-supply-chain-agent.js +463 -0
- package/cli/agents/ai-infra-inventory-agent.js +449 -0
- package/cli/agents/api-fuzzer.js +345 -0
- package/cli/agents/auth-bypass-agent.js +348 -0
- package/cli/agents/base-agent.js +280 -0
- package/cli/agents/cicd-scanner.js +300 -0
- package/cli/agents/config-auditor.js +757 -0
- package/cli/agents/deep-analyzer.js +776 -0
- package/cli/agents/endpoint-agent-abuse-agent.js +404 -0
- package/cli/agents/exception-handler-agent.js +187 -0
- package/cli/agents/git-history-scanner.js +169 -0
- package/cli/agents/governance-audits.js +138 -0
- package/cli/agents/hermes-security-agent.js +536 -0
- package/cli/agents/html-reporter.js +1125 -0
- package/cli/agents/index.js +147 -0
- package/cli/agents/injection-tester.js +502 -0
- package/cli/agents/legal-risk-agent.js +328 -0
- package/cli/agents/llm-redteam.js +199 -0
- package/cli/agents/managed-agent-scanner.js +333 -0
- package/cli/agents/mcp-security-agent.js +588 -0
- package/cli/agents/memory-poisoning-agent.js +305 -0
- package/cli/agents/mobile-scanner.js +231 -0
- package/cli/agents/model-file-scanner.js +259 -0
- package/cli/agents/orchestrator.js +355 -0
- package/cli/agents/pii-compliance-agent.js +301 -0
- package/cli/agents/policy-engine.js +229 -0
- package/cli/agents/prompt-injection-prober.js +224 -0
- package/cli/agents/rag-security-agent.js +204 -0
- package/cli/agents/recon-agent.js +207 -0
- package/cli/agents/sbom-generator.js +265 -0
- package/cli/agents/scoring-engine.js +273 -0
- package/cli/agents/ssrf-prober.js +130 -0
- package/cli/agents/stateful-watcher.js +238 -0
- package/cli/agents/supabase-rls-agent.js +154 -0
- package/cli/agents/supply-chain-agent.js +857 -0
- package/cli/agents/swarm-orchestrator.js +200 -0
- package/cli/agents/verifier-agent.js +303 -0
- package/cli/agents/vibe-coding-agent.js +250 -0
- package/cli/bin/praxis.js +866 -0
- package/cli/commands/abom.js +73 -0
- package/cli/commands/agent-fix.js +1245 -0
- package/cli/commands/audit.js +1180 -0
- package/cli/commands/autofix.js +383 -0
- package/cli/commands/baseline.js +193 -0
- package/cli/commands/benchmark.js +327 -0
- package/cli/commands/checklist.js +223 -0
- package/cli/commands/ci.js +403 -0
- package/cli/commands/deps.js +516 -0
- package/cli/commands/diff.js +200 -0
- package/cli/commands/doctor.js +195 -0
- package/cli/commands/env-audit.js +349 -0
- package/cli/commands/fix.js +218 -0
- package/cli/commands/guard.js +396 -0
- package/cli/commands/hooks.js +278 -0
- package/cli/commands/init.js +514 -0
- package/cli/commands/legal.js +158 -0
- package/cli/commands/live-advisories.js +241 -0
- package/cli/commands/mcp.js +660 -0
- package/cli/commands/openclaw.js +386 -0
- package/cli/commands/red-team.js +350 -0
- package/cli/commands/redteam.js +78 -0
- package/cli/commands/remediate.js +797 -0
- package/cli/commands/rotate.js +768 -0
- package/cli/commands/rules.js +196 -0
- package/cli/commands/scan-mcp.js +534 -0
- package/cli/commands/scan-skill.js +588 -0
- package/cli/commands/scan-standard.js +251 -0
- package/cli/commands/scan.js +524 -0
- package/cli/commands/score.js +449 -0
- package/cli/commands/shell.js +514 -0
- package/cli/commands/team-report.js +398 -0
- package/cli/commands/undo.js +161 -0
- package/cli/commands/update-intel.js +126 -0
- package/cli/commands/vibe-check.js +276 -0
- package/cli/commands/watch.js +757 -0
- package/cli/commands/web.js +63 -0
- package/cli/core/ast/guardrail-detector.js +141 -0
- package/cli/core/ast/index.js +22 -0
- package/cli/core/ast/parser.js +676 -0
- package/cli/core/ast/scope-tree.js +287 -0
- package/cli/core/ast/taint-tracker.js +158 -0
- package/cli/core/branding.js +37 -0
- package/cli/core/env.js +38 -0
- package/cli/core/errors.js +61 -0
- package/cli/core/fs.js +62 -0
- package/cli/core/output/compliance.js +90 -0
- package/cli/core/output/html-theme.js +158 -0
- package/cli/core/output/index.js +57 -0
- package/cli/core/output/json.js +48 -0
- package/cli/core/output/sarif.js +240 -0
- package/cli/core/version.js +67 -0
- package/cli/core/web/jobs.js +183 -0
- package/cli/core/web/projects.js +146 -0
- package/cli/core/web/server.js +439 -0
- package/cli/data/atlas-knowledge.json +5640 -0
- package/cli/data/eaa-catalog.json +39 -0
- package/cli/data/known-mcps.json +26 -0
- package/cli/data/probes/prompt-injection-corpus.json +271 -0
- package/cli/data/threat-intel.json +85 -0
- package/cli/data/threatpacks/latest.json +41 -0
- package/cli/hooks/patterns.js +313 -0
- package/cli/hooks/post-tool-use.js +140 -0
- package/cli/hooks/pre-tool-use.js +186 -0
- package/cli/index.js +90 -0
- package/cli/providers/llm-provider.js +766 -0
- package/cli/utils/autofix-rules.js +74 -0
- package/cli/utils/cache-manager.js +310 -0
- package/cli/utils/compliance-map.js +191 -0
- package/cli/utils/entropy.js +132 -0
- package/cli/utils/fix-ledger.js +127 -0
- package/cli/utils/hermes-tool-registry.js +252 -0
- package/cli/utils/intel/cache.js +61 -0
- package/cli/utils/intel/http.js +88 -0
- package/cli/utils/intel/index.js +235 -0
- package/cli/utils/intel/merge.js +229 -0
- package/cli/utils/intel/sources/epss.js +54 -0
- package/cli/utils/intel/sources/ghsa.js +81 -0
- package/cli/utils/intel/sources/gitguardian.js +40 -0
- package/cli/utils/intel/sources/gitleaks.js +101 -0
- package/cli/utils/intel/sources/kev.js +38 -0
- package/cli/utils/intel/sources/nvd.js +84 -0
- package/cli/utils/intel/sources/osv.js +132 -0
- package/cli/utils/intel/sources/phylum.js +44 -0
- package/cli/utils/intel/sources/snyk.js +46 -0
- package/cli/utils/intel/sources/socket.js +69 -0
- package/cli/utils/intel/sources/sonatype.js +84 -0
- package/cli/utils/intel/sources/threatpack.js +69 -0
- package/cli/utils/mcp-trust.js +60 -0
- package/cli/utils/output.js +251 -0
- package/cli/utils/patterns.js +1130 -0
- package/cli/utils/pdf-generator.js +94 -0
- package/cli/utils/plugin-loader.js +364 -0
- package/cli/utils/rule-import.js +228 -0
- package/cli/utils/rule-registry.js +426 -0
- package/cli/utils/scan-fingerprint.js +109 -0
- package/cli/utils/scan-playbook.js +312 -0
- package/cli/utils/score-history.js +119 -0
- package/cli/utils/secrets-verifier.js +247 -0
- package/cli/utils/security-memory.js +296 -0
- package/cli/utils/standards/atlas-knowledge.js +87 -0
- package/cli/utils/standards/index.js +127 -0
- package/cli/utils/standards/sources/avid.js +45 -0
- package/cli/utils/standards/sources/eu-ai-act.js +89 -0
- package/cli/utils/standards/sources/google-saif.js +39 -0
- package/cli/utils/standards/sources/iso-42001.js +94 -0
- package/cli/utils/standards/sources/mitre-atlas.js +54 -0
- package/cli/utils/standards/sources/nist-ai-600-1.js +45 -0
- package/cli/utils/standards/sources/owasp-llm.js +45 -0
- package/cli/utils/standards/sources/owasp-ml.js +45 -0
- package/cli/utils/threat-intel.js +265 -0
- package/configs/firebase/firestore-rules.txt +215 -0
- package/configs/firebase/security-checklist.md +236 -0
- package/configs/firebase/storage-rules.txt +206 -0
- package/configs/gitignore-template +258 -0
- package/configs/nextjs-security-headers.js +220 -0
- package/configs/praxisignore-template +50 -0
- package/configs/supabase/secure-client.ts +225 -0
- package/configs/supabase/security-checklist.md +278 -0
- package/docs/THIRD_PARTY_NOTICES.md +26 -0
- package/docs/THREAT_INTEL.md +292 -0
- package/docs/USAGE.md +1205 -0
- package/docs/design/WEB-UI.md +82 -0
- package/package.json +71 -0
- package/scripts/check-determinism.mjs +119 -0
- package/snippets/README.md +122 -0
- package/snippets/api-security/api-security-checklist.md +412 -0
- package/snippets/api-security/cors-config.ts +322 -0
- package/snippets/api-security/input-validation.ts +430 -0
- package/snippets/auth/jwt-checklist.md +322 -0
- package/snippets/rate-limiting/nextjs-middleware.ts +211 -0
- package/snippets/rate-limiting/upstash-ratelimit.ts +229 -0
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
# Threat Intelligence — Praxis
|
|
2
|
+
|
|
3
|
+
This is the local quick reference for the multi-source threat-intel system that
|
|
4
|
+
powers `praxis scan`, `praxis intel deps`, the supply-chain agent, and every
|
|
5
|
+
other command that consumes the merged feed. It explains what each command
|
|
6
|
+
does, how the system is laid out internally, and what knobs you can turn.
|
|
7
|
+
|
|
8
|
+
For everything else (general CLI usage, scanning, hooks, etc.), see the main
|
|
9
|
+
[`README.md`](./README.md).
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## 1. Commands
|
|
14
|
+
|
|
15
|
+
Run these from any directory — they only touch `~/.praxis/` (your home dir).
|
|
16
|
+
|
|
17
|
+
| Command | What it does |
|
|
18
|
+
| --- | --- |
|
|
19
|
+
| `praxis intel update` | Refresh every configured source in parallel |
|
|
20
|
+
| `praxis intel update --list` | List all available sources and which are active |
|
|
21
|
+
| `praxis intel update --only osv,kev,epss` | Refresh a subset (comma-separated names) |
|
|
22
|
+
| `praxis intel update --force` | Ignore per-source TTL caches and re-fetch |
|
|
23
|
+
| `praxis scan ci .` | Normal CI run (does not enforce intel freshness) |
|
|
24
|
+
| `praxis scan ci . --strict-intel` | Fail CI if the merged feed is stale or core sources errored |
|
|
25
|
+
| `praxis scan ci . --strict-intel --max-intel-age 24h` | Custom freshness window (`7d`, `24h`, `30m`, `60s`) |
|
|
26
|
+
|
|
27
|
+
`praxis intel update` is safe to run any time — it caches per source and falls
|
|
28
|
+
back to the last good payload if a source is offline. Stale data is preferred
|
|
29
|
+
over no data.
|
|
30
|
+
|
|
31
|
+
### First-time setup
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
# Pull every free source. No keys required.
|
|
35
|
+
praxis intel update
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Expected output:
|
|
39
|
+
|
|
40
|
+
```
|
|
41
|
+
Fetching sources...
|
|
42
|
+
|
|
43
|
+
osv OK
|
|
44
|
+
ghsa OK
|
|
45
|
+
kev OK
|
|
46
|
+
epss OK
|
|
47
|
+
nvd OK
|
|
48
|
+
gitleaks OK
|
|
49
|
+
snyk skipped (SNYK_TOKEN not set)
|
|
50
|
+
socket skipped (SOCKET_API_KEY not set)
|
|
51
|
+
...
|
|
52
|
+
|
|
53
|
+
Merged feed v1.0.1 written.
|
|
54
|
+
|
|
55
|
+
Indicators loaded:
|
|
56
|
+
CVE advisories: ...
|
|
57
|
+
KEV entries: 1586
|
|
58
|
+
EPSS scores: ...
|
|
59
|
+
Extra secret rules: 221
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### CI usage
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
# Soft mode — runs even if the feed is missing.
|
|
66
|
+
praxis scan ci .
|
|
67
|
+
|
|
68
|
+
# Hard mode — fails the build if intel is older than 7 days
|
|
69
|
+
# or any core source erred on the last update.
|
|
70
|
+
praxis scan ci . --strict-intel
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
## 2. Architecture
|
|
76
|
+
|
|
77
|
+
```
|
|
78
|
+
cli/
|
|
79
|
+
├── bin/
|
|
80
|
+
│ └── praxis.js # CLI entry; defines update-intel + ci flags
|
|
81
|
+
├── commands/
|
|
82
|
+
│ ├── update-intel.js # User-facing command (progress, summary)
|
|
83
|
+
│ └── ci.js # Reads intel-meta.json, applies strict-intel
|
|
84
|
+
├── utils/
|
|
85
|
+
│ ├── threat-intel.js # ThreatIntel class — query API
|
|
86
|
+
│ └── intel/
|
|
87
|
+
│ ├── index.js # runUpdate() orchestrator + isStale()
|
|
88
|
+
│ ├── cache.js # Per-source TTL'd disk cache
|
|
89
|
+
│ ├── http.js # safeFetch (timeout + retry + backoff)
|
|
90
|
+
│ ├── merge.js # mergeIntel(seed, results) → unified schema
|
|
91
|
+
│ └── sources/
|
|
92
|
+
│ ├── osv.js # core
|
|
93
|
+
│ ├── ghsa.js # core
|
|
94
|
+
│ ├── kev.js # core
|
|
95
|
+
│ ├── epss.js # core
|
|
96
|
+
│ ├── nvd.js # core
|
|
97
|
+
│ ├── gitleaks.js # core
|
|
98
|
+
│ ├── snyk.js # optional
|
|
99
|
+
│ ├── socket.js # optional
|
|
100
|
+
│ ├── gitguardian.js # optional
|
|
101
|
+
│ ├── sonatype.js # optional (works anonymously, env raises limits)
|
|
102
|
+
│ └── phylum.js # optional
|
|
103
|
+
└── agents/
|
|
104
|
+
└── supply-chain-agent.js # Consumes ThreatIntel.lookupOsv / lookupGhsa,
|
|
105
|
+
# enriches findings with KEV/EPSS signals
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### Update flow
|
|
109
|
+
|
|
110
|
+
1. `praxis intel update` calls `runUpdate()` in `cli/utils/intel/index.js`.
|
|
111
|
+
2. **Pass 1** — every source except NVD runs in parallel via `Promise.all`.
|
|
112
|
+
- Each source first checks `cache.read(name)`. If the cache is fresh
|
|
113
|
+
(within its TTL), it's reused and `'cached'` is reported.
|
|
114
|
+
- Otherwise it calls `source.fetchAll()`, writes the result to
|
|
115
|
+
`~/.praxis/intel/<name>.json`, and reports `'ok'`.
|
|
116
|
+
- On fetch error, the source falls back to whatever's in the cache
|
|
117
|
+
(even if stale) so a transient outage doesn't blow away your data.
|
|
118
|
+
- Optional sources without their env var return `{ skipped: true }` and
|
|
119
|
+
are reported `'skipped'`.
|
|
120
|
+
3. **Pass 2** — NVD runs after Pass 1, using the union of CVEs collected from
|
|
121
|
+
OSV/GHSA/KEV to decide which CVE descriptions to fetch (capped at 500).
|
|
122
|
+
4. `mergeIntel(seed, results)` produces the unified feed. Internal merge
|
|
123
|
+
functions per source build:
|
|
124
|
+
- `osvIndex[ecosystem/package]` → array of advisories
|
|
125
|
+
- `ghsaIndex[ecosystem/package]` → array of advisories
|
|
126
|
+
- `cveAdvisories[]` (deduplicated by CVE)
|
|
127
|
+
- `kevList[]`, `kevDetails{}`, `epssScores{}`, `nvdDetails{}`
|
|
128
|
+
- `secretRules[]` (Gitleaks regex rules)
|
|
129
|
+
- `sources{}` (per-source status / stats / error)
|
|
130
|
+
5. The merged feed is written to `~/.praxis/threat-intel.json` and a
|
|
131
|
+
summary to `~/.praxis/intel-meta.json`.
|
|
132
|
+
|
|
133
|
+
### Query flow
|
|
134
|
+
|
|
135
|
+
`ThreatIntel` (in `cli/utils/threat-intel.js`) lazy-loads the merged feed once
|
|
136
|
+
and caches it in memory. Resolution order:
|
|
137
|
+
|
|
138
|
+
1. `~/.praxis/threat-intel.json` (merged feed)
|
|
139
|
+
2. `cli/data/threat-intel.json` (bundled seed)
|
|
140
|
+
|
|
141
|
+
Public API (used by agents and scanners):
|
|
142
|
+
|
|
143
|
+
```js
|
|
144
|
+
ThreatIntel.lookupOsv(pkg, version, ecosystem) // → [{...advisory, isAffected}]
|
|
145
|
+
ThreatIntel.lookupGhsa(pkg, ecosystem)
|
|
146
|
+
ThreatIntel.getEpss(cve) // → {score, percentile} | null
|
|
147
|
+
ThreatIntel.isInKev(cve) // → bool
|
|
148
|
+
ThreatIntel.getKevDetails(cve)
|
|
149
|
+
ThreatIntel.getNvdDetail(cve)
|
|
150
|
+
ThreatIntel.getExtraSecretRules() // → [{id, regex, ...}]
|
|
151
|
+
ThreatIntel.stats() // → counts for each indicator
|
|
152
|
+
ThreatIntel.isStale(maxAgeMs)
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
### File layout (on disk)
|
|
156
|
+
|
|
157
|
+
```
|
|
158
|
+
~/.praxis/
|
|
159
|
+
├── intel/
|
|
160
|
+
│ ├── osv.json # raw per-source payload + fetchedAt + ttlMs
|
|
161
|
+
│ ├── ghsa.json
|
|
162
|
+
│ ├── kev.json
|
|
163
|
+
│ └── ...
|
|
164
|
+
├── threat-intel.json # merged feed (everything joined into one file)
|
|
165
|
+
└── intel-meta.json # { updatedAt, version, sources: {...} }
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
You can delete any of these to force a clean re-fetch. They will be recreated
|
|
169
|
+
on the next `praxis intel update` run.
|
|
170
|
+
|
|
171
|
+
---
|
|
172
|
+
|
|
173
|
+
## 3. Customization
|
|
174
|
+
|
|
175
|
+
### Sources
|
|
176
|
+
|
|
177
|
+
| Source | Tier | Env var | TTL | Notes |
|
|
178
|
+
| --- | --- | --- | --- | --- |
|
|
179
|
+
| `osv` | core | — | 12h | OSV.dev queries (npm, PyPI, Go, Maven, NuGet, RubyGems...) |
|
|
180
|
+
| `ghsa` | core | `GITHUB_TOKEN` or `GH_TOKEN` *(optional, raises rate limit)* | 12h | GitHub Advisory DB |
|
|
181
|
+
| `kev` | core | — | 24h | CISA Known Exploited Vulnerabilities |
|
|
182
|
+
| `epss` | core | — | 24h | FIRST.org exploit-likelihood scores |
|
|
183
|
+
| `nvd` | core | `NVD_API_KEY` *(optional, faster requests)* | 7d | CVE detail enrichment |
|
|
184
|
+
| `gitleaks` | core | — | 7d | Gitleaks regex rule set |
|
|
185
|
+
| `threatpack` | core | — (override with `PRAXIS_THREATPACK_URL`) | 7d | Praxis AI attack-vector signature pack — prompt-injection probes, EAA additions, model-gateway allowlists. Bundled seed at `cli/data/threatpacks/latest.json`; a fetch failure degrades to the seed |
|
|
186
|
+
| `snyk` | optional | `SNYK_TOKEN` (+ `SNYK_ORG_ID`) | 12h | Snyk Vulnerability DB |
|
|
187
|
+
| `socket` | optional | `SOCKET_API_KEY` | 6h | Socket.dev supply-chain risk |
|
|
188
|
+
| `gitguardian` | optional | `GITGUARDIAN_API_KEY` | 7d | GitGuardian secret detector defs |
|
|
189
|
+
| `sonatype` | optional | `SONATYPE_USER` + `SONATYPE_TOKEN` *(works anonymously too)* | 12h | OSS Index |
|
|
190
|
+
| `phylum` | optional | `PHYLUM_API_KEY` | 6h | Phylum supply-chain risk |
|
|
191
|
+
|
|
192
|
+
Without any env vars the system fully works using the seven core sources. Optional
|
|
193
|
+
sources gracefully report `skipped` and don't fail the run.
|
|
194
|
+
|
|
195
|
+
### Environment variables
|
|
196
|
+
|
|
197
|
+
```bash
|
|
198
|
+
# Optional — speeds up GHSA and NVD by raising rate limits.
|
|
199
|
+
export GITHUB_TOKEN=ghp_...
|
|
200
|
+
export NVD_API_KEY=...
|
|
201
|
+
|
|
202
|
+
# Optional paid sources — enable any subset by setting the corresponding key.
|
|
203
|
+
export SNYK_TOKEN=...
|
|
204
|
+
export SNYK_ORG_ID=...
|
|
205
|
+
export SOCKET_API_KEY=...
|
|
206
|
+
export GITGUARDIAN_API_KEY=...
|
|
207
|
+
export SONATYPE_USER=...
|
|
208
|
+
export SONATYPE_TOKEN=...
|
|
209
|
+
export PHYLUM_API_KEY=...
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
After setting an env var, run `praxis intel update --list` to confirm it
|
|
213
|
+
shows up as `[active]`.
|
|
214
|
+
|
|
215
|
+
### Tuning freshness
|
|
216
|
+
|
|
217
|
+
Per-source TTLs are constants at the top of each
|
|
218
|
+
`cli/utils/intel/sources/<name>.js` file (see the table above). To shorten the
|
|
219
|
+
TTL — e.g. fetch KEV every 6 hours instead of 24 — edit `kev.js`:
|
|
220
|
+
|
|
221
|
+
```js
|
|
222
|
+
const TTL_MS = 6 * 60 * 60 * 1000;
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
### CI freshness gate
|
|
226
|
+
|
|
227
|
+
```bash
|
|
228
|
+
praxis scan ci . --strict-intel --max-intel-age 24h
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
Accepted duration formats: `7d`, `24h`, `30m`, `60s`. Default is `7d`. The
|
|
232
|
+
gate fails if either:
|
|
233
|
+
- `~/.praxis/intel-meta.json` is missing or older than the threshold, **or**
|
|
234
|
+
- any **core** source's last update errored without a stale-cache fallback.
|
|
235
|
+
|
|
236
|
+
Optional/paid sources never fail the gate — only core sources do.
|
|
237
|
+
|
|
238
|
+
### Adding a custom source
|
|
239
|
+
|
|
240
|
+
A source is just an ES module that exports five things:
|
|
241
|
+
|
|
242
|
+
```js
|
|
243
|
+
// cli/utils/intel/sources/my-source.js
|
|
244
|
+
export const name = 'mysource';
|
|
245
|
+
export const tier = 'optional'; // 'core' or 'optional'
|
|
246
|
+
export const description = 'My custom advisory feed';
|
|
247
|
+
export const envKey = 'MYSOURCE_API_KEY'; // optional
|
|
248
|
+
export const TTL = 6 * 60 * 60 * 1000; // 6h
|
|
249
|
+
|
|
250
|
+
export async function fetchAll(args) {
|
|
251
|
+
const key = process.env.MYSOURCE_API_KEY;
|
|
252
|
+
if (!key) return { skipped: true, reason: 'MYSOURCE_API_KEY not set' };
|
|
253
|
+
// ...fetch and return a payload...
|
|
254
|
+
return { records: [...] };
|
|
255
|
+
}
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
Then register it in `cli/utils/intel/index.js`:
|
|
259
|
+
|
|
260
|
+
```js
|
|
261
|
+
import * as mysource from './sources/my-source.js';
|
|
262
|
+
const ALL_SOURCES = [..., mysource];
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
If you want the merger to do something special with the payload (e.g. populate
|
|
266
|
+
`osvIndex`), add a case for `name === 'mysource'` in `cli/utils/intel/merge.js`.
|
|
267
|
+
Otherwise it'll just appear under `sources.mysource` in the merged feed without
|
|
268
|
+
contributing to any index.
|
|
269
|
+
|
|
270
|
+
### Reset everything
|
|
271
|
+
|
|
272
|
+
```bash
|
|
273
|
+
rm -rf ~/.praxis/intel ~/.praxis/threat-intel.json ~/.praxis/intel-meta.json
|
|
274
|
+
praxis intel update
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
This wipes all caches and the merged feed. The bundled seed at
|
|
278
|
+
`cli/data/threat-intel.json` is untouched, so scanning still works in the
|
|
279
|
+
window between deletion and the next update.
|
|
280
|
+
|
|
281
|
+
---
|
|
282
|
+
|
|
283
|
+
## 4. Troubleshooting
|
|
284
|
+
|
|
285
|
+
| Symptom | Cause / fix |
|
|
286
|
+
| --- | --- |
|
|
287
|
+
| `Indicators loaded: 0` after a successful update | The in-memory `ThreatIntel` cache wasn't invalidated — re-run the command, or restart the process. |
|
|
288
|
+
| `praxis intel update` is slow | NVD is rate-limited (6s between requests without a key). Set `NVD_API_KEY` to drop to 600ms. |
|
|
289
|
+
| GHSA reports `error: HTTP 403` | Set `GITHUB_TOKEN` to lift the unauthenticated rate limit. |
|
|
290
|
+
| A source reports `error` but the run still succeeds | By design — the orchestrator falls back to the cached payload. Check `~/.praxis/intel/<source>.json` for the last known good copy. |
|
|
291
|
+
| `praxis scan ci --strict-intel` fails locally | Run `praxis intel update` first. The freshness window defaults to 7 days. |
|
|
292
|
+
| Feed lives somewhere else | `~/.praxis/` is derived from `os.homedir()`. Override `HOME` (Unix) or `USERPROFILE` (Windows) to relocate it (this is how the test suite isolates state). |
|