Expand description
Runtime compilation and merging of overlay CloudFormation resource provider schemas on top of the bundled compiled schemas.
Bundled schemas are compiled at build time from raw CloudFormation registry JSON into the compiled representation baked into the binary. This module runs the same transform at engine construction time, so callers can supply additional schemas - for example properties a service has shipped but not yet published to the CloudFormation registry - and have templates using them validate without false findings.
§Merge model
One model, applied uniformly: an overlay may add entries to a collection
and restate a single-valued constraint or a logical group, and it never
silently drops a constraint the bundled schema already carries. Adding an
entry to required or to a dependency list is stating a constraint, so it can
legitimately produce a finding on a template that violates it; what an overlay
cannot do is make a bundled constraint disappear. Concretely, for every field
of a schema or property:
| Field kind | Rule |
|---|---|
Keyed collections - properties, definitions, patternProperties | deep-merged by key: new keys are added, shared keys recurse |
required | replaced when the overlay states the keyword (even as [] - that is how a requirement is cleared, and a removal is logged); unioned into the base when the keyword is omitted |
Independent-fact collections - the /properties/... lifecycle metadata lists, and each key of dependentRequired/dependentExcluded | unioned, order-preserving, deduplicated |
Single-valued constraints - type, pattern, const, numeric bounds, lengths, item and property counts, uniqueItems, format, additionalProperties, not.enum | replaced when the overlay supplies them, inherited otherwise |
Logical groups - requiredOr, requiredXor, primaryIdentifier | replaced as a whole when supplied. Each is one group (“at least one of”, “exactly one of”, “these properties identify the resource”), so unioning two groups would fabricate a third constraint that neither schema states |
Composition - allOf/anyOf/oneOf/if-then-else | replaced when supplied, because a complete overlay restates the whole composition and appending would duplicate branches. allOf splits into plain and conditional entries during compilation, so an overlay supplying allOf replaces both halves together |
Singleton subschemas - items (the schema every array element must satisfy) | deep-merged, like one keyed entry: an overlay stating only pattern narrows the element schema without discarding the rest of it |
Schema-level metadata - replacementStrategy, documentationUrl, sourceUrl | replaced when supplied. These enrich reporting and constrain nothing |
| Enums | enum and enumCaseInsensitive are two representations of one field and are never both populated for a property. Supplying either replaces whichever the bundled schema used, keeping the bundled comparison semantics: widening a case-insensitive enum with a plain enum stays case-insensitive, so previously accepted casings keep validating |
A $ref is never folded into the property that points at it. An overlay
extending a $ref property has its fields merged beside the reference, and
PropSchema::resolve combines the
whole chain at validation time - each hop’s own constraints applied over its
target, nearest hop winning. So a constraint-only overlay (say, just enum)
takes effect, a chain of references is followed to its end, and a definition
changed by a later overlay still reaches every property referencing it. It
also means the merge never depends on the order definitions are visited in.
Within a chain the same rules decide each field, so a hop that restates a
single-valued constraint overrides the one further along, while collections
accumulate across every hop.
An overlay that supplies a $ref for a property updates the reference target
(ref_name) but preserves the base property’s existing inline/additive
constraints (e.g. pattern, maxLength). This means an overlay can redirect a
property to a different definition without discarding constraints the bundled
schema already carries.
Overlays for the same type are applied in the order given; a later overlay sees the result of the earlier ones.
§Scope limits
- An overlay cannot remove an entry from a lifecycle metadata list - those
collections only ever grow.
requiredis the one collection with replacement semantics (below), and any requirement a replacement removes is logged. - Composition entries (
allOf/anyOf/oneOfbranches) are full property schemas: branchrequired,additionalProperties, dependency maps, value constraints, and nested conditionals are all evaluated when the branch is matched or (for a selectedthen/elsebranch) enforced. - Constructs the compiled model does not represent - a
$refoutside#/definitions/, tuple-formitems, an unknown property type, malformed keyword values, or invalid regular expressions - are rejected. - Validation keywords with no compiled representation (
propertyNames,contains, andnotother thannot.enum) are rejected.multipleOfanddependencies(array-form property dependencies) ARE represented and accepted. - Constraint siblings beside a
$refare accepted when they have a compiled representation (e.g.pattern,maxLength,enum). Only genuinely unrepresented keywords are rejected. Annotation-only siblings (description,title) are always accepted. Bundled schemas are compiled with draft-07$refevaluation instead (siblings ignored), so the engine never enforces more than CloudFormation’s own contract on them; an overlay author states siblings deliberately and gets them enforced. enumandenumCaseInsensitiveare one field in two comparison modes; an overlay cannot switch a property the service treats case-insensitively over to case-sensitive comparison, because doing so would reject casings that validate today.requiredhas authoritative replacement semantics: an overlay that explicitly statesrequired(even asrequired: []) replaces the prior required list at that schema level, including clearing it. Omittingrequiredfrom the overlay preserves the base’s list unchanged.- Conditional constraints the build pipeline contributes as extension fragments are validated from a separate embedded artifact that overlays do not merge into, so an overlay cannot suppress a finding originating there.
- Schema-level metadata (
documentationUrl,sourceUrl,replacementStrategy) alone is not sufficient - the overlay must carry at least one validatable constraint. Metadata enriches diagnostic context only when combined with properties, required, or other constraints. Annotations such asdescriptionare accepted anywhere and compiled to nothing: they have no validation meaning and no reader, so an overlay stating only a description changes nothing. - Overlay-derived resource types, GetAtt attributes and types, Ref return types, primary identifiers, and schema metadata are propagated to both rule engines. Region-specific availability and enum snapshots remain bundled.
§Catalog vs. config separation
The SchemaValidator separates its schema store
(the validated/merged catalog of all compiled schemas) from its construction
config (SchemaValidatorConfig) so embedders
can serialize/deserialize the config and rebuild the validator without keeping
the merged store around. The overlay catalog exposes overlay-aware metadata
(type names, GetAtt/Ref types, primary identifiers) without re-merging.
Enums§
- Schema
Overlay Error - Why an overlay schema was rejected.
Constants§
- MAX_
OVERLAY_ DEPTH - Maximum JSON nesting accepted in an overlay schema.