Quick Start

A step-by-step guide to building an infrastructure dependency graph with rescile.


Rescile Quick Start Guide

This guide will walk you through building a dependency graph of your infrastructure using rescile-ce.

We’ll start with a minimal “Hello, World” example and progressively build a more realistic model representing a hybrid environment with on-premise and cloud resources, including applying a compliance control.

Before You Begin

To follow this guide, you need the rescile-ce binary installed and accessible in your system's PATH. You can verify the installation by running rescile-ce --version. Download the latest version or run rescile-ce update.

For easy project based setup have a look into the bootstrap repository.

First, let’s create a project folder named my-infra-graph and the necessary subdirectories:

mkdir -p my-infra-graph/data/{assets,models,compliance,reports}
cd my-infra-graph

All subsequent file paths in this guide will be relative to the my-infra-graph directory.


Step 1: The “Hello, World” Graph - Creating a Derived Resource

Goal: Model a single application and derive a server resource from it. This demonstrates the core workflow: Assets -> Models -> Compliance -> Reports.

flowchart LR subgraph "Phase 1: Ground Truth" A["
Assets
Define components
in CSV files.
"] end subgraph "Phase 2: Architecture" B["
Models
Transform assets
with TOML files.
"] end subgraph "Phase 3: Governance" C["
Compliance
Enforce policies
with TOML files.
"] end subgraph "Phase 4: Output" R["
Output
Generate artifacts
with TOML files.
"] end subgraph "Result" G["
Queryable Graph
A digital twin
of your estate.
"] end A -- "Provide Ground Truth" --> B -- "Define Architecture" --> C -- "Enforce Policy" --> R -- "Generate Artifacts" --> G

1. Define the Foundational Asset

Assets are the ground truth of your environment. Create a CSV file to define a single application. The filename (application.csv) becomes the resource’s type, and the first column (name) is its primary key.

data/assets/application.csv

name,owner,runtime
billing-api,team-alpha,java

2. Create an Architectural Model

Models transform assets into a richer graph. We will create a server.toml model that unconditionally creates one server resource for every application resource.

data/models/server.toml

# The origin resource type to read from (from application.csv).
origin_resource = "application"

# The [[create_resource]] block defines a rule for creating new resources.
# Since there is no 'match_on' key, this rule applies to every 'application' resource.
[[create_resource]]
# The type of the new resource.
resource_type = "server"
# The type of the new relation.
relation_type = "RUNS_ON"
# The primary key (name) for the new server.
# The template `{{origin_resource.name}}` accesses the 'name' property of the application.
name = "{{origin_resource.name}}_server"
# Define properties for the newly created server resource.
[create_resource.properties]
os = "Linux"
managed_by = "{{origin_resource.owner}}" # Inherit the owner from the application

3. Build and Verify the Graph

Now, run the rescile-ce command-line tool to process your assets and models and generate the graph.

# Start the server
rescile-ce --data-dir ./data serve

Open your browser to http://localhost:7600 and run the following query in the GraphiQL interface:

query VerifySimpleGraph {
  application(filter: {name: "billing-api"}) {
    name
    owner
    server {
      properties {
        relation
      }
      node {
        name
        os
        managed_by
      }
    }
  }
}
{
  "data": {
    "application": [
      {
        "name": "billing-api",
        "owner": "team-alpha",
        "server": [
          {
            "properties": {
              "relation": "RUNS_ON"
            },
            "node": {
              "name": "billing-api_server",
              "os": "Linux",
              "managed_by": "team-alpha"
            }
          }
        ]
      }
    ]
  }
}
  1. An application resource named billing-api.
  2. A server resource named billing-api_server with properties os="Linux" and managed_by="team-alpha".
  3. An relation type RUNS_ON connecting (application:billing-api) to (server:billing-api_server).
graph TD App["application
billing-api"] -- RUNS_ON --> Server["server
billing-api_server
{os: Linux,
managed_by: team-alpha}"]

Before the start with step 2, we will save the current graph to compare at the end of the step.

rescile-ce --data-dir ./data save step1.json

Step 2: A Hybrid Cloud Model with Compliance

Goal: Expand the graph to model a hybrid environment. We will:

  1. Distinguish between on-premise and cloud applications.
  2. Use conditional logic (match_on) to create different platform resources.
  3. Introduce a new database asset and an automatic relationship.
  4. Apply a compliance control to enforce encryption on database connections.

1. Enhance the Assets

Update application.csv with platform and database columns. The database column acts as a foreign key, automatically creating a relationship to a resource defined in database.csv.

data/assets/application.csv

name,owner,runtime,platform,database
billing-api,team-alpha,java,on-prem,billing-db-prod
frontend-app,team-bravo,nodejs,cloud,user-db-prod

Now, create the database asset file.

data/assets/database.csv

name,type,version
billing-db-prod,PostgreSQL,14
user-db-prod,MySQL,8.0

2. Create a Conditional Model for Platforms

This model will read application resources and, based on the platform property, create either an onprem_datacenter or a cloud_provider resource, demonstrating how to model hybrid infrastructure.

data/models/platform.toml

origin_resource = "application"

# Rule 1: For on-premise applications.
[[create_resource]]
# This rule only applies if the application's 'platform' property is 'on-prem'.
match_on = [
  { property = "platform", value = "on-prem" }
]
resource_type = "onprem_datacenter"
relation_type = "HOSTED_IN"
name = "dc-frankfurt" # A static name for our on-prem DC
[create_resource.properties]
location = "Frankfurt"
operator = "internal-hosting"

# Rule 2: For cloud applications.
[[create_resource]]
match_on = [
  { property = "platform", value = "cloud" }
]
resource_type = "cloud_provider"
relation_type = "HOSTED_BY"
name = "aws-eu-central-1" # A static name for our cloud provider region
[create_resource.properties]
region = "eu-central-1"
vendor = "AWS"

3. Define a Compliance Control

Compliance files are processed after the main graph is built. This control will find all connections between an application and a database and enrich the connecting relation with a security requirement.

data/compliance/security.toml

audit_id = "INTERNAL-SEC-POLICY"
audit_name = "Internal Security Policy"

[[control]]
id = "SEC-DB-01"
name = "Database Encryption in Transit"

# A key-value store for control parameters.
[control.config]
min_tls_version = "1.2"
status = "mandatory"

[[control.target]]
# This pattern targets an existing RELATIONSHIP.
# Find all relations between an 'application' and a 'database'.
relation_origin_type = "application"
relation_target_type = "database"

# Copy these keys from [control.config] onto the properties of the matched relation.
properties_from_config = ["min_tls_version", "status"]

4. Build and Verify the Hybrid Graph

Re-run the rescile-ce commands to build and view the new graph.

# Start the server to query with GraphQL
rescile-ce --data-dir ./data serve

Verification with GraphQL: Run these queries in GraphiQL at http://localhost:7600.

Query 1: Verify Hybrid Platform Creation This query checks that the conditional platform.toml model worked correctly.

query VerifyHybridPlatforms {
  # Check the on-prem application
  onPremApplication: application(filter: {name: "billing-api"}) {
    name
    onprem_datacenter {
      node {
        name
        location
      }
    }
  }
  # Check the cloud application
  cloudApplication: application(filter: {name: "frontend-app"}) {
    name
    cloud_provider {
      node {
        name
        vendor
      }
    }
  }
}
{
  "data": {
    "onPremApplication": [
      {
        "name": "billing-api",
        "onprem_datacenter": [
          {
            "node": {
              "name": "dc-frankfurt",
              "location": "Frankfurt"
            }
          }
        ]
      }
    ],
    "cloudApplication": [
      {
        "name": "frontend-app",
        "cloud_provider": [
          {
            "node": {
              "name": "aws-eu-central-1",
              "vendor": "AWS"
            }
          }
        ]
      }
    ]
  }
}

You will see billing-api is HOSTED_IN the onprem_datacenter named dc-frankfurt, while frontend-app is HOSTED_BY the cloud_provider aws-eu-central-1.

Query 2: Verify Compliance Enrichment This query checks that the security.toml control was applied to the relation between the application and the database.

query VerifyComplianceEnrichment {
  application(filter: {name: "billing-api"}) {
    name
    database {
      # The 'properties' block queries the relation itself.
      properties {
        relation
        controls # The importer groups compliance properties under 'controls'
      }
      # The 'node' block queries the connected database resources.
      node {
        name
        type
      }
    }
  }
}
{
  "data": {
    "application": [
      {
        "name": "billing-api",
        "database": [
          {
            "properties": {
              "relation": "database",
              "controls": [
                {
                  "audit_id": "INTERNAL-SEC-POLICY",
                  "audit_name": "Internal Security Policy",
                  "control_id": "SEC-DB-01",
                  "control_name": "Database Encryption in Transit",
                  "min_tls_version": 1.2,
                  "status": "mandatory"
                }
              ]
            },
            "node": {
              "name": "billing-db-prod",
              "type": "PostgreSQL"
            }
          }
        ]
      }
    ]
  }
}

The result will show the database relation with a controls array containing an object with audit_id: "INTERNAL-SEC-POLICY", min_tls_version: "1.2", and status: "mandatory".

The final graph should look like this:

graph TD subgraph "Cloud Resources" AppCloud["application
frontend-app"] DBCloud["database
user-db-prod"] PlatformCloud["cloud_provider
aws-eu-central-1"] AppCloud -- "database
{ controls: ... }" --> DBCloud AppCloud -- "HOSTED_BY" --> PlatformCloud end subgraph "On-Premise Resources" AppOnPrem["application
billing-api"] DBOnPrem["database
billing-db-prod"] PlatformOnPrem["onprem_datacenter
dc-frankfurt"] AppOnPrem -- "database
{ controls: ... }" --> DBOnPrem AppOnPrem -- "HOSTED_IN" --> PlatformOnPrem end

If the state has been saved in the previous step, wen can run a comparison.

# Start the graph diff
rescile-ce --data-dir ./data diff step1.json
[...]

Comparing graph step1.json with current in-memory graph

Structural Graph Comparison Result

Resources Added:
  (+) frontend-app (type: application)
  (+) INTERNAL-SEC-POLICY (type: audit)
  (+) aws-eu-central-1 (type: cloud_provider)
  (+) SEC-DB-01 (type: control)
  (+) billing-db-prod (type: database)
  (+) user-db-prod (type: database)
  (+) dc-frankfurt (type: onprem_datacenter)
  (+) frontend-app_server (type: server)

Relations Added:
  (+) (application `billing-api`) --[database]--> (database `billing-db-prod`)
  (+) (application `billing-api`) --[HOSTED_IN]--> (onprem_datacenter `dc-frankfurt`)
  (+) (application `frontend-app`) --[HOSTED_BY]--> (cloud_provider `aws-eu-central-1`)
  (+) (application `frontend-app`) --[database]--> (database `user-db-prod`)
  (+) (application `frontend-app`) --[RUNS_ON]--> (server `frontend-app_server`)
  (+) (control `SEC-DB-01`) --[BELONGS_TO]--> (audit `INTERNAL-SEC-POLICY`)