OpalScript
OpalScript
Programmable Access Automation

The Problem with Webhooks

Access automation shouldn't require building and maintaining infrastructure
Infrastructure Overhead
You need servers, databases, and monitoring just to process access webhooks
Latency & Reliability
Network calls add seconds to every access decision, and if your server is down, access breaks
Limited Context
Webhooks only send you fragments -- you can't query the full picture when making decisions
Development Friction
Every policy change means code changes, deploys, and hoping nothing breaks

OpalScript: A Better Way

Write access logic as code that runs inside Opal -- no infrastructure required
No Infrastructure
OpalScript runs directly inside Opal. No servers to deploy, no endpoints to maintain, no infrastructure to manage.
Access-Aware
Full access to Opal's data model -- users, groups, resources, tickets, risk levels -- all from within your script.
Safe by Design
Deterministic execution, sandboxed runtime, resource limits. Your scripts can't break Opal or cause unintended side effects.
1
DEMO 1

Auto-Approve with
Group Membership

Instantly approve access requests for users who already belong to the right group — zero manual steps
DEMO 1

Auto-Approve with Group Membership

The Script · 1 of 4
An engineer joins the on-call rotation and immediately needs Datadog access to monitor production. In the old world, that's a ticket, an approval queue, and potential delays during an incident window. With OpalScript, the policy verifies group membership and request duration in real time — approving instantly when both conditions are met, and routing to manual review when they aren't. No webhook. No external service. No waiting.
When assigned to request
Then
Run Opalscript
Script
Ask Opal to modify your Opalscript...
ALLOWED_GROUPS = ["fc959125-9372-43e6-8802-499cb319cc61"] DENY_MSG = "Access Denied: Not a member of Oncall Engineering" APPROVE_MSG = "Access Approved: Oncall Engineering and request for 4 hours or less" REVIEW_MSG = "Member of Oncall Engineering, but request is greater than 4 hours" OWNER_GROUP = "432298c8-e46d-48ca-9fb7-c3438bc29984" # Get request request = context.get_request() # Check group membership allowed = any([ accesslib.check_access(request.requester_id, group_uuid) for group_uuid in ALLOWED_GROUPS ]) # Deny if not a member of designated groups if not allowed: actions.deny(DENY_MSG) return # Auto-approve if 4 hours or less; Manual approve otherwise if request.requested_duration_minutes and \ request.requested_duration_minutes <= 240: actions.approve(APPROVE_MSG) else: actions.comment("Manual Review: " + REVIEW_MSG) notificationslib.notify_owner( OWNER_GROUP, "Manual Review Required", REVIEW_MSG )
DENY Not in Group
User is not a member of On-call Engineering — request denied immediately with an explanatory message. No escalation, no queue.
APPROVE In Group · ≤ 4 hrs
Member of On-call Engineering requesting 4 hours or less — auto-approved instantly. No human in the loop, no incident delay.
REVIEW In Group · > 4 hrs
Member qualifies, but duration exceeds the threshold — a comment is added and the manager is notified via notificationslib.notify_owner().
Key Point
accesslib + notificationslib handle all three paths natively — no webhook, no external service, no infrastructure to maintain.
DEMO 1

Auto-Approve with Group Membership

Not in Group · 2 of 4
John Clark is not a member of On-call Engineering. The moment his request hits Opal, OpalScript fires — calls accesslib.check_access() against the allowed groups list, gets back false, and denies the request before a single reviewer is notified to act. No queue, no delay, no ambiguity.
Denied request
"Need access to Datadog with viewer role to troubleshoot an issue for a customer incident"
Requested For
JC
John Clark
Duration
an hour
Requested
Denied
Propagation
1 Requested Item
datadog-viewer-okta-group · Never Used
Okta/ · Okta Group · More Info
Reviewers
Stage 1 ANY
OwnerStatus
SE Demo Reviewers ○ No Action
ReviewersStatus
MH
Matt Heffler
matt@opal.dev
○ No Action
IndividualsStatus
O1
OpalScript 1: Auto-Approve On-Call Engineers
12682275-9e06-40c9-b8b0-d0b9c070b28b
Denied
Activity
All Comments Events ↑ Sort by Newest
John Clark
Requested access for an hour
a few seconds ago (Tuesday, March 17, 2026 6:44 PM)
🔔
John Clark
Was notified of their own request
a few seconds ago (Tuesday, March 17, 2026 6:44 PM)
🔔
Matt Heffler
Was notified to review the request
a few seconds ago (Tuesday, March 17, 2026 6:44 PM)
O1
OpalScript 1: Auto-Approve On-Call Engineers
Was notified to review the request
a few seconds ago (Tuesday, March 17, 2026 6:44 PM)
💬
OpalScript 1: Auto-Approve On-Call Engineers
Commented on the request
a few seconds ago (Tuesday, March 17, 2026 6:44 PM)
Access Denied: Not a member of Oncall Engineering
DENY Not in Group
John Clark is not a member of On-call Engineering. accesslib.check_access() returns false for every group in ALLOWED_GROUPS — OpalScript denies the request immediately and exits.
Status: Denied — Instantly
The request moves Requested → Denied with no pending state. No reviewer touches it. The decision is complete before the review queue is even populated.
Audit-Ready Comment
OpalScript writes the exact DENY_MSG to the request as a comment: "Access Denied: Not a member of Oncall Engineering" — a permanent, searchable record of exactly why access was refused.
No Reviewer Burden
Matt Heffler and SE Demo Reviewers show No Action — they were notified but never had to act. OpalScript handled it entirely, keeping human reviewers focused on requests that actually need judgment.
DEMO 1

Auto-Approve with Group Membership

In Group · ≤ 4 hrs · 3 of 4
This time John Clark is a member of On-call Engineering and requests just one hour of access. accesslib.check_access() returns true, the duration check passes, and OpalScript approves the request instantly — no reviewer queue, no wait, no incident delay. The Datadog access propagates immediately.
Approved request
"Need access to Datadog with viewer role to troubleshoot an issue for a customer incident"
Requested For
JC
John Clark
Duration
an hour
Requested
Reviewed
Propagated
1 Requested Item
datadog-viewer-okta-group
Okta/ · Okta Group · More Info
Reviewers
Stage 1 ANY
OwnerStatus
SE Demo Reviewers ○ No Action
ReviewersStatus
MH
Matt Heffler
matt@opal.dev
○ No Action
IndividualsStatus
O1
OpalScript 1: Auto-Approve On-Call Engineers
12682275-9e06-40c9-b8b0-d0b9c070b28b
Approved
Activity
All Comments Events ↑ Sort by Newest
John Clark
Requested access for an hour
a few seconds ago (Tuesday, March 17, 2026 6:55 PM)
🔔
John Clark
Was notified of their own request
a few seconds ago (Tuesday, March 17, 2026 6:55 PM)
🔔
Matt Heffler
Was notified to review the request
a few seconds ago (Tuesday, March 17, 2026 6:55 PM)
O1
OpalScript 1: Auto-Approve On-Call Engineers
Was notified to review the request
a few seconds ago (Tuesday, March 17, 2026 6:55 PM)
💬
OpalScript 1: Auto-Approve On-Call Engineers
Commented on the request
a few seconds ago (Tuesday, March 17, 2026 6:55 PM)
Access Approved: Oncall Engineering and request for 4 hours or less
Opal System
Changed the request status to approved
2 minutes ago (Tuesday, March 17, 2026 6:57 PM)
John Clark
Was added to the requested group
2 minutes ago (Tuesday, March 17, 2026 6:57 PM)
APPROVE In Group · ≤ 4 hrs
John Clark is a member of On-call Engineering and requests 1 hour. Both conditions pass — group membership via accesslib.check_access() and duration ≤ 240 minutes — so OpalScript calls actions.approve() immediately.
Status: Requested → Reviewed → Propagated
All three steps complete green. Access is provisioned end-to-end with no human in the loop — the entire lifecycle runs in seconds, not hours.
Audit-Ready Comment
OpalScript writes the exact APPROVE_MSG as a comment: "Access Approved: Oncall Engineering and request for 4 hours or less" — the reasoning is on record, not just the outcome.
Reviewers Still No Action
Matt Heffler and SE Demo Reviewers were notified but never acted. OpalScript resolved it first — keeping human reviewers free for requests that actually need judgment.
DEMO 1

