Skip to content

@mitre/hdf-schema ​

JSON schemas and multi-language type definitions for Heimdall Data Format (HDF).

Overview ​

HDF is a standardized format for representing security assessment results. This package provides:

  • JSON Schemas for validating HDF documents
  • Generated types for TypeScript and Go

Installation ​

bash
npm install @mitre/hdf-schema

Schema Types ​

Eight document types: seven covering the full security assessment lifecycle, plus a continuous-monitoring change-event stream.

HDF Results (hdf-results) ​

Assessment findings from running security checks against target systems. The primary output of converters. Contains evaluated baselines with requirement results, components (hosts, containers, cloud resources), status overrides with disposition tracking, and statistics.

HDF Baseline (hdf-baseline) ​

Security requirement definitions without results — the "what to check" document. Contains requirement metadata (title, descriptions, severity, impact), check/fix instructions, framework mappings (NIST, CCI), and dependency information.

HDF System (hdf-system) ​

Authorization boundary definition. Describes a system's components (with polymorphic types: host, container, cloud account, application, etc.), data flows between components, and control designations (common/hybrid/system-specific).

HDF Plan (hdf-plan) ​

Assessment plan linking baselines to system components. Defines what will be assessed, how, and by whom. References baselines, systems, and runner configurations.

HDF Amendments (hdf-amendments) ​

Standalone amendment documents containing waivers, attestations, POA&Ms, and other overrides. Applied to results via hdf amend apply to track adjudication decisions (false positives, risk adjustments, operational requirements).

HDF Evidence Package (hdf-evidence-package) ​

Bundles references to all documents needed for a compliance review — results, baselines, system, plan, and amendments — with checksums for integrity verification.

HDF Comparison (hdf-comparison) ​

Output of the diff engine. Structural comparison between two or more HDF documents showing requirement-level changes, status transitions, and field diffs.

HDF Requirement Change Event (hdf-requirement-change-event) ​

A continuous-monitoring event stream: one event per requirement whose posture changed between two results scans (new, absent, updated, fixed, regressed). Each event carries the full after-state, a thin before-state, and a per-key sequence, so a reconciled results document can be replayed from a seed. Produced by hdf events derive.

Usage ​

Importing Schemas ​

Schemas can be imported in two ways:

typescript
// Named exports from the barrel (all schemas + types available)
import { hdfResultsSchema, hdfBaselineSchema, hdfSystemSchema } from '@mitre/hdf-schema';
import type { HDFResults, HDFBaseline, HDFSystem, HDFPlan, HDFAmendments, HDFEvidencePackage, HDFComparison, HDFRequirementChangeEvent } from '@mitre/hdf-schema';

// Sub-path imports also work (all resolve to the same combined module)
import type { HDFResults } from '@mitre/hdf-schema/hdf-results';
import type { HDFBaseline } from '@mitre/hdf-schema/hdf-baseline';

Helper functions (severity mapping, effective status computation):

typescript
import { severityToImpact, impactToSeverity, computeEffectiveStatus } from '@mitre/hdf-schema/helpers';

Validating Documents (TypeScript/JavaScript) ​

typescript
import Ajv from 'ajv';
import { hdfResultsSchema } from '@mitre/hdf-schema';

const ajv = new Ajv({ strict: false });
const validate = ajv.compile(hdfResultsSchema);

const isValid = validate(myDocument);
if (!isValid) {
  console.error(validate.errors);
}

Using Generated Types (TypeScript) ​

typescript
import type { HDFResults, HDFBaseline } from '@mitre/hdf-schema';

function processResults(results: HDFResults) {
  for (const baseline of results.baselines) {
    for (const requirement of baseline.requirements) {
      console.log(`${requirement.id}: ${requirement.results[0]?.status}`);
    }
  }
}

Using Generated Types (Go) ​

go
import hdf "github.com/mitre/hdf-libs/hdf-schema/dist/go/v3"

func main() {
    data := []byte(`{"baselines": [...]}`)
    results, err := hdf.UnmarshalHDFResults(data)
    if err != nil {
        panic(err)
    }
    for _, baseline := range results.Baselines {
        fmt.Printf("%s: %d requirements\n", baseline.Name, len(baseline.Requirements))
    }
}

Schema Files ​

