Installable overlays for domain logic.
Packs extend Cordum without core code changes. Installation is declarative and safe — it registers data (YAML, JSON Schema, config patches) but never executes code. Workers are deployed separately.
- API-native installs via gateway
- No arbitrary code execution during install
- Namespaced resources avoid collisions
- Soft uninstall by default, --purge to hard delete
├── pack.yaml# Manifest
├── workflows/# Workflow YAML
├── schemas/# JSON Schema
├── overlays/# Config + policy patches
│ ├── pools.patch.yaml
│ ├── timeouts.patch.yaml
│ └── policy.fragment.yaml
└── deploy/# Informational only
Distributed as a directory or .tgz archive. Max 256 MiB uncompressed, 2048 files, 32 MiB per file.
Pack Manifest
apiVersion: cordum.io/v1alpha1
kind: Pack
metadata:
id: sre-investigator # ^[a-z0-9-]+$
version: 0.3.1
title: SRE Investigator
description: Kubernetes incident triage pack.
compatibility:
protocolVersion: 1 # Must match core
minCoreVersion: 0.6.0 # Semver range
maxCoreVersion: 1.0.0
topics:
- name: job.sre-investigator.collect.k8s
capability: sre.collect.k8s
requires: [kubectl, network:egress]
riskTags: [read]
resources:
schemas:
- id: sre-investigator/IncidentContext
path: schemas/IncidentContext.json
workflows:
- id: sre-investigator.triage
path: workflows/triage.yaml
overlays:
config:
- name: pools
scope: system
key: pools
strategy: json_merge_patch
path: overlays/pools.patch.yaml
policy:
- name: safety
strategy: bundle_fragment
path: overlays/policy.fragment.yaml
tests:
policySimulations:
- name: allow_collect
request:
topic: job.sre-investigator.collect.k8s
capability: sre.collect.k8s
expectDecision: ALLOWSchema File Format
Schemas use JSON Schema Draft 2020-12. IDs follow the pattern <pack_id>/<name>. During install, each schema is registered to the Redis schema registry and assigned a SHA256 digest for collision detection.
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "Hello Pack Echo Input",
"type": "object",
"properties": {
"message": { "type": "string" },
"author": { "type": "string" }
},
"required": ["message"],
"additionalProperties": false
}Collision Detection
If a schema ID already exists with a different SHA256 digest, install fails. Pass --upgrade to overwrite.
Rollback
If install fails after schemas are registered, the original schema is restored (or the new one deleted). Digests verify state before rollback.
Overlay Mechanics
Config overlays use JSON Merge Patch (RFC 7396) to modify pool routing and timeout settings. Maps are merged recursively; null values delete keys (used during uninstall).
# Route topic to a namespaced pool
topics:
job.hello-pack.echo: hello-pack
# Define the pool
pools:
hello-pack:
requires:
- local# Set workflow-level timeout (seconds) workflows: hello-pack.echo: 120 # Set per-topic timeout topics: job.hello-pack.echo: 60
Validation Rules
- Pools overlay: Topic keys must start with
job.<pack_id>.. New pool keys must start with<pack_id>. Onlytopicsandpoolskeys accepted. - Timeouts overlay: Topic keys must start with
job.<pack_id>.. Workflow keys must start with<pack_id>.. Onlytopicsandworkflowskeys accepted. - Scope: Overlays target
cfg:<scope>:<scope_id>.data.<key>. Most packs usesystemscope with default ID.
Policy Fragments
Packs inject policy rules via bundle_fragment strategy. Each fragment is stored at cfg:system:policy.data.bundles["<pack_id>/<name>"] and merged with file-based policies at evaluation time.
rules:
- id: hello-pack-allow
match:
topics:
- job.hello-pack.echo
decision: allow
reason: "Allow the hello-pack echo demo."
- id: hello-pack-deny-secrets
match:
topics:
- job.hello-pack.echo
secrets_present: true
decision: deny
reason: "Echo pack must not handle secrets."Bundle Entry (stored in Redis)
{
"hello-pack/safety": {
"content": "rules:\n - id: hello-pack-allow\n ...",
"version": "0.1.0",
"sha256": "a1b2c3...",
"installed_at": "2025-03-15T10:00:00Z",
"enabled": true,
"author": "cordumctl"
}
}Fragment ID is <pack_id>/<overlay_name>. The Safety Kernel merges file-based policies + all config-service fragments at reload time. Snapshot hash covers both: baseSnapshot|cfg:<hash>.
Namespacing & Conventions
All pack resources are namespaced by pack ID. The installer validates every topic, schema, workflow, and pool name against these patterns before writing any data.
| Resource | Pattern | Example |
|---|---|---|
| Pack ID | ^[a-z0-9-]+$ | sre-investigator |
| Topics | job.<pack_id>.* | job.sre-investigator.collect.k8s |
| Workflows | <pack_id>.<name> | sre-investigator.triage |
| Schemas | <pack_id>/<name> | sre-investigator/IncidentContext |
| Pools | <pack_id>-* | sre-investigator-primary |
--upgrade is passed. Policy fragments and overlays overwrite by pack+name key.Installation Flow
- 1Acquire global + pack-specific distributed locks
- 2Validate pack.yaml: namespacing, protocol version, core compatibility
- 3Plan: compute SHA256 digests, detect collisions (fail or --upgrade)
- 4Register schemas to Redis schema registry
- 5Upsert workflows to Redis workflow store
- 6Apply config overlays via JSON merge patch (RFC 7396)
- 7Apply policy fragments into cfg:system:policy bundles
- 8Write pack record to cfg:system:packs registry
# Install from a directory cordumctl pack install ./my-pack # Install from a tarball URL cordumctl pack install https://packs.cordum.io/packs/sre-k8s/0.3.1/pack.tgz # Install with overwrite (upgrade existing schemas/workflows) cordumctl pack install --upgrade ./my-pack # Dry-run: print intent without writing cordumctl pack install --dry-run ./my-pack # Install inactive (no pool mappings, status: INACTIVE) cordumctl pack install --inactive ./my-pack
Locking
Acquires global + pack-specific distributed locks (60 s TTL). Only one pack operation runs at a time.
Rollback
If any step fails after writes begin, previous state is restored in reverse order. Digests verify correctness.
Status
ACTIVE if pools overlay applied. INACTIVE if --inactive flag used. DISABLED after uninstall.
Uninstall
Soft Uninstall
Default behavior. Removes routing and policy but preserves data.
- Config overlays reversed (keys set to
null) - Policy fragments removed from bundles
- Workflows and schemas kept intact
- Pack status set to DISABLED
Purge Uninstall
Pass --purge to also delete registered data.
- Everything from soft uninstall, plus:
- Workflows deleted from Redis
- Schemas deleted from registry
- Pack record retained (status: DISABLED)
# Soft uninstall (preserves schemas + workflows) cordumctl pack uninstall sre-investigator # Hard uninstall (deletes everything) cordumctl pack uninstall --purge sre-investigator
Testing & Validation
The tests.policySimulations block in pack.yaml defines policy simulation tests. Run them with cordumctl pack verify after install.
tests:
policySimulations:
- name: allow_echo
request:
tenantId: default
topic: job.hello-pack.echo
capability: hello-pack.echo
expectDecision: ALLOW
- name: deny_secrets
request:
topic: job.hello-pack.echo
capability: hello-pack.echo
riskTags: [secrets]
expectDecision: DENY# Verify installed pack (runs policy simulations) cordumctl pack verify hello-pack # Output: # ✓ allow_echo: ALLOW (expected ALLOW) # ✓ deny_secrets: DENY (expected DENY) # pack hello-pack: 2/2 policy simulations passed
What verify checks
- Each test calls
POST /api/v1/policy/simulatewith the request fields - Compares returned decision (case-insensitive) against
expectDecision - Auto-fills
packIdandtenantIdif omitted - Fails with expected vs actual if any simulation mismatches
Example: hello-pack
A minimal pack that registers one schema, one workflow, pool routing, a timeout, and a policy allow rule. See the full source at examples/hello-pack.
id: hello-pack.echo
name: Hello Pack Echo
org_id: default
steps:
echo:
id: echo
name: Echo input
type: worker
topic: job.hello-pack.echo
input_schema_id: hello-pack/EchoInput
input:
message: "${input.message}"
author: "${input.author}"
meta:
pack_id: hello-pack
capability: hello-pack.echo# Install
cordumctl pack install ./examples/hello-pack
# Verify policy tests
cordumctl pack verify hello-pack
# Run the workflow
cordumctl workflow run hello-pack.echo \
--input '{"message": "Hello, world!"}'
# List installed packs
cordumctl pack list
# Uninstall
cordumctl pack uninstall hello-pack