Auto-Approve with Group Membership

In Group · > 4 hrs · 4 of 4
John Clark is a member of On-call Engineering — but this time he requests a full day. Group membership passes, but the duration exceeds the 4-hour threshold. OpalScript can't auto-approve, so it adds a comment explaining exactly why and fires notificationslib.notify_owner() to alert the manager. The request sits in Review — waiting for a human to take it from here.
Pending request
"Need access to Datadog with viewer role to troubleshoot an issue for a customer incident"
Requested For
JC
John Clark
Duration
a day
Requested
Review
Propagation
1 Requested Item
datadog-viewer-okta-group · Never Used
Okta/ · Okta Group · More Info
Reviewers
Stage 1 ANY
OwnerStatus
SE Demo Reviewers ○ No Action
ReviewersStatus
MH
Matt Heffler
matt@opal.dev
○ No Action
IndividualsStatus
O1
OpalScript 1: Auto-Approve On-Call Engineers
12682275-9e06-40c9-b8b0-d0b9c070b28b
○ No Action
Activity
All Comments Events ↑ Sort by Newest
John Clark
Requested access for a day
a few seconds ago (Tuesday, March 17, 2026 6:58 PM)
🔔
John Clark
Was notified of their own request
a few seconds ago (Tuesday, March 17, 2026 6:58 PM)
O1
OpalScript 1: Auto-Approve On-Call Engineers
Was notified to review the request
a few seconds ago (Tuesday, March 17, 2026 6:58 PM)
🔔
Matt Heffler
Was notified to review the request
a few seconds ago (Tuesday, March 17, 2026 6:58 PM)
💬
OpalScript 1: Auto-Approve On-Call Engineers
Commented on the request
a few seconds ago (Tuesday, March 17, 2026 6:58 PM)
Manual Review: Member of Oncall Engineering, but request is greater than 4 hours
REVIEW In Group · > 4 hrs
John Clark is in On-call Engineering, but requests a full day. Group check passes, but requested_duration_minutes > 240 — so OpalScript routes to manual review instead of auto-approving.
Status: In Review — Awaiting Human
The request stops at Review — not denied, not propagated. A human reviewer (Matt Heffler) now owns the decision. OpalScript has done its job and stepped aside.
Manager Notified via notify_owner()
notificationslib.notify_owner() fires alongside the comment — the OWNER_GROUP receives a direct notification with the REVIEW_MSG, so the right person is already looped in before they even check the queue.
Comment Explains the Why
OpalScript leaves a precise comment — "Member of Oncall Engineering, but request is greater than 4 hours" — so the reviewer immediately understands the context without digging through the script.
2
DEMO 2

Breakglass Access Control

Grant emergency access with full audit trails — speed when you need it, accountability always
DEMO 2

Breakglass Access Control

The Script · 1 of 4
A production incident just triggered. Your on-call engineer needs AdministratorAccess to the Prod AWS Account — right now, not after a 30-minute approval chain. Breakglass access exists for exactly this moment. OpalScript reads the custom fields on the request, verifies breakglass authorization via accesslib, confirms a ticket is attached, and checks the duration. If everything aligns, access is granted in seconds. If anything doesn't, the manager is already notified before they check the queue.
When assigned to request
Then
Run Opalscript
Script
Ask Opal to modify your Opalscript...
BREAKGLASS_GROUP = "0fefc325-aaf4-41a2-9c61-74a7e0556526" BG_APPROVE_MSG = "Access Approved: Breakglass access with duration of 1 hour. Ticket " BG_DENY_MSG = "Breakglass access requested, but no ticket specified" BG_REVIEW_MSG = "Breakglass access requested, but request is greater than 1 hour. Ticket " REVIEW_MSG = "Non-breakglass access requested. No ticket required." OWNER_GROUP = "432298c8-e46d-48ca-9fb7-c3438bc29984" # Access the request request = context.get_request() # Obtain the custom fields custom_fields = request.custom_fields is_breakglass = custom_fields.get("Breakglass Access", False) ticket_number = custom_fields.get("Ticket Number", "") # Obtain breakglass authorization requester = request.requester_id is_authorized = accesslib.check_access(requester, BREAKGLASS_GROUP) # Approve breakglass access if is_breakglass and is_authorized: if not ticket_number.strip(): actions.deny("Request Denied: " + BG_DENY_MSG) else: duration = request.requested_duration_minutes if duration and duration <= 60: actions.approve(BG_APPROVE_MSG + ticket_number) else: notificationslib.notify_owner( OWNER_GROUP, "Manual Review Required", BG_REVIEW_MSG + ticket_number ) actions.comment("Manual Review: " + BG_REVIEW_MSG + ticket_number) # Manual review for everything else notificationslib.notify_owner( OWNER_GROUP, "Manual Review Required", REVIEW_MSG + ticket_number ) actions.comment("Manual Review: " + REVIEW_MSG + ticket_number)
DENY BG · No Ticket
Breakglass flag is set and requester is authorized, but no ticket number is provided — request denied immediately. A ticket is non-negotiable for any breakglass approval.
APPROVE BG · Ticket · ≤ 60 min
Breakglass flag set, requester authorized, ticket present, duration within 60 minutes — auto-approved instantly with the ticket number appended to the approval message.
REVIEW BG · > 60 min  ·  or Non-BG
Either breakglass with duration over 60 minutes, or no breakglass flag at all — both route to manual review. Manager notified via notify_owner(), comment added with context.
Key Point
custom_fields.get() reads form data natively — the breakglass flag and ticket number come directly from the request form. No webhook, no external lookup, no parsing required.
DEMO 2

Breakglass Access Control

