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
107 changes: 107 additions & 0 deletions .github/workflows/update-sidecar-version.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
name: Update Sidecar Version Reference

on:
repository_dispatch:
types: [sidecar-release]
workflow_dispatch:
inputs:
version:
description: 'Sidecar version tag (e.g., v0.1.0)'
required: true
type: string
publish_sidecar_package:
description: 'Publish predicate-authority-sidecar to PyPI'
required: false
type: boolean
default: false

jobs:
update-and-publish:
name: Update sidecar version and optionally publish
runs-on: ubuntu-latest
permissions:
contents: write
id-token: write

steps:
- uses: actions/checkout@v4

- name: Get version
id: version
run: |
if [ "${{ github.event_name }}" = "repository_dispatch" ]; then
VERSION="${{ github.event.client_payload.version }}"
else
VERSION="${{ inputs.version }}"
fi
# Remove 'v' prefix for Python package version
PY_VERSION="${VERSION#v}"
echo "version=$VERSION" >> $GITHUB_OUTPUT
echo "py_version=$PY_VERSION" >> $GITHUB_OUTPUT
echo "Sidecar version: $VERSION (Python: $PY_VERSION)"

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

- name: Install build tools
run: pip install build twine

- name: Update sidecar package version
run: |
PY_VERSION="${{ steps.version.outputs.py_version }}"
sed -i "s/version = \".*\"/version = \"$PY_VERSION\"/" predicate_authority_sidecar/pyproject.toml
echo "Updated predicate-authority-sidecar to version $PY_VERSION"
cat predicate_authority_sidecar/pyproject.toml

- name: Build sidecar package
working-directory: predicate_authority_sidecar
run: python -m build

