Metadata-Version: 2.4
Name: django-middleaudit
Version: 0.1.0
Summary: Audit log for Django projects: a middleware applies configurable rules to every request and stores the results.
Author-email: Aníbal Pacheco <apacheco.uy@gmail.com>, pyspring <hello@pyspring.com>
License-Expression: MIT
Keywords: django,audit,audit-log,middleware
Classifier: Development Status :: 3 - Alpha
Classifier: Environment :: Web Environment
Classifier: Framework :: Django
Classifier: Framework :: Django :: 4.2
Classifier: Framework :: Django :: 5.0
Classifier: Framework :: Django :: 5.1
Classifier: Framework :: Django :: 5.2
Classifier: Intended Audience :: Developers
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
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: Django>=4.2
Provides-Extra: dev
Requires-Dist: black; extra == "dev"
Requires-Dist: isort; extra == "dev"
Requires-Dist: mypy; extra == "dev"
Requires-Dist: pylint; extra == "dev"
Requires-Dist: pylint-django; extra == "dev"
Dynamic: license-file

# django-middleaudit

A reusable Django app that adds an audit log to your project. A middleware runs
every request through a set of *audit rules*; whenever a rule returns a result
(anything other than `None`), an audit log entry is stored in the database.

> **Status:** under active development, working towards a first minimal release
> on PyPI.

## How it works

1. You add the `middleaudit` middleware to your project.
2. On each request, the middleware applies the configured audit rules.
3. Each rule receives the request and returns either `None` (nothing to audit)
   or a result describing what happened.
4. Every non-`None` result is persisted as an audit log entry.

Rules are plain classes with a well-known interface, so writing your own is
trivial: subclass the provided base class, implement one method, and add the
rule to your settings.

The app ships with a default rule set, which the project settings can override
or extend.

## Installation

```bash
pip install django-middleaudit
```

Add the app and the middleware to your settings:

```python
INSTALLED_APPS = [
    # ...
    "middleaudit",
]

MIDDLEWARE = [
    # ...
    "middleaudit.middleware.MiddleauditMiddleware",
]
```

The middleware must be placed after
`django.contrib.auth.middleware.AuthenticationMiddleware`, so rules can
inspect `request.user`.

Run the migrations:

```bash
python manage.py migrate middleaudit
```

Optionally, include the audit log view in your URLconf:

```python
urlpatterns = [
    # ...
    path("audit-log/", include("middleaudit.urls")),
]
```

## The audit log view

The app provides a view, restricted to staff users, that lists the audit log
entries from most recent to oldest, paginated (page size defaults to Django
admin's default, 100 entries per page).

## Rules

A rule is a class with a known attribute and method:

```python
from middleaudit.rules import AuditRule


class AccessRule(AuditRule):
    """The default rule: logs every authenticated request."""

    name = "access"

    def apply(self, request):
        if not request.user.is_authenticated:
            return None
        return (request.user, f"accessed URL {request.path}")
```

- `name` identifies the rule in the audit log entries it produces.
- `apply(request)` returns `None` when there is nothing to audit, or a result
  tuple that becomes an audit log entry.

### Configuring the rule set

The default rule set can be overridden from your project settings with a list
of dotted paths:

```python
MIDDLEAUDIT_RULES = [
    "middleaudit.rules.AccessRule",
    "myproject.audit.MyCustomRule",
]
```

## Settings

Every setting this app reads is prefixed with `MIDDLEAUDIT_`.

- `MIDDLEAUDIT_RULES`: list of dotted paths to the audit rule classes to
  apply. Defaults to the app's built-in rule set.
- `MIDDLEAUDIT_BASE_TEMPLATE`: name of the base template the audit log view
  extends, so the listing integrates with your project's look and feel.
  Defaults to a minimal standalone base shipped with the app.

  ```python
  MIDDLEAUDIT_BASE_TEMPLATE = "myproject/base.html"
  ```

  The only requirement is that the template defines a `content` block, where
  the audit log table is rendered. A minimal valid base template looks like
  this:

  ```html
  <!DOCTYPE html>
  <html lang="en">
  <head>
    <meta charset="utf-8">
    <title>My project</title>
  </head>
  <body>
    {% block content %}{% endblock %}
  </body>
  </html>
  ```

## Roadmap

- Response-aware rules. Some actions can only be asserted once the response
  is known: "user X deleted something" is only true if the delete request
  succeeded (e.g. returned a 2xx status). Rules will optionally be able to
  inspect the response, with the middleware applying them after the view has
  run. The basic access rule does not need this — the access happens
  regardless of the outcome.
- View decorators to trigger a specific rule directly, for views whose intent
  is already known:

  ```python
  @middleaudit(rule_name="delete_something")
  def delete_view(request, pk):
      ...
  ```

## Development

Run the test suite:

```bash
django-admin test middleaudit --settings=test_settings --pythonpath=. --failfast
```

Format, type-check and lint the code:

```bash
./lint.sh        # check only
./lint.sh fix    # apply isort/black fixes, then run checkers
```

## License

MIT — see [LICENSE](LICENSE).
