bastion-red
Adversarial assessment SDK for AI agents. Python equivalent of @pistonsolutions/bastion. Same CLI, same wrap() programmatic API, same scope authoring, same hosted-runner endpoints.
pipx install bastion-red # or: uv tool install bastion-red
bastion login
bastion run --target https://your-agent.example.com/chat --plugin pii-direct
The same run appears in your dashboard with the full probe target transcript.
Full reference: https://bastion.pistonsolutions.ai/docs
Quickstart
pipx install bastion-red
bastion login # opens dashboard, hands API key back to terminal
bastion init # scaffold .bastion/ in the current repo
bastion run --scope SCOPE.md # text assessment
# or:
bastion voice --target-ws wss://your-agent.example.com/voice \
--rule "Do not disclose PII without verification"
Requires Python ≥ 3.10.
Architecture
The SDK is a thin client. Your machine never runs an LLM, opens a WebSocket to your target, or places a phone call — all of that happens on Bastion infra. The CLI reads your scope, POSTs a job descriptor with your bk_* token, polls until the run completes.
What this means: only your target's URL/DID and the scope leave your network. No LLM keys on your end, no telephony provider to integrate, no WebRTC stack to install.
Failsafe: if the primary probe engine fails on a given run, Bastion falls back to a curated payload catalog automatically. You get telemetry from every bastion run, not an empty report.
Modes
| Mode | Command | When to use |
|---|---|---|
| Text | bastion run --target <url> |
HTTP chat endpoints, RAG, agent backends |
| Voice WebSocket | bastion voice --target-ws <wss> |
In-house voice agents you can expose as 8 kHz μ-law WS |
| Telephony | bastion voice --target-did <e164> |
Agents on a phone number; tests real PSTN conditions |
bastion run --target https://your-agent.example.com/chat --plugin pii-direct
bastion voice --target-ws wss://your-agent.example.com/voice --rule "..."
bastion voice --target-did +14155551234 --rule "..."
Telephony note: only test phone numbers you own or have explicit written authorization to test.
Programmatic API: wrap()
from bastion import wrap
def agent(msg: str) -> str:
return llm.complete(msg)
traced = wrap(agent, mode="observe", on_event=lambda e: print("event", e["session_id"]))
traced("hello")
Events flow into the dashboard's Live Activity view. Flagged events auto-promote into scope-seeds so the next assessment can replay them as adversarial probes.
SCOPE.md
YAML frontmatter + markdown body. Frontmatter declares what to test; body describes the agent for grading context.
---
target: https://api.example.com/v1/chat/completions
model: gpt-4o-mini
headers:
Authorization: Bearer ${OPENAI_API_KEY}
categories:
- system_prompt_extraction
- pii_leakage
- jailbreak_resistance
---
# Customer-support agent
The agent answers billing questions for retail customers. Must verify identity
(email + last 4 of card) before discussing any account, must refuse refunds
above $100 without supervisor approval.
Env vars in headers interpolate via ${VAR}. Categories default to system_prompt_extraction if omitted.
CLI reference
| Command | What it does |
|---|---|
bastion login |
Authenticate; persists ~/.bastion/credentials.json |
bastion whoami |
Print email, org, credential source |
bastion init [--ci] |
Scaffold .bastion/ in the current repo |
bastion run |
Text assessment (thin-client by default) |
bastion voice --target-ws <url> |
Voice WebSocket probe |
bastion voice --target-did <e164> |
Telephony probe |
bastion assessment |
Run the configured scope |
bastion diff [a] [b] |
Compare two reports |
bastion docs |
Open the docs page |
Every command supports --help.
Authentication
Two ways to provision a bk_* key:
- Interactive:
bastion login(opens browser, hands key back, persists~/.bastion/credentials.jsonmode 0600) - CI:
export BASTION_API_KEY=bk_live_...
Resolution order: env -> file. Keys revocable from the dashboard.
CI/CD
name: Bastion Assessment
on: { pull_request: {}, push: { branches: [main] } }
jobs:
bastion:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with: { python-version: '3.12' }
- run: pipx install bastion-red
- run: bastion run --scope SCOPE.md --no-tui
env: { BASTION_API_KEY: ${{ secrets.BASTION_API_KEY }} }
Privacy
- Only the scope you write leaves your machine.
- Verbatim target responses are stored as evidence — if your agent returns real PII, that PII is visible in the dashboard transcript.
- API keys never leave the dashboard in plaintext (only a SHA-256 hash).
- Runs are scoped to the org that minted the API key.
MIT © Piston Solutions
Metadata
Release files for bastion-red 0.5.3
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| bastion_red-0.5.3.tar.gz | 43.7 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| bastion_red-0.5.3-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 93.5 kB
Release files / bastion_red-0.5.3.tar.gz
| Download URL | bastion_red-0.5.3.tar.gz |
|---|---|
| Size | 43.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
a64fb343133ea118b779b5a1482f856ffa5f1895f46ce5b6600367f076f1749b
|
|
BLAKE2b-256 checksum How to use checksums |
0034298819936d80d4d86144e2d481b10508669a96dcba7fc0364d8bd63e86c5
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.11.8 {"installer":{"name":"uv","version":"0.11.8","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Release files / bastion_red-0.5.3-py3-none-any.whl
| Download URL | bastion_red-0.5.3-py3-none-any.whl |
|---|---|
| Size | 49.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
7e41daba233851854a726ce8e71ff62d3b2ed53b30eacb89fa9e296465ccc0e8
|
|
BLAKE2b-256 checksum How to use checksums |
6ca38cb31c0cfb8fca93fbb069d438e526748c67564411b167db540fdc73bac7
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.11.8 {"installer":{"name":"uv","version":"0.11.8","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Security for bastion-red 0.5.3
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.