mirror of
https://github.com/Infisical/infisical.git
synced 2025-08-24 20:43:19 +00:00
Compare commits
24 Commits
general-oi
...
sso-empty-
Author | SHA1 | Date | |
---|---|---|---|
|
ef70de1e0b | ||
|
7e9ee7b5e3 | ||
|
3306a9ca69 | ||
|
e9af34a6ba | ||
|
3de8ed169f | ||
|
d1eb350bdd | ||
|
0c1ccf7c2e | ||
|
b55a39dd24 | ||
|
7b880f85cc | ||
|
c7dc595e1a | ||
|
6e494f198b | ||
|
e1f3eaf1a0 | ||
|
1e11702c58 | ||
|
3b81cdb16e | ||
|
6584166815 | ||
|
827cb35194 | ||
|
89a6a0ba13 | ||
|
3f74d3a80d | ||
|
4a44dc6119 | ||
|
dd4bc4bc73 | ||
|
b0c4fddf86 | ||
|
cccd4ba9e5 | ||
|
63f0f8e299 | ||
|
bae62421ae |
@@ -714,13 +714,15 @@ export const oidcConfigServiceFactory = ({
|
||||
}
|
||||
}
|
||||
|
||||
const groups = typeof claims.groups === "string" ? [claims.groups] : (claims.groups as string[] | undefined);
|
||||
|
||||
oidcLogin({
|
||||
email: claims.email,
|
||||
externalId: claims.sub,
|
||||
firstName: claims.given_name ?? "",
|
||||
lastName: claims.family_name ?? "",
|
||||
orgId: org.id,
|
||||
groups: claims.groups as string[] | undefined,
|
||||
groups,
|
||||
callbackPort,
|
||||
manageGroupMemberships: oidcCfg.manageGroupMemberships
|
||||
})
|
||||
|
@@ -2144,6 +2144,7 @@ export const SecretSyncs = {
|
||||
const destinationName = SECRET_SYNC_NAME_MAP[destination];
|
||||
return {
|
||||
initialSyncBehavior: `Specify how Infisical should resolve the initial sync to the ${destinationName} destination.`,
|
||||
keySchema: `Specify the format to use for structuring secret keys in the ${destinationName} destination.`,
|
||||
disableSecretDeletion: `Enable this flag to prevent removal of secrets from the ${destinationName} destination when syncing.`
|
||||
};
|
||||
},
|
||||
|
@@ -511,7 +511,7 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
|
||||
})
|
||||
}
|
||||
},
|
||||
onRequest: verifyAuth([AuthMode.JWT]),
|
||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||
handler: async (req) => {
|
||||
const workspace = await server.services.project.updateAuditLogsRetention({
|
||||
actorId: req.permission.id,
|
||||
|
@@ -17,7 +17,6 @@ import { request } from "@app/lib/config/request";
|
||||
import { BadRequestError, NotFoundError, PermissionBoundaryError, UnauthorizedError } from "@app/lib/errors";
|
||||
import { extractIPDetails, isValidIpOrCidr } from "@app/lib/ip";
|
||||
import { logger } from "@app/lib/logger";
|
||||
import { blockLocalAndPrivateIpAddresses } from "@app/lib/validator";
|
||||
|
||||
import { ActorType, AuthTokenType } from "../auth/auth-type";
|
||||
import { TIdentityOrgDALFactory } from "../identity/identity-org-dal";
|
||||
@@ -59,9 +58,7 @@ export const identityOciAuthServiceFactory = ({
|
||||
|
||||
const identityMembershipOrg = await identityOrgMembershipDAL.findOne({ identityId: identityOciAuth.identityId });
|
||||
|
||||
await blockLocalAndPrivateIpAddresses(headers.host);
|
||||
|
||||
// Validate OCI host format
|
||||
// Validate OCI host format. Ensures that the host is in "identity.<region>.oraclecloud.com" format.
|
||||
if (!headers.host || !new RE2("^identity\\.([a-z]{2}-[a-z]+-[1-9])\\.oraclecloud\\.com$").test(headers.host)) {
|
||||
throw new BadRequestError({
|
||||
message: "Invalid OCI host format. Expected format: identity.<region>.oraclecloud.com"
|
||||
|
@@ -2,6 +2,7 @@ import AWS, { AWSError } from "aws-sdk";
|
||||
|
||||
import { getAwsConnectionConfig } from "@app/services/app-connection/aws/aws-connection-fns";
|
||||
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";
|
||||
|
||||
import { TAwsParameterStoreSyncWithCredentials } from "./aws-parameter-store-sync-types";
|
||||
@@ -389,6 +390,9 @@ export const AwsParameterStoreSyncFns = {
|
||||
for (const entry of Object.entries(awsParameterStoreSecretsRecord)) {
|
||||
const [key, parameter] = entry;
|
||||
|
||||
// eslint-disable-next-line no-continue
|
||||
if (!matchesSchema(key, syncOptions.keySchema)) continue;
|
||||
|
||||
if (!(key in secretMap) || !secretMap[key].value) {
|
||||
parametersToDelete.push(parameter);
|
||||
}
|
||||
|
@@ -27,6 +27,7 @@ import {
|
||||
import { getAwsConnectionConfig } from "@app/services/app-connection/aws/aws-connection-fns";
|
||||
import { AwsSecretsManagerSyncMappingBehavior } from "@app/services/secret-sync/aws-secrets-manager/aws-secrets-manager-sync-enums";
|
||||
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";
|
||||
|
||||
import { TAwsSecretsManagerSyncWithCredentials } from "./aws-secrets-manager-sync-types";
|
||||
@@ -399,6 +400,9 @@ export const AwsSecretsManagerSyncFns = {
|
||||
if (syncOptions.disableSecretDeletion) return;
|
||||
|
||||
for await (const secretKey of Object.keys(awsSecretsRecord)) {
|
||||
// eslint-disable-next-line no-continue
|
||||
if (!matchesSchema(secretKey, syncOptions.keySchema)) continue;
|
||||
|
||||
if (!(secretKey in secretMap) || !secretMap[secretKey].value) {
|
||||
try {
|
||||
await deleteSecret(client, secretKey);
|
||||
|
@@ -7,6 +7,7 @@ import { TAppConnectionDALFactory } from "@app/services/app-connection/app-conne
|
||||
import { getAzureConnectionAccessToken } from "@app/services/app-connection/azure-key-vault";
|
||||
import { isAzureKeyVaultReference } from "@app/services/integration-auth/integration-sync-secret-fns";
|
||||
import { TKmsServiceFactory } from "@app/services/kms/kms-service";
|
||||
import { matchesSchema } from "@app/services/secret-sync/secret-sync-fns";
|
||||
import { TSecretMap } from "@app/services/secret-sync/secret-sync-types";
|
||||
|
||||
import { TAzureAppConfigurationSyncWithCredentials } from "./azure-app-configuration-sync-types";
|
||||
@@ -139,6 +140,9 @@ export const azureAppConfigurationSyncFactory = ({
|
||||
if (secretSync.syncOptions.disableSecretDeletion) return;
|
||||
|
||||
for await (const key of Object.keys(azureAppConfigSecrets)) {
|
||||
// eslint-disable-next-line no-continue
|
||||
if (!matchesSchema(key, secretSync.syncOptions.keySchema)) continue;
|
||||
|
||||
const azureSecret = azureAppConfigSecrets[key];
|
||||
if (
|
||||
!(key in secretMap) ||
|
||||
|
@@ -5,6 +5,7 @@ import { request } from "@app/lib/config/request";
|
||||
import { TAppConnectionDALFactory } from "@app/services/app-connection/app-connection-dal";
|
||||
import { getAzureConnectionAccessToken } from "@app/services/app-connection/azure-key-vault";
|
||||
import { TKmsServiceFactory } from "@app/services/kms/kms-service";
|
||||
import { matchesSchema } from "@app/services/secret-sync/secret-sync-fns";
|
||||
import { TSecretMap } from "@app/services/secret-sync/secret-sync-types";
|
||||
|
||||
import { SecretSyncError } from "../secret-sync-errors";
|
||||
@@ -192,7 +193,9 @@ export const azureKeyVaultSyncFactory = ({ kmsService, appConnectionDAL }: TAzur
|
||||
if (secretSync.syncOptions.disableSecretDeletion) return;
|
||||
|
||||
for await (const deleteSecretKey of deleteSecrets.filter(
|
||||
(secret) => !setSecrets.find((setSecret) => setSecret.key === secret)
|
||||
(secret) =>
|
||||
matchesSchema(secret, secretSync.syncOptions.keySchema) &&
|
||||
!setSecrets.find((setSecret) => setSecret.key === secret)
|
||||
)) {
|
||||
await request.delete(`${secretSync.destinationConfig.vaultBaseUrl}/secrets/${deleteSecretKey}?api-version=7.3`, {
|
||||
headers: {
|
||||
|
@@ -12,6 +12,7 @@ import {
|
||||
TCamundaSyncWithCredentials
|
||||
} from "@app/services/secret-sync/camunda/camunda-sync-types";
|
||||
import { SecretSyncError } from "@app/services/secret-sync/secret-sync-errors";
|
||||
import { matchesSchema } from "@app/services/secret-sync/secret-sync-fns";
|
||||
|
||||
import { TSecretMap } from "../secret-sync-types";
|
||||
|
||||
@@ -116,6 +117,9 @@ export const camundaSyncFactory = ({ kmsService, appConnectionDAL }: TCamundaSec
|
||||
if (secretSync.syncOptions.disableSecretDeletion) return;
|
||||
|
||||
for await (const secret of Object.keys(camundaSecrets)) {
|
||||
// eslint-disable-next-line no-continue
|
||||
if (!matchesSchema(secret, secretSync.syncOptions.keySchema)) continue;
|
||||
|
||||
if (!(secret in secretMap) || !secretMap[secret].value) {
|
||||
try {
|
||||
await deleteCamundaSecret({
|
||||
|
@@ -11,6 +11,7 @@ import {
|
||||
TDatabricksSyncWithCredentials
|
||||
} from "@app/services/secret-sync/databricks/databricks-sync-types";
|
||||
import { SecretSyncError } from "@app/services/secret-sync/secret-sync-errors";
|
||||
import { matchesSchema } from "@app/services/secret-sync/secret-sync-fns";
|
||||
import { SECRET_SYNC_NAME_MAP } from "@app/services/secret-sync/secret-sync-maps";
|
||||
|
||||
import { TSecretMap } from "../secret-sync-types";
|
||||
@@ -115,6 +116,9 @@ export const databricksSyncFactory = ({ kmsService, appConnectionDAL }: TDatabri
|
||||
if (secretSync.syncOptions.disableSecretDeletion) return;
|
||||
|
||||
for await (const secret of databricksSecretKeys) {
|
||||
// eslint-disable-next-line no-continue
|
||||
if (!matchesSchema(secret.key, secretSync.syncOptions.keySchema)) continue;
|
||||
|
||||
if (!(secret.key in secretMap)) {
|
||||
await deleteDatabricksSecrets({
|
||||
key: secret.key,
|
||||
|
@@ -4,6 +4,7 @@ import { request } from "@app/lib/config/request";
|
||||
import { logger } from "@app/lib/logger";
|
||||
import { getGcpConnectionAuthToken } from "@app/services/app-connection/gcp";
|
||||
import { IntegrationUrls } from "@app/services/integration-auth/integration-list";
|
||||
import { matchesSchema } from "@app/services/secret-sync/secret-sync-fns";
|
||||
|
||||
import { SecretSyncError } from "../secret-sync-errors";
|
||||
import { TSecretMap } from "../secret-sync-types";
|
||||
@@ -153,6 +154,9 @@ export const GcpSyncFns = {
|
||||
}
|
||||
|
||||
for await (const key of Object.keys(gcpSecrets)) {
|
||||
// eslint-disable-next-line no-continue
|
||||
if (!matchesSchema(key, secretSync.syncOptions.keySchema)) continue;
|
||||
|
||||
try {
|
||||
if (!(key in secretMap) || !secretMap[key].value) {
|
||||
// eslint-disable-next-line no-continue
|
||||
|
@@ -4,6 +4,7 @@ import sodium from "libsodium-wrappers";
|
||||
import { getGitHubClient } from "@app/services/app-connection/github";
|
||||
import { GitHubSyncScope, GitHubSyncVisibility } from "@app/services/secret-sync/github/github-sync-enums";
|
||||
import { SecretSyncError } from "@app/services/secret-sync/secret-sync-errors";
|
||||
import { matchesSchema } from "@app/services/secret-sync/secret-sync-fns";
|
||||
import { SECRET_SYNC_NAME_MAP } from "@app/services/secret-sync/secret-sync-maps";
|
||||
import { TSecretMap } from "@app/services/secret-sync/secret-sync-types";
|
||||
|
||||
@@ -222,6 +223,9 @@ export const GithubSyncFns = {
|
||||
if (secretSync.syncOptions.disableSecretDeletion) return;
|
||||
|
||||
for await (const encryptedSecret of encryptedSecrets) {
|
||||
// eslint-disable-next-line no-continue
|
||||
if (!matchesSchema(encryptedSecret.name, secretSync.syncOptions.keySchema)) continue;
|
||||
|
||||
if (!(encryptedSecret.name in secretMap)) {
|
||||
await deleteSecret(client, secretSync, encryptedSecret);
|
||||
}
|
||||
|
@@ -11,6 +11,7 @@ import {
|
||||
TPostHCVaultVariable
|
||||
} from "@app/services/secret-sync/hc-vault/hc-vault-sync-types";
|
||||
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 listHCVaultVariables = async ({ instanceUrl, namespace, mount, accessToken, path }: THCVaultListVariables) => {
|
||||
@@ -68,7 +69,7 @@ export const HCVaultSyncFns = {
|
||||
const {
|
||||
connection,
|
||||
destinationConfig: { mount, path },
|
||||
syncOptions: { disableSecretDeletion }
|
||||
syncOptions: { disableSecretDeletion, keySchema }
|
||||
} = secretSync;
|
||||
|
||||
const { namespace } = connection.credentials;
|
||||
@@ -95,6 +96,9 @@ export const HCVaultSyncFns = {
|
||||
if (disableSecretDeletion) return;
|
||||
|
||||
for await (const [key] of Object.entries(variables)) {
|
||||
// eslint-disable-next-line no-continue
|
||||
if (!matchesSchema(key, keySchema)) continue;
|
||||
|
||||
if (!(key in secretMap)) {
|
||||
delete variables[key];
|
||||
tainted = true;
|
||||
|
@@ -2,6 +2,7 @@ import { request } from "@app/lib/config/request";
|
||||
import { logger } from "@app/lib/logger";
|
||||
import { IntegrationUrls } from "@app/services/integration-auth/integration-list";
|
||||
import { SecretSyncError } from "@app/services/secret-sync/secret-sync-errors";
|
||||
import { matchesSchema } from "@app/services/secret-sync/secret-sync-fns";
|
||||
import { SECRET_SYNC_NAME_MAP } from "@app/services/secret-sync/secret-sync-maps";
|
||||
import { TSecretMap } from "@app/services/secret-sync/secret-sync-types";
|
||||
|
||||
@@ -199,6 +200,9 @@ export const HumanitecSyncFns = {
|
||||
if (secretSync.syncOptions.disableSecretDeletion) return;
|
||||
|
||||
for await (const humanitecSecret of humanitecSecrets) {
|
||||
// eslint-disable-next-line no-continue
|
||||
if (!matchesSchema(humanitecSecret.key, secretSync.syncOptions.keySchema)) continue;
|
||||
|
||||
if (!secretMap[humanitecSecret.key]) {
|
||||
await deleteSecret(secretSync, humanitecSecret);
|
||||
}
|
||||
|
@@ -11,6 +11,7 @@ import {
|
||||
TUpdateOCIVaultVariable
|
||||
} from "@app/services/secret-sync/oci-vault/oci-vault-sync-types";
|
||||
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 listOCIVaultVariables = async ({ provider, compartmentId, vaultId, onlyActive }: TOCIVaultListVariables) => {
|
||||
@@ -211,6 +212,9 @@ export const OCIVaultSyncFns = {
|
||||
|
||||
// Update and delete secrets
|
||||
for await (const [key, variable] of Object.entries(variables)) {
|
||||
// eslint-disable-next-line no-continue
|
||||
if (!matchesSchema(key, secretSync.syncOptions.keySchema)) continue;
|
||||
|
||||
// Only update / delete active secrets
|
||||
if (variable.lifecycleState === vault.models.SecretSummary.LifecycleState.Active) {
|
||||
if (key in secretMap && secretMap[key].value.length > 0) {
|
||||
|
@@ -1,4 +1,5 @@
|
||||
import { AxiosError } from "axios";
|
||||
import RE2 from "re2";
|
||||
|
||||
import {
|
||||
AWS_PARAMETER_STORE_SYNC_LIST_OPTION,
|
||||
@@ -61,45 +62,63 @@ type TSyncSecretDeps = {
|
||||
kmsService: Pick<TKmsServiceFactory, "createCipherPairWithDataKey">;
|
||||
};
|
||||
|
||||
// const addAffixes = (secretSync: TSecretSyncWithCredentials, unprocessedSecretMap: TSecretMap) => {
|
||||
// let secretMap = { ...unprocessedSecretMap };
|
||||
//
|
||||
// const { appendSuffix, prependPrefix } = secretSync.syncOptions;
|
||||
//
|
||||
// if (appendSuffix || prependPrefix) {
|
||||
// secretMap = {};
|
||||
// Object.entries(unprocessedSecretMap).forEach(([key, value]) => {
|
||||
// secretMap[`${prependPrefix || ""}${key}${appendSuffix || ""}`] = value;
|
||||
// });
|
||||
// }
|
||||
//
|
||||
// return secretMap;
|
||||
// };
|
||||
//
|
||||
// const stripAffixes = (secretSync: TSecretSyncWithCredentials, unprocessedSecretMap: TSecretMap) => {
|
||||
// let secretMap = { ...unprocessedSecretMap };
|
||||
//
|
||||
// const { appendSuffix, prependPrefix } = secretSync.syncOptions;
|
||||
//
|
||||
// if (appendSuffix || prependPrefix) {
|
||||
// secretMap = {};
|
||||
// Object.entries(unprocessedSecretMap).forEach(([key, value]) => {
|
||||
// let processedKey = key;
|
||||
//
|
||||
// if (prependPrefix && processedKey.startsWith(prependPrefix)) {
|
||||
// processedKey = processedKey.slice(prependPrefix.length);
|
||||
// }
|
||||
//
|
||||
// if (appendSuffix && processedKey.endsWith(appendSuffix)) {
|
||||
// processedKey = processedKey.slice(0, -appendSuffix.length);
|
||||
// }
|
||||
//
|
||||
// secretMap[processedKey] = value;
|
||||
// });
|
||||
// }
|
||||
//
|
||||
// return secretMap;
|
||||
// };
|
||||
// Add schema to secret keys
|
||||
const addSchema = (unprocessedSecretMap: TSecretMap, schema?: string): TSecretMap => {
|
||||
if (!schema) return unprocessedSecretMap;
|
||||
|
||||
const processedSecretMap: TSecretMap = {};
|
||||
|
||||
for (const [key, value] of Object.entries(unprocessedSecretMap)) {
|
||||
const newKey = new RE2("{{secretKey}}").replace(schema, key);
|
||||
processedSecretMap[newKey] = value;
|
||||
}
|
||||
|
||||
return processedSecretMap;
|
||||
};
|
||||
|
||||
// Strip schema from secret keys
|
||||
const stripSchema = (unprocessedSecretMap: TSecretMap, schema?: string): TSecretMap => {
|
||||
if (!schema) return unprocessedSecretMap;
|
||||
|
||||
const [prefix, suffix] = schema.split("{{secretKey}}");
|
||||
|
||||
const strippedMap: TSecretMap = {};
|
||||
|
||||
for (const [key, value] of Object.entries(unprocessedSecretMap)) {
|
||||
if (!key.startsWith(prefix) || !key.endsWith(suffix)) {
|
||||
// eslint-disable-next-line no-continue
|
||||
continue;
|
||||
}
|
||||
|
||||
const strippedKey = key.slice(prefix.length, key.length - suffix.length);
|
||||
strippedMap[strippedKey] = value;
|
||||
}
|
||||
|
||||
return strippedMap;
|
||||
};
|
||||
|
||||
// Checks if a key matches a schema
|
||||
export const matchesSchema = (key: string, schema?: string): boolean => {
|
||||
if (!schema) return true;
|
||||
|
||||
const [prefix, suffix] = schema.split("{{secretKey}}");
|
||||
if (prefix === undefined || suffix === undefined) return true;
|
||||
|
||||
return key.startsWith(prefix) && key.endsWith(suffix);
|
||||
};
|
||||
|
||||
// Filter only for secrets with keys that match the schema
|
||||
const filterForSchema = (secretMap: TSecretMap, schema?: string): TSecretMap => {
|
||||
const filteredMap: TSecretMap = {};
|
||||
|
||||
for (const [key, value] of Object.entries(secretMap)) {
|
||||
if (matchesSchema(key, schema)) {
|
||||
filteredMap[key] = value;
|
||||
}
|
||||
}
|
||||
|
||||
return filteredMap;
|
||||
};
|
||||
|
||||
export const SecretSyncFns = {
|
||||
syncSecrets: (
|
||||
@@ -107,51 +126,51 @@ export const SecretSyncFns = {
|
||||
secretMap: TSecretMap,
|
||||
{ kmsService, appConnectionDAL }: TSyncSecretDeps
|
||||
): Promise<void> => {
|
||||
// const affixedSecretMap = addAffixes(secretSync, secretMap);
|
||||
const schemaSecretMap = addSchema(secretMap, secretSync.syncOptions.keySchema);
|
||||
|
||||
switch (secretSync.destination) {
|
||||
case SecretSync.AWSParameterStore:
|
||||
return AwsParameterStoreSyncFns.syncSecrets(secretSync, secretMap);
|
||||
return AwsParameterStoreSyncFns.syncSecrets(secretSync, schemaSecretMap);
|
||||
case SecretSync.AWSSecretsManager:
|
||||
return AwsSecretsManagerSyncFns.syncSecrets(secretSync, secretMap);
|
||||
return AwsSecretsManagerSyncFns.syncSecrets(secretSync, schemaSecretMap);
|
||||
case SecretSync.GitHub:
|
||||
return GithubSyncFns.syncSecrets(secretSync, secretMap);
|
||||
return GithubSyncFns.syncSecrets(secretSync, schemaSecretMap);
|
||||
case SecretSync.GCPSecretManager:
|
||||
return GcpSyncFns.syncSecrets(secretSync, secretMap);
|
||||
return GcpSyncFns.syncSecrets(secretSync, schemaSecretMap);
|
||||
case SecretSync.AzureKeyVault:
|
||||
return azureKeyVaultSyncFactory({
|
||||
appConnectionDAL,
|
||||
kmsService
|
||||
}).syncSecrets(secretSync, secretMap);
|
||||
}).syncSecrets(secretSync, schemaSecretMap);
|
||||
case SecretSync.AzureAppConfiguration:
|
||||
return azureAppConfigurationSyncFactory({
|
||||
appConnectionDAL,
|
||||
kmsService
|
||||
}).syncSecrets(secretSync, secretMap);
|
||||
}).syncSecrets(secretSync, schemaSecretMap);
|
||||
case SecretSync.Databricks:
|
||||
return databricksSyncFactory({
|
||||
appConnectionDAL,
|
||||
kmsService
|
||||
}).syncSecrets(secretSync, secretMap);
|
||||
}).syncSecrets(secretSync, schemaSecretMap);
|
||||
case SecretSync.Humanitec:
|
||||
return HumanitecSyncFns.syncSecrets(secretSync, secretMap);
|
||||
return HumanitecSyncFns.syncSecrets(secretSync, schemaSecretMap);
|
||||
case SecretSync.TerraformCloud:
|
||||
return TerraformCloudSyncFns.syncSecrets(secretSync, secretMap);
|
||||
return TerraformCloudSyncFns.syncSecrets(secretSync, schemaSecretMap);
|
||||
case SecretSync.Camunda:
|
||||
return camundaSyncFactory({
|
||||
appConnectionDAL,
|
||||
kmsService
|
||||
}).syncSecrets(secretSync, secretMap);
|
||||
}).syncSecrets(secretSync, schemaSecretMap);
|
||||
case SecretSync.Vercel:
|
||||
return VercelSyncFns.syncSecrets(secretSync, secretMap);
|
||||
return VercelSyncFns.syncSecrets(secretSync, schemaSecretMap);
|
||||
case SecretSync.Windmill:
|
||||
return WindmillSyncFns.syncSecrets(secretSync, secretMap);
|
||||
return WindmillSyncFns.syncSecrets(secretSync, schemaSecretMap);
|
||||
case SecretSync.HCVault:
|
||||
return HCVaultSyncFns.syncSecrets(secretSync, secretMap);
|
||||
return HCVaultSyncFns.syncSecrets(secretSync, schemaSecretMap);
|
||||
case SecretSync.TeamCity:
|
||||
return TeamCitySyncFns.syncSecrets(secretSync, secretMap);
|
||||
return TeamCitySyncFns.syncSecrets(secretSync, schemaSecretMap);
|
||||
case SecretSync.OCIVault:
|
||||
return OCIVaultSyncFns.syncSecrets(secretSync, secretMap);
|
||||
return OCIVaultSyncFns.syncSecrets(secretSync, schemaSecretMap);
|
||||
default:
|
||||
throw new Error(
|
||||
`Unhandled sync destination for sync secrets fns: ${(secretSync as TSecretSyncWithCredentials).destination}`
|
||||
@@ -226,59 +245,58 @@ export const SecretSyncFns = {
|
||||
);
|
||||
}
|
||||
|
||||
return secretMap;
|
||||
// return stripAffixes(secretSync, secretMap);
|
||||
return stripSchema(filterForSchema(secretMap), secretSync.syncOptions.keySchema);
|
||||
},
|
||||
removeSecrets: (
|
||||
secretSync: TSecretSyncWithCredentials,
|
||||
secretMap: TSecretMap,
|
||||
{ kmsService, appConnectionDAL }: TSyncSecretDeps
|
||||
): Promise<void> => {
|
||||
// const affixedSecretMap = addAffixes(secretSync, secretMap);
|
||||
const schemaSecretMap = addSchema(secretMap, secretSync.syncOptions.keySchema);
|
||||
|
||||
switch (secretSync.destination) {
|
||||
case SecretSync.AWSParameterStore:
|
||||
return AwsParameterStoreSyncFns.removeSecrets(secretSync, secretMap);
|
||||
return AwsParameterStoreSyncFns.removeSecrets(secretSync, schemaSecretMap);
|
||||
case SecretSync.AWSSecretsManager:
|
||||
return AwsSecretsManagerSyncFns.removeSecrets(secretSync, secretMap);
|
||||
return AwsSecretsManagerSyncFns.removeSecrets(secretSync, schemaSecretMap);
|
||||
case SecretSync.GitHub:
|
||||
return GithubSyncFns.removeSecrets(secretSync, secretMap);
|
||||
return GithubSyncFns.removeSecrets(secretSync, schemaSecretMap);
|
||||
case SecretSync.GCPSecretManager:
|
||||
return GcpSyncFns.removeSecrets(secretSync, secretMap);
|
||||
return GcpSyncFns.removeSecrets(secretSync, schemaSecretMap);
|
||||
case SecretSync.AzureKeyVault:
|
||||
return azureKeyVaultSyncFactory({
|
||||
appConnectionDAL,
|
||||
kmsService
|
||||
}).removeSecrets(secretSync, secretMap);
|
||||
}).removeSecrets(secretSync, schemaSecretMap);
|
||||
case SecretSync.AzureAppConfiguration:
|
||||
return azureAppConfigurationSyncFactory({
|
||||
appConnectionDAL,
|
||||
kmsService
|
||||
}).removeSecrets(secretSync, secretMap);
|
||||
}).removeSecrets(secretSync, schemaSecretMap);
|
||||
case SecretSync.Databricks:
|
||||
return databricksSyncFactory({
|
||||
appConnectionDAL,
|
||||
kmsService
|
||||
}).removeSecrets(secretSync, secretMap);
|
||||
}).removeSecrets(secretSync, schemaSecretMap);
|
||||
case SecretSync.Humanitec:
|
||||
return HumanitecSyncFns.removeSecrets(secretSync, secretMap);
|
||||
return HumanitecSyncFns.removeSecrets(secretSync, schemaSecretMap);
|
||||
case SecretSync.TerraformCloud:
|
||||
return TerraformCloudSyncFns.removeSecrets(secretSync, secretMap);
|
||||
return TerraformCloudSyncFns.removeSecrets(secretSync, schemaSecretMap);
|
||||
case SecretSync.Camunda:
|
||||
return camundaSyncFactory({
|
||||
appConnectionDAL,
|
||||
kmsService
|
||||
}).removeSecrets(secretSync, secretMap);
|
||||
}).removeSecrets(secretSync, schemaSecretMap);
|
||||
case SecretSync.Vercel:
|
||||
return VercelSyncFns.removeSecrets(secretSync, secretMap);
|
||||
return VercelSyncFns.removeSecrets(secretSync, schemaSecretMap);
|
||||
case SecretSync.Windmill:
|
||||
return WindmillSyncFns.removeSecrets(secretSync, secretMap);
|
||||
return WindmillSyncFns.removeSecrets(secretSync, schemaSecretMap);
|
||||
case SecretSync.HCVault:
|
||||
return HCVaultSyncFns.removeSecrets(secretSync, secretMap);
|
||||
return HCVaultSyncFns.removeSecrets(secretSync, schemaSecretMap);
|
||||
case SecretSync.TeamCity:
|
||||
return TeamCitySyncFns.removeSecrets(secretSync, secretMap);
|
||||
return TeamCitySyncFns.removeSecrets(secretSync, schemaSecretMap);
|
||||
case SecretSync.OCIVault:
|
||||
return OCIVaultSyncFns.removeSecrets(secretSync, secretMap);
|
||||
return OCIVaultSyncFns.removeSecrets(secretSync, schemaSecretMap);
|
||||
default:
|
||||
throw new Error(
|
||||
`Unhandled sync destination for remove secrets fns: ${(secretSync as TSecretSyncWithCredentials).destination}`
|
||||
|
@@ -1,3 +1,4 @@
|
||||
import RE2 from "re2";
|
||||
import { AnyZodObject, z } from "zod";
|
||||
|
||||
import { SecretSyncsSchema } from "@app/db/schemas/secret-syncs";
|
||||
@@ -24,6 +25,14 @@ const BaseSyncOptionsSchema = <T extends AnyZodObject | undefined = undefined>({
|
||||
? z.nativeEnum(SecretSyncInitialSyncBehavior)
|
||||
: z.literal(SecretSyncInitialSyncBehavior.OverwriteDestination)
|
||||
).describe(SecretSyncs.SYNC_OPTIONS(destination).initialSyncBehavior),
|
||||
keySchema: z
|
||||
.string()
|
||||
.optional()
|
||||
.refine((val) => !val || new RE2(/^(?:[a-zA-Z0-9_\-/]*)(?:\{\{secretKey\}\})(?:[a-zA-Z0-9_\-/]*)$/).test(val), {
|
||||
message:
|
||||
"Key schema must include one {{secretKey}} and only contain letters, numbers, dashes, underscores, slashes, and the {{secretKey}} placeholder."
|
||||
})
|
||||
.describe(SecretSyncs.SYNC_OPTIONS(destination).keySchema),
|
||||
disableSecretDeletion: z.boolean().optional().describe(SecretSyncs.SYNC_OPTIONS(destination).disableSecretDeletion)
|
||||
});
|
||||
|
||||
|
@@ -1,6 +1,7 @@
|
||||
import { request } from "@app/lib/config/request";
|
||||
import { getTeamCityInstanceUrl } from "@app/services/app-connection/teamcity";
|
||||
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";
|
||||
import {
|
||||
TDeleteTeamCityVariable,
|
||||
@@ -125,6 +126,9 @@ export const TeamCitySyncFns = {
|
||||
const variables = await listTeamCityVariables({ instanceUrl, accessToken, project, buildConfig });
|
||||
|
||||
for await (const [key, variable] of Object.entries(variables)) {
|
||||
// eslint-disable-next-line no-continue
|
||||
if (!matchesSchema(key, secretSync.syncOptions.keySchema)) continue;
|
||||
|
||||
if (!(key in secretMap)) {
|
||||
try {
|
||||
await deleteTeamCityVariable({
|
||||
|
@@ -4,6 +4,7 @@ import { AxiosResponse } from "axios";
|
||||
import { request } from "@app/lib/config/request";
|
||||
import { IntegrationUrls } from "@app/services/integration-auth/integration-list";
|
||||
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";
|
||||
|
||||
import { SECRET_SYNC_NAME_MAP } from "../secret-sync-maps";
|
||||
@@ -231,6 +232,9 @@ export const TerraformCloudSyncFns = {
|
||||
if (secretSync.syncOptions.disableSecretDeletion) return;
|
||||
|
||||
for (const terraformCloudVariable of terraformCloudVariables) {
|
||||
// eslint-disable-next-line no-continue
|
||||
if (!matchesSchema(terraformCloudVariable.key, secretSync.syncOptions.keySchema)) continue;
|
||||
|
||||
if (!Object.prototype.hasOwnProperty.call(secretMap, terraformCloudVariable.key)) {
|
||||
await deleteVariable(secretSync, terraformCloudVariable);
|
||||
}
|
||||
|
@@ -2,6 +2,7 @@
|
||||
import { request } from "@app/lib/config/request";
|
||||
import { IntegrationUrls } from "@app/services/integration-auth/integration-list";
|
||||
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";
|
||||
|
||||
import { VercelEnvironmentType } from "./vercel-sync-enums";
|
||||
@@ -290,6 +291,9 @@ export const VercelSyncFns = {
|
||||
if (secretSync.syncOptions.disableSecretDeletion) return;
|
||||
|
||||
for await (const vercelSecret of vercelSecrets) {
|
||||
// eslint-disable-next-line no-continue
|
||||
if (!matchesSchema(vercelSecret.key, secretSync.syncOptions.keySchema)) continue;
|
||||
|
||||
if (!secretMap[vercelSecret.key]) {
|
||||
await deleteSecret(secretSync, vercelSecret);
|
||||
}
|
||||
|
@@ -1,6 +1,7 @@
|
||||
import { request } from "@app/lib/config/request";
|
||||
import { getWindmillInstanceUrl } from "@app/services/app-connection/windmill";
|
||||
import { SecretSyncError } from "@app/services/secret-sync/secret-sync-errors";
|
||||
import { matchesSchema } from "@app/services/secret-sync/secret-sync-fns";
|
||||
import {
|
||||
TDeleteWindmillVariable,
|
||||
TPostWindmillVariable,
|
||||
@@ -128,7 +129,7 @@ export const WindmillSyncFns = {
|
||||
const {
|
||||
connection,
|
||||
destinationConfig: { path },
|
||||
syncOptions: { disableSecretDeletion }
|
||||
syncOptions: { disableSecretDeletion, keySchema }
|
||||
} = secretSync;
|
||||
|
||||
// url needs to be lowercase
|
||||
@@ -169,6 +170,9 @@ export const WindmillSyncFns = {
|
||||
if (disableSecretDeletion) return;
|
||||
|
||||
for await (const [key, variable] of Object.entries(variables)) {
|
||||
// eslint-disable-next-line no-continue
|
||||
if (!matchesSchema(key, keySchema)) continue;
|
||||
|
||||
if (!(key in secretMap)) {
|
||||
try {
|
||||
await deleteWindmillVariable({
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 885 KiB After Width: | Height: | Size: 782 KiB |
Binary file not shown.
Before Width: | Height: | Size: 878 KiB After Width: | Height: | Size: 779 KiB |
@@ -22,11 +22,11 @@ description: "How to sync secrets from Infisical to Heroku"
|
||||
</Step>
|
||||
<Step title="Start integration">
|
||||
Select which Infisical environment secrets you want to sync to which Heroku app and press create integration to start syncing secrets to Heroku.
|
||||
|
||||
|
||||

|
||||
|
||||
Here's some guidance on each field:
|
||||
|
||||
|
||||
- Project Environment: The environment in the current Infisical project from which you want to sync secrets from.
|
||||
- Secrets Path: The path in the current Infisical project from which you want to sync secrets from such as `/` (for secrets that do not reside in a folder) or `/foo/bar` (for secrets nested in a folder, in this case a folder called `bar` in another folder called `foo`).
|
||||
- Heroku App: The application in Heroku that you want to sync secrets to.
|
||||
@@ -34,7 +34,7 @@ description: "How to sync secrets from Infisical to Heroku"
|
||||
- **No Import - Overwrite all values in Heroku**: Sync secrets and overwrite any existing secrets in Heroku.
|
||||
- **Import - Prefer values from Infisical**: Import secrets from Heroku to Infisical; if a secret with the same name already exists in Infisical, do nothing. Afterwards, sync secrets to Heroku.
|
||||
- **Import - Prefer values from Heroku**: Import secrets from Heroku to Infisical; if a secret with the same name already exists in Infisical, replace its value with the one from Heroku. Afterwards, sync secrets to Heroku.
|
||||
|
||||
|
||||

|
||||
</Step>
|
||||
</Steps>
|
||||
@@ -46,27 +46,26 @@ description: "How to sync secrets from Infisical to Heroku"
|
||||
<Step title="Create an API client in Heroku">
|
||||
Navigate to your user Account settings > Applications to create a new API client.
|
||||
|
||||

|
||||

|
||||

|
||||
|
||||

|
||||

|
||||

|
||||
|
||||
Create the API client. As part of the form, set the **OAuth callback URL** to `https://your-domain.com/integrations/heroku/oauth2/callback`.
|
||||
|
||||

|
||||

|
||||
</Step>
|
||||
<Step title="Add your Heroku API client credentials to Infisical">
|
||||
Obtain the **Client ID** and **Client Secret** for your Heroku API client.
|
||||
|
||||

|
||||
|
||||
|
||||

|
||||
|
||||
Back in your Infisical instance, add two new environment variables for the credentials of your Heroku API client.
|
||||
|
||||
- `CLIENT_ID_HEROKU`: The **Client ID** of your Heroku API client.
|
||||
- `CLIENT_SECRET_HEROKU`: The **Client Secret** of your Heroku API client.
|
||||
|
||||
|
||||
Once added, restart your Infisical instance and use the Heroku integration.
|
||||
</Step>
|
||||
</Steps>
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
|
@@ -40,6 +40,10 @@ description: "Learn how to configure an AWS Parameter Store Sync for 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 Parameter Store when keys conflict.
|
||||
- **Import Secrets (Prioritize AWS Parameter Store)**: Imports secrets from the destination endpoint before syncing, prioritizing values from Parameter Store over Infisical when keys conflict.
|
||||
- **Key Schema**: Template that determines how secret names are transformed when syncing, using `{{secretKey}}` as a placeholder for the original secret name.
|
||||
<Note>
|
||||
We highly recommend using a Key Schema to ensure that Infisical only manages the specific keys you intend, keeping everything else untouched.
|
||||
</Note>
|
||||
- **KMS Key**: The AWS KMS key ID or alias to encrypt parameters with.
|
||||
- **Tags**: Optional resource tags to add to parameters synced by Infisical.
|
||||
- **Sync Secret Metadata as Resource Tags**: If enabled, metadata attached to secrets will be added as resource tags to parameters synced by Infisical.
|
||||
|
@@ -43,6 +43,10 @@ description: "Learn how to configure an AWS Secrets Manager Sync for 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 Secrets Manager when keys conflict.
|
||||
- **Import Secrets (Prioritize AWS Secrets Manager)**: Imports secrets from the destination endpoint before syncing, prioritizing values from Secrets Manager over Infisical when keys conflict.
|
||||
- **Key Schema**: Template that determines how secret names are transformed when syncing, using `{{secretKey}}` as a placeholder for the original secret name.
|
||||
<Note>
|
||||
We highly recommend using a Key Schema to ensure that Infisical only manages the specific keys you intend, keeping everything else untouched.
|
||||
</Note>
|
||||
- **KMS Key**: The AWS KMS key ID or alias to encrypt secrets with.
|
||||
- **Tags**: Optional tags to add to secrets synced by Infisical.
|
||||
- **Sync Secret Metadata as Tags**: If enabled, metadata attached to secrets will be added as tags to secrets synced by Infisical.
|
||||
|
@@ -48,7 +48,10 @@ description: "Learn how to configure an Azure App Configuration Sync for Infisic
|
||||
- **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 Secrets Manager when keys conflict.
|
||||
- **Import Secrets (Prioritize Azure App Configuration)**: Imports secrets from the destination endpoint before syncing, prioritizing values from Secrets Manager over Infisical when keys conflict.
|
||||
|
||||
- **Key Schema**: Template that determines how secret names are transformed when syncing, using `{{secretKey}}` as a placeholder for the original secret name.
|
||||
<Note>
|
||||
We highly recommend using a Key Schema to ensure that Infisical only manages the specific keys you intend, keeping everything else untouched.
|
||||
</Note>
|
||||
- **Auto-Sync Enabled**: If enabled, secrets will automatically be synced from the source location when changes occur. Disable to enforce manual syncing only.
|
||||
- **Disable Secret Deletion**: If enabled, Infisical will not remove secrets from the sync destination. Enable this option if you intend to manage some secrets manually outside of Infisical.
|
||||
|
||||
|
@@ -51,6 +51,10 @@ description: "Learn how to configure a Azure Key Vault Sync for 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 Secrets Manager when keys conflict.
|
||||
- **Import Secrets (Prioritize Azure Key Vault)**: Imports secrets from the destination endpoint before syncing, prioritizing values from Secrets Manager over Infisical when keys conflict.
|
||||
- **Key Schema**: Template that determines how secret names are transformed when syncing, using `{{secretKey}}` as a placeholder for the original secret name.
|
||||
<Note>
|
||||
We highly recommend using a Key Schema to ensure that Infisical only manages the specific keys you intend, keeping everything else untouched.
|
||||
</Note>
|
||||
- **Auto-Sync Enabled**: If enabled, secrets will automatically be synced from the source location when changes occur. Disable to enforce manual syncing only.
|
||||
- **Disable Secret Deletion**: If enabled, Infisical will not remove secrets from the sync destination. Enable this option if you intend to manage some secrets manually outside of Infisical.
|
||||
|
||||
|
@@ -39,6 +39,10 @@ description: "Learn how to configure a Camunda Sync for 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 Camunda when keys conflict.
|
||||
- **Import Secrets (Prioritize Camunda)**: Imports secrets from the destination endpoint before syncing, prioritizing values from Camunda over Infisical when keys conflict.
|
||||
- **Key Schema**: Template that determines how secret names are transformed when syncing, using `{{secretKey}}` as a placeholder for the original secret name.
|
||||
<Note>
|
||||
We highly recommend using a Key Schema to ensure that Infisical only manages the specific keys you intend, keeping everything else untouched.
|
||||
</Note>
|
||||
- **Auto-Sync Enabled**: If enabled, secrets will automatically be synced from the source location when changes occur. Disable to enforce manual syncing only.
|
||||
- **Disable Secret Deletion**: If enabled, Infisical will not remove secrets from the sync destination. Enable this option if you intend to manage some secrets manually outside of Infisical.
|
||||
|
||||
|
@@ -46,6 +46,10 @@ description: "Learn how to configure a Databricks Sync for Infisical."
|
||||
<Note>
|
||||
Databricks 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.
|
||||
<Note>
|
||||
We highly recommend using a Key Schema to ensure that Infisical only manages the specific keys you intend, keeping everything else untouched.
|
||||
</Note>
|
||||
- **Auto-Sync Enabled**: If enabled, secrets will automatically be synced from the source location when changes occur. Disable to enforce manual syncing only.
|
||||
- **Disable Secret Deletion**: If enabled, Infisical will not remove secrets from the sync destination. Enable this option if you intend to manage some secrets manually outside of Infisical.
|
||||
|
||||
|
@@ -42,6 +42,10 @@ description: "Learn how to configure a GCP Secret Manager Sync for 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 GCP Secret Manager when keys conflict.
|
||||
- **Import Secrets (Prioritize GCP Secret Manager)**: Imports secrets from the destination endpoint before syncing, prioritizing values from GCP Secret Manager over Infisical when keys conflict.
|
||||
- **Key Schema**: Template that determines how secret names are transformed when syncing, using `{{secretKey}}` as a placeholder for the original secret name.
|
||||
<Note>
|
||||
We highly recommend using a Key Schema to ensure that Infisical only manages the specific keys you intend, keeping everything else untouched.
|
||||
</Note>
|
||||
- **Auto-Sync Enabled**: If enabled, secrets will automatically be synced from the source location when changes occur. Disable to enforce manual syncing only.
|
||||
- **Disable Secret Deletion**: If enabled, Infisical will not remove secrets from the sync destination. Enable this option if you intend to manage some secrets manually outside of Infisical.
|
||||
|
||||
|
@@ -62,6 +62,10 @@ description: "Learn how to configure a GitHub Sync for Infisical."
|
||||
<Note>
|
||||
GitHub 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.
|
||||
<Note>
|
||||
We highly recommend using a Key Schema to ensure that Infisical only manages the specific keys you intend, keeping everything else untouched.
|
||||
</Note>
|
||||
- **Auto-Sync Enabled**: If enabled, secrets will automatically be synced from the source location when changes occur. Disable to enforce manual syncing only.
|
||||
- **Disable Secret Deletion**: If enabled, Infisical will not remove secrets from the sync destination. Enable this option if you intend to manage some secrets manually outside of Infisical.
|
||||
|
||||
|
@@ -54,6 +54,10 @@ description: "Learn how to configure a Hashicorp Vault Sync for 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 Hashicorp Vault when keys conflict.
|
||||
- **Import Secrets (Prioritize Hashicorp Vault)**: Imports secrets from the destination endpoint before syncing, prioritizing values from Hashicorp Vault over Infisical when keys conflict.
|
||||
- **Key Schema**: Template that determines how secret names are transformed when syncing, using `{{secretKey}}` as a placeholder for the original secret name.
|
||||
<Note>
|
||||
We highly recommend using a Key Schema to ensure that Infisical only manages the specific keys you intend, keeping everything else untouched.
|
||||
</Note>
|
||||
- **Auto-Sync Enabled**: If enabled, secrets will automatically be synced from the source location when changes occur. Disable to enforce manual syncing only.
|
||||
- **Disable Secret Deletion**: If enabled, Infisical will not remove secrets from the sync destination. Enable this option if you intend to manage some secrets manually outside of Infisical.
|
||||
</Step>
|
||||
|
@@ -55,6 +55,10 @@ description: "Learn how to configure a Humanitec Sync for Infisical."
|
||||
<Note>
|
||||
Humanitec 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.
|
||||
<Note>
|
||||
We highly recommend using a Key Schema to ensure that Infisical only manages the specific keys you intend, keeping everything else untouched.
|
||||
</Note>
|
||||
- **Auto-Sync Enabled**: If enabled, secrets will automatically be synced from the source location when changes occur. Disable to enforce manual syncing only.
|
||||
- **Disable Secret Deletion**: If enabled, Infisical will not remove secrets from the sync destination. Enable this option if you intend to manage some secrets manually outside of Infisical.
|
||||
|
||||
|
@@ -47,10 +47,13 @@ description: "Learn how to configure an Oracle Cloud Infrastructure Vault Sync f
|
||||

|
||||
|
||||
- **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.
|
||||
- **Import Secrets (Prioritize Infisical)**: Imports secrets from the destination endpoint before syncing, prioritizing values from Infisical over OCI Vault when keys conflict.
|
||||
- **Import Secrets (Prioritize OCI Vault)**: Imports secrets from the destination endpoint before syncing, prioritizing values from OCI Vault over Infisical when keys conflict.
|
||||
|
||||
- **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 OCI Vault when keys conflict.
|
||||
- **Import Secrets (Prioritize OCI Vault)**: Imports secrets from the destination endpoint before syncing, prioritizing values from OCI Vault over Infisical when keys conflict.
|
||||
- **Key Schema**: Template that determines how secret names are transformed when syncing, using `{{secretKey}}` as a placeholder for the original secret name.
|
||||
<Note>
|
||||
We highly recommend using a Key Schema to ensure that Infisical only manages the specific keys you intend, keeping everything else untouched.
|
||||
</Note>
|
||||
- **Auto-Sync Enabled**: If enabled, secrets will automatically be synced from the source location when changes occur. Disable to enforce manual syncing only.
|
||||
- **Disable Secret Deletion**: If enabled, Infisical will not remove secrets from the sync destination. Enable this option if you intend to manage some secrets manually outside of Infisical.
|
||||
</Step>
|
||||
|
@@ -93,4 +93,26 @@ via the UI or API for the third-party service you intend to sync secrets to.
|
||||
<Note>
|
||||
Infisical is continuously expanding it's Secret Sync third-party service support. If the service you need isn't available,
|
||||
you can still use our Native Integrations in the interim, or contact us at team@infisical.com to make a request .
|
||||
</Note>
|
||||
</Note>
|
||||
|
||||
## Key Schemas
|
||||
|
||||
Key Schemas transform your secret keys by applying a prefix, suffix, or format pattern during sync to external destinations. This makes it clear which secrets are managed by Infisical and prevents accidental changes to unrelated secrets.
|
||||
|
||||
**Example:**
|
||||
- Infisical key: `SECRET_1`
|
||||
- Schema: `INFISICAL_{{secretKey}}`
|
||||
- Synced key: `INFISICAL_SECRET_1`
|
||||
|
||||
<div align="center">
|
||||
```mermaid
|
||||
graph LR
|
||||
A[Infisical: **SECRET_1**] -->|Apply Schema| B[Destination: **INFISICAL_SECRET_1**]
|
||||
style B fill:#F4FFE6,stroke:#96D600,stroke-width:2px,color:black,rx:15px
|
||||
style A fill:#E6F4FF,stroke:#0096D6,stroke-width:2px,color:black,rx:15px
|
||||
```
|
||||
</div>
|
||||
|
||||
<Note>
|
||||
When importing secrets from the destination into Infisical, the schema is stripped from imported secret keys.
|
||||
</Note>
|
||||
|
@@ -48,7 +48,10 @@ description: "Learn how to configure a TeamCity Sync for Infisical."
|
||||
<Note>
|
||||
Infisical only syncs secrets from within the target scope; inherited secrets will not be imported.
|
||||
</Note>
|
||||
|
||||
- **Key Schema**: Template that determines how secret names are transformed when syncing, using `{{secretKey}}` as a placeholder for the original secret name.
|
||||
<Note>
|
||||
We highly recommend using a Key Schema to ensure that Infisical only manages the specific keys you intend, keeping everything else untouched.
|
||||
</Note>
|
||||
- **Auto-Sync Enabled**: If enabled, secrets will automatically be synced from the source location when changes occur. Disable to enforce manual syncing only.
|
||||
- **Disable Secret Deletion**: If enabled, Infisical will not remove secrets from the sync destination. Enable this option if you intend to manage some secrets manually outside of Infisical.
|
||||
|
||||
|
@@ -56,6 +56,10 @@ description: "Learn how to configure a Terraform Cloud Sync for Infisical."
|
||||
<Note>
|
||||
Terraform Cloud 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.
|
||||
<Note>
|
||||
We highly recommend using a Key Schema to ensure that Infisical only manages the specific keys you intend, keeping everything else untouched.
|
||||
</Note>
|
||||
- **Auto-Sync Enabled**: If enabled, secrets will automatically be synced from the source location when changes occur. Disable to enforce manual syncing only.
|
||||
- **Disable Secret Deletion**: If enabled, Infisical will not remove secrets from the sync destination. Enable this option if you intend to manage some secrets manually outside of Infisical.
|
||||
|
||||
|
@@ -43,6 +43,10 @@ description: "Learn how to configure a Vercel Sync for 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 Vercel when keys conflict.
|
||||
- **Import Secrets (Prioritize Vercel)**: Imports secrets from the destination endpoint before syncing, prioritizing values from Vercel over Infisical when keys conflict.
|
||||
- **Key Schema**: Template that determines how secret names are transformed when syncing, using `{{secretKey}}` as a placeholder for the original secret name.
|
||||
<Note>
|
||||
We highly recommend using a Key Schema to ensure that Infisical only manages the specific keys you intend, keeping everything else untouched.
|
||||
</Note>
|
||||
- **Auto-Sync Enabled**: If enabled, secrets will automatically be synced from the source location when changes occur. Disable to enforce manual syncing only.
|
||||
- **Disable Secret Deletion**: If enabled, Infisical will not remove secrets from the sync destination. Enable this option if you intend to manage some secrets manually outside of Infisical.
|
||||
|
||||
|
@@ -44,6 +44,10 @@ description: "Learn how to configure a Windmill Sync for 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 Windmill when keys conflict.
|
||||
- **Import Secrets (Prioritize Windmill)**: Imports secrets from the destination endpoint before syncing, prioritizing values from Windmill over Infisical when keys conflict.
|
||||
- **Key Schema**: Template that determines how secret names are transformed when syncing, using `{{secretKey}}` as a placeholder for the original secret name.
|
||||
<Note>
|
||||
We highly recommend using a Key Schema to ensure that Infisical only manages the specific keys you intend, keeping everything else untouched.
|
||||
</Note>
|
||||
- **Auto-Sync Enabled**: If enabled, secrets will automatically be synced from the source location when changes occur. Disable to enforce manual syncing only.
|
||||
- **Disable Secret Deletion**: If enabled, Infisical will not remove secrets from the sync destination. Enable this option if you intend to manage some secrets manually outside of Infisical.
|
||||
|
||||
|
@@ -44,7 +44,9 @@ const Content = ({ secretSync, onComplete }: ContentProps) => {
|
||||
handleSubmit,
|
||||
control,
|
||||
formState: { isSubmitting, isDirty }
|
||||
} = useForm<TFormData>({ resolver: zodResolver(FormSchema) });
|
||||
} = useForm<TFormData>({
|
||||
resolver: zodResolver(FormSchema)
|
||||
});
|
||||
|
||||
const triggerImportSecrets = useTriggerSecretSyncImportSecrets();
|
||||
|
||||
|
@@ -1,9 +1,13 @@
|
||||
import { ReactNode } from "react";
|
||||
import { Controller, useFormContext } from "react-hook-form";
|
||||
import { faQuestionCircle, faTriangleExclamation } from "@fortawesome/free-solid-svg-icons";
|
||||
import {
|
||||
faCircleInfo,
|
||||
faQuestionCircle,
|
||||
faTriangleExclamation
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
|
||||
import { FormControl, Select, SelectItem, Switch, Tooltip } from "@app/components/v2";
|
||||
import { FormControl, Input, Select, SelectItem, Switch, Tooltip } from "@app/components/v2";
|
||||
import { SECRET_SYNC_INITIAL_SYNC_BEHAVIOR_MAP, SECRET_SYNC_MAP } from "@app/helpers/secretSyncs";
|
||||
import { SecretSync, useSecretSyncOption } from "@app/hooks/api/secretSyncs";
|
||||
|
||||
@@ -122,6 +126,46 @@ export const SecretSyncOptionsFields = ({ hideInitialSync }: Props) => {
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
<Controller
|
||||
render={({ field: { value, onChange }, fieldState: { error } }) => (
|
||||
<FormControl
|
||||
tooltipClassName="max-w-md"
|
||||
tooltipText="When a secret is synced, its key will be injected into the key schema before it reaches the destination. This is useful for organization."
|
||||
isError={Boolean(error)}
|
||||
isOptional
|
||||
errorText={error?.message}
|
||||
label="Key Schema"
|
||||
helperText={
|
||||
<Tooltip
|
||||
className="max-w-md"
|
||||
content={
|
||||
<span>
|
||||
We highly recommend using a{" "}
|
||||
<a
|
||||
href="https://infisical.com/docs/integrations/secret-syncs/overview#key-schemas"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Key Schema
|
||||
</a>{" "}
|
||||
to ensure that Infisical only manages the specific keys you intend, keeping
|
||||
everything else untouched.
|
||||
</span>
|
||||
}
|
||||
>
|
||||
<div>
|
||||
<span>Infisical strongly advises setting a Key Schema</span>{" "}
|
||||
<FontAwesomeIcon icon={faCircleInfo} className="text-mineshaft-400" />
|
||||
</div>
|
||||
</Tooltip>
|
||||
}
|
||||
>
|
||||
<Input value={value} onChange={onChange} placeholder="INFISICAL_{{secretKey}}" />
|
||||
</FormControl>
|
||||
)}
|
||||
control={control}
|
||||
name="syncOptions.keySchema"
|
||||
/>
|
||||
{AdditionalSyncOptionsFieldsComponent}
|
||||
<Controller
|
||||
control={control}
|
||||
@@ -161,34 +205,6 @@ export const SecretSyncOptionsFields = ({ hideInitialSync }: Props) => {
|
||||
);
|
||||
}}
|
||||
/>
|
||||
{/* <Controller
|
||||
render={({ field: { value, onChange }, fieldState: { error } }) => (
|
||||
<FormControl
|
||||
isError={Boolean(error)}
|
||||
isOptional
|
||||
errorText={error?.message}
|
||||
label="Prepend Prefix"
|
||||
>
|
||||
<Input className="uppercase" value={value} onChange={onChange} placeholder="INF_" />
|
||||
</FormControl>
|
||||
)}
|
||||
control={control}
|
||||
name="syncOptions.prependPrefix"
|
||||
/>
|
||||
<Controller
|
||||
render={({ field: { value, onChange }, fieldState: { error } }) => (
|
||||
<FormControl
|
||||
isError={Boolean(error)}
|
||||
isOptional
|
||||
errorText={error?.message}
|
||||
label="Append Suffix"
|
||||
>
|
||||
<Input className="uppercase" value={value} onChange={onChange} placeholder="_INF" />
|
||||
</FormControl>
|
||||
)}
|
||||
control={control}
|
||||
name="syncOptions.appendSuffix"
|
||||
/> */}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
@@ -41,11 +41,7 @@ export const SecretSyncReviewFields = () => {
|
||||
connection,
|
||||
environment,
|
||||
secretPath,
|
||||
syncOptions: {
|
||||
// appendSuffix, prependPrefix,
|
||||
disableSecretDeletion,
|
||||
initialSyncBehavior
|
||||
},
|
||||
syncOptions: { disableSecretDeletion, initialSyncBehavior, keySchema },
|
||||
destination,
|
||||
isAutoSyncEnabled
|
||||
} = watch();
|
||||
@@ -137,8 +133,7 @@ export const SecretSyncReviewFields = () => {
|
||||
<GenericFieldLabel label="Initial Sync Behavior">
|
||||
{SECRET_SYNC_INITIAL_SYNC_BEHAVIOR_MAP[initialSyncBehavior](destinationName).name}
|
||||
</GenericFieldLabel>
|
||||
{/* <SecretSyncLabel label="Prepend Prefix">{prependPrefix}</SecretSyncLabel>
|
||||
<SecretSyncLabel label="Append Suffix">{appendSuffix}</SecretSyncLabel> */}
|
||||
<GenericFieldLabel label="Key Schema">{keySchema}</GenericFieldLabel>
|
||||
{AdditionalSyncOptionsFieldsComponent}
|
||||
{disableSecretDeletion && (
|
||||
<GenericFieldLabel label="Secret Deletion">
|
||||
|
@@ -8,18 +8,18 @@ export const BaseSecretSyncSchema = <T extends AnyZodObject | undefined = undefi
|
||||
) => {
|
||||
const baseSyncOptionsSchema = z.object({
|
||||
initialSyncBehavior: z.nativeEnum(SecretSyncInitialSyncBehavior),
|
||||
disableSecretDeletion: z.boolean().optional().default(false)
|
||||
// scott: removed temporarily for evaluation of template formatting
|
||||
// prependPrefix: z
|
||||
// .string()
|
||||
// .trim()
|
||||
// .transform((str) => str.toUpperCase())
|
||||
// .optional(),
|
||||
// appendSuffix: z
|
||||
// .string()
|
||||
// .trim()
|
||||
// .transform((str) => str.toUpperCase())
|
||||
// .optional()
|
||||
disableSecretDeletion: z.boolean().optional().default(false),
|
||||
keySchema: z
|
||||
.string()
|
||||
.optional()
|
||||
.refine(
|
||||
(val) =>
|
||||
!val || /^(?:[a-zA-Z0-9_\-/]*)(?:\{\{secretKey\}\})(?:[a-zA-Z0-9_\-/]*)$/.test(val),
|
||||
{
|
||||
message:
|
||||
"Key schema must include one {{secretKey}} and only contain letters, numbers, dashes, underscores, slashes, and the {{secretKey}} placeholder."
|
||||
}
|
||||
)
|
||||
});
|
||||
|
||||
const syncOptionsSchema = additionalSyncOptions
|
||||
|
@@ -4,8 +4,7 @@ import { SecretSyncInitialSyncBehavior, SecretSyncStatus } from "@app/hooks/api/
|
||||
export type RootSyncOptions = {
|
||||
initialSyncBehavior: SecretSyncInitialSyncBehavior;
|
||||
disableSecretDeletion?: boolean;
|
||||
// prependPrefix?: string;
|
||||
// appendSuffix?: string;
|
||||
keySchema?: string;
|
||||
};
|
||||
|
||||
export type TRootSecretSync = {
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import { twMerge } from "tailwind-merge";
|
||||
|
||||
import { UpgradePlanModal } from "@app/components/license/UpgradePlanModal";
|
||||
import { Button, ContentLoader } from "@app/components/v2";
|
||||
import { Button, ContentLoader, EmptyState } from "@app/components/v2";
|
||||
import {
|
||||
OrgPermissionActions,
|
||||
OrgPermissionSubjects,
|
||||
@@ -60,102 +60,108 @@ export const OrgSsoTab = withPermission(
|
||||
const shouldShowCreateIdentityProviderView =
|
||||
!isOidcConfigured && !isSamlConfigured && !isLdapConfigured;
|
||||
|
||||
const createIdentityProviderView = (shouldDisplaySection(LoginMethod.SAML) ||
|
||||
const createIdentityProviderView =
|
||||
shouldDisplaySection(LoginMethod.SAML) ||
|
||||
shouldDisplaySection(LoginMethod.OIDC) ||
|
||||
shouldDisplaySection(LoginMethod.LDAP)) && (
|
||||
<>
|
||||
<div className="mb-6 rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-6">
|
||||
<p className="text-xl font-semibold text-gray-200">Connect an Identity Provider</p>
|
||||
<p className="mb-2 mt-1 text-gray-400">
|
||||
Connect your identity provider to simplify user management
|
||||
</p>
|
||||
{shouldDisplaySection(LoginMethod.SAML) && (
|
||||
<div
|
||||
className={twMerge(
|
||||
"mt-4 flex items-center justify-between",
|
||||
(shouldDisplaySection(LoginMethod.OIDC) ||
|
||||
shouldDisplaySection(LoginMethod.LDAP)) &&
|
||||
"border-b border-mineshaft-500 pb-4"
|
||||
)}
|
||||
>
|
||||
<p className="text-lg text-gray-200">SAML</p>
|
||||
<Button
|
||||
colorSchema="secondary"
|
||||
onClick={() => {
|
||||
if (!subscription?.samlSSO) {
|
||||
handlePopUpOpen("upgradePlan", { feature: "SAML SSO", plan: "Pro" });
|
||||
return;
|
||||
}
|
||||
|
||||
handlePopUpOpen("addSSO");
|
||||
}}
|
||||
shouldDisplaySection(LoginMethod.LDAP) ? (
|
||||
<>
|
||||
<div className="mb-6 rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-6">
|
||||
<p className="text-xl font-semibold text-gray-200">Connect an Identity Provider</p>
|
||||
<p className="mb-2 mt-1 text-gray-400">
|
||||
Connect your identity provider to simplify user management
|
||||
</p>
|
||||
{shouldDisplaySection(LoginMethod.SAML) && (
|
||||
<div
|
||||
className={twMerge(
|
||||
"mt-4 flex items-center justify-between",
|
||||
(shouldDisplaySection(LoginMethod.OIDC) ||
|
||||
shouldDisplaySection(LoginMethod.LDAP)) &&
|
||||
"border-b border-mineshaft-500 pb-4"
|
||||
)}
|
||||
>
|
||||
Connect
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
{shouldDisplaySection(LoginMethod.OIDC) && (
|
||||
<div
|
||||
className={twMerge(
|
||||
"mt-4 flex items-center justify-between",
|
||||
shouldDisplaySection(LoginMethod.LDAP) && "border-b border-mineshaft-500 pb-4"
|
||||
)}
|
||||
>
|
||||
<p className="text-lg text-gray-200">OIDC</p>
|
||||
<Button
|
||||
colorSchema="secondary"
|
||||
onClick={() => {
|
||||
if (!subscription?.oidcSSO) {
|
||||
handlePopUpOpen("upgradePlan", { feature: "OIDC SSO", plan: "Pro" });
|
||||
return;
|
||||
}
|
||||
<p className="text-lg text-gray-200">SAML</p>
|
||||
<Button
|
||||
colorSchema="secondary"
|
||||
onClick={() => {
|
||||
if (!subscription?.samlSSO) {
|
||||
handlePopUpOpen("upgradePlan", { feature: "SAML SSO", plan: "Pro" });
|
||||
return;
|
||||
}
|
||||
|
||||
handlePopUpOpen("addOIDC");
|
||||
}}
|
||||
handlePopUpOpen("addSSO");
|
||||
}}
|
||||
>
|
||||
Connect
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
{shouldDisplaySection(LoginMethod.OIDC) && (
|
||||
<div
|
||||
className={twMerge(
|
||||
"mt-4 flex items-center justify-between",
|
||||
shouldDisplaySection(LoginMethod.LDAP) && "border-b border-mineshaft-500 pb-4"
|
||||
)}
|
||||
>
|
||||
Connect
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
{shouldDisplaySection(LoginMethod.LDAP) && (
|
||||
<div className="mt-4 flex items-center justify-between">
|
||||
<p className="text-lg text-gray-200">LDAP</p>
|
||||
<Button
|
||||
colorSchema="secondary"
|
||||
onClick={() => {
|
||||
if (!subscription?.ldap) {
|
||||
handlePopUpOpen("upgradePlan", { feature: "LDAP", plan: "Enterprise" });
|
||||
return;
|
||||
}
|
||||
<p className="text-lg text-gray-200">OIDC</p>
|
||||
<Button
|
||||
colorSchema="secondary"
|
||||
onClick={() => {
|
||||
if (!subscription?.oidcSSO) {
|
||||
handlePopUpOpen("upgradePlan", { feature: "OIDC SSO", plan: "Pro" });
|
||||
return;
|
||||
}
|
||||
|
||||
handlePopUpOpen("addLDAP");
|
||||
}}
|
||||
>
|
||||
Connect
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<SSOModal
|
||||
hideDelete
|
||||
popUp={popUp}
|
||||
handlePopUpClose={handlePopUpClose}
|
||||
handlePopUpToggle={handlePopUpToggle}
|
||||
/>
|
||||
<OIDCModal
|
||||
hideDelete
|
||||
popUp={popUp}
|
||||
handlePopUpClose={handlePopUpClose}
|
||||
handlePopUpToggle={handlePopUpToggle}
|
||||
/>
|
||||
<LDAPModal
|
||||
hideDelete
|
||||
popUp={popUp}
|
||||
handlePopUpClose={handlePopUpClose}
|
||||
handlePopUpToggle={handlePopUpToggle}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
handlePopUpOpen("addOIDC");
|
||||
}}
|
||||
>
|
||||
Connect
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
{shouldDisplaySection(LoginMethod.LDAP) && (
|
||||
<div className="mt-4 flex items-center justify-between">
|
||||
<p className="text-lg text-gray-200">LDAP</p>
|
||||
<Button
|
||||
colorSchema="secondary"
|
||||
onClick={() => {
|
||||
if (!subscription?.ldap) {
|
||||
handlePopUpOpen("upgradePlan", { feature: "LDAP", plan: "Enterprise" });
|
||||
return;
|
||||
}
|
||||
|
||||
handlePopUpOpen("addLDAP");
|
||||
}}
|
||||
>
|
||||
Connect
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<SSOModal
|
||||
hideDelete
|
||||
popUp={popUp}
|
||||
handlePopUpClose={handlePopUpClose}
|
||||
handlePopUpToggle={handlePopUpToggle}
|
||||
/>
|
||||
<OIDCModal
|
||||
hideDelete
|
||||
popUp={popUp}
|
||||
handlePopUpClose={handlePopUpClose}
|
||||
handlePopUpToggle={handlePopUpToggle}
|
||||
/>
|
||||
<LDAPModal
|
||||
hideDelete
|
||||
popUp={popUp}
|
||||
handlePopUpClose={handlePopUpClose}
|
||||
handlePopUpToggle={handlePopUpToggle}
|
||||
/>
|
||||
</>
|
||||
) : (
|
||||
<EmptyState title="" iconSize="2x" className="!pb-10 pt-14">
|
||||
<p className="text-center text-lg">Single Sign-On (SSO) has been disabled</p>
|
||||
<p className="text-center">Contact your server administrator</p>
|
||||
</EmptyState>
|
||||
);
|
||||
|
||||
if (areConfigsLoading) {
|
||||
return <ContentLoader />;
|
||||
|
@@ -21,12 +21,7 @@ type Props = {
|
||||
export const SecretSyncOptionsSection = ({ secretSync, onEditOptions }: Props) => {
|
||||
const {
|
||||
destination,
|
||||
syncOptions: {
|
||||
// appendSuffix,
|
||||
// prependPrefix,
|
||||
initialSyncBehavior,
|
||||
disableSecretDeletion
|
||||
}
|
||||
syncOptions: { initialSyncBehavior, disableSecretDeletion, keySchema }
|
||||
} = secretSync;
|
||||
|
||||
let AdditionalSyncOptionsComponent: ReactNode;
|
||||
@@ -88,8 +83,7 @@ export const SecretSyncOptionsSection = ({ secretSync, onEditOptions }: Props) =
|
||||
<GenericFieldLabel label="Initial Sync Behavior">
|
||||
{SECRET_SYNC_INITIAL_SYNC_BEHAVIOR_MAP[initialSyncBehavior](destination).name}
|
||||
</GenericFieldLabel>
|
||||
{/* <SecretSyncLabel label="Prefix">{prependPrefix}</SecretSyncLabel>
|
||||
<SecretSyncLabel label="Suffix">{appendSuffix}</SecretSyncLabel> */}
|
||||
<GenericFieldLabel label="Key Schema">{keySchema}</GenericFieldLabel>
|
||||
{AdditionalSyncOptionsComponent}
|
||||
{disableSecretDeletion && (
|
||||
<GenericFieldLabel label="Secret Deletion">
|
||||
|
Reference in New Issue
Block a user