Skip to content

@mitre/hdf-parsers ​

Parse and load Heimdall Data Format (HDF) documents with validation. Provides a simple, type-safe API for reading HDF Results and Baselines from JSON with automatic schema validation.

Scope and Responsibilities ​

hdf-parsers provides validated parsing of HDF documents:

  • Parse HDF Results, Baseline, System, Plan, Evidence Package, and Comparison documents from JSON
  • Automatic schema validation via hdf-validators
  • Auto-detection of document type across those six document types
  • Type-safe output using hdf-schema types
  • Detailed error reporting with validation messages
  • Support for both TypeScript and Go implementations

hdf-parsers vs. hdf-validators ​

hdf-parsershdf-validators
Parse JSON → typed objectsValidate JSON against schema
"Load and validate this HDF file""Is this valid HDF?"
Returns typed HDFResults/HDFBaselineReturns validation errors
One-step parse + validateSchema validation only
Used by CLI commands and toolsUsed internally by parsers

Example:

  • validateResults(data) → { valid: true, errors: [] } (validators - just validates)
  • parseResults(json) → { success: true, data: HDFResults } (parsers - validates AND parses)

Installation ​

bash
npm install @mitre/hdf-parsers

Usage ​

TypeScript ​

typescript
import { parseResults, parseBaseline, parseSystem, parsePlan, parseEvidencePackage, parseComparison, parse } from '@mitre/hdf-parsers';

// Parse HDF Results
const json = '{"baselines":[...],"targets":[],"statistics":{}}';
const result = parseResults(json);

if (result.success) {
  console.log('Parsed HDF Results:', result.data);
  console.log('Number of baselines:', result.data.baselines?.length);
} else {
  console.error('Parse failed:', result.error);
}
typescript
// Parse HDF Baseline
const baselineJson = '{"name":"My Baseline","requirements":[...],...}';
const baselineResult = parseBaseline(baselineJson);

if (baselineResult.success) {
  console.log('Baseline name:', baselineResult.data.name);
  console.log('Requirements:', baselineResult.data.requirements.length);
}
typescript
// Auto-detect document type
const unknownJson = '...'; // Any of the six detected document types
const autoResult = parse(unknownJson);

if (autoResult.success) {
  console.log('Document type:', autoResult.type); // "results" | "baseline" | "system" | "plan" | "evidencePackage" | "comparison"
  console.log('Parsed data:', autoResult.data);
}
typescript
// Parse from Uint8Array (e.g., file reads)
import { readFileSync } from 'fs';

const bytes = readFileSync('scan-results.json');
const result = parseResults(bytes);

Go ​

go
package main

import (
	"fmt"
	"os"

	parsers "github.com/mitre/hdf-libs/hdf-parsers/go/v3"
)

func main() {
	// Read HDF file
	data, err := os.ReadFile("results.json")
	if err != nil {
		panic(err)
	}

	// Parse HDF Results
	result := parsers.ParseResults(data)

	if result.Success {
		fmt.Println("✓ Parsed HDF Results")
		fmt.Printf("Baselines: %d\n", len(result.Data.Baselines))
	} else {
		fmt.Println("✗ Parse failed:")
		fmt.Println(result.Error)
		os.Exit(1)
	}
}
go
// Parse HDF Baseline
result := parsers.ParseBaseline(baselineData)

if result.Success {
	fmt.Println("Baseline name:", result.Data.Name)
	fmt.Printf("Requirements: %d\n", len(result.Data.Requirements))
}
go
// Auto-detect document type
result := parsers.Parse(data)

if result.Success {
	fmt.Println("Document type:", result.Type) // "results", "baseline", "system", "plan", "evidencePackage", or "comparison"
}

API Reference ​

TypeScript ​

parseResults(input: string | Uint8Array): ParseResult<HDFResults> ​

Parse HDF Results document from JSON string or bytes.

  • Parameters:
    • input - JSON string or Uint8Array to parse
  • Returns: ParseResult<HDFResults> with parsed data or error

parseBaseline(input: string | Uint8Array): ParseResult<HDFBaseline> ​

Parse HDF Baseline document from JSON string or bytes.

  • Parameters:
    • input - JSON string or Uint8Array to parse
  • Returns: ParseResult<HDFBaseline> with parsed data or error

