
GitLab CIで自動収集されるSOC 2エビデンス:マージのたびに署名済みバンドルを生成し、OPAゲートが証跡不足のリリースをブロック、監査担当者はスクリーンショットの代わりに1つのリンクを受け取ります。
GitLab CI で自動的に収集される SOC 2 エビデンス:マージのたびに署名済みバンドルを生成し、Open Policy Agent ゲートが証明の欠けたリリースをブロックし、監査人はスクリーンショットの代わりに 1 つのパケットリンクを受け取ります。
監査人向けライブダッシュボード · GitLab プロジェクト · デモエビデンス · ロードマップ
ShipProof を開発したのは、エンタープライズ営業が情報セキュリティレビューで何度も停滞するからです。監査人が SOC 2 Type II の変更管理エビデンスを求めると、エンジニアは Jira、Slack、Drive をまたいでスクリーンショットを探すのに 2 週間を費やすことがよくあります。
私は証明をデプロイパイプラインの中に直接置きたいと考えました。ShipProof では、マージコミットごとに、テスト実行、Semgrep SAST スキャン、Gitleaks シークレット検出、Syft ソフトウェア部品表(SBOM)、CODEOWNERS 承認を網羅する正規の署名済みエビデンスバンドルが自動的に生成されます。
私の中心的な設計原則は厳格です。LLM は証明を要約したり、イシューの説明を起草したりすることはできますが、リリースを承認することは決してできません。リリースゲートは Rego で記述された Open Policy Agent の評価です。成果物が欠けている場合や、承認が形式的なものに見える場合、ゲートはフェイルクローズドで失敗し、リリースを停止し、修正手順を記載したイシューを作成します。ゲートが許可した場合、監査人は静的サイトまたは認証済み API への単一のリンクを受け取ります。
ShipProof を GitLab DevOps ライフサイクルに照らしてマッピングしました。9 つのステージすべてをネイティブに自動化しています:
| ステージ | パイプラインで自動化した内容 |
|---|---|
| plan | クローズドループのギャップワークアイテム管理。ゲートの拒否は再発回数付きの構造化された追跡イシューを自動起票し、その後の成功したパイプラインは修正コミット参照付きでイシューを自動解決・クローズします。 |
| create | コードレビューとソース管理。CODEOWNERS がポリシーファイルを保護し、ゲートは 5 分未満の形式的承認を拒否し、自動 MR ノートがレビューを導き、Duo フローが MR コメントを説明します。 |
| verify | pytest、Semgrep SAST、Gitleaks が verify ステージで実行され、成果物のハッシュを記録します。 |
| package | Syft が package ステージで CycloneDX SBOM を生成し、成果物をハッシュ化してバンドルに含めます。 |
| secure | 決定論的 OPA ゲートがリリース前に署名、チェーンハッシュ、形式的承認ルールをチェックします。 |
| release | コンプライアンスゲートジョブが本番環境へのデプロイをブロックし、デプロイジョブは許可判定を必要とします。 |
| configure | Cloud Run デプロイメントマニフェストは、シークレットをコミットすることなく環境変数からレンダリングされます。 |
| monitor | デプロイ後のチェックにより、実行中のコンテナイメージダイジェストがバンドルで承認されたコミットと一致することを検証します。 |
| govern | 不変のハッシュチェーン化された台帳が、監査人パケット、ギャップイシュー、GitLab Pages ダッシュボードにデータを供給します。 |
ShipProof は Python 3.11 と Node.js 20 で開発しました。
python -m venv .venv && source .venv/bin/activate && pip install -r requirements.txt
テストスイートと型チェックを実行します:
OPA_BIN=/tmp/opa pytest -q && ruff check src tests demo-app scripts && mypy --strict src scripts
任意のコミットに対してローカルバンドルを収集します:
PYTHONPATH=src python -m comply.collect --sha aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa --out /tmp/bundle.json
コレクターは単一の JSON 行を stdout に出力し、完全なバンドルを policy/inputs.json とともにディスクに書き込みます。証明が欠落している場合、バンドルには deny ステータスが記録されます。
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
CI では、scripts/gate_bridge.py が pipeline.json を準備し、scripts/fetch_approvals.py が GitLab API からレビューデータを取得します。ファイルが見つからない場合は、合格と見なすのではなく、missing ステータスとして記録されます。すべての stderr ログにはバンドルの相関 ID が含まれ、シークレットは *** としてマスクされます。
PYTHONPATH=src python -m comply.gate --bundle evidence/bundle.json --ledger logs/ledger.jsonl
終了コード 0 は許可の判定を示します。終了コード 1 は、失敗した制御を明示する構造化エラーを伴う拒否を示します。終了コード 2 は無効な引数を示します。CI でゲートがブロックすると、パイプラインは python -m comply.gap を起動して追跡 issue を作成します。
PYTHONPATH=src python -m comply.packet --ledger logs/ledger.jsonl --release all \
--out packet.json --csv packet.csv --pdf packet.pdf
CSV エクスポートには 11 個の列が含まれます: bundle_id,commit_sha,mr_iid,pipeline_id,control,proof_type,status,artifact_sha,approver_ids,policy_sha,created_at。PDF は同じ JSON ソースから印刷用 CSS を介してレンダリングされます。
AUDITOR_TOKEN=local-only PYTHONPATH=src uvicorn comply.api:app --port 8000
ベアラ認証を使用してバンドルをクエリします:
curl -H "Authorization: Bearer local-only" "localhost:8000/api/v1/bundles?mr_iid=42"
APIは、バンドルクエリ、リリースパケット、バックグラウンドPDFエクスポート用のエンドポイントを公開しており、ベアラートークンと1分あたり60リクエストのレート制限によって保護されています。
cd auditor && npm install && npm run build
インターフェースは React 19、TypeScript、Tailwind CSS で構築されています。ハッシュルーティングを使用した静的サイトとしてエクスポートされるため、サーバー側のリライトなしで GitLab Pages 上で直接実行できます。バックエンド API が存在しない場合は、public/fallback/demo-packets.json のサンプルデータを使用します。
flowchart LR
A["CI jobs (pytest, Semgrep, Gitleaks, Syft)"] --> B["gate_bridge.py (artifact summary)"]
B --> C["comply.collect (bundle.json + inputs.json)"]
C --> D["comply.sign (Cosign, HMAC fallback)"]
D --> E["ledger.jsonl (hash chain)"]
E --> F["comply.gate (OPA policy + signature + chain)"]
F -->|"deny"| G["comply.gap (gap issue + MR comment)"]
F -->|"allow"| H["deploy jobs (gated)"]
E --> I["comply.packet (JSON, CSV, PDF)"]
I --> J["GitLab Pages dashboard + read API"]
パイプラインはユニットテストとセキュリティスキャナーを実行し、出力を証拠コレクターにブリッジし、バンドルに署名し、台帳にレコードを追加します。ゲートジョブはバンドル、暗号署名、台帳チェーンに対して policy/soc2-v1.rego を評価します。拒否時はマージリクエストに通知し、GitLab ワークアイテムを起票します。評価が成功するとデプロイジョブのブロックが解除され、監査人パケットが公開されます。
| コントロール | 基準 | バンドルで収集される証拠 |
|---|---|---|
| CC8.1 変更管理 | 本番変更にはコードレビューと対象コミットでのパイプライン成功が必要。大規模な差分で5分未満のレビューは失敗とする。 | マージリクエスト IID、承認者 ID、レビュー所要時間、差分統計、パイプライン ID。 |
| CC7.2 システム監視 | 変更は不変で順序付けられたデプロイログを生成する。 | パイプラインジョブステータス、ハッシュチェーン化された台帳、CycloneDX SBOM ダイジェスト、コンテナタグ。 |
| CC6.1 論理アクセス | デプロイは承認された ID から発信され、環境の混在があってはならない。 | トリガー ID、シークレット検出ログ、環境変数名のスナップショット。 |
| CC6.3 ロールベースアクセス制御 | 権限のないロールは本番へ昇格できない。 | 署名者 ID、Cosign 証明書または署名の有効性、OPA ポリシー評価。 |
| CC7.1 監査連携 | ブロックされたリリースは追跡イシューにリンクする必要があり、解決済みイシューはマージリクエストにリンクする必要がある。 | イシュー IID、マージリクエスト IID、コメント間のバンドル ID 参照。 |
ローカル実行は .env から読み取ります。本番パイプラインはマスクされた GitLab CI 変数を使用します。
| 変数 | 必須 | 目的 |
|---|---|---|
GITLAB_TOKEN | CI では必須 | コレクターとギャップイシュー生成器が使用するプロジェクトアクセストークン。 |
AUDITOR_TOKEN | API 用 | comply.api エンドポイントに必要なベアラートークン。 |
VANTA_API_KEY | 任意 | バンドル同期用の API キー。省略時は正常にスキップされる。 |
GCP_SA_KEY | デプロイ時のみ | Google Cloud Run デプロイ用のサービスアカウントキー。 |
GCP_PROJECT_PREVIEW | デプロイ時のみ | プレビュー環境用の Google Cloud プロジェクト ID。 |
GCP_PROJECT_PROD | デプロイ時のみ | 本番デプロイ用の Google Cloud プロジェクト ID。 |
SHIPPROOF_SIGNING_KEY | Cosign なしの場合 | キーレス Cosign 署名が利用できない場合に使用される HMAC キー。 |
OPA_BIN | 任意 | OPA バイナリへのカスタムパス。CI はこれを自動的にダウンロードする。 |
CI_API_V4_URL | CI のみ | フェッチスクリプトが使用する GitLab API ルート URL。 |
src/comply/ Collector, gate, signing, ledger, gap reporter, packet builder, read API
policy/ soc2-v1.rego policy contract and evaluation fixtures
tests/ Contract, unit, and API tests
auditor/ Static React auditor interface
demo-app/ FastAPI sample application with container configuration
scripts/ CI bridges and offline seed demonstration scripts
templates/ Markdown templates for gate denial comments
.gitlab/ Duo agent flow definitions and issue templates
demo/ Evidence notes and verified demonstration links
evidence/ logs/ Local bundles and hash-chained ledger storage
ゲートが意図どおりに機能することを確認するため、2つのデモパスを構築して検証しました。
demo/good、MR !8):テスト、SAST、シークレットスキャン、SBOM生成を実行します。CODEOWNERSの承認を受け取ります。ゲートはプロモーションを許可し、監査人パケットを公開し、マージリクエストにコメントします。demo/missing-scan、MR !9):SASTスキャナーをスキップします。コレクターが欠落した成果物をフラグし、OPAがCC8.1でリリースを拒否し、パイプラインが停止し、comply.gapが是正手順とともにissue #3を作成します。