Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 2 additions & 5 deletions .github/workflows/py-sdk-build-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ jobs:

publish_test:
name: Publish to Test PyPI
if: github.ref != 'refs/heads/main'
needs: [build_wheels, build_sdist]
runs-on: ubuntu-latest
#environment: pypi
Expand Down Expand Up @@ -205,8 +206,4 @@ jobs:
- name: Publish package
uses: pypa/gh-action-pypi-publish@release/v1
with:
packages-dir: dist

- uses: softprops/action-gh-release@v2
with:
files: dist/*
packages-dir: dist
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,6 @@ __pycache__/
lib_actra_core.dylib.dSYM/
.pytest_cache/
venv_test
wheelhouse
wheelhouse
____*/
____*
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ members = [
resolver = "2"

[workspace.package]
version = "0.2.2"
version = "0.3.0"
edition = "2021"
license = "Apache-2.0"
authors = ["Amit Saxena"]
Expand Down
124 changes: 124 additions & 0 deletions examples/python/core-sdk/basic_refund.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
"""
Basic Actra Example

This example shows how Actra can enforce admission
control policies on normal Python functions.

Actra evaluates a policy BEFORE the function executes
and blocks the call if the policy denies it.
"""

from actra import Actra
from actra.runtime import ActraRuntime


# ------------------------------------------------------------
# 1. Schema definition
# ------------------------------------------------------------
# The schema defines the structure of data that policies
# are allowed to reference.
#
# Domains:
# - action : parameters passed to the function
# - actor : identity of the caller
# - snapshot : external system state
#
schema_yaml = """
version: 1

actions:
refund:
fields:
amount: number

actor:
fields:
role: string

snapshot:
fields:
fraud_flag: boolean
"""


# ------------------------------------------------------------
# 2. Policy definition
# ------------------------------------------------------------
# This policy blocks refunds larger than 1000
#
# Scope limits the rule to the "refund" action
# The rule inspects the action.amount field
#
policy_yaml = """
version: 1

rules:
- id: block_large_refund
scope:
action: refund
when:
subject:
domain: action
field: amount
operator: greater_than
value:
literal: 1000
effect: block
"""

# ------------------------------------------------------------
# 3. Compile policy
# ------------------------------------------------------------

policy = Actra.from_strings(schema_yaml, policy_yaml)

# ------------------------------------------------------------
# 4. Create runtime
# ------------------------------------------------------------

runtime = ActraRuntime(policy)

# ------------------------------------------------------------
# 5. Register context resolvers
# ------------------------------------------------------------
# Resolvers dynamically supply runtime context used by policies.
#
# actor_resolver : information about the caller
# snapshot_resolver: external system state
#

runtime.set_actor_resolver(lambda ctx: {"role": "support"})
runtime.set_snapshot_resolver(lambda ctx: {"fraud_flag": False})


# ------------------------------------------------------------
# 6. Protect a function with Actra
# ------------------------------------------------------------
# The @runtime.admit decorator intercepts the function call
# and evaluates policies before execution.
#
# 1. Default mapping
# @runtime.admit() : all kwargs become action fields
#
# 2. Field filtering
# @runtime.admit(fields=["amount"])
#
# 3. Custom action builder
# @runtime.admit(action_builder=my_builder)
#

@runtime.admit()
def refund(amount: int):
print("Refund executed:", amount)


# ------------------------------------------------------------
# 7. Execute calls
# ------------------------------------------------------------

print("\n--- Allowed call ---")
refund(amount=200)


print("\n--- Blocked call ---")
refund(amount=1500)
107 changes: 107 additions & 0 deletions examples/python/core-sdk/custom_action_builder.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
"""
Custom Action Builder Example

This example demonstrates how to provide a custom function
to construct the Actra action object.

Custom builders are useful when application inputs do not
map directly to policy fields.
"""

from actra import Actra
from actra.runtime import ActraRuntime


# ------------------------------------------------------------
# 1. Schema
# ------------------------------------------------------------

schema_yaml = """
version: 1

actions:
refund:
fields:
amount: number

actor:
fields:
role: string

snapshot:
fields:
fraud_flag: boolean
"""


# ------------------------------------------------------------
# 2. Policy
# ------------------------------------------------------------

policy_yaml = """
version: 1

rules:
- id: block_large_refund
scope:
action: refund
when:
subject:
domain: action
field: amount
operator: greater_than
value:
literal: 1000
effect: block
"""


# ------------------------------------------------------------
# 3. Compile policy
# ------------------------------------------------------------

policy = Actra.from_strings(schema_yaml, policy_yaml)
runtime = ActraRuntime(policy)


# ------------------------------------------------------------
# 4. Register resolvers
# ------------------------------------------------------------

runtime.set_actor_resolver(lambda ctx: {"role": "support"})
runtime.set_snapshot_resolver(lambda ctx: {"fraud_flag": False})


# ------------------------------------------------------------
# 5. Custom action builder
# ------------------------------------------------------------

def build_refund_action(action_type, args, kwargs, ctx):
"""
Convert application inputs into the policy action object.
"""

return {
"type": action_type,
"amount": kwargs["amount"]
}


# ------------------------------------------------------------
# 6. Protect function using custom builder
# ------------------------------------------------------------

@runtime.admit(action_builder=build_refund_action)
def refund(amount: int, currency: str):
print(f"Refund executed: {amount} {currency}")


# ------------------------------------------------------------
# 7. Calls
# ------------------------------------------------------------

print("\nAllowed call")
refund(amount=200, currency="USD")

print("\nBlocked call")
refund(amount=1500, currency="USD")
88 changes: 88 additions & 0 deletions examples/python/core-sdk/custom_actor_snapshot_resolvers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
"""
Custom Actor and Snapshot Resolvers Example

Demonstrates how runtime context can be used to dynamically
resolve actor and system state.
"""

from actra import Actra, ActraRuntime


schema_yaml = """
version: 1

actions:
refund:
fields:
amount: number

actor:
fields:
role: string

snapshot:
fields:
fraud_flag: boolean
"""


policy_yaml = """
version: 1

rules:
- id: block_large_refund_for_support
scope:
action: refund
when:
all:
- subject:
domain: action
field: amount
operator: greater_than
value:
literal: 1000
- subject:
domain: actor
field: role
operator: equals
value:
literal: "support"
effect: block
"""


policy = Actra.from_strings(schema_yaml, policy_yaml)
runtime = ActraRuntime(policy)


# Example request context
class RequestContext:
def __init__(self, role, fraud_flag):
self.role = role
self.fraud_flag = fraud_flag


# Actor resolver
runtime.set_actor_resolver(
lambda ctx: {"role": ctx.role}
)

# Snapshot resolver
runtime.set_snapshot_resolver(
lambda ctx: {"fraud_flag": ctx.fraud_flag}
)


ctx = RequestContext(role="support", fraud_flag=False)


action = runtime.build_action(
action_type="refund",
args=(),
kwargs={"amount": 2000},
ctx=ctx
)

decision = runtime.evaluate(action, ctx)

print(decision)
Loading
Loading