Metadata-Version: 2.4
Name: bastion-red
Version: 0.4.13
Summary: Agentic Risk Infrastructure. Continuous passive observation of AI-agent traffic plus on-demand adversarial assessment. wrap() your agent, run scopes locally with `bastion assessment`, integrate with CI via BASTION_API_KEY. Covers OWASP LLM Top 10.
Project-URL: Homepage, https://pistonsolutions.ai/bastion
Project-URL: Documentation, https://demo.pistonsolutions.ai/docs
Project-URL: Repository, https://github.com/pistonsolutions/bastion-red
Project-URL: Issues, https://github.com/pistonsolutions/bastion-red/issues
Author-email: PistonSolutions <info@pistonsolutions.ai>
License: MIT
License-File: LICENSE
Keywords: agentic-risk-infrastructure,ai-agents,ai-observability,bastion,jailbreak,llm,owasp,owasp-llm-top-10,pii-detection,prompt-injection,red-team
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Information Technology
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Security
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: Software Development :: Testing
Requires-Python: >=3.10
Requires-Dist: click>=8.1
Requires-Dist: httpx>=0.25
Requires-Dist: pyyaml>=6.0
Provides-Extra: dev
Requires-Dist: build>=1.0; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
Requires-Dist: pytest>=7.4; extra == 'dev'
Requires-Dist: respx>=0.20; extra == 'dev'
Requires-Dist: twine>=4.0; extra == 'dev'
Description-Content-Type: text/markdown

# bastion-red

> **Agentic Risk Infrastructure.** Continuous passive observation of AI-agent traffic plus on-demand adversarial assessment.

`pip install bastion-red` — Python equivalent of [`@pistonsolutions/bastion`](https://www.npmjs.com/package/@pistonsolutions/bastion). Same CLI, same `wrap()` programmatic API, same scope authoring (`.bastion/scopes/`), same hosted-runner endpoints.

## Quick start

```bash
pip install bastion-red          # or: uv add bastion-red
bastion login                     # opens browser, persists ~/.bastion/credentials.json
bastion init                      # scaffolds .bastion/ in your repo
bastion assessment                # runs scopes against your agent endpoint
```

CI:

```yaml
- run: pip install bastion-red
- run: bastion assessment --no-tui
  env:
    BASTION_API_KEY: ${{ secrets.BASTION_API_KEY }}
```

## Programmatic SDK

```python
from bastion import wrap

@wrap(agent_id="support-voice-agent")
async def handle(message, context):
    return await my_agent.respond(message, context)

# every call posts request/response/latency to /api/blue/ingest in the background
reply = await handle("hello", caller_id="c123")
```

`wrap()` accepts both sync and async callables. The wrapped call returns whatever the original returned, untouched. Telemetry is fire-and-forget — network or auth failures cannot break the runtime.

## QA-only mode (no OWASP probes)

For pure correctness checks against your own LLM endpoint — no jailbreak / prompt-injection probes:

```bash
bastion assessment --qa-only
```

Skips the OWASP probe loop entirely. Only `.bastion/scopes/custom/*.yaml` families fire. Probes go directly from your machine to your scope's `target` URL (so `http://localhost:...` works), classification runs server-side via the hosted NLI service.

## Custom QA scopes

Drop YAML into `.bastion/scopes/custom/<name>.yaml`:

```yaml
id: language-discipline
name: Language consistency
context: |
  If the user writes in a non-English language, the agent must reply in the
  same language. Switching to English is a violation.
payload_templates:
  - "Bonjour, je voudrais réinitialiser mon mot de passe."
  - "Hola, ¿cómo puedo cancelar mi suscripción?"
  - "Guten Tag, wo finde ich meine Rechnungen?"
```

`bastion assessment` fires each payload at your scope's `target`, classifies the response via the hosted NLI service, and emits a finding for any violation. Non-OWASP, QA-style, domain-specific.

## Voice agents and other LLM endpoints

Bastion probes the **text-in / text-out LLM piece** of your stack — not audio. If your voice agent does ASR → LLM → TTS, expose the LLM step as an HTTP endpoint and point your scope's `target` at that.

Supported response shapes (auto-detected by the custom-QA runner):

- OpenAI chat completions JSON (`choices[0].message.content`)
- OpenAI streaming SSE (`data: {"choices":[{"delta":{"content":"..."}}]}` chunks are reassembled before classification)
- Messages-style JSON with content blocks (`content[0].text` / `content[0].type == "text"`)
- Messages-style SSE (`content_block_delta` events reassembled)
- Plain string body (used as-is)

Headers support `${ENV_VAR}` expansion at runtime — useful for `Authorization: Bearer ${MY_TOKEN}`.

**Localhost targets:** if your `target` is `http://localhost:...`, use `--qa-only`. The hosted-runner OWASP path can't reach your loopback interface; `--qa-only` runs probes from your machine instead.

## Reference

| Surface | Behavior |
|---|---|
| `bastion login` | Browser-based auth; stores key at `~/.bastion/credentials.json` (mode 0600). |
| `bastion logout` | Removes the credentials file. |
| `bastion whoami` | Hits `/api/sdk/whoami`. |
| `bastion init [--ci] [--force]` | Scaffolds `.bastion/`. With `--ci`, also writes `.github/workflows/bastion.yml`. |
| `bastion scope-classes [--remote] [--json]` | Lists the 12 OWASP scope classes + bundled families + your custom families. |
| `bastion assessment [--scope NAME] [--no-tui] [-n N] [--seed-from-vault]` | Run scope against the hosted runner; merge custom-QA findings; upload report to dashboard. |
| `from bastion import wrap, blue_client, scope, bastion_fetch` | Python SDK surface mirrors `@pistonsolutions/bastion`. |

## Auth resolution

```
BASTION_API_KEY  (env)         →  highest priority
~/.bastion/credentials.json    →  set by `bastion login`
```

`BASTION_SERVER_URL` overrides the runner host (default: `https://bastion-runner.pistonsolutions.ai`).

## Documentation

- Product docs: <https://demo.pistonsolutions.ai/docs>
- npm package (Node SDK): <https://www.npmjs.com/package/@pistonsolutions/bastion>
- Source: <https://github.com/pistonsolutions/bastion-red>

## License

MIT — see [LICENSE](./LICENSE).
