Advanced Runtime Examples
GraphQL API Chaining
The api engine supports declarative GraphQL queries alongside REST endpoints, enabling seamless integration with GraphQL servers.
# actions/query_infrastructure.toml
name = "query_infrastructure"
description = "Query infrastructure state via GraphQL"
[[input]]
name = "environment"
description = "Target environment"
type = "string"
required = true
[vault_secrets.metrics_token]
collection = "observability"
secret = "metrics_api_token"
[runtime]
engine = "http"
# Native GraphQL support
[[runtime.steps]]
method = "POST"
url = "https://api.internal/graphql"
graphql_query = """
query GetDeployments($env: String!) {
deployments(environment: $env) {
id
name
status
lastDeployed
}
}
"""
[runtime.steps.graphql_variables]
env = "{{ input.environment }}"
[[runtime.steps]]
method = "POST"
url = "https://metrics.internal/graphql"
headers = { "Authorization" = "Bearer ${secrets.metrics_token}" }
graphql_query = """
query GetMetrics($env: String!) {
metrics(environment: $env) {
cpu
memory
requests
}
}
"""
[runtime.steps.graphql_variables]
env = "{{ input.environment }}"
REST API Chaining with Templates
Chain multiple REST API calls with input and secret templating for orchestrated workflows.
# actions/provision_database.toml
name = "provision_database"
description = "Provision a database and configure backups via API chaining"
[[input]]
name = "db_name"
description = "Database name"
type = "string"
required = true
[[input]]
name = "instance_type"
description = "Instance type (small, medium, large)"
type = "string"
default = "medium"
[[mount]]
resource_type = "payload"
origin_resource = "infrastructure"
filename = "create_db_payload.json"
mount_path = "create_db_payload.json"
[vault_secrets.cloud_api_key]
collection = "cloud_credentials"
secret = "api_key"
[vault_secrets.provisioning_token]
collection = "internal_services"
secret = "provisioning_webhook_token"
[runtime]
engine = "http"
# Step 1: Create database instance
[[runtime.steps]]
method = "POST"
url = "https://api.cloud.internal/v1/databases"
headers = { "Authorization" = "Bearer ${secrets.cloud_api_key}", "Content-Type" = "application/json" }
body = "@create_db_payload.json"
# Step 2: Enable automated backups
[[runtime.steps]]
method = "POST"
url = "https://api.cloud.internal/v1/databases/{{ input.db_name }}/backups"
headers = { "Authorization" = "Bearer ${secrets.cloud_api_key}" }
body = """
{
"schedule": "0 2 * * *",
"retentionDays": 30,
"encrypted": true,
"storageClass": "standard"
}
"""
# Step 3: Notify provisioning system
[[runtime.steps]]
method = "POST"
url = "https://provisioning.internal/webhooks/db-created"
headers = { "X-Webhook-Secret" = "${secrets.provisioning_token}" }
body = """
{
"databaseName": "{{ input.db_name }}",
"timestamp": "{{ .now }}"
}
"""
Secure Signed Webhook Headers
The http engine supports HMAC-SHA256 signed payloads for securely triggering external CI/CD pipelines.
# actions/trigger_deployment.toml
name = "trigger_deployment"
description = "Securely trigger a deployment via signed webhook"
[[input]]
name = "version"
description = "Version to deploy"
type = "string"
required = true
[[input]]
name = "environment"
description = "Target environment"
type = "string"
required = true
[vault_secrets.github_webhook_secret]
collection = "github_credentials"
secret = "webhook_secret"
[vault_secrets.github_token]
collection = "github_credentials"
secret = "api_token"
[runtime]
engine = "http"
[[runtime.steps]]
method = "POST"
url = "https://github.com/repos/org/service/dispatches"
signature_secret = "${secrets.github_webhook_secret}"
signature_header = "X-Hub-Signature-256"
headers = { "Authorization" = "Bearer ${secrets.github_token}" }
When executing via webhook (fetch mode) directly from the Controller:
rescile-ce runner \
--inputs version=1.2.3,environment=production \
"http://127.0.0.1:7600/api/actions/module_name/trigger_deployment"
The runner automatically:
- Serializes inputs into a JSON payload
- Computes HMAC-SHA256 signature using the secret
- Sends
POSTrequest with signature header:X-Hub-Signature-256: sha256=<hex_signature> - GitHub (or any compatible system) verifies the signature before processing
Tip: You can access the dynamic URLs of the current rescile environment via the
rescile_endpointsmap (e.g.,{{ rescile_endpoints.controller }}). These are automatically populated, but can be overridden by setting theRESCILE_CTX_URL_CONTROLLER,RESCILE_CTX_URL_MCP, andRESCILE_CTX_URL_VAULTenvironment variables.
Dynamic Service Tunneling & Proxy Routing
Actions that act as long-running services (e.g., API Gateways) can declare network exposure using the [runtime.expose] block.
You can expose services either via dynamic HTTP ports or via secure Unix Domain Sockets (recommended on Linux for zero TCP overhead and enhanced isolation).
Exposing via Unix Socket (Linux only):
name = "start_acme_gateway"
run_mode = "service"
[runtime.expose]
protocol = "socket"
env_var = "UNIX_SOCKET" # Injects the generated socket path into the sandbox
[runtime]
engine = "nix"
flake = "./flake.nix"
exec = ["python3", "acme_gateway.py"]
Exposing via Dynamic HTTP Port:
[runtime.expose]
protocol = "http"
env_var = "PORT" # Injects the dynamic port into the sandbox
How it works:
- The runner either dynamically allocates a free port on the host (e.g.,
38192) or generates a temporary Unix Domain Socket path. - It injects this value into the sandbox as the configured environment variable (
UNIX_SOCKETorPORT). - The runner reports the dynamically allocated endpoint back to the Controller’s Active Execution state.
- Your application frontend (
proxy.toml) routes directly to the action, oblivious to whether it’s running via port or socket:[[route]] path = "/acme/*" target = "action://cert-manager/start_acme_gateway/acme"
WebAssembly (WASM) Execution
Execute compiled WebAssembly modules with strict sandboxing and efficient resource isolation. WASM modules must export a _start function and are executed with wasmtime.
# actions/validate_config.toml
name = "validate_config"
description = "Validate configuration using a WASM module"
[[input]]
name = "config_path"
description = "Path to configuration file"
type = "string"
required = true
default = "config.json"
[runtime]
engine = "wasi"
wasm = "./validator.wasm"
files = ["./config.json", "./schema.json"]
[[mount]]
resource_type = "config"
origin_resource = "infrastructure"
filename = "config.json"
mount_path = "config.json"
[[mount]]
resource_type = "schema"
origin_resource = "infrastructure"
filename = "schema.json"
mount_path = "schema.json"
Building WASM modules for rescile:
# Rust example with wasm-pack
wasm-pack build --target wasi --release
# The _start function serves as the entry point
#[no_mangle]
pub extern "C" fn _start() {
// Read from /workspace/config.json
// Validate against /workspace/schema.json
// Exit with status 0 on success, 1 on failure
}
WASM execution provides:
- Zero external dependencies: No syscall overhead
- Strict I/O isolation: Only explicit mounts are accessible
- High performance: Near-native execution speed
- Deterministic behavior: Same code always produces same output
Combining Engines: Multi-Stage Pipelines
Complex workflows can chain multiple engines in sequence:
# actions/deploy_with_validation.toml
name = "deploy_with_validation"
description = "Validate config (WASM) → Query state (GraphQL) → Deploy (Nix)"
[[input]]
name = "version"
type = "string"
required = true
# Stage 1: Native WASM Engine
[[stages]]
name = "validate"
[stages.runtime]
engine = "wasi"
wasm = "./validator.wasm"
args = ["{{ input.version }}"]
# Stage 2: Native API Engine
[[stages]]
name = "query_state"
[stages.runtime]
engine = "http"
[[stages.runtime.steps]]
method = "POST"
url = "https://api.internal/graphql"
graphql_query = """
query GetState($version: String!) {
state(version: $version) {
status
}
}
"""
[stages.runtime.steps.graphql_variables]
version = "{{ input.version }}"
# Stage 3: Native Nix Engine
[[stages]]
name = "deploy"
[stages.runtime]
engine = "nix"
flake = "./flake.nix"
exec = [
["nix", "flake", "update"],
["nix", "develop", "--command", "deploy.sh", "{{ input.version }}"]
]