Skip to content
Open
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
104 changes: 104 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ members = [
"crates/apl-pii-scanner",
"crates/apl-audit-logger",
"examples/go-demo/ffi",
# PyO3 bindings — excluded from default-members so plain `cargo build`
# stays libpython-independent (KD3). Use `cargo build -p cpex-python`
# or `maturin develop` to build this crate explicitly.
"bindings/python",
]

# `default-members` controls what `cargo build` / `cargo test` (with no
Expand Down
45 changes: 40 additions & 5 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,11 @@ help:
@echo " rust-lint-check Read-only fmt --check + clippy (CI-safe)"
@echo " rust-clean Remove the Rust target/ directory"
@echo ""
@echo "Python bindings (bindings/python — requires maturin):"
@echo " bindings-python-build Build and install Python bindings (debug)"
@echo " bindings-python-build-release Build Python bindings wheel (release)"
@echo " bindings-python-test Build + run Python binding tests"
@echo ""
@echo "Go (go/cpex):"
@echo " go-build Build the Go cpex package (requires libcpex_ffi)"
@echo " go-test Run Go tests"
Expand Down Expand Up @@ -443,19 +448,19 @@ GO_DIR = go/cpex
.PHONY: rust-build
rust-build:
@echo "🦀 Building Rust workspace (debug)..."
@$(CARGO) build --workspace
@$(CARGO) build --workspace --exclude cpex-python
@echo "✅ Rust workspace built"

.PHONY: rust-build-release
rust-build-release:
@echo "🦀 Building Rust workspace (release)..."
@$(CARGO) build --release --workspace
@$(CARGO) build --release --workspace --exclude cpex-python
@echo "✅ Rust workspace built (release)"

.PHONY: rust-test
rust-test:
@echo "🧪 Running Rust workspace tests..."
@$(CARGO) test --workspace
@$(CARGO) test --workspace --exclude cpex-python
@echo "✅ Rust tests passed"

.PHONY: rust-test-ffi
Expand Down Expand Up @@ -486,7 +491,7 @@ rust-lint: rust-lint-fix
rust-lint-fix:
@echo "🦀 Formatting + auto-fixing Rust..."
@$(CARGO) fmt --all
@$(CARGO) clippy --workspace --all-targets --fix --allow-dirty --allow-staged -- -D warnings
@$(CARGO) clippy --workspace --exclude cpex-python --all-targets --fix --allow-dirty --allow-staged -- -D warnings
@echo "✅ Rust lint-fix complete"

# rust-lint-check is the CI-safe variant: no writes. Fails if formatting
Expand All @@ -495,7 +500,7 @@ rust-lint-fix:
rust-lint-check:
@echo "🦀 Checking Rust formatting + clippy (read-only)..."
@$(CARGO) fmt --all -- --check
@$(CARGO) clippy --workspace --all-targets -- -D warnings
@$(CARGO) clippy --workspace --exclude cpex-python --all-targets -- -D warnings
@echo "✅ Rust lint-check passed"

.PHONY: rust-clean
Expand All @@ -504,6 +509,36 @@ rust-clean:
@$(CARGO) clean
@echo "✅ target/ removed"

# =============================================================================
# Python bindings (bindings/python)
# =============================================================================
#
# cpex-python is built via maturin, not plain cargo. The targets below
# require maturin to be installed (`pip install maturin`). The crate is
# excluded from the pure-Rust `rust-build` / `rust-test` targets so those
# paths stay libpython-independent (KD3).

PYTHON_BINDINGS_DIR = bindings/python
MATURIN ?= maturin

.PHONY: bindings-python-build
bindings-python-build:
@echo "🐍 Building Python bindings (debug)..."
@cd $(PYTHON_BINDINGS_DIR) && $(MATURIN) develop
@echo "✅ Python bindings built (debug)"

.PHONY: bindings-python-build-release
bindings-python-build-release:
@echo "🐍 Building Python bindings (release)..."
@cd $(PYTHON_BINDINGS_DIR) && $(MATURIN) build --release
@echo "✅ Python bindings built (release)"

.PHONY: bindings-python-test
bindings-python-test: bindings-python-build
@echo "🧪 Running Python binding tests..."
@cd $(PYTHON_BINDINGS_DIR) && $(VENV_BIN)/pytest tests/ -v
@echo "✅ Python binding tests passed"

# =============================================================================
# Go bindings (go/cpex)
# =============================================================================
Expand Down
59 changes: 59 additions & 0 deletions bindings/python/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# Location: ./bindings/python/Cargo.toml
# Copyright 2025
# SPDX-License-Identifier: Apache-2.0
# Authors: Ted Habeck
#
# cpex-python — PyO3 bindings over the CPEX Rust runtime.
#
# Built via maturin (`maturin develop` / `maturin build`).
# The `extension-module` feature is opt-in (non-default) so the pure-Rust
# workspace build stays libpython-independent (KD3). maturin activates it
# automatically via `[features] -> pyo3/extension-module` in pyproject.toml.
#
# Build this crate directly (macOS, Python present):
# cargo build -p cpex-python
# Build via maturin (any platform):
# cd bindings/python && maturin develop

[package]
name = "cpex-python"
description = "PyO3 bindings for the CPEX plugin runtime"
version.workspace = true
edition.workspace = true
license.workspace = true
authors.workspace = true

[lib]
name = "_lib"
crate-type = ["cdylib"]

[dependencies]
cpex-core = { path = "../../crates/cpex-core" }

# APL governance layer — same set as cpex-ffi so bundled factories are
# available to Python callers. Keep in sync with crates/cpex-ffi/Cargo.toml.
apl-cpex = { path = "../../crates/apl-cpex" }
apl-pii-scanner = { path = "../../crates/apl-pii-scanner" }
apl-audit-logger = { path = "../../crates/apl-audit-logger" }
apl-identity-jwt = { path = "../../crates/apl-identity-jwt" }
apl-delegator-oauth = { path = "../../crates/apl-delegator-oauth" }
apl-pdp-cedar-direct = { path = "../../crates/apl-pdp-cedar-direct" }

# Heavy Cedarling deps behind an opt-in feature — off by default.
apl-cedarling = { path = "../../crates/apl-cedarling", optional = true }

serde = { workspace = true }
serde_json = { workspace = true }
tokio = { workspace = true }
futures = { workspace = true }
tracing = { workspace = true }

# PyO3 — extension-module is non-default; maturin enables it via pyproject.toml.
# Plan KD6 pinned "0.28"; using 0.29 (released 2026-06-11/12) as the latest
# compatible stable pair. pyo3 0.28.0 was yanked; 0.29 is the current series.
pyo3 = { version = "0.29", features = [] }
pyo3-async-runtimes = { version = "0.29", features = ["tokio-runtime"] }

[features]
default = []
cedarling = ["dep:apl-cedarling"]
Loading