BG · No Ticket · 2 of 4
The EKS cluster is down and John Clark needs AdministratorAccess immediately. He sets the breakglass flag and submits — but forgets to attach a ticket number. OpalScript sees the breakglass flag, confirms he's in the authorized group, then checks for a ticket. There isn't one. Request denied before it reaches any reviewer. No ticket, no access — even in a breakglass scenario.
Denied request
"Need breakglass access so solve an emergency issue with the EKS Cluster that is impacting multiple customers."
Requested For
JC
John Clark
Duration
an hour
Breakglass Access
True
Requested
Denied
Propagation
1 Requested Item
AWS
AdministratorAccess · Never Used
Prod AWS Account/ · AWS IAM Role · More Info
Reviewers
Stage 1 ANY
OwnerStatus
SE Demo Reviewers ○ No Action
ReviewersStatus
MH
Matt Heffler
matt@opal.dev
○ No Action
IndividualsStatus
O2
OpalScript 2: Breakglass Access
f3b31b9e-03dc-4a73-9a28-66bbb9497f28
Denied
Activity
All Comments Events ↑ Sort by Newest
John Clark
Requested access for an hour
a few seconds ago (Tuesday, March 17, 2026 7:22 PM)
🔔
John Clark
Was notified of their own request
a few seconds ago (Tuesday, March 17, 2026 7:22 PM)
🔔
Matt Heffler
Was notified to review the request
a few seconds ago (Tuesday, March 17, 2026 7:22 PM)
O2
OpalScript 2: Breakglass Access
Was notified to review the request
a few seconds ago (Tuesday, March 17, 2026 7:22 PM)
💬
OpalScript 2: Breakglass Access
Commented on the request
a few seconds ago (Tuesday, March 17, 2026 7:22 PM)
Request Denied: Breakglass access requested, but no ticket specified
DENY BG · No Ticket
Breakglass flag is True and John Clark is in the authorized group — but ticket_number.strip() is empty. OpalScript denies immediately. No ticket, no access — even in an emergency.
Status: Denied — Instantly
The breakglass flag and group membership both pass — but the ticket check fails hard. The request moves Requested → Denied with no reviewer involvement. The guardrail holds even under incident pressure.
Audit-Ready Comment
OpalScript writes the exact BG_DENY_MSG to the request: "Request Denied: Breakglass access requested, but no ticket specified" — a clear, permanent record of why breakglass was blocked.
No Reviewer Burden
Matt Heffler shows No Action — notified but never needed. OpalScript resolved this entirely, keeping human reviewers out of a deny decision that required no judgment.
DEMO 2

Breakglass Access Control

BG · Auto-Approve ≤60m · 3 of 4
When breakglass is invoked with a valid ticket and the duration is 60 minutes or less, OpalScript instantly approves the request — no human reviewer required. John Clark's emergency EKS access is provisioned in seconds, with ticket NETOPS-15725 recorded in the audit trail.
Approved request
"Need breakglass access to solve an emergency issue with the EKS Cluster that is impacting multiple customers."
Requested For
JC
John Clark
Duration
an hour
Breakglass Access
True
Ticket Number
NETOPS-15725
Requested
Reviewed
Propagated
1 Requested Item
AWS
AdministratorAccess
Prod AWS Account/ · AWS IAM Role · More Info
Reviewers
Stage 1 ANY
SE Demo Reviewers
○ No Action
Reviewers
MH
Matt Heffler
matt@opal.dev
○ No Action
Individuals
O2
OpalScript 2: Breakglass Access
f3b31b9e-03dc-4a73-9a28-66bbb9497f28
Approved
Activity
John Clark
Requested access for an hour
a few seconds ago (Tuesday, March 17, 2026 7:27 PM)
John Clark
Was notified of their own request
a few seconds ago (Tuesday, March 17, 2026 7:27 PM)
Matt Heffler
Was notified to review the request
a few seconds ago (Tuesday, March 17, 2026 7:27 PM)
OpalScript 2: Breakglass Access
Was notified to review the request
a few seconds ago (Tuesday, March 17, 2026 7:28 PM)
OpalScript 2: Breakglass Access
Commented on the request
a few seconds ago (Tuesday, March 17, 2026 7:28 PM)
Access Approved: Breakglass access with duration of 1 hour. Ticket NETOPS-15725
Opal System
Changed the request status to approved
2 minutes ago (Tuesday, March 17, 2026 7:30 PM)
John Clark
Was assigned to the role
2 minutes ago (Tuesday, March 17, 2026 7:30 PM)
APPROVE Auto-Approve: BG ≤ 60 min
Breakglass is True, ticket NETOPS-15725 is present, and duration is 1 hour — within the 60-minute threshold. OpalScript automatically approves without escalating to a human reviewer.
Ticket Validates Intent
The script checks that a ticket exists before approving. Ticket NETOPS-15725 ties the breakglass event to a tracked incident — creating an audit trail without manual intervention.
Duration-Aware Policy
60 minutes is the auto-approve ceiling. Anything longer triggers manual review, keeping short-lived emergency access frictionless while protecting against open-ended grants.
Zero Human Latency
Matt Heffler was notified but took No Action — because none was needed. Access was provisioned instantly. The "Connect" button is live; John's emergency work begins immediately.
DEMO 2

Breakglass Access Control

Manual Review · 4 of 4
When breakglass is False — or the duration exceeds 60 minutes — OpalScript escalates to human review rather than making the call itself. Here, John Clark requested 8 hours of non-breakglass access. The script comments its reasoning, steps back, and leaves the decision to the reviewer.
Pending request
"Need breakglass access to solve an emergency issue with the EKS Cluster that is impacting multiple customers."
Requested For
JC
John Clark
Duration
8 hours
Breakglass Access
False
Requested
Review
Propagation
1 Requested Item
AWS
AdministratorAccess · Never Used
Prod AWS Account/ · AWS IAM Role · More Info
Reviewers
Stage 1 ANY
SE Demo Reviewers
○ No Action
Reviewers
MH
Matt Heffler
matt@opal.dev
○ No Action
Individuals
O2
OpalScript 2: Breakglass Access
f3b31b9e-03dc-4a73-9a28-66bbb9497f28
○ No Action
Activity
John Clark
Requested access for 8 hours
a few seconds ago (Tuesday, March 17, 2026 7:30 PM)
John Clark
Was notified of their own request
a few seconds ago (Tuesday, March 17, 2026 7:30 PM)
OpalScript 2: Breakglass Access
Was notified to review the request
a few seconds ago (Tuesday, March 17, 2026 7:30 PM)
Matt Heffler
Was notified to review the request
a few seconds ago (Tuesday, March 17, 2026 7:30 PM)
OpalScript 2: Breakglass Access
Commented on the request
a few seconds ago (Tuesday, March 17, 2026 7:30 PM)
Manual Review: Non-breakglass access requested. No ticket required.
REVIEW Manual Review: Non-BG or BG >60m
Breakglass is False and duration is 8 hours. Neither condition clears the auto-approve threshold. OpalScript explains its reasoning in a comment and steps aside — the request stays open, waiting on Matt Heffler.
Script Knows Its Limits
OpalScript doesn't block the request — it escalates it. The comment "Non-breakglass access requested" tells the reviewer exactly why automation deferred, without creating noise or ambiguity.
Duration as a Risk Signal
8 hours of AdministratorAccess is a meaningful window. The script treats long-duration requests as outside its safe auto-approve zone — a configurable threshold your team controls.
3
DEMO 3

Route Access by Role

Dynamically route access requests to the right approvers based on the requester's role and context
DEMO 3

Route Access by Role

