Skip to main content
Security and compliance rules are most valuable when they run before anything reaches the cloud. An S3 bucket with a public ACL discovered by a cloud security scanner is a bucket that was already misconfigured, already potentially exposed. A policy that catches that misconfiguration at ubx validate — before the bucket exists, before any credentials are needed, before CI even gets to the apply stage — is worth orders of magnitude more. The policy block brings compliance rules into your .iac source as first-class declarations: a condition over resource attributes, a severity, and an error message. error severity violations block ubx validate and ubx apply. warn severity violations are shown but don’t block. Every resource of the matching type in every .iac file in your project is evaluated against every applicable policy automatically — no separate tool to run, no post-apply scanner to wait for.

What you’ll learn

  • How policy blocks enforce rules at ubx validate time
  • The difference between severity = "error" and severity = "warn"
  • How to test a policy by writing a deliberately violating resource

Why this matters

Policy violations with severity = "error" block both ubx validate and ubx apply. This means policy enforcement is part of the same pipeline as type-checking — a project with policy violations is a project that doesn’t compile, by design.

The source code

# This bucket passes the policy — acl = "private".
unit "aws_s3_bucket_v2" "private_assets" {
  bucket = "myapp-private-assets"
  acl    = "private"
}

# Uncommenting this block would violate the policy and produce:
#   ✗  Policy violation: "no_public_buckets"
#   unit "aws_s3_bucket_v2" "public_files" violates:
#   condition "acl != 'public-read' && acl != 'public-read-write'" evaluated to false
#
# unit "aws_s3_bucket_v2" "public_files" {
#   bucket = "myapp-public-files"
#   acl    = "public-read"    ← would violate the policy
# }

How it works

1

Policies are evaluated during the type-check pass

After the schema type check, ubx evaluates every policy block against every unit block whose resource type matches the rule.resource field. This happens at ubx validate time — no cloud credentials, no network access required.
2

The condition is evaluated against resolved attribute values

The condition string "acl != 'public-read' && acl != 'public-read-write'" is evaluated as an expression against the unit block’s attribute map. Attributes with literal values (like acl = "private") are fully evaluated. Attributes with pending values are checked for the presence of a literal that could violate the condition.
3

Violations are reported with source location

A failing condition produces an error referencing the violating unit block by file, line, type, and label. The description and the condition that failed are both included in the error message, making the violation self-explanatory without needing to look up the policy.

What ubx generates

policy blocks produce no generated code — they are compile-time validators only. The generated TypeScript/Python/Go contains only the unit resources. Policy enforcement happens in the ubx compiler, not in the Pulumi runtime.
index.ts
// Generated by ubx — do not edit
// (policy blocks produce no generated code)
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";

const privateAssets = new aws.s3.BucketV2("private_assets", {
    bucket: "myapp-private-assets",
    acl: "private",
});

Common mistakes

Policy conditions are evaluated against the raw attribute map — not the generated Pulumi code. The condition "acl != 'public-read'" checks the .iac attribute acl, not the Pulumi SDK’s Acl property. Use the .iac attribute names (snake_case), not the SDK property names (camelCase).
Put your policy blocks in a dedicated policies.iac file at the project root — or in a shared policies directory if multiple stacks share the same rules. Keeping policies separate from resources makes them easier to audit and update independently.

Run it

ubx validate               # evaluates policies — no cloud credentials needed
ubx validate --strict      # same, but warn-severity violations also become errors

What you learned

policy blocks enforce rules at ubx validate time — before any cloud credentials are needed
severity = "error" blocks validate and apply; severity = "warn" shows a warning but doesn’t block
Policy blocks produce no generated code — enforcement is entirely in the ubx compiler

Next steps

import existing resource

Bring existing cloud resources under ubx management

policy block reference

Full policy block syntax and condition language