HushSpec/Docs
HUSHED · MMXXVI
Documentation v1.0
v1.0.0guidestable

Merge Semantics#

HushSpec supports policy inheritance via the extends field. When a child policy extends a base, the merge_strategy controls how they combine.

The merge result is a resolved document: extends and merge_strategy are consumed during resolution and omitted from the merged output. Engines evaluate only resolved documents; evaluating a child whose extends has not been resolved silently drops the base policy.

Under every strategy, a child metadata object replaces the base's entirely; when the child omits metadata, the base's is kept.

Strategies#

deep_merge (default)#

Child rules override base rules at the individual rule-block level. If the child defines rules.egress, it replaces the base's rules.egress entirely, including its when condition. Rules not defined in the child are preserved from the base.

Extensions use their companion-spec merge rules under deep_merge:

  • posture merges states by name and replaces transitions with the child's list
  • origins merges profiles by id and preserves default_behavior when omitted
  • detection merges subsections independently and preserves omitted subsection fields

merge#

For core rules, merge matches deep_merge in HushSpec v1.

For extensions, merge is shallower: if the child defines an extension block, that block replaces the base extension block entirely. Unspecified extension blocks are still preserved from the base.

replace#

The child document entirely replaces the base. No fields from the base are preserved.

Example#

Each YAML block below is a complete file; save both in the same directory.

yaml
# base.yaml
hushspec: "1.0.0"
name: base
rules:
  egress:
    allow: ["a.com"]
    default: block
  forbidden_paths:
    patterns: ["**/.ssh/**"]
yaml
# child.yaml
hushspec: "1.0.0"
name: child
extends: base.yaml
rules:
  egress:
    allow: ["b.com"]
    default: allow

Result: egress uses child's config (b.com, allow). forbidden_paths preserved from base.

Resolution Order#

Resolve from the oldest base toward the leaf, applying each child's strategy at its hop. Three files root.yaml -> team.yaml -> agent.yaml do not concatenate lists: each explicitly supplied rule block replaces that block from the previous result. extends and merge_strategy disappear from the resolved output. Use h2h resolve agent.yaml and review the result before evaluating it.

Cycles, missing bases, malformed pins, digest mismatches and chains beyond the 32-hop limit refuse the whole load. Do not recover by evaluating only the leaf. See core resolution.

Strategy Comparison#

Child strategyCore rule blocksExtensionsMetadata
deep_mergeReplace supplied blocks; preserve othersCompanion-specific mergeReplace whole object if supplied
mergeSame core behaviorReplace supplied extension blocksReplace whole object if supplied
replaceChild onlyChild onlyChild only

Extension Merge Rules#

For deep_merge, posture replaces states by name and the transition list; origins replaces profiles by ID; detection merges subsection fields. This inheritance behavior is different from origin projection, which narrows a resolved policy for a request.

Note on Merge Helpers#

HushSpec does not support additional_* or remove_* fields. These are engine-specific features. If you need additive pattern management, use your engine's native format.

Loading documentation index…

↑↓ navigate↵ openesc close