# Éditions CatrustDB — Community & Enterprise

> Ce document décrit les deux éditions du serveur `catrustdb`,
> les fonctionnalités incluses dans chacune, et la procédure d'activation
> d'une licence Enterprise.

---

## Comparatif des éditions

| Fonctionnalité | Community | Enterprise |
|---|:---:|:---:|
| **Schéma CQL** (Schema, Instance, Mapping) | ✅ | ✅ |
| **Migrations** Σ / Δ / Π | ✅ | ✅ |
| **Serveur TCP NDJSON** (port 7474) | ✅ | ✅ |
| **Studio web** (port 7878) | ✅ | ✅ |
| **Export** CSV / JSONL / Parquet | ✅ | ✅ |
| **Import** CSV / Parquet | ✅ | ✅ |
| **Audit log** NDJSON (`--audit-log`) | ✅ | ✅ |
| **Mode lecture seule** (`--read-only`) | ✅ | ✅ |
| **Auth Bearer** simple (`--token`) | ✅ | ✅ |
| **Limite d'entités** | **5** | Illimité |
| **Limite de lignes** | **100 000** | Illimité |
| **RBAC** multi-rôle (`--token-admin / --token-rw / --token-ro`) | ❌ | ✅ |
| **WAL chiffré** AES-256-GCM + Argon2id (`--wal-key` / `CATRUST_WAL_KEY`) | ❌ | ✅ |
| **Sel Argon2id par-fichier** (sidecar `.salt`) | ❌ | ✅ |
| **Log Raft chiffré** AES-256-GCM (`--wal-key` appliqué au log consensus) | ❌ | ✅ |
| **Snapshot Raft chiffré + checksumé** (xxh3 + AES-GCM) | ❌ | ✅ |
| **TLS** rustls (`--tls-cert / --tls-key`) | ✅ | ✅ |
| **RGPD** : `anonymize`, `data_subject_access`, `data_subject_export`, `compliance_report` | ❌ | ✅ |
| **Arrow Flight** gRPC + pgwire | ✅* | ✅ |
| **Backends** Snowflake + Trino | ✅* | ✅ |
| **Rotation de clé WAL** (`rotate_wal_key`) | ❌ | ✅ |
| Licence | Gratuite, sans clé | Clé signée Ed25519 |
| Support | Communauté | Commercial — support@catrust.dev |

> \* Arrow Flight et pgwire sont activés par les binaires `catrust serve-flight` / `catrust serve-sql`
> qui sont distincts du serveur `catrustdb`. Ces modes ne nécessitent pas de licence.

---

## Démarrage Community

Aucune clé requise. Le serveur démarre automatiquement en mode Community si aucun
`--license-key` n'est fourni.

```bash
catrustdb --port 7474 --data-dir ./data
```

Le serveur affiche au démarrage :

```
[catrustdb] édition community (org: community)
[catrustdb] INFO édition community — certaines fonctionnalités nécessitent une licence Enterprise
```

### Limites Community

- **5 entités** maximum dans une base chargée
- **100 000 lignes** maximum au total

En cas de dépassement, la commande concernée (`load`, `import_csv`) retourne :

```json
{
  "ok": false,
  "error": "limite community 'max_entities' dépassée (6/5) — mise à niveau vers Enterprise"
}
```

Et pour les fonctionnalités bloquées par l'édition :

```json
{
  "ok": false,
  "error": "fonctionnalité Compliance nécessite une licence Enterprise — contacter support@catrust.dev"
}
```

---

## Démarrage Enterprise

### Via variables d'environnement (recommandé en production)

Tous les secrets peuvent être injectés par variable d'environnement plutôt que
par argument CLI — ce qui évite leur exposition dans `ps aux` ou les journaux système.

| Variable d'environnement | Argument CLI équivalent | Description |
|---|---|---|
| `CATRUST_LICENSE_KEY` | `--license-key` | Clé Ed25519 signée |
| `CATRUST_TOKEN` | `--token` | Token Bearer simple |
| `CATRUST_TOKEN_ADMIN` | `--token-admin` | Token RBAC Admin |
| `CATRUST_TOKEN_RW` | `--token-rw` | Token RBAC Read-Write |
| `CATRUST_TOKEN_RO` | `--token-ro` | Token RBAC Read-Only |
| `CATRUST_WAL_KEY` | `--wal-key` | Passphrase chiffrement WAL |

