@vltpkg/query 1.0.0-rc.33 → 1.0.0-rc.34

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/index.js CHANGED
@@ -124,6 +124,8 @@ const securitySelectors = new Set([
124
124
  ':unmaintained',
125
125
  ':unpopular',
126
126
  ':unstable',
127
+ ':vuln',
128
+ ':vulnerable',
127
129
  ]);
128
130
  const setMethodToJSON = (node) => {
129
131
  const { toJSON } = node;
@@ -234,12 +236,7 @@ export class Query {
234
236
  none: securityArchiveEntry.alerts.some(i => i.type === 'noLicenseFound'),
235
237
  exception: securityArchiveEntry.alerts.some(i => i.type === 'licenseException'),
236
238
  },
237
- malware: {
238
- low: securityArchiveEntry.alerts.some(i => i.type === 'gptAnomaly'),
239
- medium: securityArchiveEntry.alerts.some(i => i.type === 'gptSecurity'),
240
- high: securityArchiveEntry.alerts.some(i => i.type === 'gptMalware'),
241
- critical: securityArchiveEntry.alerts.some(i => i.type === 'malware'),
242
- },
239
+ malware: securityArchiveEntry.alerts.some(i => i.type === 'malware' || i.type === 'gptMalware'),
243
240
  minified: securityArchiveEntry.alerts.some(i => i.type === 'minifiedFile'),
244
241
  native: securityArchiveEntry.alerts.some(i => i.type === 'hasNativeCode'),
245
242
  network: securityArchiveEntry.alerts.some(i => i.type === 'networkAccess'),
@@ -265,6 +262,13 @@ export class Query {
265
262
  unmaintained: securityArchiveEntry.alerts.some(i => i.type === 'unmaintained'),
266
263
  unpopular: securityArchiveEntry.alerts.some(i => i.type === 'unpopularPackage'),
267
264
  unstable: securityArchiveEntry.alerts.some(i => i.type === 'unstableOwnership'),
265
+ vuln: {
266
+ low: securityArchiveEntry.alerts.some(i => i.type === 'mildCVE' || i.type === 'gptAnomaly'),
267
+ medium: securityArchiveEntry.alerts.some(i => i.type === 'potentialVulnerability' ||
268
+ i.type === 'gptSecurity'),
269
+ high: securityArchiveEntry.alerts.some(i => i.type === 'cve'),
270
+ critical: securityArchiveEntry.alerts.some(i => i.type === 'criticalCVE'),
271
+ },
268
272
  };
269
273
  setMethodToJSON(node);
270
274
  }
package/dist/parser.js CHANGED
@@ -11,12 +11,13 @@ export const unescapeDots = (query) => query.replaceAll('\\.', '.');
11
11
  const pseudoCleanUpNeeded = new Set([
12
12
  ':published',
13
13
  ':score',
14
- ':malware',
15
14
  ':severity',
16
15
  ':sev',
17
16
  ':squat',
18
17
  ':semver',
19
18
  ':v',
19
+ ':vuln',
20
+ ':vulnerable',
20
21
  ':path',
21
22
  ]);
22
23
  const hasParamsToEscape = (node) => pseudoCleanUpNeeded.has(node.value);
@@ -1,22 +1,9 @@
1
1
  import type { ParserState } from '../types.ts';
2
- import type { PostcssNode } from '@vltpkg/dss-parser';
3
- export type MalwareKinds = '0' | '1' | '2' | '3' | 'critical' | 'high' | 'medium' | 'low' | undefined;
4
- export type MalwareAlertTypes = 'malware' | 'gptMalware' | 'gptSecurity' | 'gptAnomaly' | undefined;
5
- export type MalwareComparator = '>' | '<' | '>=' | '<=' | undefined;
6
- export declare const isMalwareKind: (value?: string) => value is MalwareKinds;
7
- export declare const asMalwareKind: (value?: string) => MalwareKinds;
8
- export declare const parseInternals: (nodes: PostcssNode[]) => {
9
- kind: MalwareKinds;
10
- comparator: MalwareComparator;
11
- };
12
2
  /**
13
- * :malware Pseudo-Selector, matches nodes with malware alerts.
3
+ * :malware Pseudo-Selector, matches nodes with any malware-related alert.
14
4
  *
15
- * Usage:
16
- * - :malware - matches malware with severity >= medium (critical, high, medium but not low)
17
- * - :malware(critical) - matches specific malware kind
18
- * - :malware(>1) - matches malware with severity greater than 1
19
- * - :malware(">=medium") - matches malware with severity >= medium
5
+ * This is a binary selector — no parameters. A node matches if it has
6
+ * at least one alert whose type is `malware` or `gptMalware`.
20
7
  */
