Improve terraform-cloud secret sync destination variables

This commit is contained in:
carlosmonastyrski
2025-04-10 07:38:11 -03:00
parent 68374a17f0
commit a84dddaf6f
10 changed files with 62 additions and 50 deletions
+4 -2
View File
@@ -1815,8 +1815,10 @@ export const SecretSyncs = {
}, },
TERRAFORM_CLOUD: { TERRAFORM_CLOUD: {
org: "The ID of the Terraform Cloud org to sync secrets to.", org: "The ID of the Terraform Cloud org to sync secrets to.",
destinationName: "The name of the Terraform Cloud variable set / workspace to sync secrets to.", variableSetName: "The name of the Terraform Cloud Variable Set to sync secrets to.",
destinationId: "The ID of the Terraform Cloud variable set / workspace to sync secrets to.", variableSetId: "The ID of the Terraform Cloud Variable Set to sync secrets to.",
workspaceName: "The name of the Terraform Cloud workspace to sync secrets to.",
workspaceId: "The ID of the Terraform Cloud workspace to sync secrets to.",
scope: "The Terraform Cloud scope that secrets should be synced to.", scope: "The Terraform Cloud scope that secrets should be synced to.",
category: "The Terraform Cloud category that secrets should be synced to." category: "The Terraform Cloud category that secrets should be synced to."
} }
@@ -29,10 +29,10 @@ const getTerraformCloudVariables = async (
let source: TerraformCloudVariable["source"]; let source: TerraformCloudVariable["source"];
if (destinationConfig.scope === TerraformCloudSyncScope.VariableSet) { if (destinationConfig.scope === TerraformCloudSyncScope.VariableSet) {
url = `${IntegrationUrls.TERRAFORM_CLOUD_API_URL}/api/v2/varsets/${destinationConfig.destinationId}/relationships/vars`; url = `${IntegrationUrls.TERRAFORM_CLOUD_API_URL}/api/v2/varsets/${destinationConfig.variableSetId}/relationships/vars`;
source = "varset"; source = "varset";
} else { } else {
url = `${IntegrationUrls.TERRAFORM_CLOUD_API_URL}/api/v2/workspaces/${destinationConfig.destinationId}/vars`; url = `${IntegrationUrls.TERRAFORM_CLOUD_API_URL}/api/v2/workspaces/${destinationConfig.workspaceId}/vars`;
source = "workspace"; source = "workspace";
} }
@@ -92,9 +92,9 @@ const deleteVariable = async (
let url; let url;
if (destinationConfig.scope === TerraformCloudSyncScope.VariableSet) { if (destinationConfig.scope === TerraformCloudSyncScope.VariableSet) {
url = `${IntegrationUrls.TERRAFORM_CLOUD_API_URL}/api/v2/varsets/${destinationConfig.destinationId}/relationships/vars/${variable.id}`; url = `${IntegrationUrls.TERRAFORM_CLOUD_API_URL}/api/v2/varsets/${destinationConfig.variableSetId}/relationships/vars/${variable.id}`;
} else { } else {
url = `${IntegrationUrls.TERRAFORM_CLOUD_API_URL}/api/v2/workspaces/${destinationConfig.destinationId}/vars/${variable.id}`; url = `${IntegrationUrls.TERRAFORM_CLOUD_API_URL}/api/v2/workspaces/${destinationConfig.workspaceId}/vars/${variable.id}`;
} }
await request.delete(url, { await request.delete(url, {
@@ -127,9 +127,9 @@ const createVariable = async (
let url; let url;
if (destinationConfig.scope === TerraformCloudSyncScope.VariableSet) { if (destinationConfig.scope === TerraformCloudSyncScope.VariableSet) {
url = `${IntegrationUrls.TERRAFORM_CLOUD_API_URL}/api/v2/varsets/${destinationConfig.destinationId}/relationships/vars`; url = `${IntegrationUrls.TERRAFORM_CLOUD_API_URL}/api/v2/varsets/${destinationConfig.variableSetId}/relationships/vars`;
} else { } else {
url = `${IntegrationUrls.TERRAFORM_CLOUD_API_URL}/api/v2/workspaces/${destinationConfig.destinationId}/vars`; url = `${IntegrationUrls.TERRAFORM_CLOUD_API_URL}/api/v2/workspaces/${destinationConfig.workspaceId}/vars`;
} }
await request.post( await request.post(
@@ -177,9 +177,9 @@ const updateVariable = async (
let url; let url;
if (destinationConfig.scope === TerraformCloudSyncScope.VariableSet) { if (destinationConfig.scope === TerraformCloudSyncScope.VariableSet) {
url = `${IntegrationUrls.TERRAFORM_CLOUD_API_URL}/api/v2/varsets/${destinationConfig.destinationId}/relationships/vars/${variable.id}`; url = `${IntegrationUrls.TERRAFORM_CLOUD_API_URL}/api/v2/varsets/${destinationConfig.variableSetId}/relationships/vars/${variable.id}`;
} else { } else {
url = `${IntegrationUrls.TERRAFORM_CLOUD_API_URL}/api/v2/workspaces/${destinationConfig.destinationId}/vars/${variable.id}`; url = `${IntegrationUrls.TERRAFORM_CLOUD_API_URL}/api/v2/workspaces/${destinationConfig.workspaceId}/vars/${variable.id}`;
} }
await request.patch( await request.patch(
@@ -20,27 +20,27 @@ const TerraformCloudSyncDestinationConfigSchema = z.discriminatedUnion("scope",
.literal(TerraformCloudSyncScope.VariableSet) .literal(TerraformCloudSyncScope.VariableSet)
.describe(SecretSyncs.DESTINATION_CONFIG.TERRAFORM_CLOUD.scope), .describe(SecretSyncs.DESTINATION_CONFIG.TERRAFORM_CLOUD.scope),
org: z.string().min(1, "Org ID is required").describe(SecretSyncs.DESTINATION_CONFIG.TERRAFORM_CLOUD.org), org: z.string().min(1, "Org ID is required").describe(SecretSyncs.DESTINATION_CONFIG.TERRAFORM_CLOUD.org),
destinationName: z variableSetName: z
.string() .string()
.min(1, "Variable set name is required") .min(1, "Variable set name is required")
.describe(SecretSyncs.DESTINATION_CONFIG.TERRAFORM_CLOUD.destinationName), .describe(SecretSyncs.DESTINATION_CONFIG.TERRAFORM_CLOUD.variableSetName),
destinationId: z variableSetId: z
.string() .string()
.min(1, "Variable set ID is required") .min(1, "Variable set ID is required")
.describe(SecretSyncs.DESTINATION_CONFIG.TERRAFORM_CLOUD.destinationId), .describe(SecretSyncs.DESTINATION_CONFIG.TERRAFORM_CLOUD.variableSetId),
category: z.nativeEnum(TerraformCloudSyncCategory).describe(SecretSyncs.DESTINATION_CONFIG.TERRAFORM_CLOUD.category) category: z.nativeEnum(TerraformCloudSyncCategory).describe(SecretSyncs.DESTINATION_CONFIG.TERRAFORM_CLOUD.category)
}), }),
z.object({ z.object({
scope: z.literal(TerraformCloudSyncScope.Workspace).describe(SecretSyncs.DESTINATION_CONFIG.TERRAFORM_CLOUD.scope), scope: z.literal(TerraformCloudSyncScope.Workspace).describe(SecretSyncs.DESTINATION_CONFIG.TERRAFORM_CLOUD.scope),
org: z.string().min(1, "Org ID is required").describe(SecretSyncs.DESTINATION_CONFIG.TERRAFORM_CLOUD.org), org: z.string().min(1, "Org ID is required").describe(SecretSyncs.DESTINATION_CONFIG.TERRAFORM_CLOUD.org),
destinationName: z workspaceName: z
.string() .string()
.min(1, "Workspace name is required") .min(1, "Workspace name is required")
.describe(SecretSyncs.DESTINATION_CONFIG.TERRAFORM_CLOUD.destinationName), .describe(SecretSyncs.DESTINATION_CONFIG.TERRAFORM_CLOUD.workspaceName),
destinationId: z workspaceId: z
.string() .string()
.min(1, "Workspace ID is required") .min(1, "Workspace ID is required")
.describe(SecretSyncs.DESTINATION_CONFIG.TERRAFORM_CLOUD.destinationId), .describe(SecretSyncs.DESTINATION_CONFIG.TERRAFORM_CLOUD.workspaceId),
category: z.nativeEnum(TerraformCloudSyncCategory).describe(SecretSyncs.DESTINATION_CONFIG.TERRAFORM_CLOUD.category) category: z.nativeEnum(TerraformCloudSyncCategory).describe(SecretSyncs.DESTINATION_CONFIG.TERRAFORM_CLOUD.category)
}) })
]); ]);
@@ -94,8 +94,8 @@ description: "Learn how to configure a Terraform Cloud Sync for Infisical."
}, },
"destinationConfig": { "destinationConfig": {
"scope": "variable-set", "scope": "variable-set",
"destinationId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "variableSetId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"destinationName": "my-variable-set", "variableSetName": "my-variable-set",
"org": "my-organization-id", "org": "my-organization-id",
"category": "env" "category": "env"
} }
@@ -149,8 +149,8 @@ description: "Learn how to configure a Terraform Cloud Sync for Infisical."
"destination": "terraform-cloud", "destination": "terraform-cloud",
"destinationConfig": { "destinationConfig": {
"scope": "workspace", "scope": "workspace",
"destinationId": "3c90c3cc-0d44-4b50-8888-8dd25736052a", "workspaceId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"destinationName": "my-workspace", "workspaceName": "my-workspace",
"org": "my-organization-id", "org": "my-organization-id",
"category": "terraform" "category": "terraform"
} }
@@ -39,8 +39,10 @@ export const TerraformCloudSyncFields = () => {
<SecretSyncConnectionField <SecretSyncConnectionField
onChange={() => { onChange={() => {
setValue("destinationConfig.org", ""); setValue("destinationConfig.org", "");
setValue("destinationConfig.destinationId", ""); setValue("destinationConfig.variableSetId", "");
setValue("destinationConfig.destinationName", ""); setValue("destinationConfig.workspaceId", "");
setValue("destinationConfig.variableSetName", "");
setValue("destinationConfig.workspaceName", "");
}} }}
/> />
<Controller <Controller
@@ -60,8 +62,10 @@ export const TerraformCloudSyncFields = () => {
onChange( onChange(
(option as SingleValue<TTerraformCloudConnectionOrganization>)?.id ?? null (option as SingleValue<TTerraformCloudConnectionOrganization>)?.id ?? null
); );
setValue("destinationConfig.destinationId", ""); setValue("destinationConfig.variableSetId", "");
setValue("destinationConfig.destinationName", ""); setValue("destinationConfig.workspaceId", "");
setValue("destinationConfig.variableSetName", "");
setValue("destinationConfig.workspaceName", "");
}} }}
options={organizations} options={organizations}
placeholder="Select an organization..." placeholder="Select an organization..."
@@ -155,8 +159,10 @@ export const TerraformCloudSyncFields = () => {
value={value} value={value}
onValueChange={(val) => { onValueChange={(val) => {
onChange(val); onChange(val);
setValue("destinationConfig.destinationId", ""); setValue("destinationConfig.variableSetId", "");
setValue("destinationConfig.destinationName", ""); setValue("destinationConfig.workspaceId", "");
setValue("destinationConfig.variableSetName", "");
setValue("destinationConfig.workspaceName", "");
}} }}
className="w-full border border-mineshaft-500 capitalize" className="w-full border border-mineshaft-500 capitalize"
position="popper" position="popper"
@@ -174,7 +180,7 @@ export const TerraformCloudSyncFields = () => {
/> />
{currentScope === TerraformCloudSyncScope.VariableSet && ( {currentScope === TerraformCloudSyncScope.VariableSet && (
<Controller <Controller
name="destinationConfig.destinationId" name="destinationConfig.variableSetId"
control={control} control={control}
render={({ field: { value, onChange }, fieldState: { error } }) => ( render={({ field: { value, onChange }, fieldState: { error } }) => (
<FormControl isError={Boolean(error)} errorText={error?.message} label="Variable Set"> <FormControl isError={Boolean(error)} errorText={error?.message} label="Variable Set">
@@ -189,9 +195,9 @@ export const TerraformCloudSyncFields = () => {
onChange(selectedOption?.id ?? null); onChange(selectedOption?.id ?? null);
if (selectedOption) { if (selectedOption) {
setValue("destinationConfig.destinationName", selectedOption.name); setValue("destinationConfig.variableSetName", selectedOption.name);
} else { } else {
setValue("destinationConfig.destinationName", ""); setValue("destinationConfig.variableSetName", "");
} }
}} }}
options={variableSets} options={variableSets}
@@ -205,7 +211,7 @@ export const TerraformCloudSyncFields = () => {
)} )}
{currentScope === TerraformCloudSyncScope.Workspace && ( {currentScope === TerraformCloudSyncScope.Workspace && (
<Controller <Controller
name="destinationConfig.destinationId" name="destinationConfig.workspaceId"
control={control} control={control}
render={({ field: { value, onChange }, fieldState: { error } }) => ( render={({ field: { value, onChange }, fieldState: { error } }) => (
<FormControl isError={Boolean(error)} errorText={error?.message} label="Workspace"> <FormControl isError={Boolean(error)} errorText={error?.message} label="Workspace">
@@ -219,9 +225,9 @@ export const TerraformCloudSyncFields = () => {
onChange(selectedOption?.id ?? null); onChange(selectedOption?.id ?? null);
if (selectedOption) { if (selectedOption) {
setValue("destinationConfig.destinationName", selectedOption.name); setValue("destinationConfig.workspaceName", selectedOption.name);
} else { } else {
setValue("destinationConfig.destinationName", ""); setValue("destinationConfig.workspaceName", "");
} }
}} }}
options={workspaces} options={workspaces}
@@ -8,7 +8,8 @@ import { SecretSync } from "@app/hooks/api/secretSyncs";
export const TerraformCloudSyncReviewFields = () => { export const TerraformCloudSyncReviewFields = () => {
const { watch } = useFormContext<TSecretSyncForm & { destination: SecretSync.TerraformCloud }>(); const { watch } = useFormContext<TSecretSyncForm & { destination: SecretSync.TerraformCloud }>();
const orgId = watch("destinationConfig.org"); const orgId = watch("destinationConfig.org");
const destinationName = watch("destinationConfig.destinationName"); const variableSetName = watch("destinationConfig.variableSetName");
const workspaceName = watch("destinationConfig.workspaceName");
const scope = watch("destinationConfig.scope"); const scope = watch("destinationConfig.scope");
const category = watch("destinationConfig.category"); const category = watch("destinationConfig.category");
@@ -16,10 +17,10 @@ export const TerraformCloudSyncReviewFields = () => {
<> <>
<GenericFieldLabel label="Organization">{orgId}</GenericFieldLabel> <GenericFieldLabel label="Organization">{orgId}</GenericFieldLabel>
{scope === TerraformCloudSyncScope.VariableSet && ( {scope === TerraformCloudSyncScope.VariableSet && (
<GenericFieldLabel label="Variable Set">{destinationName}</GenericFieldLabel> <GenericFieldLabel label="Variable Set">{variableSetName}</GenericFieldLabel>
)} )}
{scope === TerraformCloudSyncScope.Workspace && ( {scope === TerraformCloudSyncScope.Workspace && (
<GenericFieldLabel label="Workspace">{destinationName}</GenericFieldLabel> <GenericFieldLabel label="Workspace">{workspaceName}</GenericFieldLabel>
)} )}
<GenericFieldLabel label="Category">{category}</GenericFieldLabel> <GenericFieldLabel label="Category">{category}</GenericFieldLabel>
</> </>
@@ -14,15 +14,15 @@ export const TerraformCloudSyncDestinationSchema = BaseSecretSyncSchema().merge(
z.object({ z.object({
scope: z.literal(TerraformCloudSyncScope.VariableSet), scope: z.literal(TerraformCloudSyncScope.VariableSet),
org: z.string().trim().min(1, "Organization required"), org: z.string().trim().min(1, "Organization required"),
destinationId: z.string().trim().min(1, "Variable Set required"), variableSetId: z.string().trim().min(1, "Variable Set required"),
destinationName: z.string().trim().min(1, "Variable set name required"), variableSetName: z.string().trim().min(1, "Variable set name required"),
category: z.nativeEnum(TerraformCloudSyncCategory) category: z.nativeEnum(TerraformCloudSyncCategory)
}), }),
z.object({ z.object({
scope: z.literal(TerraformCloudSyncScope.Workspace), scope: z.literal(TerraformCloudSyncScope.Workspace),
org: z.string().trim().min(1, "Organization required"), org: z.string().trim().min(1, "Organization required"),
destinationId: z.string().trim().min(1, "Workspace required"), workspaceId: z.string().trim().min(1, "Workspace required"),
destinationName: z.string().trim().min(1, "Workspace name required"), workspaceName: z.string().trim().min(1, "Workspace name required"),
category: z.nativeEnum(TerraformCloudSyncCategory) category: z.nativeEnum(TerraformCloudSyncCategory)
}) })
]) ])
@@ -11,15 +11,15 @@ export type TTerraformCloudSync = TRootSecretSync & {
scope: TerraformCloudSyncScope.VariableSet; scope: TerraformCloudSyncScope.VariableSet;
org: string; org: string;
category: TerraformCloudSyncCategory; category: TerraformCloudSyncCategory;
destinationId: string; variableSetId: string;
destinationName: string; variableSetName: string;
} }
| { | {
scope: TerraformCloudSyncScope.Workspace; scope: TerraformCloudSyncScope.Workspace;
org: string; org: string;
category: TerraformCloudSyncCategory; category: TerraformCloudSyncCategory;
destinationId: string; workspaceId: string;
destinationName: string; workspaceName: string;
}; };
connection: { connection: {
app: AppConnection.TerraformCloud; app: AppConnection.TerraformCloud;
@@ -1,3 +1,4 @@
import { TerraformCloudSyncScope } from "@app/hooks/api/appConnections/terraform-cloud";
import { SecretSync, TSecretSync } from "@app/hooks/api/secretSyncs"; import { SecretSync, TSecretSync } from "@app/hooks/api/secretSyncs";
import { import {
GitHubSyncScope, GitHubSyncScope,
@@ -75,7 +76,11 @@ export const getSecretSyncDestinationColValues = (secretSync: TSecretSync) => {
break; break;
case SecretSync.TerraformCloud: case SecretSync.TerraformCloud:
primaryText = destinationConfig.org; primaryText = destinationConfig.org;
secondaryText = destinationConfig.destinationName; if (destinationConfig.scope === TerraformCloudSyncScope.VariableSet) {
secondaryText = destinationConfig.variableSetName;
} else {
secondaryText = destinationConfig.workspaceName;
}
break; break;
default: default:
throw new Error(`Unhandled Destination Col Values ${destination}`); throw new Error(`Unhandled Destination Col Values ${destination}`);
@@ -20,7 +20,7 @@ export const TerraformCloudSyncDestinationSection = ({ secretSync }: Props) => {
<> <>
<GenericFieldLabel label="Organization">{destinationConfig.org}</GenericFieldLabel> <GenericFieldLabel label="Organization">{destinationConfig.org}</GenericFieldLabel>
<GenericFieldLabel label="Variable Set"> <GenericFieldLabel label="Variable Set">
{destinationConfig.destinationName} {destinationConfig.variableSetName}
</GenericFieldLabel> </GenericFieldLabel>
</> </>
); );
@@ -29,9 +29,7 @@ export const TerraformCloudSyncDestinationSection = ({ secretSync }: Props) => {
Components = ( Components = (
<> <>
<GenericFieldLabel label="Organization">{destinationConfig.org}</GenericFieldLabel> <GenericFieldLabel label="Organization">{destinationConfig.org}</GenericFieldLabel>
<GenericFieldLabel label="Workspace"> <GenericFieldLabel label="Workspace">{destinationConfig.workspaceName}</GenericFieldLabel>
{destinationConfig.destinationName}
</GenericFieldLabel>
</> </>
); );
break; break;