The Script · 1 of 3
Not all GitHub roles carry the same risk. Admin and Write access can alter code and settings — they warrant a human review. Maintain, Triage, and Read are lower-privilege roles that can be safely auto-approved. This script enforces that distinction automatically, every time.
When assigned to request
Then
Run Opalscript
Script
Ask Opal to modify your Opalscript...
APPROVE_MSG = "Access Approved: Access request role is " REVIEW_MSG1 = "Access request role is " REVIEW_MSG2 = "Access request role is " OWNER_GROUP = "432298c8-e46d-48ca-9fb7-c3438bc29984" # Get request request = context.get_request() # For Github repos, obtain the access level for resource in request.requested_resources: if resource.resource_type == "GIT_HUB_REPO": role = resource.access_level_name # use remote_id, not name if role in ["admin", "write"]: actions.comment("Manual Review: " + REVIEW_MSG1 + role) notificationslib.notify_owner( OWNER_GROUP, "Manual Review Required", REVIEW_MSG1 + role ) elif role in ["maintain", "triage", "read"]: actions.approve(APPROVE_MSG + role) else: actions.comment("Manual Review: " + REVIEW_MSG2 + role) notificationslib.notify_owner( OWNER_GROUP, "Manual Review Required", REVIEW_MSG2 + role )
Opalscript is a Python-like configuration language. View the Opalscript documentation
REVIEW Admin or Write → Manual Review
Elevated roles that can push code or change settings are flagged for human review. The script comments its reasoning and notifies the owner group — the reviewer sees exactly why the request was held.
APPROVE Maintain, Triage, or Read → Auto-Approve
Lower-privilege roles carry minimal risk — OpalScript approves them instantly with a message recording the exact role granted. No reviewer time spent on routine, low-risk access.
REVIEW Unknown Role → Manual Review
The else branch defaults any unrecognized role to manual review — new GitHub role types introduced in the future are never silently auto-approved.
DEMO 3

Route Access by Role

Write Role · Manual Review · 2 of 3
John Clark requests Write access to infra-as-code-platform for a day — citing a disaster recovery deployment. Write is an elevated role. OpalScript flags it for human review, comments its reasoning, and notifies the owner group. Matt Heffler now has the full context to approve or deny.
Pending request
"Need write access to repo so I can make changes to accommodate deployment of new infrastructure for a disaster recovery region"
Requested For
JC
John Clark
Duration
a day
Requested
Review
Propagation
1 Requested Item
infra-as-code-platform
GitHub Opal/ · GitHub Repo · More Info
Role: write
Reviewers
Stage 1 ANY
SE Demo Reviewers
○ No Action
Reviewers
MH
Matt Heffler
matt@opal.dev
○ No Action
Individuals
O3
OpalScript 3: Route Based on Resource Type an...
13ff5ebb-b9d3-4623-893a-12d674032dbf
○ No Action
Activity
John Clark
Requested access for a day
a few seconds ago (Tuesday, March 17, 2026 7:46 PM)
John Clark
Was notified of their own request
a few seconds ago (Tuesday, March 17, 2026 7:46 PM)
OpalScript 3: Route Based on Resource Type and Role
Was notified to review the request
a few seconds ago (Tuesday, March 17, 2026 7:46 PM)
Matt Heffler
Was notified to review the request
a few seconds ago (Tuesday, March 17, 2026 7:46 PM)
OpalScript 3: Route Based on Resource Type and Role
Commented on the request
a few seconds ago (Tuesday, March 17, 2026 7:46 PM)
Manual Review: Access request role is write
REVIEW Write Role → Manual Review
Write access to infra-as-code-platform means the ability to push code to production infrastructure. OpalScript identifies this as a high-privilege role and escalates to Matt Heffler, recording the role name in the comment for full context.
Self-Documenting Decisions
The comment "Manual Review: Access request role is write" gives the reviewer instant context — no need to open a separate ticket or ask the requester why the request was flagged.
Owner Group Notified
Beyond commenting, the script calls notify_owner — pushing a "Manual Review Required" alert to the designated owner group so the right team is always in the loop.
DEMO 3

Route Access by Role

Read Role · Auto-Approve · 3 of 3
John Clark requests Read access to infra-as-code-platform to evaluate what changes are needed — a low-risk, read-only operation. OpalScript recognizes the role, approves instantly, and propagates access in seconds. Matt Heffler is notified but never needs to act.
Approved request
"Need read access to repo so I can evaluate what changes are needed to accommodate deployment of new infrastructure for a disaster recovery region"
Requested For
JC
John Clark
Duration
a day
Requested
Reviewed
Propagated
1 Requested Item
infra-as-code-platform
GitHub Opal/ · GitHub Repo · More Info
Role: read
Reviewers
Stage 1 ANY
SE Demo Reviewers
○ No Action
Reviewers
MH
Matt Heffler
matt@opal.dev
○ No Action
Individuals
O3
OpalScript 3: Route Based on Resource Type and Role
13ff5ebb-b9d3-4623-893a-12d674032dbf
Approved
Activity
John Clark
Requested access for a day
a few seconds ago (Tuesday, March 17, 2026 7:47 PM)
John Clark
Was notified of their own request
a few seconds ago (Tuesday, March 17, 2026 7:47 PM)
Matt Heffler
Was notified to review the request
a few seconds ago (Tuesday, March 17, 2026 7:47 PM)
OpalScript 3: Route Based on Resource Type and Role
Was notified to review the request
a few seconds ago (Tuesday, March 17, 2026 7:47 PM)
OpalScript 3: Route Based on Resource Type and Role
Commented on the request
a few seconds ago (Tuesday, March 17, 2026 7:47 PM)
Access Approved: Access request role is read
Opal System
Changed the request status to approved
2 minutes ago (Tuesday, March 17, 2026 7:49 PM)
John Clark
Was assigned the requested role
2 minutes ago (Tuesday, March 17, 2026 7:49 PM)
APPROVE Read Role → Auto-Approve
Read is the lowest-privilege GitHub role — view only, no ability to push changes. OpalScript approves immediately, propagates access, and logs the exact role in the comment. All three status dots turn green.
Fully Propagated in Seconds
Unlike the write request that stalled at Review, this one flows all the way through to Propagated — access is live immediately. No human needed in the loop for a read-only role.
Same Script, Two Outcomes
The same OpalScript handled both the write request (escalated) and this read request (approved). One policy applied consistently — no manual triage, no inconsistency between reviewers.
Audit Trail Included
The approval comment "Access Approved: Access request role is read" is permanently recorded in the activity feed — giving compliance teams a clear, machine-written log of every automated decision.
4
DEMO 4

Tiered Approval

Automatically route access requests through multiple approval tiers based on sensitivity and risk level
DEMO 4

Duration & Risk Tiered Approval

Tier 1 · Auto-Approve or Escalate · 1 of 3
TIER 1 OF 3 Auto-Approve or Escalate to Manager
The first gate in a three-script chain. It classifies the request by risk and duration — auto-approving low and medium-risk requests within one day, and passing everything else up the chain. Permanent access is blocked hard at this tier and every tier that follows.
When assigned to request
Then
Run Opalscript
Script
Ask Opal to modify your Opalscript...
# Tier 1 - Duration and Risk Tiered Approval (Tier 1 - Auto) HIGH_RISK = ["ACCOUNTADMIN", "ORGADMIN", "SECURITYADMIN", "SYSADMIN", "USERADMIN"] MEDIUM_RISK = ["CUSTOMER_READ", "CUSTOMER_SUPPORT"] LOW_RISK = ["PUBLIC"] # Get request request = context.get_request() # Determine risk risk = None for group in request.requested_groups: if group.group_name in HIGH_RISK: risk = "high" break elif group.group_name in MEDIUM_RISK: risk = "medium" break elif group.group_name in LOW_RISK: risk = "low" break # Get duration duration = request.requested_duration_minutes if not duration: actions.deny("Request Denied: Request for permanent access is prohibited") return # Evaluate risk and duration if risk == None: actions.deny() elif risk == "high": actions.approve() elif risk == "medium": if duration <= 1440: actions.approve("Request Approved: Request for medium-risk access level with duration 1-day or less") else: actions.approve() else: actions.approve("Request Approved: Request for low-risk access")
Opalscript is a Python-like configuration language. View the Opalscript documentation
APPROVE Low Risk (any duration) · Medium Risk ≤1 Day → Auto-Approve
PUBLIC is approved immediately regardless of duration. CUSTOMER_ roles with durations of one day or less are also approved with a recorded message. Neither requires human involvement.
ESCALATE High Risk (any duration) · Medium Risk >1 Day → Pass to Tier 2 (Manager)
High-risk roles (ACCOUNTADMIN, SYSADMIN, etc.) always exceed Tier 1's authority. Medium-risk requests beyond one day also escalate. actions.approve() with no message signals the next script in the chain to evaluate.
DENY Permanent Access (Any Risk Level) → Hard Deny
If no duration is set, the request is denied immediately regardless of role or risk — "Request for permanent access is prohibited." The same check runs at all three tiers, making it impossible to slip through at any stage.
Three Scripts, One Policy
Each tier shares the same risk classification logic but applies different thresholds. Updating a role list in one script doesn't automatically update the others — giving teams independent control over each approval level.
DEMO 4

