Skip to main content

Autonomous API QA agent — define actions and invariants, explore every state path automatically.

Project description

VenomQA

Autonomous QA agent that exhaustively explores APIs — define actions and invariants, let VenomQA find every bug sequence your linear tests miss.

PyPI version Python 3.10+ License: MIT

VenomQA demo


The Problem

Your unit tests check individual endpoints. Your integration tests check one happy path. Neither catches bugs that only appear in a specific sequence of calls.

PUT /refund → 200   # fine alone
PUT /refund → 200   # fine again
GET /order  → 200   # refunded_amount > original_amount  ← BUG

VenomQA finds these. Automatically.


How It Works

  You define:                VenomQA does:
  ┌─────────────┐            ┌─────────────────────────────────────────────┐
  │  Actions    │            │                                             │
  │  (API calls)│──────────▶ │   S0 ──[create]──▶ S1 ──[update]──▶ S2   │
  │             │            │   │                  │                  │   │
  │  Invariants │            │   └──[list]──▶ S3   └──[delete]──▶ S4  │   │
  │  (rules that│──────────▶ │              ✓OK    ✓OK        ✗FAIL!  │   │
  │  must hold) │            │                                             │
  └─────────────┘            │   After every step, checks ALL invariants.  │
                             │   Rolls back DB between branches.           │
                             └─────────────────────────────────────────────┘

Schemathesis tests endpoints one at a time with random inputs. VenomQA tests sequences of endpoints — the bugs that only appear after create → update → delete → create.


Quickstart

pip install venomqa
from venomqa.v1 import Action, Invariant, Agent, World, BFS, Severity
from venomqa.v1.adapters.http import HttpClient

# 1. Define actions
def create_order(api, context):
    resp = api.post("/orders", json={"product_id": 1, "qty": 2})
    context.set("order_id", resp.json()["id"])
    return resp

def cancel_order(api, context):
    return api.post(f"/orders/{context.get('order_id')}/cancel")

def refund_order(api, context):
    return api.post(f"/orders/{context.get('order_id')}/refund", json={"amount": 100})

def list_orders(api, context):
    resp = api.get("/orders")
    context.set("orders", resp.json())
    return resp

# 2. Define invariants (rules that must always hold)
def no_over_refund(world):
    orders = world.context.get("orders") or []
    return all(o.get("refunded", 0) <= o.get("total", 0) for o in orders)

# 3. Explore every reachable sequence
agent = Agent(
    world=World(api=HttpClient("http://localhost:8000")),
    actions=[
        Action(name="create_order", execute=create_order),
        Action(name="cancel_order", execute=cancel_order),
        Action(name="refund_order", execute=refund_order),
        Action(name="list_orders",  execute=list_orders),
    ],
    invariants=[
        Invariant(name="no_over_refund", check=no_over_refund,
                  message="Refunded amount cannot exceed order total",
                  severity=Severity.CRITICAL),
    ],
    strategy=BFS(),
    max_steps=200,
)

result = agent.explore()
# States: 12, Violations: 1
# [CRITICAL] no_over_refund: Refunded amount cannot exceed order total
#   Reproduction path: create_order → cancel_order → refund_order → refund_order → list_orders

From OpenAPI Spec

# Generate actions from your spec, run immediately
venomqa scaffold openapi https://api.example.com/openapi.json \
  --base-url https://api.example.com \
  --output actions.py

python3 actions.py
# Runs BFS over all 19 endpoints, reports violations

State Graph Exploration

                     ┌─── S0 (initial) ───┐
                     │                    │
                [create]              [list]
                     │                    │
                     ▼                    ▼
                    S1                   S2
                   /   \               (pass)
              [update] [delete]
                 /         \
                S3           S4
              (pass)      [✗ VIOLATION]
                          Invariant failed:
                          "delete then create
                           returns stale state"

VenomQA checkpoints the DB before each branch and rolls back after, so every path starts from a clean slate. No test pollution between branches.


Core Concepts

Concept What it is
Action A callable (api, context) → response — one API call
Invariant A rule (world) → bool checked after every action
World Sandbox: HTTP client + rollbackable systems + shared context
Agent Orchestrates BFS/DFS exploration, handles checkpoints
Context Key-value store across actions — context.set() / context.get()
Violation Recorded invariant failure with severity + exact reproduction path

Rollback Backends

System Mechanism
PostgreSQL SAVEPOINT / ROLLBACK TO SAVEPOINT — entire run is one transaction
Redis DUMP + FLUSHALL + RESTORE — full key restore
In-memory (queue, mail, storage) Copy + restore
Custom HTTP Subclass MockHTTPServer (3-method interface)
world = World(
    api=HttpClient("http://localhost:8000"),
    systems={
        "db":    PostgresAdapter("postgresql://localhost/mydb"),
        "cache": RedisAdapter("redis://localhost:6379"),
    },
)

Reporters

from venomqa.v1.reporters.console import ConsoleReporter
from venomqa.v1.reporters.html_trace import HTMLTraceReporter

ConsoleReporter().report(result)           # colored terminal output

html = HTMLTraceReporter().report(result)  # D3 force-graph of the state space
open("trace.html", "w").write(html)

Working Example

examples/github_stripe_qa/ — two deliberately planted bugs that VenomQA catches automatically:

cd examples/github_stripe_qa && python3 main.py
# Bug 1: GitHub open-issues endpoint leaks closed issues  [CRITICAL]
# Bug 2: Stripe allows refund > original charge amount    [CRITICAL]

CLI

venomqa scaffold openapi <spec>    # generate actions from OpenAPI spec
venomqa explore journey.py         # run stateful BFS exploration
venomqa validate journey.py        # check journey syntax
venomqa record journey.py          # record HTTP traffic → generate skeleton
venomqa replay report.json         # replay a violation's reproduction path
venomqa doctor                     # system diagnostics
venomqa llm-docs                   # print LLM context doc (paste into Claude/ChatGPT)

Development

git clone https://github.com/namanag97/venomqa
cd venomqa
pip install -e ".[dev]"

make test       # all unit tests
make lint       # ruff
make typecheck  # mypy --strict
make ci         # lint + typecheck + coverage

Docs

namanag97.github.io/venomqa


MIT — built by Naman Agarwal

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

venomqa-0.4.6.tar.gz (2.0 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

venomqa-0.4.6-py3-none-any.whl (1.0 MB view details)

Uploaded Python 3

File details

Details for the file venomqa-0.4.6.tar.gz.

File metadata

  • Download URL: venomqa-0.4.6.tar.gz
  • Upload date:
  • Size: 2.0 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.5

File hashes

Hashes for venomqa-0.4.6.tar.gz
Algorithm Hash digest
SHA256 f069437b74fe6e6733727daa44f658c31ae84fb7f3e24b8679a5376482a1835d
MD5 121a89bd2f8bcb675fd0ed4b945b4714
BLAKE2b-256 756aed82e1193c935c594242dc3a00e64c8c1d163d546ba665429ad26fedce40

See more details on using hashes here.

File details

Details for the file venomqa-0.4.6-py3-none-any.whl.

File metadata

  • Download URL: venomqa-0.4.6-py3-none-any.whl
  • Upload date:
  • Size: 1.0 MB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.5

File hashes

Hashes for venomqa-0.4.6-py3-none-any.whl
Algorithm Hash digest
SHA256 6d310f2fb73259933ff29c870c51c8540d4a3b24085585c39a372eef60cb4852
MD5 9fc3b8c49840dd90ea752ef393045d9e
BLAKE2b-256 b97450cb2a02138acbeec4a0d40f36e9b5bf1221292024c64bf27273c39f8ff6

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page