La valeur CLI a toujours **priorité** sur la variable d'environnement si les deux
sont définies. Les variables d'environnement sont lues en second recours.

```bash
# Injecter les secrets via l'environnement (Docker, Kubernetes, systemd EnvironmentFile…)
export CATRUST_LICENSE_KEY="<votre-clé>"
export CATRUST_TOKEN_ADMIN="$(cat /run/secrets/admin_token)"
export CATRUST_TOKEN_RW="$(cat /run/secrets/rw_token)"
export CATRUST_TOKEN_RO="$(cat /run/secrets/ro_token)"
export CATRUST_WAL_KEY="$(cat /run/secrets/wal_passphrase)"

catrustdb --port 7474 \
          --data-dir ./data \
          --tls-cert ./certs/server.crt \
          --tls-key  ./certs/server.key \
          --audit-log ./logs/audit.jsonl \
          --audit-log-max-days 90
```

### Via arguments CLI (développement / tests)

```bash
catrustdb --port 7474 \
          --license-key "<votre-clé>" \
          --data-dir ./data \
          --token-admin "$ADMIN_SECRET" \
          --token-rw    "$RW_SECRET" \
          --token-ro    "$RO_SECRET" \
          --wal-key     "$WAL_PASSPHRASE" \
          --tls-cert    ./certs/server.crt \
          --tls-key     ./certs/server.key \
          --audit-log   ./logs/audit.jsonl \
          --audit-log-max-days 90
```

Le serveur affiche au démarrage :

```
[catrustdb] édition enterprise (org: ACME Corp)
[catrustdb] authentification activée (RBAC)
[catrustdb] audit log : ./logs/audit.jsonl
```

### Comportement si la clé est invalide ou expirée

Le serveur **ne se bloque pas** — il démarre en mode Community avec un avertissement :

```
[catrustdb] WARN licence invalide : licence expirée — mode community activé
```

Seule exception : si `--wal-key` est passé avec une licence Community ou invalide,
le serveur refuse de démarrer et s'arrête avec code 1 :

```
[catrustdb] ERREUR : --wal-key requiert une licence Enterprise. ...
```

---

## Référence complète des arguments

```
catrustdb [OPTION...]

Options réseau :
  --host <addr>               Adresse d'écoute (défaut : 127.0.0.1)
  --port <n>                  Port TCP NDJSON (défaut : 7474)

Licence :
  --license-key <clé>         Clé Ed25519 signée (base64url.sig). Absent = Community.
                              Env : CATRUST_LICENSE_KEY

Authentification :
  --token <secret>            Auth Bearer simple (donne le niveau Admin)
                              Env : CATRUST_TOKEN
  --token-admin <secret>      Token RBAC Admin          [Enterprise]
                              Env : CATRUST_TOKEN_ADMIN
  --token-rw <secret>         Token RBAC Read-Write     [Enterprise]
                              Env : CATRUST_TOKEN_RW
  --token-ro <secret>         Token RBAC Read-Only      [Enterprise]
                              Env : CATRUST_TOKEN_RO

Sécurité des données :
  --wal-key <passphrase>      Chiffrement WAL AES-256-GCM (Argon2id) [Enterprise]
                              Chiffre le WAL utilisateur, le log Raft ET les snapshots.
                              Un sel Argon2id par-fichier est stocké dans <wal>.salt.
                              Env : CATRUST_WAL_KEY
  --wal-compact-threshold <n> Auto-compaction WAL toutes les n entrées (0 = désactivé)
  --tls-cert <path>           Certificat TLS (PEM)
  --tls-key <path>            Clé privée TLS (PEM)
  --data-dir <path>           Répertoire de données (whitelist persist/from_wal/compact)
  --read-only                 Mode lecture seule global

Performance :
  --max-connections <n>       Connexions simultanées max (défaut : 128)
  --max-payload-bytes <n>     Taille max d'un message NDJSON (défaut : 67 108 864 = 64 Mo)

Audit :
  --audit-log <path>          Fichier d'audit log NDJSON
  --audit-log-max-mb <n>      Rotation après n Mo (défaut : 0 = désactivé)
  --audit-log-max-days <n>    Suppression des fichiers de plus de n jours (défaut : 0 = illimité)

Cluster HA (Enterprise — nécessite capability MultiNode) :
  --cluster-id <n>            Identifiant du nœud (0–255). Active le mode cluster.
  --cluster-addr <host:port>  Adresse de ce nœud sur le port Raft (défaut : <host>:7476)
  --cluster-peers <liste>     Membres du cluster : "0=host0:7476,1=host1:7476,2=host2:7476"
  --cluster-tls-cert <path>   Certificat mTLS du nœud (PEM) — exige aussi key + ca
  --cluster-tls-key <path>    Clé privée mTLS du nœud (PEM)
  --cluster-tls-ca <path>     Certificat CA pour la vérification mutuelle (PEM)
  --read-linearizable         Lectures linéarisables via ReadIndex Raft (défaut : false)

  Note : les trois flags --cluster-tls-* doivent être fournis ensemble ou absents.
  Sans mTLS, le port 7476 doit impérativement être protégé par un firewall ou VPC.
  La réponse "not_leader" retourne l'adresse API (port --port, défaut 7474) du leader.
```

