Skip to content

Compliance and Evidence – Proving Rather Than Declaring

Machine translation of the French original.

A dashboard that displays "compliant" in green answers a question that no one asks. An auditor would ask something else: "How do you know that it was true at that date, and that the evidence hasn't been tampered with since?"

This page describes how the park responds to this question: a catalog of controls, probes that measure, a status that cannot be manually verified, and a record that cannot be rewritten without being noticed.

The technical terms refer to the glossary.


What "compliant" can mean here

Two frameworks serve as a benchmark, and neither applies strictly:

  • NIS2 requires entities that are essential and important to the Union. A private park is not one of them. The directive serves as a measurement framework: its ten minimum measures (Article 21 §2) and its notification mechanism (Article 23) provide a good inventory of what a serious defense should cover.
  • SOC 2 is a report prepared by an accredited auditor, over a period. No tool is "SOC 2 certified", and a product that claims to be so confuses the report with the audit file. However, a tool can produce the evidence file that the auditor would request.

That's what the park does: a catalog of controls, measured evidence, a status derived from the evidence, and an export – and the uncovered criteria, displayed as such rather than hidden.

flowchart LR
    classDef src fill:#3f3f46,stroke:#3f3f46,color:#fff
    classDef proof fill:#1e40af,stroke:#1e40af,color:#fff
    classDef out fill:#0f766e,stroke:#0f766e,color:#fff

    cat["Catalogue de contrôles<br/>versionné dans git"]:::src
    son["Sondes<br/>pass · fail · indeterminate"]:::src
    att["Attestations humaines<br/>session authentifiée · expiration"]:::src
    tri["Gestes de triage<br/>avant → après · auteur"]:::src

    run["Lanceur<br/>toutes les six heures"]:::proof
    reg["Registre chaîné<br/>ajout seul · SHA-256"]:::proof
    anc["Ancre quotidienne<br/>git, deux dépôts distants"]:::proof

    der["Statut DÉRIVÉ<br/>recalculé à chaque lecture"]:::out
    tab["Tableau de conformité"]:::out
    exp["Dossier d'audit"]:::out

    cat --> run
    son --> run --> reg
    att --> reg
    tri --> reg
    reg --> anc
    reg --> der --> tab
    der --> exp

1. The Common Controls Catalog

A control is a security measure that can be proven to work. The catalog contains around thirty of them. Each one includes:

  • a goal, in one sentence;
  • the NIS2 articles and SOC 2 criteria it addresses – a single control serves both frameworks (common controls);
  • its evidence sources: one or more probes, an attestation, or both.

The catalog is a versioned file in Git. Each version also registers itself: we not only know what was proven at a given date, but also what we required at that date.

How does the catalog cover the ten measures of Article 21 §2:

NIS2, Art. 21 §2 What the catalog requires SOC 2 Evidence
a) Risk analysis Written risk analysis and blind spots, annual review CC3 Attestation
b) Incident management SIEM and alerting, runtime detection, network IDS, file system monitoring, threat intelligence, automated response, incident investigation CC7 Probes
c) Continuity, backups, crisis management Immutable backups, proven recovery, offline master key A1, CC9 Probes + Attestation
d) Supply chain Version quarantine, SBOM, review of critical vendors CC8, CC9 Probes + Attestation
e) Development and maintenance security, vulnerabilities Continuous scanning, remediation of identified vulnerabilities, change traceability, patches, perimeter blocking CC6, CC7, CC8 Probes
f) Effectiveness evaluation Integrity of evidence log, quarterly review of controls CC4 Probe + Attestation
g) Cybersecurity and training Patches, CIS hardening, operator competency CC1, CC5 Probes + Attestation
h) Cryptography Valid certificates, master key CC6 Probes
i) Access control, asset management Inventory and persistence, SBOM, absence of clear secrets on hosts CC6, C1 Probes
j) Multi-factor authentication, secure communications MFA on privileged accounts, out-of-band crisis channel CC6, CC2 Probe + Attestation

This is supplemented by Article 20 (Responsibility and oversight: an annual attestation) and Article 23 (Notification: the incident log).


2. The Probes

A probe is a script that measures a fact and delivers a verdict. Its contract is short, and each clause has a reason:

Clause Reason
A single JSON line as output: identifier, verdict, observed fact, detail, measurement date A single trigger, a unique format, no interpretation
Verdict among pass, fail, indeterminate Three states, because there are three situations
Unreachable target → indeterminate, never pass The absence of a response is not a measurement
Output as success as soon as a verdict is delivered, even fail A failed check is not a faulty probe
Less than one minute A slow probe is a probe that eventually gets disabled
No secrets in the output The detail goes into a log that others read
Header: what it proves, what it does not prove, the command that caused it to fail A probe that has never turned red measures nothing
{"probe": "<identifiant>", "status": "pass",
 "observed": "<le fait mesuré, en une phrase>",
 "detail": {"...": "..."}, "measured_at": "<date ISO 8601>"}

