@vltpkg/query 1.0.0-rc.31 → 1.0.0-rc.32
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/pseudo/cve.d.ts +6 -2
- package/dist/pseudo/cve.js +29 -11
- package/dist/pseudo/cwe.d.ts +6 -2
- package/dist/pseudo/cwe.js +29 -10
- package/dist/pseudo/dist.d.ts +22 -0
- package/dist/pseudo/dist.js +110 -0
- package/dist/pseudo/semver.d.ts +3 -1
- package/dist/pseudo/semver.js +43 -6
- package/dist/pseudo/vulnerable.d.ts +8 -0
- package/dist/pseudo/vulnerable.js +17 -0
- package/dist/pseudo.js +5 -0
- package/package.json +8 -8
package/dist/pseudo/cve.d.ts
CHANGED
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
import type { ParserState } from '../types.ts';
|
|
2
2
|
import type { PostcssNode } from '@vltpkg/dss-parser';
|
|
3
3
|
export type CveInternals = {
|
|
4
|
-
cveId: string;
|
|
4
|
+
cveId: string | undefined;
|
|
5
5
|
};
|
|
6
6
|
export declare const parseInternals: (nodes: PostcssNode[]) => CveInternals;
|
|
7
7
|
/**
|
|
8
|
-
* Filters out any node that does not have a CVE alert
|
|
8
|
+
* Filters out any node that does not have a CVE alert.
|
|
9
|
+
*
|
|
10
|
+
* Usage:
|
|
11
|
+
* - :cve - matches any package with at least one CVE alert
|
|
12
|
+
* - :cve(CVE-2023-1234) - matches only the specific CVE ID
|
|
9
13
|
*/
|
|
10
14
|
export declare const cve: (state: ParserState) => Promise<ParserState & {
|
|
11
15
|
securityArchive: NonNullable<ParserState["securityArchive"]>;
|
package/dist/pseudo/cve.js
CHANGED
|
@@ -2,23 +2,35 @@ import { error } from '@vltpkg/error-cause';
|
|
|
2
2
|
import { asPostcssNodeWithChildren, asStringNode, asTagNode, isStringNode, isTagNode, } from '@vltpkg/dss-parser';
|
|
3
3
|
import { assertSecurityArchive, removeDanglingEdges, removeNode, removeQuotes, } from "./helpers.js";
|
|
4
4
|
export const parseInternals = (nodes) => {
|
|
5
|
+
if (!nodes[0]) {
|
|
6
|
+
return { cveId: undefined };
|
|
7
|
+
}
|
|
8
|
+
const selectorNode = asPostcssNodeWithChildren(nodes[0]);
|
|
9
|
+
if (!selectorNode.nodes[0]) {
|
|
10
|
+
return { cveId: undefined };
|
|
11
|
+
}
|
|
5
12
|
let cveId = '';
|
|
6
|
-
if (isStringNode(
|
|
7
|
-
cveId = removeQuotes(asStringNode(
|
|
8
|
-
.value);
|
|
13
|
+
if (isStringNode(selectorNode.nodes[0])) {
|
|
14
|
+
cveId = removeQuotes(asStringNode(selectorNode.nodes[0]).value);
|
|
9
15
|
}
|
|
10
|
-
else if (isTagNode(
|
|
11
|
-
cveId = asTagNode(
|
|
16
|
+
else if (isTagNode(selectorNode.nodes[0])) {
|
|
17
|
+
cveId = asTagNode(selectorNode.nodes[0]).value;
|
|
12
18
|
}
|
|
19
|
+
/* c8 ignore start - unreachable via normal parser */
|
|
13
20
|
if (!cveId) {
|
|
14
21
|
throw error('Expected a CVE ID', {
|
|
15
|
-
found:
|
|
22
|
+
found: selectorNode.nodes[0],
|
|
16
23
|
});
|
|
17
24
|
}
|
|
25
|
+
/* c8 ignore stop */
|
|
18
26
|
return { cveId };
|
|
19
27
|
};
|
|
20
28
|
/**
|
|
21
|
-
* Filters out any node that does not have a CVE alert
|
|
29
|
+
* Filters out any node that does not have a CVE alert.
|
|
30
|
+
*
|
|
31
|
+
* Usage:
|
|
32
|
+
* - :cve - matches any package with at least one CVE alert
|
|
33
|
+
* - :cve(CVE-2023-1234) - matches only the specific CVE ID
|
|
22
34
|
*/
|
|
23
35
|
export const cve = async (state) => {
|
|
24
36
|
assertSecurityArchive(state, 'cve');
|
|
@@ -26,14 +38,20 @@ export const cve = async (state) => {
|
|
|
26
38
|
try {
|
|
27
39
|
internals = parseInternals(asPostcssNodeWithChildren(state.current).nodes);
|
|
28
40
|
}
|
|
29
|
-
catch (err) {
|
|
41
|
+
catch (err) /* c8 ignore start */ {
|
|
30
42
|
throw error('Failed to parse :cve selector', { cause: err });
|
|
31
|
-
}
|
|
43
|
+
} /* c8 ignore stop */
|
|
32
44
|
const { cveId } = internals;
|
|
33
45
|
for (const node of state.partial.nodes) {
|
|
34
46
|
const report = state.securityArchive.get(node.id);
|
|
35
|
-
|
|
36
|
-
|
|
47
|
+
let exclude;
|
|
48
|
+
if (cveId === undefined) {
|
|
49
|
+
exclude = !report?.alerts.some(alert => alert.props?.cveId);
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
exclude = !report?.alerts.some(alert => alert.props?.cveId?.trim().toLowerCase() ===
|
|
53
|
+
cveId.trim().toLowerCase());
|
|
54
|
+
}
|
|
37
55
|
if (exclude) {
|
|
38
56
|
removeNode(state, node);
|
|
39
57
|
}
|
package/dist/pseudo/cwe.d.ts
CHANGED
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
import type { ParserState } from '../types.ts';
|
|
2
2
|
import type { PostcssNode } from '@vltpkg/dss-parser';
|
|
3
3
|
export type CweInternals = {
|
|
4
|
-
cweId: string;
|
|
4
|
+
cweId: string | undefined;
|
|
5
5
|
};
|
|
6
6
|
export declare const parseInternals: (nodes: PostcssNode[]) => CweInternals;
|
|
7
7
|
/**
|
|
8
|
-
* Filters out any node that does not have a CWE alert
|
|
8
|
+
* Filters out any node that does not have a CWE alert.
|
|
9
|
+
*
|
|
10
|
+
* Usage:
|
|
11
|
+
* - :cwe - matches any package with at least one CWE alert
|
|
12
|
+
* - :cwe(CWE-79) - matches only the specific CWE ID
|
|
9
13
|
*/
|
|
10
14
|
export declare const cwe: (state: ParserState) => Promise<ParserState & {
|
|
11
15
|
securityArchive: NonNullable<ParserState["securityArchive"]>;
|
package/dist/pseudo/cwe.js
CHANGED
|
@@ -2,23 +2,35 @@ import { error } from '@vltpkg/error-cause';
|
|
|
2
2
|
import { asPostcssNodeWithChildren, asStringNode, asTagNode, isStringNode, isTagNode, } from '@vltpkg/dss-parser';
|
|
3
3
|
import { assertSecurityArchive, removeDanglingEdges, removeNode, removeQuotes, } from "./helpers.js";
|
|
4
4
|
export const parseInternals = (nodes) => {
|
|
5
|
+
if (!nodes[0]) {
|
|
6
|
+
return { cweId: undefined };
|
|
7
|
+
}
|
|
8
|
+
const selectorNode = asPostcssNodeWithChildren(nodes[0]);
|
|
9
|
+
if (!selectorNode.nodes[0]) {
|
|
10
|
+
return { cweId: undefined };
|
|
11
|
+
}
|
|
5
12
|
let cweId = '';
|
|
6
|
-
if (isStringNode(
|
|
7
|
-
cweId = removeQuotes(asStringNode(
|
|
8
|
-
.value);
|
|
13
|
+
if (isStringNode(selectorNode.nodes[0])) {
|
|
14
|
+
cweId = removeQuotes(asStringNode(selectorNode.nodes[0]).value);
|
|
9
15
|
}
|
|
10
|
-
else if (isTagNode(
|
|
11
|
-
cweId = asTagNode(
|
|
16
|
+
else if (isTagNode(selectorNode.nodes[0])) {
|
|
17
|
+
cweId = asTagNode(selectorNode.nodes[0]).value;
|
|
12
18
|
}
|
|
19
|
+
/* c8 ignore start - unreachable via normal parser */
|
|
13
20
|
if (!cweId) {
|
|
14
21
|
throw error('Expected a CWE ID', {
|
|
15
|
-
found:
|
|
22
|
+
found: selectorNode.nodes[0],
|
|
16
23
|
});
|
|
17
24
|
}
|
|
25
|
+
/* c8 ignore stop */
|
|
18
26
|
return { cweId };
|
|
19
27
|
};
|
|
20
28
|
/**
|
|
21
|
-
* Filters out any node that does not have a CWE alert
|
|
29
|
+
* Filters out any node that does not have a CWE alert.
|
|
30
|
+
*
|
|
31
|
+
* Usage:
|
|
32
|
+
* - :cwe - matches any package with at least one CWE alert
|
|
33
|
+
* - :cwe(CWE-79) - matches only the specific CWE ID
|
|
22
34
|
*/
|
|
23
35
|
export const cwe = async (state) => {
|
|
24
36
|
assertSecurityArchive(state, 'cwe');
|
|
@@ -26,13 +38,20 @@ export const cwe = async (state) => {
|
|
|
26
38
|
try {
|
|
27
39
|
internals = parseInternals(asPostcssNodeWithChildren(state.current).nodes);
|
|
28
40
|
}
|
|
29
|
-
catch (err) {
|
|
41
|
+
catch (err) /* c8 ignore start */ {
|
|
30
42
|
throw error('Failed to parse :cwe selector', { cause: err });
|
|
31
|
-
}
|
|
43
|
+
} /* c8 ignore stop */
|
|
32
44
|
const { cweId } = internals;
|
|
33
45
|
for (const node of state.partial.nodes) {
|
|
34
46
|
const report = state.securityArchive.get(node.id);
|
|
35
|
-
|
|
47
|
+
let exclude;
|
|
48
|
+
if (cweId === undefined) {
|
|
49
|
+
exclude = !report?.alerts.some(alert => alert.props?.cwes && alert.props.cwes.length > 0);
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
exclude = !report?.alerts.some(alert => alert.props?.cwes?.some(cwe => cwe.id.trim().toLowerCase() ===
|
|
53
|
+
cweId.trim().toLowerCase()));
|
|
54
|
+
}
|
|
36
55
|
if (exclude) {
|
|
37
56
|
removeNode(state, node);
|
|
38
57
|
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { NodeLike } from '@vltpkg/types';
|
|
2
|
+
import type { ParserState } from '../types.ts';
|
|
3
|
+
/**
|
|
4
|
+
* Fetches the dist-tags of a package from the registry.
|
|
5
|
+
*/
|
|
6
|
+
export declare const retrieveDistTags: (node: NodeLike, signal?: AbortSignal) => Promise<Record<string, string>>;
|
|
7
|
+
/**
|
|
8
|
+
* Checks whether a node's installed version matches the version
|
|
9
|
+
* associated with the given dist-tag. Returns the node if it should
|
|
10
|
+
* be removed (does NOT match), or undefined if it matches.
|
|
11
|
+
*/
|
|
12
|
+
export declare const queueNode: (state: ParserState, node: NodeLike, tagName: string) => Promise<NodeLike | undefined>;
|
|
13
|
+
/**
|
|
14
|
+
* :dist(tag) Pseudo-Selector, matches only nodes whose installed
|
|
15
|
+
* version corresponds to the given dist-tag in the registry.
|
|
16
|
+
*
|
|
17
|
+
* Examples:
|
|
18
|
+
* - :dist(latest) — matches packages at the `latest` dist-tag version
|
|
19
|
+
* - :dist(nightly) — matches packages at the `nightly` dist-tag version
|
|
20
|
+
* - :not(:dist(nightly)) — excludes nightly-tagged versions
|
|
21
|
+
*/
|
|
22
|
+
export declare const dist: (state: ParserState) => Promise<ParserState>;
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import pRetry, { AbortError } from 'p-retry';
|
|
2
|
+
import { hydrate, splitDepID } from '@vltpkg/dep-id/browser';
|
|
3
|
+
import { error } from '@vltpkg/error-cause';
|
|
4
|
+
import { asPostcssNodeWithChildren, asTagNode, asStringNode, isTagNode, } from '@vltpkg/dss-parser';
|
|
5
|
+
import { removeDanglingEdges, removeNode, removeQuotes, } from "./helpers.js";
|
|
6
|
+
/**
|
|
7
|
+
* Fetches the dist-tags of a package from the registry.
|
|
8
|
+
*/
|
|
9
|
+
export const retrieveDistTags = async (node, signal) => {
|
|
10
|
+
const spec = hydrate(node.id, String(node.name), node.options);
|
|
11
|
+
if (!spec.registry || !node.name) {
|
|
12
|
+
return {};
|
|
13
|
+
}
|
|
14
|
+
const url = new URL(spec.registry);
|
|
15
|
+
url.pathname = `/${node.name}`;
|
|
16
|
+
const response = await fetch(String(url), {
|
|
17
|
+
headers: {
|
|
18
|
+
Accept: 'application/vnd.npm.install-v1+json',
|
|
19
|
+
},
|
|
20
|
+
signal,
|
|
21
|
+
});
|
|
22
|
+
if (response.status === 404) {
|
|
23
|
+
throw new AbortError('Missing API');
|
|
24
|
+
}
|
|
25
|
+
if (!response.ok) {
|
|
26
|
+
throw error('Failed to fetch packument', {
|
|
27
|
+
name: node.name,
|
|
28
|
+
spec,
|
|
29
|
+
response,
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
const packument = (await response.json());
|
|
33
|
+
return packument['dist-tags'];
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* Checks whether a node's installed version matches the version
|
|
37
|
+
* associated with the given dist-tag. Returns the node if it should
|
|
38
|
+
* be removed (does NOT match), or undefined if it matches.
|
|
39
|
+
*/
|
|
40
|
+
export const queueNode = async (state, node, tagName) => {
|
|
41
|
+
if (!node.name || !node.version) {
|
|
42
|
+
return node;
|
|
43
|
+
}
|
|
44
|
+
let distTags;
|
|
45
|
+
try {
|
|
46
|
+
distTags = await pRetry(() => retrieveDistTags(node, state.signal), {
|
|
47
|
+
retries: state.retries,
|
|
48
|
+
signal: state.signal,
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
catch (err) {
|
|
52
|
+
// eslint-disable-next-line no-console
|
|
53
|
+
console.warn(error('Could not retrieve dist-tags', {
|
|
54
|
+
name: node.name,
|
|
55
|
+
cause: err,
|
|
56
|
+
}));
|
|
57
|
+
return node;
|
|
58
|
+
}
|
|
59
|
+
const tagVersion = distTags[tagName];
|
|
60
|
+
if (tagVersion !== node.version) {
|
|
61
|
+
return node;
|
|
62
|
+
}
|
|
63
|
+
return undefined;
|
|
64
|
+
};
|
|
65
|
+
/**
|
|
66
|
+
* :dist(tag) Pseudo-Selector, matches only nodes whose installed
|
|
67
|
+
* version corresponds to the given dist-tag in the registry.
|
|
68
|
+
*
|
|
69
|
+
* Examples:
|
|
70
|
+
* - :dist(latest) — matches packages at the `latest` dist-tag version
|
|
71
|
+
* - :dist(nightly) — matches packages at the `nightly` dist-tag version
|
|
72
|
+
* - :not(:dist(nightly)) — excludes nightly-tagged versions
|
|
73
|
+
*/
|
|
74
|
+
export const dist = async (state) => {
|
|
75
|
+
const top = asPostcssNodeWithChildren(state.current);
|
|
76
|
+
const selector = asPostcssNodeWithChildren(top.nodes[0]);
|
|
77
|
+
const firstChild = selector.nodes[0];
|
|
78
|
+
let tagName;
|
|
79
|
+
try {
|
|
80
|
+
tagName = removeQuotes(asStringNode(firstChild).value);
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
if (isTagNode(firstChild)) {
|
|
84
|
+
tagName = asTagNode(firstChild).value;
|
|
85
|
+
/* c8 ignore start */
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
throw error('Failed to parse :dist selector', {
|
|
89
|
+
found: firstChild,
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
/* c8 ignore stop */
|
|
93
|
+
}
|
|
94
|
+
const queue = [];
|
|
95
|
+
for (const node of state.partial.nodes) {
|
|
96
|
+
if (splitDepID(node.id)[0] !== 'registry') {
|
|
97
|
+
removeNode(state, node);
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
queue.push(queueNode(state, node, tagName));
|
|
101
|
+
}
|
|
102
|
+
const removeNodeQueue = await Promise.all(queue);
|
|
103
|
+
for (const node of removeNodeQueue) {
|
|
104
|
+
if (node) {
|
|
105
|
+
removeNode(state, node);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
removeDanglingEdges(state);
|
|
109
|
+
return state;
|
|
110
|
+
};
|
package/dist/pseudo/semver.d.ts
CHANGED
|
@@ -5,10 +5,12 @@ import type { PostcssNode } from '@vltpkg/dss-parser';
|
|
|
5
5
|
export type SemverInternals = {
|
|
6
6
|
semverValue: string;
|
|
7
7
|
semverFunction: SemverComparatorFn;
|
|
8
|
+
semverRangeFunction: SemverRangeComparatorFn | undefined;
|
|
8
9
|
compareAttribute: SemverCompareAttribute;
|
|
9
10
|
};
|
|
10
|
-
export type SemverFunctionNames = 'satisfies' | 'gt' | 'gte' | 'lt' | 'lte' | 'eq' | 'neq';
|
|
11
|
+
export type SemverFunctionNames = 'satisfies' | 'gt' | 'gte' | 'lt' | 'lte' | 'eq' | 'neq' | 'intersects' | 'subset';
|
|
11
12
|
export type SemverComparatorFn = (version: Version | string, range: string) => boolean;
|
|
13
|
+
export type SemverRangeComparatorFn = (r1: string, r2: string) => boolean;
|
|
12
14
|
export type SemverCompareAttribute = Pick<AttrInternals, 'attribute' | 'properties'> | undefined;
|
|
13
15
|
export declare const isSemverFunctionName: (name: string) => name is SemverFunctionNames;
|
|
14
16
|
export declare const asSemverFunctionName: (name: string) => SemverFunctionNames;
|
package/dist/pseudo/semver.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { satisfies, gt, gte, lt, lte, eq, neq, parse, parseRange, } from '@vltpkg/semver';
|
|
1
|
+
import { satisfies, gt, gte, lt, lte, eq, neq, intersects, subset, parse, parseRange, } from '@vltpkg/semver';
|
|
2
2
|
import { error } from '@vltpkg/error-cause';
|
|
3
3
|
import { asError } from '@vltpkg/types';
|
|
4
4
|
import { parseInternals as parseAttrInternals } from "./attr.js";
|
|
5
5
|
import { getManifestPropertyValues } from "../attribute.js";
|
|
6
6
|
import { asAttributeNode, asPostcssNodeWithChildren, asPseudoNode, asStringNode, asTagNode, isAttributeNode, isPseudoNode, isStringNode, isTagNode, } from '@vltpkg/dss-parser';
|
|
7
|
-
import { removeNode, removeQuotes } from "./helpers.js";
|
|
7
|
+
import { removeEdge, removeNode, removeQuotes, removeUnlinkedNodes, } from "./helpers.js";
|
|
8
8
|
const semverFunctionNames = new Set([
|
|
9
9
|
'satisfies',
|
|
10
10
|
'gt',
|
|
@@ -13,6 +13,8 @@ const semverFunctionNames = new Set([
|
|
|
13
13
|
'lte',
|
|
14
14
|
'eq',
|
|
15
15
|
'neq',
|
|
16
|
+
'intersects',
|
|
17
|
+
'subset',
|
|
16
18
|
]);
|
|
17
19
|
export const isSemverFunctionName = (name) => semverFunctionNames.has(name);
|
|
18
20
|
export const asSemverFunctionName = (name) => {
|
|
@@ -33,6 +35,10 @@ const semverFunctions = new Map([
|
|
|
33
35
|
['eq', eq],
|
|
34
36
|
['neq', neq],
|
|
35
37
|
]);
|
|
38
|
+
const semverRangeFunctions = new Map([
|
|
39
|
+
['intersects', intersects],
|
|
40
|
+
['subset', subset],
|
|
41
|
+
]);
|
|
36
42
|
export const parseInternals = (nodes, loose) => {
|
|
37
43
|
// tries to parse the first param as a string node, otherwise defaults
|
|
38
44
|
// to reading all postcss nodes as just strings, since it just means
|
|
@@ -82,13 +88,17 @@ export const parseInternals = (nodes, loose) => {
|
|
|
82
88
|
}
|
|
83
89
|
}
|
|
84
90
|
const semverFunction = semverFunctions.get(fnName);
|
|
91
|
+
const semverRangeFunction = semverRangeFunctions.get(fnName);
|
|
85
92
|
// the following should never happen as long as the semver function names
|
|
86
93
|
// type and Set are correctly mirroring each other values
|
|
87
94
|
/* c8 ignore start */
|
|
88
|
-
if (!semverFunction) {
|
|
95
|
+
if (!semverFunction && !semverRangeFunction) {
|
|
89
96
|
throw error('Invalid semver function name', {
|
|
90
97
|
found: fnName,
|
|
91
|
-
validOptions:
|
|
98
|
+
validOptions: [
|
|
99
|
+
...Array.from(semverFunctions.keys()),
|
|
100
|
+
...Array.from(semverRangeFunctions.keys()),
|
|
101
|
+
],
|
|
92
102
|
});
|
|
93
103
|
}
|
|
94
104
|
/* c8 ignore stop */
|
|
@@ -117,7 +127,8 @@ export const parseInternals = (nodes, loose) => {
|
|
|
117
127
|
}
|
|
118
128
|
return {
|
|
119
129
|
semverValue,
|
|
120
|
-
semverFunction,
|
|
130
|
+
semverFunction: semverFunction ?? satisfies,
|
|
131
|
+
semverRangeFunction,
|
|
121
132
|
compareAttribute,
|
|
122
133
|
};
|
|
123
134
|
};
|
|
@@ -131,7 +142,33 @@ export const semverParser = async (state) => {
|
|
|
131
142
|
cause: err,
|
|
132
143
|
});
|
|
133
144
|
}
|
|
134
|
-
const { semverValue, semverFunction, compareAttribute } = internals;
|
|
145
|
+
const { semverValue, semverFunction, semverRangeFunction, compareAttribute, } = internals;
|
|
146
|
+
// Range-vs-range functions (subset, intersects) operate on edges by default
|
|
147
|
+
if (semverRangeFunction) {
|
|
148
|
+
if (compareAttribute) {
|
|
149
|
+
// Compare the semverValue against a manifest property value as ranges
|
|
150
|
+
for (const node of state.partial.nodes) {
|
|
151
|
+
const compareValues = getManifestPropertyValues(node, compareAttribute.properties, compareAttribute.attribute);
|
|
152
|
+
const compareValue = compareValues?.[0];
|
|
153
|
+
if (!compareValue ||
|
|
154
|
+
!semverRangeFunction(compareValue, semverValue)) {
|
|
155
|
+
removeNode(state, node);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
else {
|
|
160
|
+
// Default: operate on edges using bareSpec
|
|
161
|
+
for (const edge of state.partial.edges) {
|
|
162
|
+
const edgeRange = edge.spec.semver ?? edge.spec.bareSpec;
|
|
163
|
+
if (!edgeRange ||
|
|
164
|
+
!semverRangeFunction(edgeRange, semverValue)) {
|
|
165
|
+
removeEdge(state, edge);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
removeUnlinkedNodes(state);
|
|
169
|
+
}
|
|
170
|
+
return state;
|
|
171
|
+
}
|
|
135
172
|
for (const node of state.partial.nodes) {
|
|
136
173
|
if (compareAttribute) {
|
|
137
174
|
const compareValues = getManifestPropertyValues(node, compareAttribute.properties, compareAttribute.attribute);
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { ParserState } from '../types.ts';
|
|
2
|
+
/**
|
|
3
|
+
* :vulnerable / :vuln Pseudo-Selector matches any package version
|
|
4
|
+
* that has at least one CVE associated with it.
|
|
5
|
+
*/
|
|
6
|
+
export declare const vulnerable: (state: ParserState) => Promise<ParserState & {
|
|
7
|
+
securityArchive: NonNullable<ParserState["securityArchive"]>;
|
|
8
|
+
}>;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { assertSecurityArchive, removeDanglingEdges, removeNode, } from "./helpers.js";
|
|
2
|
+
/**
|
|
3
|
+
* :vulnerable / :vuln Pseudo-Selector matches any package version
|
|
4
|
+
* that has at least one CVE associated with it.
|
|
5
|
+
*/
|
|
6
|
+
export const vulnerable = async (state) => {
|
|
7
|
+
assertSecurityArchive(state, 'vulnerable');
|
|
8
|
+
for (const node of state.partial.nodes) {
|
|
9
|
+
const report = state.securityArchive.get(node.id);
|
|
10
|
+
const hasCve = report?.alerts.some(alert => alert.props?.cveId);
|
|
11
|
+
if (!hasCve) {
|
|
12
|
+
removeNode(state, node);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
removeDanglingEdges(state);
|
|
16
|
+
return state;
|
|
17
|
+
};
|
package/dist/pseudo.js
CHANGED
|
@@ -12,6 +12,7 @@ import { debug } from "./pseudo/debug.js";
|
|
|
12
12
|
import { deprecated } from "./pseudo/deprecated.js";
|
|
13
13
|
import { dev } from "./pseudo/dev.js";
|
|
14
14
|
import { diff } from "./pseudo/diff.js";
|
|
15
|
+
import { dist } from "./pseudo/dist.js";
|
|
15
16
|
import { dynamic } from "./pseudo/dynamic.js";
|
|
16
17
|
import { empty } from "./pseudo/empty.js";
|
|
17
18
|
import { entropic } from "./pseudo/entropic.js";
|
|
@@ -57,6 +58,7 @@ import { unknown } from "./pseudo/unknown.js";
|
|
|
57
58
|
import { unmaintained } from "./pseudo/unmaintained.js";
|
|
58
59
|
import { unpopular } from "./pseudo/unpopular.js";
|
|
59
60
|
import { unstable } from "./pseudo/unstable.js";
|
|
61
|
+
import { vulnerable } from "./pseudo/vulnerable.js";
|
|
60
62
|
import { workspace } from "./pseudo/workspace.js";
|
|
61
63
|
/**
|
|
62
64
|
* :has Pseudo-Selector, matches only nodes that have valid results
|
|
@@ -286,6 +288,7 @@ const pseudoSelectors = new Map(Object.entries({
|
|
|
286
288
|
deprecated,
|
|
287
289
|
dev,
|
|
288
290
|
diff,
|
|
291
|
+
dist,
|
|
289
292
|
dynamic,
|
|
290
293
|
eval: evalParser,
|
|
291
294
|
empty,
|
|
@@ -338,6 +341,8 @@ const pseudoSelectors = new Map(Object.entries({
|
|
|
338
341
|
unpopular,
|
|
339
342
|
unstable,
|
|
340
343
|
v: semver,
|
|
344
|
+
vuln: vulnerable,
|
|
345
|
+
vulnerable,
|
|
341
346
|
workspace,
|
|
342
347
|
}));
|
|
343
348
|
/**
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vltpkg/query",
|
|
3
3
|
"description": "Query syntax parser that retrieves items from a graph",
|
|
4
|
-
"version": "1.0.0-rc.
|
|
4
|
+
"version": "1.0.0-rc.32",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
7
|
"url": "git+https://github.com/vltpkg/vltpkg.git",
|
|
@@ -13,12 +13,12 @@
|
|
|
13
13
|
"url": "http://vlt.sh"
|
|
14
14
|
},
|
|
15
15
|
"dependencies": {
|
|
16
|
-
"@vltpkg/dep-id": "1.0.0-rc.
|
|
17
|
-
"@vltpkg/dss-parser": "1.0.0-rc.
|
|
18
|
-
"@vltpkg/error-cause": "1.0.0-rc.
|
|
19
|
-
"@vltpkg/security-archive": "1.0.0-rc.
|
|
20
|
-
"@vltpkg/semver": "1.0.0-rc.
|
|
21
|
-
"@vltpkg/types": "1.0.0-rc.
|
|
16
|
+
"@vltpkg/dep-id": "1.0.0-rc.32",
|
|
17
|
+
"@vltpkg/dss-parser": "1.0.0-rc.32",
|
|
18
|
+
"@vltpkg/error-cause": "1.0.0-rc.32",
|
|
19
|
+
"@vltpkg/security-archive": "1.0.0-rc.32",
|
|
20
|
+
"@vltpkg/semver": "1.0.0-rc.32",
|
|
21
|
+
"@vltpkg/types": "1.0.0-rc.32",
|
|
22
22
|
"minimatch": "^10.1.1",
|
|
23
23
|
"p-retry": "^7.1.1",
|
|
24
24
|
"postcss-selector-parser": "^7.1.1"
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
"devDependencies": {
|
|
27
27
|
"@eslint/js": "^9.39.1",
|
|
28
28
|
"@types/node": "^22.19.2",
|
|
29
|
-
"@vltpkg/spec": "1.0.0-rc.
|
|
29
|
+
"@vltpkg/spec": "1.0.0-rc.32",
|
|
30
30
|
"eslint": "^9.39.1",
|
|
31
31
|
"prettier": "^3.7.4",
|
|
32
32
|
"tap": "^21.5.0",
|