Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added .github/assets/easyadmin_integration_dark.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
134 changes: 70 additions & 64 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,61 @@ AuditTrailBundle is a modern, lightweight bundle that automatically tracks and s

---

## Why AuditTrailBundle?

Most audit bundles capture changes synchronously, which can significantly slow down your application's write performance. AuditTrailBundle solves this by separating the **Capture** and **Persistence** phases.

### Split-Phase Architecture

```text
Application Doctrine ORM AuditTrailBundle Queue / Storage
| | | |
| flush() | | |
|----------------->| | |
| | onFlush (Capture) | |
| |------------------->| |
| | | Compute Diffs |
| | | Cache Payload |
| |<-------------------| |
| | | |
| | Execute SQL | |
| | (Transaction) | |
| | | |
| | postFlush | |
| |------------------->| |
| | | Dispatch Audit |
| | |-------------------->|
| flush() returns | | |
|<-----------------| | |
| Async Save
```

- **Non-blocking**: Audit capture happens during the flush, but storage is offloaded to a background process.
- **Data Integrity**: Cryptographic signing ensures logs cannot be tampered with.
- **Developer First**: Simple PHP 8 attributes, zero boilerplate.

---

## Enterprise-Ready UI

Native integration with **EasyAdmin** provides a professional dashboard for your audit logs out of the box.

![EasyAdmin Integration Showcase](.github/assets/easyadmin_integration_dark.png)

---

## Security & Compliance

Track not just what changed, but who did it and where they were.

- **Sensitive Data Masking**: Native support for `#[SensitiveParameter]` and custom `#[Sensitive]` attributes.
- **HMAC Signatures**: Every audit log is signed to prevent database tampering.
- **Integrity Verification**: Command-line tools to audit your audit logs.

![Integrity Check CLI](.github/assets/audit_integrity_check.png)

---

## Documentation

| Topic | Description |
Expand All @@ -32,17 +87,6 @@ AuditTrailBundle is a modern, lightweight bundle that automatically tracks and s

---

## Key Features

- **High Performance**: Non-blocking audits using a **Split-Phase Architecture** (capture in `onFlush`, dispatch in `postFlush`).
- **Multiple Transports**: Doctrine, HTTP (ELK/Splunk), Queue (RabbitMQ/Redis).
- **Deep Collection Tracking**: Tracks Many-to-Many and One-to-Many changes with precision.
- **Sensitive Data Masking**: Native support for `#[SensitiveParameter]` and custom `#[Sensitive]` attributes.
- **Safe Revert Support**: Easily roll back entities to any point in history.
- **Conditional Auditing**: Skip logs based on runtime conditions.
- **Access Auditing**: Track entity read operations (GET requests) with high-performance caching and configurable cooldowns.
- **Rich Context**: Tracks IP, User Agent, Impersonation, and custom metadata.

## Quick Start

### 1. Installation
Expand All @@ -51,79 +95,41 @@ AuditTrailBundle is a modern, lightweight bundle that automatically tracks and s
composer require rcsofttech/audit-trail-bundle
```

### 2. Database Setup (Doctrine Transport)

If you are using the **Doctrine Transport** (default), update your database schema:

```bash
php bin/console make:migration
php bin/console doctrine:migrations:migrate
```

### 3. Basic Usage
### 2. Basic Usage

Add the `#[Auditable]` attribute to any Doctrine entity you want to track.

```php
<?php

use Rcsofttech\AuditTrailBundle\Attribute\Auditable;

#[ORM\Entity]
#[Auditable(ignoredProperties: ['internalCode'])]
class Product
{
#[ORM\Id, ORM\GeneratedValue, ORM\Column]
private ?int $id = null;

#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column]
private string $name;
}
```

### 4. Access Auditing (Read Tracking)

To track when an entity is accessed (read), use the `#[AuditAccess]` attribute. This feature is strictly optimized for **GET requests** to minimize overhead.
public private(set) ?int $id = null;

```php
use Rcsofttech\AuditTrailBundle\Attribute\AuditAccess;

#[ORM\Entity]
#[AuditAccess(cooldown: 3600, level: 'info', message: 'User accessed sensitive record')]
class SensitiveDocument
{
// ...
#[ORM\Column]
public private(set) string $name;
}
```

#### Parameters
### 3. Requirements

| Parameter | Type | Default | Description |
| :--- | :--- | :--- | :--- |
| `cooldown` | `int` | `0` | Prevent duplicate logs for the same user/entity within X seconds (requires PSR-6 cache). |
| `level` | `string` | `'info'` | The log level for the access audit. |
| `message` | `string?` | `null` | A custom message to include in the audit log. |

> [!NOTE]
> `#[AuditAccess]` does not require `#[Auditable]` — they are independent attributes.
> However, if `#[AuditCondition]` is present on the same entity, it **is** respected for access logs.
> The expression receives `action = "access"` for fine-grained control.

#### Cache Configuration

To use the `cooldown` feature, you must specify a PSR-6 cache pool in your configuration:

```yaml
# config/packages/audit_trail.yaml
audit_trail:
cache_pool: 'cache.app' # Use any available PSR-6 cache pool
```
- **PHP**: 8.4+
- **Symfony**: 7.4+ or 8.0+
- **Doctrine ORM**: 3.0+

---

## Requirements
## Community & Support