The last clause is the most important. Before being accepted, each probe undergoes its reverse verification: we deliberately create the situation that it must detect, and we watch it turn red. A probe that cannot fail is not proof, it's just decoration.

What probes measure, for example: actually served certificates and their expiration dates; SIEM agents connected; a disposable container that triggers detection at runtime; the canary rule for file systems; a refused deletion on the backup target; the age of the last restore exercise; the presence of dozens of versions in each repository; the second factor of privileged accounts; the integrity of the registry against its anchors.

A probe proves what it measures, and nothing more

The incident log probe verifies that the deadlines for reported incidents are being met. An empty log indicates that this is not the case. It does not prove that no incidents have occurred, nor that a real incident has been reported – and this is written in its header, where the next reader will find it.

The probes rotate every six hours. A probe present on disk but not attached to any control will appear on the table as an orphaned proof: it measures something that no one has requested, or a control has lost its proof.


3. The Derived Status

The status of a control is not captured. It is calculated, at each reading, from the evidence:

Status Condition
Active All its probes are pass, and they are fresh (36 hours by default), and all its attestations are valid
Failed At least one probe is fail
Unverified Everything else: a silent probe, expired probe, indeterminate probe, a missing or expired attestation

The third line is the key difference. The absence of measurement is not a measurement: a control whose probe has failed does not remain green due to inertia; it goes to "unverified".

Why never capture a status: a captured status is a declaration. It was true on the day it was written, and it remains in the interface long after the reality has changed. A derived status cannot remain inaccurate longer than the freshness of its evidence.


4. The Chain Log and its Anchor

All evidence – each probe verdict, each attestation, each version of the catalog – enters a chain log, adding only.

flowchart LR
    classDef e fill:#1e40af,stroke:#1e40af,color:#fff
    classDef a fill:#0f766e,stroke:#0f766e,color:#fff

    e1["Entrée n<br/>contenu + empreinte de n-1"]:::e
    e2["Entrée n+1<br/>contenu + empreinte de n"]:::e
    e3["Entrée n+2 — tête<br/>contenu + empreinte de n+1"]:::e
    anc["Ancre du jour<br/>numéro + empreinte de tête<br/>versionnée dans git"]:::a

    e1 --> e2 --> e3
    e3 -.->|"chaque soir"| anc
  • Each entry contains the SHA-256 hash of the previous one. Modifying, deleting, or inserting an entry in the middle breaks the chain at the exact entry: the verification tells you where.
  • There is also a case where the chain alone doesn't see it: truncation. Deleting the last entries leaves a perfectly valid chain, simply shorter.
  • This is why the anchor is important: every evening, the number and hash of the head of the log are versioned in Git and pushed to two remote repositories. A truncated log no longer finds its anchors. A probe confronts the log with the published anchors.

An intended consequence

Restoring the log from a backup returns it to a previous state: its recent entries are gone, and the verification against the anchors fails. This is exactly what happens – the log has indeed lost evidence. This failure is recorded; it never "corrects" itself by purging the anchors, which would be equivalent to erasing the trace of the loss.


5. Two logs, and who signs them

The log contains two types of entries:

  • the evidence, described above;
  • human actions: each decision to triage, each remediation action, recorded with its state before and after, in the same transaction as the action itself – an action without a trace cannot have occurred.

The author of an action is read from the channel – the authenticated session provided by the identity provider – and never from the body of the request. A log where the author declares themselves proves nothing: anyone with access could write any name.


6. The attestations

Some things cannot be measured: that a risk analysis has been reviewed, that the operator has been trained, that critical suppliers have been reviewed, that the off-site crisis channel has been tested. These are all based on a declaration: a human statement dated.

Three safeguards ensure that this is more than just a checkbox:

  • it is only accepted after an authenticated session;
  • it expires – annually or quarterly depending on the control;
  • it is entered into the register as any other piece of evidence, so it cannot be altered.

7. Auditing – The Process

An auditor, or the operator, will repeat these steps:

  1. Recalculate the chain in the register, then compare it to the anchors taken in git – not those that the server announces: the purpose of an anchor is to be outside the reach of the machine it monitors.
  2. Export the audit file – including the catalogue, status, evidence, incidents, and method – into a single file.
  3. Manually run a probe without writing to the register, and compare its verdict to the last one recorded.
  4. Choose a control at random and ask for its reverse verification – what command caused it to fail, and what did it reveal?

8. Adding a Control or Probe

  1. Write the probe according to the contract, including the header.
  2. Make it fail intentionally, and note the command that caused it to fail.
  3. Declare it in a catalogue control – the probe's identifier is the name of the file.
  4. Run it without declaring it, then wait for the next launch. A probe that has not been declared will appear as orphaned: it is clear that it has been forgotten.

To Read Next

Dernière vérification de cette page : 2026-09-11