> ## Documentation Index
> Fetch the complete documentation index at: https://docs.snakysec.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Report model

# Report Model — Schema v3.0

Spécification du format des artefacts d'audit générés par le moteur PowerShell.

## Nomenclature

```
artifacts/audit/<framework>-<product-area>-<tenantId>-<timestamp>.json
```

* `<framework>` : `cis` | `scuba`
* `<product-area>` : `entra` | `exchange` | `teams` | `sharepoint` | `defender` | `purview`
* `<tenantId>` : GUID tenant Entra
* `<timestamp>` : ISO 8601 compact (`20260414T213045Z`)

Exemple : `artifacts/audit/cis-entra-12345678-abcd-...-20260414T213045Z.json`

## Structure de l'artefact

```jsonc theme={null}
{
  "schemaVersion": "3.0",
  "generatedAt": "2026-04-14T21:30:45Z",
  "runMetadata": {
    "framework": "cis",               // cis | scuba
    "frameworkVersion": "v6.0.1",     // v6.0.1 (CIS) | v1.5.0 (SCuBA)
    "productArea": "entra",
    "runnerVersion": "3.0.0",
    "authMode": "oidc-wif",           // oidc-wif | cert-x509 | secret
    "isHybrid": false                  // Test-MsspTenantHybrid
  },
  "tenant": {
    "tenantId": "<guid>",
    "tenantName": "Contoso",
    "skus": ["ENTERPRISEPREMIUM", "SPE_E5", ...]
  },
  "summary": {
    "total": 60,
    "compliant": 42,
    "finding": 8,
    "manual": 5,
    "not_applicable": 3,
    "insufficient_perms": 1,
    "not_assessed": 1,
    "error": 0
  },
  "controls": [
    {
      "id": "CIS-ENTRA-1.1.1",
      "title": "...",
      "level": 1,                     // CIS L1 | L2  —  SCuBA: absent
      "method": "automated",          // automated | manual
      "status": "compliant",          // voir taxonomie ci-dessous
      "severity": "high",             // critical | high | medium | low
      "evidence": {                   // payload brut (Graph JSON ou cmdlet output)
        "endpoint": "/policies/authorizationPolicy",
        "response": { ... },
        "apiVersion": "v1.0"          // v1.0 | beta (quand renseigné par le contrôle)
      },
      "check": {                      // condition évaluée
        "property": "allowedToSignUpEmailBasedSubscriptions",
        "operator": "eq",
        "expected": false,
        "observed": true
      },
      "remediation": {
        "instructions": "...",
        "graphSetUrl": "https://...",
        "portalUrl": "https://..."
      },
      "mappings": {
        "cis": "CIS-ENTRA-1.1.1",
        "iso27001": "A.5.15",
        "nistCsf2": "PR.AC-01"
      },
      "requiredPermissions": ["Policy.Read.All"],
      "requiredLicense": null,
      "applicability": {
        "hybridOnly": false,
        "cloudOnly": false
      },
      "manualValidation": null         // objet présent quand method=manual
    }
  ]
}
```

## Taxonomie des statuts (v3.0 — 7 valeurs)

| Statut               | Signification                                                                 | Conversion `GapFinding`             |
| -------------------- | ----------------------------------------------------------------------------- | ----------------------------------- |
| `compliant`          | Contrôle évalué, conforme                                                     | Non                                 |
| `finding`            | Contrôle évalué, non conforme                                                 | **Oui** (→ OPEN)                    |
| `manual`             | Contrôle non automatisable — nécessite validation humaine                     | Non (guide dans `manualValidation`) |
| `not_applicable`     | Contrôle non applicable (licence manquante, hybrid-only sur cloud-only, etc.) | Non                                 |
| `insufficient_perms` | Permissions Graph insuffisantes pour évaluer                                  | Non (audit log)                     |
| `not_assessed`       | Évaluation impossible (dépendance externe, endpoint indisponible)             | Non                                 |
| `error`              | Erreur technique (throw dans le check)                                        | Non (audit log + Sentry)            |

## Import pipeline

`platform/src/lib/import/index.ts` :

1. Télécharge l'artefact depuis GitLab (via API job artifact).
2. Valide le schéma v3 (Zod).
3. Upsert `AuditRun` avec le `summary`.
4. Insère/update `ControlResult` par contrôle.
5. Pour chaque `status: "finding"`, crée un `GapFinding` en état `OPEN` (ou update si existant).
6. Génère les alertes (score dégradé, critical finding).

## Génération rapports

À partir des `ControlResult` + `GapFinding` en DB :

* **PDF** (`/api/v1/audits/:id/report`) — Score exécutif + scores domaine + table contrôles + plan remédiation
* **Excel** (`/api/v1/audits/:id/report/excel`) — 6 onglets (Summary, Domain Scores, Framework Mapping, All Controls, Failed Controls, Remediation Plan)
* **HTML** (`/api/v1/audits/:id/report/html`) — Standalone (CSS/JS inline), search + filtres temps réel

## Évolution schéma

* Breaking change sur le schéma → incrémenter `schemaVersion` majeur et supporter parallèlement l'ancien dans l'import pipeline pendant ≥ 1 release.
* Nouveau champ optionnel → conserver `schemaVersion` 3.x.
