Skip to content

feat(gitlab): encrypt GitLab integration credentials at rest#4539

Open
eshurakov wants to merge 4 commits into
mainfrom
woolly-peridot
Open

feat(gitlab): encrypt GitLab integration credentials at rest#4539
eshurakov wants to merge 4 commits into
mainfrom
woolly-peridot

Conversation

@eshurakov

Copy link
Copy Markdown
Contributor

Summary

Migrates plaintext GitLab OAuth, personal access, and project access tokens out of platform_integrations metadata into the existing encrypted platform_oauth_credentials / platform_access_token_credentials tables already used by Bitbucket. Private-key decryption and OAuth refresh are centralized in git-token-service, exposed to server-side web consumers through a minimal internal broker so the web app never handles raw key material.

Key pieces:

  • Schema (migration 0183): Generalizes both credential tables for GitLab — nullable owner/scope/verified fields, provider_metadata JSONB, provider_base_url, oauth_client_secret_encrypted, resource-scoped partial unique indexes, and credential_version > 0 checks. No GitLab-specific table is added.
  • @kilocode/worker-utils: New gitlab-credential module with GitLab-specific envelope schemes, versions, and AAD builders reusing the Bitbucket RSA/envelope helpers; new broker/audit internal-service token audiences.
  • git-token-service: New credential broker, audit, crypto, store, service, OAuth refresher, and HTTP handlers for encrypted GitLab credential read/refresh/audit.
  • Web: New credential broker client, encryption helpers, metadata mutation, OAuth integration writer, and a three-mode (audit / backfill / scrub) migration runner with a scripts/db entrypoint. The GitLab service, adapter, OAuth callback, and downstream callers (code reviews, cloud agent, gastown git-credentials) are updated to source tokens through the broker.
  • Docs: ENVIRONMENT.md documents the shared BITBUCKET_OAUTH_CREDENTIAL_* key vars now used by both providers.

The migration is staged: encrypted write paths are in place and a backfill migrates existing plaintext rows; legacy plaintext fallback is preserved until a scrub pass confirms all credentials are encrypted.

Verification

No manual testing performed — this is a backend credential-storage change with no user-facing surface. Confidence comes from automated coverage:

  • @kilocode/db schema-consistency tests
  • @kilocode/worker-utils (245 tests)
  • git-token-service (474 tests)
  • Affected apps/web suites: gitlab-service, gitlab platform adapter/broker/encryption/migration/metadata, bitbucket cache, cloud-agent helpers, user soft-delete, code-review-status, code-reviews & organization routers (916 tests)
  • pnpm typecheck --changes-only, pnpm lint, pnpm format:check clean

Visual Changes

N/A

Reviewer Notes

  • Migration safety: The scrub mode requires a passing private-key audit assertion before removing any plaintext fields; review the credential-migration audit/backfill/scrub gating in apps/web/src/lib/integrations/platforms/gitlab/.
  • Schema nullable widening: Several NOT NULL columns were dropped to accommodate GitLab PAT/project tokens that lack OAuth-style fields; confirm no existing Bitbucket write path relies on the old constraints.
  • Key reuse: The same BITBUCKET_OAUTH_CREDENTIAL_* RSA keypair now encrypts GitLab credentials — verify key provisioning matches the documented shared-key model.
  • PII: softDeleteUser was updated for the new credential rows; see apps/web/src/lib/user/index.ts.

Comment thread packages/worker-utils/src/gitlab-credential.ts
@kilo-code-bot

kilo-code-bot Bot commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Code Review Summary

Status: No Issues Found | Recommendation: Merge

Executive Summary

Incremental review since the last pass: the migration now stages the previously-flagged destructive DROP COLUMN statements out for a follow-up PR (renamed 0186_glorious_aaron_stack.sql to 0186_milky_amazoness.sql, dropped columns re-added to schema.ts as nullable/optional, and gitlab-credential.ts/bitbucket-workspace-access-token.ts row schemas updated to tolerate the retained platform/owned_by_organization_id/integration_type columns), resolving the prior destructive-drop WARNING; no new issues found. The non-concurrent index WARNING on line 14 of the migration remains open and unchanged.