- name: Publish to PyPI (if requested or on dispatch)
if: github.event_name == 'repository_dispatch' || inputs.publish_sidecar_package
working-directory: predicate_authority_sidecar
env:
TWINE_USERNAME: __token__
TWINE_PASSWORD: ${{ secrets.PYPI_TOKEN }}
run: |
echo "Publishing predicate-authority-sidecar to PyPI..."
twine upload dist/* --skip-existing

- name: Commit version update
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add predicate_authority_sidecar/pyproject.toml
git commit -m "chore: update sidecar package to ${{ steps.version.outputs.version }}" || echo "No changes to commit"
git push

- name: Create notification issue
uses: actions/github-script@v7
with:
script: |
const version = '${{ steps.version.outputs.version }}';
const pyVersion = '${{ steps.version.outputs.py_version }}';
const releaseUrl = '${{ github.event.client_payload.release_url || 'N/A' }}';
const published = '${{ github.event_name }}' === 'repository_dispatch' || '${{ inputs.publish_sidecar_package }}' === 'true';

await github.rest.issues.create({
owner: context.repo.owner,
repo: context.repo.repo,
title: `Sidecar ${version} released`,
body: `A new version of the Predicate Authority sidecar has been released.\n\n` +
`**Sidecar Version:** ${version}\n` +
`**Release:** ${releaseUrl}\n\n` +
`**Python Package:** predicate-authority-sidecar ${pyVersion}\n` +
`**Published to PyPI:** ${published ? 'Yes' : 'No'}\n\n` +
`## Installation\n\n` +
`\`\`\`bash\n` +
`pip install predicate-authority[sidecar]\n` +
`\`\`\`\n\n` +
`Or download manually:\n` +
`\`\`\`bash\n` +
`predicate-download-sidecar --version ${version}\n` +
`\`\`\``,
labels: ['sidecar-release', 'automated']
});
33 changes: 33 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,19 @@ This SDK requires the **Predicate Authority Sidecar** daemon to be running. The

### Quick Sidecar Setup

**Option A: Install with sidecar (recommended)**

```bash
# Install SDK with automatic sidecar download
pip install predicate-authority[sidecar]

# The sidecar binary is downloaded automatically on first use
# Or manually trigger download:
predicate-download-sidecar
```

**Option B: Manual download**

```bash
# Download the latest release for your platform
# Linux x64, macOS x64/ARM64, Windows x64 available
Expand All @@ -78,10 +91,30 @@ chmod +x predicate-authorityd
./predicate-authorityd run --port 8787 --mode local_only --policy-file policy.json
```

### Running the sidecar from Python

```python
from predicate_authority import run_sidecar, is_sidecar_available, download_sidecar

# Download if not available
if not is_sidecar_available():
download_sidecar()

# Run sidecar as subprocess
process = run_sidecar(port=8787, policy_file="policy.json")

# Later: graceful shutdown
process.terminate()
process.wait()
```

## Installation

```bash
pip install predicate-authority

# Or with sidecar binary:
pip install predicate-authority[sidecar]
```

For local editable development in this monorepo, install both package roots
Expand Down
140 changes: 91 additions & 49 deletions docs/authorityd-operations.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,67 @@

This guide shows how to run the local sidecar daemon, provide a policy file, and verify health/status endpoints.

---

## Sidecar Installation

The sidecar (`predicate-authorityd`) is a lightweight Rust binary that handles policy evaluation and mandate signing.

### Option A: Install via pip (recommended for Python users)

```bash
# Install SDK with sidecar extra - downloads binary automatically
pip install predicate-authority[sidecar]

# Or manually trigger download after installing core SDK
pip install predicate-authority
predicate-download-sidecar
```

Binary location after install:
- macOS: `~/Library/Application Support/predicate-authority/bin/predicate-authorityd`
- Linux: `~/.local/share/predicate-authority/bin/predicate-authorityd`
- Windows: `%LOCALAPPDATA%/predicate-authority/bin/predicate-authorityd.exe`

### Option B: Download binary directly

Download pre-built binaries from [GitHub Releases](https://github.com/PredicateSystems/predicate-authority-sidecar/releases):

| Platform | Binary |
|----------|--------|
| macOS ARM64 (Apple Silicon) | `predicate-authorityd-darwin-arm64.tar.gz` |
| macOS x64 (Intel) | `predicate-authorityd-darwin-x64.tar.gz` |
| Linux x64 | `predicate-authorityd-linux-x64.tar.gz` |
| Linux ARM64 | `predicate-authorityd-linux-arm64.tar.gz` |
| Windows x64 | `predicate-authorityd-windows-x64.zip` |

```bash
# Example: macOS ARM64
curl -LO https://github.com/PredicateSystems/predicate-authority-sidecar/releases/latest/download/predicate-authorityd-darwin-arm64.tar.gz
tar -xzf predicate-authorityd-darwin-arm64.tar.gz
chmod +x predicate-authorityd
./predicate-authorityd --version
```

### Option C: Use from Python code

```python
from predicate_authority import run_sidecar, is_sidecar_available, download_sidecar

# Download if needed
if not is_sidecar_available():
download_sidecar()

# Start as subprocess
process = run_sidecar(port=8787, policy_file="policy.json")

# Graceful shutdown
process.terminate()
process.wait()
```

---

## 1) Sample `policy.json`

Create `examples/authorityd/policy.json`:
Expand Down Expand Up @@ -31,87 +92,68 @@ Create `examples/authorityd/policy.json`:

## 2) Start the daemon

Run from repo root:
### Basic local mode

```bash
PYTHONPATH=. predicate-authorityd \
./predicate-authorityd run \
--host 127.0.0.1 \
--port 8787 \
--mode local_only \
--policy-file examples/authorityd/policy.json \
--policy-poll-interval-s 2.0 \
--credential-store-file ./.predicate-authorityd/credentials.json
--policy-file policy.json
```

By design, mandate/revocation cache is in-memory (ephemeral) unless you explicitly
enable persistence with `--mandate-store-file`.

### Optional: enable persisted mandate/revocation cache (parity extension)

Use this only when restart-recovery for local revocations/mandate lineage is required.
If omitted, default behavior remains ephemeral.
### With local identity registry

```bash
PYTHONPATH=. predicate-authorityd \
./predicate-authorityd run \
--host 127.0.0.1 \
--port 8787 \
--mode local_only \
--policy-file examples/authorityd/policy.json \
--mandate-store-file ./.predicate-authorityd/mandates.json
--policy-file policy.json \
--identity-file ./local-identities.json
```

### Optional: enable control-plane shipping
### Cloud-connected mode (control-plane sync)

To automatically ship proof events and usage records to
`predicate-authority-control-plane`, set:
Connect to Predicate Authority control-plane for policy sync, revocation push, and audit forwarding:

```bash
export CONTROL_PLANE_URL="http://127.0.0.1:8080"
export CONTROL_PLANE_TENANT_ID="dev-tenant"
export CONTROL_PLANE_PROJECT_ID="dev-project"
export CONTROL_PLANE_API_KEY="<bearer-token>"
export PREDICATE_API_KEY="your-api-key"

PYTHONPATH=. predicate-authorityd \
./predicate-authorityd run \
--host 127.0.0.1 \
--port 8787 \
--mode local_only \
--policy-file examples/authorityd/policy.json \
--control-plane-enabled \
--control-plane-fail-open
--mode cloud_connected \
--policy-file policy.json \
--control-plane-url https://api.predicatesystems.dev \
--tenant-id your-tenant \
--project-id your-project \
--predicate-api-key $PREDICATE_API_KEY \
--sync-enabled
```

### Optional: enable long-poll policy/revocation sync from control-plane
### Local IdP mode (development/air-gapped)

Use this when running `cloud_connected` mode and you want active policy/revocation
updates pushed through long-poll sync instead of waiting for file-based policy polling.
For development or air-gapped environments without external IdP:

```bash
export CONTROL_PLANE_URL="http://127.0.0.1:8080"
export CONTROL_PLANE_TENANT_ID="dev-tenant"
export CONTROL_PLANE_PROJECT_ID="dev-project"
export CONTROL_PLANE_API_KEY="<bearer-token>"
export LOCAL_IDP_SIGNING_KEY="replace-with-strong-secret"

PYTHONPATH=. predicate-authorityd \
./predicate-authorityd run \
--host 127.0.0.1 \
--port 8787 \
--mode cloud_connected \
--policy-file examples/authorityd/policy.json \
--control-plane-enabled \
--control-plane-sync-enabled \
--control-plane-sync-project-id "$CONTROL_PLANE_PROJECT_ID" \
--control-plane-sync-environment "prod" \
--control-plane-sync-wait-timeout-s 15 \
--control-plane-sync-poll-interval-ms 200
--mode local_only \
--policy-file policy.json \
--identity-mode local-idp \
--local-idp-issuer "http://localhost/predicate-local-idp" \
--local-idp-audience "api://predicate-authority"
```

Quick checks:
Quick health checks:

```bash
# daemon sync health counters
curl -s http://127.0.0.1:8787/status | jq '.control_plane_sync_poll_count, .control_plane_sync_update_count, .control_plane_sync_error_count, .control_plane_last_sync_error'

# daemon metrics includes control-plane sync counters
curl -s http://127.0.0.1:8787/metrics | rg "predicate_authority_control_plane_sync_total"
curl -s http://127.0.0.1:8787/health | jq
curl -s http://127.0.0.1:8787/status | jq
```

### Signing key safety note (required until mandate `v2` claims)
Expand Down
Loading