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
100 changes: 100 additions & 0 deletions .github/workflows/phase1-ci-and-release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
name: phase1-ci-and-release

on:
pull_request:
push:
branches: ["main", "phase1"]
workflow_dispatch:
inputs:
publish:
description: "Run ordered publish jobs"
required: true
default: "false"
type: choice
options: ["false", "true"]

jobs:
quality:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.11"

- name: Install dependencies
run: python -m pip install --upgrade pip pre-commit pytest

- name: Verify package release order
run: python scripts/verify_release_order.py

- name: Run tests
run: python -m pytest -q

- name: Run pre-commit checks
run: pre-commit run --all-files

publish-predicate-contracts:
runs-on: ubuntu-latest
needs: [quality]
if: github.event_name == 'workflow_dispatch' && inputs.publish == 'true'
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.11"

- name: Install build tooling
run: python -m pip install --upgrade pip build twine

- name: Verify release order
run: python scripts/verify_release_order.py

- name: Build predicate-contracts
run: python -m build predicate_contracts

- name: Validate distribution metadata
run: twine check predicate_contracts/dist/*

- name: Publish predicate-contracts to PyPI
env:
TWINE_USERNAME: __token__
TWINE_PASSWORD: ${{ secrets.PYPI_TOKEN_PREDICATE_CONTRACTS }}
run: twine upload predicate_contracts/dist/*

publish-predicate-authority:
runs-on: ubuntu-latest
needs: [publish-predicate-contracts]
if: github.event_name == 'workflow_dispatch' && inputs.publish == 'true'
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.11"

- name: Install build tooling
run: python -m pip install --upgrade pip build twine

- name: Verify release order
run: python scripts/verify_release_order.py

- name: Build predicate-authority
run: python -m build predicate_authority

- name: Validate distribution metadata
run: twine check predicate_authority/dist/*

- name: Publish predicate-authority to PyPI
env:
TWINE_USERNAME: __token__
TWINE_PASSWORD: ${{ secrets.PYPI_TOKEN_PREDICATE_AUTHORITY }}
run: twine upload predicate_authority/dist/*
30 changes: 30 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
name: tests

on:
pull_request:
push:
branches: ["main", "phase1"]
workflow_dispatch:

jobs:
pytest:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version: ["3.11", "3.12"]

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}

- name: Install test dependencies
run: python -m pip install --upgrade pip pytest

- name: Run tests
run: python -m pytest -q
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -55,3 +55,7 @@ traces/
artifacts/
tmp/
temp/

# Local build artifacts from package-level builds
predicate_authority/predicate_authority/
predicate_contracts/predicate_contracts/
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Pre-commit hooks for AgentIdentity repository
# Pre-commit hooks for predicate-authority repository
# Baseline adapted from /Code/Sentience/sdk-python/.pre-commit-config.yaml

repos:
Expand Down
17 changes: 16 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,11 +1,26 @@
.PHONY: hooks lint format format-python format-docs lint-docs
.PHONY: hooks lint test examples verify-release-order build-packages format format-python format-docs lint-docs

hooks:
pre-commit install

lint:
pre-commit run --all-files

test:
python -m pytest -q

examples:
PYTHONPATH=. python examples/browser_guard_example.py
PYTHONPATH=. python examples/mcp_tool_guard_example.py
PYTHONPATH=. python examples/outbound_http_guard_example.py

verify-release-order:
python scripts/verify_release_order.py

build-packages:
python -m build predicate_contracts
python -m build predicate_authority

format: format-python format-docs

format-python:
Expand Down
149 changes: 149 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
# Predicate Authority

**Deterministic Authority for AI Agents: Secure the "Confused Deputy" with your existing Identity stack.**

[![License](https://img.shields.io/badge/License-MIT%2FApache--2.0-blue.svg)](LICENSE)
[![PyPI - predicate-authority](https://img.shields.io/pypi/v/predicate-authority.svg)](https://pypi.org/project/predicate-authority/)
[![PyPI - predicate-contracts](https://img.shields.io/pypi/v/predicate-contracts.svg)](https://pypi.org/project/predicate-contracts/)

`predicate-authority` is a production-grade pre-execution authority layer that binds AI agent identity to deterministic state. It bridges standard IdPs (Entra ID, Okta, OIDC) with runtime verification so every sensitive action is authorized, bounded, and provable.

## Why Predicate Authority?

Most agent security fails because it relies on static API keys or broad permissions. Predicate introduces short-lived mandates that are cryptographically tied to:

- `state_hash` (what state the agent is in),
- `intent_hash` (what action it intends to perform),
- policy constraints and required verification labels.

This closes the confused-deputy gap where an agent can misuse delegated credentials.

- **Bridge, don't replace**: leverage existing enterprise identity and governance.
- **Fail-closed by design**: deny before execution when state/intent/policy checks fail.
- **Deterministic binding**: authority is tied to runtime evidence, not only identity.
- **Provable controls**: each decision can emit signed proof events for audit pipelines.

### Why not just use IdP directly?

You should still use Entra/Okta/OIDC for identity and token issuance. `predicate-authority` adds the runtime control layer those systems do not provide by default for AI agents:

- pre-execution allow/deny checks right before each sensitive action,
- binding authority to current `state_hash` and `intent_hash`,
- optional required verification labels from runtime checks (currently web-agent only via [predicate-sdk](https://github.com/PredicateSystems/sdk-python) integration),
- fail-closed local enforcement and per-decision proof events.

In practice: IdP answers **who the principal is**, while `predicate-authority` answers **whether this exact action is allowed right now in this state**.

## Repository Components

| Package | Purpose |
| --- | --- |
| `predicate_contracts` | Shared typed contracts and protocols (`ActionRequest`, `PolicyRule`, evidence, decision/proof models). |
| `predicate_authority` | Runtime authorization engine (`PolicyEngine`, `ActionGuard`, mandate signing, proof ledger, telemetry emitter). |
| `examples/` | Browser/MCP/HTTP guard examples using the local Phase 1 runtime. |

## Phase 1 Status

Implemented in this repository:

- local pre-execution `ActionGuard.authorize(...)` and `enforce(...)`,
- signed local mandates with TTL (`LocalMandateSigner`),
- policy evaluation with deny precedence and required verification labels,
- typed [predicate-sdk](https://github.com/PredicateSystems/sdk-python) integration adapter (`predicate_authority.integrations`),
- OpenTelemetry-compatible trace emitter (`OpenTelemetryTraceEmitter`),
- pytest coverage for core authorization, mandate, integration, and telemetry flows.

Planned in upcoming phases:

- `predicate-authorityd` sidecar for token lifecycle and local kill-switch,
- enterprise IdP bridge hardening (Entra/Okta/OIDC adapters),
- hosted governance control plane.

## Installation

```bash
pip install predicate-authority
```

For shared contracts directly:

```bash
pip install predicate-contracts
```

## Quick Start (Phase 1 API)

```python
from predicate_authority import ActionGuard, InMemoryProofLedger, LocalMandateSigner, PolicyEngine
from predicate_contracts import (
ActionRequest,
ActionSpec,
PolicyEffect,
PolicyRule,
PrincipalRef,
StateEvidence,
VerificationEvidence,
)

guard = ActionGuard(
policy_engine=PolicyEngine(
rules=(
PolicyRule(
name="allow-payment-submit",
effect=PolicyEffect.ALLOW,
principals=("agent:payments",),
actions=("http.post",),
resources=("https://finance.example.com/transfers",),
),
)
),
mandate_signer=LocalMandateSigner(secret_key="dev-secret"),
proof_ledger=InMemoryProofLedger(),
)

request = ActionRequest(
principal=PrincipalRef(principal_id="agent:payments"),
action_spec=ActionSpec(
action="http.post",
resource="https://finance.example.com/transfers",
intent="submit transfer request #1234",
),
state_evidence=StateEvidence(source="backend", state_hash="state-hash-abc"),
verification_evidence=VerificationEvidence(),
)

decision = guard.authorize(request)
if not decision.allowed:
raise RuntimeError(f"Authority denied: {decision.reason.value}")
```

See runnable examples in:

- `examples/browser_guard_example.py`
- `examples/mcp_tool_guard_example.py`
- `examples/outbound_http_guard_example.py`

## Security: Local Kill-Switch Path

The current Phase 1 runtime supports fail-closed checks and local proof emission. The sidecar model (`predicate-authorityd`) is planned to provide instant local revocation and managed token lifecycle for long-running production agents.

## Release

- CI workflow: `.github/workflows/phase1-ci-and-release.yml`
- Release guide: `docs/pypi-release-guide.md`

Publish order is always:

1. `predicate-contracts`
2. `predicate-authority`

## License

Dual-licensed under **MIT** and **Apache 2.0**:

- `LICENSE-MIT`
- `LICENSE-APACHE`

---

Copyright (c) 2026 Predicate Systems Inc.
Loading