Compliance as Code

Automatically Enforcing Governance and Security Policies


3. Compliance Engine: Enforcing Policy on Your Graph

After rescile builds the foundational graph from your assets and models, it enters the compliance phase. In this phase, the Compliance Engine processes declarative rules from TOML files in data/compliance/ to automatically mutate the graph, ensuring it adheres to your organization’s security and governance policies.

This “compliance-as-code” approach makes your security posture auditable, version-controlled, and consistently applied across your entire hybrid estate.

Core Structure of a Compliance File

A compliance file defines an audit_id for the framework it represents and contains one or more [[control]] blocks. Each control has an id, a name, and a [control.config] table to store parameters. The [[control.target]] blocks define what to change in the graph.

data/compliance/bafin.toml

audit_id = "BAFIN-VAIT"
audit_name = "Supervisory Requirements for IT in Financial Institutions"

[[control]]
id = "VAIT-7.2"
name = "Database Encryption in Transit"
# A key-value store for control parameters.
[control.config]
min_tls_version = "1.2"
status = "mandatory"

# Defines where and how to apply the control.
[[control.target]]
relation_origin_type = "application"
relation_target_type = "database"
properties_from_config = ["min_tls_version", "status"]

Common Mutation Patterns

1. Enriching Connections

Use Case: Add security requirements or metadata to existing relationships. This pattern finds all relations between two resource types and adds properties to them from the [control.config] block.

  • Result: Every relation between an application and database now has a controls property containing an object with the control’s details and the specified config values.
graph TD App[application] -- "database
Enriched with:
controls: [{ control_id: 'VAIT-7.2', ... }]" --> DB[database]

2. Attaching New Control Resources

Use Case: Model a policy that applies to a resource, such as an MFA requirement. This pattern finds matching resources, creates a new resource representing the policy, and links it to the original resource.

[[control]]
id = "SEC-MFA-01"
name = "MFA for Privileged Identities"

[[control.target]]
origin_resource_type = "identity"
match_on = [ { property = "privileged", value = "true" } ]

[control.target.resource]
type = "security_control"
name = "mfa_for_{{origin_resource.name}}"

[control.target.resource.properties] # Define properties directly
mfa_required = true
mfa_types = ["TOTP", "FIDO2"]

[control.target.relation]
type = "APPLIES_TO"
  • Result: A privileged identity gets a new security_control resource linked to it.
graph TD subgraph Before I1[identity
name: admin
privileged: true] end subgraph After I2[identity
name: admin
privileged: true] -->|APPLIES_TO| SC[security_control
mfa_required: true] end

Advanced: Linking the New Resource to Others

In more complex scenarios, the new control resource you create might itself need to be linked to other existing parts of your architecture. You can achieve this by adding a [[control.target.resource_links]] block.

Use Case: An internal application must have a specific firewall rule. The control should create the firewall_rule resource and then link that new rule to the existing network_zone it applies to.

[[control]]
id = "NET-SEG-01"
name = "Segment Internal Apps"

[[control.target]]
# 1. Find the internal application.
origin_resource_type = "application"
match_on = [ { property = "environment", value = "internal" } ]

# 2. Define the new 'firewall_rule' resource to attach.
[control.target.resource]
type = "firewall_rule"
name = "rule_for_{{origin_resource.name}}"
[control.target.resource.properties]
action = "allow"

# 3. Link the application to the new rule.
[control.target.relation]
type = "HAS_RULE"

# 4. Add a secondary link from the new rule to an existing network zone.
[[control.target.resource_links]]
[control.target.resource_links.relation]
type = "APPLIES_TO_ZONE"
[control.target.resource_links.resource]
type = "network_zone"
match_on = [ { property = "name", value = "internal-zone" } ]

This pattern allows you to insert new control artifacts into your graph and immediately connect them to the relevant architectural components in a single, declarative rule.

3. Linking Existing Resources

Use Case: Create a new relationship between existing resources to enforce a policy, such as forcing all internet-facing applications to be protected by a central Web Application Firewall (WAF).

[[control]]
id = "SEC-WAF-01"
name = "WAF for Edge Applications"
[control.config]
protection_level = "standard"

[[control.target]]
# 1. Find all origin applications on the 'edge' network.
origin_resource_type = "application"
match_on = [ { property = "network", value = "edge" } ]

# 2. Find the single existing target resource to link to.
[control.target.resource]
type = "gateway"
match_on = [ { property = "name", value = "waf-edge-gw" } ]

# 3. Define the new relation to create between them.
[control.target.relation]
type = "PROTECTED_BY"
  • Result: Creates a PROTECTED_BY relationship from every application on the edge network to the waf-edge-gw gateway.

4. Convention-Based Responsibility Mapping ([control.target.map])

Use Case: Model ownership and responsibility across the entire graph with a single, declarative rule. Instead of writing dozens of individual rules, this advanced pattern discovers roles from the graph itself (e.g., from a role.csv file) and automatically creates the appropriate HAS_RESPONSIBILITY relationships between assets and providers.

This powerful pattern, which is key to managing organizational responsibility at scale, is covered in detail in the Advanced Modeling documentation.

Verifying Compliance with GraphQL

After the importer runs, you can use GraphQL to audit your compliance posture. To check if the database encryption control was applied to billing-api, you can query its database relation:

query VerifyComplianceEnrichment {
  application(filter: {name: "billing-api"}) {
    name
    database {
      properties {
        relation
        controls {
          control_id
          min_tls_version
          status
        }
      }
      node { name }
    }
  }
}