mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-11 12:29:26 +00:00
Addressed PR comments
This commit is contained in:
@@ -2504,9 +2504,9 @@ export const SecretSyncs = {
|
||||
projectName: "The name of the Supabase project to sync secrets to."
|
||||
},
|
||||
BITBUCKET: {
|
||||
workspace: "The Bitbucket Workspace slug to sync secrets to.",
|
||||
repository: "The Bitbucket Repository slug to sync secrets to.",
|
||||
environment: "The Bitbucket Deployment Environment uuid to sync secrets to."
|
||||
workspaceSlug: "The Bitbucket Workspace slug to sync secrets to.",
|
||||
repositorySlug: "The Bitbucket Repository slug to sync secrets to.",
|
||||
environmentId: "The Bitbucket Deployment Environment uuid to sync secrets to."
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -22,11 +22,15 @@ export const getBitbucketConnectionListItem = () => {
|
||||
};
|
||||
};
|
||||
|
||||
export const createAuthHeader = (email: string, apiToken: string): string => {
|
||||
return `Basic ${Buffer.from(`${email}:${apiToken}`).toString("base64")}`;
|
||||
};
|
||||
|
||||
export const getBitbucketUser = async ({ email, apiToken }: { email: string; apiToken: string }) => {
|
||||
try {
|
||||
const { data } = await request.get<{ username: string }>(`${IntegrationUrls.BITBUCKET_API_URL}/2.0/user`, {
|
||||
headers: {
|
||||
Authorization: `Basic ${Buffer.from(`${email}:${apiToken}`).toString("base64")}`,
|
||||
Authorization: createAuthHeader(email, apiToken),
|
||||
Accept: "application/json"
|
||||
}
|
||||
});
|
||||
@@ -58,7 +62,7 @@ export const listBitbucketWorkspaces = async (appConnection: TBitbucketConnectio
|
||||
const { email, apiToken } = appConnection.credentials;
|
||||
|
||||
const headers = {
|
||||
Authorization: `Basic ${Buffer.from(`${email}:${apiToken}`).toString("base64")}`,
|
||||
Authorization: createAuthHeader(email, apiToken),
|
||||
Accept: "application/json"
|
||||
};
|
||||
|
||||
@@ -90,7 +94,7 @@ export const listBitbucketRepositories = async (appConnection: TBitbucketConnect
|
||||
const { email, apiToken } = appConnection.credentials;
|
||||
|
||||
const headers = {
|
||||
Authorization: `Basic ${Buffer.from(`${email}:${apiToken}`).toString("base64")}`,
|
||||
Authorization: createAuthHeader(email, apiToken),
|
||||
Accept: "application/json"
|
||||
};
|
||||
|
||||
@@ -125,7 +129,7 @@ export const listBitbucketEnvironments = async (
|
||||
const { email, apiToken } = appConnection.credentials;
|
||||
|
||||
const headers = {
|
||||
Authorization: `Basic ${Buffer.from(`${email}:${apiToken}`).toString("base64")}`,
|
||||
Authorization: createAuthHeader(email, apiToken),
|
||||
Accept: "application/json"
|
||||
};
|
||||
|
||||
@@ -134,7 +138,9 @@ export const listBitbucketEnvironments = async (
|
||||
|
||||
let environmentsUrl = `${IntegrationUrls.BITBUCKET_API_URL}/2.0/repositories/${encodeURIComponent(workspaceSlug)}/${encodeURIComponent(repositorySlug)}/environments?pagelen=100`;
|
||||
|
||||
while (hasNextPage) {
|
||||
let iterationCount = 0;
|
||||
// Limit to 10 iterations, fetching at most 10 * 100 = 1000 environments
|
||||
while (hasNextPage && iterationCount < 100) {
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
const { data }: { data: { values: TBitbucketEnvironment[]; next: string } } = await request.get(environmentsUrl, {
|
||||
headers
|
||||
@@ -149,6 +155,7 @@ export const listBitbucketEnvironments = async (
|
||||
} else {
|
||||
hasNextPage = false;
|
||||
}
|
||||
iterationCount += 1;
|
||||
}
|
||||
|
||||
return environments;
|
||||
|
||||
@@ -6,5 +6,5 @@ export const BITBUCKET_SYNC_LIST_OPTION: TSecretSyncListItem = {
|
||||
name: "Bitbucket",
|
||||
destination: SecretSync.Bitbucket,
|
||||
connection: AppConnection.Bitbucket,
|
||||
canImportSecrets: true
|
||||
canImportSecrets: false
|
||||
};
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { request } from "@app/lib/config/request";
|
||||
import { createAuthHeader } from "@app/services/app-connection/bitbucket";
|
||||
import { IntegrationUrls } from "@app/services/integration-auth/integration-list";
|
||||
import {
|
||||
TBitbucketListVariables,
|
||||
@@ -11,29 +12,25 @@ import { SecretSyncError } from "@app/services/secret-sync/secret-sync-errors";
|
||||
import { matchesSchema } from "@app/services/secret-sync/secret-sync-fns";
|
||||
import { TSecretMap } from "@app/services/secret-sync/secret-sync-types";
|
||||
|
||||
const createAuthHeader = (email: string, apiToken: string): string => {
|
||||
return `Basic ${Buffer.from(`${email}:${apiToken}`).toString("base64")}`;
|
||||
};
|
||||
import { SECRET_SYNC_NAME_MAP } from "../secret-sync-maps";
|
||||
|
||||
const buildVariablesUrl = (workspace: string, repository: string, environment?: string, uuid?: string): string => {
|
||||
const baseUrl = `${IntegrationUrls.BITBUCKET_API_URL}/2.0/repositories/${encodeURIComponent(workspace)}/${encodeURIComponent(repository)}`;
|
||||
|
||||
if (environment) {
|
||||
return `${baseUrl}/deployments_config/environments/${environment}/variables${uuid ? `/${uuid}` : ""}`;
|
||||
return `${baseUrl}/deployments_config/environments/${environment}/variables/${uuid || ""}`;
|
||||
}
|
||||
|
||||
return `${baseUrl}/pipelines_config/variables/${uuid || ""}`;
|
||||
};
|
||||
|
||||
const listVariables = async ({
|
||||
email,
|
||||
apiToken,
|
||||
workspace,
|
||||
repository,
|
||||
environment
|
||||
}: TBitbucketListVariables & { environment?: string }): Promise<TBitbucketVariable[]> => {
|
||||
const url = buildVariablesUrl(workspace, repository, environment);
|
||||
const authHeader = createAuthHeader(email, apiToken);
|
||||
workspaceSlug,
|
||||
repositorySlug,
|
||||
environmentId,
|
||||
authHeader
|
||||
}: TBitbucketListVariables): Promise<TBitbucketVariable[]> => {
|
||||
const url = buildVariablesUrl(workspaceSlug, repositorySlug, environmentId);
|
||||
|
||||
const { data } = await request.get<{ values: TBitbucketVariable[] }>(url, {
|
||||
headers: {
|
||||
@@ -46,26 +43,23 @@ const listVariables = async ({
|
||||
};
|
||||
|
||||
const upsertVariable = async ({
|
||||
email,
|
||||
apiToken,
|
||||
workspace,
|
||||
repository,
|
||||
environment,
|
||||
workspaceSlug,
|
||||
repositorySlug,
|
||||
environmentId,
|
||||
key,
|
||||
value,
|
||||
existingVariables
|
||||
existingVariables,
|
||||
authHeader
|
||||
}: {
|
||||
email: string;
|
||||
apiToken: string;
|
||||
workspace: string;
|
||||
repository: string;
|
||||
environment?: string;
|
||||
workspaceSlug: string;
|
||||
repositorySlug: string;
|
||||
environmentId?: string;
|
||||
key: string;
|
||||
value: string;
|
||||
existingVariables: TBitbucketVariable[];
|
||||
authHeader: string;
|
||||
}) => {
|
||||
const existingVariable = existingVariables.find((variable) => variable.key === key);
|
||||
const authHeader = createAuthHeader(email, apiToken);
|
||||
const requestData = { key, value, secured: true };
|
||||
const headers = {
|
||||
Authorization: authHeader,
|
||||
@@ -73,40 +67,37 @@ const upsertVariable = async ({
|
||||
};
|
||||
|
||||
if (existingVariable) {
|
||||
const url = buildVariablesUrl(workspace, repository, environment, existingVariable.uuid);
|
||||
const url = buildVariablesUrl(workspaceSlug, repositorySlug, environmentId, existingVariable.uuid);
|
||||
return request.put(url, requestData, { headers });
|
||||
}
|
||||
|
||||
const url = buildVariablesUrl(workspace, repository, environment);
|
||||
const url = buildVariablesUrl(workspaceSlug, repositorySlug, environmentId);
|
||||
return request.post(url, requestData, { headers });
|
||||
};
|
||||
|
||||
const putVariables = async ({
|
||||
email,
|
||||
apiToken,
|
||||
workspace,
|
||||
repository,
|
||||
environment,
|
||||
secretMap
|
||||
}: TPutBitbucketVariable & { environment?: string; secretMap: TSecretMap }) => {
|
||||
workspaceSlug,
|
||||
repositorySlug,
|
||||
environmentId,
|
||||
secretMap,
|
||||
authHeader
|
||||
}: TPutBitbucketVariable & { secretMap: TSecretMap; authHeader: string }) => {
|
||||
const existingVariables = await listVariables({
|
||||
email,
|
||||
apiToken,
|
||||
workspace,
|
||||
repository,
|
||||
environment
|
||||
workspaceSlug,
|
||||
repositorySlug,
|
||||
environmentId,
|
||||
authHeader
|
||||
});
|
||||
|
||||
const promises = Object.entries(secretMap).map(([key, { value }]) =>
|
||||
upsertVariable({
|
||||
email,
|
||||
apiToken,
|
||||
workspace,
|
||||
repository,
|
||||
environment,
|
||||
workspaceSlug,
|
||||
repositorySlug,
|
||||
environmentId,
|
||||
key,
|
||||
value,
|
||||
existingVariables
|
||||
existingVariables,
|
||||
authHeader
|
||||
})
|
||||
);
|
||||
|
||||
@@ -114,26 +105,22 @@ const putVariables = async ({
|
||||
};
|
||||
|
||||
const deleteVariables = async ({
|
||||
email,
|
||||
apiToken,
|
||||
workspace,
|
||||
repository,
|
||||
environment,
|
||||
keys
|
||||
}: TDeleteBitbucketVariable & { environment?: string }) => {
|
||||
workspaceSlug,
|
||||
repositorySlug,
|
||||
environmentId,
|
||||
keys,
|
||||
authHeader
|
||||
}: TDeleteBitbucketVariable) => {
|
||||
const existingVariables = await listVariables({
|
||||
email,
|
||||
apiToken,
|
||||
workspace,
|
||||
repository,
|
||||
environment
|
||||
workspaceSlug,
|
||||
repositorySlug,
|
||||
environmentId,
|
||||
authHeader
|
||||
});
|
||||
|
||||
const variablesToDelete = existingVariables.filter((variable) => keys.includes(variable.key));
|
||||
|
||||
const authHeader = createAuthHeader(email, apiToken);
|
||||
const promises = variablesToDelete.map((variable) => {
|
||||
const url = buildVariablesUrl(workspace, repository, environment, variable.uuid);
|
||||
const url = buildVariablesUrl(workspaceSlug, repositorySlug, environmentId, variable.uuid);
|
||||
return request.delete(url, {
|
||||
headers: { Authorization: authHeader }
|
||||
});
|
||||
@@ -147,19 +134,19 @@ export const BitbucketSyncFns = {
|
||||
const {
|
||||
connection,
|
||||
environment,
|
||||
destinationConfig: { workspace, repository, environment: configEnvironment }
|
||||
destinationConfig: { workspaceSlug, repositorySlug, environmentId }
|
||||
} = secretSync;
|
||||
|
||||
const { email, apiToken } = connection.credentials;
|
||||
const authHeader = createAuthHeader(email, apiToken);
|
||||
|
||||
try {
|
||||
await putVariables({
|
||||
email,
|
||||
apiToken,
|
||||
workspace,
|
||||
repository,
|
||||
environment: configEnvironment,
|
||||
secretMap
|
||||
workspaceSlug,
|
||||
repositorySlug,
|
||||
environmentId,
|
||||
secretMap,
|
||||
authHeader
|
||||
});
|
||||
} catch (error) {
|
||||
throw new SecretSyncError({ error });
|
||||
@@ -169,11 +156,10 @@ export const BitbucketSyncFns = {
|
||||
|
||||
try {
|
||||
const existingVariables = await listVariables({
|
||||
email,
|
||||
apiToken,
|
||||
workspace,
|
||||
repository,
|
||||
environment: configEnvironment
|
||||
workspaceSlug,
|
||||
repositorySlug,
|
||||
environmentId,
|
||||
authHeader
|
||||
});
|
||||
|
||||
const keysToDelete = existingVariables
|
||||
@@ -185,12 +171,11 @@ export const BitbucketSyncFns = {
|
||||
|
||||
if (keysToDelete.length > 0) {
|
||||
await deleteVariables({
|
||||
email,
|
||||
apiToken,
|
||||
workspace,
|
||||
repository,
|
||||
environment: configEnvironment,
|
||||
keys: keysToDelete
|
||||
workspaceSlug,
|
||||
repositorySlug,
|
||||
environmentId,
|
||||
keys: keysToDelete,
|
||||
authHeader
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
@@ -201,30 +186,29 @@ export const BitbucketSyncFns = {
|
||||
removeSecrets: async (secretSync: TBitbucketSyncWithCredentials, secretMap: TSecretMap) => {
|
||||
const {
|
||||
connection,
|
||||
destinationConfig: { workspace, repository, environment: configEnvironment }
|
||||
destinationConfig: { workspaceSlug, repositorySlug, environmentId }
|
||||
} = secretSync;
|
||||
|
||||
const { email, apiToken } = connection.credentials;
|
||||
const authHeader = createAuthHeader(email, apiToken);
|
||||
|
||||
try {
|
||||
const existingVariables = await listVariables({
|
||||
email,
|
||||
apiToken,
|
||||
workspace,
|
||||
repository,
|
||||
environment: configEnvironment
|
||||
workspaceSlug,
|
||||
repositorySlug,
|
||||
environmentId,
|
||||
authHeader
|
||||
});
|
||||
|
||||
const keysToRemove = existingVariables.map((variable) => variable.key).filter((secret) => secret in secretMap);
|
||||
|
||||
if (keysToRemove.length > 0) {
|
||||
await deleteVariables({
|
||||
email,
|
||||
apiToken,
|
||||
workspace,
|
||||
repository,
|
||||
environment: configEnvironment,
|
||||
keys: keysToRemove
|
||||
workspaceSlug,
|
||||
repositorySlug,
|
||||
environmentId,
|
||||
keys: keysToRemove,
|
||||
authHeader
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
@@ -232,34 +216,7 @@ export const BitbucketSyncFns = {
|
||||
}
|
||||
},
|
||||
|
||||
getSecrets: async (secretSync: TBitbucketSyncWithCredentials) => {
|
||||
const {
|
||||
connection,
|
||||
destinationConfig: { workspace, repository, environment }
|
||||
} = secretSync;
|
||||
|
||||
const { email, apiToken } = connection.credentials;
|
||||
|
||||
try {
|
||||
const variables = await listVariables({
|
||||
email,
|
||||
apiToken,
|
||||
workspace,
|
||||
repository,
|
||||
environment
|
||||
});
|
||||
|
||||
const secretMap: TSecretMap = {};
|
||||
variables.forEach((variable) => {
|
||||
secretMap[variable.key] = {
|
||||
value: variable.secured ? "[SECURED]" : variable.value || "",
|
||||
comment: ""
|
||||
};
|
||||
});
|
||||
|
||||
return secretMap;
|
||||
} catch (error) {
|
||||
throw new SecretSyncError({ error });
|
||||
}
|
||||
getSecrets: async (secretSync: TBitbucketSyncWithCredentials): Promise<TSecretMap> => {
|
||||
throw new Error(`${SECRET_SYNC_NAME_MAP[secretSync.destination]} does not support importing secrets.`);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -11,12 +11,12 @@ import {
|
||||
import { TSyncOptionsConfig } from "@app/services/secret-sync/secret-sync-types";
|
||||
|
||||
const BitbucketSyncDestinationConfigSchema = z.object({
|
||||
repository: z.string().describe(SecretSyncs.DESTINATION_CONFIG.BITBUCKET.repository),
|
||||
environment: z.string().optional().describe(SecretSyncs.DESTINATION_CONFIG.BITBUCKET.environment),
|
||||
workspace: z.string().describe(SecretSyncs.DESTINATION_CONFIG.BITBUCKET.workspace)
|
||||
repositorySlug: z.string().describe(SecretSyncs.DESTINATION_CONFIG.BITBUCKET.repositorySlug),
|
||||
environmentId: z.string().optional().describe(SecretSyncs.DESTINATION_CONFIG.BITBUCKET.environmentId),
|
||||
workspaceSlug: z.string().describe(SecretSyncs.DESTINATION_CONFIG.BITBUCKET.workspaceSlug)
|
||||
});
|
||||
|
||||
const BitbucketSyncOptionsConfig: TSyncOptionsConfig = { canImportSecrets: true };
|
||||
const BitbucketSyncOptionsConfig: TSyncOptionsConfig = { canImportSecrets: false };
|
||||
|
||||
export const BitbucketSyncSchema = BaseSecretSyncSchema(SecretSync.Bitbucket, BitbucketSyncOptionsConfig).extend({
|
||||
destination: z.literal(SecretSync.Bitbucket),
|
||||
@@ -41,5 +41,5 @@ export const BitbucketSyncListItemSchema = z.object({
|
||||
name: z.literal("Bitbucket"),
|
||||
connection: z.literal(AppConnection.Bitbucket),
|
||||
destination: z.literal(SecretSync.Bitbucket),
|
||||
canImportSecrets: z.literal(true)
|
||||
canImportSecrets: z.literal(false)
|
||||
});
|
||||
|
||||
@@ -17,34 +17,34 @@ export type TBitbucketSyncWithCredentials = TBitbucketSync & {
|
||||
export type TBitbucketVariable = {
|
||||
key: string;
|
||||
value?: string;
|
||||
// Secure variables values are not returned by the API neither are they shown in Bitbucket UI
|
||||
secured: boolean;
|
||||
uuid: string;
|
||||
type: string;
|
||||
};
|
||||
|
||||
export type TBitbucketListVariables = {
|
||||
apiToken: string;
|
||||
email: string;
|
||||
workspace: string;
|
||||
repository: string;
|
||||
workspaceSlug: string;
|
||||
repositorySlug: string;
|
||||
environmentId?: string;
|
||||
authHeader: string;
|
||||
};
|
||||
|
||||
export type TPutBitbucketVariable = {
|
||||
email: string;
|
||||
apiToken: string;
|
||||
workspace: string;
|
||||
repository: string;
|
||||
authHeader: string;
|
||||
workspaceSlug: string;
|
||||
repositorySlug: string;
|
||||
environmentId?: string;
|
||||
};
|
||||
|
||||
export type TDeleteBitbucketVariable = {
|
||||
email: string;
|
||||
apiToken: string;
|
||||
workspace: string;
|
||||
repository: string;
|
||||
authHeader: string;
|
||||
workspaceSlug: string;
|
||||
repositorySlug: string;
|
||||
environmentId?: string;
|
||||
keys: string[];
|
||||
};
|
||||
|
||||
export type TBitbucketConnectionCredentials = {
|
||||
email: string;
|
||||
apiToken: string;
|
||||
authHeader: string;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user