@mitre/hdf-schema 3.4.4 → 3.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/helpers.d.ts CHANGED
@@ -14,8 +14,19 @@ import type {
14
14
  ResultStatus,
15
15
  SupportedPlatform,
16
16
  RequirementGroup,
17
+ StatusOverride,
18
+ Poam,
19
+ Cvss,
20
+ Reference,
21
+ AffectedPackage,
22
+ Epss,
23
+ Kev,
24
+ OverrideType,
17
25
  } from '../dist/ts/hdf.js';
18
26
 
27
+ /** Minimal identity shape used by amendment appliedBy fields. */
28
+ type Identity = { type: string; identifier: string; description?: string };
29
+
19
30
  export function createMinimalBaseline(
20
31
  name: string,
21
32
  requirements: EvaluatedRequirement[],
@@ -35,13 +46,27 @@ export function createMinimalBaseline(
35
46
 
36
47
  export function createRequirement(
37
48
  id: string,
38
- title: string,
49
+ title: string | null | undefined,
39
50
  descriptions: Description[],
40
51
  impact: number,
41
52
  results: RequirementResult[],
42
53
  options?: {
43
54
  sourceLocation?: SourceLocation;
44
55
  tags?: Record<string, unknown>;
56
+ code?: string;
57
+ // Amendment fields
58
+ effectiveStatus?: ResultStatus;
59
+ effectiveImpact?: number;
60
+ disposition?: OverrideType;
61
+ statusOverrides?: StatusOverride[];
62
+ poams?: Poam[];
63
+ // Vulnerability fields
64
+ cwe?: string[];
65
+ cvss?: Cvss[];
66
+ refs?: Reference[];
67
+ affectedPackages?: AffectedPackage[];
68
+ epss?: Epss;
69
+ kev?: Kev;
45
70
  }
46
71
  ): EvaluatedRequirement;
47
72
 
@@ -56,6 +81,8 @@ export function createResult(
56
81
  runTime?: number;
57
82
  backtrace?: string[];
58
83
  exception?: string;
84
+ resource?: string;
85
+ resourceId?: string;
59
86
  }
60
87
  ): RequirementResult;
61
88
 
@@ -68,6 +95,34 @@ export function createSupportedPlatform(
68
95
 
69
96
  export function createSourceLocation(ref: string, line: number): SourceLocation;
70
97
 
98
+ export function createStatusOverride(
99
+ type: OverrideType | string,
100
+ options?: {
101
+ reason?: string;
102
+ appliedBy?: Identity;
103
+ appliedAt?: string;
104
+ expiresAt?: string;
105
+ status?: ResultStatus;
106
+ impact?: { value: number };
107
+ }
108
+ ): StatusOverride;
109
+
110
+ export function createPoam(
111
+ type: 'remediation' | 'mitigation' | 'riskAcceptance' | 'vendorDependency' | string,
112
+ options?: {
113
+ explanation?: string;
114
+ appliedBy?: Identity;
115
+ appliedAt?: string;
116
+ expiresAt?: string;
117
+ milestones?: Array<Record<string, unknown>>;
118
+ }
119
+ ): Poam;
120
+
121
+ export function createCvss(
122
+ version: string,
123
+ options?: Partial<Omit<Cvss, 'version'>>
124
+ ): Cvss;
125
+
71
126
  export function severityToImpact(severity: null): null;
72
127
  export function severityToImpact(severity: string): number;
73
128
  export function severityToImpact(severity: string | null): number | null;
package/dist/helpers.js CHANGED
@@ -54,27 +54,43 @@ export function createMinimalBaseline(name, requirements, options = {}) {
54
54
  /**
55
55
  * Create a minimal valid EvaluatedRequirement
56
56
  * @param {string} id - Unique requirement identifier
57
- * @param {string} title - Human-readable title
57
+ * @param {string|null|undefined} title - Human-readable title. Pass null/undefined
58
+ * to omit it (some controls legitimately have no title).
58
59
  * @param {import('../dist/ts/hdf-results.js').Description[]} descriptions - Array of descriptions
59
60
  * @param {number} impact - Impact score (0.0 to 1.0)
60
61
  * @param {import('../dist/ts/hdf-results.js').RequirementResult[]} results - Array of test results
61
- * @param {Object} [options] - Optional fields
62
+ * @param {Object} [options] - Optional fields: sourceLocation, code, tags;
63
+ * amendment fields (effectiveStatus, effectiveImpact, disposition, statusOverrides, poams);
64
+ * vulnerability fields (cwe, cvss, refs, affectedPackages, epss, kev).
62
65
  * @returns {import('../dist/ts/hdf-results.js').EvaluatedRequirement}
63
66
  */
64
67
  export function createRequirement(id, title, descriptions, impact, results, options = {}) {
65
68
  const req = {
66
69
  id,
67
- title,
68
70
  descriptions,
69
71
  impact,
70
72
  results,
71
73
  tags: options.tags || {},
72
74
  };
73
75
 
74
- // Only include sourceLocation if it's provided
75
- if (options.sourceLocation) {
76
- req.sourceLocation = options.sourceLocation;
77
- }
76
+ if (title != null) req.title = title;
77
+ if (options.sourceLocation) req.sourceLocation = options.sourceLocation;
78
+ if (options.code != null) req.code = options.code;
79
+
80
+ // Amendment fields
81
+ if (options.effectiveStatus) req.effectiveStatus = options.effectiveStatus;
82
+ if (options.effectiveImpact != null) req.effectiveImpact = options.effectiveImpact;
83
+ if (options.disposition) req.disposition = options.disposition;
84
+ if (options.statusOverrides) req.statusOverrides = options.statusOverrides;
85
+ if (options.poams) req.poams = options.poams;
86
+
87
+ // Vulnerability fields
88
+ if (options.cwe) req.cwe = options.cwe;
89
+ if (options.cvss) req.cvss = options.cvss;
90
+ if (options.refs) req.refs = options.refs;
91
+ if (options.affectedPackages) req.affectedPackages = options.affectedPackages;
92
+ if (options.epss) req.epss = options.epss;
93
+ if (options.kev) req.kev = options.kev;
78
94
 
79
95
  return req;
80
96
  }
@@ -107,6 +123,8 @@ export function createResult(status, message, options = {}) {
107
123
  runTime: options.runTime,
108
124
  backtrace: options.backtrace,
109
125
  exception: options.exception,
126
+ ...(options.resource ? { resource: options.resource } : {}),
127
+ ...(options.resourceId ? { resourceId: options.resourceId } : {}),
110
128
  };
111
129
  }
112
130
 
@@ -144,11 +162,75 @@ export function createSourceLocation(ref, line) {
144
162
  return { ref, line };
145
163
  }
146
164
 
165
+ /**
166
+ * Create a minimal valid inline Status_Override (requirement.statusOverrides[]).
167
+ * The schema requires one of status/impact; when neither is supplied this
168
+ * defaults status to 'notApplicable' so the built override stays valid.
169
+ * @param {string} type - Override_Type (waiver, attestation, falsePositive, riskAdjustment, ...)
170
+ * @param {Object} [options] - reason, appliedBy, appliedAt, expiresAt, status, impact
171
+ * @returns {Object}
172
+ */
173
+ export function createStatusOverride(type, options = {}) {
174
+ const override = {
175
+ type,
176
+ reason: options.reason || 'Test override',
177
+ appliedBy: options.appliedBy || { type: 'simple', identifier: 'test' },
178
+ appliedAt: options.appliedAt || '2025-01-01T00:00:00Z',
179
+ expiresAt: options.expiresAt || '2099-12-31T00:00:00Z',
180
+ };
181
+ if (options.status) override.status = options.status;
182
+ if (options.impact) override.impact = options.impact;
183
+ if (!override.status && !override.impact) override.status = 'notApplicable';
184
+ return override;
185
+ }
186
+
187
+ /**
188
+ * Create a minimal valid POA&M (requirement.poams[]). expiresAt is schema-
189
+ * required (a POA&M is time-boxed) and defaults to a far-future constant.
190
+ * @param {string} type - remediation | mitigation | riskAcceptance | vendorDependency
191
+ * @param {Object} [options] - explanation, appliedBy, appliedAt, expiresAt, milestones
192
+ * @returns {Object}
193
+ */
194
+ export function createPoam(type, options = {}) {
195
+ const poam = {
196
+ type,
197
+ explanation: options.explanation || 'Remediation planned',
198
+ appliedBy: options.appliedBy || { type: 'simple', identifier: 'test' },
199
+ appliedAt: options.appliedAt || '2025-01-01T00:00:00Z',
200
+ expiresAt: options.expiresAt || '2099-12-31T00:00:00Z',
201
+ };
202
+ if (options.milestones) poam.milestones = options.milestones;
203
+ return poam;
204
+ }
205
+
206
+ /**
207
+ * Create a Cvss primitive. Only `version` is schema-required; every other CVSS
208
+ * field is passed through from options when present.
209
+ * @param {string} version - CVSS version (e.g. '3.1', '4.0')
210
+ * @param {Object} [options] - source, baseVector, baseScore, baseSeverity, threatVector,
211
+ * threatScore, environmentalVector, environmentalScore, supplementalVector, computedScore, computedSeverity
212
+ * @returns {Object}
213
+ */
214
+ export function createCvss(version, options = {}) {
215
+ const cvss = { version };
216
+ const fields = [
217
+ 'source', 'baseVector', 'baseScore', 'baseSeverity',
218
+ 'threatVector', 'threatScore', 'environmentalVector', 'environmentalScore',
219
+ 'supplementalVector', 'computedScore', 'computedSeverity',
220
+ ];
221
+ for (const f of fields) {
222
+ if (options[f] != null) cvss[f] = options[f];
223
+ }
224
+ return cvss;
225
+ }
226
+
147
227
  // Re-export severity mapping from @mitre/hdf-utilities (canonical location).
148
228
  // Kept here for backwards compatibility — consumers importing from
149
229
  // @mitre/hdf-schema/helpers still get these functions.
150
230
  export { severityToImpact, impactToSeverity } from '@mitre/hdf-utilities';
151
231
 
232
+ import { worstStatus } from '@mitre/hdf-utilities';
233
+
152
234
  /**
153
235
  * Compute the effective status of a requirement from its results and impact.
154
236
  *
@@ -157,10 +239,8 @@ export { severityToImpact, impactToSeverity } from '@mitre/hdf-utilities';
157
239
  * 1. effectiveStatus already set → return it
158
240
  * 2. impact === 0 → notApplicable
159
241
  * 3. No results → notReviewed
160
- * 4. Any "error" result → error
161
- * 5. Any "failed" result → failed
162
- * 6. All "passed" → passed
163
- * 7. Otherwise → notReviewed
242
+ * 4. Worst-wins roll-up of results via the canonical shared ordering
243
+ * (error > failed > passed > notApplicable > notReviewed)
164
244
  *
165
245
  * @param {import('../dist/ts/hdf-results.js').EvaluatedRequirement} requirement
166
246
  * @returns {import('../dist/ts/hdf-results.js').ResultStatus}
@@ -174,31 +254,11 @@ export function computeEffectiveStatus(requirement) {
174
254
  return 'notApplicable';
175
255
  }
176
256
 
177
- const results = requirement.results;
178
- if (!results || results.length === 0) {
179
- return 'notReviewed';
180
- }
181
-
182
- let hasError = false;
183
- let hasFailed = false;
184
- let hasPassed = false;
185
-
186
- for (const result of results) {
187
- switch (result.status) {
188
- case 'error':
189
- hasError = true;
190
- break;
191
- case 'failed':
192
- hasFailed = true;
193
- break;
194
- case 'passed':
195
- hasPassed = true;
196
- break;
197
- }
198
- }
199
-
200
- if (hasError) return 'error';
201
- if (hasFailed) return 'failed';
202
- if (hasPassed) return 'passed';
203
- return 'notReviewed';
257
+ // Worst-wins roll-up via the canonical shared ordering (error > failed >
258
+ // passed > notApplicable > notReviewed); empty results -> notReviewed.
259
+ // NOTE: unlike the full effective-status computation in @mitre/hdf-utilities,
260
+ // this helper deliberately honors an already-set effectiveStatus first (its
261
+ // documented back-compat contract) and does not consult statusOverrides.
262
+ const results = requirement.results ?? [];
263
+ return worstStatus(results.map((result) => result.status));
204
264
  }
package/dist/index.d.ts CHANGED
@@ -11,6 +11,7 @@ export declare const hdfBaselineSchema: Readonly<Record<string, unknown>>;
11
11
  export declare const hdfComparisonSchema: Readonly<Record<string, unknown>>;
12
12
  export declare const hdfEvidencePackageSchema: Readonly<Record<string, unknown>>;
13
13
  export declare const hdfPlanSchema: Readonly<Record<string, unknown>>;
14
+ export declare const hdfRequirementChangeEventSchema: Readonly<Record<string, unknown>>;
14
15
  export declare const hdfResultsSchema: Readonly<Record<string, unknown>>;
15
16
  export declare const hdfSystemSchema: Readonly<Record<string, unknown>>;
16
17
  export declare const affectedPackageSchema: Readonly<Record<string, unknown>>;
@@ -22,6 +23,7 @@ export declare const componentSchema: Readonly<Record<string, unknown>>;
22
23
  export declare const cvssSchema: Readonly<Record<string, unknown>>;
23
24
  export declare const dataFlowSchema: Readonly<Record<string, unknown>>;
24
25
  export declare const epssSchema: Readonly<Record<string, unknown>>;
26
+ export declare const eventsSchema: Readonly<Record<string, unknown>>;
25
27
  export declare const extensionsSchema: Readonly<Record<string, unknown>>;
26
28
  export declare const kevSchema: Readonly<Record<string, unknown>>;
27
29
  export declare const parameterSchema: Readonly<Record<string, unknown>>;