Duration & Risk Tiered Approval

Tier 2 · Manager Approve or Escalate · 2 of 3
TIER 2 OF 3 Manager Review or Escalate to Director / VP
Picks up where Tier 1 left off. It approves low-risk requests outright and handles the medium-risk, longer-duration cases — flagging anything between 1 day and 1 month for manager review. High-risk roles are passed straight to Tier 3.
When assigned to request
Then
Run Opalscript
Script
Ask Opal to modify your Opalscript...
# Tier 2 – Duration and Risk Tiered Approval (Tier 2 – Manager) HIGH_RISK = ["ACCOUNTADMIN", "ORGADMIN", "SECURITYADMIN", "SYSADMIN", "USERADMIN"] MEDIUM_RISK = ["CUSTOMER_READ", "CUSTOMER_SUPPORT"] LOW_RISK = ["PUBLIC"] # Get request request = context.get_request() # Determine risk risk = None for group in request.requested_groups: if group.group_name in HIGH_RISK: risk = "high" break elif group.group_name in MEDIUM_RISK: risk = "medium" break elif group.group_name in LOW_RISK: risk = "low" break # Get duration duration = request.requested_duration_minutes if not duration: actions.deny("Request Denied: Request for permanent access is prohibited") return # Evaluate risk and duration if risk == None: actions.deny() elif risk == "high": actions.approve() elif risk == "medium": if duration <= 1440: actions.approve() elif duration <= 43200: actions.comment("Manager Approval Required: Request for medium-risk access level with duration 1 month or less") else: actions.approve() else: actions.approve()
Opalscript is a Python-like configuration language. View the Opalscript documentation
REVIEW Medium Risk, 1 Day–1 Month → Manager Review
Tier 2's key decision: CUSTOMER_READ or CUSTOMER_SUPPORT access for more than a day but less than a month (43,200 min) requires manager sign-off. The script comments the reason and waits.
APPROVE Low Risk or Short Duration → Auto-Approve
LOW_RISK (PUBLIC) is approved at this tier regardless of duration. Medium-risk requests already handled by Tier 1 (≤1 day) are also approved cleanly here.
ESCALATE High Risk → Pass to Tier 3 (Director / VP)
Tier 2 doesn't act on HIGH_RISK roles — it calls approve() with no message, signaling Tier 3 to take over. The chain is intentional and explicit.
Three Scripts, One Policy
Each tier shares the same risk classification logic but applies different thresholds. Updating a role list in one script doesn't automatically update the others — giving teams independent control over each approval level.
DEMO 4

Duration & Risk Tiered Approval

Tier 3 · Director / VP Approve · 3 of 3
TIER 3 OF 3 Director / VP Review
Handles everything the first two tiers couldn't resolve. High-risk admin roles always require Director or VP sign-off. Medium-risk access beyond one month is evaluated against a one-year ceiling — requests that exceed it are denied outright. No exceptions, no workarounds.
When assigned to request
Then
Run Opalscript
Script
Ask Opal to modify your Opalscript...
# Tier 3 – Duration and Risk Tiered Approval (Tier 3 – Director / VP) HIGH_RISK = ["ACCOUNTADMIN", "ORGADMIN", "SECURITYADMIN", "SYSADMIN", "USERADMIN"] MEDIUM_RISK = ["CUSTOMER_READ", "CUSTOMER_SUPPORT"] LOW_RISK = ["PUBLIC"] # Get request request = context.get_request() # Determine risk risk = None for group in request.requested_groups: if group.group_name in HIGH_RISK: risk = "high" break elif group.group_name in MEDIUM_RISK: risk = "medium" break elif group.group_name in LOW_RISK: risk = "low" break # Get duration duration = request.requested_duration_minutes if not duration: actions.deny("Request Denied: Request for permanent access is prohibited") return # Evaluate risk and duration if risk == None: actions.deny() elif risk == "high": actions.comment("Director/VP Approval Required: Request for high-risk access level") elif risk == "medium": if duration <= 43200: actions.approve() elif duration <= 525600: actions.comment("Director/VP Approval Required: Request for medium-risk access level with duration 1 year or less") else: actions.deny("Request Denied: Request for medium-risk access level with duration greater than 1 year is prohibited") else: actions.approve()
Opalscript is a Python-like configuration language. View the Opalscript documentation
REVIEW High Risk → Director/VP Required
ACCOUNTADMIN, SYSADMIN, and similar roles always reach Tier 3. No duration shortcut applies — every request for these roles must get a Director or VP to sign off, no exceptions.
DENY Medium Risk, >1 Year → Hard Deny
Requests for medium-risk access beyond 525,600 minutes (1 year) are denied outright — not escalated, not held. The policy has a ceiling, and this is it.
Three Scripts, One Policy
Each tier shares the same risk classification logic but applies different thresholds. Updating a role list in one script doesn't automatically update the others — giving teams independent control over each approval level.
DEMO 4

Duration & Risk Tiered Approval

