( owner: Owner, token: string, instanceUrl: string = 'https://gitlab.com' )
| 832 | credential_version: credentialVersion, |
| 833 | last_validated_at: validatedAt, |
| 834 | }); |
| 835 | }); |
| 836 | } |
| 837 | |
| 838 | /** |
| 839 | * Removes the stored Project Access Token for a project |
| 840 | * Called when a project is removed from code reviews |
| 841 | */ |
| 842 | export async function removeStoredProjectAccessToken( |
| 843 | integration: PlatformIntegration, |
| 844 | projectId: string | number, |
| 845 | actor: GitLabCredentialActor |
| 846 | ): Promise<void> { |
| 847 | const metadata = integration.metadata as GitLabIntegrationMetadata | null; |
| 848 | const projectIdStr = requireGitLabProjectId(projectId); |
| 849 | const storedCredential = await getStoredProjectCredential(integration.id, projectIdStr); |
| 850 | if (!storedCredential) return; |
| 851 | const instanceUrl = normalizeInstanceUrl(metadata?.gitlab_instance_url); |
| 852 | |
| 853 | // Try to revoke the token in GitLab |
| 854 | try { |
| 855 | const userToken = await getValidGitLabToken(integration, actor); |
| 856 | await revokeProjectAccessToken(userToken, projectId, storedCredential.tokenId, instanceUrl); |
| 857 | logExceptInTest('[removeStoredProjectAccessToken] Token revoked in GitLab', { |
| 858 | projectId, |
| 859 | tokenId: storedCredential.tokenId, |
| 860 | }); |
| 861 | } catch (error) { |
| 862 | // Log but don't fail - the token might already be revoked |
| 863 | logExceptInTest('[removeStoredProjectAccessToken] Failed to revoke token in GitLab', { |
| 864 | projectId, |
| 865 | tokenId: storedCredential.tokenId, |
| 866 | error: error instanceof Error ? error.message : String(error), |
| 867 | }); |
| 868 | } |
| 869 | |
| 870 | await db.transaction(async tx => { |
| 871 | await mutateGitLabMetadataInTransaction(tx, integration.id, currentMetadata => { |
| 872 | const projectTokens = copyMetadataObject(currentMetadata, 'project_tokens'); |
| 873 | delete projectTokens[projectIdStr]; |
| 874 | return { set: { project_tokens: projectTokens } }; |
| 875 | }); |
| 876 | const deleted = await tx |
| 877 | .delete(platform_access_token_credentials) |
| 878 | .where( |
| 879 | and( |
| 880 | eq(platform_access_token_credentials.id, storedCredential.credentialId), |
| 881 | eq( |
| 882 | platform_access_token_credentials.credential_version, |
| 883 | storedCredential.credentialVersion |
| 884 | ) |
| 885 | ) |
| 886 | ) |
| 887 | .returning({ id: platform_access_token_credentials.id }); |
| 888 | if (deleted.length !== 1) { |
| 889 | throw new Error('GitLab project access token was replaced concurrently'); |
| 890 | } |
| 891 | }); |
nothing calls this directly
no test coverage detected