FileDescription
src/schemas/hdf-results.schema.jsonAssessment findings (modular, uses $ref)
src/schemas/hdf-baseline.schema.jsonRequirement definitions without results
src/schemas/hdf-system.schema.jsonAuthorization boundary, components, data flows
src/schemas/hdf-plan.schema.jsonAssessment plan linking baselines to components
src/schemas/hdf-amendments.schema.jsonWaivers, attestations, POA&Ms
src/schemas/hdf-evidence-package.schema.jsonBundle of references to all documents
src/schemas/hdf-comparison.schema.jsonDifferential analysis between assessments
src/schemas/hdf-requirement-change-event.schema.jsonContinuous-monitoring per-requirement change-event stream
src/schemas/primitives/*.schema.jsonShared type definitions
dist/schemas/*.schema.jsonBundled schemas (self-contained, all $refs inlined)

Modular vs Bundled Schemas ​

Modular schemas (src/schemas/) use $ref to reference shared definitions from primitive files. Use these if your validator supports $ref resolution.

Bundled schemas (dist/schemas/) have all references inlined. Use these for tools that don't support $ref or for simpler integration.

Generated Types ​

After building, types are available in:

LanguageLocation
TypeScriptdist/ts/hdf.ts (single combined file, all types deduplicated)
Godist/go/hdf.go (single combined file, all types deduplicated)

Development ​

bash
# Install dependencies
pnpm install

# Run tests
pnpm test

# Build everything (schemas + types)
pnpm build

# Build only bundled schemas
pnpm build:schemas

# Build only generated types
pnpm build:types

Versioning ​

This package has two version numbers that serve different purposes:

  • Package version (package.json version): Follows npm semver. Bumped on every release — bug fixes, new helpers, type generation improvements, dependency updates. This is what consumers see in npm install @mitre/hdf-schema@3.0.1.

  • Schema version ($id URL in each .schema.json): Identifies the schema structure itself. Only changes when the schema structure changes — new fields, removed fields, type changes, constraint changes. Example: https://mitre.github.io/hdf-libs/schemas/hdf-results/v3.1.0.

These versions are aligned at major boundaries (both are 3.x to signal this is the successor to the heimdall2 v2.x ecosystem) but can diverge at minor/patch levels. A package patch release (e.g., 3.0.1 → 3.0.2) that only fixes a converter bug or updates a helper function does not change the schema $id. A schema structural change (e.g., adding a new required field) bumps the schema version in the $id URL regardless of where the package version stands.

The $id URLs are also the canonical hosted location for each schema: https://mitre.github.io/hdf-libs/schemas/.

JSON Schema dialect ​

All schemas use JSON Schema draft/2020-12.

Hosted schema documentation ​

Interactive schema reference documentation is published at: https://mitre.github.io/hdf-libs/schemas/

What's new in v3.7.0 ​

  • Milestone.title — optional single-line label. A short label on each POA&M Milestone, suitable where a consumer needs a title (for example an OSCAL POA&M remediation or task). It is optional and does not replace description, which remains the full milestone text; a consumer needing a title where none is supplied derives one. The value carries the project's single-line-label constraint — minLength: 1 plus a pattern (OSCAL's StringDatatype, spelled with explicit character classes so ECMA-262 and Go regexp engines agree) banning line breaks and leading/trailing whitespace.
  • Evidence.data tightened. data now requires minLength: 1 (an empty evidence body no longer validates), and when encoding is exactly base64 (lowercase) the data must be bare base64 matching ^[0-9A-Za-z+/]+={0,2}$ (OSCAL's Base64Datatype): no data: URI prefix, URL, or line breaks. Tightening: a v3.6.x document with an empty data, or with a base64-encoded value that carries a data: prefix or line breaks, now fails validation — strip the prefix/whitespace or correct the encoding label.
  • Compatibility. Milestone.title is additive and optional, so a v3.6.x document validates unchanged under v3.7.0. The Evidence.data change is a validation tightening, not a structural one: documents whose evidence bodies were already non-empty and (for base64) bare validate cleanly; the rest must be corrected. A v3.7.0 document carrying Milestone.title will not validate against the v3.6.x schemas, which reject unevaluated properties; strip the field or validate against v3.7.0.

What's new in v3.6.0 ​

  • preAmendmentChecksum on the Results root. Optional Checksum recording the document's hash as it stood immediately before the most recent amendment application, written by hdf amend apply. It covers the results file's raw bytes as read, not a canonical form, and records only the most recent application rather than accumulating. Distinct from the override-level previousChecksum, which chains amendments to one another over a canonical form. This is the only structural change in v3.6.0; everything else below is description-level.
  • previousChecksum semantics stated precisely (description-only, on Standalone_Override, Status_Override, and the POA&M element) — each amendment's checksum is recorded by the next one, so an in-place edit is detectable only for an amendment that has a later one chained to it. The chain is not tamper-proof: the final amendment, the document envelope, deleted trailing amendments, and a wholesale recompute are outside what it can detect; use signature for non-repudiation. The field is omitted (not null) on the first amendment. This is the contract hdf amend verify enforces.
  • Schema descriptions reflowed into paragraphs and the source files pretty-printed one value per line. Cosmetic in the source, but the bundled dist/schemas/ descriptions now carry paragraph breaks, which IDE tooltips render.
  • computeEffectiveStatus helper delegates to the canonical status ladder in @mitre/hdf-utilities. Behavior change for @mitre/hdf-schema/helpers consumers: the helper no longer returns a pre-set effectiveStatus verbatim, and it now applies the governing non-expired statusOverrides entry and the error roll-up ahead of the impact-0 notApplicable short-circuit, matching the CLI and converters.
  • @mitre/hdf-schema/testhdf sub-path export — test-only builders (req, baseline, doc, results, baselineDoc, override, amendments, system, plan, evidencePackage, changeEvent, comparison, and friends) that construct schema-valid documents for downstream test suites, with a Go counterpart at github.com/mitre/hdf-libs/hdf-schema/testhdf/go.
  • Compatibility. The one schema addition is optional, so v3.5.x documents validate unchanged under v3.6.0. A v3.6.0 document carrying preAmendmentChecksum will not validate against the v3.5.x schemas, which reject unevaluated properties; strip the field or validate against v3.6.0.

What's new in v3.5.0 ​

  • hdf-requirement-change-event document type — a new schema for the continuous-monitoring change-event stream: per-requirement events (new/absent/updated/fixed/regressed) with a full after-state, thin before-state, and per-key sequence, chained for deterministic replay from a seed. Produced by hdf events derive.
  • External_Reference primitive + externalReferences[] wiring — a generalized, STIX-2.1-aligned reference (required sourceName plus one of externalId/href/description, open rel/kind, optional lossless embedded document) wired across the document types, including on the inline Status_Override. Backs the STIX CTI enrichment feature.
  • Change_Reason gains dispositionChanged and effectiveImpactChanged — the diff engine's amendment-axis change reasons are now part of the comparison vocabulary.
  • POA&M expiresAt is now required — a POA&M is a time-boxed acceptance of an open finding; the deadline is no longer optional. Breaking: previously-valid HDF documents with deadline-less POA&Ms now fail validation. Source a real remediation/vendor-fix date.
  • Compatibility. The additions are additive except the required POA&M expiresAt; v3.4.x documents without deadline-less POA&Ms validate cleanly under v3.5.0. See CHANGELOG.

What's new in v3.4.0 ​

  • Generalized boms[] on components — a single boms[] array on Base_Component carries any Bill of Materials (SBOM, ai-model, dataset, or reserved future bomType), each by passthrough (ref/document) or normalized shape. Breaking: replaces the former sbom / sbomRef / sbomFormat trio; a component may now carry several BOMs (e.g. an SBOM plus an ai-model BOM). See primitives/bom.schema.json.
  • aiModel and dataset component types — thin AI-subject components whose detail lives in an attached ai-model / dataset BOM.
  • Generic component integrity[] — one array home for artifact/subject integrity (model weights/shards, dataset archive, container image, package bytes). Breaking: replaces the per-type Container_Image.digest and Artifact.checksum fields.
  • Host identity hostname + domain on Host_Component — short OS-reported name and directory (AD/NetBIOS/LDAP) domain, kept distinct from fqdn (ECS host.hostname / host.domain semantics).
  • agent identity type on Identity — provenance for AI-agent actors.
  • blake3 added to the Hash_Algorithm enum.
  • Compatibility. Additive fields validate v3.3.x documents cleanly; the BOM/integrity field removals are the one breaking change — migrate sbom/sbomRef/sbomFormat to boms[] and per-type digests to integrity[]. See CHANGELOG.

What's new in v3.2.0 ​

  • Combined TypeScript output — all types are now generated into a single dist/ts/hdf.ts via quicktype combined mode. This eliminates the duplicate Identity type bug (same interface from different per-file outputs was not assignable). Sub-path exports (@mitre/hdf-schema/hdf-results, etc.) still work but all resolve to the same module.
  • Canonical type naming via title — all generated enum names are now controlled by explicit title properties in the source schemas. Key renames: Copyright → TargetType, OwnerType → IdentityType, Status → MilestoneStatus, SbomFormat → SBOMFormat, PoamType → POAMType.
  • Deprecated aliases — HdfResults, HdfBaseline, etc. are deprecated type aliases for HDFResults, HDFBaseline. They still compile but consumers should migrate to the HDF* naming.
  • controlType field on Requirement_Core — optional enum (policy | procedure | technical | management | operational) aligning with NIST SP 800-53 / SP 800-53A categories.
  • verificationMethod field on Requirement_Core — optional enum (automated | manual-by-design | manual-pending-automation | hybrid) disambiguating the two cases that null code overloaded.
  • applicability field on Requirement_Core — optional enum (required | optional | advisory) providing a uniform expression for what FedRAMP CORE props, FedRAMP 20x Optional: markers, CIS Implementation Groups, and CMMC sublevels each encode incompatibly today.
  • All schema fields are optional and additive. v3.1.x documents validate cleanly under v3.2.0.

What's new in v3.1.0 ​

  • disposition field on EvaluatedRequirement — the type of the governing override or POAM (e.g., waiver, falsePositive, riskAdjustment). Indicates why a requirement is in its current state.
  • effectiveImpact field on EvaluatedRequirement — the computed impact score (0.0–1.0) after applying the most recent non-expired impact override.
  • Impact_Override type on Status_Override and Standalone_Override — object with a value field (0.0–1.0). At least one of status or impact must be set (enforced via anyOf).
  • Override_Type expansion — added falsePositive, riskAdjustment, operationalRequirement; removed exception (use waiver with status: "notApplicable" instead).
  • vendorDependency added to POAM type enum.
  • Breaking: The ./schemas/<name>.schema.json sub-path export was removed. Use named imports from the barrel (import { hdfResultsSchema } from '@mitre/hdf-schema') instead.

Released under the Apache 2.0 License.