What it is

Compliance findings are history; gates are prevention. Wildcard actions ("actions": ["*"]), unbounded resources, and bolted-on inline policies survive every review cycle because reviewers end and permissions stay. This repo makes them merge-blocking: three fixtures prove the gate in all directions (vulnerable denied, clean allowed, malformed input denied) on every push and pull request.

How it works

Same Rego source enforces both the CI gate (offline, gate.sh) and request-time checks via service/server.clj (OPA as PDP, this service as PEP) — one policy, two enforcement points, no drift possible.

Input contract (normalized Terraform-plan / access-review output):

{
  "role_permissions": [ { "role": "...", "actions": ["s3:GetObject"], "resources": ["arn:..."] } ],
  "inline_policies":  [ { "principal": "...", "attached": false } ]
}

Three rules, no exceptions:

Rule Denies
wildcard action "*" in any role’s action list
wildcard resource bare "*" bound to any role
inline policy attached: true on any principal

Plus missing-section deny: absent role_permissions or inline_policies is denied, not skipped.

Run locally (1 command)

git clone https://github.com/nurazhardotcom/identity-policy-as-code
cd identity-policy-as-code
./scripts/gate.sh    # needs opa on PATH — runs the full gate

gate.sh runs, in order: strict syntax check + format check + unit tests + fixture gates (vulnerable and malformed inputs must be denied, clean input must be allowed). Exit 0 = merge allowed, exit 1 = blocked.

Automated testing:

opa check --strict policy/   # syntax check
opa fmt --fail policy/       # format check (non-zero on drift)
opa test policy/ -v          # Rego unit suite (policy/iam_guard_test.rego)

CI

Two jobs on every push/PR: opa-gate (the script above) and pdpa-secret-scan (pdpa-sg-clj scans the repo for Singapore PII and secrets; any finding fails the build).

The bigger story

This is the public slice of a working compliance-automation practice: zero-dependency CLI scanners, deterministic scoring, evidence over assertions. Tooling: pdpa-sg-clj · idira-audit-clj · identity-control-plane.

Labs

When it gets messy — a wildcard pull request meets the gate, loses, and gets fixed:

Lab 1 — feel the deny. Feed the vulnerable fixture through gate.sh, read the deny reason, then the clean fixture — confirm allow.

Lab 2 — malformed input. Drop one section from the input JSON, confirm deny (not skip).

Lab 3 — add a denial. Write one new Rego rule (e.g. deny a specific action prefix), add a fixture + test, watch the gate enforce it.