Snowflake PUBLIC · Low Risk · All Tiers Auto-Approve
John Clark requests 7 days of Snowflake PUBLIC access. PUBLIC is LOW_RISK — Tier 1 classifies and passes the chain signal, Tier 2 auto-approves low-risk outright, and Tier 3 does the same. All three OpalScripts approve in sequence. No manager, no director, no reviewer queue — the entire three-tier chain resolves automatically.
Approved request
"I need access to the PUBLIC Snowflake role in order to retrieve data for an analysis project that has an end-of-week deadline."
Requested For
JC
John Clark
Duration
7 days
Requested
Reviewed
Propagated
1 Requested Item
PUBLIC
Snowflake/ · Snowflake Role · More Info
Reviewers
Stage 1
IndividualsStatus
O4
OpalScript 4: Duration and Risk Tiered ...
3d796dc1-a273-4582-8f0f-745d78339b85
Approved
Stage 2 ANY
OwnerStatus
SE Demo Manager ○ No Action
ReviewersStatus
AP
Adrian Pasqualini
adrian@opal.dev
○ No Action
IndividualsStatus
O4
OpalScript 4: Duration and Risk Tiered ...
01da60ca-f26c-4970-a91f-3a51d6dc00c3
Approved
Stage 3 ANY
OwnerStatus
SE Demo Director/VP ○ No Action
ReviewersStatus
DW
Dean Walker
dean@opal.dev
○ No Action
IndividualsStatus
O4
OpalScript 4: Duration and Risk Tiered ...
c4ff488d-94b2-444f-8b0a-552c4142de0f
Approved
Activity
All Comments Events ↓ Sort by Oldest
John Clark
Requested access for 7 days
an hour ago (Wednesday, March 18, 2026 11:53 AM)
🔔
John Clark
Was notified of their own request
an hour ago (Wednesday, March 18, 2026 11:53 AM)
O4
OpalScript 4: Duration and Risk Tiered Approval (Tier 1 - Auto)
Was notified to review the request
an hour ago (Wednesday, March 18, 2026 11:53 AM)
💬
OpalScript 4: Duration and Risk Tiered Approval (Tier 1 - Auto)
Commented on the request
an hour ago (Wednesday, March 18, 2026 11:53 AM)
Request Approved: Request for low-risk access
O4
OpalScript 4: Duration and Risk Tiered Approval (Tier 2 - Manager)
Was notified to review the request
an hour ago (Wednesday, March 18, 2026 11:53 AM)
O4
OpalScript 4: Duration and Risk Tiered Approval (Tier 3 - Director / VP)
Was notified to review the request
an hour ago (Wednesday, March 18, 2026 11:53 AM)
Opal System
Changed the request status to approved
43 minutes ago (Wednesday, March 18, 2026 11:55 AM)
John Clark
Was assigned the requested role
43 minutes ago (Wednesday, March 18, 2026 11:55 AM)
APPROVE PUBLIC · 7 Days → All Three Tiers Auto-Approve
PUBLIC is LOW_RISK. Tier 1 classifies and passes the chain signal, Tier 2 auto-approves all LOW_RISK regardless of duration, and Tier 3 does the same. No human reviewer at any stage needs to act — the entire chain resolves automatically.
Three Scripts, Zero Humans
All three OpalScripts fire and approve in sequence. Adrian Pasqualini (Manager) and Dean Walker (Director/VP) are notified but never need to act — the ANY stage condition is satisfied by OpalScript alone at each tier.
Three Scripts, One Policy
The same risk classification logic runs across all three tiers. For PUBLIC, the answer is the same at every level — low risk, no escalation, no ceiling. The tiered structure doesn't create friction for requests that don't need it.
DEMO 4

Duration & Risk Tiered Approval

