ossrisk 0.1.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 +160 -0
- package/dist/action/main.d.ts +2 -0
- package/dist/action/main.d.ts.map +1 -0
- package/dist/action/main.js +67 -0
- package/dist/action/main.js.map +1 -0
- package/dist/src/checkers/activity.d.ts +3 -0
- package/dist/src/checkers/activity.d.ts.map +1 -0
- package/dist/src/checkers/activity.js +49 -0
- package/dist/src/checkers/activity.js.map +1 -0
- package/dist/src/checkers/eol.d.ts +3 -0
- package/dist/src/checkers/eol.d.ts.map +1 -0
- package/dist/src/checkers/eol.js +71 -0
- package/dist/src/checkers/eol.js.map +1 -0
- package/dist/src/checkers/osv.d.ts +3 -0
- package/dist/src/checkers/osv.d.ts.map +1 -0
- package/dist/src/checkers/osv.js +71 -0
- package/dist/src/checkers/osv.js.map +1 -0
- package/dist/src/checkers/outdated.d.ts +3 -0
- package/dist/src/checkers/outdated.d.ts.map +1 -0
- package/dist/src/checkers/outdated.js +33 -0
- package/dist/src/checkers/outdated.js.map +1 -0
- package/dist/src/cli.d.ts +3 -0
- package/dist/src/cli.d.ts.map +1 -0
- package/dist/src/cli.js +79 -0
- package/dist/src/cli.js.map +1 -0
- package/dist/src/output/markdown.d.ts +3 -0
- package/dist/src/output/markdown.d.ts.map +1 -0
- package/dist/src/output/markdown.js +47 -0
- package/dist/src/output/markdown.js.map +1 -0
- package/dist/src/output/table.d.ts +3 -0
- package/dist/src/output/table.d.ts.map +1 -0
- package/dist/src/output/table.js +77 -0
- package/dist/src/output/table.js.map +1 -0
- package/dist/src/parsers/npm.d.ts +3 -0
- package/dist/src/parsers/npm.d.ts.map +1 -0
- package/dist/src/parsers/npm.js +43 -0
- package/dist/src/parsers/npm.js.map +1 -0
- package/dist/src/parsers/python.d.ts +3 -0
- package/dist/src/parsers/python.d.ts.map +1 -0
- package/dist/src/parsers/python.js +24 -0
- package/dist/src/parsers/python.js.map +1 -0
- package/dist/src/scanner.d.ts +3 -0
- package/dist/src/scanner.d.ts.map +1 -0
- package/dist/src/scanner.js +74 -0
- package/dist/src/scanner.js.map +1 -0
- package/dist/src/types.d.ts +65 -0
- package/dist/src/types.d.ts.map +1 -0
- package/dist/src/types.js +2 -0
- package/dist/src/types.js.map +1 -0
- package/package.json +51 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 depkeep
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
# ossrisk
|
|
2
|
+
|
|
3
|
+
Scan your dependencies for long-term viability risk: **EOL versions**, **known CVEs**, and **abandonment signals**.
|
|
4
|
+
|
|
5
|
+
Supports `package.json` (npm) and `requirements.txt` (PyPI).
|
|
6
|
+
|
|
7
|
+
[](https://github.com/depkeep/ossrisk/actions/workflows/ci.yml)
|
|
8
|
+
[](https://www.npmjs.com/package/ossrisk)
|
|
9
|
+
[](LICENSE)
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## Install
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install -g ossrisk
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Or run without installing:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npx ossrisk .
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## CLI usage
|
|
28
|
+
|
|
29
|
+
```
|
|
30
|
+
ossrisk [path] [options]
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
| Option | Default | Description |
|
|
34
|
+
|---|---|---|
|
|
35
|
+
| `[path]` | `.` | Path to project directory to scan |
|
|
36
|
+
| `-f, --format <fmt>` | `table` | Output format: `table`, `json`, `markdown` |
|
|
37
|
+
| `--fail-on <level>` | `high` | Exit 1 if any dep reaches this risk level (`none`\|`low`\|`medium`\|`high`\|`critical`) |
|
|
38
|
+
| `-c, --concurrency <n>` | `8` | Concurrent API requests per batch |
|
|
39
|
+
| `--no-eol` | | Skip EOL checks |
|
|
40
|
+
| `--no-cve` | | Skip CVE checks |
|
|
41
|
+
| `--no-activity` | | Skip abandonment/staleness checks |
|
|
42
|
+
| `--no-outdated` | | Skip latest-version checks |
|
|
43
|
+
|
|
44
|
+
### Examples
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
# Scan the current directory
|
|
48
|
+
ossrisk
|
|
49
|
+
|
|
50
|
+
# Scan a specific project
|
|
51
|
+
ossrisk /path/to/project
|
|
52
|
+
|
|
53
|
+
# Output as JSON
|
|
54
|
+
ossrisk . --format json
|
|
55
|
+
|
|
56
|
+
# Fail on medium risk or above
|
|
57
|
+
ossrisk . --fail-on medium
|
|
58
|
+
|
|
59
|
+
# Skip CVE checks, output markdown
|
|
60
|
+
ossrisk . --no-cve --format markdown
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## Risk levels
|
|
66
|
+
|
|
67
|
+
| Level | Triggers |
|
|
68
|
+
|---|---|
|
|
69
|
+
| `critical` | CVE with CVSS ≥ 9.0 |
|
|
70
|
+
| `high` | CVE with CVSS 7.0–8.9, or EOL version |
|
|
71
|
+
| `medium` | CVE with CVSS 4.0–6.9, or no release in 24+ months (abandoned) |
|
|
72
|
+
| `low` | CVE with CVSS < 4.0, no release in 12–24 months (stale), or newer version available |
|
|
73
|
+
| `none` | No issues found |
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
## GitHub Actions
|
|
78
|
+
|
|
79
|
+
Add ossrisk to your CI pipeline to automatically scan dependencies on every pull request.
|
|
80
|
+
|
|
81
|
+
```yaml
|
|
82
|
+
- name: Scan dependencies
|
|
83
|
+
uses: depkeep/ossrisk@v1
|
|
84
|
+
with:
|
|
85
|
+
fail-on: high
|
|
86
|
+
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
When `github-token` is provided and the workflow runs on a pull request, ossrisk posts a markdown report as a PR comment.
|
|
90
|
+
|
|
91
|
+
### Action inputs
|
|
92
|
+
|
|
93
|
+
| Input | Default | Description |
|
|
94
|
+
|---|---|---|
|
|
95
|
+
| `path` | `.` | Path to the project directory |
|
|
96
|
+
| `fail-on` | `high` | Exit 1 if any dep reaches this level or above |
|
|
97
|
+
| `no-eol` | `false` | Skip EOL checks |
|
|
98
|
+
| `no-cve` | `false` | Skip CVE checks |
|
|
99
|
+
| `no-activity` | `false` | Skip abandonment/staleness checks |
|
|
100
|
+
| `no-outdated` | `false` | Skip latest-version checks |
|
|
101
|
+
| `github-token` | | GitHub token for posting a PR comment |
|
|
102
|
+
|
|
103
|
+
### Action outputs
|
|
104
|
+
|
|
105
|
+
| Output | Description |
|
|
106
|
+
|---|---|
|
|
107
|
+
| `risk-level` | Highest risk level found across all dependencies |
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
## Programmatic API
|
|
112
|
+
|
|
113
|
+
```ts
|
|
114
|
+
import { scan } from 'ossrisk';
|
|
115
|
+
|
|
116
|
+
const result = await scan({
|
|
117
|
+
path: '/path/to/project',
|
|
118
|
+
format: 'json',
|
|
119
|
+
failOn: 'high',
|
|
120
|
+
concurrency: 8,
|
|
121
|
+
noEol: false,
|
|
122
|
+
noCve: false,
|
|
123
|
+
noActivity: false,
|
|
124
|
+
noOutdated: false,
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
console.log(result.summary);
|
|
128
|
+
// { total: 42, critical: 0, high: 1, medium: 3, low: 5, clean: 33 }
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
---
|
|
132
|
+
|
|
133
|
+
## Data sources
|
|
134
|
+
|
|
135
|
+
- **CVEs** — [OSV.dev](https://osv.dev) batch API
|
|
136
|
+
- **EOL dates** — [endoflife.date](https://endoflife.date) API
|
|
137
|
+
- **Activity** — npm registry / PyPI JSON API
|
|
138
|
+
- **Latest versions** — npm registry / PyPI JSON API
|
|
139
|
+
|
|
140
|
+
All checks are read-only and require no API keys.
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
## Contributing
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
git clone https://github.com/depkeep/ossrisk.git
|
|
148
|
+
cd ossrisk
|
|
149
|
+
npm install
|
|
150
|
+
npm test # run tests
|
|
151
|
+
npm run dev . # run CLI from source
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
Before submitting a PR, run `npm run build` and commit the updated `dist/` so the GitHub Action stays functional.
|
|
155
|
+
|
|
156
|
+
---
|
|
157
|
+
|
|
158
|
+
## License
|
|
159
|
+
|
|
160
|
+
MIT © [DepKeep](https://depkeep.com)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../../action/main.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { appendFileSync, readFileSync } from 'fs';
|
|
2
|
+
import { resolve } from 'path';
|
|
3
|
+
import { scan } from '../src/scanner.js';
|
|
4
|
+
import { renderMarkdown } from '../src/output/markdown.js';
|
|
5
|
+
const RISK_ORDER = ['none', 'low', 'medium', 'high', 'critical'];
|
|
6
|
+
function getInput(name, fallback = '') {
|
|
7
|
+
return process.env[`INPUT_${name.toUpperCase().replace(/-/g, '_')}`] ?? fallback;
|
|
8
|
+
}
|
|
9
|
+
function setOutput(name, value) {
|
|
10
|
+
const file = process.env.GITHUB_OUTPUT;
|
|
11
|
+
if (file)
|
|
12
|
+
appendFileSync(file, `${name}=${value}\n`);
|
|
13
|
+
}
|
|
14
|
+
async function postPrComment(token, body) {
|
|
15
|
+
const { GITHUB_REPOSITORY, GITHUB_EVENT_PATH } = process.env;
|
|
16
|
+
if (!GITHUB_REPOSITORY || !GITHUB_EVENT_PATH)
|
|
17
|
+
return;
|
|
18
|
+
const event = JSON.parse(readFileSync(GITHUB_EVENT_PATH, 'utf-8'));
|
|
19
|
+
const prNumber = event.pull_request?.number;
|
|
20
|
+
if (!prNumber)
|
|
21
|
+
return;
|
|
22
|
+
const [owner, repo] = GITHUB_REPOSITORY.split('/');
|
|
23
|
+
await fetch(`https://api.github.com/repos/${owner}/${repo}/issues/${prNumber}/comments`, {
|
|
24
|
+
method: 'POST',
|
|
25
|
+
headers: {
|
|
26
|
+
Authorization: `Bearer ${token}`,
|
|
27
|
+
'Content-Type': 'application/json',
|
|
28
|
+
},
|
|
29
|
+
body: JSON.stringify({ body }),
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
async function run() {
|
|
33
|
+
const opts = {
|
|
34
|
+
path: resolve(getInput('path', '.')),
|
|
35
|
+
format: 'markdown',
|
|
36
|
+
failOn: getInput('fail-on', 'high'),
|
|
37
|
+
concurrency: 8,
|
|
38
|
+
noEol: getInput('no-eol') === 'true',
|
|
39
|
+
noCve: getInput('no-cve') === 'true',
|
|
40
|
+
noActivity: getInput('no-activity') === 'true',
|
|
41
|
+
noOutdated: getInput('no-outdated') === 'true',
|
|
42
|
+
};
|
|
43
|
+
try {
|
|
44
|
+
const result = await scan(opts);
|
|
45
|
+
const report = renderMarkdown(result);
|
|
46
|
+
console.log(report);
|
|
47
|
+
const token = getInput('github-token');
|
|
48
|
+
if (token && process.env.GITHUB_EVENT_NAME === 'pull_request') {
|
|
49
|
+
await postPrComment(token, report);
|
|
50
|
+
}
|
|
51
|
+
setOutput('risk-level', result.results[0]?.riskLevel ?? 'none');
|
|
52
|
+
const threshold = RISK_ORDER.indexOf(opts.failOn);
|
|
53
|
+
if (threshold > 0) {
|
|
54
|
+
const breached = result.results.some(r => RISK_ORDER.indexOf(r.riskLevel) >= threshold);
|
|
55
|
+
if (breached) {
|
|
56
|
+
console.error(`ossrisk: one or more dependencies are at risk level "${opts.failOn}" or above`);
|
|
57
|
+
process.exit(1);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
catch (err) {
|
|
62
|
+
console.error('ossrisk action failed:', err.message);
|
|
63
|
+
process.exit(2);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
run();
|
|
67
|
+
//# sourceMappingURL=main.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"main.js","sourceRoot":"","sources":["../../action/main.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"activity.d.ts","sourceRoot":"","sources":["../../../src/checkers/activity.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AA+B5E,wBAAsB,aAAa,CACjC,GAAG,EAAE,UAAU,GACd,OAAO,CAAC,CAAC,eAAe,GAAG,WAAW,CAAC,EAAE,CAAC,CAuB5C"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
const ABANDONED_MONTHS = 24;
|
|
2
|
+
const STALE_MONTHS = 12;
|
|
3
|
+
function monthsSince(date) {
|
|
4
|
+
return (Date.now() - date.getTime()) / (1000 * 60 * 60 * 24 * 30.44);
|
|
5
|
+
}
|
|
6
|
+
async function lastNpmRelease(name) {
|
|
7
|
+
const res = await fetch(`https://registry.npmjs.org/${encodeURIComponent(name)}`, {
|
|
8
|
+
headers: { Accept: 'application/json' },
|
|
9
|
+
});
|
|
10
|
+
if (!res.ok)
|
|
11
|
+
return null;
|
|
12
|
+
const data = await res.json();
|
|
13
|
+
const modified = data.time?.modified;
|
|
14
|
+
return modified ? new Date(modified) : null;
|
|
15
|
+
}
|
|
16
|
+
async function lastPypiRelease(name) {
|
|
17
|
+
const res = await fetch(`https://pypi.org/pypi/${encodeURIComponent(name)}/json`);
|
|
18
|
+
if (!res.ok)
|
|
19
|
+
return null;
|
|
20
|
+
const data = await res.json();
|
|
21
|
+
const files = data.releases[data.info.version];
|
|
22
|
+
if (!files?.length)
|
|
23
|
+
return null;
|
|
24
|
+
return new Date(files[0].upload_time);
|
|
25
|
+
}
|
|
26
|
+
export async function checkActivity(dep) {
|
|
27
|
+
try {
|
|
28
|
+
let last = null;
|
|
29
|
+
if (dep.ecosystem === 'npm')
|
|
30
|
+
last = await lastNpmRelease(dep.name);
|
|
31
|
+
if (dep.ecosystem === 'pypi')
|
|
32
|
+
last = await lastPypiRelease(dep.name);
|
|
33
|
+
if (!last)
|
|
34
|
+
return [];
|
|
35
|
+
const months = Math.floor(monthsSince(last));
|
|
36
|
+
const dateStr = last.toISOString().split('T')[0];
|
|
37
|
+
if (months >= ABANDONED_MONTHS) {
|
|
38
|
+
return [{ type: 'abandoned', lastReleaseDate: dateStr, monthsSince: months }];
|
|
39
|
+
}
|
|
40
|
+
if (months >= STALE_MONTHS) {
|
|
41
|
+
return [{ type: 'stale', lastReleaseDate: dateStr, monthsSince: months }];
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
// Registry unreachable — not a failure condition
|
|
46
|
+
}
|
|
47
|
+
return [];
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=activity.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"activity.js","sourceRoot":"","sources":["../../../src/checkers/activity.ts"],"names":[],"mappings":"AAEA,MAAM,gBAAgB,GAAG,EAAE,CAAC;AAC5B,MAAM,YAAY,GAAG,EAAE,CAAC;AAExB,SAAS,WAAW,CAAC,IAAU;IAC7B,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC,GAAG,CAAC,IAAI,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,KAAK,CAAC,CAAC;AACvE,CAAC;AAED,KAAK,UAAU,cAAc,CAAC,IAAY;IACxC,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,8BAA8B,kBAAkB,CAAC,IAAI,CAAC,EAAE,EAAE;QAChF,OAAO,EAAE,EAAE,MAAM,EAAE,kBAAkB,EAAE;KACxC,CAAC,CAAC;IACH,IAAI,CAAC,GAAG,CAAC,EAAE;QAAE,OAAO,IAAI,CAAC;IACzB,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAuC,CAAC;IACnE,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,EAAE,QAAQ,CAAC;IACrC,OAAO,QAAQ,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AAC9C,CAAC;AAED,KAAK,UAAU,eAAe,CAAC,IAAY;IACzC,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,yBAAyB,kBAAkB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAClF,IAAI,CAAC,GAAG,CAAC,EAAE;QAAE,OAAO,IAAI,CAAC;IACzB,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAG1B,CAAC;IACF,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC/C,IAAI,CAAC,KAAK,EAAE,MAAM;QAAE,OAAO,IAAI,CAAC;IAChC,OAAO,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC;AACxC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,GAAe;IAEf,IAAI,CAAC;QACH,IAAI,IAAI,GAAgB,IAAI,CAAC;QAE7B,IAAI,GAAG,CAAC,SAAS,KAAK,KAAK;YAAG,IAAI,GAAG,MAAM,cAAc,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACpE,IAAI,GAAG,CAAC,SAAS,KAAK,MAAM;YAAE,IAAI,GAAG,MAAM,eAAe,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAErE,IAAI,CAAC,IAAI;YAAE,OAAO,EAAE,CAAC;QAErB,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC;QAC7C,MAAM,OAAO,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QAEjD,IAAI,MAAM,IAAI,gBAAgB,EAAE,CAAC;YAC/B,OAAO,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,eAAe,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,CAAC,CAAC;QAChF,CAAC;QACD,IAAI,MAAM,IAAI,YAAY,EAAE,CAAC;YAC3B,OAAO,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,eAAe,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,CAAC,CAAC;QAC5E,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,iDAAiD;IACnD,CAAC;IAED,OAAO,EAAE,CAAC;AACZ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"eol.d.ts","sourceRoot":"","sources":["../../../src/checkers/eol.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAgDzD,wBAAsB,QAAQ,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC,CA2BpE"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
// Maps package names → endoflife.date product slugs.
|
|
2
|
+
// Only packages/runtimes that have formal EOL policies are included.
|
|
3
|
+
const EOL_MAP = {
|
|
4
|
+
// Runtimes
|
|
5
|
+
'node': 'nodejs',
|
|
6
|
+
'nodejs': 'nodejs',
|
|
7
|
+
'python': 'python',
|
|
8
|
+
'ruby': 'ruby',
|
|
9
|
+
'php': 'php',
|
|
10
|
+
'golang': 'go',
|
|
11
|
+
// Frameworks
|
|
12
|
+
'django': 'django',
|
|
13
|
+
'rails': 'rails',
|
|
14
|
+
'laravel': 'laravel',
|
|
15
|
+
'symfony': 'symfony',
|
|
16
|
+
'spring-boot': 'spring-boot',
|
|
17
|
+
'angular': 'angular',
|
|
18
|
+
'@angular/core': 'angular',
|
|
19
|
+
'bootstrap': 'bootstrap',
|
|
20
|
+
// Databases (client package name → server product)
|
|
21
|
+
'pg': 'postgresql',
|
|
22
|
+
'mysql': 'mysql',
|
|
23
|
+
'mysql2': 'mysql',
|
|
24
|
+
'mongodb': 'mongodb',
|
|
25
|
+
// Others
|
|
26
|
+
'wordpress': 'wordpress',
|
|
27
|
+
'drupal': 'drupal',
|
|
28
|
+
'magento': 'magento-2',
|
|
29
|
+
'nextjs': 'nextjs',
|
|
30
|
+
'next': 'nextjs',
|
|
31
|
+
'nuxt': 'nuxtjs',
|
|
32
|
+
};
|
|
33
|
+
function candidateCycles(version) {
|
|
34
|
+
const parts = version.split('.').filter(p => /^\d+$/.test(p));
|
|
35
|
+
const cycles = [];
|
|
36
|
+
if (parts.length >= 2)
|
|
37
|
+
cycles.push(`${parts[0]}.${parts[1]}`);
|
|
38
|
+
if (parts.length >= 1)
|
|
39
|
+
cycles.push(parts[0]);
|
|
40
|
+
return cycles;
|
|
41
|
+
}
|
|
42
|
+
export async function checkEol(dep) {
|
|
43
|
+
const product = EOL_MAP[dep.name];
|
|
44
|
+
if (!product)
|
|
45
|
+
return [];
|
|
46
|
+
try {
|
|
47
|
+
const res = await fetch(`https://endoflife.date/api/${product}.json`);
|
|
48
|
+
if (!res.ok)
|
|
49
|
+
return [];
|
|
50
|
+
const cycles = await res.json();
|
|
51
|
+
const candidates = candidateCycles(dep.version);
|
|
52
|
+
for (const candidate of candidates) {
|
|
53
|
+
const cycle = cycles.find(c => c.cycle === candidate);
|
|
54
|
+
if (!cycle)
|
|
55
|
+
continue;
|
|
56
|
+
const { eol } = cycle;
|
|
57
|
+
if (eol === false)
|
|
58
|
+
return []; // still supported
|
|
59
|
+
if (eol === true)
|
|
60
|
+
return [{ type: 'eol', cycle: candidate, eolDate: 'unknown' }];
|
|
61
|
+
if (new Date(eol) <= new Date()) {
|
|
62
|
+
return [{ type: 'eol', cycle: candidate, eolDate: eol }];
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
// Silently skip — endoflife.date may not have data for every product
|
|
68
|
+
}
|
|
69
|
+
return [];
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=eol.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"eol.js","sourceRoot":"","sources":["../../../src/checkers/eol.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"osv.d.ts","sourceRoot":"","sources":["../../../src/checkers/osv.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAa,MAAM,aAAa,CAAC;AA0CpE,wBAAsB,cAAc,CAClC,IAAI,EAAE,UAAU,EAAE,GACjB,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC,CAqCnC"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
const OSV_BATCH_API = 'https://api.osv.dev/v1/querybatch';
|
|
2
|
+
const BATCH_SIZE = 100;
|
|
3
|
+
const ECOSYSTEM_MAP = {
|
|
4
|
+
npm: 'npm',
|
|
5
|
+
pypi: 'PyPI',
|
|
6
|
+
maven: 'Maven',
|
|
7
|
+
cargo: 'crates.io',
|
|
8
|
+
go: 'Go',
|
|
9
|
+
};
|
|
10
|
+
function cvssToLevel(score) {
|
|
11
|
+
const n = parseFloat(score);
|
|
12
|
+
if (n >= 9.0)
|
|
13
|
+
return 'critical';
|
|
14
|
+
if (n >= 7.0)
|
|
15
|
+
return 'high';
|
|
16
|
+
if (n >= 4.0)
|
|
17
|
+
return 'medium';
|
|
18
|
+
return 'low';
|
|
19
|
+
}
|
|
20
|
+
function vulnSeverity(v) {
|
|
21
|
+
for (const s of v.severity ?? []) {
|
|
22
|
+
if (s.type === 'CVSS_V3' || s.type === 'CVSS_V2')
|
|
23
|
+
return cvssToLevel(s.score);
|
|
24
|
+
}
|
|
25
|
+
const ds = v.database_specific?.severity?.toUpperCase();
|
|
26
|
+
if (ds === 'CRITICAL')
|
|
27
|
+
return 'critical';
|
|
28
|
+
if (ds === 'HIGH')
|
|
29
|
+
return 'high';
|
|
30
|
+
if (ds === 'MODERATE' || ds === 'MEDIUM')
|
|
31
|
+
return 'medium';
|
|
32
|
+
if (ds === 'LOW')
|
|
33
|
+
return 'low';
|
|
34
|
+
return 'medium';
|
|
35
|
+
}
|
|
36
|
+
export async function checkCvesBatch(deps) {
|
|
37
|
+
const results = new Map();
|
|
38
|
+
for (let i = 0; i < deps.length; i += BATCH_SIZE) {
|
|
39
|
+
const batch = deps.slice(i, i + BATCH_SIZE);
|
|
40
|
+
try {
|
|
41
|
+
const res = await fetch(OSV_BATCH_API, {
|
|
42
|
+
method: 'POST',
|
|
43
|
+
headers: { 'Content-Type': 'application/json' },
|
|
44
|
+
body: JSON.stringify({
|
|
45
|
+
queries: batch.map(d => ({
|
|
46
|
+
version: d.version,
|
|
47
|
+
package: { name: d.name, ecosystem: ECOSYSTEM_MAP[d.ecosystem] ?? d.ecosystem },
|
|
48
|
+
})),
|
|
49
|
+
}),
|
|
50
|
+
});
|
|
51
|
+
if (!res.ok)
|
|
52
|
+
continue;
|
|
53
|
+
const data = await res.json();
|
|
54
|
+
for (let j = 0; j < batch.length; j++) {
|
|
55
|
+
const dep = batch[j];
|
|
56
|
+
const vulns = data.results[j]?.vulns ?? [];
|
|
57
|
+
results.set(`${dep.name}@${dep.version}`, vulns.map(v => ({
|
|
58
|
+
type: 'cve',
|
|
59
|
+
id: v.id,
|
|
60
|
+
severity: vulnSeverity(v),
|
|
61
|
+
summary: v.summary ?? 'No description available',
|
|
62
|
+
})));
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
// Network errors: skip batch, leave entries absent (treated as no CVEs)
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return results;
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=osv.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"osv.js","sourceRoot":"","sources":["../../../src/checkers/osv.ts"],"names":[],"mappings":"AAEA,MAAM,aAAa,GAAG,mCAAmC,CAAC;AAC1D,MAAM,UAAU,GAAG,GAAG,CAAC;AAEvB,MAAM,aAAa,GAA2B;IAC5C,GAAG,EAAI,KAAK;IACZ,IAAI,EAAG,MAAM;IACb,KAAK,EAAE,OAAO;IACd,KAAK,EAAE,WAAW;IAClB,EAAE,EAAK,IAAI;CACZ,CAAC;AAWF,SAAS,WAAW,CAAC,KAAa;IAChC,MAAM,CAAC,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;IAC5B,IAAI,CAAC,IAAI,GAAG;QAAE,OAAO,UAAU,CAAC;IAChC,IAAI,CAAC,IAAI,GAAG;QAAE,OAAO,MAAM,CAAC;IAC5B,IAAI,CAAC,IAAI,GAAG;QAAE,OAAO,QAAQ,CAAC;IAC9B,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,YAAY,CAAC,CAAU;IAC9B,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,QAAQ,IAAI,EAAE,EAAE,CAAC;QACjC,IAAI,CAAC,CAAC,IAAI,KAAK,SAAS,IAAI,CAAC,CAAC,IAAI,KAAK,SAAS;YAAE,OAAO,WAAW,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;IAChF,CAAC;IACD,MAAM,EAAE,GAAG,CAAC,CAAC,iBAAiB,EAAE,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxD,IAAI,EAAE,KAAK,UAAU;QAAE,OAAO,UAAU,CAAC;IACzC,IAAI,EAAE,KAAK,MAAM;QAAM,OAAO,MAAM,CAAC;IACrC,IAAI,EAAE,KAAK,UAAU,IAAI,EAAE,KAAK,QAAQ;QAAE,OAAO,QAAQ,CAAC;IAC1D,IAAI,EAAE,KAAK,KAAK;QAAO,OAAO,KAAK,CAAC;IACpC,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,IAAkB;IAElB,MAAM,OAAO,GAAG,IAAI,GAAG,EAAuB,CAAC;IAE/C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,IAAI,UAAU,EAAE,CAAC;QACjD,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,UAAU,CAAC,CAAC;QAC5C,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,aAAa,EAAE;gBACrC,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;gBAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;oBACnB,OAAO,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;wBACvB,OAAO,EAAE,CAAC,CAAC,OAAO;wBAClB,OAAO,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,SAAS,EAAE,aAAa,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE;qBAChF,CAAC,CAAC;iBACJ,CAAC;aACH,CAAC,CAAC;YAEH,IAAI,CAAC,GAAG,CAAC,EAAE;gBAAE,SAAS;YAEtB,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAsB,CAAC;YAElD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;gBACtC,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;gBACrB,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,KAAK,IAAI,EAAE,CAAC;gBAC3C,OAAO,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,IAAI,IAAI,GAAG,CAAC,OAAO,EAAE,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;oBACxD,IAAI,EAAE,KAAc;oBACpB,EAAE,EAAE,CAAC,CAAC,EAAE;oBACR,QAAQ,EAAE,YAAY,CAAC,CAAC,CAAC;oBACzB,OAAO,EAAE,CAAC,CAAC,OAAO,IAAI,0BAA0B;iBACjD,CAAC,CAAC,CAAC,CAAC;YACP,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,wEAAwE;QAC1E,CAAC;IACH,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"outdated.d.ts","sourceRoot":"","sources":["../../../src/checkers/outdated.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAmB9D,wBAAsB,aAAa,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC,CAkB9E"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
async function latestNpmVersion(name) {
|
|
2
|
+
const res = await fetch(`https://registry.npmjs.org/${encodeURIComponent(name)}/latest`, { headers: { Accept: 'application/json' } });
|
|
3
|
+
if (!res.ok)
|
|
4
|
+
return null;
|
|
5
|
+
const data = await res.json();
|
|
6
|
+
return data.version ?? null;
|
|
7
|
+
}
|
|
8
|
+
async function latestPypiVersion(name) {
|
|
9
|
+
const res = await fetch(`https://pypi.org/pypi/${encodeURIComponent(name)}/json`);
|
|
10
|
+
if (!res.ok)
|
|
11
|
+
return null;
|
|
12
|
+
const data = await res.json();
|
|
13
|
+
return data.info?.version ?? null;
|
|
14
|
+
}
|
|
15
|
+
export async function checkOutdated(dep) {
|
|
16
|
+
try {
|
|
17
|
+
let latest = null;
|
|
18
|
+
if (dep.ecosystem === 'npm') {
|
|
19
|
+
latest = await latestNpmVersion(dep.name);
|
|
20
|
+
}
|
|
21
|
+
else if (dep.ecosystem === 'pypi') {
|
|
22
|
+
latest = await latestPypiVersion(dep.name);
|
|
23
|
+
}
|
|
24
|
+
if (!latest || latest === dep.version)
|
|
25
|
+
return [];
|
|
26
|
+
return [{ type: 'outdated', latestVersion: latest }];
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
// Registry unreachable — not a failure condition
|
|
30
|
+
}
|
|
31
|
+
return [];
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=outdated.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"outdated.js","sourceRoot":"","sources":["../../../src/checkers/outdated.ts"],"names":[],"mappings":"AAEA,KAAK,UAAU,gBAAgB,CAAC,IAAY;IAC1C,MAAM,GAAG,GAAG,MAAM,KAAK,CACrB,8BAA8B,kBAAkB,CAAC,IAAI,CAAC,SAAS,EAC/D,EAAE,OAAO,EAAE,EAAE,MAAM,EAAE,kBAAkB,EAAE,EAAE,CAC5C,CAAC;IACF,IAAI,CAAC,GAAG,CAAC,EAAE;QAAE,OAAO,IAAI,CAAC;IACzB,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAA0B,CAAC;IACtD,OAAO,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC;AAC9B,CAAC;AAED,KAAK,UAAU,iBAAiB,CAAC,IAAY;IAC3C,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,yBAAyB,kBAAkB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAClF,IAAI,CAAC,GAAG,CAAC,EAAE;QAAE,OAAO,IAAI,CAAC;IACzB,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAqC,CAAC;IACjE,OAAO,IAAI,CAAC,IAAI,EAAE,OAAO,IAAI,IAAI,CAAC;AACpC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,GAAe;IACjD,IAAI,CAAC;QACH,IAAI,MAAM,GAAkB,IAAI,CAAC;QAEjC,IAAI,GAAG,CAAC,SAAS,KAAK,KAAK,EAAE,CAAC;YAC5B,MAAM,GAAG,MAAM,gBAAgB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAC5C,CAAC;aAAM,IAAI,GAAG,CAAC,SAAS,KAAK,MAAM,EAAE,CAAC;YACpC,MAAM,GAAG,MAAM,iBAAiB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAC7C,CAAC;QAED,IAAI,CAAC,MAAM,IAAI,MAAM,KAAK,GAAG,CAAC,OAAO;YAAE,OAAO,EAAE,CAAC;QAEjD,OAAO,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,EAAE,CAAC,CAAC;IACvD,CAAC;IAAC,MAAM,CAAC;QACP,iDAAiD;IACnD,CAAC;IAED,OAAO,EAAE,CAAC;AACZ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../../src/cli.ts"],"names":[],"mappings":""}
|
package/dist/src/cli.js
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { readFileSync } from 'fs';
|
|
3
|
+
import { fileURLToPath } from 'url';
|
|
4
|
+
import { dirname, join, resolve } from 'path';
|
|
5
|
+
import { Command } from 'commander';
|
|
6
|
+
import { scan } from './scanner.js';
|
|
7
|
+
import { renderTable } from './output/table.js';
|
|
8
|
+
import { renderMarkdown } from './output/markdown.js';
|
|
9
|
+
function readVersion() {
|
|
10
|
+
const dir = dirname(fileURLToPath(import.meta.url));
|
|
11
|
+
// '../package.json' works when running via `tsx src/cli.ts` (dev)
|
|
12
|
+
// '../../package.json' works from the compiled `dist/src/cli.js`
|
|
13
|
+
for (const rel of ['../package.json', '../../package.json']) {
|
|
14
|
+
try {
|
|
15
|
+
const p = JSON.parse(readFileSync(join(dir, rel), 'utf-8'));
|
|
16
|
+
if (p.name === 'ossrisk' && p.version)
|
|
17
|
+
return p.version;
|
|
18
|
+
}
|
|
19
|
+
catch { /* skip */ }
|
|
20
|
+
}
|
|
21
|
+
return '0.0.0';
|
|
22
|
+
}
|
|
23
|
+
const RISK_ORDER = ['none', 'low', 'medium', 'high', 'critical'];
|
|
24
|
+
const program = new Command();
|
|
25
|
+
program
|
|
26
|
+
.name('ossrisk')
|
|
27
|
+
.description('Scan dependencies for long-term viability risk:\n' +
|
|
28
|
+
'EOL versions, known CVEs, and abandonment signals.\n\n' +
|
|
29
|
+
'Supports: package.json (npm), requirements.txt (PyPI)')
|
|
30
|
+
.version(readVersion());
|
|
31
|
+
program
|
|
32
|
+
.argument('[path]', 'Path to project directory to scan', '.')
|
|
33
|
+
.option('-f, --format <fmt>', 'Output format: table | json | markdown', 'table')
|
|
34
|
+
.option('--fail-on <level>', 'Exit 1 if any dep reaches this level or above (none|low|medium|high|critical)', 'high')
|
|
35
|
+
.option('-c, --concurrency <n>', 'Concurrent API requests per batch', '8')
|
|
36
|
+
.option('--no-eol', 'Skip EOL checks')
|
|
37
|
+
.option('--no-cve', 'Skip CVE checks')
|
|
38
|
+
.option('--no-activity', 'Skip abandonment/staleness checks')
|
|
39
|
+
.option('--no-outdated', 'Skip latest-version checks')
|
|
40
|
+
.action(async (pathArg, options) => {
|
|
41
|
+
const opts = {
|
|
42
|
+
path: resolve(pathArg),
|
|
43
|
+
format: options.format,
|
|
44
|
+
failOn: options.failOn,
|
|
45
|
+
concurrency: parseInt(options.concurrency, 10) || 8,
|
|
46
|
+
noEol: !options.eol,
|
|
47
|
+
noCve: !options.cve,
|
|
48
|
+
noActivity: !options.activity,
|
|
49
|
+
noOutdated: !options.outdated,
|
|
50
|
+
};
|
|
51
|
+
try {
|
|
52
|
+
if (opts.format === 'table') {
|
|
53
|
+
process.stdout.write('\r Scanning…');
|
|
54
|
+
}
|
|
55
|
+
const result = await scan(opts);
|
|
56
|
+
if (opts.format === 'json') {
|
|
57
|
+
console.log(JSON.stringify(result, null, 2));
|
|
58
|
+
}
|
|
59
|
+
else if (opts.format === 'markdown') {
|
|
60
|
+
console.log(renderMarkdown(result));
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
process.stdout.write('\r' + ' '.repeat(20) + '\r');
|
|
64
|
+
console.log(renderTable(result));
|
|
65
|
+
}
|
|
66
|
+
if (opts.failOn !== 'none') {
|
|
67
|
+
const threshold = RISK_ORDER.indexOf(opts.failOn);
|
|
68
|
+
const breached = result.results.some(r => RISK_ORDER.indexOf(r.riskLevel) >= threshold);
|
|
69
|
+
if (breached)
|
|
70
|
+
process.exit(1);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
catch (err) {
|
|
74
|
+
console.error(`\n error: ${err.message}`);
|
|
75
|
+
process.exit(2);
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
program.parse();
|
|
79
|
+
//# sourceMappingURL=cli.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../../src/cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"markdown.d.ts","sourceRoot":"","sources":["../../../src/output/markdown.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAa,UAAU,EAAE,MAAM,aAAa,CAAC;AAUzD,wBAAgB,cAAc,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CA6CzD"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
const EMOJI = {
|
|
2
|
+
critical: '🔴',
|
|
3
|
+
high: '🟠',
|
|
4
|
+
medium: '🟡',
|
|
5
|
+
low: '🔵',
|
|
6
|
+
none: '🟢',
|
|
7
|
+
};
|
|
8
|
+
export function renderMarkdown(result) {
|
|
9
|
+
const { summary } = result;
|
|
10
|
+
const lines = [];
|
|
11
|
+
lines.push('## ossrisk — Dependency Health Report');
|
|
12
|
+
lines.push('');
|
|
13
|
+
lines.push(`Scanned \`${result.manifest}\` · ${result.scannedAt}`);
|
|
14
|
+
lines.push('');
|
|
15
|
+
lines.push(`**${summary.total} dependencies** — ` +
|
|
16
|
+
`${EMOJI.critical} ${summary.critical} critical · ` +
|
|
17
|
+
`${EMOJI.high} ${summary.high} high · ` +
|
|
18
|
+
`${EMOJI.medium} ${summary.medium} medium · ` +
|
|
19
|
+
`${EMOJI.low} ${summary.low} low · ` +
|
|
20
|
+
`${EMOJI.none} ${summary.clean} clean`);
|
|
21
|
+
lines.push('');
|
|
22
|
+
const risky = result.results.filter(r => r.riskLevel !== 'none');
|
|
23
|
+
if (risky.length === 0) {
|
|
24
|
+
lines.push('✅ All dependencies are healthy.');
|
|
25
|
+
return lines.join('\n');
|
|
26
|
+
}
|
|
27
|
+
lines.push('| Package | Version | Risk | Details |');
|
|
28
|
+
lines.push('|---------|---------|------|---------|');
|
|
29
|
+
for (const dep of risky) {
|
|
30
|
+
const details = dep.signals.map(s => {
|
|
31
|
+
if (s.type === 'cve') {
|
|
32
|
+
return `[${s.id}](https://osv.dev/vulnerability/${s.id}) — ${s.summary}`;
|
|
33
|
+
}
|
|
34
|
+
if (s.type === 'eol')
|
|
35
|
+
return `EOL since ${s.eolDate} (cycle ${s.cycle})`;
|
|
36
|
+
if (s.type === 'abandoned')
|
|
37
|
+
return `No release in ${s.monthsSince} months (last: ${s.lastReleaseDate})`;
|
|
38
|
+
if (s.type === 'stale')
|
|
39
|
+
return `Last release ${s.monthsSince} months ago (${s.lastReleaseDate})`;
|
|
40
|
+
if (s.type === 'outdated')
|
|
41
|
+
return `Newer version available: ${s.latestVersion}`;
|
|
42
|
+
}).join('<br>');
|
|
43
|
+
lines.push(`| \`${dep.name}\` | \`${dep.version}\` | ${EMOJI[dep.riskLevel]} ${dep.riskLevel} | ${details} |`);
|
|
44
|
+
}
|
|
45
|
+
return lines.join('\n');
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=markdown.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"markdown.js","sourceRoot":"","sources":["../../../src/output/markdown.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"table.d.ts","sourceRoot":"","sources":["../../../src/output/table.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAa,UAAU,EAAE,MAAM,aAAa,CAAC;AAqCzD,wBAAgB,WAAW,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CAmDtD"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
const C = {
|
|
2
|
+
reset: '\x1b[0m',
|
|
3
|
+
bold: '\x1b[1m',
|
|
4
|
+
dim: '\x1b[2m',
|
|
5
|
+
red: '\x1b[31m',
|
|
6
|
+
yellow: '\x1b[33m',
|
|
7
|
+
blue: '\x1b[34m',
|
|
8
|
+
cyan: '\x1b[36m',
|
|
9
|
+
green: '\x1b[32m',
|
|
10
|
+
};
|
|
11
|
+
const LEVEL_COLOR = {
|
|
12
|
+
critical: C.red,
|
|
13
|
+
high: C.yellow,
|
|
14
|
+
medium: C.blue,
|
|
15
|
+
low: C.cyan,
|
|
16
|
+
none: C.green,
|
|
17
|
+
};
|
|
18
|
+
const LEVEL_ICON = {
|
|
19
|
+
critical: '✖',
|
|
20
|
+
high: '▲',
|
|
21
|
+
medium: '●',
|
|
22
|
+
low: '◆',
|
|
23
|
+
none: '✔',
|
|
24
|
+
};
|
|
25
|
+
function col(text, level) {
|
|
26
|
+
return `${LEVEL_COLOR[level]}${text}${C.reset}`;
|
|
27
|
+
}
|
|
28
|
+
function pad(s, n) {
|
|
29
|
+
return s.length >= n ? s.slice(0, n - 1) + '…' : s.padEnd(n);
|
|
30
|
+
}
|
|
31
|
+
export function renderTable(result) {
|
|
32
|
+
const lines = [];
|
|
33
|
+
lines.push('');
|
|
34
|
+
lines.push(`${C.bold}ossrisk${C.reset} ${C.dim}${result.manifest}${C.reset}`);
|
|
35
|
+
lines.push(`${C.dim}${result.scannedAt}${C.reset}`);
|
|
36
|
+
lines.push('');
|
|
37
|
+
const nameW = Math.min(42, Math.max(20, ...result.results.map(r => r.name.length + 2)));
|
|
38
|
+
lines.push(` ${C.bold}${'Package'.padEnd(nameW)}${'Version'.padEnd(14)}${'Risk'.padEnd(11)}Details${C.reset}`);
|
|
39
|
+
lines.push(' ' + '─'.repeat(84));
|
|
40
|
+
for (const dep of result.results) {
|
|
41
|
+
const details = dep.signals.map(s => {
|
|
42
|
+
if (s.type === 'cve')
|
|
43
|
+
return `${s.id} (${s.severity})`;
|
|
44
|
+
if (s.type === 'eol')
|
|
45
|
+
return `EOL ${s.eolDate}`;
|
|
46
|
+
if (s.type === 'abandoned')
|
|
47
|
+
return `no release in ${s.monthsSince}mo`;
|
|
48
|
+
if (s.type === 'stale')
|
|
49
|
+
return `last release ${s.monthsSince}mo ago`;
|
|
50
|
+
if (s.type === 'outdated')
|
|
51
|
+
return `latest ${s.latestVersion}`;
|
|
52
|
+
}).join(' ');
|
|
53
|
+
const isClean = dep.riskLevel === 'none';
|
|
54
|
+
const icon = LEVEL_ICON[dep.riskLevel];
|
|
55
|
+
const name = pad(dep.name, nameW - 2);
|
|
56
|
+
lines.push(isClean
|
|
57
|
+
? ` ${C.dim}${icon} ${name} ${dep.version.padEnd(12)} ${'—'.padEnd(9)} —${C.reset}`
|
|
58
|
+
: ` ${col(`${icon} ${name}`, dep.riskLevel)} ` +
|
|
59
|
+
`${dep.version.padEnd(12)} ` +
|
|
60
|
+
`${col(dep.riskLevel.padEnd(9), dep.riskLevel)} ` +
|
|
61
|
+
`${C.dim}${details}${C.reset}`);
|
|
62
|
+
}
|
|
63
|
+
const s = result.summary;
|
|
64
|
+
const parts = [
|
|
65
|
+
`${C.bold}${s.total}${C.reset} deps`,
|
|
66
|
+
s.critical ? col(`${s.critical} critical`, 'critical') : '',
|
|
67
|
+
s.high ? col(`${s.high} high`, 'high') : '',
|
|
68
|
+
s.medium ? col(`${s.medium} medium`, 'medium') : '',
|
|
69
|
+
s.low ? col(`${s.low} low`, 'low') : '',
|
|
70
|
+
col(`${s.clean} clean`, 'none'),
|
|
71
|
+
].filter(Boolean);
|
|
72
|
+
lines.push('');
|
|
73
|
+
lines.push(` ${parts.join(' · ')}`);
|
|
74
|
+
lines.push('');
|
|
75
|
+
return lines.join('\n');
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=table.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"table.js","sourceRoot":"","sources":["../../../src/output/table.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"npm.d.ts","sourceRoot":"","sources":["../../../src/parsers/npm.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AA+C9C,wBAAsB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CAEjE"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { readFile } from 'fs/promises';
|
|
2
|
+
import { join } from 'path';
|
|
3
|
+
function cleanVersion(raw) {
|
|
4
|
+
// Strip range operators (^, ~, >=, etc.) and take the first concrete version
|
|
5
|
+
return raw
|
|
6
|
+
.replace(/^[^0-9]*/, '')
|
|
7
|
+
.split(/\s+/)[0]
|
|
8
|
+
.split('||')[0]
|
|
9
|
+
.trim();
|
|
10
|
+
}
|
|
11
|
+
async function fromLockfile(dir) {
|
|
12
|
+
try {
|
|
13
|
+
const content = await readFile(join(dir, 'package-lock.json'), 'utf-8');
|
|
14
|
+
const lock = JSON.parse(content);
|
|
15
|
+
if (!lock.packages)
|
|
16
|
+
return null;
|
|
17
|
+
return Object.entries(lock.packages)
|
|
18
|
+
.filter(([name, pkg]) => name !== '' && !pkg.dev && pkg.version)
|
|
19
|
+
.map(([name, pkg]) => ({
|
|
20
|
+
name: name.replace(/^node_modules\//, ''),
|
|
21
|
+
version: pkg.version,
|
|
22
|
+
ecosystem: 'npm',
|
|
23
|
+
}));
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
async function fromPackageJson(dir) {
|
|
30
|
+
const content = await readFile(join(dir, 'package.json'), 'utf-8');
|
|
31
|
+
const pkg = JSON.parse(content);
|
|
32
|
+
return Object.entries(pkg.dependencies ?? {})
|
|
33
|
+
.map(([name, version]) => ({
|
|
34
|
+
name,
|
|
35
|
+
version: cleanVersion(version),
|
|
36
|
+
ecosystem: 'npm',
|
|
37
|
+
}))
|
|
38
|
+
.filter(d => d.version && !d.version.includes('github') && !d.version.startsWith('file:'));
|
|
39
|
+
}
|
|
40
|
+
export async function parseNpm(dir) {
|
|
41
|
+
return (await fromLockfile(dir)) ?? (await fromPackageJson(dir));
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=npm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"npm.js","sourceRoot":"","sources":["../../../src/parsers/npm.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvC,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAG5B,SAAS,YAAY,CAAC,GAAW;IAC/B,6EAA6E;IAC7E,OAAO,GAAG;SACP,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC;SACvB,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;SACf,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;SACd,IAAI,EAAE,CAAC;AACZ,CAAC;AAED,KAAK,UAAU,YAAY,CAAC,GAAW;IACrC,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,GAAG,EAAE,mBAAmB,CAAC,EAAE,OAAO,CAAC,CAAC;QACxE,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAE9B,CAAC;QAEF,IAAI,CAAC,IAAI,CAAC,QAAQ;YAAE,OAAO,IAAI,CAAC;QAEhC,OAAO,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC;aACjC,MAAM,CAAC,CAAC,CAAC,IAAI,EAAE,GAAG,CAAC,EAAE,EAAE,CAAC,IAAI,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC;aAC/D,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC;YACrB,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,iBAAiB,EAAE,EAAE,CAAC;YACzC,OAAO,EAAE,GAAG,CAAC,OAAO;YACpB,SAAS,EAAE,KAAc;SAC1B,CAAC,CAAC,CAAC;IACR,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,KAAK,UAAU,eAAe,CAAC,GAAW;IACxC,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,GAAG,EAAE,cAAc,CAAC,EAAE,OAAO,CAAC,CAAC;IACnE,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAE7B,CAAC;IAEF,OAAO,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,EAAE,CAAC;SAC1C,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE,EAAE,CAAC,CAAC;QACzB,IAAI;QACJ,OAAO,EAAE,YAAY,CAAC,OAAO,CAAC;QAC9B,SAAS,EAAE,KAAc;KAC1B,CAAC,CAAC;SACF,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC;AAC/F,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,GAAW;IACxC,OAAO,CAAC,MAAM,YAAY,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,MAAM,eAAe,CAAC,GAAG,CAAC,CAAC,CAAC;AACnE,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"python.d.ts","sourceRoot":"","sources":["../../../src/parsers/python.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAO9C,wBAAsB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CAmBpE"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { readFile } from 'fs/promises';
|
|
2
|
+
import { join } from 'path';
|
|
3
|
+
function cleanVersion(spec) {
|
|
4
|
+
const match = spec.match(/[=~><!]+\s*([0-9][0-9a-zA-Z._-]*)/);
|
|
5
|
+
return match ? match[1] : spec.trim();
|
|
6
|
+
}
|
|
7
|
+
export async function parsePython(dir) {
|
|
8
|
+
const content = await readFile(join(dir, 'requirements.txt'), 'utf-8');
|
|
9
|
+
const deps = [];
|
|
10
|
+
for (const raw of content.split('\n')) {
|
|
11
|
+
const line = raw.split('#')[0].trim();
|
|
12
|
+
if (!line || line.startsWith('-'))
|
|
13
|
+
continue;
|
|
14
|
+
// e.g. "Django==4.2.0", "requests>=2.28.0", "flask~=2.3"
|
|
15
|
+
const match = line.match(/^([a-zA-Z0-9_.-]+)\s*([=~><!][=~>!]?\s*[0-9][0-9a-zA-Z._-]*)?/);
|
|
16
|
+
if (!match)
|
|
17
|
+
continue;
|
|
18
|
+
const name = match[1].toLowerCase().replace(/_/g, '-');
|
|
19
|
+
const version = match[2] ? cleanVersion(match[2]) : '0.0.0';
|
|
20
|
+
deps.push({ name, version, ecosystem: 'pypi' });
|
|
21
|
+
}
|
|
22
|
+
return deps;
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=python.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"python.js","sourceRoot":"","sources":["../../../src/parsers/python.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvC,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAG5B,SAAS,YAAY,CAAC,IAAY;IAChC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,mCAAmC,CAAC,CAAC;IAC9D,OAAO,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;AACxC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,GAAW;IAC3C,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,GAAG,EAAE,kBAAkB,CAAC,EAAE,OAAO,CAAC,CAAC;IACvE,MAAM,IAAI,GAAiB,EAAE,CAAC;IAE9B,KAAK,MAAM,GAAG,IAAI,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QACtC,MAAM,IAAI,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QACtC,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;YAAE,SAAS;QAE5C,yDAAyD;QACzD,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,+DAA+D,CAAC,CAAC;QAC1F,IAAI,CAAC,KAAK;YAAE,SAAS;QAErB,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;QACvD,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;QAE5D,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC,CAAC;IAClD,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scanner.d.ts","sourceRoot":"","sources":["../../src/scanner.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAMV,WAAW,EACX,UAAU,EACX,MAAM,YAAY,CAAC;AAyCpB,wBAAsB,IAAI,CAAC,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC,CA+CjE"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { existsSync } from 'fs';
|
|
2
|
+
import { join } from 'path';
|
|
3
|
+
import { checkCvesBatch } from './checkers/osv.js';
|
|
4
|
+
import { checkActivity } from './checkers/activity.js';
|
|
5
|
+
import { checkEol } from './checkers/eol.js';
|
|
6
|
+
import { checkOutdated } from './checkers/outdated.js';
|
|
7
|
+
import { parseNpm } from './parsers/npm.js';
|
|
8
|
+
import { parsePython } from './parsers/python.js';
|
|
9
|
+
const RISK_ORDER = ['none', 'low', 'medium', 'high', 'critical'];
|
|
10
|
+
function signalRisk(s) {
|
|
11
|
+
switch (s.type) {
|
|
12
|
+
case 'cve': return s.severity;
|
|
13
|
+
case 'eol': return 'high';
|
|
14
|
+
case 'abandoned': return 'medium';
|
|
15
|
+
case 'stale': return 'low';
|
|
16
|
+
case 'outdated': return 'low';
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
function maxRisk(signals) {
|
|
20
|
+
return signals.reduce((max, s) => {
|
|
21
|
+
const level = signalRisk(s);
|
|
22
|
+
return RISK_ORDER.indexOf(level) > RISK_ORDER.indexOf(max) ? level : max;
|
|
23
|
+
}, 'none');
|
|
24
|
+
}
|
|
25
|
+
async function detectAndParse(dir) {
|
|
26
|
+
if (existsSync(join(dir, 'package.json'))) {
|
|
27
|
+
const deps = await parseNpm(dir);
|
|
28
|
+
return { deps, manifest: join(dir, 'package.json') };
|
|
29
|
+
}
|
|
30
|
+
if (existsSync(join(dir, 'requirements.txt'))) {
|
|
31
|
+
const deps = await parsePython(dir);
|
|
32
|
+
return { deps, manifest: join(dir, 'requirements.txt') };
|
|
33
|
+
}
|
|
34
|
+
throw new Error('No supported manifest found. Supported: package.json, requirements.txt');
|
|
35
|
+
}
|
|
36
|
+
export async function scan(opts) {
|
|
37
|
+
const { deps, manifest } = await detectAndParse(opts.path);
|
|
38
|
+
// CVEs: one batched API call for all deps
|
|
39
|
+
const cveMap = opts.noCve
|
|
40
|
+
? new Map()
|
|
41
|
+
: await checkCvesBatch(deps);
|
|
42
|
+
// EOL + activity: per-dep, run concurrently in controlled batches
|
|
43
|
+
const results = [];
|
|
44
|
+
for (let i = 0; i < deps.length; i += opts.concurrency) {
|
|
45
|
+
const batch = deps.slice(i, i + opts.concurrency);
|
|
46
|
+
const batchResults = await Promise.all(batch.map(async (dep) => {
|
|
47
|
+
const signals = [
|
|
48
|
+
...(cveMap.get(`${dep.name}@${dep.version}`) ?? []),
|
|
49
|
+
...(!opts.noEol ? await checkEol(dep) : []),
|
|
50
|
+
...(!opts.noActivity ? await checkActivity(dep) : []),
|
|
51
|
+
...(!opts.noOutdated ? await checkOutdated(dep) : []),
|
|
52
|
+
];
|
|
53
|
+
return {
|
|
54
|
+
name: dep.name,
|
|
55
|
+
version: dep.version,
|
|
56
|
+
ecosystem: dep.ecosystem,
|
|
57
|
+
riskLevel: maxRisk(signals),
|
|
58
|
+
signals,
|
|
59
|
+
};
|
|
60
|
+
}));
|
|
61
|
+
results.push(...batchResults);
|
|
62
|
+
}
|
|
63
|
+
results.sort((a, b) => RISK_ORDER.indexOf(b.riskLevel) - RISK_ORDER.indexOf(a.riskLevel));
|
|
64
|
+
const summary = {
|
|
65
|
+
total: results.length,
|
|
66
|
+
critical: results.filter(r => r.riskLevel === 'critical').length,
|
|
67
|
+
high: results.filter(r => r.riskLevel === 'high').length,
|
|
68
|
+
medium: results.filter(r => r.riskLevel === 'medium').length,
|
|
69
|
+
low: results.filter(r => r.riskLevel === 'low').length,
|
|
70
|
+
clean: results.filter(r => r.riskLevel === 'none').length,
|
|
71
|
+
};
|
|
72
|
+
return { scannedAt: new Date().toISOString(), manifest, results, summary };
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=scanner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scanner.js","sourceRoot":"","sources":["../../src/scanner.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
export type Ecosystem = 'npm' | 'pypi' | 'maven' | 'cargo' | 'go';
|
|
2
|
+
export type RiskLevel = 'none' | 'low' | 'medium' | 'high' | 'critical';
|
|
3
|
+
export interface Dependency {
|
|
4
|
+
name: string;
|
|
5
|
+
version: string;
|
|
6
|
+
ecosystem: Ecosystem;
|
|
7
|
+
}
|
|
8
|
+
export interface CveSignal {
|
|
9
|
+
type: 'cve';
|
|
10
|
+
id: string;
|
|
11
|
+
severity: RiskLevel;
|
|
12
|
+
summary: string;
|
|
13
|
+
}
|
|
14
|
+
export interface EolSignal {
|
|
15
|
+
type: 'eol';
|
|
16
|
+
cycle: string;
|
|
17
|
+
eolDate: string;
|
|
18
|
+
}
|
|
19
|
+
export interface AbandonedSignal {
|
|
20
|
+
type: 'abandoned';
|
|
21
|
+
lastReleaseDate: string;
|
|
22
|
+
monthsSince: number;
|
|
23
|
+
}
|
|
24
|
+
export interface StaleSignal {
|
|
25
|
+
type: 'stale';
|
|
26
|
+
lastReleaseDate: string;
|
|
27
|
+
monthsSince: number;
|
|
28
|
+
}
|
|
29
|
+
export interface OutdatedSignal {
|
|
30
|
+
type: 'outdated';
|
|
31
|
+
latestVersion: string;
|
|
32
|
+
}
|
|
33
|
+
export type RiskSignal = CveSignal | EolSignal | AbandonedSignal | StaleSignal | OutdatedSignal;
|
|
34
|
+
export interface DependencyResult {
|
|
35
|
+
name: string;
|
|
36
|
+
version: string;
|
|
37
|
+
ecosystem: Ecosystem;
|
|
38
|
+
riskLevel: RiskLevel;
|
|
39
|
+
signals: RiskSignal[];
|
|
40
|
+
}
|
|
41
|
+
export interface ScanSummary {
|
|
42
|
+
total: number;
|
|
43
|
+
critical: number;
|
|
44
|
+
high: number;
|
|
45
|
+
medium: number;
|
|
46
|
+
low: number;
|
|
47
|
+
clean: number;
|
|
48
|
+
}
|
|
49
|
+
export interface ScanResult {
|
|
50
|
+
scannedAt: string;
|
|
51
|
+
manifest: string;
|
|
52
|
+
results: DependencyResult[];
|
|
53
|
+
summary: ScanSummary;
|
|
54
|
+
}
|
|
55
|
+
export interface ScanOptions {
|
|
56
|
+
path: string;
|
|
57
|
+
format: 'table' | 'json' | 'markdown';
|
|
58
|
+
failOn: RiskLevel | 'none';
|
|
59
|
+
concurrency: number;
|
|
60
|
+
noEol: boolean;
|
|
61
|
+
noCve: boolean;
|
|
62
|
+
noActivity: boolean;
|
|
63
|
+
noOutdated: boolean;
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,SAAS,GAAG,KAAK,GAAG,MAAM,GAAG,OAAO,GAAG,OAAO,GAAG,IAAI,CAAC;AAElE,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,UAAU,CAAC;AAExE,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,SAAS,CAAC;CACtB;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,KAAK,CAAC;IACZ,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,SAAS,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,KAAK,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,WAAW,CAAC;IAClB,eAAe,EAAE,MAAM,CAAC;IACxB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,OAAO,CAAC;IACd,eAAe,EAAE,MAAM,CAAC;IACxB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,UAAU,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,MAAM,UAAU,GAAG,SAAS,GAAG,SAAS,GAAG,eAAe,GAAG,WAAW,GAAG,cAAc,CAAC;AAEhG,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,SAAS,CAAC;IACrB,SAAS,EAAE,SAAS,CAAC;IACrB,OAAO,EAAE,UAAU,EAAE,CAAC;CACvB;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,UAAU;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,gBAAgB,EAAE,CAAC;IAC5B,OAAO,EAAE,WAAW,CAAC;CACtB;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,OAAO,GAAG,MAAM,GAAG,UAAU,CAAC;IACtC,MAAM,EAAE,SAAS,GAAG,MAAM,CAAC;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,EAAE,OAAO,CAAC;IACf,UAAU,EAAE,OAAO,CAAC;IACpB,UAAU,EAAE,OAAO,CAAC;CACrB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":""}
|
package/package.json
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "ossrisk",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Scan dependencies for long-term viability risk: EOL versions, CVEs, and abandonment signals",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"ossrisk": "./dist/src/cli.js"
|
|
8
|
+
},
|
|
9
|
+
"main": "./dist/src/scanner.js",
|
|
10
|
+
"types": "./dist/src/scanner.d.ts",
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"types": "./dist/src/scanner.d.ts",
|
|
14
|
+
"default": "./dist/src/scanner.js"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"dist/"
|
|
19
|
+
],
|
|
20
|
+
"scripts": {
|
|
21
|
+
"build": "tsc",
|
|
22
|
+
"dev": "tsx src/cli.ts",
|
|
23
|
+
"test": "vitest run",
|
|
24
|
+
"test:watch": "vitest",
|
|
25
|
+
"prepare": "npm run build",
|
|
26
|
+
"prepublishOnly": "npm test"
|
|
27
|
+
},
|
|
28
|
+
"keywords": ["security", "dependencies", "cve", "eol", "supply-chain", "sbom", "cli"],
|
|
29
|
+
"author": "DepKeep <hello@depkeep.com>",
|
|
30
|
+
"license": "MIT",
|
|
31
|
+
"dependencies": {
|
|
32
|
+
"commander": "^14.0.3"
|
|
33
|
+
},
|
|
34
|
+
"devDependencies": {
|
|
35
|
+
"typescript": "^5.4.0",
|
|
36
|
+
"@types/node": "^20.0.0",
|
|
37
|
+
"tsx": "^4.0.0",
|
|
38
|
+
"vitest": "^2.0.0"
|
|
39
|
+
},
|
|
40
|
+
"engines": {
|
|
41
|
+
"node": ">=18.0.0"
|
|
42
|
+
},
|
|
43
|
+
"repository": {
|
|
44
|
+
"type": "git",
|
|
45
|
+
"url": "https://github.com/depkeep/ossrisk.git"
|
|
46
|
+
},
|
|
47
|
+
"homepage": "https://github.com/depkeep/ossrisk#readme",
|
|
48
|
+
"bugs": {
|
|
49
|
+
"url": "https://github.com/depkeep/ossrisk/issues"
|
|
50
|
+
}
|
|
51
|
+
}
|