Files Reviewed (7 files)
  • packages/db/src/migrations/0186_milky_amazoness.sql (renamed from 0186_glorious_aaron_stack.sql)
  • packages/db/src/migrations/meta/0186_snapshot.json
  • packages/db/src/migrations/meta/_journal.json
  • packages/db/src/schema.ts
  • packages/worker-utils/src/bitbucket-workspace-access-token.ts
  • packages/worker-utils/src/gitlab-credential.ts (+ test)
Previous Review Summaries (5 snapshots, latest commit 613ad3e)

Current summary above is authoritative. Previous snapshots are kept for context only.

Previous review (commit 613ad3e)

Status: No Issues Found | Recommendation: Merge

Executive Summary

Incremental review since the last pass: the only change is removal of a stale platform field from mock credential objects in three git-token-service test files, consistent with the identity-column removal already merged; no new issues found.

Files Reviewed (3 files)
  • services/git-token-service/src/bitbucket-authorization-service.test.ts
  • services/git-token-service/src/gitlab-credential-service.test.ts
  • services/git-token-service/src/gitlab-oauth-credential-refresher.test.ts

Previous review (commit 4d3a7de)

Status: No Issues Found | Recommendation: Merge

Executive Summary

Incremental review since the last pass: the only change is a test-only fixture cleanup removing a stale owned_by_organization_id field from platform_access_token_credentials inserts in apps/web/src/lib/user/index.test.ts, consistent with the identity-column removal already merged; no new issues found.

Files Reviewed (1 file)
  • apps/web/src/lib/user/index.test.ts

Previous review (commit a8ba27f)

Status: 2 Issues Found | Recommendation: Address before merge

Executive Summary

History was rewritten since the last review (the PR is now a single squashed commit), so this is a fresh full review; the highest-risk new finding is non-concurrent index creation on the live platform_access_token_credentials table in the new migration.

Overview

Severity Count
CRITICAL 0
WARNING 2
SUGGESTION 0
Issue Details (click to expand)

WARNING

File Line Issue
packages/db/src/migrations/0186_glorious_aaron_stack.sql 14 Non-concurrent CREATE UNIQUE INDEX/CREATE INDEX on the live platform_access_token_credentials table blocks writes during the build
packages/db/src/migrations/0186_glorious_aaron_stack.sql 17 Destructive DROP COLUMN statements on live Bitbucket-serving tables in the same migration as the new columns, with rolling-deploy timing risk

Previously Flagged, Re-Verified (not new, not re-reported)

  • packages/worker-utils/src/gitlab-credential.ts:166 — OAuth AAD credentialVersion gap: confirmed fixed. buildGitLabOAuthCredentialAad now binds credentialVersion, and every encrypt/decrypt/refresh call site consistently threads the persisted/next row version.
  • apps/web/src/lib/integrations/platforms/gitlab/credential-migration-audit.ts:71 — Org-owner authorizer check: confirmed consistent with the author's prior justification. Org ownership is independently audited via owned_by_user_id/owned_by_organization_id (credential-migration.ts), not via authorized_by_user_id, so the no-op-like authorizerMatchesOwner behavior for org rows does not weaken the scrub-mode safety gate as originally feared.
