@vltpkg/security-archive 0.0.0-17 → 0.0.0-18
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/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +23 -20
- package/dist/esm/index.js.map +1 -1
- package/package.json +7 -7
package/dist/esm/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
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;AAG3C,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;AAyBD,eAAO,MAAQ,OAAO,QAKrB,CAAA;
|
|
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;AAG3C,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;AAyBD,eAAO,MAAQ,OAAO,QAKrB,CAAA;AAiBD;;;;;;;GAOG;AACH,qBAAa,eACX,SAAQ,QAAQ,CAAC,KAAK,EAAE,iBAAiB,CACzC,YAAW,mBAAmB;;IAO9B;;;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;IA+PhD;;;;;;OAMG;IACG,OAAO,CAAC,EACZ,KAAK,EACL,WAAW,GACZ,EAAE,6BAA6B;IA+ChC;;OAEG;IACH,MAAM;CAOP"}
|
package/dist/esm/index.js
CHANGED
|
@@ -4,7 +4,7 @@ import { dirname } from 'node:path';
|
|
|
4
4
|
import { LRUCache } from 'lru-cache';
|
|
5
5
|
import pRetry, { AbortError } from 'p-retry';
|
|
6
6
|
import { loadPackageJson } from 'package-json-from-dist';
|
|
7
|
-
import { asDepID, splitDepID,
|
|
7
|
+
import { asDepID, splitDepID, baseDepID } from '@vltpkg/dep-id';
|
|
8
8
|
import { error } from '@vltpkg/error-cause';
|
|
9
9
|
import { XDG } from '@vltpkg/xdg';
|
|
10
10
|
import { asPackageReportData } from "./types.js";
|
|
@@ -29,6 +29,16 @@ const usesTargetRegistry = (depID, specOptions) => {
|
|
|
29
29
|
};
|
|
30
30
|
// Loads the version number to be used in the User-Agent header
|
|
31
31
|
export const { version } = loadPackageJson(import.meta.filename, process.env.__VLT_INTERNAL_CLI_PACKAGE_JSON);
|
|
32
|
+
/**
|
|
33
|
+
* Retrieves a node from the graph using its name and version.
|
|
34
|
+
*/
|
|
35
|
+
const retrieveNodeFromGraph = (graph, name, version) => {
|
|
36
|
+
for (const node of graph.nodesByName.get(name) ?? []) {
|
|
37
|
+
if (node.version === version) {
|
|
38
|
+
return node;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
};
|
|
32
42
|
/**
|
|
33
43
|
* A database of security information for given packages in a graph.
|
|
34
44
|
*
|
|
@@ -101,7 +111,7 @@ export class SecurityArchive extends LRUCache {
|
|
|
101
111
|
#loadItemsFromDatabase(db, graph) {
|
|
102
112
|
const depIDs = [];
|
|
103
113
|
for (const node of graph.nodes.values()) {
|
|
104
|
-
depIDs.push(`'${node.id}'`);
|
|
114
|
+
depIDs.push(`'${baseDepID(node.id)}'`);
|
|
105
115
|
}
|
|
106
116
|
// retrieves from the db packages using their dep-id reference
|
|
107
117
|
// and only include entries that have a valid TTL value
|
|
@@ -113,7 +123,7 @@ export class SecurityArchive extends LRUCache {
|
|
|
113
123
|
this.#expired.clear();
|
|
114
124
|
for (const entry of dbRead.all()) {
|
|
115
125
|
const { depID, now, report, start, ttl } = entry;
|
|
116
|
-
const id = asDepID(depID);
|
|
126
|
+
const id = baseDepID(asDepID(depID));
|
|
117
127
|
try {
|
|
118
128
|
this.set(id, asPackageReportData(JSON.parse(report)), {
|
|
119
129
|
ttl,
|
|
@@ -141,7 +151,7 @@ export class SecurityArchive extends LRUCache {
|
|
|
141
151
|
async #updateExpired(db, graph) {
|
|
142
152
|
const expiredQueue = new Set();
|
|
143
153
|
for (const depID of this.#expired) {
|
|
144
|
-
const node = graph.nodes.get(depID);
|
|
154
|
+
const node = graph.nodes.get(baseDepID(depID));
|
|
145
155
|
/* c8 ignore next */
|
|
146
156
|
if (!node)
|
|
147
157
|
continue;
|
|
@@ -161,12 +171,13 @@ export class SecurityArchive extends LRUCache {
|
|
|
161
171
|
const queue = new Set();
|
|
162
172
|
const nodes = graph.nodes.values();
|
|
163
173
|
for (const node of nodes) {
|
|
174
|
+
const normalizedId = baseDepID(node.id);
|
|
164
175
|
// only queue up valid public registry
|
|
165
176
|
// references that are missing from the archive
|
|
166
177
|
// also skips any pkg marked as expired
|
|
167
178
|
if (usesTargetRegistry(node.id, specOptions) &&
|
|
168
|
-
!this.has(
|
|
169
|
-
!this.#expired.has(
|
|
179
|
+
!this.has(normalizedId) &&
|
|
180
|
+
!this.#expired.has(normalizedId)) {
|
|
170
181
|
const purl = `pkg:npm/${node.name}@${node.version}`;
|
|
171
182
|
queue.add({ purl });
|
|
172
183
|
}
|
|
@@ -213,19 +224,11 @@ export class SecurityArchive extends LRUCache {
|
|
|
213
224
|
continue;
|
|
214
225
|
const data = JSON.parse(line + '}');
|
|
215
226
|
const scope = data.namespace ? `${data.namespace}/` : '';
|
|
216
|
-
const
|
|
217
|
-
|
|
218
|
-
'',
|
|
219
|
-
`${scope}${data.name}@${data.version}`,
|
|
220
|
-
]);
|
|
221
|
-
const aliasedDepID = joinDepIDTuple([
|
|
222
|
-
'registry',
|
|
223
|
-
'npm',
|
|
224
|
-
`${scope}${data.name}@${data.version}`,
|
|
225
|
-
]);
|
|
226
|
-
const node = graph.nodes.get(depID) ?? graph.nodes.get(aliasedDepID);
|
|
227
|
+
const name = `${scope}${data.name}`;
|
|
228
|
+
const node = retrieveNodeFromGraph(graph, name, data.version);
|
|
227
229
|
if (node) {
|
|
228
|
-
|
|
230
|
+
const normalizedId = baseDepID(node.id);
|
|
231
|
+
fetchedDepIDs.add(baseDepID(node.id));
|
|
229
232
|
// Calculate average score from all score components
|
|
230
233
|
const scoreComponents = [
|
|
231
234
|
data.score.license,
|
|
@@ -241,7 +244,7 @@ export class SecurityArchive extends LRUCache {
|
|
|
241
244
|
...data.score,
|
|
242
245
|
overall: newAverageScore,
|
|
243
246
|
};
|
|
244
|
-
this.set(
|
|
247
|
+
this.set(normalizedId, asPackageReportData({
|
|
245
248
|
...data,
|
|
246
249
|
score: scoreWithNewAverage,
|
|
247
250
|
}));
|
|
@@ -282,7 +285,7 @@ export class SecurityArchive extends LRUCache {
|
|
|
282
285
|
#validateReportData(graph, specOptions) {
|
|
283
286
|
for (const node of graph.nodes.values()) {
|
|
284
287
|
if (usesTargetRegistry(node.id, specOptions)) {
|
|
285
|
-
if (!this.has(node.id)) {
|
|
288
|
+
if (!this.has(baseDepID(node.id))) {
|
|
286
289
|
this.ok = false;
|
|
287
290
|
return;
|
|
288
291
|
}
|
package/dist/esm/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
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, joinDepIDTuple } 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 { GraphLike } from '@vltpkg/graph'\nimport type { SpecOptions } from '@vltpkg/spec'\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 = (\n depID: DepID,\n specOptions: SpecOptions,\n): boolean => {\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 in a graph.\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\n /**\n * True if the refresh process was successful and report data\n * is available for all public registry packages in the graph.\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 * 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, graph: GraphLike): void {\n const depIDs: string[] = []\n for (const node of graph.nodes.values()) {\n depIDs.push(`'${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 = 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, graph)\n }\n\n /**\n * Updates the database with renewed entries for expired packages.\n */\n async #updateExpired(\n db: DatabaseSync,\n graph: GraphLike,\n ): Promise<void> {\n const expiredQueue = new Set<Record<'purl', string>>()\n for (const depID of this.#expired) {\n const node = graph.nodes.get(depID)\n /* c8 ignore next */\n if (!node) continue\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, graph)\n this.#storeNewItemsToDatabase(db, ids)\n }\n }\n\n /**\n * Queues up all required packages that are missing from the archive.\n */\n #queueUpRequiredPackages(\n graph: GraphLike,\n specOptions: SpecOptions,\n ): Set<Record<'purl', string>> {\n const queue = new Set<Record<'purl', string>>()\n const nodes = graph.nodes.values()\n for (const node of nodes) {\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.id, specOptions) &&\n !this.has(node.id) &&\n !this.#expired.has(node.id)\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, graph: GraphLike): 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 depID = joinDepIDTuple([\n 'registry',\n '',\n `${scope}${data.name}@${data.version}`,\n ])\n const aliasedDepID = joinDepIDTuple([\n 'registry',\n 'npm',\n `${scope}${data.name}@${data.version}`,\n ])\n const node =\n graph.nodes.get(depID) ?? graph.nodes.get(aliasedDepID)\n if (node) {\n fetchedDepIDs.add(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 node.id,\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 graph\n * have a valid report data in the current in-memory cache.\n */\n #validateReportData(graph: GraphLike, specOptions: SpecOptions) {\n for (const node of graph.nodes.values()) {\n if (usesTargetRegistry(node.id, specOptions)) {\n if (!this.has(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 a {@link GraphLike} instance,\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({\n graph,\n specOptions,\n }: SecurityArchiveRefreshOptions) {\n // should start by clearing the current in-memory cache\n this.clear()\n\n const db = this.#openDatabase()\n\n try {\n this.#loadItemsFromDatabase(db, graph)\n\n const queue = this.#queueUpRequiredPackages(graph, specOptions)\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, graph)\n this.#storeNewItemsToDatabase(db, ids)\n }\n\n // validates the refresh process was successful\n this.#validateReportData(graph, specOptions)\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
|
+
{"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 { GraphLike, NodeLike } from '@vltpkg/graph'\nimport type { SpecOptions } from '@vltpkg/spec'\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 = (\n depID: DepID,\n specOptions: SpecOptions,\n): boolean => {\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 * Retrieves a node from the graph using its name and version.\n */\nconst retrieveNodeFromGraph = (\n graph: GraphLike,\n name: string,\n version: string,\n): NodeLike | undefined => {\n for (const node of graph.nodesByName.get(name) ?? []) {\n if (node.version === version) {\n return node\n }\n }\n}\n\n/**\n * A database of security information for given packages in a graph.\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\n /**\n * True if the refresh process was successful and report data\n * is available for all public registry packages in the graph.\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 * 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, graph: GraphLike): void {\n const depIDs: string[] = []\n for (const node of graph.nodes.values()) {\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, graph)\n }\n\n /**\n * Updates the database with renewed entries for expired packages.\n */\n async #updateExpired(\n db: DatabaseSync,\n graph: GraphLike,\n ): Promise<void> {\n const expiredQueue = new Set<Record<'purl', string>>()\n for (const depID of this.#expired) {\n const node = graph.nodes.get(baseDepID(depID))\n\n /* c8 ignore next */\n if (!node) continue\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, graph)\n this.#storeNewItemsToDatabase(db, ids)\n }\n }\n\n /**\n * Queues up all required packages that are missing from the archive.\n */\n #queueUpRequiredPackages(\n graph: GraphLike,\n specOptions: SpecOptions,\n ): Set<Record<'purl', string>> {\n const queue = new Set<Record<'purl', string>>()\n const nodes = graph.nodes.values()\n for (const node of nodes) {\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.id, specOptions) &&\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, graph: GraphLike): 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 = retrieveNodeFromGraph(graph, 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 graph\n * have a valid report data in the current in-memory cache.\n */\n #validateReportData(graph: GraphLike, specOptions: SpecOptions) {\n for (const node of graph.nodes.values()) {\n if (usesTargetRegistry(node.id, specOptions)) {\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 a {@link GraphLike} instance,\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({\n graph,\n specOptions,\n }: SecurityArchiveRefreshOptions) {\n // should start by clearing the current in-memory cache\n this.clear()\n\n const db = this.#openDatabase()\n\n try {\n this.#loadItemsFromDatabase(db, graph)\n\n const queue = this.#queueUpRequiredPackages(graph, specOptions)\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, graph)\n this.#storeNewItemsToDatabase(db, ids)\n }\n\n // validates the refresh process was successful\n this.#validateReportData(graph, specOptions)\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"]}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vltpkg/security-archive",
|
|
3
3
|
"description": "A database of security information of packages",
|
|
4
|
-
"version": "0.0.0-
|
|
4
|
+
"version": "0.0.0-18",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
7
|
"url": "git+https://github.com/vltpkg/vltpkg.git",
|
|
@@ -23,12 +23,12 @@
|
|
|
23
23
|
"lru-cache": "^11.1.0",
|
|
24
24
|
"p-retry": "^6.2.1",
|
|
25
25
|
"package-json-from-dist": "^1.0.1",
|
|
26
|
-
"@vltpkg/dep-id": "0.0.0-
|
|
27
|
-
"@vltpkg/error-cause": "0.0.0-
|
|
28
|
-
"@vltpkg/graph": "0.0.0-
|
|
29
|
-
"@vltpkg/types": "0.0.0-
|
|
30
|
-
"@vltpkg/
|
|
31
|
-
"@vltpkg/
|
|
26
|
+
"@vltpkg/dep-id": "0.0.0-18",
|
|
27
|
+
"@vltpkg/error-cause": "0.0.0-18",
|
|
28
|
+
"@vltpkg/graph": "0.0.0-18",
|
|
29
|
+
"@vltpkg/types": "0.0.0-18",
|
|
30
|
+
"@vltpkg/xdg": "0.0.0-18",
|
|
31
|
+
"@vltpkg/spec": "0.0.0-18"
|
|
32
32
|
},
|
|
33
33
|
"devDependencies": {
|
|
34
34
|
"@eslint/js": "^9.28.0",
|