Skip to content
10 changes: 8 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,16 +90,22 @@ With the TUI:
python -m pip install ".[tui]"
```

With the SQLAlchemy sink integration:

```bash
python -m pip install ".[sink]"
```

With Redis support:

```bash
python -m pip install ".[redis]"
```

With both:
With everything:

```bash
python -m pip install ".[tui,redis]"
python -m pip install ".[tui,sink,redis]"
```

After install, the `adv` command is available in that environment.
Expand Down
4 changes: 2 additions & 2 deletions adiuvare/integrations/flask.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import asyncio
import json

from .sqlalchemy import _sink_mode
from werkzeug.wrappers import Request, Response

from .sqlalchemy import _sink_mode
from . import build_http_ctx, ctx_payload


Expand All @@ -13,7 +13,7 @@ def __init__(self, app, guard, flask_app=None) -> None:
self._guard = guard
self._flask = flask_app

def __call__(self, environ, start_response):
def __call__(self, environ, start_response):
req = Request(environ)
raw_ip = req.headers.get("x-forwarded-for", "")
ip = raw_ip.split(",", 1)[0].strip() or req.remote_addr or "127.0.0.1"
Expand Down
5 changes: 3 additions & 2 deletions adiuvare/integrations/sqlalchemy.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
from contextvars import ContextVar

from sqlalchemy import event

from ..signals.patterns import check_sql
from ..vendor import detect_sqli, normalize

Expand Down Expand Up @@ -41,6 +39,9 @@ def check_statement(


def attach_sink(engine, guard) -> None:

from sqlalchemy import event

if getattr(engine, "_adiuvare_guard", None) is guard:
return

Expand Down
32 changes: 31 additions & 1 deletion docs/installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ Use these commands to install Adiuvare directly from GitHub into your environmen
| --- | --- |
| core library | `python -m pip install "git+https://github.com/0-Shimanshu/ADIUVARE.git"` |
| core + TUI | `python -m pip install "adiuvare[tui] @ git+https://github.com/0-Shimanshu/ADIUVARE.git"` |
| core + SQLAlchemy sink | `python -m pip install "adiuvare[sink] @ git+https://github.com/0-Shimanshu/ADIUVARE.git"` |
| core + Redis | `python -m pip install "adiuvare[redis] @ git+https://github.com/0-Shimanshu/ADIUVARE.git"` |

### For Project Contributors (Local Repository Clone)
Expand All @@ -22,7 +23,7 @@ If you are a developer working directly inside a local clone of the repository s
| --- | --- |
| editable local dev | `python -m pip install -e .` |
| editable dev test stack | `python -m pip install -e ".[dev]"` |
| editable dev with extras | `python -m pip install -e ".[dev,tui,redis]"` |
| editable dev with extras | `python -m pip install -e ".[dev,tui,sink,redis]"` |

## Verify the install

Expand Down Expand Up @@ -76,6 +77,27 @@ The current TUI has seven screens:
- Audit
- Changes

## Sink install

If you want to use the SQLAlchemy sink integration (`attach_sink()`), install
the sink extra.

```bash
python -m pip install "adiuvare[sink] @ git+https://github.com/0-Shimanshu/ADIUVARE.git"
```

For local development:

```bash
pip install -e ".[sink]"
```

Once Adiuvare is published to PyPI, the shorter form will work:

```bash
pip install "adiuvare[sink]"
```

## Redis install

If you want the Redis event-stream backend, install the Redis extra.
Expand Down Expand Up @@ -143,6 +165,14 @@ heuristics. That keeps the runtime usable, but it is still the weaker path.

## Troubleshooting

### `SQLAlchemy is required to use attach_sink()`

Install the sink extra:

```bash
pip install "adiuvare[sink] @ git+https://github.com/0-Shimanshu/ADIUVARE.git"
```

### `tui deps are missing`

Install the TUI extra:
Expand Down
18 changes: 18 additions & 0 deletions docs/integrations/django.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,24 @@ and direct block or throttle outcomes.
Use the explicit Django attach path here. `Guard.auto(...)` is not the right
shortcut for Django at the moment.

## Sink install

If you want to use the SQLAlchemy sink integration alongside Django, install
the `sink` extra:

```bash
# from GitHub (before PyPI publish)
pip install "adiuvare[sink] @ git+https://github.com/0-Shimanshu/ADIUVARE.git"

# local development
pip install -e ".[sink]"

# once published to PyPI
pip install "adiuvare[sink]"
```

See [SQLAlchemy sink](../integrations/sqlalchemy.md) for usage.

## Working example

A maintained Django demo is available here:
Expand Down
16 changes: 16 additions & 0 deletions docs/integrations/sqlalchemy.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,22 @@ Adiuvare can inspect SQL statements close to the sink. This is not the main
request middleware path. It is the extra layer that runs near real SQL
execution when you want a last checkpoint there too.

## Install

The SQLAlchemy sink integration requires SQLAlchemy. Install it via the `sink`
extra:

```bash
# from GitHub (before PyPI publish)
pip install "adiuvare[sink] @ git+https://github.com/0-Shimanshu/ADIUVARE.git"

# local development
pip install -e ".[sink]"

# once published to PyPI
pip install "adiuvare[sink]"
```

## Quick example

```python
Expand Down
6 changes: 6 additions & 0 deletions docs/quickstart.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@ If you also want the TUI:
python -m pip install "adiuvare[tui] @ git+https://github.com/0-Shimanshu/ADIUVARE.git"
```

If you want the SQLAlchemy sink integration:

```bash
python -m pip install "adiuvare[sink] @ git+https://github.com/0-Shimanshu/ADIUVARE.git"
```

If you want the Redis backend too:

```bash
Expand Down
3 changes: 3 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ dependencies = [
]

[project.optional-dependencies]
sink = [
"sqlalchemy",
]
dev = [
"pytest",
"pytest-asyncio",
Expand Down
6 changes: 6 additions & 0 deletions tests/test_flask.py
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,12 @@ def billing():
assert res.status_code == 200


def test_flask_middleware_import_does_not_require_sqlalchemy():

from adiuvare.integrations.flask import AdiuvareMiddleware
assert AdiuvareMiddleware is not None


def _capture_flask_payload(monkeypatch, guard, client_call_func) -> str | None:
captured = None

Expand Down
9 changes: 5 additions & 4 deletions tests/test_sink.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import pytest
import sqlalchemy as sa

from adiuvare import Guard
from adiuvare.integrations.django_sink import wrap_query
from adiuvare.integrations.sqlalchemy import AdiuvareBlockError, _sink_mode, attach_sink, check_statement
sa = pytest.importorskip("sqlalchemy", reason="sqlalchemy not installed, skipping sink tests")

from adiuvare import Guard # noqa: E402
from adiuvare.integrations.django_sink import wrap_query # noqa: E402
from adiuvare.integrations.sqlalchemy import AdiuvareBlockError, _sink_mode, attach_sink, check_statement # noqa: E402


def test_sqlalchemy_sink_can_block_inline():
Expand Down
Loading