{{ member.identity.legal_name }}
ID: {{ member.member_id }}
Slug: {{ member.slug }}
Statut: {{ member.status }}
{% if member.label.current %}Label: {{ member.label.current.level }} ({{ member.label.current.score_global }}/100)
{% endif %}# Document 14 : Structure YAML du Registraire ## L'Alliance Boréale — Source de Vérité Technique **Version:** 1.0 **Date:** 23 octobre 2025 **Statut:** Document technique **Adopté par :** Cercle Opérationnel **Licence:** CC BY-SA 4.0 --- ## PRÉAMBULE Le Registraire est **la source de vérité unique** de L'Alliance Boréale. **Tout ce qui compte est dans le Registraire :** - Membres (actifs, probation, sortis) - Services fédérés (DNS, email, Matrix) - Labels et scores - Décisions de gouvernance - Zones DNS **Format : YAML + Git** **Pourquoi YAML ?** - ✅ Lisible par humains (contrairement à JSON) - ✅ Éditable manuellement (pas besoin d'interface web) - ✅ Versionnable (Git track changes) - ✅ Validable (schemas, linters) - ✅ Parsable par machines (Ansible, scripts) **Pourquoi Git ?** - ✅ Historique complet (qui a changé quoi, quand, pourquoi) - ✅ Pull requests (review avant merge) - ✅ Branches (test modifications avant prod) - ✅ Réversibilité (rollback si erreur) - ✅ Distribution (chaque membre peut cloner) **Principe :** Une seule source de vérité, maintenue collectivement, auditable par tous. --- ## SECTION 1 : STRUCTURE DU DÉPÔT GIT ### 1.1 Arborescence Complète ``` registraire/ ├── README.md # Documentation générale ├── CONTRIBUTING.md # Guide contribution ├── LICENSE # CC BY-SA 4.0 │ ├── schemas/ # Schémas de validation │ ├── member.schema.json # JSON Schema fiche membre │ ├── decision.schema.json # JSON Schema décision │ └── label.schema.json # JSON Schema label │ ├── membres/ # Fiches membres │ ├── m001-chezlepro.yml # Membre 001 │ ├── m002-technolibre.yml # Membre 002 │ ├── m003-coop-nordique.yml # Membre 003 │ └── ... │ ├── gouvernance/ # Décisions & gouvernance │ ├── decisions/ │ │ ├── 2025-001-admission-m001.yml │ │ ├── 2025-002-admission-m002.yml │ │ └── 2025-042-amendement-charte.yml │ │ │ ├── cercles/ │ │ ├── strategique.yml # Composition cercle │ │ ├── operationnel.yml │ │ └── ethique.yml │ │ │ └── assemblees/ │ ├── 2025-01-ag-annuelle.yml # PV assemblée générale │ └── 2026-01-ag-annuelle.yml │ ├── labels/ # Labellisation │ ├── attributions/ │ │ ├── m001-2025-Q4.yml # Label attribué │ │ ├── m002-2025-Q4.yml │ │ └── ... │ │ │ └── audits/ │ ├── m001-2025-Q4-rapport.yml # Rapport audit (synthèse) │ └── ... │ ├── dns/ # Configuration DNS │ ├── zones/ │ │ ├── boreal.ca.zone # Zone racine │ │ ├── chezlepro.boreal.ca.zone # Zones membres │ │ └── technolibre.boreal.ca.zone │ │ │ └── delegations/ │ └── delegations.yml # Liste délégations actives │ ├── incidents/ # Post-mortems │ ├── 2025-10-incident-dns-p1.yml │ └── 2025-11-incident-cert-p0.yml │ └── banque-temps/ # Transactions (si implémentée) └── transactions-2025-Q4.yml ``` --- ### 1.2 Nomenclature des Fichiers **Règles strictes :** | Type | Format | Exemple | |------|--------|---------| | **Membre** | `mXXX-[slug].yml` | `m001-chezlepro.yml` | | **Décision** | `YYYY-NNN-[titre-court].yml` | `2025-042-amendement-charte.yml` | | **Label** | `mXXX-YYYY-QN.yml` | `m001-2025-Q4.yml` | | **Audit** | `mXXX-YYYY-QN-rapport.yml` | `m001-2025-Q4-rapport.yml` | | **Incident** | `YYYY-MM-incident-[titre]-[prio].yml` | `2025-10-incident-dns-p1.yml` | | **Zone DNS** | `[domain].zone` | `chezlepro.boreal.ca.zone` | **Avantages :** - Tri alphabétique = tri chronologique (pour décisions, incidents) - ID membre visible (mXXX) - Parsing facile (scripts) --- ### 1.3 Branches et Workflow Git **Branches :** ``` main → Production (fiches validées) ├── dev → Développement (intégration continue) └── feature/* → Branches de travail (1 feature = 1 branch) ├── feature/add-member-m004 ├── feature/update-label-m001 └── feature/dns-delegation-m002 ``` **Workflow Pull Request :** 1. **Créer branche** : `git checkout -b feature/add-member-m004` 2. **Modifier fichier(s)** : Éditer `membres/m004-nouveau.yml` 3. **Commit** : `git commit -m "feat: Add member m004 (Nouveau OBNL)"` 4. **Push** : `git push origin feature/add-member-m004` 5. **Ouvrir Pull Request** sur Forge 6. **Review** : 1+ membre (vérification conformité) 7. **CI/CD** : Tests automatiques (yamllint, schema validation) 8. **Merge** : Si tests ✅ + review ✅ → merge dans `main` **Protection branche `main` :** - Aucun push direct (seulement via PR) - Review obligatoire (1+ personne) - CI/CD doit passer (tests) --- ## SECTION 2 : SCHÉMA FICHE MEMBRE ### 2.1 Structure Complète (Commentée) **Fichier : `membres/m001-chezlepro.yml`** ```yaml # ============================================================================ # FICHE MEMBRE — L'Alliance Boréale # ============================================================================ # ID: m001 # Slug: chezlepro # Nom légal: Chez le Pro Technologies Inc. # Statut: actif # Dernière mise à jour: 2025-10-23 # ============================================================================ # ---------------------------------------------------------------------------- # SECTION 1 : IDENTITÉ # ---------------------------------------------------------------------------- member_id: m001 slug: chezlepro status: active # active | probation | suspended | exited identity: legal_name: "Chez le Pro Technologies Inc." legal_form: corporation # corporation | coop | npo | sole_proprietorship jurisdiction: QC # Juridiction d'enregistrement registration_number: "1234567890" # NEQ (Québec) ou équivalent operating_name: "Chez le Pro" # Nom commercial (si différent) website: "https://chezle.pro" founded_date: "2018-03-15" joined_alliance_date: "2025-01-15" probation_end_date: "2025-04-15" # null si membre actif confirmé description: | Chez le Pro offre des services d'hébergement web éthique et de développement logiciel sur mesure pour PME québécoises. Membre fondateur de L'Alliance Boréale. # ---------------------------------------------------------------------------- # SECTION 2 : CONTACTS # ---------------------------------------------------------------------------- contacts: primary: name: "Jean Tremblay" role: "Président" email: "jean@chezle.pro" phone: "+1-514-555-0100" matrix: "@jean:matrix.chezlepro.boreal.ca" technical: name: "Marie Gagnon" role: "Directrice technique" email: "marie@chezle.pro" phone: "+1-514-555-0101" matrix: "@marie:matrix.chezlepro.boreal.ca" security: email: "security@chezle.pro" pgp_key: "0x1234567890ABCDEF" pgp_fingerprint: "1234 5678 90AB CDEF 1234 5678 90AB CDEF 1234 5678" legal: name: "Sophie Lavoie" role: "Conseillère juridique" email: "legal@chezle.pro" # ---------------------------------------------------------------------------- # SECTION 3 : INFRASTRUCTURE # ---------------------------------------------------------------------------- infrastructure: hosting: provider: "OVH Canada" datacenter_location: "Montreal, QC, Canada" owned: false # true = hardware propre, false = loué network: ipv4_public: - "203.0.113.10/32" - "203.0.113.20/28" ipv6_public: - "2001:db8:1234::/48" ipv4_private: "10.1.0.0/16" # Selon Doc 5 asn: null # Autonomous System Number (si applicable) dns: primary_ns: "ns1.chezlepro.boreal.ca" secondary_ns: "ns2.chezlepro.boreal.ca" ns_ips: ns1: "203.0.113.10" ns2: "203.0.113.11" dnssec_enabled: true dnssec_ds_records: - "12345 8 2 1234567890ABCDEF..." # DS record pour parent servers: count: 3 summary: | - 1x serveur compute (Proxmox) - 1x serveur storage (ZFS) - 1x serveur backup (dédié) # ---------------------------------------------------------------------------- # SECTION 4 : SERVICES PUBLICS # ---------------------------------------------------------------------------- services: email: enabled: true domain: "chezle.pro" mx_records: - priority: 10 host: "mail.chezlepro.boreal.ca" protocols: - smtp - smtps - imap - imaps security: dkim: true spf: true dmarc: true tls_min_version: "1.2" web: enabled: true urls: - "https://chezle.pro" - "https://www.chezle.pro" technologies: - nginx - php-fpm - postgresql cloud_storage: enabled: true platform: nextcloud url: "https://cloud.chezlepro.boreal.ca" version: "28.0.1" matrix: enabled: true homeserver_url: "https://matrix.chezlepro.boreal.ca" federation_enabled: true server_name: "chezlepro.boreal.ca" status_page: enabled: true url: "https://status.chezlepro.boreal.ca" platform: "upptime" # upptime | cachet | custom monitoring: prometheus_endpoint: "https://prometheus.chezlepro.boreal.ca" grafana_url: "https://grafana.chezlepro.boreal.ca" public_metrics: true # Métriques partagées avec Alliance # ---------------------------------------------------------------------------- # SECTION 5 : STANDARDS ET CONFORMITÉ # ---------------------------------------------------------------------------- standards: open_source_percentage: 85 # % de stack en logiciels libres protocols_supported: - smtp - imap - caldav - carddav - webdav - matrix certifications: - name: "ISO 27001" issued_by: "BSI Group" valid_until: "2026-12-31" certificate_url: "https://chezle.pro/certs/iso27001.pdf" compliance: loi_25: true # Conformité Loi 25 (Québec) rgpd: true # Conformité RGPD (EU) pipeda: true # Conformité PIPEDA (Canada) # ---------------------------------------------------------------------------- # SECTION 6 : LABEL DE PRESTIGE # ---------------------------------------------------------------------------- label: current: level: gold # bronze | silver | gold | platinum | null score_global: 82 scores_by_domain: infrastructure: 85 security: 88 interoperability: 78 open_source: 90 operations: 75 sustainability: 72 issued_date: "2025-10-01" valid_until: "2026-10-01" audited_by: "m002" # Membre auditeur report_url: "registraire/labels/audits/m001-2025-Q4-rapport.yml" history: - level: silver score_global: 68 issued_date: "2025-04-01" valid_until: "2026-04-01" - level: bronze score_global: 52 issued_date: "2025-01-15" valid_until: "2026-01-15" # ---------------------------------------------------------------------------- # SECTION 7 : PARTICIPATION & CONTRIBUTIONS # ---------------------------------------------------------------------------- participation: cercles: - name: "Cercle Stratégique" role: "membre" since: "2025-01-15" - name: "Cercle Opérationnel" role: "président" since: "2025-07-01" until: "2026-01-01" contributions: - type: "code" description: "Développement Registraire YAML (validation, CI/CD)" date: "2025-03-20" hours: 15 - type: "documentation" description: "Rédaction runbooks DNS & DNSSEC" date: "2025-05-10" hours: 8 - type: "mentoring" description: "Parrainage membre m003 (probation)" date: "2025-08-01" status: "en_cours" banque_temps: balance: 42 # Crédits (heures) last_updated: "2025-10-20" # ---------------------------------------------------------------------------- # SECTION 8 : MÉTADONNÉES # ---------------------------------------------------------------------------- metadata: created_at: "2025-01-15T10:30:00Z" updated_at: "2025-10-23T14:22:00Z" updated_by: "m001" # Dernière modification par version: 2 # Numéro de version du schéma notes: | Membre fondateur. Infrastructure solide. Contributions régulières. Candidat potentiel Platine en 2026 si maintien niveau actuel. tags: - fondateur - hebergement - quebec - infrastructure-mature ``` --- ### 2.2 Champs Obligatoires vs Optionnels **Obligatoires (validation bloquante) :** - `member_id` - `slug` - `status` - `identity.legal_name` - `identity.legal_form` - `identity.joined_alliance_date` - `contacts.primary` (name, email) - `contacts.technical.email` - `contacts.security.email` - `infrastructure.dns.primary_ns` - `services.status_page.url` **Recommandés (warning si absent) :** - `identity.website` - `infrastructure.dns.dnssec_enabled` - `services.email` (si service email offert) - `standards.open_source_percentage` - `label.current` (si labellisé) **Optionnels (sans warning) :** - `infrastructure.network.asn` - `standards.certifications` - `participation.contributions` - `metadata.notes` --- ### 2.3 Valeurs Enum (Contrôlées) **Statut membre (`status`) :** - `probation` : En période probatoire (3 mois) - `active` : Membre actif confirmé - `suspended` : Suspendu temporairement - `exited` : Sorti de L'Alliance (volontaire ou radiation) **Forme légale (`identity.legal_form`) :** - `corporation` : Entreprise incorporée - `coop` : Coopérative - `npo` : Organisme à but non lucratif - `sole_proprietorship` : Travailleur autonome **Niveau label (`label.current.level`) :** - `bronze` - `silver` - `gold` - `platinum` - `null` : Non labellisé **Type contribution (`participation.contributions.type`) :** - `code` : Contribution code (forge) - `documentation` : Rédaction wiki/runbooks - `mentoring` : Parrainage nouveau membre - `audit` : Audit pair-à-pair - `governance` : Participation cercle - `infrastructure` : Support technique mutuel --- ## SECTION 3 : VALIDATION AUTOMATIQUE ### 3.1 YAML Lint (Syntaxe) **Outil : `yamllint`** **Configuration : `.yamllint`** ```yaml extends: default rules: line-length: max: 120 level: warning indentation: spaces: 2 comments: min-spaces-from-content: 2 document-start: present: true ``` **Commande :** ```bash yamllint membres/*.yml ``` **Résultat attendu :** ``` membres/m001-chezlepro.yml 0:0 warning missing document start "---" (document-start) membres/m002-technolibre.yml 0:0 warning missing document start "---" (document-start) ``` --- ### 3.2 JSON Schema (Structure) **Schéma : `schemas/member.schema.json`** ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://registraire.alliance-boreale.ca/schemas/member.schema.json", "title": "Alliance Boréale - Fiche Membre", "description": "Schéma de validation pour fiche membre", "type": "object", "required": [ "member_id", "slug", "status", "identity", "contacts", "infrastructure", "services" ], "properties": { "member_id": { "type": "string", "pattern": "^m[0-9]{3}$", "description": "ID unique membre (format: mXXX)" }, "slug": { "type": "string", "pattern": "^[a-z0-9-]{3,20}$", "description": "Slug textuel unique (3-20 car, minuscules)" }, "status": { "type": "string", "enum": ["probation", "active", "suspended", "exited"] }, "identity": { "type": "object", "required": ["legal_name", "legal_form", "joined_alliance_date"], "properties": { "legal_name": { "type": "string", "minLength": 3 }, "legal_form": { "type": "string", "enum": ["corporation", "coop", "npo", "sole_proprietorship"] }, "jurisdiction": { "type": "string", "pattern": "^[A-Z]{2}$" }, "registration_number": { "type": "string" }, "website": { "type": "string", "format": "uri" }, "joined_alliance_date": { "type": "string", "format": "date" }, "description": { "type": "string" } } }, "contacts": { "type": "object", "required": ["primary", "technical", "security"], "properties": { "primary": { "type": "object", "required": ["name", "email"], "properties": { "name": { "type": "string" }, "role": { "type": "string" }, "email": { "type": "string", "format": "email" }, "phone": { "type": "string" }, "matrix": { "type": "string" } } }, "technical": { "type": "object", "required": ["email"], "properties": { "name": { "type": "string" }, "email": { "type": "string", "format": "email" } } }, "security": { "type": "object", "required": ["email"], "properties": { "email": { "type": "string", "format": "email" }, "pgp_key": { "type": "string" } } } } }, "infrastructure": { "type": "object", "required": ["dns"], "properties": { "dns": { "type": "object", "required": ["primary_ns"], "properties": { "primary_ns": { "type": "string", "format": "hostname" }, "secondary_ns": { "type": "string", "format": "hostname" }, "dnssec_enabled": { "type": "boolean" } } } } }, "services": { "type": "object", "required": ["status_page"], "properties": { "status_page": { "type": "object", "required": ["url"], "properties": { "enabled": { "type": "boolean" }, "url": { "type": "string", "format": "uri" } } } } }, "label": { "type": "object", "properties": { "current": { "type": "object", "required": ["level", "score_global", "issued_date", "valid_until"], "properties": { "level": { "type": "string", "enum": ["bronze", "silver", "gold", "platinum"] }, "score_global": { "type": "integer", "minimum": 0, "maximum": 100 }, "scores_by_domain": { "type": "object", "properties": { "infrastructure": { "type": "integer", "minimum": 0, "maximum": 100 }, "security": { "type": "integer", "minimum": 0, "maximum": 100 }, "interoperability": { "type": "integer", "minimum": 0, "maximum": 100 }, "open_source": { "type": "integer", "minimum": 0, "maximum": 100 }, "operations": { "type": "integer", "minimum": 0, "maximum": 100 }, "sustainability": { "type": "integer", "minimum": 0, "maximum": 100 } } }, "issued_date": { "type": "string", "format": "date" }, "valid_until": { "type": "string", "format": "date" } } } } } } } ``` **Validation :** ```bash # Outil: ajv-cli (JSON Schema validator) ajv validate -s schemas/member.schema.json -d "membres/*.yml" ``` --- ### 3.3 CI/CD Pipeline **Fichier : `.gitlab-ci.yml` (ou `.github/workflows/validate.yml`)** ```yaml stages: - validate - test - deploy # Job 1: Validation syntaxe YAML yaml-lint: stage: validate image: python:3.11-alpine before_script: - pip install yamllint script: - yamllint membres/*.yml gouvernance/**/*.yml labels/**/*.yml only: - merge_requests - main # Job 2: Validation structure (JSON Schema) schema-validation: stage: validate image: node:18-alpine before_script: - npm install -g ajv-cli ajv-formats script: - ajv validate -s schemas/member.schema.json -d "membres/*.yml" - ajv validate -s schemas/decision.schema.json -d "gouvernance/decisions/*.yml" - ajv validate -s schemas/label.schema.json -d "labels/attributions/*.yml" only: - merge_requests - main # Job 3: Vérification unicité slug/ID uniqueness-check: stage: test image: python:3.11-alpine before_script: - pip install pyyaml script: - python scripts/check-uniqueness.py only: - merge_requests - main # Job 4: Génération site web statique (optionnel) generate-website: stage: deploy image: python:3.11-alpine before_script: - pip install pyyaml jinja2 script: - python scripts/generate-website.py - mkdir -p public - cp -r website/* public/ artifacts: paths: - public only: - main ``` **Script `scripts/check-uniqueness.py` :** ```python #!/usr/bin/env python3 """Vérifier unicité des IDs et slugs membres.""" import sys from pathlib import Path import yaml def check_uniqueness(): members_dir = Path("membres") ids = [] slugs = [] for file in members_dir.glob("*.yml"): with open(file) as f: data = yaml.safe_load(f) member_id = data.get("member_id") slug = data.get("slug") if member_id in ids: print(f"❌ ERREUR: ID {member_id} dupliqué dans {file}") sys.exit(1) ids.append(member_id) if slug in slugs: print(f"❌ ERREUR: Slug {slug} dupliqué dans {file}") sys.exit(1) slugs.append(slug) print(f"✅ Validation OK: {len(ids)} membres, IDs et slugs uniques") return 0 if __name__ == "__main__": sys.exit(check_uniqueness()) ``` --- ## SECTION 4 : PROCESSUS DE MISE À JOUR ### 4.1 Modification par le Membre Lui-Même **Cas d'usage :** Mise à jour contact technique, ajout service, etc. **Processus :** 1. **Cloner le dépôt** ```bash git clone https://forge.boreal.ca/alliance/registraire.git cd registraire ``` 2. **Créer branche** ```bash git checkout -b update/m001-add-matrix-service ``` 3. **Éditer fiche** ```bash vim membres/m001-chezlepro.yml # Ajouter section services.matrix ``` 4. **Valider localement** ```bash yamllint membres/m001-chezlepro.yml ajv validate -s schemas/member.schema.json -d membres/m001-chezlepro.yml ``` 5. **Commit** ```bash git add membres/m001-chezlepro.yml git commit -m "feat(m001): Add Matrix federation service" ``` 6. **Push et Pull Request** ```bash git push origin update/m001-add-matrix-service # Ouvrir PR sur forge.boreal.ca ``` 7. **Review + Merge** - Cercle Opérationnel review (vérification cohérence) - CI/CD valide (tests automatiques) - Merge dans `main` **Délai typique :** 1-3 jours. --- ### 4.2 Modification par Cercle Opérationnel **Cas d'usage :** Changement statut, attribution label, décision gouvernance. **Processus similaire, mais :** - Commit signé GPG (authentification) - Mention dans commit message : `[CERCLE-OPS]` - Review par 2+ membres du Cercle Opérationnel **Exemple :** ```bash git commit -S -m "[CERCLE-OPS] feat(m001): Promote to Gold label (Q4 2025)" ``` --- ### 4.3 Modification Urgente (Incident) **Cas d'usage :** Révocation certificat, changement IP urgent. **Processus accéléré :** - Commit direct sur `main` autorisé (exception) - Notification Matrix #incidents immédiate - Justification dans commit message **Exemple :** ```bash git commit -m "fix(m001): Update DNS IP after datacenter migration (P1 incident)" git push origin main # Post dans Matrix: "🚨 Update urgent registraire m001 (migration datacenter)" ``` **Post-mortem :** Documentation de l'incident + amélioration du processus si nécessaire. --- ## SECTION 5 : GÉNÉRATION DE VUES ### 5.1 Site Web Public **Concept :** Générer site web statique à partir des YAML (lecture seule). **URL :** `https://registraire.alliance-boreale.ca` **Pages générées :** - `/` : Liste membres actifs - `/membres/m001` : Fiche membre détaillée (infos publiques) - `/labels` : Tableau de bord labels - `/decisions` : Liste décisions publiques - `/stats` : Statistiques agrégées **Technologie :** Python + Jinja2, ou Jekyll, ou Hugo. **Script `scripts/generate-website.py` (squelette) :** ```python #!/usr/bin/env python3 """Générer site web statique à partir des YAML.""" from pathlib import Path import yaml from jinja2 import Environment, FileSystemLoader def generate(): # Charger tous les membres members = [] for file in Path("membres").glob("*.yml"): with open(file) as f: data = yaml.safe_load(f) if data["status"] in ["active", "probation"]: members.append(data) # Trier par joined_date members.sort(key=lambda m: m["identity"]["joined_alliance_date"]) # Générer HTML env = Environment(loader=FileSystemLoader("templates")) template = env.get_template("index.html") html = template.render(members=members) Path("website").mkdir(exist_ok=True) with open("website/index.html", "w") as f: f.write(html) print(f"✅ Site généré: {len(members)} membres") if __name__ == "__main__": generate() ``` **Template `templates/index.html` :** ```html
Fédération de services numériques éthiques
ID: {{ member.member_id }}
Slug: {{ member.slug }}
Statut: {{ member.status }}
{% if member.label.current %}Label: {{ member.label.current.level }} ({{ member.label.current.score_global }}/100)
{% endif %}