Skip to content

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

ens
for each <type> in <container> {
  <statements>
}

Directory Iteration

ens
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

ens
invariant {
  <statements>
}

Why Invariants?

Invariants are executed first in the topological order. Use them for critical guarantees that must be established before anything else.

ens
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:

ens
invariant {
  for each file in directory "/secrets" {
    ensure encrypted with AES:256 key "env:SECRET_KEY"
    ensure permissions with posix mode "0600"
  }
}

This ensures:

  1. All files in /secrets are encrypted (highest priority)
  2. Executed before any other guarantees

Practical Examples

Secure Secrets Directory

ens
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

ens
for each file in directory "/var/www/html" {
  ensure exists
  ensure readable
  ensure permissions with posix mode "0644"
}

Log Files

ens
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:

ens
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:

ens
# 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

  1. Use sparingly - Only for truly critical guarantees
  2. Foundation guarantees - License files, critical configs, security policies
  3. System prerequisites - Things that must exist before the system can function

Implementation Note

The for each loop expands during the binding phase:

ens
for each file in directory "/secrets" {
  ensure encrypted
}

If /secrets contains a.txt and b.txt, this expands to:

ens
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.

Released under the MIT License.