Skip to main content

Generic audit library for applications

Project description

Cette librairie permet d'auditer les actions sur un projet et mets également à disposition une UI intégrée.

Structure complète du projet

project-audit/
├── audit_recorder/
│   ├── __init__.py
│   ├── context.py
│   ├── audit_decorator.py
│   ├── transactional_decorator.py
│   ├── service.py
│   ├── models.py
│   ├── resolver.py
│   └── result.py
├── tests/
├── LICENSE
├── README.md
└── pyproject.toml

Formatting with ruff

ruff check . --fix ruff format .

Tests

pytest

Builder la lib

python -m pip install --upgrade build
python -m build

Le répertoire dist contiendra un fichier .whl et un fichier .tar.gz.

Installer la distribution sur un projet (en local)

pip install /path/to/project-audit/dist/audit_recorder-0.1.0-py3-none-any.whl
pip show audit-recorder

Installer la distribution sur un projet (en mode dev)

pip install -e /home/you/dev/project-audit

Executer les tests unitaires

pytest -v

Intégration de la base de données (sqlalchemy et alembic)

Importer et ajouter la metadata dans le fichier de configuration :

from audit_recorder import models as audit_recorder_models

target_metadata = [app.models.model.Base.metadata, audit_recorder_models.Base.metadata]

Générer et executer le script de mise à jour, sous Alembic :

alembic revision --autogenerate -m "create_audit_logs_from_audit_recorder"
alembic upgrade head

Intégration du service

Configuration

Créer un fichier audit_setup.py. Celui-ci condiendra les requêtes qui seront executées avant et après chaque action, afin d'historiser les données et les changements. Les actions et les types de resources sont à la charge de chaque projet. TODO : héritage

Créer autant de query et de register que vous avez de type de resource. Exemple :

from audit_recorder.resolver import resolver
from sqlalchemy.orm import Session
from app.models.model import Compte

class AuditResourceEnum(enum.Enum):
    COMPTE = "COMPTE"

class AuditActionEnum(enum.Enum):
    APPROVE = "APPROVE"
    REFUSE = "REFUSE"

def get_compte(session: Session, id: int) -> Compte | None:
    return session.query(Compte).get(id)

def audit_setup():
    resolver.register(AuditResourceEnum.COMPTE.name, get_compte, Compte.id)

La méthode register accepte trois paramètres :

  • resource_type : le nom de la ressource
  • loader : la fonction de chargement de la ressource, signature (session: Session, resource_id: Any) -> Any
  • identifier : le champ SQLAlchemy utilisé comme identifiant de la ressource (ex. Compte.id, Compte.uuid)

L'identifier sert à extraire automatiquement l'id depuis l'objet retourné par la fonction décorée lorsque id_param n'est pas renseigné, notamment dans le cas d'une création.

Appeler la méthode audit_setup() dans le context manager :

from app.audit_setup import audit_setup

@asynccontextmanager
async def lifespan(_: FastAPI) -> AsyncIterator[None]:
    ...
    audit_setup()
    yield

Décorateur @audit

La lib mets à disposition un décorateur afin d'auditer une action. Exemple d'utilisation :

from audit_recorder.decorators.audit_decorator import audit

@audit(action="UPDATE", resource_type="COMPTE", id_param="compteDTO.id")
async def update_compte(compteDTO: CompteDTO, id_token: KeycloakIDToken, session: Session) -> CompteDTO:

Si id_param n'est pas renseigné, l'identifiant sera extrait automatiquement depuis l'objet retourné par la fonction, en utilisant l'identifier enregistré dans le resolver (via resolver.register). Exemple :

@audit(action="CREATE", resource_type="COMPTE")  # pas d'id_param
async def create_compte(compteDTO: CompteDTO, id_token: KeycloakIDToken, session: Session) -> Compte:
    ...
    return db_compte  # db_compte.id sera extrait via Compte.id déclaré dans le resolver

Important: - Tous les paramètres du décorateur @audit doivent être passés en nommés (action=, resource_type=, id_param=) - Tous les arguments de la fonction décorée doivent également être passés en nommés lors de l'appel - id_token: KeycloakIDToken est obligatoire afin de pouvoir récupérer les informations sur l'utilisateur - session: Session est obligatoire afin que les logs d'audit soient ajoutées dans la même session

Gestion de la transaction - décorateur @transactional

Le décorateur @audit ne réalise aucun commit, c'est action à la charge de la méthode appelante. Un décorateur @transactional est mis à disposition afin d'automatiser les commits, exemple :

from audit_recorder.decorators.audit_decorator import audit
from audit_recorder.decorators.transactional_decorator import transactional

@transactional
@audit(action=AuditActionEnum.CREATE.name, resource_type=AuditResourceEnum.COMPTE.name, id_param="db_compte.id")
def approve_demande_creation(...)

A noter: l'ordre est important, le l'annotation @transactional doit précéder l'annotation @audit pour la persitance des données.

Contexte

Dans certain cas, on souhaite auditer une action en fonction de l'appelant. Par exemple, auditer une approbation manuelle mais ne pas auditer une autoapprobation.

Pour cela il est possible de définir un contexte afin de désactiver un ou plusieurs audits, exemple :

from audit_recorder.context import skip_audit

with skip_audit(AuditActionEnum.APPROVE, AuditActionEnum.REJECT)
with skip_audit():
    service.approve(...)

Ignorer l'audit

L'audit est automatiquement réalisée après l'execution de la méthode annotée, sauf si celle-ci lance une exception. Il est possible d'ignorer explicitement l'audit. Exemple :

from audit_recorder.result import AuditResult

def approve(...) {
    if is_already_approve:
        return AuditResult.skip(db_compte)
}

Services

La lib mets à disposition des services afin de récupérer des données filtrées et paginées :

from audit_recorder import service

service.query_logs(...)
service.query_log_by_id(...)

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

audit_recorder-0.1.0.tar.gz (17.3 kB view details)

Uploaded Source

Built Distribution

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

audit_recorder-0.1.0-py3-none-any.whl (12.5 kB view details)

Uploaded Python 3

File details

Details for the file audit_recorder-0.1.0.tar.gz.

File metadata

  • Download URL: audit_recorder-0.1.0.tar.gz
  • Upload date:
  • Size: 17.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.15

File hashes

Hashes for audit_recorder-0.1.0.tar.gz
Algorithm Hash digest
SHA256 385eb6dd8d7fdab73576e2075fea5a6033916556ee2ef013cb02d53e16840a87
MD5 cee68548d4237520b69497a05f085feb
BLAKE2b-256 ddc2e28c1436bae05e8a99067777c25bcf8d37a47ca348c3089b66b28fe5554f

See more details on using hashes here.

File details

Details for the file audit_recorder-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: audit_recorder-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 12.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.15

File hashes

Hashes for audit_recorder-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 0bbeb702f90ab28f4403eccfacedf51da9f19c9b234225d58e7768223d73c7a1
MD5 137b59eae595d820c60f379550916f2f
BLAKE2b-256 053f36ab7079f9564c0405334da0fa798625477bf0ec1da86c99a56cf446b914

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