- PHP 8.4+
- Symfony 7.4+
- Doctrine ORM 3.0+
- **Bugs & Features**: Please use the [GitHub Issue Tracker](https://github.com/rcsofttech85/AuditTrailBundle/issues).
- **Contributing**: Check out our [Contributing Guide](https://github.com/rcsofttech85/AuditTrailBundle/blob/main/CONTRIBUTING.md).

## License

Expand Down
29 changes: 27 additions & 2 deletions docs/advanced-usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@
You can ignore specific properties or enable/disable auditing per entity via the class-level attribute.

```php
<?php

declare(strict_types=1);

use Rcsofttech\AuditTrailBundle\Attribute\Auditable;

#[Auditable(enabled: true, ignoredProperties: ['internalCode'])]
class Product
{
Expand All @@ -21,14 +27,21 @@ Skip auditing based on runtime conditions using the `#[AuditCondition]` attribut
Add the `#[AuditCondition]` attribute to your entity. You have access to `object`, `action`, `changeSet`, and `user`.

```php
<?php

declare(strict_types=1);

use Rcsofttech\AuditTrailBundle\Attribute\AuditCondition;
use Rcsofttech\AuditTrailBundle\Attribute\Auditable;

#[Auditable]
#[AuditCondition("action == 'update' and object.getPrice() > 100")]
class Product
{
public function getPrice(): int { ... }
public function getPrice(): int
{
// ...
}
}
```

Expand All @@ -44,6 +57,10 @@ class Product
For complex logic, implement the `AuditVoterInterface`. Your voter will be automatically discovered if it's registered as a service.

```php
<?php

declare(strict_types=1);

use Rcsofttech\AuditTrailBundle\Contract\AuditVoterInterface;

class MyCustomVoter implements AuditVoterInterface
Expand Down Expand Up @@ -78,6 +95,10 @@ if (isset($context['impersonation'])) {
You can manually add custom metadata to your audit logs by implementing the `AuditContextContributorInterface`. This is the recommended way to add application-specific information like correlation IDs, app versions, or feature flags.

```php
<?php

declare(strict_types=1);

namespace App\Audit;

use Rcsofttech\AuditTrailBundle\Contract\AuditContextContributorInterface;
Expand Down Expand Up @@ -109,6 +130,10 @@ Dispatched immediately after an `AuditLog` object is created but before it is pe
- Trigger external notifications.

```php
<?php

declare(strict_types=1);

namespace App\EventSubscriber;

use Rcsofttech\AuditTrailBundle\Event\AuditLogCreatedEvent;
Expand All @@ -126,7 +151,7 @@ class AuditSubscriber implements EventSubscriberInterface
public function onAuditLogCreated(AuditLogCreatedEvent $event): void
{
$log = $event->getAuditLog();

// Add custom metadata
$context = $log->getContext();
$context['server_id'] = 'node-01';
Expand Down
6 changes: 5 additions & 1 deletion docs/integrations.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@
Add the `AuditLogCrudController` to your `DashboardController`:

```php
<?php

declare(strict_types=1);

use Rcsofttech\AuditTrailBundle\Controller\Admin\AuditLogCrudController;

yield MenuItem::linkToCrud('Audit Logs', 'fas fa-history', AuditLog::class)
Expand All @@ -19,4 +23,4 @@ To ensure the custom styling for the Audit Log UI (diffs, action badges, and rev
php bin/console assets:install
```

![EasyAdmin Integration Showcase](../.github/assets/easyadmin_integration.png)
![EasyAdmin Integration Showcase](../.github/assets/easyadmin_integration_dark.png)
10 changes: 9 additions & 1 deletion docs/revert-feature.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,13 @@ php bin/console audit:revert 123 --noisy
You can pass custom context when programmatically reverting an entity. This is useful for tracking why a revert was performed.

```php
<?php

declare(strict_types=1);

$auditReverter->revert($log, false, false, [
'reason' => 'Accidental deletion',
'ticket_id' => 'TICKET-456'
'ticket_id' => 'TICKET-456',
]);
```

Expand All @@ -33,6 +37,10 @@ By default, `AuditReverter` **silences** the standard `AuditSubscriber` during a
For scenarios requiring full technical transparency (e.g., strict forensic compliance), you can disable this silencing:

```php
<?php

declare(strict_types=1);

// Pass 'false' as the 5th parameter to keep standard update logs enabled
$auditReverter->revert($log, false, false, [], false);
```
Expand Down
18 changes: 16 additions & 2 deletions docs/security-integrity.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,24 @@ Sensitive data is automatically masked in audit logs.
### Option 1: Use PHP's `#[SensitiveParameter]`

```php
<?php

declare(strict_types=1);

public function __construct(
#[\SensitiveParameter] private string $password,
) {}
#[\SensitiveParameter]
private string $password,
) {
}
```

### Option 2: Use `#[Sensitive]`

```php
<?php

declare(strict_types=1);

use Rcsofttech\AuditTrailBundle\Attribute\Sensitive;

#[Sensitive(mask: '****')]
Expand Down Expand Up @@ -59,6 +69,10 @@ Content-Type: application/json
The bundle adds a `SignatureStamp` to the Messenger envelope containing the signature of the serialized `AuditLogMessage`.

```php
<?php

declare(strict_types=1);

use Rcsofttech\AuditTrailBundle\Message\Stamp\SignatureStamp;

// In your message handler
Expand Down
Loading
Loading