Aller au contenu

Audit : export déterministe de preuves de conformité

Le module Audit transforme le jeu de données de claims de conformité du moteur en un paquet de preuves déterministe, expurgé des données personnelles et exploitable par un auditeur de conformité. Il trie chaque collection afin de produire une sortie stable au niveau de l’octet, valide le paquet par rapport à un schéma et peut le projeter vers une version stable.

Stabilité : expérimentale. L’exporteur lui-même est déterministe et bien testé, mais le jeu de données amont claims.json qu’il consomme est une matrice de conformité en cours d’élaboration (son propre _status le reflète). Tant que le pipeline de preuves n’a pas atteint la disponibilité générale (GA), considère la sortie de ce module comme une preuve d’ingénierie, et non comme une attestation certifiée.

Fenêtre de terminal
composer require nextpdf/core:^3

AuditExporter est l’unique point d’entrée. buildBundle() accepte un jeu de données de claims décodé ainsi qu’un AuditExportContext, puis renvoie un AuditExportBundle. buildBundleFromFile() est le raccourci pratique pour charger depuis un fichier. encode() sérialise le paquet en JSON. La construction est purement fonctionnelle. Avec un AuditExportContext::generatedAt figé (par exemple via SOURCE_DATE_EPOCH) et un jeu de données de claims stable, la sortie est identique octet pour octet d’une exécution à l’autre, car claims[] est trié par (standard, clause_id), evidence[] par ref_id et clause_hashes[] par clause_id. C’est pourquoi le profil de reproductibilité est bitwise.

Le paquet est une arborescence typée : AuditExportClaim (un claim de conformité), AuditExportEvidence (l’enregistrement de preuve à l’appui), AuditExportClauseHash (l’empreinte du contenu de la clause) et AuditExportContext (le contexte de génération). Chaque objet expose un toArray() pour la sérialisation.

Le module respecte la confidentialité par défaut. Le constructeur installe un DefaultPiiSanitiser (une implémentation de PiiSanitiser) qui nettoie les chaînes de métadonnées de preuve avant la sérialisation. Tu peux injecter un autre nettoyeur. L’exporteur valide les empreintes de clause, les condensats de preuve et les ancres de citation RAG selon un motif SHA-256 strict de 64 caractères hexadécimaux en minuscules, et émet un avertissement structuré (plutôt qu’un abandon silencieux) lorsqu’une clause n’a pas d’empreinte valide ou de métadonnées d’évaluateur. validateAgainstSchema() vérifie le paquet construit. projectToV1() produit une projection v1 stable. La conception de l’exporteur est alignée sur OWASP ASVS V8.3, NIST CSF 2.0 PR.PT-1, NIST SP 800-53 r5 AU-2/AU-3 et ISO/IEC 27001 A.12.4 ; ce sont des alignements de conception documentés dans le code source, pas des claims normatifs ancrés à un chunk.

ClasseMembres clésRôle
AuditExporterbuildBundle(), buildBundleFromFile(), encode(), validateAgainstSchema(), projectToV1()Constructeur/validateur déterministe du paquet
AuditExportBundletoArray()Le paquet de preuves assemblé
AuditExportClaimtoArray()Un enregistrement de claim de conformité
AuditExportEvidencetoArray()Un enregistrement de preuve à l’appui
AuditExportClauseHashtoArray()Un enregistrement d’empreinte du contenu de clause
AuditExportContextGENERATOR_VERSIONContexte de génération (fige l’horodatage pour le déterminisme)
PiiSanitiser (interface)sanitise(string): stringNettoyeur enfichable de métadonnées de preuve (@since 5.2.0)
DefaultPiiSanitisersanitise()Nettoyeur respectant la confidentialité par défaut (@since 5.2.0)

Exécute composer docs:generate-api-php -- --module=Audit pour obtenir le tableau PHPDoc complet.

Construis et encode un paquet à partir d’un fichier de claims.

