@vltpkg/security-archive 1.0.0-rc.8 → 1.0.1

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.
@@ -14,4 +14,3 @@ export declare class SecurityArchive extends Map<DepID, PackageReportData> imple
14
14
  */
15
15
  static load(dump: unknown): SecurityArchive | undefined;
16
16
  }
17
- //# sourceMappingURL=browser.d.ts.map
@@ -33,4 +33,3 @@ export class SecurityArchive extends Map {
33
33
  return archive;
34
34
  }
35
35
  }
36
- //# sourceMappingURL=browser.js.map
@@ -80,4 +80,3 @@ export declare class SecurityArchive extends LRUCache<DepID, PackageReportData>
80
80
  */
81
81
  toJSON(): Record<DepID, PackageReportData>;
82
82
  }
83
- //# sourceMappingURL=index.d.ts.map
@@ -1,4 +1,6 @@
1
+ var _a;
1
2
  import { DatabaseSync } from 'node:sqlite';
3
+ import { spawn } from 'node:child_process';
2
4
  import { mkdirSync } from 'node:fs';
3
5
  import { dirname } from 'node:path';
4
6
  import { LRUCache } from 'lru-cache';
@@ -8,6 +10,7 @@ import { asDepID, splitDepID, baseDepID } from '@vltpkg/dep-id';
8
10
  import { error } from '@vltpkg/error-cause';
9
11
  import { XDG } from '@vltpkg/xdg';
10
12
  import { asPackageReportData } from "./types.js";
13
+ import { __CODE_SPLIT_SCRIPT_NAME } from "./update-expired.js";
11
14
  export * from "./types.js";
12
15
  const SOCKET_API_V0_URL = 'https://api.socket.dev/v0/purl?alerts=true';
13
16
  const SOCKET_PUBLIC_API_TOKEN = 'sktsec_t_--RAN5U4ivauy4w37-6aoKyYPDt5ZbaT5JBVMqiwKo_api';
@@ -24,9 +27,7 @@ const usesTargetRegistry = (node) => {
24
27
  if (nodeType !== 'registry') {
25
28
  return false;
26
29
  }
27
- const reg = nodeRegistry === '' ?
28
- specOptions.registry
29
- : specOptions.registries?.[nodeRegistry];
30
+ const reg = specOptions.registries?.[nodeRegistry];
30
31
  return reg === targetSecurityRegisty;
31
32
  };
32
33
  // Loads the version number to be used in the User-Agent header
