Fix edge case for delete humanitec secret and improvements on docs

This commit is contained in:
carlosmonastyrski
2025-03-14 09:27:21 -03:00
parent 155e59e571
commit 16866d46bf
8 changed files with 81 additions and 102 deletions

View File

@@ -2,7 +2,6 @@ import { AxiosError, AxiosResponse } from "axios";
import { request } from "@app/lib/config/request";
import { BadRequestError, InternalServerError } from "@app/lib/errors";
import { logger } from "@app/lib/logger";
import { AppConnection } from "@app/services/app-connection/app-connection-enums";
import { IntegrationUrls } from "@app/services/integration-auth/integration-list";
@@ -73,30 +72,23 @@ export const listOrganizations = async (appConnection: THumanitecConnection): Pr
const orgsWithApps: HumanitecOrgWithApps[] = [];
for (const org of orgs) {
try {
// eslint-disable-next-line no-await-in-loop
const appsResponse = await request.get<HumanitecApp[]>(
`${IntegrationUrls.HUMANITEC_API_URL}/orgs/${org.id}/apps`,
{
headers: {
Authorization: `Bearer ${apiToken}`
}
}
);
if (appsResponse.data) {
const apps = appsResponse.data;
orgsWithApps.push({
...org,
apps: apps.map((app) => ({
name: app.name,
id: app.id,
envs: app.envs
}))
});
// eslint-disable-next-line no-await-in-loop
const appsResponse = await request.get<HumanitecApp[]>(`${IntegrationUrls.HUMANITEC_API_URL}/orgs/${org.id}/apps`, {
headers: {
Authorization: `Bearer ${apiToken}`
}
} catch (error) {
logger.error(error, `Failed to get apps for organization ${org.name}`);
});
if (appsResponse.data) {
const apps = appsResponse.data;
orgsWithApps.push({
...org,
apps: apps.map((app) => ({
name: app.name,
id: app.id,
envs: app.envs
}))
});
}
}
return orgsWithApps;

View File

@@ -1,4 +1,5 @@
import { request } from "@app/lib/config/request";
import { logger } from "@app/lib/logger";
import { IntegrationUrls } from "@app/services/integration-auth/integration-list";
import { SecretSyncError } from "@app/services/secret-sync/secret-sync-errors";
import { SECRET_SYNC_NAME_MAP } from "@app/services/secret-sync/secret-sync-maps";
@@ -39,6 +40,13 @@ const deleteSecret = async (secretSync: THumanitecSyncWithCredentials, encrypted
}
} = secretSync;
if (destinationConfig.scope === HumanitecSyncScope.Environment && encryptedSecret.source === "app") {
logger.info(
`Humanitec secret ${encryptedSecret.key} on app ${destinationConfig.app} has no environment override, not deleted as it is an app-level secret`
);
return;
}
try {
let url = `${IntegrationUrls.HUMANITEC_API_URL}/orgs/${destinationConfig.org}/apps/${destinationConfig.app}`;
if (destinationConfig.scope === HumanitecSyncScope.Environment) {
@@ -69,11 +77,12 @@ const createSecret = async (secretSync: THumanitecSyncWithCredentials, secretMap
}
} = secretSync;
const appLevelSecret = destinationConfig.scope === HumanitecSyncScope.Application ? secretMap[key].value : "";
await request.post(
`${IntegrationUrls.HUMANITEC_API_URL}/orgs/${destinationConfig.org}/apps/${destinationConfig.app}/values`,
{
key,
value: "",
value: appLevelSecret,
description: secretMap[key].comment || "",
is_secret: true
},

View File

@@ -1,10 +0,0 @@
---
title: "Create"
openapi: "POST /api/v1/app-connections/humanitec"
---
<Note>
Humanitec Connections must be created through the Infisical UI.
Check out the configuration docs for [Humanitec Connections](/integrations/app-connections/humanitec) for a step-by-step
guide.
</Note>

View File

@@ -1,10 +0,0 @@
---
title: "Update"
openapi: "PATCH /api/v1/app-connections/humanitec/{connectionId}"
---
<Note>
Humanitec Connections must be updated through the Infisical UI.
Check out the configuration docs for [Humanitec Connections](/integrations/app-connections/humanitec) for a step-by-step
guide.
</Note>

View File

@@ -22,8 +22,10 @@ Infisical supports connecting to Humanitec using a service user.
</Step>
<Step title="Create the API Token for the Service User">
Create the API token for the service user.
If you configure an expiry date for your API token you will need to manually rotate to a new token prior to expiration to avoid integration downtime.
This token's permission will be limited to the **Service User** role.
<Note>
If you configure an expiry date for your API token you will need to manually rotate to a new token prior to expiration to avoid integration downtime.
</Note>
![Humanitec Create API Token](/images/app-connections/humanitec/humanitec-create-api-token.png)
</Step>
<Step title="Copy the API Token">

View File

@@ -908,8 +908,6 @@
"api-reference/endpoints/app-connections/humanitec/available",
"api-reference/endpoints/app-connections/humanitec/get-by-id",
"api-reference/endpoints/app-connections/humanitec/get-by-name",
"api-reference/endpoints/app-connections/humanitec/create",
"api-reference/endpoints/app-connections/humanitec/update",
"api-reference/endpoints/app-connections/humanitec/delete"
]
}

View File

@@ -45,58 +45,6 @@ export const HumanitecSyncFields = () => {
setValue("destinationConfig.env", "");
}}
/>
<Controller
name="destinationConfig.scope"
control={control}
defaultValue={HumanitecSyncScope.Application}
render={({ field: { value, onChange }, fieldState: { error } }) => (
<FormControl
errorText={error?.message}
isError={Boolean(error?.message)}
label="Scope"
tooltipClassName="max-w-lg py-3"
tooltipText={
<div className="flex flex-col gap-3">
<p>
Specify how Infisical should manage secrets from Humanitec. The following options
are available:
</p>
<ul className="flex list-disc flex-col gap-3 pl-4">
{Object.values(HUMANITEC_SYNC_SCOPES).map(({ name, description }) => {
return (
<li key={name}>
<p className="text-mineshaft-300">
<span className="font-medium text-bunker-200">{name}</span>: {description}
</p>
</li>
);
})}
</ul>
</div>
}
>
<Select
value={value}
onValueChange={(val) => {
onChange(val);
setValue("destinationConfig.env", "");
setValue("destinationConfig.app", "");
setValue("destinationConfig.org", "");
}}
className="w-full border border-mineshaft-500 capitalize"
position="popper"
placeholder="Select a scope..."
dropdownContainerClassName="max-w-none"
>
{Object.values(HumanitecSyncScope).map((scope) => (
<SelectItem className="capitalize" value={scope} key={scope}>
{scope.replace("-", " ")}
</SelectItem>
))}
</Select>
</FormControl>
)}
/>
<Controller
name="destinationConfig.org"
control={control}
@@ -166,6 +114,56 @@ export const HumanitecSyncFields = () => {
</FormControl>
)}
/>
<Controller
name="destinationConfig.scope"
control={control}
defaultValue={HumanitecSyncScope.Application}
render={({ field: { value, onChange }, fieldState: { error } }) => (
<FormControl
errorText={error?.message}
isError={Boolean(error?.message)}
label="Scope"
tooltipClassName="max-w-lg py-3"
tooltipText={
<div className="flex flex-col gap-3">
<p>
Specify how Infisical should manage secrets from Humanitec. The following options
are available:
</p>
<ul className="flex list-disc flex-col gap-3 pl-4">
{Object.values(HUMANITEC_SYNC_SCOPES).map(({ name, description }) => {
return (
<li key={name}>
<p className="text-mineshaft-300">
<span className="font-medium text-bunker-200">{name}</span>: {description}
</p>
</li>
);
})}
</ul>
</div>
}
>
<Select
value={value}
onValueChange={(val) => {
onChange(val);
setValue("destinationConfig.env", "");
}}
className="w-full border border-mineshaft-500 capitalize"
position="popper"
placeholder="Select a scope..."
dropdownContainerClassName="max-w-none"
>
{Object.values(HumanitecSyncScope).map((scope) => (
<SelectItem className="capitalize" value={scope} key={scope}>
{scope.replace("-", " ")}
</SelectItem>
))}
</Select>
</FormControl>
)}
/>
{currentScope === HumanitecSyncScope.Environment && (
<Controller
name="destinationConfig.env"

View File

@@ -76,11 +76,11 @@ export const HUMANITEC_SYNC_SCOPES: Record<
[HumanitecSyncScope.Application]: {
name: "Application",
description:
"Infisical will import any secrets present in the selected Humanitec application. This includes all secrets that are not limited to a specific environment."
"Infisical will sync secrets as application level shared values to the specified Humanitec application."
},
[HumanitecSyncScope.Environment]: {
name: "Environment",
description:
"Infisical will import any secrets present in the selected Humanitec environment. This includes all secrets that are limited to the selected environment."
"Infisical will sync secrets as environment level shared values to the specified Humanitec application environment."
}
};