Collections & Invariants
Enforce guarantees across multiple resources using for each loops and invariant blocks.
For Each Loops
Apply guarantees to all items in a collection.
Syntax
for each <type> in <container> {
<statements>
}Directory Iteration
for each file in directory "/secrets" {
ensure encrypted with AES:256 key "env:SECRET_KEY"
ensure permissions with posix mode "0600"
}This ensures every file in /secrets is encrypted and has 0600 permissions.
Invariants
Invariant blocks declare guarantees with higher priority than regular guarantees.
Syntax
invariant {
<statements>
}Why Invariants?
Invariants are executed first in the topological order. Use them for critical guarantees that must be established before anything else.
invariant {
ensure exists on file "/etc/app/license.key"
ensure readable on file "/etc/app/license.key"
}
# Regular guarantees follow
ensure running on service "app"The license key is guaranteed to exist before the service starts.
Combining For Each and Invariant
The most powerful pattern - enforce critical guarantees across collections:
invariant {
for each file in directory "/secrets" {
ensure encrypted with AES:256 key "env:SECRET_KEY"
ensure permissions with posix mode "0600"
}
}This ensures:
- All files in
/secretsare encrypted (highest priority) - Executed before any other guarantees
Practical Examples
Secure Secrets Directory
invariant {
# Ensure the directory itself is secure
ensure exists on directory "/var/app/secrets"
ensure permissions with posix mode "0700" on directory "/var/app/secrets"
# Ensure all files within are encrypted and restricted
for each file in directory "/var/app/secrets" {
ensure encrypted with AES:256 key "env:SECRET_KEY"
ensure permissions with posix mode "0600"
}
}Web Assets Validation
for each file in directory "/var/www/html" {
ensure exists
ensure readable
ensure permissions with posix mode "0644"
}Log Files
for each file in directory "/var/log/app" {
ensure exists
ensure writable
ensure permissions with posix mode "0640"
}For Each with Policies
Combine collection iteration with policies:
policy secure_file(key_ref) {
ensure encrypted with AES:256 key key_ref
ensure permissions with posix mode "0600"
}
for each file in directory "/secrets" {
apply secure_file("env:SECRET_KEY")
}Execution Order
Invariants have priority +1000 in topological sorting:
# Priority 1000
invariant {
ensure exists on file "critical.db"
}
# Priority 0
ensure backed_up on file "critical.db"The exists guarantee runs first, even though backed_up might logically depend on it.
Invariant Best Practices
- Use sparingly - Only for truly critical guarantees
- Foundation guarantees - License files, critical configs, security policies
- System prerequisites - Things that must exist before the system can function
Implementation Note
The for each loop expands during the binding phase:
for each file in directory "/secrets" {
ensure encrypted
}If /secrets contains a.txt and b.txt, this expands to:
ensure encrypted on file "/secrets/a.txt"
ensure encrypted on file "/secrets/b.txt"Each guarantee is then processed through implication expansion and added to the dependency graph.
Next Steps
Continue to Violation Handling to learn how to configure retry logic and notifications when guarantees fail.