Rule patterns cookbook
Use these reusable patterns when writing policy rules.
Each pattern includes:
- when to use it
- a rule example
- what to verify
Pattern 1: Scope enables control
When to use:
- A scope decision should enable a required control.
- id: WEB_APPLICATION_SERVICE_CONTINUITY_SCOPE
target: component
if:
- eq: { key: type, value: webApplication }
- eq: { key: serviceContinuity, value: inScope }
then:
- expect: { entity: component, control: trafficFiltering }
Verify:
- control appears when
serviceContinuity=inScope - control does not appear when
outOfScope/notAssessed
Pattern 2: Parallel entity parity (api + webApplication)
When to use:
- The same behavior should apply to more than one entity type.
- id: API_SERVICE_CONTINUITY_SCOPE
target: component
if:
- eq: { key: type, value: api }
- eq: { key: serviceContinuity, value: inScope }
then:
- expect: { entity: component, control: trafficFiltering }
- id: WEBAPP_SERVICE_CONTINUITY_SCOPE
target: component
if:
- eq: { key: type, value: webApplication }
- eq: { key: serviceContinuity, value: inScope }
then:
- expect: { entity: component, control: trafficFiltering }
is easier to debug and work with, even if it uses more lines in a file than:
- id: SERVICE_CONTINUITY_SCOPE
target: component
if:
- eq: { key: type, value: [api, webApplication] }
- eq: { key: serviceContinuity, value: inScope }
then:
- expect: { entity: component, control: trafficFiltering }
Verify:
- both entity types trigger identical outcomes
Pattern 3: Value-based scoring map
When to use:
- A config value should map directly to score outcomes.
- id: TRAFFIC_FILTERING_SCORE
target: connection
if:
- eq: { key: type, value: apiConnection }
then:
- map_score:
key: trafficFiltering
map:
"true": 1
"false": -1
default: 0
missing: 0
Verify:
- known values map correctly
- missing/unknown values are deterministic
Pattern 4: Topology-aware prerequisite
When to use:
- A control depends on upstream/downstream context.
- id: SENSITIVE_UPSTREAM_REQUIRES_AUTH
target: component
if:
- eq: { entity: upstream, key: sensitiveData, value: true }
- eq: { key: identity, value: inScope }
then:
- expect: { entity: component, control: hasAuthentication }
Verify:
- only components with matching upstream context are affected
Pattern 5: Derived value before score
When to use:
- You need a normalized derived field before scoring.
- id: DERIVE_RUNTIME_CLASS
stage: init
target: component
if:
- eq: { key: deploymentType, value: managed }
then:
- set: { key: runtimeClass, value: managed }
- id: SCORE_RUNTIME_CLASS
stage: post
target: component
if:
- present: { key: runtimeClass }
then:
- map_score:
key: runtimeClass
map:
managed: 1
unmanaged: -1
Verify:
- derived value exists before score rule executes
Pattern 6: Specification mapping by value
When to use:
- Implementation guidance should vary by config value.
- id: ENCRYPTION_SPEC_HINTS
target: component
if:
- present: { key: encryptionInTransit }
then:
- map_specification:
key: encryptionInTransit
map:
strong ciphers:
- Use modern TLS configuration
none or weak:
- Upgrade transport encryption
Verify:
- correct specification guidance appears for each value
Pattern 7: Rule-level reporting references
When to use:
- You need standards traceability per rule.
- id: WEBAPP_AUTH_REFERENCE
target: component
if:
- eq: { key: type, value: webApplication }
- eq: { key: identity, value: inScope }
then:
- expect: { entity: component, control: hasAuthentication }
reporting:
references:
- standard: NIST CSF 2.0
requirement: PR.AA
Verify:
- reporting output includes the expected rule-level mapping
Pattern 8: Negative guard rule
When to use:
- You need explicit non-compliant signaling for missing values.
- id: MISSING_IDENTITY_SIGNAL
target: component
if:
- eq: { key: type, value: webApplication }
- not:
present: { key: identity }
then:
- score: -1
Verify:
- rule triggers only on genuinely missing/unset state