mirror of
https://github.com/Infisical/infisical.git
synced 2025-08-24 20:43:19 +00:00
Compare commits
18 Commits
general-oi
...
infisical/
Author | SHA1 | Date | |
---|---|---|---|
|
d1eb350bdd | ||
|
0c1ccf7c2e | ||
|
b55a39dd24 | ||
|
7b880f85cc | ||
|
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({
|
oidcLogin({
|
||||||
email: claims.email,
|
email: claims.email,
|
||||||
externalId: claims.sub,
|
externalId: claims.sub,
|
||||||
firstName: claims.given_name ?? "",
|
firstName: claims.given_name ?? "",
|
||||||
lastName: claims.family_name ?? "",
|
lastName: claims.family_name ?? "",
|
||||||
orgId: org.id,
|
orgId: org.id,
|
||||||
groups: claims.groups as string[] | undefined,
|
groups,
|
||||||
callbackPort,
|
callbackPort,
|
||||||
manageGroupMemberships: oidcCfg.manageGroupMemberships
|
manageGroupMemberships: oidcCfg.manageGroupMemberships
|
||||||
})
|
})
|
||||||
|
@@ -2144,6 +2144,7 @@ export const SecretSyncs = {
|
|||||||
const destinationName = SECRET_SYNC_NAME_MAP[destination];
|
const destinationName = SECRET_SYNC_NAME_MAP[destination];
|
||||||
return {
|
return {
|
||||||
initialSyncBehavior: `Specify how Infisical should resolve the initial sync to the ${destinationName} destination.`,
|
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.`
|
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) => {
|
handler: async (req) => {
|
||||||
const workspace = await server.services.project.updateAuditLogsRetention({
|
const workspace = await server.services.project.updateAuditLogsRetention({
|
||||||
actorId: req.permission.id,
|
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 { BadRequestError, NotFoundError, PermissionBoundaryError, UnauthorizedError } from "@app/lib/errors";
|
||||||
import { extractIPDetails, isValidIpOrCidr } from "@app/lib/ip";
|
import { extractIPDetails, isValidIpOrCidr } from "@app/lib/ip";
|
||||||
import { logger } from "@app/lib/logger";
|
import { logger } from "@app/lib/logger";
|
||||||
import { blockLocalAndPrivateIpAddresses } from "@app/lib/validator";
|
|
||||||
|
|
||||||
import { ActorType, AuthTokenType } from "../auth/auth-type";
|
import { ActorType, AuthTokenType } from "../auth/auth-type";
|
||||||
import { TIdentityOrgDALFactory } from "../identity/identity-org-dal";
|
import { TIdentityOrgDALFactory } from "../identity/identity-org-dal";
|
||||||
@@ -59,9 +58,7 @@ export const identityOciAuthServiceFactory = ({
|
|||||||
|
|
||||||
const identityMembershipOrg = await identityOrgMembershipDAL.findOne({ identityId: identityOciAuth.identityId });
|
const identityMembershipOrg = await identityOrgMembershipDAL.findOne({ identityId: identityOciAuth.identityId });
|
||||||
|
|
||||||
await blockLocalAndPrivateIpAddresses(headers.host);
|
// Validate OCI host format. Ensures that the host is in "identity.<region>.oraclecloud.com" format.
|
||||||
|
|
||||||
// Validate OCI host format
|
|
||||||
if (!headers.host || !new RE2("^identity\\.([a-z]{2}-[a-z]+-[1-9])\\.oraclecloud\\.com$").test(headers.host)) {
|
if (!headers.host || !new RE2("^identity\\.([a-z]{2}-[a-z]+-[1-9])\\.oraclecloud\\.com$").test(headers.host)) {
|
||||||
throw new BadRequestError({
|
throw new BadRequestError({
|
||||||
message: "Invalid OCI host format. Expected format: identity.<region>.oraclecloud.com"
|
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 { getAwsConnectionConfig } from "@app/services/app-connection/aws/aws-connection-fns";
|
||||||
import { SecretSyncError } from "@app/services/secret-sync/secret-sync-errors";
|
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 { TSecretMap } from "@app/services/secret-sync/secret-sync-types";
|
||||||
|
|
||||||
import { TAwsParameterStoreSyncWithCredentials } from "./aws-parameter-store-sync-types";
|
import { TAwsParameterStoreSyncWithCredentials } from "./aws-parameter-store-sync-types";
|
||||||
@@ -389,6 +390,9 @@ export const AwsParameterStoreSyncFns = {
|
|||||||
for (const entry of Object.entries(awsParameterStoreSecretsRecord)) {
|
for (const entry of Object.entries(awsParameterStoreSecretsRecord)) {
|
||||||
const [key, parameter] = entry;
|
const [key, parameter] = entry;
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-continue
|
||||||
|
if (!matchesSchema(key, syncOptions.keySchema)) continue;
|
||||||
|
|
||||||
if (!(key in secretMap) || !secretMap[key].value) {
|
if (!(key in secretMap) || !secretMap[key].value) {
|
||||||
parametersToDelete.push(parameter);
|
parametersToDelete.push(parameter);
|
||||||
}
|
}
|
||||||
|
@@ -27,6 +27,7 @@ import {
|
|||||||
import { getAwsConnectionConfig } from "@app/services/app-connection/aws/aws-connection-fns";
|
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 { 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 { 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 { TSecretMap } from "@app/services/secret-sync/secret-sync-types";
|
||||||
|
|
||||||
import { TAwsSecretsManagerSyncWithCredentials } from "./aws-secrets-manager-sync-types";
|
import { TAwsSecretsManagerSyncWithCredentials } from "./aws-secrets-manager-sync-types";
|
||||||
@@ -399,6 +400,9 @@ export const AwsSecretsManagerSyncFns = {
|
|||||||
if (syncOptions.disableSecretDeletion) return;
|
if (syncOptions.disableSecretDeletion) return;
|
||||||
|
|
||||||
for await (const secretKey of Object.keys(awsSecretsRecord)) {
|
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) {
|
if (!(secretKey in secretMap) || !secretMap[secretKey].value) {
|
||||||
try {
|
try {
|
||||||
await deleteSecret(client, secretKey);
|
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 { getAzureConnectionAccessToken } from "@app/services/app-connection/azure-key-vault";
|
||||||
import { isAzureKeyVaultReference } from "@app/services/integration-auth/integration-sync-secret-fns";
|
import { isAzureKeyVaultReference } from "@app/services/integration-auth/integration-sync-secret-fns";
|
||||||
import { TKmsServiceFactory } from "@app/services/kms/kms-service";
|
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 { TSecretMap } from "@app/services/secret-sync/secret-sync-types";
|
||||||
|
|
||||||
import { TAzureAppConfigurationSyncWithCredentials } from "./azure-app-configuration-sync-types";
|
import { TAzureAppConfigurationSyncWithCredentials } from "./azure-app-configuration-sync-types";
|
||||||
@@ -139,6 +140,9 @@ export const azureAppConfigurationSyncFactory = ({
|
|||||||
if (secretSync.syncOptions.disableSecretDeletion) return;
|
if (secretSync.syncOptions.disableSecretDeletion) return;
|
||||||
|
|
||||||
for await (const key of Object.keys(azureAppConfigSecrets)) {
|
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];
|
const azureSecret = azureAppConfigSecrets[key];
|
||||||
if (
|
if (
|
||||||
!(key in secretMap) ||
|
!(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 { TAppConnectionDALFactory } from "@app/services/app-connection/app-connection-dal";
|
||||||
import { getAzureConnectionAccessToken } from "@app/services/app-connection/azure-key-vault";
|
import { getAzureConnectionAccessToken } from "@app/services/app-connection/azure-key-vault";
|
||||||
import { TKmsServiceFactory } from "@app/services/kms/kms-service";
|
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 { TSecretMap } from "@app/services/secret-sync/secret-sync-types";
|
||||||
|
|
||||||
import { SecretSyncError } from "../secret-sync-errors";
|
import { SecretSyncError } from "../secret-sync-errors";
|
||||||
@@ -192,7 +193,9 @@ export const azureKeyVaultSyncFactory = ({ kmsService, appConnectionDAL }: TAzur
|
|||||||
if (secretSync.syncOptions.disableSecretDeletion) return;
|
if (secretSync.syncOptions.disableSecretDeletion) return;
|
||||||
|
|
||||||
for await (const deleteSecretKey of deleteSecrets.filter(
|
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`, {
|
await request.delete(`${secretSync.destinationConfig.vaultBaseUrl}/secrets/${deleteSecretKey}?api-version=7.3`, {
|
||||||
headers: {
|
headers: {
|
||||||
|
@@ -12,6 +12,7 @@ import {
|
|||||||
TCamundaSyncWithCredentials
|
TCamundaSyncWithCredentials
|
||||||
} from "@app/services/secret-sync/camunda/camunda-sync-types";
|
} from "@app/services/secret-sync/camunda/camunda-sync-types";
|
||||||
import { SecretSyncError } from "@app/services/secret-sync/secret-sync-errors";
|
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";
|
import { TSecretMap } from "../secret-sync-types";
|
||||||
|
|
||||||
@@ -116,6 +117,9 @@ export const camundaSyncFactory = ({ kmsService, appConnectionDAL }: TCamundaSec
|
|||||||
if (secretSync.syncOptions.disableSecretDeletion) return;
|
if (secretSync.syncOptions.disableSecretDeletion) return;
|
||||||
|
|
||||||
for await (const secret of Object.keys(camundaSecrets)) {
|
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) {
|
if (!(secret in secretMap) || !secretMap[secret].value) {
|
||||||
try {
|
try {
|
||||||
await deleteCamundaSecret({
|
await deleteCamundaSecret({
|
||||||
|
@@ -11,6 +11,7 @@ import {
|
|||||||
TDatabricksSyncWithCredentials
|
TDatabricksSyncWithCredentials
|
||||||
} from "@app/services/secret-sync/databricks/databricks-sync-types";
|
} from "@app/services/secret-sync/databricks/databricks-sync-types";
|
||||||
import { SecretSyncError } from "@app/services/secret-sync/secret-sync-errors";
|
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 { SECRET_SYNC_NAME_MAP } from "@app/services/secret-sync/secret-sync-maps";
|
||||||
|
|
||||||
import { TSecretMap } from "../secret-sync-types";
|
import { TSecretMap } from "../secret-sync-types";
|
||||||
@@ -115,6 +116,9 @@ export const databricksSyncFactory = ({ kmsService, appConnectionDAL }: TDatabri
|
|||||||
if (secretSync.syncOptions.disableSecretDeletion) return;
|
if (secretSync.syncOptions.disableSecretDeletion) return;
|
||||||
|
|
||||||
for await (const secret of databricksSecretKeys) {
|
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)) {
|
if (!(secret.key in secretMap)) {
|
||||||
await deleteDatabricksSecrets({
|
await deleteDatabricksSecrets({
|
||||||
key: secret.key,
|
key: secret.key,
|
||||||
|
@@ -4,6 +4,7 @@ import { request } from "@app/lib/config/request";
|
|||||||
import { logger } from "@app/lib/logger";
|
import { logger } from "@app/lib/logger";
|
||||||
import { getGcpConnectionAuthToken } from "@app/services/app-connection/gcp";
|
import { getGcpConnectionAuthToken } from "@app/services/app-connection/gcp";
|
||||||
import { IntegrationUrls } from "@app/services/integration-auth/integration-list";
|
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 { SecretSyncError } from "../secret-sync-errors";
|
||||||
import { TSecretMap } from "../secret-sync-types";
|
import { TSecretMap } from "../secret-sync-types";
|
||||||
@@ -153,6 +154,9 @@ export const GcpSyncFns = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for await (const key of Object.keys(gcpSecrets)) {
|
for await (const key of Object.keys(gcpSecrets)) {
|
||||||
|
// eslint-disable-next-line no-continue
|
||||||
|
if (!matchesSchema(key, secretSync.syncOptions.keySchema)) continue;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (!(key in secretMap) || !secretMap[key].value) {
|
if (!(key in secretMap) || !secretMap[key].value) {
|
||||||
// eslint-disable-next-line no-continue
|
// eslint-disable-next-line no-continue
|
||||||
|
@@ -4,6 +4,7 @@ import sodium from "libsodium-wrappers";
|
|||||||
import { getGitHubClient } from "@app/services/app-connection/github";
|
import { getGitHubClient } from "@app/services/app-connection/github";
|
||||||
import { GitHubSyncScope, GitHubSyncVisibility } from "@app/services/secret-sync/github/github-sync-enums";
|
import { GitHubSyncScope, GitHubSyncVisibility } from "@app/services/secret-sync/github/github-sync-enums";
|
||||||
import { SecretSyncError } from "@app/services/secret-sync/secret-sync-errors";
|
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 { SECRET_SYNC_NAME_MAP } from "@app/services/secret-sync/secret-sync-maps";
|
||||||
import { TSecretMap } from "@app/services/secret-sync/secret-sync-types";
|
import { TSecretMap } from "@app/services/secret-sync/secret-sync-types";
|
||||||
|
|
||||||
@@ -222,6 +223,9 @@ export const GithubSyncFns = {
|
|||||||
if (secretSync.syncOptions.disableSecretDeletion) return;
|
if (secretSync.syncOptions.disableSecretDeletion) return;
|
||||||
|
|
||||||
for await (const encryptedSecret of encryptedSecrets) {
|
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)) {
|
if (!(encryptedSecret.name in secretMap)) {
|
||||||
await deleteSecret(client, secretSync, encryptedSecret);
|
await deleteSecret(client, secretSync, encryptedSecret);
|
||||||
}
|
}
|
||||||
|
@@ -11,6 +11,7 @@ import {
|
|||||||
TPostHCVaultVariable
|
TPostHCVaultVariable
|
||||||
} from "@app/services/secret-sync/hc-vault/hc-vault-sync-types";
|
} from "@app/services/secret-sync/hc-vault/hc-vault-sync-types";
|
||||||
import { SecretSyncError } from "@app/services/secret-sync/secret-sync-errors";
|
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 { TSecretMap } from "@app/services/secret-sync/secret-sync-types";
|
||||||
|
|
||||||
const listHCVaultVariables = async ({ instanceUrl, namespace, mount, accessToken, path }: THCVaultListVariables) => {
|
const listHCVaultVariables = async ({ instanceUrl, namespace, mount, accessToken, path }: THCVaultListVariables) => {
|
||||||
@@ -68,7 +69,7 @@ export const HCVaultSyncFns = {
|
|||||||
const {
|
const {
|
||||||
connection,
|
connection,
|
||||||
destinationConfig: { mount, path },
|
destinationConfig: { mount, path },
|
||||||
syncOptions: { disableSecretDeletion }
|
syncOptions: { disableSecretDeletion, keySchema }
|
||||||
} = secretSync;
|
} = secretSync;
|
||||||
|
|
||||||
const { namespace } = connection.credentials;
|
const { namespace } = connection.credentials;
|
||||||
@@ -95,6 +96,9 @@ export const HCVaultSyncFns = {
|
|||||||
if (disableSecretDeletion) return;
|
if (disableSecretDeletion) return;
|
||||||
|
|
||||||
for await (const [key] of Object.entries(variables)) {
|
for await (const [key] of Object.entries(variables)) {
|
||||||
|
// eslint-disable-next-line no-continue
|
||||||
|
if (!matchesSchema(key, keySchema)) continue;
|
||||||
|
|
||||||
if (!(key in secretMap)) {
|
if (!(key in secretMap)) {
|
||||||
delete variables[key];
|
delete variables[key];
|
||||||
tainted = true;
|
tainted = true;
|
||||||
|
@@ -2,6 +2,7 @@ import { request } from "@app/lib/config/request";
|
|||||||
import { logger } from "@app/lib/logger";
|
import { logger } from "@app/lib/logger";
|
||||||
import { IntegrationUrls } from "@app/services/integration-auth/integration-list";
|
import { IntegrationUrls } from "@app/services/integration-auth/integration-list";
|
||||||
import { SecretSyncError } from "@app/services/secret-sync/secret-sync-errors";
|
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 { SECRET_SYNC_NAME_MAP } from "@app/services/secret-sync/secret-sync-maps";
|
||||||
import { TSecretMap } from "@app/services/secret-sync/secret-sync-types";
|
import { TSecretMap } from "@app/services/secret-sync/secret-sync-types";
|
||||||
|
|
||||||
@@ -199,6 +200,9 @@ export const HumanitecSyncFns = {
|
|||||||
if (secretSync.syncOptions.disableSecretDeletion) return;
|
if (secretSync.syncOptions.disableSecretDeletion) return;
|
||||||
|
|
||||||
for await (const humanitecSecret of humanitecSecrets) {
|
for await (const humanitecSecret of humanitecSecrets) {
|
||||||
|
// eslint-disable-next-line no-continue
|
||||||
|
if (!matchesSchema(humanitecSecret.key, secretSync.syncOptions.keySchema)) continue;
|
||||||
|
|
||||||
if (!secretMap[humanitecSecret.key]) {
|
if (!secretMap[humanitecSecret.key]) {
|
||||||
await deleteSecret(secretSync, humanitecSecret);
|
await deleteSecret(secretSync, humanitecSecret);
|
||||||
}
|
}
|
||||||
|
@@ -11,6 +11,7 @@ import {
|
|||||||
TUpdateOCIVaultVariable
|
TUpdateOCIVaultVariable
|
||||||
} from "@app/services/secret-sync/oci-vault/oci-vault-sync-types";
|
} from "@app/services/secret-sync/oci-vault/oci-vault-sync-types";
|
||||||
import { SecretSyncError } from "@app/services/secret-sync/secret-sync-errors";
|
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 { TSecretMap } from "@app/services/secret-sync/secret-sync-types";
|
||||||
|
|
||||||
const listOCIVaultVariables = async ({ provider, compartmentId, vaultId, onlyActive }: TOCIVaultListVariables) => {
|
const listOCIVaultVariables = async ({ provider, compartmentId, vaultId, onlyActive }: TOCIVaultListVariables) => {
|
||||||
@@ -211,6 +212,9 @@ export const OCIVaultSyncFns = {
|
|||||||
|
|
||||||
// Update and delete secrets
|
// Update and delete secrets
|
||||||
for await (const [key, variable] of Object.entries(variables)) {
|
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
|
// Only update / delete active secrets
|
||||||
if (variable.lifecycleState === vault.models.SecretSummary.LifecycleState.Active) {
|
if (variable.lifecycleState === vault.models.SecretSummary.LifecycleState.Active) {
|
||||||
if (key in secretMap && secretMap[key].value.length > 0) {
|
if (key in secretMap && secretMap[key].value.length > 0) {
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
import { AxiosError } from "axios";
|
import { AxiosError } from "axios";
|
||||||
|
import RE2 from "re2";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
AWS_PARAMETER_STORE_SYNC_LIST_OPTION,
|
AWS_PARAMETER_STORE_SYNC_LIST_OPTION,
|
||||||
@@ -61,45 +62,63 @@ type TSyncSecretDeps = {
|
|||||||
kmsService: Pick<TKmsServiceFactory, "createCipherPairWithDataKey">;
|
kmsService: Pick<TKmsServiceFactory, "createCipherPairWithDataKey">;
|
||||||
};
|
};
|
||||||
|
|
||||||
// const addAffixes = (secretSync: TSecretSyncWithCredentials, unprocessedSecretMap: TSecretMap) => {
|
// Add schema to secret keys
|
||||||
// let secretMap = { ...unprocessedSecretMap };
|
const addSchema = (unprocessedSecretMap: TSecretMap, schema?: string): TSecretMap => {
|
||||||
//
|
if (!schema) return unprocessedSecretMap;
|
||||||
// const { appendSuffix, prependPrefix } = secretSync.syncOptions;
|
|
||||||
//
|
const processedSecretMap: TSecretMap = {};
|
||||||
// if (appendSuffix || prependPrefix) {
|
|
||||||
// secretMap = {};
|
for (const [key, value] of Object.entries(unprocessedSecretMap)) {
|
||||||
// Object.entries(unprocessedSecretMap).forEach(([key, value]) => {
|
const newKey = new RE2("{{secretKey}}").replace(schema, key);
|
||||||
// secretMap[`${prependPrefix || ""}${key}${appendSuffix || ""}`] = value;
|
processedSecretMap[newKey] = value;
|
||||||
// });
|
}
|
||||||
// }
|
|
||||||
//
|
return processedSecretMap;
|
||||||
// return secretMap;
|
};
|
||||||
// };
|
|
||||||
//
|
// Strip schema from secret keys
|
||||||
// const stripAffixes = (secretSync: TSecretSyncWithCredentials, unprocessedSecretMap: TSecretMap) => {
|
const stripSchema = (unprocessedSecretMap: TSecretMap, schema?: string): TSecretMap => {
|
||||||
// let secretMap = { ...unprocessedSecretMap };
|
if (!schema) return unprocessedSecretMap;
|
||||||
//
|
|
||||||
// const { appendSuffix, prependPrefix } = secretSync.syncOptions;
|
const [prefix, suffix] = schema.split("{{secretKey}}");
|
||||||
//
|
|
||||||
// if (appendSuffix || prependPrefix) {
|
const strippedMap: TSecretMap = {};
|
||||||
// secretMap = {};
|
|
||||||
// Object.entries(unprocessedSecretMap).forEach(([key, value]) => {
|
for (const [key, value] of Object.entries(unprocessedSecretMap)) {
|
||||||
// let processedKey = key;
|
if (!key.startsWith(prefix) || !key.endsWith(suffix)) {
|
||||||
//
|
// eslint-disable-next-line no-continue
|
||||||
// if (prependPrefix && processedKey.startsWith(prependPrefix)) {
|
continue;
|
||||||
// processedKey = processedKey.slice(prependPrefix.length);
|
}
|
||||||
// }
|
|
||||||
//
|
const strippedKey = key.slice(prefix.length, key.length - suffix.length);
|
||||||
// if (appendSuffix && processedKey.endsWith(appendSuffix)) {
|
strippedMap[strippedKey] = value;
|
||||||
// processedKey = processedKey.slice(0, -appendSuffix.length);
|
}
|
||||||
// }
|
|
||||||
//
|
return strippedMap;
|
||||||
// secretMap[processedKey] = value;
|
};
|
||||||
// });
|
|
||||||
// }
|
// Checks if a key matches a schema
|
||||||
//
|
export const matchesSchema = (key: string, schema?: string): boolean => {
|
||||||
// return secretMap;
|
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 = {
|
export const SecretSyncFns = {
|
||||||
syncSecrets: (
|
syncSecrets: (
|
||||||
@@ -107,51 +126,51 @@ export const SecretSyncFns = {
|
|||||||
secretMap: TSecretMap,
|
secretMap: TSecretMap,
|
||||||
{ kmsService, appConnectionDAL }: TSyncSecretDeps
|
{ kmsService, appConnectionDAL }: TSyncSecretDeps
|
||||||
): Promise<void> => {
|
): Promise<void> => {
|
||||||
// const affixedSecretMap = addAffixes(secretSync, secretMap);
|
const schemaSecretMap = addSchema(secretMap, secretSync.syncOptions.keySchema);
|
||||||
|
|
||||||
switch (secretSync.destination) {
|
switch (secretSync.destination) {
|
||||||
case SecretSync.AWSParameterStore:
|
case SecretSync.AWSParameterStore:
|
||||||
return AwsParameterStoreSyncFns.syncSecrets(secretSync, secretMap);
|
return AwsParameterStoreSyncFns.syncSecrets(secretSync, schemaSecretMap);
|
||||||
case SecretSync.AWSSecretsManager:
|
case SecretSync.AWSSecretsManager:
|
||||||
return AwsSecretsManagerSyncFns.syncSecrets(secretSync, secretMap);
|
return AwsSecretsManagerSyncFns.syncSecrets(secretSync, schemaSecretMap);
|
||||||
case SecretSync.GitHub:
|
case SecretSync.GitHub:
|
||||||
return GithubSyncFns.syncSecrets(secretSync, secretMap);
|
return GithubSyncFns.syncSecrets(secretSync, schemaSecretMap);
|
||||||
case SecretSync.GCPSecretManager:
|
case SecretSync.GCPSecretManager:
|
||||||
return GcpSyncFns.syncSecrets(secretSync, secretMap);
|
return GcpSyncFns.syncSecrets(secretSync, schemaSecretMap);
|
||||||
case SecretSync.AzureKeyVault:
|
case SecretSync.AzureKeyVault:
|
||||||
return azureKeyVaultSyncFactory({
|
return azureKeyVaultSyncFactory({
|
||||||
appConnectionDAL,
|
appConnectionDAL,
|
||||||
kmsService
|
kmsService
|
||||||
}).syncSecrets(secretSync, secretMap);
|
}).syncSecrets(secretSync, schemaSecretMap);
|
||||||
case SecretSync.AzureAppConfiguration:
|
case SecretSync.AzureAppConfiguration:
|
||||||
return azureAppConfigurationSyncFactory({
|
return azureAppConfigurationSyncFactory({
|
||||||
appConnectionDAL,
|
appConnectionDAL,
|
||||||
kmsService
|
kmsService
|
||||||
}).syncSecrets(secretSync, secretMap);
|
}).syncSecrets(secretSync, schemaSecretMap);
|
||||||
case SecretSync.Databricks:
|
case SecretSync.Databricks:
|
||||||
return databricksSyncFactory({
|
return databricksSyncFactory({
|
||||||
appConnectionDAL,
|
appConnectionDAL,
|
||||||
kmsService
|
kmsService
|
||||||
}).syncSecrets(secretSync, secretMap);
|
}).syncSecrets(secretSync, schemaSecretMap);
|
||||||
case SecretSync.Humanitec:
|
case SecretSync.Humanitec:
|
||||||
return HumanitecSyncFns.syncSecrets(secretSync, secretMap);
|
return HumanitecSyncFns.syncSecrets(secretSync, schemaSecretMap);
|
||||||
case SecretSync.TerraformCloud:
|
case SecretSync.TerraformCloud:
|
||||||
return TerraformCloudSyncFns.syncSecrets(secretSync, secretMap);
|
return TerraformCloudSyncFns.syncSecrets(secretSync, schemaSecretMap);
|
||||||
case SecretSync.Camunda:
|
case SecretSync.Camunda:
|
||||||
return camundaSyncFactory({
|
return camundaSyncFactory({
|
||||||
appConnectionDAL,
|
appConnectionDAL,
|
||||||
kmsService
|
kmsService
|
||||||
}).syncSecrets(secretSync, secretMap);
|
}).syncSecrets(secretSync, schemaSecretMap);
|
||||||
case SecretSync.Vercel:
|
case SecretSync.Vercel:
|
||||||
return VercelSyncFns.syncSecrets(secretSync, secretMap);
|
return VercelSyncFns.syncSecrets(secretSync, schemaSecretMap);
|
||||||
case SecretSync.Windmill:
|
case SecretSync.Windmill:
|
||||||
return WindmillSyncFns.syncSecrets(secretSync, secretMap);
|
return WindmillSyncFns.syncSecrets(secretSync, schemaSecretMap);
|
||||||
case SecretSync.HCVault:
|
case SecretSync.HCVault:
|
||||||
return HCVaultSyncFns.syncSecrets(secretSync, secretMap);
|
return HCVaultSyncFns.syncSecrets(secretSync, schemaSecretMap);
|
||||||
case SecretSync.TeamCity:
|
case SecretSync.TeamCity:
|
||||||
return TeamCitySyncFns.syncSecrets(secretSync, secretMap);
|
return TeamCitySyncFns.syncSecrets(secretSync, schemaSecretMap);
|
||||||
case SecretSync.OCIVault:
|
case SecretSync.OCIVault:
|
||||||
return OCIVaultSyncFns.syncSecrets(secretSync, secretMap);
|
return OCIVaultSyncFns.syncSecrets(secretSync, schemaSecretMap);
|
||||||
default:
|
default:
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Unhandled sync destination for sync secrets fns: ${(secretSync as TSecretSyncWithCredentials).destination}`
|
`Unhandled sync destination for sync secrets fns: ${(secretSync as TSecretSyncWithCredentials).destination}`
|
||||||
@@ -226,59 +245,58 @@ export const SecretSyncFns = {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return secretMap;
|
return stripSchema(filterForSchema(secretMap), secretSync.syncOptions.keySchema);
|
||||||
// return stripAffixes(secretSync, secretMap);
|
|
||||||
},
|
},
|
||||||
removeSecrets: (
|
removeSecrets: (
|
||||||
secretSync: TSecretSyncWithCredentials,
|
secretSync: TSecretSyncWithCredentials,
|
||||||
secretMap: TSecretMap,
|
secretMap: TSecretMap,
|
||||||
{ kmsService, appConnectionDAL }: TSyncSecretDeps
|
{ kmsService, appConnectionDAL }: TSyncSecretDeps
|
||||||
): Promise<void> => {
|
): Promise<void> => {
|
||||||
// const affixedSecretMap = addAffixes(secretSync, secretMap);
|
const schemaSecretMap = addSchema(secretMap, secretSync.syncOptions.keySchema);
|
||||||
|
|
||||||
switch (secretSync.destination) {
|
switch (secretSync.destination) {
|
||||||
case SecretSync.AWSParameterStore:
|
case SecretSync.AWSParameterStore:
|
||||||
return AwsParameterStoreSyncFns.removeSecrets(secretSync, secretMap);
|
return AwsParameterStoreSyncFns.removeSecrets(secretSync, schemaSecretMap);
|
||||||
case SecretSync.AWSSecretsManager:
|
case SecretSync.AWSSecretsManager:
|
||||||
return AwsSecretsManagerSyncFns.removeSecrets(secretSync, secretMap);
|
return AwsSecretsManagerSyncFns.removeSecrets(secretSync, schemaSecretMap);
|
||||||
case SecretSync.GitHub:
|
case SecretSync.GitHub:
|
||||||
return GithubSyncFns.removeSecrets(secretSync, secretMap);
|
return GithubSyncFns.removeSecrets(secretSync, schemaSecretMap);
|
||||||
case SecretSync.GCPSecretManager:
|
case SecretSync.GCPSecretManager:
|
||||||
return GcpSyncFns.removeSecrets(secretSync, secretMap);
|
return GcpSyncFns.removeSecrets(secretSync, schemaSecretMap);
|
||||||
case SecretSync.AzureKeyVault:
|
case SecretSync.AzureKeyVault:
|
||||||
return azureKeyVaultSyncFactory({
|
return azureKeyVaultSyncFactory({
|
||||||
appConnectionDAL,
|
appConnectionDAL,
|
||||||
kmsService
|
kmsService
|
||||||
}).removeSecrets(secretSync, secretMap);
|
}).removeSecrets(secretSync, schemaSecretMap);
|
||||||
case SecretSync.AzureAppConfiguration:
|
case SecretSync.AzureAppConfiguration:
|
||||||
return azureAppConfigurationSyncFactory({
|
return azureAppConfigurationSyncFactory({
|
||||||
appConnectionDAL,
|
appConnectionDAL,
|
||||||
kmsService
|
kmsService
|
||||||
}).removeSecrets(secretSync, secretMap);
|
}).removeSecrets(secretSync, schemaSecretMap);
|
||||||
case SecretSync.Databricks:
|
case SecretSync.Databricks:
|
||||||
return databricksSyncFactory({
|
return databricksSyncFactory({
|
||||||
appConnectionDAL,
|
appConnectionDAL,
|
||||||
kmsService
|
kmsService
|
||||||
}).removeSecrets(secretSync, secretMap);
|
}).removeSecrets(secretSync, schemaSecretMap);
|
||||||
case SecretSync.Humanitec:
|
case SecretSync.Humanitec:
|
||||||
return HumanitecSyncFns.removeSecrets(secretSync, secretMap);
|
return HumanitecSyncFns.removeSecrets(secretSync, schemaSecretMap);
|
||||||
case SecretSync.TerraformCloud:
|
case SecretSync.TerraformCloud:
|
||||||
return TerraformCloudSyncFns.removeSecrets(secretSync, secretMap);
|
return TerraformCloudSyncFns.removeSecrets(secretSync, schemaSecretMap);
|
||||||
case SecretSync.Camunda:
|
case SecretSync.Camunda:
|
||||||
return camundaSyncFactory({
|
return camundaSyncFactory({
|
||||||
appConnectionDAL,
|
appConnectionDAL,
|
||||||
kmsService
|
kmsService
|
||||||
}).removeSecrets(secretSync, secretMap);
|
}).removeSecrets(secretSync, schemaSecretMap);
|
||||||
case SecretSync.Vercel:
|
case SecretSync.Vercel:
|
||||||
return VercelSyncFns.removeSecrets(secretSync, secretMap);
|
return VercelSyncFns.removeSecrets(secretSync, schemaSecretMap);
|
||||||
case SecretSync.Windmill:
|
case SecretSync.Windmill:
|
||||||
return WindmillSyncFns.removeSecrets(secretSync, secretMap);
|
return WindmillSyncFns.removeSecrets(secretSync, schemaSecretMap);
|
||||||
case SecretSync.HCVault:
|
case SecretSync.HCVault:
|
||||||
return HCVaultSyncFns.removeSecrets(secretSync, secretMap);
|
return HCVaultSyncFns.removeSecrets(secretSync, schemaSecretMap);
|
||||||
case SecretSync.TeamCity:
|
case SecretSync.TeamCity:
|
||||||
return TeamCitySyncFns.removeSecrets(secretSync, secretMap);
|
return TeamCitySyncFns.removeSecrets(secretSync, schemaSecretMap);
|
||||||
case SecretSync.OCIVault:
|
case SecretSync.OCIVault:
|
||||||
return OCIVaultSyncFns.removeSecrets(secretSync, secretMap);
|
return OCIVaultSyncFns.removeSecrets(secretSync, schemaSecretMap);
|
||||||
default:
|
default:
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Unhandled sync destination for remove secrets fns: ${(secretSync as TSecretSyncWithCredentials).destination}`
|
`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 { AnyZodObject, z } from "zod";
|
||||||
|
|
||||||
import { SecretSyncsSchema } from "@app/db/schemas/secret-syncs";
|
import { SecretSyncsSchema } from "@app/db/schemas/secret-syncs";
|
||||||
@@ -24,6 +25,14 @@ const BaseSyncOptionsSchema = <T extends AnyZodObject | undefined = undefined>({
|
|||||||
? z.nativeEnum(SecretSyncInitialSyncBehavior)
|
? z.nativeEnum(SecretSyncInitialSyncBehavior)
|
||||||
: z.literal(SecretSyncInitialSyncBehavior.OverwriteDestination)
|
: z.literal(SecretSyncInitialSyncBehavior.OverwriteDestination)
|
||||||
).describe(SecretSyncs.SYNC_OPTIONS(destination).initialSyncBehavior),
|
).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, slashes, and the {{secretKey}} placeholder."
|
||||||
|
})
|
||||||
|
.describe(SecretSyncs.SYNC_OPTIONS(destination).keySchema),
|
||||||
disableSecretDeletion: z.boolean().optional().describe(SecretSyncs.SYNC_OPTIONS(destination).disableSecretDeletion)
|
disableSecretDeletion: z.boolean().optional().describe(SecretSyncs.SYNC_OPTIONS(destination).disableSecretDeletion)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
import { request } from "@app/lib/config/request";
|
import { request } from "@app/lib/config/request";
|
||||||
import { getTeamCityInstanceUrl } from "@app/services/app-connection/teamcity";
|
import { getTeamCityInstanceUrl } from "@app/services/app-connection/teamcity";
|
||||||
import { SecretSyncError } from "@app/services/secret-sync/secret-sync-errors";
|
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 { TSecretMap } from "@app/services/secret-sync/secret-sync-types";
|
||||||
import {
|
import {
|
||||||
TDeleteTeamCityVariable,
|
TDeleteTeamCityVariable,
|
||||||
@@ -125,6 +126,9 @@ export const TeamCitySyncFns = {
|
|||||||
const variables = await listTeamCityVariables({ instanceUrl, accessToken, project, buildConfig });
|
const variables = await listTeamCityVariables({ instanceUrl, accessToken, project, buildConfig });
|
||||||
|
|
||||||
for await (const [key, variable] of Object.entries(variables)) {
|
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)) {
|
if (!(key in secretMap)) {
|
||||||
try {
|
try {
|
||||||
await deleteTeamCityVariable({
|
await deleteTeamCityVariable({
|
||||||
|
@@ -4,6 +4,7 @@ import { AxiosResponse } from "axios";
|
|||||||
import { request } from "@app/lib/config/request";
|
import { request } from "@app/lib/config/request";
|
||||||
import { IntegrationUrls } from "@app/services/integration-auth/integration-list";
|
import { IntegrationUrls } from "@app/services/integration-auth/integration-list";
|
||||||
import { SecretSyncError } from "@app/services/secret-sync/secret-sync-errors";
|
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 { TSecretMap } from "@app/services/secret-sync/secret-sync-types";
|
||||||
|
|
||||||
import { SECRET_SYNC_NAME_MAP } from "../secret-sync-maps";
|
import { SECRET_SYNC_NAME_MAP } from "../secret-sync-maps";
|
||||||
@@ -231,6 +232,9 @@ export const TerraformCloudSyncFns = {
|
|||||||
if (secretSync.syncOptions.disableSecretDeletion) return;
|
if (secretSync.syncOptions.disableSecretDeletion) return;
|
||||||
|
|
||||||
for (const terraformCloudVariable of terraformCloudVariables) {
|
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)) {
|
if (!Object.prototype.hasOwnProperty.call(secretMap, terraformCloudVariable.key)) {
|
||||||
await deleteVariable(secretSync, terraformCloudVariable);
|
await deleteVariable(secretSync, terraformCloudVariable);
|
||||||
}
|
}
|
||||||
|
@@ -2,6 +2,7 @@
|
|||||||
import { request } from "@app/lib/config/request";
|
import { request } from "@app/lib/config/request";
|
||||||
import { IntegrationUrls } from "@app/services/integration-auth/integration-list";
|
import { IntegrationUrls } from "@app/services/integration-auth/integration-list";
|
||||||
import { SecretSyncError } from "@app/services/secret-sync/secret-sync-errors";
|
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 { TSecretMap } from "@app/services/secret-sync/secret-sync-types";
|
||||||
|
|
||||||
import { VercelEnvironmentType } from "./vercel-sync-enums";
|
import { VercelEnvironmentType } from "./vercel-sync-enums";
|
||||||
@@ -290,6 +291,9 @@ export const VercelSyncFns = {
|
|||||||
if (secretSync.syncOptions.disableSecretDeletion) return;
|
if (secretSync.syncOptions.disableSecretDeletion) return;
|
||||||
|
|
||||||
for await (const vercelSecret of vercelSecrets) {
|
for await (const vercelSecret of vercelSecrets) {
|
||||||
|
// eslint-disable-next-line no-continue
|
||||||
|
if (!matchesSchema(vercelSecret.key, secretSync.syncOptions.keySchema)) continue;
|
||||||
|
|
||||||
if (!secretMap[vercelSecret.key]) {
|
if (!secretMap[vercelSecret.key]) {
|
||||||
await deleteSecret(secretSync, vercelSecret);
|
await deleteSecret(secretSync, vercelSecret);
|
||||||
}
|
}
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
import { request } from "@app/lib/config/request";
|
import { request } from "@app/lib/config/request";
|
||||||
import { getWindmillInstanceUrl } from "@app/services/app-connection/windmill";
|
import { getWindmillInstanceUrl } from "@app/services/app-connection/windmill";
|
||||||
import { SecretSyncError } from "@app/services/secret-sync/secret-sync-errors";
|
import { SecretSyncError } from "@app/services/secret-sync/secret-sync-errors";
|
||||||
|
import { matchesSchema } from "@app/services/secret-sync/secret-sync-fns";
|
||||||
import {
|
import {
|
||||||
TDeleteWindmillVariable,
|
TDeleteWindmillVariable,
|
||||||
TPostWindmillVariable,
|
TPostWindmillVariable,
|
||||||
@@ -128,7 +129,7 @@ export const WindmillSyncFns = {
|
|||||||
const {
|
const {
|
||||||
connection,
|
connection,
|
||||||
destinationConfig: { path },
|
destinationConfig: { path },
|
||||||
syncOptions: { disableSecretDeletion }
|
syncOptions: { disableSecretDeletion, keySchema }
|
||||||
} = secretSync;
|
} = secretSync;
|
||||||
|
|
||||||
// url needs to be lowercase
|
// url needs to be lowercase
|
||||||
@@ -169,6 +170,9 @@ export const WindmillSyncFns = {
|
|||||||
if (disableSecretDeletion) return;
|
if (disableSecretDeletion) return;
|
||||||
|
|
||||||
for await (const [key, variable] of Object.entries(variables)) {
|
for await (const [key, variable] of Object.entries(variables)) {
|
||||||
|
// eslint-disable-next-line no-continue
|
||||||
|
if (!matchesSchema(key, keySchema)) continue;
|
||||||
|
|
||||||
if (!(key in secretMap)) {
|
if (!(key in secretMap)) {
|
||||||
try {
|
try {
|
||||||
await deleteWindmillVariable({
|
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>
|
||||||
<Step title="Start integration">
|
<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.
|
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:
|
Here's some guidance on each field:
|
||||||
|
|
||||||
- Project Environment: The environment in the current Infisical project from which you want to sync secrets from.
|
- 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`).
|
- 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.
|
- 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.
|
- **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 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.
|
- **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>
|
</Step>
|
||||||
</Steps>
|
</Steps>
|
||||||
@@ -46,27 +46,26 @@ description: "How to sync secrets from Infisical to Heroku"
|
|||||||
<Step title="Create an API client in Heroku">
|
<Step title="Create an API client in Heroku">
|
||||||
Navigate to your user Account settings > Applications to create a new API client.
|
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`.
|
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>
|
||||||
<Step title="Add your Heroku API client credentials to Infisical">
|
<Step title="Add your Heroku API client credentials to Infisical">
|
||||||
Obtain the **Client ID** and **Client Secret** for your Heroku API client.
|
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.
|
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_ID_HEROKU`: The **Client ID** of your Heroku API client.
|
||||||
- `CLIENT_SECRET_HEROKU`: The **Client Secret** 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.
|
Once added, restart your Infisical instance and use the Heroku integration.
|
||||||
</Step>
|
</Step>
|
||||||
</Steps>
|
</Steps>
|
||||||
</Tab>
|
</Tab>
|
||||||
</Tabs>
|
</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.
|
- **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 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.
|
- **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.
|
- **KMS Key**: The AWS KMS key ID or alias to encrypt parameters with.
|
||||||
- **Tags**: Optional resource tags to add to parameters synced by Infisical.
|
- **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.
|
- **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.
|
- **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 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.
|
- **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.
|
- **KMS Key**: The AWS KMS key ID or alias to encrypt secrets with.
|
||||||
- **Tags**: Optional tags to add to secrets synced by Infisical.
|
- **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.
|
- **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.
|
- **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 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.
|
- **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.
|
- **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.
|
- **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.
|
- **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 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.
|
- **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.
|
- **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.
|
- **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.
|
- **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 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.
|
- **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.
|
- **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.
|
- **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>
|
<Note>
|
||||||
Databricks does not support importing secrets.
|
Databricks does not support importing secrets.
|
||||||
</Note>
|
</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.
|
- **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.
|
- **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.
|
- **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 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.
|
- **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.
|
- **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.
|
- **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>
|
<Note>
|
||||||
GitHub does not support importing secrets.
|
GitHub does not support importing secrets.
|
||||||
</Note>
|
</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.
|
- **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.
|
- **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.
|
- **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 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.
|
- **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.
|
- **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.
|
- **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>
|
</Step>
|
||||||
|
@@ -55,6 +55,10 @@ description: "Learn how to configure a Humanitec Sync for Infisical."
|
|||||||
<Note>
|
<Note>
|
||||||
Humanitec does not support importing secrets.
|
Humanitec does not support importing secrets.
|
||||||
</Note>
|
</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.
|
- **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.
|
- **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.
|
- **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 OCI Vault when keys conflict.
|
- **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.
|
- **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.
|
- **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.
|
- **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>
|
</Step>
|
||||||
|
@@ -93,4 +93,28 @@ via the UI or API for the third-party service you intend to sync secrets to.
|
|||||||
<Note>
|
<Note>
|
||||||
Infisical is continuously expanding it's Secret Sync third-party service support. If the service you need isn't available,
|
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 .
|
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 let you control how Infisical names your secret keys when syncing to external destinations. This makes it clear which secrets are managed by Infisical and prevents accidental changes to unrelated secrets.
|
||||||
|
|
||||||
|
A Key Schema adds a prefix, suffix, or format to your secrets before they reach the destination.
|
||||||
|
|
||||||
|
This example demonstrates key behavior if the schema was set to `INFISICAL_{{secretKey}}`:
|
||||||
|
|
||||||
|
<div align="center">
|
||||||
|
```mermaid
|
||||||
|
graph LR
|
||||||
|
A[SECRET_1] --> T["Syncs as"] --> B[INFISICAL_SECRET_1]
|
||||||
|
|
||||||
|
style A fill:#E6F4FF,stroke:#0096D6,stroke-width:2px,color:black,rx:15px
|
||||||
|
style B fill:#F4FFE6,stroke:#96D600,stroke-width:2px,color:black,rx:15px
|
||||||
|
style T fill:#FFF2B2,stroke:#E6C34A,stroke-width:2px,color:black,rx:2px,font-size:12px
|
||||||
|
|
||||||
|
```
|
||||||
|
</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>
|
<Note>
|
||||||
Infisical only syncs secrets from within the target scope; inherited secrets will not be imported.
|
Infisical only syncs secrets from within the target scope; inherited secrets will not be imported.
|
||||||
</Note>
|
</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.
|
- **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.
|
- **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>
|
<Note>
|
||||||
Terraform Cloud does not support importing secrets.
|
Terraform Cloud does not support importing secrets.
|
||||||
</Note>
|
</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.
|
- **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.
|
- **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.
|
- **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 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.
|
- **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.
|
- **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.
|
- **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.
|
- **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 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.
|
- **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.
|
- **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.
|
- **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,
|
handleSubmit,
|
||||||
control,
|
control,
|
||||||
formState: { isSubmitting, isDirty }
|
formState: { isSubmitting, isDirty }
|
||||||
} = useForm<TFormData>({ resolver: zodResolver(FormSchema) });
|
} = useForm<TFormData>({
|
||||||
|
resolver: zodResolver(FormSchema)
|
||||||
|
});
|
||||||
|
|
||||||
const triggerImportSecrets = useTriggerSecretSyncImportSecrets();
|
const triggerImportSecrets = useTriggerSecretSyncImportSecrets();
|
||||||
|
|
||||||
|
@@ -1,9 +1,13 @@
|
|||||||
import { ReactNode } from "react";
|
import { ReactNode } from "react";
|
||||||
import { Controller, useFormContext } from "react-hook-form";
|
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 { 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 { SECRET_SYNC_INITIAL_SYNC_BEHAVIOR_MAP, SECRET_SYNC_MAP } from "@app/helpers/secretSyncs";
|
||||||
import { SecretSync, useSecretSyncOption } from "@app/hooks/api/secretSyncs";
|
import { SecretSync, useSecretSyncOption } from "@app/hooks/api/secretSyncs";
|
||||||
|
|
||||||
@@ -122,6 +126,45 @@ 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"
|
||||||
|
>
|
||||||
|
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}
|
{AdditionalSyncOptionsFieldsComponent}
|
||||||
<Controller
|
<Controller
|
||||||
control={control}
|
control={control}
|
||||||
@@ -161,34 +204,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,
|
connection,
|
||||||
environment,
|
environment,
|
||||||
secretPath,
|
secretPath,
|
||||||
syncOptions: {
|
syncOptions: { disableSecretDeletion, initialSyncBehavior, keySchema },
|
||||||
// appendSuffix, prependPrefix,
|
|
||||||
disableSecretDeletion,
|
|
||||||
initialSyncBehavior
|
|
||||||
},
|
|
||||||
destination,
|
destination,
|
||||||
isAutoSyncEnabled
|
isAutoSyncEnabled
|
||||||
} = watch();
|
} = watch();
|
||||||
@@ -137,8 +133,7 @@ export const SecretSyncReviewFields = () => {
|
|||||||
<GenericFieldLabel label="Initial Sync Behavior">
|
<GenericFieldLabel label="Initial Sync Behavior">
|
||||||
{SECRET_SYNC_INITIAL_SYNC_BEHAVIOR_MAP[initialSyncBehavior](destinationName).name}
|
{SECRET_SYNC_INITIAL_SYNC_BEHAVIOR_MAP[initialSyncBehavior](destinationName).name}
|
||||||
</GenericFieldLabel>
|
</GenericFieldLabel>
|
||||||
{/* <SecretSyncLabel label="Prepend Prefix">{prependPrefix}</SecretSyncLabel>
|
<GenericFieldLabel label="Key Schema">{keySchema}</GenericFieldLabel>
|
||||||
<SecretSyncLabel label="Append Suffix">{appendSuffix}</SecretSyncLabel> */}
|
|
||||||
{AdditionalSyncOptionsFieldsComponent}
|
{AdditionalSyncOptionsFieldsComponent}
|
||||||
{disableSecretDeletion && (
|
{disableSecretDeletion && (
|
||||||
<GenericFieldLabel label="Secret Deletion">
|
<GenericFieldLabel label="Secret Deletion">
|
||||||
|
@@ -8,18 +8,17 @@ export const BaseSecretSyncSchema = <T extends AnyZodObject | undefined = undefi
|
|||||||
) => {
|
) => {
|
||||||
const baseSyncOptionsSchema = z.object({
|
const baseSyncOptionsSchema = z.object({
|
||||||
initialSyncBehavior: z.nativeEnum(SecretSyncInitialSyncBehavior),
|
initialSyncBehavior: z.nativeEnum(SecretSyncInitialSyncBehavior),
|
||||||
disableSecretDeletion: z.boolean().optional().default(false)
|
disableSecretDeletion: z.boolean().optional().default(false),
|
||||||
// scott: removed temporarily for evaluation of template formatting
|
keySchema: z
|
||||||
// prependPrefix: z
|
.string()
|
||||||
// .string()
|
.optional()
|
||||||
// .trim()
|
.refine(
|
||||||
// .transform((str) => str.toUpperCase())
|
(val) => !val || /^(?:[a-zA-Z0-9\-/]*)(?:\{\{secretKey\}\})(?:[a-zA-Z0-9\-/]*)$/.test(val),
|
||||||
// .optional(),
|
{
|
||||||
// appendSuffix: z
|
message:
|
||||||
// .string()
|
"Key schema must include one {{secretKey}} and only contain letters, numbers, dashes, slashes, and the {{secretKey}} placeholder."
|
||||||
// .trim()
|
}
|
||||||
// .transform((str) => str.toUpperCase())
|
)
|
||||||
// .optional()
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const syncOptionsSchema = additionalSyncOptions
|
const syncOptionsSchema = additionalSyncOptions
|
||||||
|
@@ -4,8 +4,7 @@ import { SecretSyncInitialSyncBehavior, SecretSyncStatus } from "@app/hooks/api/
|
|||||||
export type RootSyncOptions = {
|
export type RootSyncOptions = {
|
||||||
initialSyncBehavior: SecretSyncInitialSyncBehavior;
|
initialSyncBehavior: SecretSyncInitialSyncBehavior;
|
||||||
disableSecretDeletion?: boolean;
|
disableSecretDeletion?: boolean;
|
||||||
// prependPrefix?: string;
|
keySchema?: string;
|
||||||
// appendSuffix?: string;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TRootSecretSync = {
|
export type TRootSecretSync = {
|
||||||
|
@@ -21,12 +21,7 @@ type Props = {
|
|||||||
export const SecretSyncOptionsSection = ({ secretSync, onEditOptions }: Props) => {
|
export const SecretSyncOptionsSection = ({ secretSync, onEditOptions }: Props) => {
|
||||||
const {
|
const {
|
||||||
destination,
|
destination,
|
||||||
syncOptions: {
|
syncOptions: { initialSyncBehavior, disableSecretDeletion, keySchema }
|
||||||
// appendSuffix,
|
|
||||||
// prependPrefix,
|
|
||||||
initialSyncBehavior,
|
|
||||||
disableSecretDeletion
|
|
||||||
}
|
|
||||||
} = secretSync;
|
} = secretSync;
|
||||||
|
|
||||||
let AdditionalSyncOptionsComponent: ReactNode;
|
let AdditionalSyncOptionsComponent: ReactNode;
|
||||||
@@ -88,8 +83,7 @@ export const SecretSyncOptionsSection = ({ secretSync, onEditOptions }: Props) =
|
|||||||
<GenericFieldLabel label="Initial Sync Behavior">
|
<GenericFieldLabel label="Initial Sync Behavior">
|
||||||
{SECRET_SYNC_INITIAL_SYNC_BEHAVIOR_MAP[initialSyncBehavior](destination).name}
|
{SECRET_SYNC_INITIAL_SYNC_BEHAVIOR_MAP[initialSyncBehavior](destination).name}
|
||||||
</GenericFieldLabel>
|
</GenericFieldLabel>
|
||||||
{/* <SecretSyncLabel label="Prefix">{prependPrefix}</SecretSyncLabel>
|
<GenericFieldLabel label="Key Schema">{keySchema}</GenericFieldLabel>
|
||||||
<SecretSyncLabel label="Suffix">{appendSuffix}</SecretSyncLabel> */}
|
|
||||||
{AdditionalSyncOptionsComponent}
|
{AdditionalSyncOptionsComponent}
|
||||||
{disableSecretDeletion && (
|
{disableSecretDeletion && (
|
||||||
<GenericFieldLabel label="Secret Deletion">
|
<GenericFieldLabel label="Secret Deletion">
|
||||||
|
Reference in New Issue
Block a user