<?php
declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
use NextPDF\Audit\AuditExportContext;
use NextPDF\Audit\AuditExporter;
$exporter = new AuditExporter();
$bundle = $exporter->buildBundleFromFile(
'/srv/nextpdf/claims.json',
new AuditExportContext(/* pin generatedAt for determinism */),
);
file_put_contents('/srv/out/audit-bundle.json', $exporter->encode($bundle));

Valide le paquet et traite tout avertissement de schéma ou d’empreinte comme une condition bloquante.

<?php
declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
use NextPDF\Audit\AuditExportContext;
use NextPDF\Audit\AuditExporter;
use Psr\Log\LoggerInterface;
final readonly class EvidenceGate
{
public function __construct(
private AuditExporter $exporter,
private LoggerInterface $logger,
) {}
/** @param array<string, mixed> $claims Decoded claims dataset. */
public function export(array $claims, AuditExportContext $context): string
{
$bundle = $this->exporter->buildBundle($claims, $context);
$errors = $this->exporter->validateAgainstSchema($bundle->toArray());
if ($errors !== []) {
$this->logger->error('Audit bundle failed schema validation.', ['errors' => $errors]);
throw new \RuntimeException('Audit evidence bundle is not schema-valid; refusing to publish.');
}
return $this->exporter->encode($bundle);
}
}
  • Le déterminisme exige un AuditExportContext::generatedAt figé. Sans lui, l’horodatage varie et la sortie n’est pas stable au niveau de l’octet, ce qui annule le profil bitwise.
  • Une clause sans clause_hash valide de 64 caractères hexadécimaux, ou sans métadonnées d’évaluateur, est ignorée avec un avertissement structuré et n’est pas incluse en silence. Vérifie les avertissements : une clause ignorée est une preuve manquante, pas une réussite.
  • Le PiiSanitiser par défaut est utilisé, sauf si tu en injectes un autre. Désactiver le nettoyage est un choix explicite avec des conséquences sur la confidentialité ; ne le fais pas pour un export réglementé.
  • validateAgainstSchema() n’a qu’une valeur indicative tant que tu n’exploites pas sa valeur de retour. En production, traite tout résultat non vide comme une erreur bloquant la publication.
  • Le paquet reflète la maturité du jeu de données d’entrée. Un jeu de données de claims encore en cours d’élaboration produit un paquet du même niveau de maturité ; l’exporteur n’améliore pas la qualité des preuves.

La construction est linéaire par rapport au nombre d’enregistrements de claims et de preuves, avec un coût dominé par le tri. Il n’y a aucune E/S dans buildBundle() (l’appelant gère l’accès au fichier). La charge de travail de référence par défaut reste bien en deçà du budget de 1500 ms de temps réel / 64 Mo de pic. Le profil de reproductibilité est bitwise dès lors que le contexte est figé et que l’entrée est stable, par conception.

Ce module manipule des preuves de conformité, qui peuvent contenir des métadonnées sensibles. Le nettoyage des données personnelles est activé par défaut (alignement RGPD art. 32). Garde-le activé pour tout paquet partagé à l’extérieur. L’exporteur valide chaque condensat et ancre de citation selon un motif SHA-256 strict, de sorte qu’une empreinte malformée ou tronquée est rejetée au lieu d’être considérée comme fiable. Traite le jeu de données de claims d’entrée comme la racine de confiance : l’exporteur sérialise fidèlement ce que tu lui fournis, si bien que la preuve n’est fiable que dans la mesure où ce jeu de données l’est. Consulte le modèle de menaces du moteur dans /modules/core/security/.

Ce module n’affirme aucun claim normatif de la spécification PDF. Il exporte des preuves concernant la conformité ; il n’implémente pas lui-même une clause PDF citée. Ses alignements de conception (OWASP ASVS V8.3, NIST CSF 2.0, NIST SP 800-53 r5, ISO/IEC 27001 A.12.4) sont documentés dans le code source : ce sont des alignements sur des cadres de contrôle, pas des citations PDF ancrées à un chunk. La conformité rapportée par le paquet est produite et validée par l’oracle et les suites de référence décrits dans /modules/core/conformance/.