parseSystem(input: string | Uint8Array): ParseResult<HDFSystem> ​

parsePlan(input: string | Uint8Array): ParseResult<HDFPlan> ​

parseEvidencePackage(input: string | Uint8Array): ParseResult<HDFEvidencePackage> ​

parseComparison(input: string | Uint8Array): ParseResult<HDFComparison> ​

Typed parsers for the other HDF document types, with the same input handling and ParseResult shape as parseResults.

parse(input: string | Uint8Array): ParseResult<HDFResults | HDFBaseline | HDFSystem | HDFPlan | HDFEvidencePackage | HDFComparison> ​

Parse HDF document with auto-detection of type. Detection is by root-level discriminator, checked in this order: baselines (results), requirementDiffs (comparison), assessments (plan), contents (evidence package), name with requirements (baseline), then components (system).

  • Parameters:
    • input - JSON string or Uint8Array to parse
  • Returns: ParseResult with parsed data, type indicator, or error

ParseResult<T> ​

typescript
interface ParseResult<T> {
  success: boolean;           // True if parsing succeeded
  data?: T;                   // Parsed data (undefined if failed)
  error?: string;             // Error message (undefined if succeeded)
  type?: 'results' | 'baseline' | 'system' | 'plan' | 'evidencePackage' | 'comparison';  // Document type (only for parse())
}

flattenOverlays(results: HDFResults): FlattenResult ​

Flatten overlay and wrapper baselines in a parsed Results document into their root baselines. Handles deep nesting (overlay chains sharing control IDs via parentBaseline), wide nesting (wrapper profiles aggregating independent bases), and hybrids of both. Returns the flattened results plus metadata describing each merge (FlattenMetadata, BaselineMerge).

normalizeTimestamps(input: string): string ​

Rewrite zone-less ISO timestamps in raw JSON text to UTC (Z) so both language implementations parse them identically. Every parser above applies it before parsing.

Go ​

ParseResults(input []byte) ResultsParseResult ​

Parse HDF Results document from JSON bytes.

  • Parameters:
    • input - JSON bytes to parse
  • Returns: ResultsParseResult with parsed data or error

ParseBaseline(input []byte) BaselineParseResult ​

Parse HDF Baseline document from JSON bytes.

  • Parameters:
    • input - JSON bytes to parse
  • Returns: BaselineParseResult with parsed data or error

ParseSystem(input []byte) SystemParseResult ​

ParsePlan(input []byte) PlanParseResult ​

ParseEvidencePackage(input []byte) EvidencePackageParseResult ​

ParseComparison(input []byte) ComparisonParseResult ​

Typed parsers for the other HDF document types; each result type carries Success, a typed Data pointer, and Error, like ResultsParseResult.

Parse(input []byte) ParseResult ​

Parse HDF document with auto-detection of type, using the same root-level discriminators as the TypeScript parse().

  • Parameters:
    • input - JSON bytes to parse
  • Returns: ParseResult with parsed data, type indicator, or error

FlattenOverlays(results hdf.HDFResults) FlattenResult ​

Go twin of flattenOverlays: merges overlay and wrapper baselines into their roots and returns the flattened Results with Metadata (FlattenMetadata, BaselineMerge, MergePattern).

NormalizeTimestamps(input []byte) []byte ​

Go twin of normalizeTimestamps; every parser above applies it before decoding.

Parse Result Types ​

go
type ResultsParseResult struct {
    Success bool            `json:"success"`
    Data    *hdf.HDFResults `json:"data,omitempty"`
    Error   string          `json:"error,omitempty"`
}

type BaselineParseResult struct {
    Success bool             `json:"success"`
    Data    *hdf.HDFBaseline `json:"data,omitempty"`
    Error   string           `json:"error,omitempty"`
}

type ParseResult struct {
    Success bool        `json:"success"`
    Data    interface{} `json:"data,omitempty"`
    Error   string      `json:"error,omitempty"`
    Type    string      `json:"type,omitempty"` // "results", "baseline", "system", "plan", "evidencePackage", or "comparison"
}

Common Parse Errors ​

Invalid JSON Syntax ​

error: "Invalid JSON: Unexpected token } in JSON at position 42"