CUSTOMER_SUPPORT · Medium Risk · Manager Review
John Clark requests 7 days of Snowflake CUSTOMER_SUPPORT access. CUSTOMER_SUPPORT is MEDIUM_RISK — Tier 1 evaluates the duration against the 1-day auto-approve threshold, finds it exceeded, and silently escalates to Tier 2. Tier 2 comments "Manager Approval Required" and queues Adrian Pasqualini for manual sign-off. Tier 3 is notified and armed, but dormant until Tier 2 resolves.
Pending request
"I need access to the CUSTOMER_SUPPORT Snowflake role for 1-week in order to retrieve metrics data for customer health analysis."
Requested For
JC
John Clark
Duration
7 days
Requested
Review
Propagation
1 Requested Item
CUSTOMER_SUPPORT · Never Used
Snowflake/ · Snowflake Role · More Info
Reviewers Send reminder to reviewers
Stage 1
IndividualsStatus
O4
OpalScript 4: Duration and Risk Tiered ...
3d796dc1-a273-4582-8f0f-745d78339b85
Approved
Stage 2 ANY
OwnerStatus
SE Demo Manager
○ No Action ▲ Hide Reviewers
ReviewersStatus
AP
Adrian Pasqualini
adrian@opal.dev
○ No Action
IndividualsStatus
O4
OpalScript 4: Duration and Risk Tiered ...
01da60ca-f26c-4970-a91f-3a51d6dc00c3
○ No Action
Stage 3 ANY
OwnerStatus
SE Demo Director/VP
○ No Action ▲ Hide Reviewers
ReviewersStatus
DW
Dean Walker
dean@opal.dev
○ No Action
IndividualsStatus
O4
OpalScript 4: Duration and Risk Tiered ...
c4ff488d-94b2-444f-8b0a-552c4142de0f
○ No Action
Activity
All Comments Events ↓ Sort by Oldest
John Clark
Requested access for 7 days
a few seconds ago (Wednesday, March 18, 2026 12:47 PM)
🔔
John Clark
Was notified of their own request
a few seconds ago (Wednesday, March 18, 2026 12:47 PM)
O4
OpalScript 4: Duration and Risk Tiered Approval (Tier 1 - Auto)
Was notified to review the request
a few seconds ago (Wednesday, March 18, 2026 12:47 PM)
O4
OpalScript 4: Duration and Risk Tiered Approval (Tier 2 - Manager)
Was notified to review the request
a few seconds ago (Wednesday, March 18, 2026 12:47 PM)
🔔
Adrian Pasqualini
Was notified to review the request
a few seconds ago (Wednesday, March 18, 2026 12:47 PM)
💬
OpalScript 4: Duration and Risk Tiered Approval (Tier 2 - Manager)
Commented on the request
a few seconds ago (Wednesday, March 18, 2026 12:47 PM)
Manager Approval Required: Request for medium-risk access level with duration 1 month or less
ESCALATE CUSTOMER_SUPPORT · 7 Days → Tier 1 Escalates to Manager
CUSTOMER_SUPPORT is MEDIUM_RISK. A 7-day request clears Tier 1 (duration ≤ 1 day would auto-approve; 7 days doesn't), so Tier 1 silently passes chain control to Tier 2. Tier 2 fires, comments "Manager Approval Required", and queues Adrian Pasqualini. Tier 3 is notified but waits.
Silent Escalation
Tier 1 approves without a message — the absence of a comment is the signal. The chain continues to Tier 2, which takes over, evaluates its own thresholds, and decides whether to auto-approve or require a human. No manual configuration needed between tiers.
Three Scripts, One Policy
The same risk classification logic runs across all three tiers. Each tier independently decides whether to act or pass — giving teams fine-grained control over every level of the approval chain.
DEMO 4

Duration & Risk Tiered Approval

ACCOUNTADMIN · High Risk · Director/VP Review
John Clark requests 1 month of Snowflake ACCOUNTADMIN access. ACCOUNTADMIN is HIGH_RISK — no duration shortcut applies. Tier 1 silently escalates to Tier 2, which also escalates and comments "Director/VP Approval Required." Tier 3 queues Dean Walker for manual sign-off. Both Tier 1 and Tier 2 OpalScripts approve in sequence; Tier 3 holds the chain for a Director or VP to decide.
Pending request
"I need access to the ACCOUNTADMIN Snowflake role for 1-month to administer resources across all accounts."
Requested For
JC
John Clark
Duration
a month
Requested
Review
Propagation
1 Requested Item
ACCOUNTADMIN · Never Used
Snowflake/ · Snowflake Role · More Info
Reviewers Send reminder to reviewers
Stage 1
IndividualsStatus
O4
OpalScript 4: Duration and Risk Tiered ...
3d796dc1-a273-4582-8f0f-745d78339b85
Approved
Stage 2 ANY
OwnerStatus
SE Demo Manager
○ No Action ▲ Hide Reviewers
ReviewersStatus
AP
Adrian Pasqualini
adrian@opal.dev
○ No Action
IndividualsStatus
O4
OpalScript 4: Duration and Risk Tiered ...
01da60ca-f26c-4970-a91f-3a51d6dc00c3
Approved
Stage 3 ANY
OwnerStatus
SE Demo Director/VP
○ No Action ▲ Hide Reviewers
ReviewersStatus
DW
Dean Walker
dean@opal.dev
○ No Action
IndividualsStatus
O4
OpalScript 4: Duration and Risk Tiered ...
c4ff488d-94b2-444f-8b0a-552c4142de0f
○ No Action
Activity
All Comments Events ↓ Sort by Oldest
John Clark
Requested access for a month
8 minutes ago (Wednesday, March 18, 2026 2:28 PM)
🔔
John Clark
Was notified of their own request
8 minutes ago (Wednesday, March 18, 2026 2:28 PM)
O4
OpalScript 4: Duration and Risk Tiered Approval (Tier 1 - Auto)
Was notified to review the request
8 minutes ago (Wednesday, March 18, 2026 2:28 PM)
O4
OpalScript 4: Duration and Risk Tiered Approval (Tier 2 - Manager)
Was notified to review the request
8 minutes ago (Wednesday, March 18, 2026 2:28 PM)
O4
OpalScript 4: Duration and Risk Tiered Approval (Tier 3 - Director / VP)
Was notified to review the request
8 minutes ago (Wednesday, March 18, 2026 2:28 PM)
🔔
Dean Walker
Was notified to review the request
8 minutes ago (Wednesday, March 18, 2026 2:28 PM)
💬
OpalScript 4: Duration and Risk Tiered Approval (Tier 3 - Director / VP)
Commented on the request
8 minutes ago (Wednesday, March 18, 2026 2:28 PM)
Director/VP Approval Required: Request for high-risk access level
ESCALATE ACCOUNTADMIN · 1 Month → All Three Tiers Fire, Director/VP Decides
ACCOUNTADMIN is HIGH_RISK — no duration shortcut exists. Tier 1 silently escalates, Tier 2 comments "Director/VP Approval Required" and escalates, and Tier 3 OpalScript queues Dean Walker. Two OpalScripts have approved; only the Director/VP can close this one out.
No Shortcut for High Risk
HIGH_RISK roles like ACCOUNTADMIN, SYSADMIN, and ORGADMIN always reach Stage 3 — every request, every duration. The three-tier chain exists precisely for this: no script can auto-approve its way past a Director or VP for the most sensitive roles.
Three Scripts, One Policy
The same risk classification logic runs at every tier. Each tier independently confirms the role is high-risk and passes the baton upward — a consistent, auditable chain from request to Director/VP decision.
5
DEMO 5

Separation of Duties

Automatically enforce SoD policies — block conflicting access before it's ever granted
DEMO 5

Separation of Duties

GitHub · Code 1 of 5
SCRIPT 1 OF 2 GitHub Repo — data-pipeline-analytics
No single person should be able to both write code and deploy it. This script runs on every request for the data-pipeline-analytics GitHub repo — if the requester already holds the EKSClusterAdmin deployment role, write/admin access is blocked on the spot. Script 2 (slide 19) covers the other side.
When assigned to request
Then
Run Opalscript
Script
Ask Opal to modify your Opalscript...
# On: GitHub repo (write/admin access) # Checks: does the requester already have deployment access? DEPLOY_ROLE_ID = "92a32260-be21-4a78-a1cb-cbf8aabb5987" # Opal resource UUID for deploy role SECURITY_OWNER_ID = "6551ba92-8ddc-4b24-aa8c-0c16a60ed758" request = context.get_request() requester = request.target_user_id if request.target_user_id != None else request.requester_id # Only apply SoD check for elevated roles elevated = ["admin", "write"] role_requested = None for resource in request.requested_resources: if resource.resource_type == "GIT_HUB_REPO": role_requested = resource.access_level_name break if role_requested in elevated: has_deploy = accesslib.check_access(requester, DEPLOY_ROLE_ID) if has_deploy: actions.deny( "Access Denied: User has deployment access and cannot be granted write/admin access to repo simultaneously" ) notificationslib.notify_owner( SECURITY_OWNER_ID, "SoD Violation Blocked", "User " + requester + " was denied GitHub write access due to existing deployment access. Request ID: " + request.id ) return # Starlark doesn't support return at top level — wrap in def main() actions.approve("Access Approved")
Opalscript is a Python-like configuration language. View the Opalscript documentation
DENY Has Deployment + Requests Write/Admin → Blocked
If the requester already holds the EKSClusterAdmin role, any request for GitHub write or admin access is denied immediately. The conflict is caught before access is granted — not after.
APPROVE No Deployment Conflict → Access Granted
Requesters without the deployment role pass the SoD check cleanly. Read-only and non-elevated roles bypass the check entirely — the script only enforces where the risk actually exists.
Security Team Alerted on Every Block
notificationslib.notify_owner() fires on every denial — the security owner receives the requester ID and request ID, creating a real-time audit trail of attempted SoD violations.
DEMO 5

Separation of Duties

EKSClusterAdmin · Code 2 of 5
SCRIPT 2 OF 2 Prod AWS Account IAM Role — EKSClusterAdmin
This script runs on every request for the Prod AWS Account IAM Role — EKSClusterAdmin. It checks whether the requester already holds GitHub write or admin access to the repo — if they do, deployment access is denied, closing the other side of the SoD pair established in Script 1 (slide 18).
When assigned to request
Then
Run Opalscript
Script
Ask Opal to modify your Opalscript...
# On: AWS deployment IAM role (or EKS/ECS resource) # Checks: does the requester already have GitHub write/admin access? GITHUB_REPO_ID = "18554406-f439-4a87-9ff5-2527c298292f" # Opal resource UUID for the repo SECURITY_OWNER_ID = "6551ba92-8ddc-4b24-aa8c-0c16a60ed758" request = context.get_request() requester = request.target_user_id if request.target_user_id != None else request.requester_id # Check for write (push) or admin access to the repo has_write = accesslib.check_access(requester, GITHUB_REPO_ID, "push") has_admin = accesslib.check_access(requester, GITHUB_REPO_ID, "admin") if has_write or has_admin: actions.deny( "Access Denied: Requester has write/admin to repo and cannot be granted deployment access simultaneously" ) notificationslib.notify_owner( SECURITY_OWNER_ID, "SoD Violation Blocked", "User " + requester + " was denied deployment access due to existing GitHub write access. Request ID: " + request.id ) else: actions.approve("Access Approved")
Opalscript is a Python-like configuration language. View the Opalscript documentation
DENY Has GitHub Write/Admin → Deployment Blocked
If accesslib.check_access() confirms the requester holds push or admin rights to the repo, EKSClusterAdmin access is denied. Both sides of the privilege pair are now enforced.
APPROVE No Code Access Conflict → Deployment Granted
Requesters with no GitHub write or admin rights pass cleanly. Ops engineers who deploy but don't write code are approved without friction.
Live Permission Check at Request Time
accesslib.check_access() queries live access state — not a stale snapshot. If someone was granted GitHub write an hour ago, this script catches it the moment they request deployment access.
DEMO 5

Separation of Duties

EKSClusterAdmin · Approved · 3 of 5
John Clark holds no GitHub write or admin access to data-pipeline-analytics. OpalScript checks accesslib.check_access() for both push and admin — gets false for both — and approves EKSClusterAdmin immediately. No conflict, no violation, no delay.
Approved request
"Need admin access to the EKS Cluster in production AWS account so I can deploy the new data analysis code needed to process PII data."
Requested For
JC
John Clark
Duration
an hour
Requested
Reviewed
Propagated
1 Requested Item
AWS
EKSClusterAdmin
Prod AWS Account/ · AWS IAM Role · More Info
Reviewers
Stage 1 ANY
IndividualsStatus
O5
OpalScript 5: Separation of Duties (Prod AWS Account I...
20596879-0f73-4c60-b085-1d916778775b
Approved
Activity
All Comments Events ↑ Sort by Newest
John Clark
Requested access for an hour
a few seconds ago (Wednesday, March 18, 2026 8:47 AM)
🔔
John Clark
Was notified of their own request
a few seconds ago (Wednesday, March 18, 2026 8:47 AM)
O5
OpalScript 5: Separation of Duties (Prod AWS Account IAM Role - EKSClusterAdmin)
Was notified to review the request
a few seconds ago (Wednesday, March 18, 2026 8:47 AM)
💬
OpalScript 5: Separation of Duties (Prod AWS Account IAM Role - EKSClusterAdmin)
Commented on the request
a few seconds ago (Wednesday, March 18, 2026 8:47 AM)
Access Approved
Opal System
Changed the request status to approved
2 minutes ago (Wednesday, March 18, 2026 8:49 AM)
John Clark
Was assigned the requested role
2 minutes ago (Wednesday, March 18, 2026 8:49 AM)
APPROVE No GitHub Conflict → EKS Access Granted
John Clark holds no push or admin rights to the GitHub repo. Both check_access(requester, GITHUB_REPO_ID, "push") and "admin" return false — OpalScript approves and the access propagates immediately.
Status: Requested → Reviewed → Propagated
All three steps complete green with no reviewer involvement. Ops engineers who deploy but don't write code move through instantly — SoD enforcement adds zero friction for compliant users.
Live Permission Check at Request Time
accesslib.check_access() queries live access state — not a stale snapshot. If someone was granted GitHub write an hour ago, this script catches it the moment they request EKS access.
DEMO 5

Separation of Duties

GitHub Write · SoD Violation · 4 of 5
John Clark already holds EKSClusterAdmin. When he requests write access to data-pipeline-analytics, OpalScript checks his existing access — finds the conflict — and denies before any reviewer sees the request. The security team is notified in real time.
Denied request
"Requesting write access to the data analysis code reposition to update with new capability to process customer PII data."
Requested For
JC
John Clark
Duration
a day
Requested
Denied
Propagation
1 Requested Item
data-pipeline-analytics
GitHub Opal/ · GitHub Repo · More Info
Role: write
Reviewers
Stage 1 ANY
IndividualsStatus
O5
OpalScript 5: Separation of Duties (Github Repo - data-pipeli...
6e1ef633-335d-46b0-8694-5b40d8a3e088
Denied
Activity
All Comments Events ↑ Sort by Newest
John Clark
Requested access for a day
a few seconds ago (Wednesday, March 18, 2026 8:48 AM)
🔔
John Clark
Was notified of their own request
a few seconds ago (Wednesday, March 18, 2026 8:48 AM)
O5
OpalScript 5: Separation of Duties (Github Repo - data-pipeline-analytics)
Was notified to review the request
a few seconds ago (Wednesday, March 18, 2026 8:48 AM)
💬
OpalScript 5: Separation of Duties (Github Repo - data-pipeline-analytics)
Commented on the request
a few seconds ago (Wednesday, March 18, 2026 8:48 AM)
Access Denied: User has deployment access and cannot be granted write/admin access to repo simultaneously
DENY Has EKS Access + Requests Write → Blocked
John Clark holds EKSClusterAdmin. Requesting GitHub write access creates a direct SoD conflict — the script detects it via accesslib.check_access() and denies before any reviewer is involved.
Status: Denied — Instantly
The request moves Requested → Denied with no reviewer queue. The SoD guardrail holds regardless of business justification — even under urgency, the rule is enforced the same way, every time.
Security Team Alerted on Every Block
notificationslib.notify_owner() fires on every denial — the security owner receives the requester ID and request ID, creating a real-time audit trail of every attempted SoD violation.
DEMO 5

Separation of Duties

GitHub Read · SoD Compliant · 5 of 5
Same user, same EKS access — but requesting read-only access to data-pipeline-analytics. OpalScript only checks for push and admin rights. Neither exists for read, so the script approves cleanly. Read access doesn't create a deployment conflict.
Approved request
"Requesting read access to the data analysis code reposition to review the repo related to how PII data is processed."
Requested For
JC
John Clark
Duration
an hour
Requested
Reviewed
Propagated
1 Requested Item
data-pipeline-analytics
GitHub Opal/ · GitHub Repo · More Info
Role: read
Reviewers
Stage 1 ANY
IndividualsStatus
O5
OpalScript 5: Separation of Duties (Github Repo - data-pipeli...
6e1ef633-335d-46b0-8694-5b40d8a3e088
Approved
Activity
All Comments Events ↑ Sort by Newest
John Clark
Requested access for an hour
a few seconds ago (Wednesday, March 18, 2026 8:50 AM)
🔔
John Clark
Was notified of their own request
a few seconds ago (Wednesday, March 18, 2026 8:50 AM)
O5
OpalScript 5: Separation of Duties (Github Repo - data-pipeline-analytics)
Was notified to review the request
a few seconds ago (Wednesday, March 18, 2026 8:50 AM)
💬
OpalScript 5: Separation of Duties (Github Repo - data-pipeline-analytics)
Commented on the request
a few seconds ago (Wednesday, March 18, 2026 8:50 AM)
Access Approved
Opal System
Changed the request status to approved
2 minutes ago (Wednesday, March 18, 2026 8:52 AM)
John Clark
Was added to the requested group
2 minutes ago (Wednesday, March 18, 2026 8:52 AM)
APPROVE Read Role Bypasses SoD Check → Access Granted
The script only blocks push and admin access. Read roles carry no deployment risk, so has_write and has_admin are both false — the else branch runs and approves immediately.
Precision Enforcement — Not Over-Blocking
SoD doesn't mean locking down everything. The policy targets the specific privilege combination that creates risk. Read access for an ops engineer who deploys is legitimate — and OpalScript lets it through without any human review.
Two Scripts, One Policy
Both scripts enforce the same SoD rule from opposite directions — one guards GitHub, the other guards deployment. Together they close every path a user might take to hold both privileges simultaneously.

Built for Safety

OpalScript's architecture ensures your access policies are reliable and secure
Deterministic
Same input always produces the same output. No network calls, no randomness, no surprises.
Sandboxed
Scripts run in an isolated environment. They can't access the filesystem, network, or other resources.
Resource Limits
CPU time, memory, and execution duration are all capped. A bad script can't take down Opal.
Python-like Syntax
Familiar syntax that any developer can read and write. No new language to learn.

What's Next

Extending OpalScript to more Opal lifecycle events
User Access Reviews
H1 2026
Trigger custom logic during certification campaigns to auto-certify or flag based on usage patterns
Attribute Transformation
H1 2026
Transform and normalize user attributes from identity providers before they reach Opal's policy engine
Custom Provisioning
H2 2026
Define custom provisioning workflows for applications that need special handling beyond standard connectors
General Extension Points
H2 2026
Hook into any Opal lifecycle event -- from group membership changes to compliance checks

Try OpalScript Today

Start writing access policies in minutes. OpalScript is available now in your Opal dashboard.
< 5 min
Setup Time
0
Servers Needed
100%
Sandboxed
Opal Demo Hub
Home Product Roadmap OpalScript OpalQuery Paladin UAR Reimagined