
Preuves SOC 2 qui se collectent d'elles-mêmes dans GitLab CI : chaque merge émet un bundle signé, une barrière OPA bloque les releases dont les preuves manquent, et les auditeurs reçoivent un seul lien au lieu de captures d'écran.
Preuves SOC 2 qui se collectent d'elles-mêmes dans GitLab CI : chaque merge émet un bundle signé, une barrière Open Policy Agent bloque les releases dont les preuves manquent, et un auditeur reçoit un seul lien vers un paquet au lieu de captures d'écran.
Tableau de bord auditeur en direct · Projet GitLab · Preuves de démonstration · Feuille de route
J'ai construit ShipProof parce que les ventes enterprise s'enlisent systématiquement lors de la revue infosec. Quand un auditeur demande des preuves de gestion des changements SOC 2 Type II, les ingénieurs passent souvent deux semaines à chercher des captures d'écran dans Jira, Slack et Drive.
Je voulais que les preuves vivent directement dans le pipeline de déploiement. Chaque commit de merge dans ShipProof crée automatiquement un bundle de preuves canonique et signé couvrant les exécutions de tests, les scans SAST Semgrep, la détection de secrets Gitleaks, les nomenclatures logicielles Syft et les approbations CODEOWNERS.
Ma règle de conception centrale est stricte : un LLM peut résumer des preuves ou rédiger des descriptions d'issues, mais il ne peut jamais approuver une release. La barrière de release est une évaluation Open Policy Agent écrite en Rego. Si un artefact manque ou si une approbation ressemble à un tampon automatique, la barrière échoue en mode fermé, interrompt la release et ouvre une issue avec le chemin de correction. Quand la barrière autorise, l'auditeur reçoit un seul lien vers un site statique ou une API authentifiée.
J'ai confronté ShipProof au cycle de vie DevOps de GitLab. Il automatise nativement les neuf étapes :
| Étape | Ce que j'ai automatisé dans le pipeline |
|---|---|
| plan | Gestion en boucle fermée des éléments de travail d'écart. Les refus de la barrière ouvrent automatiquement des issues de suivi structurées avec des compteurs de récurrence ; les pipelines réussis suivants résolvent et ferment automatiquement les issues avec les références des commits de correction. |
| create | Revue de code et gestion des sources. CODEOWNERS protège les fichiers de politique ; la barrière rejette les approbations en tampon automatique de moins de cinq minutes ; des notes MR automatisées guident la revue ; les flux Duo narrent les commentaires MR. |
| verify | pytest, Semgrep SAST et Gitleaks s'exécutent à l'étape verify, en enregistrant les hachages des artefacts. |
| package | Syft génère des SBOM CycloneDX à l'étape package et hache l'artefact dans le bundle. |
| secure | La barrière OPA déterministe vérifie les signatures, les hachages de chaîne et les règles de tampon automatique avant la release. |
| release | Le job de barrière de conformité bloque le déploiement en production ; les jobs de déploiement exigent un verdict d'autorisation. |
| configure | Les manifestes de déploiement Cloud Run sont générés à partir de variables d'environnement sans committer de secrets. |
| monitor | Les vérifications post-déploiement confirment que les digests des images de conteneur en cours d'exécution correspondent au commit approuvé dans le bundle. |
| govern | Un registre immuable chaîné par hachage alimente les paquets auditeur, les issues d'écart et le tableau de bord GitLab Pages. |
J'ai développé ShipProof avec Python 3.11 et Node.js 20.
python -m venv .venv && source .venv/bin/activate && pip install -r requirements.txt
Exécutez ma suite de tests et les vérifications de types :
OPA_BIN=/tmp/opa pytest -q && ruff check src tests demo-app scripts && mypy --strict src scripts
Collectez un bundle local pour n'importe quel commit :
PYTHONPATH=src python -m comply.collect --sha aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa --out /tmp/bundle.json
Le collecteur produit une seule ligne JSON sur stdout et écrit le bundle complet sur disque à côté de policy/inputs.json. Si des preuves sont manquantes, le bundle enregistre un statut de refus.
PYTHONPATH=src python -m comply.collect --sha <40-hex-sha> --out evidence/bundle.json \
--mr-iid 42 --pipeline-id 1001 --project group/project \
--pipeline-file pipeline.json --approvals-file approvals.json
Dans la CI, scripts/gate_bridge.py prépare pipeline.json, tandis que scripts/fetch_approvals.py récupère les données de revue depuis l'API GitLab. Les fichiers manquants sont enregistrés avec le statut manquant plutôt que considérés comme validés par défaut. Chaque journal stderr inclut l'ID de corrélation du bundle, et les secrets sont masqués par ***.
PYTHONPATH=src python -m comply.gate --bundle evidence/bundle.json --ledger logs/ledger.jsonl
Le code de sortie 0 indique un verdict d'autorisation. Le code de sortie 1 indique un refus avec une erreur structurée nommant le contrôle défaillant. Le code de sortie 2 indique des arguments invalides. Lorsque la barrière bloque dans la CI, le pipeline déclenche python -m comply.gap pour ouvrir un ticket de suivi.
PYTHONPATH=src python -m comply.packet --ledger logs/ledger.jsonl --release all \
--out packet.json --csv packet.csv --pdf packet.pdf
L'export CSV contient onze colonnes : bundle_id,commit_sha,mr_iid,pipeline_id,control,proof_type,status,artifact_sha,approver_ids,policy_sha,created_at. Le PDF est généré à partir de la même source JSON via du CSS d'impression.
AUDITOR_TOKEN=local-only PYTHONPATH=src uvicorn comply.api:app --port 8000
Interrogez les bundles à l'aide de l'authentification bearer :
curl -H "Authorization: Bearer local-only" "localhost:8000/api/v1/bundles?mr_iid=42"
L'API expose des points de terminaison pour les requêtes de bundles, les paquets de publication et les exports PDF en arrière-plan, protégés par des jetons bearer et une limite de débit de 60 requêtes par minute.
cd auditor && npm install && npm run build