@@ -41,7 +42,6 @@ export const { version } = loadPackageJson(import.meta.filename, process.env.__V
41
42
  */
42
43
  export class SecurityArchive extends LRUCache {
43
44
  #expired = new Set();
44
- #pUpdateExpired;
45
45
  #path;
46
46
  #retries;
47
47
  #nodesByName = new Map();
@@ -55,7 +55,7 @@ export class SecurityArchive extends LRUCache {
55
55
  * Creates a new security archive instance and starts the refresh process.
56
56
  */
57
57
  static async start(options) {
58
- const archive = new SecurityArchive(options);
58
+ const archive = new _a(options);
59
59
  await archive.refresh(options);
60
60
  return archive;
61
61
  }
@@ -73,8 +73,8 @@ export class SecurityArchive extends LRUCache {
73
73
  }
74
74
  constructor(options = {}) {
75
75
  super({
76
- max: SecurityArchive.defaultMax,
77
- ttl: SecurityArchive.defaultTtl,
76
+ max: _a.defaultMax,
77
+ ttl: _a.defaultTtl,
78
78
  ...options,
79
79
  allowStale: true,
80
80
  });
@@ -143,35 +143,66 @@ export class SecurityArchive extends LRUCache {
143
143
  db.prepare('DELETE FROM cache WHERE depID = ?').run(depID);
144
144
  }
145
145
  }
146
- // TODO: we need to move this to a detached process in order for the
147
- // cli commands that make usage of the security-archive, e.g: vlt ls,
148
- // vlt query to not hang while waiting for stale-while-revalidate
149
- // request to finish and close the db connection
150
- this.#pUpdateExpired = this.#updateExpired(db);
146
+ // Spawn a detached process to revalidate expired entries in the
147
+ // background so that cli commands (vlt ls, vlt query) don't hang
148
+ // waiting for stale-while-revalidate requests to complete.
149
+ this.#spawnUpdateExpired();
151
150
  }
152
151
  /**
153
- * Updates the database with renewed entries for expired packages.
152
+ * Spawns a detached child process to revalidate expired entries.
153
+ * The process runs independently — the main process does not wait for it.
154
154
  */
155
- async #updateExpired(db) {
156
- const expiredQueue = new Set();
155
+ #spawnUpdateExpired() {
156
+ const expired = [];
157
157
  for (const depID of this.#expired) {
158
158
  const node = this.#nodesByID.get(baseDepID(depID));
159
159
  /* c8 ignore start */
160
- if (!node?.version) {
161
- // skip any missing node or nodes without a version, this
160
+ if (!node?.version || !node.name) {
161
+ // skip any missing node or nodes without a version/name, this
162
162
  // should not happen, but some optional dependencies might
163
163
  // end up in this state when reading from the lockfile
164
164
  continue;
165
165
  }
166
166
  /* c8 ignore stop */
167
- const purl = `pkg:npm/${node.name}@${node.version}`;
168
- expiredQueue.add({ purl });
167
+ expired.push({
168
+ depID: baseDepID(depID),
169
+ name: node.name,
170
+ version: node.version,
171
+ });
169
172
  }
170
- if (expiredQueue.size > 0) {
171
- const res = await pRetry(() => this.#retrieveRemoteData(expiredQueue), { retries: this.#retries });
172
- const ids = this.#loadFromNDJSON(res);
173
- this.#storeNewItemsToDatabase(db, ids);
173
+ if (!expired.length) {
174
+ return;
174
175
  }
176
+ const isDeno = globalThis.Deno !=
177
+ undefined;
178
+ const payload = {
179
+ dbPath: this.#path,
180
+ retries: this.#retries,
181
+ ttl: _a.defaultTtl,
182
+ expired,
183
+ };
184
+ const args = [];
185
+ // Deno on Windows does not support detached processes
186
+ /* c8 ignore next */
187
+ const detached = !(isDeno && process.platform === 'win32');
188
+ /* c8 ignore start */
189
+ if (isDeno) {
190
+ args.push('--unstable-node-globals', '--unstable-bare-node-builtins');
191
+ }
192
+ /* c8 ignore stop */
193
+ args.push(__CODE_SPLIT_SCRIPT_NAME);
194
+ const proc = spawn(process.execPath, args, {
195
+ detached,
196
+ stdio: ['pipe', 'ignore', 'ignore'],
197
+ env: { ...process.env },
198
+ });
199
+ proc.stdin.write(JSON.stringify(payload));
200
+ proc.stdin.end();
201
+ /* c8 ignore start */
202
+ if (detached) {
203
+ proc.unref();
204
+ }
205
+ /* c8 ignore stop */
175
206
  }
176
207
  /**
177
208
  * Queues up all required packages that are missing from the archive.
@@ -337,26 +368,18 @@ export class SecurityArchive extends LRUCache {
337
368
  this.#validateReportData();
338
369
  }
339
370
  finally {
340
- // TODO: once we move the stale-while-revalidate to a detached process
341
- // the this.#close method no longer needs to be async
342
- void this.#close(db);
371
+ this.#close(db);
343
372
  }
344
373
  }
345
374
  /**
346
375
  * Closes the database connection and cleans up the internal state.
347
376
  */
348
- async #close(db) {
349
- // the revalidation of stale entries might not yet be completed
350
- // so in case we have a pending promise for that, we need to wait
351
- await this.#pUpdateExpired;
377
+ #close(db) {
352
378
  // close db connection
353
379
  db.exec('PRAGMA optimize');
354
380
  db.close();
355
381
  // clean up internal state
356
382
  this.#expired.clear();
357
- this.#pUpdateExpired = undefined;
358
- // TODO: at this point we could spawn a deref process to
359
- // remove entries with expired ttl values and vaccum the db
360
383
  }
361
384
  /**
362
385
  * Outputs the current in-memory cache as a JSON object.
@@ -369,4 +392,4 @@ export class SecurityArchive extends LRUCache {
369
392
  return obj;
370
393
  }
371
394
  }
372
- //# sourceMappingURL=index.js.map
395
+ _a = SecurityArchive;
@@ -89,4 +89,3 @@ export type PackageReportData = {
89
89
  };
90
90
  export declare const isPackageReportData: (o: unknown) => o is PackageReportData;
91
91
  export declare const asPackageReportData: (o: unknown) => PackageReportData;
92
- //# sourceMappingURL=types.d.ts.map
@@ -27,4 +27,3 @@ export const asPackageReportData = (o) => {
27
27
  }
28
28
  return o;
29
29
  };
30
- //# sourceMappingURL=types.js.map
@@ -0,0 +1,32 @@
1
+ import type { DepID } from '@vltpkg/dep-id';
2
+ import type EventEmitter from 'node:events';
3
+ export declare const __CODE_SPLIT_SCRIPT_NAME: string;
4
+ export declare const version: string;
5
+ /**
6
+ * Serialized payload sent to the detached process via stdin.
7
+ */
8
+ export type UpdateExpiredPayload = {
9
+ /** Path to the sqlite database */
10
+ dbPath: string;
11
+ /** Number of retries for fetching remote data */
12
+ retries: number;
13
+ /** TTL in ms to use for new entries */
14
+ ttl: number;
15
+ /** Expired entries to revalidate */
16
+ expired: ExpiredEntry[];
17
+ };
18
+ /**
19
+ * Minimal serialized information for each expired entry.
20
+ * Only carries what's needed for the API call + DB write.
21
+ */
22
+ export type ExpiredEntry = {
23
+ depID: DepID;
24
+ name: string;
25
+ version: string;
26
+ };
27
+ /**
28
+ * Main entrypoint for the detached process.
29
+ * Reads a JSON payload from stdin, fetches updated security data,
30
+ * and writes it back to the SQLite database.
31
+ */
32
+ export declare const main: (input?: EventEmitter) => Promise<boolean>;
@@ -0,0 +1,153 @@
1
+ import { DatabaseSync } from 'node:sqlite';
2
+ import { mkdirSync } from 'node:fs';
3
+ import { dirname } from 'node:path';
4
+ import { pathToFileURL } from 'node:url';
5
+ import pRetry, { AbortError } from 'p-retry';
6
+ import { asDepID, baseDepID } from '@vltpkg/dep-id';
7
+ import { error } from '@vltpkg/error-cause';
8
+ import { loadPackageJson } from 'package-json-from-dist';
9
+ import { asPackageReportData } from "./types.js";
10
+ export const __CODE_SPLIT_SCRIPT_NAME = import.meta.filename;
11
+ const SOCKET_API_V0_URL = 'https://api.socket.dev/v0/purl?alerts=true';
12
+ const SOCKET_PUBLIC_API_TOKEN = 'sktsec_t_--RAN5U4ivauy4w37-6aoKyYPDt5ZbaT5JBVMqiwKo_api';
13
+ export const { version } = loadPackageJson(import.meta.filename, process.env.__VLT_INTERNAL_CLI_PACKAGE_JSON);
14
+ /* c8 ignore start */
15
+ const isMain = (path) => path === __CODE_SPLIT_SCRIPT_NAME ||
16
+ path === pathToFileURL(__CODE_SPLIT_SCRIPT_NAME).toString();
17
+ /* c8 ignore stop */
18
+ /**
19
+ * Fetches security information from the socket.dev API.
20
+ */
21
+ const retrieveRemoteData = async (queue, retries) => {
22
+ return pRetry(async () => {
23
+ const req = await fetch(SOCKET_API_V0_URL, {
24
+ method: 'POST',
25
+ headers: {
26
+ Authorization: `Basic ${Buffer.from(`${SOCKET_PUBLIC_API_TOKEN}:`).toString('base64url')}`,
27
+ 'User-Agent': `@vltpkg/security-archive/${version}`,
28
+ },
29
+ body: JSON.stringify({
30
+ components: Array.from(queue),
31
+ }),
32
+ });
33
+ if (req.status === 404) {
34
+ throw new AbortError('Missing API');
35
+ }
36
+ if (!req.ok || !(req.status >= 200 && req.status <= 299)) {
37
+ throw error('Failed to fetch security data', {
38
+ response: req,
39
+ });
40
+ }
41
+ const str = await req.text();
42
+ return str.trim() + '\n';
43
+ }, { retries });
44
+ };
45
+ /**
46
+ * Main entrypoint for the detached process.
47
+ * Reads a JSON payload from stdin, fetches updated security data,
48
+ * and writes it back to the SQLite database.
49
+ */
50
+ export const main = async (input = process.stdin) => {
51
+ const payload = await new Promise((resolve, reject) => {
52
+ const chunks = [];
53
+ let chunkLen = 0;
54
+ input.on('data', (chunk) => {
55
+ chunks.push(chunk);
56
+ chunkLen += chunk.length;
57
+ });
58
+ input.on('end', () => {
59
+ try {
60
+ const raw = Buffer.concat(chunks, chunkLen).toString();
61
+ resolve(JSON.parse(raw));
62
+ /* c8 ignore start */
63
+ }
64
+ catch (err) {
65
+ reject(err);
66
+ }
67
+ /* c8 ignore stop */
68
+ });
69
+ /* c8 ignore next */
70
+ input.on('error', reject);
71
+ });
72
+ const { dbPath, retries, ttl, expired } = payload;
73
+ if (!expired.length) {
74
+ return false;
75
+ }
76
+ // Build purl queue from expired entries
77
+ const expiredQueue = new Set();
78
+ // Build a lookup map: name@version -> depID
79
+ const entryByNameVersion = new Map();
80
+ for (const entry of expired) {
81
+ const purl = `pkg:npm/${entry.name}@${entry.version}`;
82
+ expiredQueue.add({ purl });
83
+ entryByNameVersion.set(`${entry.name}@${entry.version}`, entry);
84
+ }
85
+ // Fetch updated data
86
+ const res = await retrieveRemoteData(expiredQueue, retries);
87
+ // Parse NDJSON response and collect results
88
+ const now = Date.now();
89
+ const results = [];
90
+ const json = res.split('}\n');
91
+ for (const line of json) {
92
+ if (!line.trim())
93
+ continue;
94
+ const data = JSON.parse(line + '}');
95
+ const scope = data.namespace ? `${data.namespace}/` : '';
96
+ const name = `${scope}${data.name}`;
97
+ const key = `${name}@${data.version}`;
98
+ const entry = entryByNameVersion.get(key);
99
+ if (!entry) {
100
+ // eslint-disable-next-line no-console
101
+ console.warn(`security-archive: failed to find entry for ${key} found in the response.`);
102
+ continue;
103
+ }
104
+ // Calculate average score from all score components
105
+ const scoreComponents = [
106
+ data.score.license,
107
+ data.score.maintenance,
108
+ data.score.quality,
109
+ data.score.supplyChain,
110
+ data.score.vulnerability,
111
+ ];
112
+ const newAverageScore = Number((scoreComponents.reduce((sum, score) => sum + score, 0) /
113
+ scoreComponents.length).toFixed(2));
114
+ const reportData = asPackageReportData({
115
+ ...data,
116
+ score: { ...data.score, overall: newAverageScore },
117
+ });
118
+ results.push({
119
+ depID: baseDepID(asDepID(entry.depID)),
120
+ report: JSON.stringify(reportData),
121
+ start: now,
122
+ ttl,
123
+ });
124
+ }
125
+ if (!results.length) {
126
+ return false;
127
+ }
128
+ // Write to database
129
+ mkdirSync(dirname(dbPath), { recursive: true });
130
+ const db = new DatabaseSync(dbPath);
131
+ db.exec('CREATE TABLE IF NOT EXISTS cache ' +
132
+ '(depID TEXT PRIMARY KEY, report TEXT, ttl INTEGER, start INTEGER) ' +
133
+ 'WITHOUT ROWID');
134
+ db.exec('PRAGMA journal_mode = WAL');
135
+ db.exec('PRAGMA synchronous = NORMAL');
136
+ const dbWrite = db.prepare('INSERT OR REPLACE INTO cache (depID, report, start, ttl) ' +
137
+ 'VALUES (?, ?, ?, ?)');
138
+ for (const { depID, report, start, ttl: entryTtl } of results) {
139
+ dbWrite.run(depID, report, start, entryTtl);
140
+ }
141
+ db.exec('PRAGMA optimize');
142
+ db.close();
143
+ return true;
144
+ };
145
+ /* c8 ignore start */
146
+ if (isMain(process.argv[1])) {
147
+ process.title = 'vlt-security-archive-update';
148
+ const res = await main(process.stdin);
149
+ if (!res) {
150
+ process.exit(1);
151
+ }
152
+ }
153
+ /* c8 ignore stop */
package/package.json CHANGED
@@ -1,84 +1,84 @@
1
1
  {
2
2
  "name": "@vltpkg/security-archive",
3
3
  "description": "A database of security information of packages",
4
- "version": "1.0.0-rc.8",
4
+ "version": "1.0.1",
5
5
  "repository": {
6
6
  "type": "git",
7
7
  "url": "git+https://github.com/vltpkg/vltpkg.git",
8
8
  "directory": "src/security-archive"
9
9
  },
10
- "author": "vlt technology inc. <support@vlt.sh> (http://vlt.sh)",
11
- "tshy": {
12
- "selfLink": false,
13
- "liveDev": true,
14
- "dialects": [
15
- "esm"
16
- ],
17
- "exports": {
18
- "./package.json": "./package.json",
19
- ".": "./src/index.ts",
20
- "./browser": "./src/browser.ts"
21
- }
10
+ "author": {
11
+ "name": "vlt technology inc.",
12
+ "email": "support@vlt.sh",
13
+ "url": "http://vlt.sh"
22
14
  },
23
15
  "dependencies": {
24
- "lru-cache": "^11.1.0",
25
- "p-retry": "^7.0.0",
26
- "package-json-from-dist": "^1.0.1",
27
- "@vltpkg/dep-id": "1.0.0-rc.8",
28
- "@vltpkg/graph": "1.0.0-rc.8",
29
- "@vltpkg/error-cause": "1.0.0-rc.8",
30
- "@vltpkg/spec": "1.0.0-rc.8",
31
- "@vltpkg/types": "1.0.0-rc.8",
32
- "@vltpkg/xdg": "1.0.0-rc.8"
16
+ "@vltpkg/dep-id": "1.0.1",
17
+ "@vltpkg/error-cause": "1.0.1",
18
+ "@vltpkg/spec": "1.0.1",
19
+ "@vltpkg/types": "1.0.1",
20
+ "@vltpkg/xdg": "1.0.1",
21
+ "lru-cache": "^11.2.4",
22
+ "p-retry": "^7.1.1",
23
+ "package-json-from-dist": "^1.0.1"
33
24
  },
34
25
  "devDependencies": {
35
- "@eslint/js": "^9.34.0",
36
- "@types/node": "^22.17.2",
37
- "eslint": "^9.34.0",
38
- "prettier": "^3.6.2",
39
- "tap": "^21.1.0",
40
- "tshy": "^3.0.2",
26
+ "@eslint/js": "^9.39.1",
27
+ "@types/node": "^22.19.2",
28
+ "eslint": "^9.39.1",
29
+ "prettier": "^3.7.4",
30
+ "tap": "^21.5.0",
41
31
  "typedoc": "~0.27.9",
42
32
  "typescript": "5.7.3",
43
- "typescript-eslint": "^8.40.0"
33
+ "typescript-eslint": "^8.49.0"
44
34
  },
45
35
  "license": "BSD-2-Clause-Patent",
46
36
  "engines": {
47
- "node": ">=22"
37
+ "node": ">=22.22.0"
38
+ },
39
+ "scripts": {
40
+ "format": "prettier --write . --log-level warn --ignore-path ../../.prettierignore --cache",
41
+ "format:check": "prettier --check . --ignore-path ../../.prettierignore --cache",
42
+ "lint": "eslint . --fix",
43
+ "lint:check": "eslint .",
44
+ "prepack": "tsc -p tsconfig.publish.json && ../../scripts/update-dist-exports.ts",
45
+ "snap": "tap",
46
+ "test": "tap",
47
+ "posttest": "tsc --noEmit",
48
+ "typecheck": "tsc --noEmit"
48
49
  },
49
50
  "tap": {
50
51
  "extends": "../../tap-config.yaml"
51
52
  },
52
53
  "prettier": "../../.prettierrc.js",
53
- "module": "./dist/esm/index.js",
54
+ "module": "./dist/index.js",
54
55
  "type": "module",
55
56
  "exports": {
56
57
  "./package.json": "./package.json",
57
58
  ".": {
58
59
  "import": {
59
- "types": "./dist/esm/index.d.ts",
60
- "default": "./dist/esm/index.js"
60
+ "default": "./dist/index.js"
61
61
  }
62
62
  },
63
63
  "./browser": {
64
64
  "import": {
65
- "types": "./dist/esm/browser.d.ts",
66
- "default": "./dist/esm/browser.js"
65
+ "default": "./dist/browser.js"
66
+ }
67
+ },
68
+ "./update-expired": {
69
+ "import": {
70
+ "default": "./dist/update-expired.js"
67
71
  }
68
72
  }
69
73
  },
70
74
  "files": [
71
75
  "dist"
72
76
  ],
73
- "scripts": {
74
- "format": "prettier --write . --log-level warn --ignore-path ../../.prettierignore --cache",
75
- "format:check": "prettier --check . --ignore-path ../../.prettierignore --cache",
76
- "lint": "eslint . --fix",
77
- "lint:check": "eslint .",
78
- "snap": "tap",
79
- "test": "tap",
80
- "posttest": "tsc --noEmit",
81
- "tshy": "tshy",
82
- "typecheck": "tsc --noEmit"
83
- }
84
- }
77
+ "bugs": [
78
+ {
79
+ "type": "link",
80
+ "url": "https://github.com/vltpkg/vltpkg/issues"
81
+ }
82
+ ],
83
+ "homepage": "https://github.com/vltpkg/vltpkg/tree/main/src/security-archive#readme"
84
+ }
@@ -1 +0,0 @@
1
- {"version":3,"file":"browser.d.ts","sourceRoot":"","sources":["../../src/browser.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,iBAAiB,EACjB,mBAAmB,EACpB,MAAM,YAAY,CAAA;AACnB,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAA;AAE3C,cAAc,YAAY,CAAA;AAsB1B;;GAEG;AACH,qBAAa,eACX,SAAQ,GAAG,CAAC,KAAK,EAAE,iBAAiB,CACpC,YAAW,mBAAmB;IAE9B;;OAEG;IACH,EAAE,UAAQ;IAEV;;OAEG;IACH,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,OAAO;CAU1B"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"browser.js","sourceRoot":"","sources":["../../src/browser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAA;AAChD,OAAO,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAA;AAC3C,OAAO,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAA;AAQhD,cAAc,YAAY,CAAA;AAE1B,MAAM,KAAK,GAAG,CAAC,CAAU,EAAgC,EAAE,CACzD,CAAC,CAAC,CAAC,IAAI,OAAO,CAAC,KAAK,QAAQ,CAAA;AAE9B,MAAM,qBAAqB,GAAG,CAC5B,IAAa,EACsB,EAAE,CACrC,KAAK,CAAC,IAAI,CAAC;IACX,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,CACxB,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,OAAO,GAAG,KAAK,QAAQ,IAAI,KAAK,CAAC,KAAK,CAAC,CAC1D,CAAA;AAEH,MAAM,qBAAqB,GAAG,CAC5B,IAAa,EACc,EAAE;IAC7B,IAAI,CAAC,qBAAqB,CAAC,IAAI,CAAC,EAAE,CAAC;QACjC,MAAM,KAAK,CAAC,+BAA+B,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAA;IAC/D,CAAC;IACD,OAAO,IAAI,CAAA;AACb,CAAC,CAAA;AAED;;GAEG;AACH,MAAM,OAAO,eACX,SAAQ,GAA6B;IAGrC;;OAEG;IACH,EAAE,GAAG,KAAK,CAAA;IAEV;;OAEG;IACH,MAAM,CAAC,IAAI,CAAC,IAAa;QACvB,IAAI,IAAI,KAAK,SAAS;YAAE,OAAO,SAAS,CAAA;QAExC,MAAM,OAAO,GAAG,IAAI,eAAe,EAAE,CAAA;QACrC,MAAM,IAAI,GAAG,qBAAqB,CAAC,IAAI,CAAC,CAAA;QACxC,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;YAChD,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,mBAAmB,CAAC,KAAK,CAAC,CAAC,CAAA;QACvD,CAAC;QACD,OAAO,OAAO,CAAA;IAChB,CAAC;CACF","sourcesContent":["import { asDepID } from '@vltpkg/dep-id/browser'\nimport { error } from '@vltpkg/error-cause'\nimport { asPackageReportData } from './types.ts'\nimport type { JSONField } from '@vltpkg/types'\nimport type {\n PackageReportData,\n SecurityArchiveLike,\n} from './types.ts'\nimport type { DepID } from '@vltpkg/dep-id'\n\nexport * from './types.ts'\n\nconst isObj = (o: unknown): o is Record<string, unknown> =>\n !!o && typeof o === 'object'\n\nconst isSecurityArchiveJSON = (\n json: unknown,\n): json is Record<string, JSONField> =>\n isObj(json) &&\n Object.entries(json).every(\n ([key, value]) => typeof key === 'string' && isObj(value),\n )\n\nconst asSecurityArchiveJSON = (\n json: unknown,\n): Record<string, JSONField> => {\n if (!isSecurityArchiveJSON(json)) {\n throw error('Invalid security archive JSON', { found: json })\n }\n return json\n}\n\n/**\n * A database of security information for given packages in a graph.\n */\nexport class SecurityArchive\n extends Map<DepID, PackageReportData>\n implements SecurityArchiveLike\n{\n /**\n * Whether the security archive is valid.\n */\n ok = false\n\n /**\n * Loads a security archive from a valid JSON dump.\n */\n static load(dump: unknown) {\n if (dump === undefined) return undefined\n\n const archive = new SecurityArchive()\n const json = asSecurityArchiveJSON(dump)\n for (const [key, value] of Object.entries(json)) {\n archive.set(asDepID(key), asPackageReportData(value))\n }\n return archive\n }\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAA;AAOpC,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAA;AAE3C,OAAO,KAAK,EACV,iBAAiB,EACjB,mBAAmB,EACnB,6BAA6B,EAC9B,MAAM,YAAY,CAAA;AAEnB,cAAc,YAAY,CAAA;AAM1B,eAAO,MAAM,qBAAqB,gCAAgC,CAAA;AAElE,MAAM,MAAM,gBAAgB,GAAG;IAC7B,SAAS,CAAC,EAAE,WAAW,CAAA;IACvB,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,CAAA;IACf,KAAK,EAAE;QACL,OAAO,EAAE,MAAM,CAAA;QACf,OAAO,EAAE,MAAM,CAAA;QACf,WAAW,EAAE,MAAM,CAAA;QACnB,OAAO,EAAE,MAAM,CAAA;QACf,WAAW,EAAE,MAAM,CAAA;QACnB,aAAa,EAAE,MAAM,CAAA;KACtB,CAAA;CACF,CAAA;AAED,MAAM,MAAM,WAAW,GAAG;IACxB,KAAK,EAAE,MAAM,CAAA;IACb,GAAG,EAAE,MAAM,CAAA;IACX,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,MAAM,CAAA;IACb,GAAG,EAAE,MAAM,CAAA;CACZ,CAAA;AAED,MAAM,MAAM,YAAY,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;AAE3D,MAAM,MAAM,sBAAsB,GAAG,QAAQ,CAAC,WAAW,CACvD,KAAK,EACL,iBAAiB,EACjB,OAAO,CACR,GAAG;IACF;;OAEG;IACH,WAAW,CAAC,EAAE,SAAS,CAAA;IACvB;;OAEG;IACH,IAAI,CAAC,EAAE,MAAM,CAAA;IACb;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB,CAAA;AAwBD,eAAO,MAAQ,OAAO,QAKrB,CAAA;AAED;;;;;;;GAOG;AACH,qBAAa,eACX,SAAQ,QAAQ,CAAC,KAAK,EAAE,iBAAiB,CACzC,YAAW,mBAAmB;;IAS9B;;;OAGG;IACH,EAAE,UAAQ;IAEV;;OAEG;WACU,KAAK,CAChB,OAAO,EAAE,sBAAsB,GAAG,6BAA6B;IAOjE;;OAEG;IACH,MAAM,KAAK,UAAU,WAEpB;IAED;;OAEG;IACH,MAAM,KAAK,UAAU,WAEpB;gBAEW,OAAO,GAAE,sBAA2B;IA6QhD;;;;;;OAMG;IACG,OAAO,CAAC,EAAE,KAAK,EAAE,EAAE,6BAA6B;IA4DtD;;OAEG;IACH,MAAM;CAOP"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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","sourcesContent":["import { DatabaseSync } from 'node:sqlite'\nimport { mkdirSync } from 'node:fs'\nimport { dirname } from 'node:path'\nimport { LRUCache } from 'lru-cache'\nimport pRetry, { AbortError } from 'p-retry'\nimport { loadPackageJson } from 'package-json-from-dist'\nimport { asDepID, splitDepID, baseDepID } from '@vltpkg/dep-id'\nimport { error } from '@vltpkg/error-cause'\nimport { XDG } from '@vltpkg/xdg'\nimport { asPackageReportData } from './types.ts'\nimport type { DepID } from '@vltpkg/dep-id'\nimport type { NodeLike } from '@vltpkg/types'\nimport type {\n PackageReportData,\n SecurityArchiveLike,\n SecurityArchiveRefreshOptions,\n} from './types.ts'\n\nexport * from './types.ts'\n\nconst SOCKET_API_V0_URL = 'https://api.socket.dev/v0/purl?alerts=true'\nconst SOCKET_PUBLIC_API_TOKEN =\n 'sktsec_t_--RAN5U4ivauy4w37-6aoKyYPDt5ZbaT5JBVMqiwKo_api'\n\nexport const targetSecurityRegisty = 'https://registry.npmjs.org/'\n\nexport type JSONItemResponse = {\n namespace?: `@{string}`\n name: string\n version: string\n score: {\n overall: number\n license: number\n maintenance: number\n quality: number\n supplyChain: number\n vulnerability: number\n }\n}\n\nexport type DBReadEntry = {\n depID: string\n now: number\n report: string\n start: number\n ttl: number\n}\n\nexport type DBWriteEntry = [string, string, number, number]\n\nexport type SecurityArchiveOptions = LRUCache.OptionsBase<\n DepID,\n PackageReportData,\n unknown\n> & {\n /**\n * Security archive does not supports a fetch-on-demand model.\n */\n fetchMethod?: undefined\n /**\n * An optional value for the path in which to store the sqlite db.\n */\n path?: string\n /**\n * Number of retries attempts to reach the remote security API.\n */\n retries?: number\n}\n\n/**\n * Only the public npm registry has information available in the\n * socket.dev API. This function checks if a given depID is pointing\n * to the public npm registry and returns `true` if it does.\n */\nconst usesTargetRegistry = (node: NodeLike): boolean => {\n const depID = node.id\n const specOptions = node.options\n const [nodeType, nodeRegistry] = splitDepID(depID)\n\n if (nodeType !== 'registry') {\n return false\n }\n\n const reg =\n nodeRegistry === '' ?\n specOptions.registry\n : specOptions.registries?.[nodeRegistry]\n return reg === targetSecurityRegisty\n}\n\n// Loads the version number to be used in the User-Agent header\nexport const { version } = loadPackageJson(\n import.meta.filename,\n process.env.__VLT_INTERNAL_CLI_PACKAGE_JSON,\n) as {\n version: string\n}\n\n/**\n * A database of security information for given packages from a list of nodes.\n *\n * Using the SecurityArchive.refresh() method will update the local cache\n * with information from the socket.dev APIs or load from the local storage\n * if available. Information about package security is then available\n * using the SecurityArchive.get() method.\n */\nexport class SecurityArchive\n extends LRUCache<DepID, PackageReportData>\n implements SecurityArchiveLike\n{\n #expired = new Set<DepID>()\n #pUpdateExpired: Promise<void> | undefined\n #path: string\n #retries: number\n #nodesByName = new Map<string, Set<NodeLike>>()\n #nodesByID = new Map<DepID, NodeLike>()\n\n /**\n * True if the refresh process was successful and report data is available\n * for all public registry packages from the initial list of nodes.\n */\n ok = false\n\n /**\n * Creates a new security archive instance and starts the refresh process.\n */\n static async start(\n options: SecurityArchiveOptions & SecurityArchiveRefreshOptions,\n ) {\n const archive = new SecurityArchive(options)\n await archive.refresh(options)\n return archive\n }\n\n /**\n * By default, limits to 100K entries in the in-memory archive.\n */\n static get defaultMax() {\n return 100_000\n }\n\n /**\n * By default, entries are cached for 3 hours.\n */\n static get defaultTtl() {\n return 1000 * 60 * 60 * 3\n }\n\n constructor(options: SecurityArchiveOptions = {}) {\n super({\n max: SecurityArchive.defaultMax,\n ttl: SecurityArchive.defaultTtl,\n ...options,\n allowStale: true,\n })\n\n this.#path =\n options.path ?? new XDG('vlt').cache('security-archive.db')\n this.#retries = options.retries ?? 3\n }\n\n /**\n * Retrieves a node using its name and version.\n */\n #retrieveNodeByNameVersion(\n name: string,\n version: string,\n ): NodeLike | undefined {\n for (const node of this.#nodesByName.get(name) ?? []) {\n if (node.version === version) {\n return node\n }\n }\n }\n\n /**\n * Opens a connection to the database at the given path.\n */\n #openDatabase(): DatabaseSync {\n mkdirSync(dirname(this.#path), { recursive: true })\n const db = new DatabaseSync(this.#path)\n db.exec(\n 'CREATE TABLE IF NOT EXISTS cache ' +\n '(depID TEXT PRIMARY KEY, report TEXT, ttl INTEGER, start INTEGER) ' +\n // WITHOUT ROWID models a key=value storage,\n // enforcing depID must be unique and not null\n // while using less space and more efficient lookups\n // https://www.sqlite.org/withoutrowid.html\n 'WITHOUT ROWID',\n )\n db.exec('PRAGMA journal_mode = WAL')\n db.exec('PRAGMA synchronous = NORMAL')\n return db\n }\n\n /**\n * Loads all valid items found in the database into the in-memory cache.\n */\n #loadItemsFromDatabase(db: DatabaseSync, nodes: NodeLike[]): void {\n const depIDs: string[] = []\n for (const node of nodes) {\n depIDs.push(`'${baseDepID(node.id)}'`)\n }\n // retrieves from the db packages using their dep-id reference\n // and only include entries that have a valid TTL value\n const dbRead = db.prepare(\n 'SELECT depID, report, start, ttl, ' +\n `(SELECT UNIXEPOCH('subsecond') * 1000) as now ` +\n 'FROM cache ' +\n `WHERE depID IN (${depIDs.join(',')})`,\n )\n // reset the list of expired entries\n this.#expired.clear()\n for (const entry of dbRead.all() as DBReadEntry[]) {\n const { depID, now, report, start, ttl } = entry\n const id = baseDepID(asDepID(depID))\n try {\n this.set(id, asPackageReportData(JSON.parse(report)), {\n ttl,\n start,\n })\n // stale values are queued up as expired for revalidation\n if (start + ttl < now) {\n this.#expired.add(id)\n }\n } catch {\n // prune any invalid entries from the database\n db.prepare('DELETE FROM cache WHERE depID = ?').run(depID)\n }\n }\n // TODO: we need to move this to a detached process in order for the\n // cli commands that make usage of the security-archive, e.g: vlt ls,\n // vlt query to not hang while waiting for stale-while-revalidate\n // request to finish and close the db connection\n this.#pUpdateExpired = this.#updateExpired(db)\n }\n\n /**\n * Updates the database with renewed entries for expired packages.\n */\n async #updateExpired(db: DatabaseSync): Promise<void> {\n const expiredQueue = new Set<Record<'purl', string>>()\n for (const depID of this.#expired) {\n const node = this.#nodesByID.get(baseDepID(depID))\n\n /* c8 ignore start */\n if (!node?.version) {\n // skip any missing node or nodes without a version, this\n // should not happen, but some optional dependencies might\n // end up in this state when reading from the lockfile\n continue\n }\n /* c8 ignore stop */\n\n const purl = `pkg:npm/${node.name}@${node.version}`\n expiredQueue.add({ purl })\n }\n if (expiredQueue.size > 0) {\n const res = await pRetry(\n () => this.#retrieveRemoteData(expiredQueue),\n { retries: this.#retries },\n )\n const ids = this.#loadFromNDJSON(res)\n this.#storeNewItemsToDatabase(db, ids)\n }\n }\n\n /**\n * Queues up all required packages that are missing from the archive.\n */\n #queueUpRequiredPackages(): Set<Record<'purl', string>> {\n const queue = new Set<Record<'purl', string>>()\n for (const node of this.#nodesByID.values()) {\n const normalizedId = baseDepID(node.id)\n // only queue up valid public registry\n // references that are missing from the archive\n // also skips any pkg marked as expired\n if (\n usesTargetRegistry(node) &&\n !this.has(normalizedId) &&\n !this.#expired.has(normalizedId)\n ) {\n const purl = `pkg:npm/${node.name}@${node.version}`\n queue.add({ purl })\n }\n }\n return queue\n }\n\n /**\n * Fetches security information from the socket.dev API.\n * Returns a string of NDJSON data.\n */\n async #retrieveRemoteData(\n queue: Set<Record<'purl', string>>,\n ): Promise<string> {\n // fetch information from the socket.dev API\n const req = await fetch(SOCKET_API_V0_URL, {\n method: 'POST',\n headers: {\n Authorization: `Basic ${Buffer.from(`${SOCKET_PUBLIC_API_TOKEN}:`).toString('base64url')}`,\n 'User-Agent': `@vltpkg/security-archive/${version}`,\n },\n body: JSON.stringify({\n components: Array.from(queue),\n }),\n })\n // on missing valid auth or API, it should abort the retry logic\n if (req.status === 404) {\n throw new AbortError('Missing API')\n }\n // on any other error throws an error that will trigger retry\n if (!req.ok || !(req.status >= 200 && req.status <= 299)) {\n throw error('Failed to fetch security data', { response: req })\n }\n\n const str = await req.text()\n return str.trim() + '\\n'\n }\n\n /**\n * Parses and load NDJSON data into the in-memory cache.\n * Returns a set of dep ids that were successfully loaded.\n */\n #loadFromNDJSON(str: string): Set<DepID> {\n // builds a set of dep ids that were successfully fetched and loaded\n const fetchedDepIDs = new Set<DepID>()\n const json = str.split('}\\n')\n for (const line of json) {\n if (!line.trim()) continue\n const data = JSON.parse(line + '}') as JSONItemResponse\n const scope = data.namespace ? `${data.namespace}/` : ''\n const name = `${scope}${data.name}`\n const node = this.#retrieveNodeByNameVersion(name, data.version)\n if (node) {\n const normalizedId = baseDepID(node.id)\n fetchedDepIDs.add(baseDepID(node.id))\n // Calculate average score from all score components\n const scoreComponents = [\n data.score.license,\n data.score.maintenance,\n data.score.quality,\n data.score.supplyChain,\n data.score.vulnerability,\n ]\n const newAverageScore = Number(\n (\n scoreComponents.reduce((sum, score) => sum + score, 0) /\n scoreComponents.length\n ).toFixed(2),\n )\n // Add average score to the score object\n const scoreWithNewAverage = {\n ...data.score,\n overall: newAverageScore,\n }\n this.set(\n normalizedId,\n asPackageReportData({\n ...data,\n score: scoreWithNewAverage,\n }),\n )\n } else {\n // eslint-disable-next-line no-console\n console.warn(\n `security-archive: failed to find node for ${scope}${data.name}@${data.version} found in the response.`,\n )\n }\n }\n return fetchedDepIDs\n }\n\n /**\n * Store new in-memory items to the database.\n */\n #storeNewItemsToDatabase(\n db: DatabaseSync,\n depIDs: Set<DepID>,\n ): void {\n const insertData: DBWriteEntry[] = []\n for (const depID of depIDs) {\n const entry = this.info(depID)\n if (entry?.start && entry.ttl) {\n insertData.push([\n depID,\n JSON.stringify(entry.value),\n entry.start,\n entry.ttl,\n ])\n }\n }\n const dbWrite = db.prepare(\n 'INSERT OR REPLACE INTO cache (depID, report, start, ttl) ' +\n 'VALUES (?, ?, ?, ?)',\n )\n for (const data of insertData) {\n dbWrite.run(...data)\n }\n }\n\n /**\n * Validates that all public-registry packages in the nodes\n * have a valid report data in the current in-memory cache.\n */\n #validateReportData() {\n for (const node of this.#nodesByID.values()) {\n if (usesTargetRegistry(node)) {\n if (!this.has(baseDepID(node.id))) {\n this.ok = false\n return\n }\n }\n }\n this.ok = true\n }\n\n /**\n * Starts the security archive by providing an array of {@link NodeLike} instances,\n * its registry-based nodes are going to be used as valid potential entries.\n *\n * Any entry that is missing from the persisted cached values are going\n * to be requested in a batch-request to the remote socket.dev API.\n */\n async refresh({ nodes }: SecurityArchiveRefreshOptions) {\n // should start by clearing the current in-memory cache\n this.clear()\n\n const db = this.#openDatabase()\n\n // indexes nodes by name and id for quick lookup\n this.#nodesByName.clear()\n this.#nodesByID.clear()\n for (const node of nodes) {\n /* c8 ignore start */\n const setByName =\n this.#nodesByName.get(node.name ?? '') ?? new Set()\n setByName.add(node)\n this.#nodesByName.set(node.name ?? '', setByName)\n /* c8 ignore stop */\n this.#nodesByID.set(baseDepID(node.id), node)\n }\n\n try {\n this.#loadItemsFromDatabase(db, nodes)\n\n const queue = this.#queueUpRequiredPackages()\n // only reach for the remote API if there are packages queued up\n if (queue.size > 0) {\n // Parse the response data\n const res = await pRetry(\n () => this.#retrieveRemoteData(queue),\n { retries: this.#retries },\n )\n const ids = this.#loadFromNDJSON(res)\n this.#storeNewItemsToDatabase(db, ids)\n }\n\n // validates the refresh process was successful\n this.#validateReportData()\n } finally {\n // TODO: once we move the stale-while-revalidate to a detached process\n // the this.#close method no longer needs to be async\n void this.#close(db)\n }\n }\n\n /**\n * Closes the database connection and cleans up the internal state.\n */\n async #close(db: DatabaseSync) {\n // the revalidation of stale entries might not yet be completed\n // so in case we have a pending promise for that, we need to wait\n await this.#pUpdateExpired\n // close db connection\n db.exec('PRAGMA optimize')\n db.close()\n // clean up internal state\n this.#expired.clear()\n this.#pUpdateExpired = undefined\n // TODO: at this point we could spawn a deref process to\n // remove entries with expired ttl values and vaccum the db\n }\n\n /**\n * Outputs the current in-memory cache as a JSON object.\n */\n toJSON() {\n const obj: Record<DepID, PackageReportData> = {}\n for (const [key, value] of this.dump()) {\n obj[key] = value.value\n }\n return obj\n }\n}\n"]}
@@ -1,3 +0,0 @@
1
- {
2
- "type": "module"
3
- }
@@ -1 +0,0 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAA;AAC3C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AAE7C;;GAEG;AACH,MAAM,MAAM,6BAA6B,GAAG;IAC1C;;;OAGG;IACH,KAAK,EAAE,QAAQ,EAAE,CAAA;CAClB,CAAA;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,GAAG,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,iBAAiB,GAAG,SAAS,CAAA;IACpD,GAAG,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,iBAAiB,KAAK,IAAI,CAAA;IACpD,MAAM,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAA;IAC9B,GAAG,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,OAAO,CAAA;IAC9B,KAAK,EAAE,MAAM,IAAI,CAAA;IACjB,EAAE,CAAC,EAAE,OAAO,CAAA;CACb;AAED,eAAO,MAAM,qBAAqB,MAC7B,OAAO,KACT,CAAC,IAAI,mBAOM,CAAA;AAEd,eAAO,MAAM,qBAAqB,MAC7B,OAAO,KACT,mBAKF,CAAA;AAED;;GAEG;AACH,MAAM,MAAM,iBAAiB,GAAG;IAC9B,WAAW,EAAE,MAAM,CAAA;IACnB,KAAK,CAAC,EAAE,OAAO,MAAM,EAAE,CAAA;IACvB,IAAI,CAAC,EAAE;QAAE,EAAE,EAAE,OAAO,MAAM,EAAE,CAAA;KAAE,EAAE,CAAA;CACjC,CAAA;AAED;;GAEG;AACH,MAAM,MAAM,YAAY,GAAG;IACzB,GAAG,EAAE,MAAM,CAAA;IACX,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,UAAU,CAAA;IAChD,QAAQ,EAAE,MAAM,CAAA;IAChB,KAAK,CAAC,EAAE,iBAAiB,CAAA;CAC1B,CAAA;AAED;;GAEG;AACH,MAAM,MAAM,YAAY,GAAG;IACzB;;OAEG;IACH,OAAO,EAAE,MAAM,CAAA;IACf;;OAEG;IACH,OAAO,EAAE,MAAM,CAAA;IACf;;OAEG;IACH,WAAW,EAAE,MAAM,CAAA;IACnB;;OAEG;IACH,OAAO,EAAE,MAAM,CAAA;IACf;;OAEG;IACH,WAAW,EAAE,MAAM,CAAA;IACnB;;OAEG;IACH,aAAa,EAAE,MAAM,CAAA;CACtB,CAAA;AAED;;GAEG;AACH,MAAM,MAAM,iBAAiB,GAAG;IAC9B,EAAE,EAAE,MAAM,CAAA;IACV,MAAM,EAAE,MAAM,EAAE,CAAA;IAChB,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,KAAK,CAAA;IACX,SAAS,CAAC,EAAE,IAAI,MAAM,EAAE,CAAA;IACxB,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,CAAA;IACf,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,YAAY,EAAE,CAAA;IACtB,KAAK,EAAE,YAAY,CAAA;CACpB,CAAA;AAED,eAAO,MAAM,mBAAmB,MAC3B,OAAO,KACT,CAAC,IAAI,iBASU,CAAA;AAElB,eAAO,MAAM,mBAAmB,MAC3B,OAAO,KACT,iBAKF,CAAA"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAA;AA2B3C,MAAM,CAAC,MAAM,qBAAqB,GAAG,CACnC,CAAU,EACgB,EAAE,CAC5B,OAAO,CAAC,KAAK,QAAQ;IACrB,CAAC,IAAI,IAAI;IACT,KAAK,IAAI,CAAC;IACV,KAAK,IAAI,CAAC;IACV,QAAQ,IAAI,CAAC;IACb,KAAK,IAAI,CAAC;IACV,OAAO,IAAI,CAAC,CAAA;AAEd,MAAM,CAAC,MAAM,qBAAqB,GAAG,CACnC,CAAU,EACW,EAAE;IACvB,IAAI,CAAC,qBAAqB,CAAC,CAAC,CAAC,EAAE,CAAC;QAC9B,MAAM,KAAK,CAAC,+BAA+B,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAA;IAC5D,CAAC;IACD,OAAO,CAAC,CAAA;AACV,CAAC,CAAA;AAoED,MAAM,CAAC,MAAM,mBAAmB,GAAG,CACjC,CAAU,EACc,EAAE,CAC1B,OAAO,CAAC,KAAK,QAAQ;IACrB,CAAC,IAAI,IAAI;IACT,IAAI,IAAI,CAAC;IACT,MAAM,IAAI,CAAC;IACX,MAAM,IAAI,CAAC;IACX,SAAS,IAAI,CAAC;IACd,QAAQ,IAAI,CAAC;IACb,OAAO,IAAI,CAAC;IACZ,CAAC,CAAC,IAAI,KAAK,KAAK,CAAA;AAElB,MAAM,CAAC,MAAM,mBAAmB,GAAG,CACjC,CAAU,EACS,EAAE;IACrB,IAAI,CAAC,mBAAmB,CAAC,CAAC,CAAC,EAAE,CAAC;QAC5B,MAAM,KAAK,CAAC,6BAA6B,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAA;IAC1D,CAAC;IACD,OAAO,CAAC,CAAA;AACV,CAAC,CAAA","sourcesContent":["import { error } from '@vltpkg/error-cause'\nimport type { DepID } from '@vltpkg/dep-id'\nimport type { NodeLike } from '@vltpkg/types'\n\n/**\n * Parameter options for initializing a security archive.\n */\nexport type SecurityArchiveRefreshOptions = {\n /**\n * A @link{GraphLike} instance to find what packages the\n * security archive should have.\n */\n nodes: NodeLike[]\n}\n\n/**\n * An interface for interacting with a security archive.\n */\nexport interface SecurityArchiveLike {\n get: (depId: DepID) => PackageReportData | undefined\n set: (depId: DepID, data: PackageReportData) => void\n delete: (depId: DepID) => void\n has: (depId: DepID) => boolean\n clear: () => void\n ok?: boolean\n}\n\nexport const isSecurityArchiveLike = (\n o: unknown,\n): o is SecurityArchiveLike =>\n typeof o === 'object' &&\n o != null &&\n 'get' in o &&\n 'set' in o &&\n 'delete' in o &&\n 'has' in o &&\n 'clear' in o\n\nexport const asSecurityArchiveLike = (\n o: unknown,\n): SecurityArchiveLike => {\n if (!isSecurityArchiveLike(o)) {\n throw error('Invalid security archive like', { found: o })\n }\n return o\n}\n\n/**\n * Package alert extra information.\n */\nexport type PackageAlertProps = {\n lastPublish: string\n cveId?: `CVE-${string}`\n cwes?: { id: `CWE-${string}` }[]\n}\n\n/**\n * A known alert for a given package.\n */\nexport type PackageAlert = {\n key: string\n type: string\n severity: 'low' | 'medium' | 'high' | 'critical'\n category: string\n props?: PackageAlertProps\n}\n\n/**\n * The scores for a given package\n */\nexport type PackageScore = {\n /**\n * The average of all score factors. (0-1)\n */\n overall: number\n /**\n * Score factors relating to package licensing (0-1)\n */\n license: number\n /**\n * Score factors relating to package maintenance (0-1)\n */\n maintenance: number\n /**\n * Score factors relating to code quality (0-1)\n */\n quality: number\n /**\n * Score factors relating to supply chain security (0-1)\n */\n supplyChain: number\n /**\n * Score factors relating to package vulnerabilities (0-1)\n */\n vulnerability: number\n}\n\n/**\n * The report data for a given package.\n */\nexport type PackageReportData = {\n id: string\n author: string[]\n size: number\n type: 'npm'\n namespace?: `@${string}`\n name: string\n version: string\n license: string\n alerts: PackageAlert[]\n score: PackageScore\n}\n\nexport const isPackageReportData = (\n o: unknown,\n): o is PackageReportData =>\n typeof o === 'object' &&\n o != null &&\n 'id' in o &&\n 'type' in o &&\n 'name' in o &&\n 'version' in o &&\n 'alerts' in o &&\n 'score' in o &&\n o.type === 'npm'\n\nexport const asPackageReportData = (\n o: unknown,\n): PackageReportData => {\n if (!isPackageReportData(o)) {\n throw error('Invalid package report data', { found: o })\n }\n return o\n}\n"]}