---

## Obtenir une licence Enterprise

Contacter **support@catrust.dev** en précisant :
- Nom de l'organisation
- Nombre d'entités et volume estimé
- Durée souhaitée

### Procédure côté éditeur (interne)

```bash
# 1. Générer la paire de clés (une seule fois, stocker la clé privée offline)
cargo run -p catrust-license --features keygen --bin gen-license -- --gen-key

# 2. Émettre une licence pour un client
cargo run -p catrust-license --features keygen --bin gen-license -- --sign \
  --signing-key <hex_clé_privée_64_chars> \
  --org         "ACME Corp"               \
  --tier        enterprise                \
  --days        365

# Avec limites personnalisées (ex. offre "Starter") :
  --max-entities 20 --max-rows 500000

# 3. Transmettre la clé au client via canal chiffré (email PGP, vault partagé…)
```

### Format de la clé

```
<base64url(json_payload)>.<base64url(signature_ed25519_64_octets)>
```

La signature est vérifiée avec la **clé publique Ed25519** embarquée dans le binaire.
La clé privée ne quitte jamais l'infrastructure interne — une clé interceptée
ne peut pas être falsifiée pour étendre ses droits.

---

## Architecture de la vérification

```
Binaire catrustdb
  └── PRODUCTION_PUBKEY: [u8; 32]   ← clé publique statique

Au démarrage :
  LicenseKey::from_signed("payload.sig")
    → base64url_decode(sig) → ed25519_verify(payload, sig, pubkey)
    → serde_json::parse(payload) → check expires > now()
    → ServerConfig { entitlements: Arc<LicenseKey> }

À chaque commande Enterprise :
  config.entitlements.require(Capability::Compliance)  // RGPD
  config.entitlements.require(Capability::AccessControl) // RBAC
  config.entitlements.require(Capability::DataSafe)    // WAL
```

Les vérifications sont distribuées à 4 sites du code serveur :

| Site | Contrôle |
|------|---------|
| Startup (`run()`) | Log de l'édition et avertissement Community |
| Startup (`main()`) | `--wal-key` bloqué si Community |
| Dispatch — auth RBAC | Multi-token bloqué si Community |
| Dispatch — RGPD cmds | `anonymize` / `data_subject_*` / `compliance_report` bloqués si Community |

---

## CHANGELOG des éditions

| Version | Nouveauté |
|---------|-----------|
| **1.1.0** | **RSSI-06** — Sel Argon2id par-fichier (`<wal>.salt`) — un sel unique par fichier WAL |
| 1.1.0 | **DPO-01** — Log Raft (`raft_log.wal`) chiffré AES-256-GCM si `--wal-key` fourni |
| 1.1.0 | **DPO-02** — Snapshots Raft (`snap_data.bin`) chiffrés AES-256-GCM |
| 1.1.0 | **SRE-02** — Checksum xxh3-64 en tête de `snap_data.bin` (détection de corruption) |
| 1.1.0 | **DPO-04** — Secrets lisibles depuis variables d'environnement `CATRUST_*` |
| 1.1.0 | **RSSI-01** — `build.rs` bloque la compilation release si `PRODUCTION_PUBKEY` est le placeholder |
| 1.1.0 | **Rotation de clé** : nouveau sel généré automatiquement après `rotate_wal_key` (forward secrecy) |
| **1.0.0** | Système de licences Ed25519 — `catrust-license` crate |
| 1.0.0 | Édition Community : limites 5 entités / 100 000 lignes |
| 1.0.0 | WAL chiffré, RBAC, commandes RGPD réservés à Enterprise |
| 1.0.0 | Outil `gen-license` : `--gen-key` + `--sign` |