Files Reviewed (89 files)
  • ENVIRONMENT.md
  • apps/web/src/app/api/gastown/git-credentials/route.ts
  • apps/web/src/app/api/internal/code-review-status/[reviewId]/route.ts (+ test)
  • apps/web/src/lib/bot/tools/spawn-cloud-agent-session.ts
  • apps/web/src/lib/cloud-agent/gitlab-integration-helpers.ts (+ test)
  • apps/web/src/lib/code-reviews/manual-code-review-jobs.ts
  • apps/web/src/lib/code-reviews/triggers/prepare-review-payload.ts
  • apps/web/src/lib/gastown/git-credentials.ts
  • apps/web/src/lib/integrations/gitlab-service.ts (+ credentials test)
  • apps/web/src/lib/integrations/oauth/platforms/gitlab-callback.ts
  • apps/web/src/lib/integrations/platforms/bitbucket/credentials.ts (+ test)
  • apps/web/src/lib/integrations/platforms/bitbucket/oauth-integration.ts
  • apps/web/src/lib/integrations/platforms/bitbucket/repository-cache.ts (+ test)
  • apps/web/src/lib/integrations/platforms/bitbucket/workspace-access-token-credentials.test.ts
  • apps/web/src/lib/integrations/platforms/bitbucket/workspace-access-token-repository-cache.ts
  • apps/web/src/lib/integrations/platforms/gitlab/adapter.ts (+ test)
  • apps/web/src/lib/integrations/platforms/gitlab/credential-broker-client.ts (+ test)
  • apps/web/src/lib/integrations/platforms/gitlab/credential-encryption.ts (+ test)
  • apps/web/src/lib/integrations/platforms/gitlab/credential-migration.ts (+ test)
  • apps/web/src/lib/integrations/platforms/gitlab/credential-migration-audit.ts
  • apps/web/src/lib/integrations/platforms/gitlab/credential-migration-backfill.ts
  • apps/web/src/lib/integrations/platforms/gitlab/credential-migration-legacy.ts
  • apps/web/src/lib/integrations/platforms/gitlab/metadata-mutation.ts (+ test)
  • apps/web/src/lib/integrations/platforms/gitlab/oauth-integration-writer.ts (+ test)
  • apps/web/src/lib/integrations/platforms/gitlab/webhook-handlers/merge-request-handler.ts
  • apps/web/src/lib/user/index.ts (+ test)
  • apps/web/src/routers/bitbucket-router.test.ts
  • apps/web/src/routers/gitlab-router.ts
  • apps/web/src/routers/code-reviews-router.ts
  • apps/web/src/routers/code-reviews/code-reviews-router.ts
  • apps/web/src/routers/organizations/organization-bitbucket-router.test.ts
  • apps/web/src/routers/organizations/organization-cloud-agent-next-router.ts (+ test)
  • apps/web/src/routers/organizations/organization-code-reviews-router.ts
  • apps/web/src/scripts/db/gitlab-credential-migration.ts
  • packages/db/src/migrations/0186_glorious_aaron_stack.sql - 2 issues
  • packages/db/src/migrations/meta/0186_snapshot.json
  • packages/db/src/migrations/meta/_journal.json
  • packages/db/src/schema.ts
  • packages/db/src/schema.test.ts
  • packages/worker-utils/package.json
  • packages/worker-utils/src/bitbucket-workspace-access-token.ts (+ test)
  • packages/worker-utils/src/gitlab-credential.ts (+ test)
  • packages/worker-utils/src/index.ts
  • packages/worker-utils/src/internal-service-token-audiences.ts (+ test)
  • services/git-token-service/.dev.vars.example
  • services/git-token-service/worker-configuration.d.ts
  • services/git-token-service/src/bitbucket-authorization-service.ts (+ test)
  • services/git-token-service/src/bitbucket-workspace-access-token-authorization-service.ts (+ test)
  • services/git-token-service/src/gitlab-credential-audit.ts (+ test)
  • services/git-token-service/src/gitlab-credential-audit-handler.ts (+ test)
  • services/git-token-service/src/gitlab-credential-broker.ts (+ test)
  • services/git-token-service/src/gitlab-credential-broker-handler.ts (+ test)
  • services/git-token-service/src/gitlab-credential-crypto.ts (+ test)
  • services/git-token-service/src/gitlab-credential-service.ts (+ test)
  • services/git-token-service/src/gitlab-credential-store.ts
  • services/git-token-service/src/gitlab-oauth-credential-refresher.ts (+ test)
  • services/git-token-service/src/gitlab-runtime-token-resolver.ts (+ test)
  • services/git-token-service/src/gitlab-session-capability.ts (+ test)
  • services/git-token-service/src/gitlab-token-service.ts (+ test)
  • services/git-token-service/src/index.ts (+ test)

Fix these issues in Kilo Cloud

Previous review (commit 51de2ee)

Status: No Issues Found | Recommendation: Merge

Executive Summary

This incremental review covers commit 49c7dbf..51de2ee1; the previously flagged OAuth AAD credentialVersion gap is now correctly threaded through every encrypt/decrypt/refresh boundary, and no new issues were found in the changed code.

