mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-09-22 13:39:35 +00:00
Fix edge case for delete humanitec secret and improvements on docs
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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
|
||||
},
|
||||
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||

|
||||
</Step>
|
||||
<Step title="Copy the API Token">
|
||||
|
||||
@@ -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"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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."
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user