@aldegad/safedeps 2.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.
@@ -0,0 +1,104 @@
1
+ #!/usr/bin/env node
2
+ import http from 'node:http';
3
+ import fs from 'node:fs';
4
+
5
+ const portFile = process.argv[2];
6
+ const stateFile = process.argv[3];
7
+
8
+ if (!portFile || !stateFile) {
9
+ console.error('usage: fixture-provider.mjs <port-file> <state-file>');
10
+ process.exit(2);
11
+ }
12
+
13
+ function readJson(req) {
14
+ return new Promise((resolve) => {
15
+ let body = '';
16
+ req.setEncoding('utf8');
17
+ req.on('data', (chunk) => {
18
+ body += chunk;
19
+ });
20
+ req.on('end', () => {
21
+ try {
22
+ resolve(JSON.parse(body || '{}'));
23
+ } catch {
24
+ resolve({});
25
+ }
26
+ });
27
+ });
28
+ }
29
+
30
+ function state() {
31
+ return JSON.parse(fs.readFileSync(stateFile, 'utf8'));
32
+ }
33
+
34
+ function osvVuln(id, fixed) {
35
+ const events = [{ introduced: '0' }];
36
+ if (fixed) events.push({ fixed });
37
+ return {
38
+ id,
39
+ aliases: [id],
40
+ affected: [
41
+ {
42
+ package: { ecosystem: 'npm', name: 'fixture' },
43
+ ranges: [{ type: 'SEMVER', events }]
44
+ }
45
+ ]
46
+ };
47
+ }
48
+
49
+ function osvResponse(packageName, version) {
50
+ const key = `${packageName}@${version}`;
51
+ const current = state();
52
+ if (current.vulnerable?.includes(key)) {
53
+ return { vulns: [osvVuln('CVE-2026-1000', null)] };
54
+ }
55
+ if (packageName === 'fixture-vuln' && version === '1.0.0') {
56
+ return { vulns: [osvVuln('CVE-2026-1001', '1.0.1')] };
57
+ }
58
+ if (packageName === 'fixture-unpatched') {
59
+ return { vulns: [osvVuln('CVE-2026-1002', null)] };
60
+ }
61
+ if (packageName === 'fixture-kev') {
62
+ return { vulns: [osvVuln('CVE-2026-9999', null)] };
63
+ }
64
+ return {};
65
+ }
66
+
67
+ const server = http.createServer(async (req, res) => {
68
+ if (req.method === 'POST' && req.url === '/osv/v1/query') {
69
+ const body = await readJson(req);
70
+ const packageName = body.package?.name || '';
71
+ const version = body.version || '';
72
+ res.setHeader('content-type', 'application/json');
73
+ res.end(JSON.stringify(osvResponse(packageName, version)));
74
+ return;
75
+ }
76
+
77
+ if (req.method === 'GET' && req.url === '/kev.json') {
78
+ res.setHeader('content-type', 'application/json');
79
+ res.end(JSON.stringify({
80
+ vulnerabilities: [
81
+ {
82
+ cveID: 'CVE-2026-9999',
83
+ vendorProject: 'fixture',
84
+ product: 'fixture-kev',
85
+ vulnerabilityName: 'Fixture KEV'
86
+ }
87
+ ]
88
+ }));
89
+ return;
90
+ }
91
+
92
+ if (req.method === 'GET' && req.url.startsWith('/advisories')) {
93
+ res.setHeader('content-type', 'application/json');
94
+ res.end('[]');
95
+ return;
96
+ }
97
+
98
+ res.statusCode = 404;
99
+ res.end('not found');
100
+ });
101
+
102
+ server.listen(0, '127.0.0.1', () => {
103
+ fs.writeFileSync(portFile, String(server.address().port));
104
+ });
@@ -0,0 +1,89 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ ROOT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)
5
+ cd "${ROOT_DIR}"
6
+
7
+ pass() {
8
+ printf 'ok - %s\n' "$1"
9
+ }
10
+
11
+ fail() {
12
+ printf 'not ok - %s\n' "$1" >&2
13
+ exit 1
14
+ }
15
+
16
+ tmp_root=$(mktemp -d "${TMPDIR:-/tmp}/safedeps-smoke.XXXXXX")
17
+ cleanup() {
18
+ rm -rf "${tmp_root}"
19
+ }
20
+ trap cleanup EXIT
21
+
22
+ bash -n bin/safedeps
23
+ bash -n lib/providers/providers.sh
24
+ bash -n lib/ledger/ledger.sh
25
+ bash -n scripts/safedeps-pre-guard.sh
26
+ bash -n scripts/safedeps-post-verify.sh
27
+ bash -n scripts/safedeps-recheck-alert.sh
28
+ pass "bash syntax"
29
+
30
+ node --check scripts/install/install-safedeps-hooks.mjs >/dev/null
31
+ node --check scripts/install/install-safedeps-recheck-agent.mjs >/dev/null
32
+ node --check scripts/install/migrate-safedeps-state.mjs >/dev/null
33
+ node --check scripts/test/fixture-provider.mjs >/dev/null
34
+ node scripts/install/install-safedeps-recheck-agent.mjs --help >/dev/null
35
+ pass "node syntax"
36
+
37
+ version_json=$(HOME="${tmp_root}/home-version" SAFEDEPS_HOME="${tmp_root}/safe-version" ./bin/safedeps --json version)
38
+ [[ "$(jq -r '.version' <<< "${version_json}")" == "2.1.0" ]] || fail "version json is 2.1.0"
39
+ pass "cli version"
40
+
41
+ ledger_json=$(HOME="${tmp_root}/home-ledger" SAFEDEPS_HOME="${tmp_root}/safe-ledger" ./bin/safedeps --json ledger)
42
+ [[ "$(jq -r '.count' <<< "${ledger_json}")" == "0" ]] || fail "isolated ledger starts empty"
43
+ pass "isolated ledger"
44
+
45
+ provider_tmp="${tmp_root}/missing/provider/tmp"
46
+ provider_created=$(
47
+ TMPDIR="${provider_tmp}" \
48
+ SAFEDEPS_HOME="${tmp_root}/safe-provider" \
49
+ bash -c 'source lib/providers/providers.sh; d=$(safedeps_provider_mktemp_dir); test -d "$d"; printf "%s" "$d"'
50
+ )
51
+ [[ "${provider_created}" == "${provider_tmp%/}/safedeps-providers."* ]] || fail "provider tmp helper uses requested TMPDIR"
52
+ pass "provider temp dir"
53
+
54
+ project_dir="${tmp_root}/project"
55
+ mkdir -p "${project_dir}"
56
+ printf '{"dependencies":{}}\n' > "${project_dir}/package.json"
57
+
58
+ deny_json=$(
59
+ HOME="${tmp_root}/home-hook" SAFEDEPS_HOME="${tmp_root}/safe-hook" \
60
+ scripts/safedeps-pre-guard.sh <<EOF
61
+ {"tool_name":"Bash","tool_input":{"command":"npm install left-pad@1.3.0"},"cwd":"${project_dir}"}
62
+ EOF
63
+ )
64
+ [[ "$(jq -r '.hookSpecificOutput.permissionDecision' <<< "${deny_json}")" == "deny" ]] || fail "hook denies unapproved install"
65
+ pass "hook denies unapproved install"
66
+
67
+ mkdir -p "${tmp_root}/safe-hook-allow"
68
+ SAFEDEPS_HOME="${tmp_root}/safe-hook-allow" lib/ledger/ledger.sh approve npm left-pad 1.3.0 1.3.0 smoke >/dev/null
69
+ allow_output=$(
70
+ HOME="${tmp_root}/home-hook-allow" SAFEDEPS_HOME="${tmp_root}/safe-hook-allow" \
71
+ scripts/safedeps-pre-guard.sh <<EOF
72
+ {"tool_name":"Bash","tool_input":{"command":"npm install left-pad@1.3.0"},"cwd":"${project_dir}"}
73
+ EOF
74
+ )
75
+ [[ -z "${allow_output}" ]] || fail "hook allows approved install"
76
+ pass "hook allows approved install"
77
+
78
+ fixture_json="${tmp_root}/recheck-fixture.json"
79
+ printf '%s\n' '{"command":"re-check","checked":2,"still_clean":1,"newly_vulnerable":[],"kev_hit":[],"revoked":[]}' > "${fixture_json}"
80
+ SAFEDEPS_NOTIFY=0 \
81
+ HOME="${tmp_root}/home-recheck" \
82
+ SAFEDEPS_HOME="${tmp_root}/safe-recheck" \
83
+ SAFEDEPS_RECHECK_FIXTURE_JSON="${fixture_json}" \
84
+ scripts/safedeps-recheck-alert.sh
85
+ grep -q '"checked":2' "${tmp_root}/safe-recheck/recheck.log" || fail "re-check wrapper writes log"
86
+ grep -q '"provider_skipped":1' "${tmp_root}/safe-recheck/recheck-alerts.jsonl" || fail "re-check wrapper alerts on skipped provider checks"
87
+ pass "re-check alert wrapper"
88
+
89
+ printf 'smoke passed\n'