Writing Rego policies
Writing Rego policies
For solution engineers governing StackGen agents and tools: policies in this repository are Open Policy Agent (OPA) rules written in Rego. You ship them with Terraform or OpenTofu using the StackGen provider’s sg_policy resource.
What the policy is deciding
Think of each evaluation as answering one question for a single moment in the agent’s work: “Given who this is, what they are trying to do right now, and any facts we attached to the policy, should we allow it, block it, or pause for human approval?”
The platform hands your Rego rules a compact factsheet (the input value in OPA). Your policy reads that factsheet and sets outcomes such as allow, approval_required / intervene (for human-in-the-loop), plus optional reason text people can read in logs or UI.
The factsheet is assembled in stackgen-aios from the tool call and related metadata—the shape is defined in code as buildOPAInput in internal/policy/opa/evaluator.go (search for buildOPAInput in that file if the link moves).
What appears on the factsheet (field by field)
| Piece | Plain meaning |
|---|---|
agent |
Which agent is acting: internal id, display name, and optional tags you configured (for example “production” or team name). |
timestamp |
When the check ran (UTC, RFC3339 string). Bundled policies parse it with time.parse_rfc3339_ns plus time.weekday / time.clock for business-hours and off-hours rules; data-risk-pii also compares it to time.now_ns() for stale-input and clock-skew checks. |
tool |
The name of the tool the agent wants to use, plus arguments: the structured parameters for that call (always present as an object, even if empty). |
reason |
When the agent supplied a short justification for the action, it appears here so policies can insist on explanations for sensitive tools. |
environment |
Present when the request is tied to a specific owner in the platform (shown as owner_id). Lets you scope rules to a customer or workload boundary. |
skill |
Present when the call is associated with a loaded skill the agent is using. Includes identity and trust metadata so you can treat approved skills differently from experimental ones. |
policy_data |
Optional JSON you store on the policy in the platform. Same content every time that policy runs—ideal for allowlists, tier names, or any stable configuration your Rego should read. |
user |
Present when appcd identity resolves for the caller: id, email, and projects[] with role_name per project (for example admin, devops, developer). Use for logic policies that gate who may invoke a tool. |
current_project |
The project membership matching the caller’s current org/workspace — same shape as one user.projects entry. Rego reads input.current_project.role_name for project-scoped gates. |
approver |
Present on HITL resolve when evaluating approval_authorization policies: the human clicking Approve/Reject (id, email, role = current-project role_name). See HITL approval authority. |
requester |
Present on HITL resolve: who triggered the original tool call (from the pending approval). |
context |
Not emitted by the default buildOPAInput factsheet in current stackgen-aios builds. If you need situational metadata (data classification, freeze flags, blast-radius hints), put it under policy_data or derive it from tool, agent, and reason. |
Beyond the rows above, buildOPAInput may omit optional blocks entirely. If you need fields the evaluator does not send yet, add them under policy_data or derive them in Rego from tool, agent, and reason.
Policy types: Use logic for caller gates, intervention for HITL pause (approval_required), and approval_authorization for who may click Approve (input.approver.*). Bundled examples that mention input.approver belong on approval_authorization policies attached to the agent — not on ordinary tool-call logic policies.
Example JSON (copy into the OPA Playground)
These match the input document OPA receives (same structure as buildOPAInput produces).
- Typical tool call — agent, time, tool + arguments, reason, and owner scope.
- With caller project roles — adds
user.projects[]andcurrent_project.role_namefor role-gated logic policies. - With skill and
policy_data— adds optional skill block andpolicy_data(example nestedcontextunderpolicy_datafor allowlist-style config; useinput.policy_data.contextin Rego if you choose that shape). - Top-level
context— legacy / illustrative sample only; current default evaluation input does not include a top-levelcontextkey. Preferpolicy_datafor custom metadata your Rego can read asinput.policy_data.….
Try policies in the browser
Use the OPA Rego Playground to edit Rego and Input side by side.
- Open play.openpolicyagent.org.
- Put your policy in the editor. Files in this repo use
package policyat the top. - Paste one of the sample JSON objects into Input (that object is the entire
inputdocument). - Run Evaluate to see whether
allow,approval_required, etc. behave as you expect.
For language reference, see the official Rego policy language guide.
Authoring policies in this repository
- Examples to learn from:
modules/aios-policies/policies/and per-module folders such asmodules/aios-agent-aws-sre/policies/. - Local checks: Install OPA as in Step 2 — Your machine, then run
make opa-check,make opa-test, andmake opa-fmt(Step 3 — Run checks). - One file at a time:
make opa-checkvalidates each policy.regofile on its own (skips*_test.rego), similar to how standalone policies are uploaded. - Co-located tests: Keep
foo_test.regonext tofoo.rego.make opa-testrunsopa teston each pair so packages do not collide across modules.
Related guides
- HITL approval authority and role-based Rego — who may approve vs who may invoke tools; samples for caller gates, intervention, and
hitl-approver-admin-only.rego.