Metadata-Version: 2.4
Name: testpulse
Version: 0.1.1
Summary: TestPulse Pro — evidence-first AAA (RADIUS/TACACS+) diagnostics for your own lab.
Author: BMI2 — Tarik Antar Riley
License: Proprietary
Keywords: radius,tacacs,802.1x,aaa,diagnostics,network
Classifier: Intended Audience :: System Administrators
Classifier: Topic :: System :: Networking :: Monitoring
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: NOTICE
Requires-Dist: PyJWT>=2.8
Requires-Dist: PyYAML>=6.0
Requires-Dist: cryptography>=42.0
Requires-Dist: fastapi>=0.110
Requires-Dist: httpx>=0.27
Requires-Dist: pydantic>=2.6
Requires-Dist: python-dotenv>=1.0
Requires-Dist: requests>=2.31
Requires-Dist: starlette>=0.36
Requires-Dist: uvicorn[standard]>=0.27
Requires-Dist: python-multipart>=0.0.9
Requires-Dist: pytest>=8.0
Requires-Dist: paramiko>=3.4
Requires-Dist: tomli>=2.0; python_version < "3.11"
Provides-Extra: ai
Requires-Dist: anthropic>=0.25; extra == "ai"
Requires-Dist: openai>=1.14; extra == "ai"
Provides-Extra: mcp
Requires-Dist: mcp>=1.0; extra == "mcp"
Provides-Extra: pcap
Requires-Dist: scapy>=2.5; extra == "pcap"
Requires-Dist: dpkt>=1.9; extra == "pcap"
Provides-Extra: windows
Requires-Dist: pywinrm>=0.4; extra == "windows"
Requires-Dist: python-evtx>=0.7; extra == "windows"
Provides-Extra: rag
Requires-Dist: chromadb>=0.4; extra == "rag"
Provides-Extra: rag-local
Requires-Dist: chromadb>=0.4; extra == "rag-local"
Requires-Dist: sentence-transformers>=2.7; extra == "rag-local"
Provides-Extra: postgres
Requires-Dist: psycopg2-binary>=2.9; extra == "postgres"
Provides-Extra: aws
Requires-Dist: boto3>=1.34; extra == "aws"
Provides-Extra: all
Requires-Dist: testpulse[ai,aws,mcp,pcap,postgres,rag,windows]; extra == "all"
Dynamic: license-file

# TestPulse Pro

**Evidence-first AAA diagnostics for your own lab.** Point it at your RADIUS or
TACACS+ server, give it the logs and captures you already have, and get a named
cause with the evidence behind it — not "RADIUS is flaky".

TestPulse never collapses a failure into a single verdict. Every diagnosis
answers four things: what was **observed**, which **cause family** it belongs to,
**why** — the specific counters and log lines that support it — and the **fix
direction**.

## Install

```bash
python3 -m venv .venv && source .venv/bin/activate
pip install testpulse
```

Optional extras, none required to start:

| Extra | Adds |
|---|---|
| `testpulse[ai]` | AI narration using **your own** Anthropic/OpenAI key |
| `testpulse[mcp]` | MCP server, to drive TestPulse from an AI client |
| `testpulse[pcap]` | Deeper packet analysis (scapy/dpkt) |
| `testpulse[windows]` | Windows endpoint collection (WinRM, Event Log) |
| `testpulse[rag]` | Retrieval over your own run history |
| `testpulse[postgres]` | Postgres instead of the bundled SQLite |

## Run

```bash
export TESTPULSE_API_TOKEN="$(python3 -c 'import secrets;print(secrets.token_urlsafe(32))')"
testpulse-api
```

Open **http://127.0.0.1:8000**. The viewer is served by the same process — there
is no second container to run.

### Diagnose a log without starting anything

```bash
testpulse-diagnose diagnose --protocol tacacs --file /var/log/tac_plus/tac_plus.log
```

## Bring your own key

TestPulse ships with **no AI key and no AI subscription**. Reasoning is optional,
and when you enable it, it runs against a key you own:

```bash
pip install 'testpulse[ai]'                                            # the SDK is not in the base install
testpulse-diagnose configure --provider anthropic --api-key sk-ant-…   # stored in your OS keychain
```

Everything else — parsing, correlation, the deterministic diagnosis, the evidence
bundle — runs locally with no network call.

## Point it at your testbed

Copy `env.example.yaml`, fill in your devices, and export the path:

```bash
export TESTPULSE_CONFIG=/path/to/my-testbed.yaml
```

**Credentials are never read from code.** Each secret comes from an environment
variable or from your config, and TestPulse declines to guess: it tells you which
variable to set rather than sending an invented shared secret to your server — a
wrong secret produces a confusing authentication failure on *your* box.

## No server to point it at?

Pro diagnoses a **real** server — it does not simulate one. If you have nothing to point it
at, `vlab/` in this download is the virtual AAA lab TestPulse is developed against, and you
can build it yourself.

Real 802.1X, RADIUS, TACACS+, DHCP and directory traffic on a single Kubernetes host, with
real EAPOL frames on the wire. Not simulated, and not hosted for you.

The **NAS is a container** (`hostapd-nas`), so the 802.1X authenticator is always present —
including on a host with no hardware virtualization, where the VM plane cannot start. What a
missing `/dev/kvm` costs you is the RouterOS **switch** evidence path, not the AAA path.

- **It needs a machine of its own: 6 cores, 32 GB RAM, 200 GB disk.** That is a minimum, not a
  recommendation. Below it the lab's two planes contend, and the inflated latency reads as a
  transport fault in a diagnosis — an undersized lab does not fail visibly, it gives you
  confident wrong answers.
- **You should not need `kubectl`.** `vlab/CLAUDE.md` is an AI administrator for the lab: it
  carries 14 real failure modes with the tell that distinguishes each from the fault it is
  usually mistaken for. Ask it in plain language — *"the lab looks broken"*, *"no packets were
  captured"*.
- **Start with `vlab/TestPulse_Pro_VLab_Guide.md`.** It covers the two planes, the three health
  checks, the lab credentials, and — most usefully — how to tell a broken lab apart from a real
  diagnostic finding.

## What this build does not include

Deliberately, not by accident:

- **The Trainer** — the curriculum, grading, and sign-off loop is a separate product.
- **Virtual-lab surfaces** — live attack generation and the cluster panels need a
  lab this download does not ship. Rather than show a disabled panel advertising
  something it can never run, they are absent.
- **Vendor plugins** — vendor-specific appliance packs are separate. The core is
  RADIUS and TACACS+, which is what this build does well.

Full walkthrough: **TestPulse_Pro_User_Guide.md**, shipped beside this file.

## Support

Beta feedback goes through the product — `testpulse-diagnose feedback`, or the
Feedback tab in the viewer. **Feedback never includes your raw logs or captures.**

---
© 2026 BMI2 — Tarik Antar Riley. All rights reserved. Proprietary & confidential.