Files Reviewed (12 files)
  • apps/web/src/lib/integrations/platforms/gitlab/credential-encryption.test.ts
  • apps/web/src/lib/integrations/platforms/gitlab/credential-migration-backfill.ts (+ test)
  • apps/web/src/lib/integrations/platforms/gitlab/credential-migration.test.ts
  • apps/web/src/lib/integrations/platforms/gitlab/oauth-integration-writer.ts (+ test)
  • packages/worker-utils/src/gitlab-credential.ts (+ test)
  • services/git-token-service/src/gitlab-credential-audit.ts (+ test)
  • services/git-token-service/src/gitlab-credential-service.ts (+ test)
  • services/git-token-service/src/gitlab-oauth-credential-refresher.ts

Previous review (commit 49c7dbf)

Status: 2 Issues Found | Recommendation: Address before merge

Executive Summary

The highest-risk finding is a weakened audit safety check in credential-migration-audit.ts that could let an org-owned GitLab OAuth credential with an unrelated authorizer pass the pre-scrub verification gate.

Overview

Severity Count
CRITICAL 0
WARNING 2
SUGGESTION 0
Issue Details (click to expand)

WARNING

File Line Issue
packages/worker-utils/src/gitlab-credential.ts 170 OAuth credential AAD omits credentialVersion, unlike the PAT/project-access-token AAD builder, leaving a version-rollback/replay gap.
apps/web/src/lib/integrations/platforms/gitlab/credential-migration-audit.ts 74 Org-owner authorizer check (`authorizedByUserId === null
Files Reviewed (85 files)
  • ENVIRONMENT.md
  • apps/web/src/app/api/gastown/git-credentials/route.ts
  • apps/web/src/app/api/internal/code-review-status/[reviewId]/route.ts (+ test)
  • apps/web/src/lib/bot/tools/spawn-cloud-agent-session.ts
  • apps/web/src/lib/cloud-agent/gitlab-integration-helpers.ts (+ test)
  • apps/web/src/lib/code-reviews/manual-code-review-jobs.ts
  • apps/web/src/lib/code-reviews/triggers/prepare-review-payload.ts
  • apps/web/src/lib/gastown/git-credentials.ts
  • apps/web/src/lib/integrations/gitlab-service.ts (+ test)
  • apps/web/src/lib/integrations/oauth/platforms/gitlab-callback.ts
  • apps/web/src/lib/integrations/platforms/bitbucket/repository-cache.ts (+ test)
  • apps/web/src/lib/integrations/platforms/bitbucket/workspace-access-token-credentials.test.ts
  • apps/web/src/lib/integrations/platforms/bitbucket/workspace-access-token-repository-cache.ts
  • apps/web/src/lib/integrations/platforms/gitlab/adapter.ts (+ test) - 0 issues
  • apps/web/src/lib/integrations/platforms/gitlab/credential-broker-client.ts (+ test) - 0 issues
  • apps/web/src/lib/integrations/platforms/gitlab/credential-encryption.ts (+ test) - 0 issues
  • apps/web/src/lib/integrations/platforms/gitlab/credential-migration-audit.ts - 1 issue
  • apps/web/src/lib/integrations/platforms/gitlab/credential-migration-backfill.ts - 0 issues
  • apps/web/src/lib/integrations/platforms/gitlab/credential-migration-legacy.ts - 0 issues
  • apps/web/src/lib/integrations/platforms/gitlab/credential-migration.ts (+ test) - 0 issues
  • apps/web/src/lib/integrations/platforms/gitlab/metadata-mutation.ts (+ test) - 0 issues
  • apps/web/src/lib/integrations/platforms/gitlab/oauth-integration-writer.ts (+ test) - 0 issues
  • apps/web/src/lib/integrations/platforms/gitlab/webhook-handlers/merge-request-handler.ts - 0 issues
  • apps/web/src/lib/user/index.ts (+ test)
  • apps/web/src/routers/code-reviews-router.ts
  • apps/web/src/routers/code-reviews/code-reviews-router.ts
  • apps/web/src/routers/gitlab-router.ts
  • apps/web/src/routers/organizations/organization-cloud-agent-next-router.ts (+ test)
  • apps/web/src/routers/organizations/organization-code-reviews-router.ts
  • apps/web/src/scripts/db/gitlab-credential-migration.ts
  • packages/db/src/migrations/0185_flashy_multiple_man.sql
  • packages/db/src/migrations/meta/0185_snapshot.json
  • packages/db/src/migrations/meta/_journal.json
  • packages/db/src/schema.ts (+ test)
  • packages/worker-utils/package.json
  • packages/worker-utils/src/bitbucket-workspace-access-token.ts (+ test)
  • packages/worker-utils/src/gitlab-credential.ts (+ test) - 1 issue
  • packages/worker-utils/src/index.ts
  • packages/worker-utils/src/internal-service-token-audiences.ts (+ test)
  • services/git-token-service/.dev.vars.example
  • services/git-token-service/src/bitbucket-authorization-service.ts (+ test)
  • services/git-token-service/src/bitbucket-workspace-access-token-authorization-service.ts (+ test)
  • services/git-token-service/src/gitlab-credential-audit-handler.ts (+ test)
  • services/git-token-service/src/gitlab-credential-audit.ts (+ test)
  • services/git-token-service/src/gitlab-credential-broker-handler.ts (+ test)
  • services/git-token-service/src/gitlab-credential-broker.ts (+ test)
  • services/git-token-service/src/gitlab-credential-crypto.ts (+ test)
  • services/git-token-service/src/gitlab-credential-service.ts (+ test)
  • services/git-token-service/src/gitlab-credential-store.ts
  • services/git-token-service/src/gitlab-oauth-credential-refresher.ts (+ test)
  • services/git-token-service/src/gitlab-runtime-token-resolver.ts (+ test)
  • services/git-token-service/src/gitlab-session-capability.ts (+ test)
  • services/git-token-service/src/gitlab-token-service.ts (+ test)
  • services/git-token-service/src/index.ts (+ test)
  • services/git-token-service/worker-configuration.d.ts

Fix these issues in Kilo Cloud


Reviewed by claude-sonnet-5 · Input: 18 · Output: 4.9K · Cached: 416.5K

Review guidance: REVIEW.md from base branch main

… harden token handling

Squashes branch work onto the credential-encryption prerequisite:
- feat(gitlab): encrypt GitLab integration credentials at rest
- fix(gitlab): bind credential version into OAuth credential AAD
- fix(bitbucket): normalize lastValidatedAt to ISO in workspace access token status

The platform_access_token_credentials and platform_oauth_credentials tables
duplicated platform and integration_type identity already owned by the parent
platform_integrations row. These redundant columns are dropped entirely and
credential identity is derived from the platform_integration_id foreign key.
Authorization queries in git-token-service now join platform_integrations to
enforce ownership rather than trusting the credential's own columns.

Stop persisting or filtering on the dropped columns, join platform_integrations
where platform membership is required, remove the now-tautological credential
profile-mismatch audit checks, and drop the columns from the GitLab and Bitbucket
credential row Zod schemas and their test fixtures.
Comment thread packages/db/src/migrations/0186_milky_amazoness.sql
Comment thread packages/db/src/migrations/0186_glorious_aaron_stack.sql Outdated
Migration 0186 drops owned_by_organization_id from
platform_access_token_credentials (ownership now flows via
platform_integration_id), but the GitLab PAT authorizer cleanup test
still inserted it, failing the CI typecheck. Remove the stale refs.
…mocks

Migration 0186 drops the platform column from platform_oauth_credentials
(Bitbucket and GitLab). The new strict BitbucketOAuthCredentialRowSchema
and GitLabOAuthCredentialRowSchema reject the extra key, so the services
returned reconnect_required instead of available. Remove the stale field
from credential-row mocks only (integration/parent rows keep platform).
Migration 0186 dropped owned_by_organization_id, platform, and
integration_type from platform_access_token_credentials and platform from
platform_oauth_credentials in the same deploy as the code that stopped
using them. origin/main still queries platform_oauth_credentials.platform
in live Bitbucket authorization paths (Worker + web), so a rolling
deploy risks crashing in-flight requests while the migration runs.

Keep the columns nullable in the schema (matching the 0185 state already
on origin/main) and regenerate 0186 so it only contains additive changes
(new columns, indexes, checks, FK) plus DROP NOT NULL widenings. Stop
using platform_oauth_credentials.platform everywhere in application code;
the column stays in the DB unused until a follow-up PR drops it.

Add the deprecated columns as nullable optional fields to the strict Zod
credential row schemas so full-table selects that include these columns
do not fail runtime validation before the drop.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants