Git Integration (GitHub / GitLab)
Nối repository GitHub hoặc GitLab vào một site LumiBase để theo dõi pull request
và CI, xem/lưu CI log, đăng ngược lại một status kiểm tra nội dung, reconcile các
content intent khai báo (GitOps), và chạy các môi trường preview tạm thời theo
từng PR (opt-in). Spec: .kiro/specs/git-integration/.
1. Mục tiêu & mô hình
- Theo tenant: một site nối một hoặc nhiều repo; mọi row đều có
site_id. - Không phụ thuộc provider: business logic phụ thuộc vào interface
GitProvider; các adapterGitHubProvider/GitLabProviderchỉ dùngfetch(REST), nên chúng chạy được trên cả Cloudflare Workers và Docker qua runtime chung. - Earned autonomy: một agent role
git-syncđược seed ở mức thận trọng L1 (PROPOSE) khi kết nối lần đầu; việc tạo goal vẫn chỉ dành cho planner.
2. Auth
- App install (
authMethod: 'app') — GitHub App / GitLab App; installation token được mint theo yêu cầu (GitHub App JWT là RS256 trên một key PKCS#8). - OAuth / PAT (
authMethod: 'pat') — người dùng dán một token, hoặc cấp phép qua luồng OAuth (GET /:id/oauth/authorizetrả về một URL; callback công khai được ràng vào mộtstatetrong cache dùng một lần).
3. Bảo mật token
- Access token và webhook secret được mã hoá at rest qua
CryptoService(AES-GCM), với AAD ràng vào{ siteId, integrationId, field }— một ciphertext không thể replay sang site khác hay field khác. Cần cóENCRYPTION_KEY. - Token không bao giờ được API trả về (chỉ có boolean
hasToken) và không bao giờ bị log (dùng fingerprintmaskToken).
4. Webhook & CI
- Receiver công khai
POST /api/v1/integrations/git/webhook/:provider/:siteId/:integrationId. GitHub được verify bằng HMAC-SHA256 (X-Hub-Signature-256), GitLab bằng shared token (X-Gitlab-Token), so sánh theo constant time. Request chưa verify nhận401 INVALID_SIGNATUREtrước khi có bất kỳ state nào bị chạm tới. Event được log idempotent theo(provider, delivery_id)và xử lý async vào cache PR/CI. Một CI run thất bại sẽ ghi mộtagent_incident+ auditgit_ci_failed. - CI log được lấy qua provider và cache trong blob storage của runtime, nên vẫn xem được sau khi provider đã hết hạn bản gốc.
5. GitOps
POST /:id/gitops/sync đọc lumibase/intents.json từ repo, upsert từng định
nghĩa vào content_intents (qua IntentService), rồi chạy một lượt quét drift +
reconcile để các item ngoài policy trở thành agent goal; provenance được ghi theo
từng intent. Việc apply schema (collection/field) qua HITL harness là bước tiếp
theo.
6. Môi trường preview (opt-in)
Khi sync_config.preview = true, một PR được mở sẽ provision một site tạm thời
dẫn xuất (${siteId}__pr-${number}), được seed bằng một bản copy các
collection/field/item/page của site gốc, phục vụ tại
/api/v1/deliver/page/${ephemeralSiteId}/…. Nó refresh khi có push và được dọn
sạch (cascade-delete) khi close/merge, kèm một lượt cleanup theo TTL.
7. Multi-tenancy
Dùng chung cho cả deployment (định danh/cấu hình của server, không phải dữ liệu tenant):
ENCRYPTION_KEY(KEK để mã hoá token), credential OAuth & AppGITHUB_*/GITLAB_*,LUMIBASE_PUBLIC_URL. Chúng định danh server/app, không phải một tenant, và không bao giờ mang dữ liệu tenant.
Cách ly theo tenant (site_id):
- Cả sáu bảng (
lumibase_git_integrations,_git_pull_requests,_git_ci_runs,_git_webhook_events,_git_preview_envs,_git_provenance) đều cósite_id; mọiGitIntegrationService/ query đều scopewhere(eq(table.siteId, siteId)); cả sáu đều được đăng ký cho RLSsite_isolationtrongpackages/database/migrations/rls-policies.sql. - Định tuyến webhook: receiver công khai nhúng
siteId+integrationIdvào URL và set biến session RLS thànhsiteIdđó trước khi đọc — nó chỉ có thể chạm tới row của đúng một site, và chữ ký bằng secret riêng theo từng integration là cửa xác thực. - Preview: id của site tạm thời được dẫn xuất từ
siteIdgốc (${siteId}__pr-${n}); nội dung preview nằm ở rowsitesriêng của nó, cách ly khỏi nội dung production của site gốc. Việc provision là một lần ghi system xuyên site có chủ đích (đọc site gốc dưới context RLS của site gốc, ghi site tạm thời dưới context của site tạm thời). - Crypto token: AAD ràng ciphertext vào
{ siteId, integrationId }, nên một row token được copy sang site khác sẽ không giải mã được.
Cách verify cách ly giữa hai site (staging, với Postgres):
- Nối repo R vào site A và (riêng biệt) vào site B.
GET /api/v1/integrations/gitvớiX-Lumi-Site: Achỉ trả về integration của A; không bao giờ của B. Tương tự với/pull-requests,/ci,/provenance.webhookUrlcủa từng integration nhúngsiteIdriêng của nó; hãy gửi một webhook đã ký tới URL của A và xác nhận chỉ cache PR/CI của A đổi.- Với
sync_config.preview, mở một PR trên A → site previewA__pr-Nđược tạo; xác nhận nó không nhìn thấy được dướiX-Lumi-Site: Bvà nội dung của nó không chạm tới item production của A.
Độ phủ tự động: crypto.test.ts chứng minh cách ly AAD xuyên site;
git-service-tenant.test.ts chứng minh việc map webhook URL / resource theo
site. Phần cách ly list/query giữa hai site có DB thật được verify trên staging
theo các bước ở trên (môi trường CI không có Postgres).
8. Ghi chú thiết lập
- Không có bước setup-wizard / seed / capability flag. Integration được tạo sau khi setup, tại Studio → Settings → Integrations → Git repositories.
- Migration
0009_git_integrationlà additive (CREATE TABLE IF NOT EXISTS, tiền tốlumibase_git_*theo ADR-010) — không backfill. Xem row git-integration trong Setup Impact Registry. - Role
git-syncđược seed lười; grant autonomy L1 của nó được seed ở lần kết nối repo đầu tiên (idempotent, không bao giờ ghi đè mức do operator đặt).