21
8
  export declare const malware: (state: ParserState) => Promise<ParserState & {
22
9
  securityArchive: NonNullable<ParserState["securityArchive"]>;
@@ -1,183 +1,23 @@
1
1
  import { error } from '@vltpkg/error-cause';
2
- import { asPostcssNodeWithChildren, asStringNode, asTagNode, isStringNode, isTagNode, } from '@vltpkg/dss-parser';
3
- import { assertSecurityArchive, removeDanglingEdges, removeNode, removeQuotes, } from "./helpers.js";
4
- const kindsMap = new Map([
5
- ['critical', 'malware'],
6
- ['high', 'gptMalware'],
7
- ['medium', 'gptSecurity'],
8
- ['low', 'gptAnomaly'],
9
- ['0', 'malware'],
10
- ['1', 'gptMalware'],
11
- ['2', 'gptSecurity'],
12
- ['3', 'gptAnomaly'],
13
- ]);
14
- // Map numerical values to their respective kinds for comparison operations
15
- const kindLevelMap = new Map([
16
- ['critical', 0],
17
- ['high', 1],
18
- ['medium', 2],
19
- ['low', 3],
20
- ['0', 0],
21
- ['1', 1],
22
- ['2', 2],
23
- ['3', 3],
24
- ]);
25
- const kinds = new Set(kindsMap.keys());
26
- export const isMalwareKind = (value) => kinds.has(value);
27
- export const asMalwareKind = (value) => {
28
- if (!isMalwareKind(value)) {
29
- throw error('Expected a valid malware kind', {
30
- found: value,
31
- validOptions: Array.from(kinds),
32
- });
33
- }
34
- return value;
35
- };
36
- export const parseInternals = (nodes) => {
37
- // Handle case where no parameters are provided (parameterless :malware)
38
- if (!nodes[0]) {
39
- return { kind: undefined, comparator: undefined };
40
- }
41
- const selectorNode = asPostcssNodeWithChildren(nodes[0]);
42
- if (!selectorNode.nodes[0]) {
43
- return { kind: undefined, comparator: undefined };
44
- }
45
- let kindValue = '';
46
- let comparator = undefined;
47
- let kind;
48
- // Parse the parameter (kind with optional comparator)
49
- if (isStringNode(selectorNode.nodes[0])) {
50
- kindValue = removeQuotes(asStringNode(selectorNode.nodes[0]).value);
51
- }
52
- else if (isTagNode(selectorNode.nodes[0])) {
53
- kindValue = asTagNode(selectorNode.nodes[0]).value;
54
- }
55
- // Extract comparator if present
56
- if (kindValue.startsWith('>=')) {
57
- comparator = '>=';
58
- kindValue = kindValue.substring(2);
59
- }
60
- else if (kindValue.startsWith('<=')) {
61
- comparator = '<=';
62
- kindValue = kindValue.substring(2);
63
- }
64
- else if (kindValue.startsWith('>')) {
65
- comparator = '>';
66
- kindValue = kindValue.substring(1);
67
- }
68
- else if (kindValue.startsWith('<')) {
69
- comparator = '<';
70
- kindValue = kindValue.substring(1);
71
- }
72
- // Validate the kind without comparator
73
- if (!comparator) {
74
- kind = asMalwareKind(kindValue);
75
- }
76
- else {
77
- // For comparisons, just make sure it's a valid numeric value or a valid kind
78
- if (isMalwareKind(kindValue)) {
79
- kind = kindValue;
80
- }
81
- else {
82
- throw error('Expected a valid malware kind or number between 0-3', {
83
- found: kindValue,
84
- });
85
- }
86
- }
87
- return { kind, comparator };
88
- };
2
+ import { asPostcssNodeWithChildren } from '@vltpkg/dss-parser';
3
+ import { assertSecurityArchive, removeDanglingEdges, removeNode, } from "./helpers.js";
4
+ const malwareAlertTypes = new Set(['malware', 'gptMalware']);
89
5
  /**
90
- * :malware Pseudo-Selector, matches nodes with malware alerts.
6
+ * :malware Pseudo-Selector, matches nodes with any malware-related alert.
91
7
  *
92
- * Usage:
93
- * - :malware - matches malware with severity >= medium (critical, high, medium but not low)
94
- * - :malware(critical) - matches specific malware kind
95
- * - :malware(>1) - matches malware with severity greater than 1
96
- * - :malware(">=medium") - matches malware with severity >= medium
8
+ * This is a binary selector — no parameters. A node matches if it has
9
+ * at least one alert whose type is `malware` or `gptMalware`.
97
10
  */
98
11
  export const malware = async (state) => {
99
12
  assertSecurityArchive(state, 'malware');
100
- let internals;
101
- try {
102
- internals = parseInternals(asPostcssNodeWithChildren(state.current).nodes);
103
- }
104
- catch (err) {
105
- throw error('Failed to parse :malware selector', { cause: err });
13
+ const currentNode = asPostcssNodeWithChildren(state.current);
14
+ if (currentNode.nodes.length > 0) {
15
+ throw error(':malware selector does not accept parameters. Use :vuln(<severity>) for severity-based filtering.');
106
16
  }
107
- const { kind, comparator } = internals;
108
- const alertName = comparator ? undefined : kindsMap.get(kind);
109
17
  for (const node of state.partial.nodes) {
110
18
  const report = state.securityArchive.get(node.id);
111
- // Always exclude nodes that don't have security data or alerts
112
- if (!report?.alerts || report.alerts.length === 0) {
113
- removeNode(state, node);
114
- }
115
- }
116
- for (const node of state.partial.nodes) {
117
- const report = state.securityArchive.get(node.id);
118
- let exclude = true;
119
- if (report) {
120
- if (kind === undefined && comparator === undefined) {
121
- // Parameterless :malware - match malware alerts with severity >= medium (exclude low/gptAnomaly)
122
- exclude = !report.alerts.some(alert => alert.type === 'malware' ||
123
- alert.type === 'gptMalware' ||
124
- alert.type === 'gptSecurity');
125
- }
126
- else if (comparator) {
127
- // retrieve the value to compare against
128
- const kindLevel = kindLevelMap.get(kind);
129
- // the kindLevel value has already been validated at this point
130
- // and thus can never return an undefined/falsy value but ts doesn't
131
- // know about that, so we have the extra check here
132
- /* c8 ignore next - impossible */
133
- if (kindLevel == null)
134
- break;
135
- // Check each alert to find any that match our comparison criteria
136
- for (const alert of report.alerts) {
137
- // Get the numerical value of the alert type
138
- const alertType = alert.type;
139
- // retrieve a key to the current alert level to be compared against
140
- const currentAlertLevelKey = [...kindsMap.entries()].find(([_, alertValue]) => alertValue === alertType)?.[0];
141
- // perform the comparison based on the user-provided kindLevel
142
- if (currentAlertLevelKey) {
143
- const currentAlertLevel = kindLevelMap.get(currentAlertLevelKey);
144
- /* c8 ignore next - impossible but ts doesn't know */
145
- if (currentAlertLevel == null)
146
- continue;
147
- switch (comparator) {
148
- case '>':
149
- if (currentAlertLevel > kindLevel) {
150
- exclude = false;
151
- }
152
- break;
153
- case '<':
154
- if (currentAlertLevel < kindLevel) {
155
- exclude = false;
156
- }
157
- break;
158
- case '>=':
159
- if (currentAlertLevel >= kindLevel) {
160
- exclude = false;
161
- }
162
- break;
163
- case '<=':
164
- if (currentAlertLevel <= kindLevel) {
165
- exclude = false;
166
- }
167
- break;
168
- }
169
- // If we've found a match, no need to check other alerts
170
- if (!exclude)
171
- break;
172
- }
173
- }
174
- }
175
- else {
176
- // Original exact match behavior
177
- exclude = !report.alerts.some(alert => alert.type === alertName);
178
- }
179
- }
180
- if (exclude) {
19
+ const hasMalware = report?.alerts.some(alert => malwareAlertTypes.has(alert.type));
20
+ if (!hasMalware) {
181
21
  removeNode(state, node);
182
22
  }
183
23
  }
@@ -0,0 +1,22 @@
1
+ import type { ParserState } from '../types.ts';
2
+ import type { PostcssNode } from '@vltpkg/dss-parser';
3
+ export type VulnKinds = '0' | '1' | '2' | '3' | 'critical' | 'high' | 'medium' | 'low' | undefined;
4
+ export type VulnComparator = '>' | '<' | '>=' | '<=' | undefined;
5
+ export declare const isVulnKind: (value?: string) => value is VulnKinds;
6
+ export declare const asVulnKind: (value?: string) => VulnKinds;
7
+ export declare const parseInternals: (nodes: PostcssNode[]) => {
8
+ kind: VulnKinds;
9
+ comparator: VulnComparator;
10
+ };
11
+ /**
12
+ * :vuln / :vulnerable Pseudo-Selector, matches nodes with vulnerability alerts.
13
+ *
14
+ * Usage:
15
+ * - :vuln - matches vulnerabilities with severity >= medium (critical, high, medium but not low)
16
+ * - :vuln(critical) - matches specific vulnerability kind
17
+ * - :vuln(>1) - matches vulnerabilities with severity greater than 1
18
+ * - :vuln(">=medium") - matches vulnerabilities with severity >= medium
19
+ */
20
+ export declare const vuln: (state: ParserState) => Promise<ParserState & {
21
+ securityArchive: NonNullable<ParserState["securityArchive"]>;
22
+ }>;
@@ -0,0 +1,220 @@
1
+ import { error } from '@vltpkg/error-cause';
2
+ import { asPostcssNodeWithChildren, asStringNode, asTagNode, isStringNode, isTagNode, } from '@vltpkg/dss-parser';
3
+ import { assertSecurityArchive, removeDanglingEdges, removeNode, removeQuotes, } from "./helpers.js";
4
+ // Valid vulnerability kind names
5
+ const kinds = new Set([
6
+ 'critical',
7
+ 'high',
8
+ 'medium',
9
+ 'low',
10
+ '0',
11
+ '1',
12
+ '2',
13
+ '3',
14
+ ]);
15
+ // Map numerical values to their respective kinds for comparison operations
16
+ const kindLevelMap = new Map([
17
+ ['critical', 0],
18
+ ['high', 1],
19
+ ['medium', 2],
20
+ ['low', 3],
21
+ ['0', 0],
22
+ ['1', 1],
23
+ ['2', 2],
24
+ ['3', 3],
25
+ ]);
26
+ // Maps alert types to their severity level for comparison operations.
27
+ // gptSecurity maps to medium (2), gptAnomaly maps to low (3).
28
+ const alertLevelMap = new Map([
29
+ ['criticalCVE', 0],
30
+ ['cve', 1],
31
+ ['potentialVulnerability', 2],
32
+ ['gptSecurity', 2],
33
+ ['mildCVE', 3],
34
+ ['gptAnomaly', 3],
35
+ ]);
36
+ // Maps alert.severity strings to numeric levels for cveId-bearing alerts
37
+ // whose type may not be in alertLevelMap.
38
+ const severityLevelMap = new Map([
39
+ ['critical', 0],
40
+ ['high', 1],
41
+ ['medium', 2],
42
+ ['low', 3],
43
+ ]);
44
+ /**
45
+ * Returns the severity level for an alert, considering both its type
46
+ * (via alertLevelMap) and its cveId + severity fields. Alerts with a
47
+ * cveId are treated as vulnerability alerts even if their type is not
48
+ * in the closed set.
49
+ */
50
+ const getAlertLevel = (alert) => {
51
+ const level = alertLevelMap.get(alert.type);
52
+ if (level != null)
53
+ return level;
54
+ // Fall back to severity field for alerts carrying a CVE id
55
+ if (alert.props?.cveId && alert.severity) {
56
+ return severityLevelMap.get(alert.severity);
57
+ }
58
+ return undefined;
59
+ };
60
+ export const isVulnKind = (value) => kinds.has(value);
61
+ export const asVulnKind = (value) => {
62
+ if (!isVulnKind(value)) {
63
+ throw error('Expected a valid vuln kind', {
64
+ found: value,
65
+ validOptions: Array.from(kinds),
66
+ });
67
+ }
68
+ return value;
69
+ };
70
+ export const parseInternals = (nodes) => {
71
+ // Handle case where no parameters are provided (parameterless :vuln)
72
+ if (!nodes[0]) {
73
+ return { kind: undefined, comparator: undefined };
74
+ }
75
+ const selectorNode = asPostcssNodeWithChildren(nodes[0]);
76
+ if (!selectorNode.nodes[0]) {
77
+ return { kind: undefined, comparator: undefined };
78
+ }
79
+ let kindValue = '';
80
+ let comparator = undefined;
81
+ let kind;
82
+ // Parse the parameter (kind with optional comparator)
83
+ if (isStringNode(selectorNode.nodes[0])) {
84
+ kindValue = removeQuotes(asStringNode(selectorNode.nodes[0]).value);
85
+ }
86
+ else if (isTagNode(selectorNode.nodes[0])) {
87
+ kindValue = asTagNode(selectorNode.nodes[0]).value;
88
+ }
89
+ // Extract comparator if present
90
+ if (kindValue.startsWith('>=')) {
91
+ comparator = '>=';
92
+ kindValue = kindValue.substring(2);
93
+ }
94
+ else if (kindValue.startsWith('<=')) {
95
+ comparator = '<=';
96
+ kindValue = kindValue.substring(2);
97
+ }
98
+ else if (kindValue.startsWith('>')) {
99
+ comparator = '>';
100
+ kindValue = kindValue.substring(1);
101
+ }
102
+ else if (kindValue.startsWith('<')) {
103
+ comparator = '<';
104
+ kindValue = kindValue.substring(1);
105
+ }
106
+ // Validate the kind without comparator
107
+ if (!comparator) {
108
+ kind = asVulnKind(kindValue);
109
+ }
110
+ else {
111
+ // For comparisons, just make sure it's a valid numeric value or a valid kind
112
+ if (isVulnKind(kindValue)) {
113
+ kind = kindValue;
114
+ }
115
+ else {
116
+ throw error('Expected a valid vuln kind or number between 0-3', {
117
+ found: kindValue,
118
+ });
119
+ }
120
+ }
121
+ return { kind, comparator };
122
+ };
123
+ /**
124
+ * :vuln / :vulnerable Pseudo-Selector, matches nodes with vulnerability alerts.
125
+ *
126
+ * Usage:
127
+ * - :vuln - matches vulnerabilities with severity >= medium (critical, high, medium but not low)
128
+ * - :vuln(critical) - matches specific vulnerability kind
129
+ * - :vuln(>1) - matches vulnerabilities with severity greater than 1
130
+ * - :vuln(">=medium") - matches vulnerabilities with severity >= medium
131
+ */
132
+ export const vuln = async (state) => {
133
+ assertSecurityArchive(state, 'vuln');
134
+ let internals;
135
+ try {
136
+ internals = parseInternals(asPostcssNodeWithChildren(state.current).nodes);
137
+ }
138
+ catch (err) {
139
+ throw error('Failed to parse :vuln selector', { cause: err });
140
+ }
141
+ const { kind, comparator } = internals;
142
+ for (const node of state.partial.nodes) {
143
+ const report = state.securityArchive.get(node.id);
144
+ // Always exclude nodes that don't have security data or alerts
145
+ if (!report?.alerts || report.alerts.length === 0) {
146
+ removeNode(state, node);
147
+ }
148
+ }
149
+ for (const node of state.partial.nodes) {
150
+ const report = state.securityArchive.get(node.id);
151
+ let exclude = true;
152
+ if (report) {
153
+ if (kind === undefined && comparator === undefined) {
154
+ // Parameterless :vuln - match vuln alerts with severity >= medium
155
+ // Includes: criticalCVE, cve, potentialVulnerability, gptSecurity,
156
+ // and any alert carrying a cveId prop
157
+ // Excludes: mildCVE, gptAnomaly (low severity)
158
+ exclude = !report.alerts.some(alert => {
159
+ const level = getAlertLevel(alert);
160
+ return level != null && level <= 2;
161
+ });
162
+ }
163
+ else if (comparator) {
164
+ // retrieve the value to compare against
165
+ const kindLevel = kindLevelMap.get(kind);
166
+ // the kindLevel value has already been validated at this point
167
+ // and thus can never return an undefined/falsy value but ts doesn't
168
+ // know about that, so we have the extra check here
169
+ /* c8 ignore next - impossible */
170
+ if (kindLevel == null)
171
+ break;
172
+ // Check each alert to find any that match our comparison criteria
173
+ for (const alert of report.alerts) {
174
+ const currentAlertLevel = getAlertLevel(alert);
175
+ if (currentAlertLevel == null)
176
+ continue;
177
+ switch (comparator) {
178
+ case '>':
179
+ if (currentAlertLevel > kindLevel) {
180
+ exclude = false;
181
+ }
182
+ break;
183
+ case '<':
184
+ if (currentAlertLevel < kindLevel) {
185
+ exclude = false;
186
+ }
187
+ break;
188
+ case '>=':
189
+ if (currentAlertLevel >= kindLevel) {
190
+ exclude = false;
191
+ }
192
+ break;
193
+ case '<=':
194
+ if (currentAlertLevel <= kindLevel) {
195
+ exclude = false;
196
+ }
197
+ break;
198
+ }
199
+ // If we've found a match, no need to check other alerts
200
+ if (!exclude)
201
+ break;
202
+ }
203
+ }
204
+ else {
205
+ // Exact match behavior — also matches gptSecurity/gptAnomaly
206
+ // at the same level as their mapped kind, and cveId-bearing alerts
207
+ const targetLevel = kindLevelMap.get(kind);
208
+ exclude = !report.alerts.some(alert => {
209
+ const level = getAlertLevel(alert);
210
+ return level != null && level === targetLevel;
211
+ });
212
+ }
213
+ }
214
+ if (exclude) {
215
+ removeNode(state, node);
216
+ }
217
+ }
218
+ removeDanglingEdges(state);
219
+ return state;
220
+ };
package/dist/pseudo.js CHANGED
@@ -58,7 +58,7 @@ import { unknown } from "./pseudo/unknown.js";
58
58
  import { unmaintained } from "./pseudo/unmaintained.js";
59
59
  import { unpopular } from "./pseudo/unpopular.js";
60
60
  import { unstable } from "./pseudo/unstable.js";
61
- import { vulnerable } from "./pseudo/vulnerable.js";
61
+ import { vuln } from "./pseudo/vuln.js";
62
62
  import { workspace } from "./pseudo/workspace.js";
63
63
  /**
64
64
  * :has Pseudo-Selector, matches only nodes that have valid results
@@ -341,8 +341,8 @@ const pseudoSelectors = new Map(Object.entries({
341
341
  unpopular,
342
342
  unstable,
343
343
  v: semver,
344
- vuln: vulnerable,
345
- vulnerable,
344
+ vuln,
345
+ vulnerable: vuln,
346
346
  workspace,
347
347
  }));
348
348
  /**
package/dist/types.d.ts CHANGED
@@ -75,7 +75,7 @@ export type Insights = {
75
75
  eval?: boolean;
76
76
  fs?: boolean;
77
77
  license?: LicenseInsights;
78
- malware?: MalwareInsights;
78
+ malware?: boolean;
79
79
  minified?: boolean;
80
80
  native?: boolean;
81
81
  network?: boolean;
@@ -95,6 +95,7 @@ export type Insights = {
95
95
  unmaintained?: boolean;
96
96
  unpopular?: boolean;
97
97
  unstable?: boolean;
98
+ vuln?: VulnInsights;
98
99
  };
99
100
  export type LicenseInsights = {
100
101
  unlicensed: boolean;
@@ -112,8 +113,8 @@ export type LeveledInsights = {
112
113
  high: boolean;
113
114
  critical: boolean;
114
115
  };
115
- export type MalwareInsights = LeveledInsights;
116
116
  export type SeverityInsights = LeveledInsights;
117
+ export type VulnInsights = LeveledInsights;
117
118
  export type SquatInsights = {
118
119
  medium: boolean;
119
120
  critical: boolean;
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.33",
4
+ "version": "1.0.0-rc.34",
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.33",
17
- "@vltpkg/dss-parser": "1.0.0-rc.33",
18
- "@vltpkg/error-cause": "1.0.0-rc.33",
19
- "@vltpkg/security-archive": "1.0.0-rc.33",
20
- "@vltpkg/semver": "1.0.0-rc.33",
21
- "@vltpkg/types": "1.0.0-rc.33",
16
+ "@vltpkg/dep-id": "1.0.0-rc.34",
17
+ "@vltpkg/dss-parser": "1.0.0-rc.34",
18
+ "@vltpkg/error-cause": "1.0.0-rc.34",
19
+ "@vltpkg/security-archive": "1.0.0-rc.34",
20
+ "@vltpkg/semver": "1.0.0-rc.34",
21
+ "@vltpkg/types": "1.0.0-rc.34",
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.33",
29
+ "@vltpkg/spec": "1.0.0-rc.34",
30
30
  "eslint": "^9.39.1",
31
31
  "prettier": "^3.7.4",
32
32
  "tap": "^21.5.0",
@@ -88,10 +88,14 @@ Package properties:
88
88
  Severity args accept names or numbers (`critical`/`0`, `high`/`1`,
89
89
  `medium`/`2`, `low`/`3`) and comparators: `:severity(">=medium")`.
90
90
 
91
- Threats: `:malware(sev?)`, `:squat(sev?)`, `:suspicious`, `:confused`.
91
+ Threats: `:malware` (binary, no params), `:squat(sev?)`,
92
+ `:suspicious`, `:confused`.
92
93
 
93
- Vulnerabilities: `:vulnerable` (alias `:vuln`), `:cve(CVE-2023-1234)`,
94
- `:cve(*)`, `:cwe(CWE-79)`, `:severity(level)`.
94
+ Vulnerabilities: `:vuln(sev?)` (alias `:vulnerable`),
95
+ `:cve(CVE-2023-1234)`, `:cve(*)`, `:cwe(CWE-79)`, `:severity(level)`.
96
+ `:vuln` without params matches severity ≥ medium; `:vuln(critical)`
97
+ exact-matches; `:vuln(">=high")` uses comparators. Also matches alerts
98
+ carrying a `cveId` prop.
95
99
 
96
100
  Licensing: `:license(type)` — types: `unlicensed`, `misc`,
97
101
  `restricted`, `ambiguous`, `copyleft`, `unknown`, `none`, `exception`.
@@ -112,7 +116,7 @@ kinds: `overall` (default), `license`, `maintenance`, `quality`,
112
116
  ## Audit query starters
113
117
 
114
118
  ```bash
115
- vlt query ':malware(critical), :cve(*), :obfuscated' # critical issues
119
+ vlt query ':malware, :vuln(critical), :cve(*), :obfuscated' # critical issues
116
120
  vlt query ':abandoned, :unmaintained, :unknown' # supply chain risk
117
121
  vlt query ':license(copyleft), :license(unlicensed)' # license compliance
118
122
  vlt query ':eval, :shell, :network, :fs' # behavior audit
@@ -143,17 +143,17 @@ so the dependency graph doubles as a security scanner. Selectors group
143
143
  into four families — compose them with anchors and combinators like
144
144
  any other filter:
145
145
 
146
- | Family | Selectors | Ask |
147
- | --------------- | --------------------------------------------------------------------------- | ------------------------------ |
148
- | Threats | `:malware(critical)` `:squat` `:obfuscated` `:suspicious` | is anything actively hostile? |
149
- | Vulnerabilities | `:cve(CVE-…)` `:cve(*)` `:cwe(CWE-79)` `:severity(">=medium")` | known CVEs, filter by severity |
150
- | Capabilities | `:eval` `:network` `:fs` `:shell` `:env` | what _can_ this code do? |
151
- | Hygiene | `:abandoned` `:unmaintained` `:deprecated` `:score("<=0.5", "maintenance")` | will this rot on us? |
146
+ | Family | Selectors | Ask |
147
+ | --------------- | -------------------------------------------------------------------------------- | -------------------------------------- |
148
+ | Threats | `:malware` `:squat` `:obfuscated` `:suspicious` | is anything actively hostile? |
149
+ | Vulnerabilities | `:vuln(critical)` `:cve(CVE-…)` `:cve(*)` `:cwe(CWE-79)` `:severity(">=medium")` | known CVEs / vulns, filter by severity |
150
+ | Capabilities | `:eval` `:network` `:fs` `:shell` `:env` | what _can_ this code do? |
151
+ | Hygiene | `:abandoned` `:unmaintained` `:deprecated` `:score("<=0.5", "maintenance")` | will this rot on us? |
152
152
 
153
153
  Audit recipes:
154
154
 
155
155
  ```bash
156
- vlt query ':malware(critical), :squat, :obfuscated' # supply-chain sweep
156
+ vlt query ':malware, :vuln(critical), :squat, :obfuscated' # supply-chain sweep
157
157
  vlt query ':workspace > :prod:severity(">=high")' # release blockers
158
158
  vlt query ':dev:shell, :dev:network' # dev deps that spawn/phone home
159
159
  ```