mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-10 19:28:51 +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."
|
projectName: "The name of the Supabase project to sync secrets to."
|
||||||
},
|
},
|
||||||
BITBUCKET: {
|
BITBUCKET: {
|
||||||
workspace: "The Bitbucket Workspace slug to sync secrets to.",
|
workspaceSlug: "The Bitbucket Workspace slug to sync secrets to.",
|
||||||
repository: "The Bitbucket Repository slug to sync secrets to.",
|
repositorySlug: "The Bitbucket Repository slug to sync secrets to.",
|
||||||
environment: "The Bitbucket Deployment Environment uuid 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 }) => {
|
export const getBitbucketUser = async ({ email, apiToken }: { email: string; apiToken: string }) => {
|
||||||
try {
|
try {
|
||||||
const { data } = await request.get<{ username: string }>(`${IntegrationUrls.BITBUCKET_API_URL}/2.0/user`, {
|
const { data } = await request.get<{ username: string }>(`${IntegrationUrls.BITBUCKET_API_URL}/2.0/user`, {
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Basic ${Buffer.from(`${email}:${apiToken}`).toString("base64")}`,
|
Authorization: createAuthHeader(email, apiToken),
|
||||||
Accept: "application/json"
|
Accept: "application/json"
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -58,7 +62,7 @@ export const listBitbucketWorkspaces = async (appConnection: TBitbucketConnectio
|
|||||||
const { email, apiToken } = appConnection.credentials;
|
const { email, apiToken } = appConnection.credentials;
|
||||||
|
|
||||||
const headers = {
|
const headers = {
|
||||||
Authorization: `Basic ${Buffer.from(`${email}:${apiToken}`).toString("base64")}`,
|
Authorization: createAuthHeader(email, apiToken),
|
||||||
Accept: "application/json"
|
Accept: "application/json"
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -90,7 +94,7 @@ export const listBitbucketRepositories = async (appConnection: TBitbucketConnect
|
|||||||
const { email, apiToken } = appConnection.credentials;
|
const { email, apiToken } = appConnection.credentials;
|
||||||
|
|
||||||
const headers = {
|
const headers = {
|
||||||
Authorization: `Basic ${Buffer.from(`${email}:${apiToken}`).toString("base64")}`,
|
Authorization: createAuthHeader(email, apiToken),
|
||||||
Accept: "application/json"
|
Accept: "application/json"
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -125,7 +129,7 @@ export const listBitbucketEnvironments = async (
|
|||||||
const { email, apiToken } = appConnection.credentials;
|
const { email, apiToken } = appConnection.credentials;
|
||||||
|
|
||||||
const headers = {
|
const headers = {
|
||||||
Authorization: `Basic ${Buffer.from(`${email}:${apiToken}`).toString("base64")}`,
|
Authorization: createAuthHeader(email, apiToken),
|
||||||
Accept: "application/json"
|
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`;
|
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
|
// eslint-disable-next-line no-await-in-loop
|
||||||
const { data }: { data: { values: TBitbucketEnvironment[]; next: string } } = await request.get(environmentsUrl, {
|
const { data }: { data: { values: TBitbucketEnvironment[]; next: string } } = await request.get(environmentsUrl, {
|
||||||
headers
|
headers
|
||||||
@@ -149,6 +155,7 @@ export const listBitbucketEnvironments = async (
|
|||||||
} else {
|
} else {
|
||||||
hasNextPage = false;
|
hasNextPage = false;
|
||||||
}
|
}
|
||||||
|
iterationCount += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return environments;
|
return environments;
|
||||||
|
|||||||
@@ -6,5 +6,5 @@ export const BITBUCKET_SYNC_LIST_OPTION: TSecretSyncListItem = {
|
|||||||
name: "Bitbucket",
|
name: "Bitbucket",
|
||||||
destination: SecretSync.Bitbucket,
|
destination: SecretSync.Bitbucket,
|
||||||
connection: AppConnection.Bitbucket,
|
connection: AppConnection.Bitbucket,
|
||||||
canImportSecrets: true
|
canImportSecrets: false
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { request } from "@app/lib/config/request";
|
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 { IntegrationUrls } from "@app/services/integration-auth/integration-list";
|
||||||
import {
|
import {
|
||||||
TBitbucketListVariables,
|
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 { matchesSchema } from "@app/services/secret-sync/secret-sync-fns";
|
||||||
import { TSecretMap } from "@app/services/secret-sync/secret-sync-types";
|
import { TSecretMap } from "@app/services/secret-sync/secret-sync-types";
|
||||||
|
|
||||||
const createAuthHeader = (email: string, apiToken: string): string => {
|
import { SECRET_SYNC_NAME_MAP } from "../secret-sync-maps";
|
||||||
return `Basic ${Buffer.from(`${email}:${apiToken}`).toString("base64")}`;
|
|
||||||
};
|
|
||||||
|
|
||||||
const buildVariablesUrl = (workspace: string, repository: string, environment?: string, uuid?: string): string => {
|
const buildVariablesUrl = (workspace: string, repository: string, environment?: string, uuid?: string): string => {
|
||||||
const baseUrl = `${IntegrationUrls.BITBUCKET_API_URL}/2.0/repositories/${encodeURIComponent(workspace)}/${encodeURIComponent(repository)}`;
|
const baseUrl = `${IntegrationUrls.BITBUCKET_API_URL}/2.0/repositories/${encodeURIComponent(workspace)}/${encodeURIComponent(repository)}`;
|
||||||
|
|
||||||
if (environment) {
|
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 || ""}`;
|
return `${baseUrl}/pipelines_config/variables/${uuid || ""}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
const listVariables = async ({
|
const listVariables = async ({
|
||||||
email,
|
workspaceSlug,
|
||||||
apiToken,
|
repositorySlug,
|
||||||
workspace,
|
environmentId,
|
||||||
repository,
|
authHeader
|
||||||
environment
|
}: TBitbucketListVariables): Promise<TBitbucketVariable[]> => {
|
||||||
}: TBitbucketListVariables & { environment?: string }): Promise<TBitbucketVariable[]> => {
|
const url = buildVariablesUrl(workspaceSlug, repositorySlug, environmentId);
|
||||||
const url = buildVariablesUrl(workspace, repository, environment);
|
|
||||||
const authHeader = createAuthHeader(email, apiToken);
|
|
||||||
|
|
||||||
const { data } = await request.get<{ values: TBitbucketVariable[] }>(url, {
|
const { data } = await request.get<{ values: TBitbucketVariable[] }>(url, {
|
||||||
headers: {
|
headers: {
|
||||||
@@ -46,26 +43,23 @@ const listVariables = async ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const upsertVariable = async ({
|
const upsertVariable = async ({
|
||||||
email,
|
workspaceSlug,
|
||||||
apiToken,
|
repositorySlug,
|
||||||
workspace,
|
environmentId,
|
||||||
repository,
|
|
||||||
environment,
|
|
||||||
key,
|
key,
|
||||||
value,
|
value,
|
||||||
existingVariables
|
existingVariables,
|
||||||
|
authHeader
|
||||||
}: {
|
}: {
|
||||||
email: string;
|
workspaceSlug: string;
|
||||||
apiToken: string;
|
repositorySlug: string;
|
||||||
workspace: string;
|
environmentId?: string;
|
||||||
repository: string;
|
|
||||||
environment?: string;
|
|
||||||
key: string;
|
key: string;
|
||||||
value: string;
|
value: string;
|
||||||
existingVariables: TBitbucketVariable[];
|
existingVariables: TBitbucketVariable[];
|
||||||
|
authHeader: string;
|
||||||
}) => {
|
}) => {
|
||||||
const existingVariable = existingVariables.find((variable) => variable.key === key);
|
const existingVariable = existingVariables.find((variable) => variable.key === key);
|
||||||
const authHeader = createAuthHeader(email, apiToken);
|
|
||||||
const requestData = { key, value, secured: true };
|
const requestData = { key, value, secured: true };
|
||||||
const headers = {
|
const headers = {
|
||||||
Authorization: authHeader,
|
Authorization: authHeader,
|
||||||
@@ -73,40 +67,37 @@ const upsertVariable = async ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (existingVariable) {
|
if (existingVariable) {
|
||||||
const url = buildVariablesUrl(workspace, repository, environment, existingVariable.uuid);
|
const url = buildVariablesUrl(workspaceSlug, repositorySlug, environmentId, existingVariable.uuid);
|
||||||
return request.put(url, requestData, { headers });
|
return request.put(url, requestData, { headers });
|
||||||
}
|
}
|
||||||
|
|
||||||
const url = buildVariablesUrl(workspace, repository, environment);
|
const url = buildVariablesUrl(workspaceSlug, repositorySlug, environmentId);
|
||||||
return request.post(url, requestData, { headers });
|
return request.post(url, requestData, { headers });
|
||||||
};
|
};
|
||||||
|
|
||||||
const putVariables = async ({
|
const putVariables = async ({
|
||||||
email,
|
workspaceSlug,
|
||||||
apiToken,
|
repositorySlug,
|
||||||
workspace,
|
environmentId,
|
||||||
repository,
|
secretMap,
|
||||||
environment,
|
authHeader
|
||||||
secretMap
|
}: TPutBitbucketVariable & { secretMap: TSecretMap; authHeader: string }) => {
|
||||||
}: TPutBitbucketVariable & { environment?: string; secretMap: TSecretMap }) => {
|
|
||||||
const existingVariables = await listVariables({
|
const existingVariables = await listVariables({
|
||||||
email,
|
workspaceSlug,
|
||||||
apiToken,
|
repositorySlug,
|
||||||
workspace,
|
environmentId,
|
||||||
repository,
|
authHeader
|
||||||
environment
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const promises = Object.entries(secretMap).map(([key, { value }]) =>
|
const promises = Object.entries(secretMap).map(([key, { value }]) =>
|
||||||
upsertVariable({
|
upsertVariable({
|
||||||
email,
|
workspaceSlug,
|
||||||
apiToken,
|
repositorySlug,
|
||||||
workspace,
|
environmentId,
|
||||||
repository,
|
|
||||||
environment,
|
|
||||||
key,
|
key,
|
||||||
value,
|
value,
|
||||||
existingVariables
|
existingVariables,
|
||||||
|
authHeader
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -114,26 +105,22 @@ const putVariables = async ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const deleteVariables = async ({
|
const deleteVariables = async ({
|
||||||
email,
|
workspaceSlug,
|
||||||
apiToken,
|
repositorySlug,
|
||||||
workspace,
|
environmentId,
|
||||||
repository,
|
keys,
|
||||||
environment,
|
authHeader
|
||||||
keys
|
}: TDeleteBitbucketVariable) => {
|
||||||
}: TDeleteBitbucketVariable & { environment?: string }) => {
|
|
||||||
const existingVariables = await listVariables({
|
const existingVariables = await listVariables({
|
||||||
email,
|
workspaceSlug,
|
||||||
apiToken,
|
repositorySlug,
|
||||||
workspace,
|
environmentId,
|
||||||
repository,
|
authHeader
|
||||||
environment
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const variablesToDelete = existingVariables.filter((variable) => keys.includes(variable.key));
|
const variablesToDelete = existingVariables.filter((variable) => keys.includes(variable.key));
|
||||||
|
|
||||||
const authHeader = createAuthHeader(email, apiToken);
|
|
||||||
const promises = variablesToDelete.map((variable) => {
|
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, {
|
return request.delete(url, {
|
||||||
headers: { Authorization: authHeader }
|
headers: { Authorization: authHeader }
|
||||||
});
|
});
|
||||||
@@ -147,19 +134,19 @@ export const BitbucketSyncFns = {
|
|||||||
const {
|
const {
|
||||||
connection,
|
connection,
|
||||||
environment,
|
environment,
|
||||||
destinationConfig: { workspace, repository, environment: configEnvironment }
|
destinationConfig: { workspaceSlug, repositorySlug, environmentId }
|
||||||
} = secretSync;
|
} = secretSync;
|
||||||
|
|
||||||
const { email, apiToken } = connection.credentials;
|
const { email, apiToken } = connection.credentials;
|
||||||
|
const authHeader = createAuthHeader(email, apiToken);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await putVariables({
|
await putVariables({
|
||||||
email,
|
workspaceSlug,
|
||||||
apiToken,
|
repositorySlug,
|
||||||
workspace,
|
environmentId,
|
||||||
repository,
|
secretMap,
|
||||||
environment: configEnvironment,
|
authHeader
|
||||||
secretMap
|
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new SecretSyncError({ error });
|
throw new SecretSyncError({ error });
|
||||||
@@ -169,11 +156,10 @@ export const BitbucketSyncFns = {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const existingVariables = await listVariables({
|
const existingVariables = await listVariables({
|
||||||
email,
|
workspaceSlug,
|
||||||
apiToken,
|
repositorySlug,
|
||||||
workspace,
|
environmentId,
|
||||||
repository,
|
authHeader
|
||||||
environment: configEnvironment
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const keysToDelete = existingVariables
|
const keysToDelete = existingVariables
|
||||||
@@ -185,12 +171,11 @@ export const BitbucketSyncFns = {
|
|||||||
|
|
||||||
if (keysToDelete.length > 0) {
|
if (keysToDelete.length > 0) {
|
||||||
await deleteVariables({
|
await deleteVariables({
|
||||||
email,
|
workspaceSlug,
|
||||||
apiToken,
|
repositorySlug,
|
||||||
workspace,
|
environmentId,
|
||||||
repository,
|
keys: keysToDelete,
|
||||||
environment: configEnvironment,
|
authHeader
|
||||||
keys: keysToDelete
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -201,30 +186,29 @@ export const BitbucketSyncFns = {
|
|||||||
removeSecrets: async (secretSync: TBitbucketSyncWithCredentials, secretMap: TSecretMap) => {
|
removeSecrets: async (secretSync: TBitbucketSyncWithCredentials, secretMap: TSecretMap) => {
|
||||||
const {
|
const {
|
||||||
connection,
|
connection,
|
||||||
destinationConfig: { workspace, repository, environment: configEnvironment }
|
destinationConfig: { workspaceSlug, repositorySlug, environmentId }
|
||||||
} = secretSync;
|
} = secretSync;
|
||||||
|
|
||||||
const { email, apiToken } = connection.credentials;
|
const { email, apiToken } = connection.credentials;
|
||||||
|
const authHeader = createAuthHeader(email, apiToken);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const existingVariables = await listVariables({
|
const existingVariables = await listVariables({
|
||||||
email,
|
workspaceSlug,
|
||||||
apiToken,
|
repositorySlug,
|
||||||
workspace,
|
environmentId,
|
||||||
repository,
|
authHeader
|
||||||
environment: configEnvironment
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const keysToRemove = existingVariables.map((variable) => variable.key).filter((secret) => secret in secretMap);
|
const keysToRemove = existingVariables.map((variable) => variable.key).filter((secret) => secret in secretMap);
|
||||||
|
|
||||||
if (keysToRemove.length > 0) {
|
if (keysToRemove.length > 0) {
|
||||||
await deleteVariables({
|
await deleteVariables({
|
||||||
email,
|
workspaceSlug,
|
||||||
apiToken,
|
repositorySlug,
|
||||||
workspace,
|
environmentId,
|
||||||
repository,
|
keys: keysToRemove,
|
||||||
environment: configEnvironment,
|
authHeader
|
||||||
keys: keysToRemove
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -232,34 +216,7 @@ export const BitbucketSyncFns = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
getSecrets: async (secretSync: TBitbucketSyncWithCredentials) => {
|
getSecrets: async (secretSync: TBitbucketSyncWithCredentials): Promise<TSecretMap> => {
|
||||||
const {
|
throw new Error(`${SECRET_SYNC_NAME_MAP[secretSync.destination]} does not support importing secrets.`);
|
||||||
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 });
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -11,12 +11,12 @@ import {
|
|||||||
import { TSyncOptionsConfig } from "@app/services/secret-sync/secret-sync-types";
|
import { TSyncOptionsConfig } from "@app/services/secret-sync/secret-sync-types";
|
||||||
|
|
||||||
const BitbucketSyncDestinationConfigSchema = z.object({
|
const BitbucketSyncDestinationConfigSchema = z.object({
|
||||||
repository: z.string().describe(SecretSyncs.DESTINATION_CONFIG.BITBUCKET.repository),
|
repositorySlug: z.string().describe(SecretSyncs.DESTINATION_CONFIG.BITBUCKET.repositorySlug),
|
||||||
environment: z.string().optional().describe(SecretSyncs.DESTINATION_CONFIG.BITBUCKET.environment),
|
environmentId: z.string().optional().describe(SecretSyncs.DESTINATION_CONFIG.BITBUCKET.environmentId),
|
||||||
workspace: z.string().describe(SecretSyncs.DESTINATION_CONFIG.BITBUCKET.workspace)
|
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({
|
export const BitbucketSyncSchema = BaseSecretSyncSchema(SecretSync.Bitbucket, BitbucketSyncOptionsConfig).extend({
|
||||||
destination: z.literal(SecretSync.Bitbucket),
|
destination: z.literal(SecretSync.Bitbucket),
|
||||||
@@ -41,5 +41,5 @@ export const BitbucketSyncListItemSchema = z.object({
|
|||||||
name: z.literal("Bitbucket"),
|
name: z.literal("Bitbucket"),
|
||||||
connection: z.literal(AppConnection.Bitbucket),
|
connection: z.literal(AppConnection.Bitbucket),
|
||||||
destination: z.literal(SecretSync.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 = {
|
export type TBitbucketVariable = {
|
||||||
key: string;
|
key: string;
|
||||||
value?: string;
|
value?: string;
|
||||||
|
// Secure variables values are not returned by the API neither are they shown in Bitbucket UI
|
||||||
secured: boolean;
|
secured: boolean;
|
||||||
uuid: string;
|
uuid: string;
|
||||||
type: string;
|
type: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TBitbucketListVariables = {
|
export type TBitbucketListVariables = {
|
||||||
apiToken: string;
|
workspaceSlug: string;
|
||||||
email: string;
|
repositorySlug: string;
|
||||||
workspace: string;
|
environmentId?: string;
|
||||||
repository: string;
|
authHeader: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TPutBitbucketVariable = {
|
export type TPutBitbucketVariable = {
|
||||||
email: string;
|
authHeader: string;
|
||||||
apiToken: string;
|
workspaceSlug: string;
|
||||||
workspace: string;
|
repositorySlug: string;
|
||||||
repository: string;
|
environmentId?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TDeleteBitbucketVariable = {
|
export type TDeleteBitbucketVariable = {
|
||||||
email: string;
|
authHeader: string;
|
||||||
apiToken: string;
|
workspaceSlug: string;
|
||||||
workspace: string;
|
repositorySlug: string;
|
||||||
repository: string;
|
environmentId?: string;
|
||||||
keys: string[];
|
keys: string[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TBitbucketConnectionCredentials = {
|
export type TBitbucketConnectionCredentials = {
|
||||||
email: string;
|
authHeader: string;
|
||||||
apiToken: string;
|
|
||||||
};
|
};
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 577 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 580 KiB After Width: | Height: | Size: 598 KiB |
@@ -50,13 +50,15 @@ Infisical supports the use of [API Tokens](https://support.atlassian.com/bitbuck
|
|||||||
<Tab title="Secret Sync">
|
<Tab title="Secret Sync">
|
||||||
```
|
```
|
||||||
read:workspace:bitbucket
|
read:workspace:bitbucket
|
||||||
|
admin:workspace:bitbucket
|
||||||
read:user:bitbucket
|
read:user:bitbucket
|
||||||
read:repository:bitbucket
|
read:repository:bitbucket
|
||||||
read:pipeline:bitbucket
|
read:pipeline:bitbucket
|
||||||
write:pipeline:bitbucket
|
write:pipeline:bitbucket
|
||||||
admin:workspace:bitbucket
|
|
||||||
admin:pipeline:bitbucket
|
admin:pipeline:bitbucket
|
||||||
```
|
```
|
||||||
|
|
||||||
|

|
||||||
</Tab>
|
</Tab>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
|
|
||||||
|
|||||||
@@ -46,8 +46,9 @@ description: "Learn how to configure a Bitbucket Sync for Infisical."
|
|||||||
|
|
||||||
- **Initial Sync Behavior**: Determines how Infisical should resolve the initial sync.
|
- **Initial Sync Behavior**: Determines how Infisical should resolve the initial sync.
|
||||||
- **Overwrite Destination Secrets**: Removes any secrets at the destination endpoint not present in Infisical.
|
- **Overwrite Destination Secrets**: Removes any secrets at the destination endpoint not present in Infisical.
|
||||||
- **Import Secrets (Prioritize Infisical)**: Imports secrets from the destination endpoint before syncing, prioritizing values from Infisical over Bitbucket when keys conflict.
|
<Note>
|
||||||
- **Import Secrets (Prioritize Bitbucket)**: Imports secrets from the destination endpoint before syncing, prioritizing values from Bitbucket over Infisical when keys conflict.
|
Bitbucket does not support importing secrets.
|
||||||
|
</Note>
|
||||||
- **Key Schema**: Template that determines how secret names are transformed when syncing, using `{{secretKey}}` as a placeholder for the original secret name and `{{environment}}` for the environment.
|
- **Key Schema**: Template that determines how secret names are transformed when syncing, using `{{secretKey}}` as a placeholder for the original secret name and `{{environment}}` for the environment.
|
||||||
<Note>
|
<Note>
|
||||||
We highly recommend using a Key Schema to ensure that Infisical only manages the specific keys you intend, keeping everything else untouched.
|
We highly recommend using a Key Schema to ensure that Infisical only manages the specific keys you intend, keeping everything else untouched.
|
||||||
@@ -96,8 +97,8 @@ description: "Learn how to configure a Bitbucket Sync for Infisical."
|
|||||||
"initialSyncBehavior": "overwrite-destination"
|
"initialSyncBehavior": "overwrite-destination"
|
||||||
},
|
},
|
||||||
"destinationConfig": {
|
"destinationConfig": {
|
||||||
"workspace": "my-bitbucket-workspace",
|
"workspaceSlug": "my-bitbucket-workspace",
|
||||||
"repository": "my-bitbucket-repository"
|
"repositorySlug": "my-bitbucket-repository"
|
||||||
}
|
}
|
||||||
}'
|
}'
|
||||||
```
|
```
|
||||||
@@ -148,8 +149,8 @@ description: "Learn how to configure a Bitbucket Sync for Infisical."
|
|||||||
},
|
},
|
||||||
"destination": "bitbucket",
|
"destination": "bitbucket",
|
||||||
"destinationConfig": {
|
"destinationConfig": {
|
||||||
"workspace": "my-bitbucket-workspace",
|
"workspaceSlug": "my-bitbucket-workspace",
|
||||||
"repository": "my-bitbucket-repository"
|
"repositorySlug": "my-bitbucket-repository"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+13
-12
@@ -21,8 +21,8 @@ export const BitbucketSyncFields = () => {
|
|||||||
>();
|
>();
|
||||||
|
|
||||||
const connectionId = useWatch({ name: "connection.id", control });
|
const connectionId = useWatch({ name: "connection.id", control });
|
||||||
const workspace = useWatch({ name: "destinationConfig.workspace", control });
|
const workspace = useWatch({ name: "destinationConfig.workspaceSlug", control });
|
||||||
const repository = useWatch({ name: "destinationConfig.repository", control });
|
const repository = useWatch({ name: "destinationConfig.repositorySlug", control });
|
||||||
|
|
||||||
const { data: workspaces = [], isPending: isWorkspacesLoading } =
|
const { data: workspaces = [], isPending: isWorkspacesLoading } =
|
||||||
useBitbucketConnectionListWorkspaces(connectionId, {
|
useBitbucketConnectionListWorkspaces(connectionId, {
|
||||||
@@ -43,14 +43,14 @@ export const BitbucketSyncFields = () => {
|
|||||||
<>
|
<>
|
||||||
<SecretSyncConnectionField
|
<SecretSyncConnectionField
|
||||||
onChange={() => {
|
onChange={() => {
|
||||||
setValue("destinationConfig.workspace", "");
|
setValue("destinationConfig.workspaceSlug", "");
|
||||||
setValue("destinationConfig.repository", "");
|
setValue("destinationConfig.repositorySlug", "");
|
||||||
setValue("destinationConfig.environment", "");
|
setValue("destinationConfig.environmentId", "");
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Controller
|
<Controller
|
||||||
name="destinationConfig.workspace"
|
name="destinationConfig.workspaceSlug"
|
||||||
control={control}
|
control={control}
|
||||||
render={({ field: { value, onChange }, fieldState: { error } }) => (
|
render={({ field: { value, onChange }, fieldState: { error } }) => (
|
||||||
<FormControl
|
<FormControl
|
||||||
@@ -67,8 +67,8 @@ export const BitbucketSyncFields = () => {
|
|||||||
const v = option as SingleValue<TBitbucketWorkspace>;
|
const v = option as SingleValue<TBitbucketWorkspace>;
|
||||||
onChange(v?.slug ?? "");
|
onChange(v?.slug ?? "");
|
||||||
// Clear downstream selections
|
// Clear downstream selections
|
||||||
setValue("destinationConfig.repository", "");
|
setValue("destinationConfig.repositorySlug", "");
|
||||||
setValue("destinationConfig.environment", "");
|
setValue("destinationConfig.environmentId", "");
|
||||||
}}
|
}}
|
||||||
options={workspaces}
|
options={workspaces}
|
||||||
placeholder="Select workspace..."
|
placeholder="Select workspace..."
|
||||||
@@ -80,7 +80,7 @@ export const BitbucketSyncFields = () => {
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<Controller
|
<Controller
|
||||||
name="destinationConfig.repository"
|
name="destinationConfig.repositorySlug"
|
||||||
control={control}
|
control={control}
|
||||||
render={({ field: { value, onChange }, fieldState: { error } }) => (
|
render={({ field: { value, onChange }, fieldState: { error } }) => (
|
||||||
<FormControl
|
<FormControl
|
||||||
@@ -97,7 +97,7 @@ export const BitbucketSyncFields = () => {
|
|||||||
const v = option as SingleValue<TBitbucketRepo>;
|
const v = option as SingleValue<TBitbucketRepo>;
|
||||||
onChange(v?.slug ?? "");
|
onChange(v?.slug ?? "");
|
||||||
// Clear downstream selections
|
// Clear downstream selections
|
||||||
setValue("destinationConfig.environment", "");
|
setValue("destinationConfig.environmentId", "");
|
||||||
}}
|
}}
|
||||||
options={repositories}
|
options={repositories}
|
||||||
placeholder="Select repository..."
|
placeholder="Select repository..."
|
||||||
@@ -109,13 +109,14 @@ export const BitbucketSyncFields = () => {
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<Controller
|
<Controller
|
||||||
name="destinationConfig.environment"
|
name="destinationConfig.environmentId"
|
||||||
control={control}
|
control={control}
|
||||||
render={({ field: { value, onChange }, fieldState: { error } }) => (
|
render={({ field: { value, onChange }, fieldState: { error } }) => (
|
||||||
<FormControl
|
<FormControl
|
||||||
isError={Boolean(error)}
|
isError={Boolean(error)}
|
||||||
errorText={error?.message}
|
errorText={error?.message}
|
||||||
label="Bitbucket Deployment Environment (optional)"
|
isOptional
|
||||||
|
label="Bitbucket Deployment Environment"
|
||||||
tooltipClassName="max-w-md"
|
tooltipClassName="max-w-md"
|
||||||
>
|
>
|
||||||
<FilterableSelect
|
<FilterableSelect
|
||||||
|
|||||||
+3
-3
@@ -6,9 +6,9 @@ import { SecretSync } from "@app/hooks/api/secretSyncs";
|
|||||||
|
|
||||||
export const BitbucketSyncReviewFields = () => {
|
export const BitbucketSyncReviewFields = () => {
|
||||||
const { watch } = useFormContext<TSecretSyncForm & { destination: SecretSync.Bitbucket }>();
|
const { watch } = useFormContext<TSecretSyncForm & { destination: SecretSync.Bitbucket }>();
|
||||||
const repository = watch("destinationConfig.repository");
|
const repository = watch("destinationConfig.repositorySlug");
|
||||||
const environment = watch("destinationConfig.environment");
|
const environment = watch("destinationConfig.environmentId");
|
||||||
const workspace = watch("destinationConfig.workspace");
|
const workspace = watch("destinationConfig.workspaceSlug");
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|||||||
+7
-3
@@ -7,9 +7,13 @@ export const BitbucketSyncDestinationSchema = BaseSecretSyncSchema().merge(
|
|||||||
z.object({
|
z.object({
|
||||||
destination: z.literal(SecretSync.Bitbucket),
|
destination: z.literal(SecretSync.Bitbucket),
|
||||||
destinationConfig: z.object({
|
destinationConfig: z.object({
|
||||||
repository: z.string().trim().min(1, "Repository slug required").describe("Repository slug"),
|
repositorySlug: z
|
||||||
environment: z.string().trim().optional().describe("Deployment environment uuid"),
|
.string()
|
||||||
workspace: z.string().trim().min(1, "Workspace slug required").describe("Workspace slug")
|
.trim()
|
||||||
|
.min(1, "Repository slug required")
|
||||||
|
.describe("Repository slug"),
|
||||||
|
environmentId: z.string().trim().optional().describe("Deployment environment uuid"),
|
||||||
|
workspaceSlug: z.string().trim().min(1, "Workspace slug required").describe("Workspace slug")
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -5,9 +5,9 @@ import { TRootSecretSync } from "@app/hooks/api/secretSyncs/types/root-sync";
|
|||||||
export type TBitbucketSync = TRootSecretSync & {
|
export type TBitbucketSync = TRootSecretSync & {
|
||||||
destination: SecretSync.Bitbucket;
|
destination: SecretSync.Bitbucket;
|
||||||
destinationConfig: {
|
destinationConfig: {
|
||||||
workspace: string;
|
workspaceSlug: string;
|
||||||
repository: string;
|
repositorySlug: string;
|
||||||
environment?: string;
|
environmentId?: string;
|
||||||
};
|
};
|
||||||
connection: {
|
connection: {
|
||||||
app: AppConnection.Bitbucket;
|
app: AppConnection.Bitbucket;
|
||||||
|
|||||||
+2
-2
@@ -175,8 +175,8 @@ export const getSecretSyncDestinationColValues = (secretSync: TSecretSync) => {
|
|||||||
secondaryText = "Supabase Project";
|
secondaryText = "Supabase Project";
|
||||||
break;
|
break;
|
||||||
case SecretSync.Bitbucket:
|
case SecretSync.Bitbucket:
|
||||||
primaryText = destinationConfig.workspace;
|
primaryText = destinationConfig.workspaceSlug;
|
||||||
secondaryText = destinationConfig.repository;
|
secondaryText = destinationConfig.repositorySlug;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new Error(`Unhandled Destination Col Values ${destination}`);
|
throw new Error(`Unhandled Destination Col Values ${destination}`);
|
||||||
|
|||||||
+5
-5
@@ -7,15 +7,15 @@ type Props = {
|
|||||||
|
|
||||||
export const BitbucketSyncDestinationSection = ({ secretSync }: Props) => {
|
export const BitbucketSyncDestinationSection = ({ secretSync }: Props) => {
|
||||||
const {
|
const {
|
||||||
destinationConfig: { workspace, repository, environment }
|
destinationConfig: { workspaceSlug, repositorySlug, environmentId }
|
||||||
} = secretSync;
|
} = secretSync;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<GenericFieldLabel label="Workspace">{workspace}</GenericFieldLabel>
|
<GenericFieldLabel label="Workspace">{workspaceSlug}</GenericFieldLabel>
|
||||||
<GenericFieldLabel label="Repository">{repository}</GenericFieldLabel>
|
<GenericFieldLabel label="Repository">{repositorySlug}</GenericFieldLabel>
|
||||||
{environment && (
|
{environmentId && (
|
||||||
<GenericFieldLabel label="Deployment Environment">{environment}</GenericFieldLabel>
|
<GenericFieldLabel label="Deployment Environment">{environmentId}</GenericFieldLabel>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user