Ensure the input is valid JSON. Check for:

  • Missing or extra commas
  • Unquoted property names
  • Trailing commas in objects/arrays

Schema Validation Failure ​

error: "Schema validation failed: baselines: is required"

The JSON is valid but doesn't match the HDF schema. Common issues:

  • Missing required fields (baselines, name, requirements)
  • Wrong field types (string instead of number)
  • Invalid enum values (status must be passed/failed/error/etc.)

Empty Input ​

error: "Input is empty"

Provide non-empty JSON content.

Trailing Data ​

error: "Invalid JSON: unexpected trailing data after end of object"

The JSON has extra characters after the closing brace. Remove any trailing content.

Use Cases ​

CLI Commands ​

Parse HDF files for CLI operations:

typescript
import { parseResults } from '@mitre/hdf-parsers';
import { readFileSync } from 'fs';

const data = readFileSync(inputFile, 'utf-8');
const result = parseResults(data);

if (!result.success) {
  console.error(`Failed to parse ${inputFile}: ${result.error}`);
  process.exit(1);
}

// Process the validated HDF data
processResults(result.data);

Converter Input Validation ​

Validate HDF input before conversion:

typescript
import { parseResults } from '@mitre/hdf-parsers';

export function convertHdfToCsv(hdfJson: string): string {
  const result = parseResults(hdfJson);

  if (!result.success) {
    throw new Error(`Invalid HDF input: ${result.error}`);
  }

  // Convert validated data
  return buildCsv(result.data);
}

HTTP API Endpoints ​

Parse and validate HDF uploads:

typescript
app.post('/api/upload', async (req, res) => {
  const result = parseResults(req.body);

  if (!result.success) {
    return res.status(400).json({
      error: 'Invalid HDF document',
      details: result.error
    });
  }

  // Store validated HDF data
  await storeResults(result.data);
  res.json({ success: true });
});

Type-Safe Processing ​

Get type-safe HDF objects:

typescript
import { parseResults } from '@mitre/hdf-parsers';
import type { HDFResults } from '@mitre/hdf-schema';

function processResults(data: HDFResults) {
  // TypeScript knows the exact structure
  for (const baseline of data.baselines ?? []) {
    console.log(`Baseline: ${baseline.name}`);

    for (const req of baseline.requirements ?? []) {
      console.log(`  Requirement ${req.id}: ${req.results?.length ?? 0} results`);
    }
  }
}

const result = parseResults(jsonData);
if (result.success) {
  processResults(result.data); // Type-safe!
}

Error Handling Best Practices ​

Always Check success Flag ​

typescript
const result = parseResults(data);

if (!result.success) {
  // Handle error - data is undefined here
  console.error(result.error);
  return;
}

// TypeScript knows data exists here
console.log(result.data.baselines);

Provide User-Friendly Error Messages ​

typescript
const result = parseResults(userInput);

if (!result.success) {
  if (result.error.includes('JSON')) {
    console.error('File contains invalid JSON syntax');
  } else if (result.error.includes('Schema validation')) {
    console.error('File does not match HDF format');
  } else {
    console.error('Failed to parse HDF file');
  }

  console.error('Details:', result.error);
}

Log Validation Errors for Debugging ​

typescript
import { parseResults } from '@mitre/hdf-parsers';
import { validateResults } from '@mitre/hdf-validators';

// For detailed debugging, use validator directly
const validationResult = validateResults(jsonData);

if (!validationResult.valid) {
  console.error('Validation errors:');
  for (const error of validationResult.errors) {
    console.error(`  ${error.field}: ${error.message}`);
  }
}

// For normal use, parser is simpler
const parseResult = parseResults(jsonData);

Development ​

bash
# Install dependencies
pnpm install

# Run TypeScript tests
pnpm test:ts

# Run Go tests
pnpm test:go

# Run all tests
pnpm test

# Run tests with coverage
pnpm test:coverage

# Build TypeScript package
pnpm build

# Lint code
pnpm lint

Test Coverage ​

Both TypeScript and Go implementations maintain >95% test coverage with comprehensive parsing tests. Run pnpm test:coverage to view current coverage report.

License ​

Apache-2.0 © MITRE Corporation

Released under the Apache 2.0 License.