mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-07 21:27:31 +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 { request } from "@app/lib/config/request";
|
||||||
import { BadRequestError, InternalServerError } from "@app/lib/errors";
|
import { BadRequestError, InternalServerError } from "@app/lib/errors";
|
||||||
import { logger } from "@app/lib/logger";
|
|
||||||
import { AppConnection } from "@app/services/app-connection/app-connection-enums";
|
import { AppConnection } from "@app/services/app-connection/app-connection-enums";
|
||||||
import { IntegrationUrls } from "@app/services/integration-auth/integration-list";
|
import { IntegrationUrls } from "@app/services/integration-auth/integration-list";
|
||||||
|
|
||||||
@@ -73,30 +72,23 @@ export const listOrganizations = async (appConnection: THumanitecConnection): Pr
|
|||||||
const orgsWithApps: HumanitecOrgWithApps[] = [];
|
const orgsWithApps: HumanitecOrgWithApps[] = [];
|
||||||
|
|
||||||
for (const org of orgs) {
|
for (const org of orgs) {
|
||||||
try {
|
// eslint-disable-next-line no-await-in-loop
|
||||||
// eslint-disable-next-line no-await-in-loop
|
const appsResponse = await request.get<HumanitecApp[]>(`${IntegrationUrls.HUMANITEC_API_URL}/orgs/${org.id}/apps`, {
|
||||||
const appsResponse = await request.get<HumanitecApp[]>(
|
headers: {
|
||||||
`${IntegrationUrls.HUMANITEC_API_URL}/orgs/${org.id}/apps`,
|
Authorization: `Bearer ${apiToken}`
|
||||||
{
|
|
||||||
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
|
|
||||||
}))
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
} 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;
|
return orgsWithApps;
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { request } from "@app/lib/config/request";
|
import { request } from "@app/lib/config/request";
|
||||||
|
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 { 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";
|
||||||
@@ -39,6 +40,13 @@ const deleteSecret = async (secretSync: THumanitecSyncWithCredentials, encrypted
|
|||||||
}
|
}
|
||||||
} = secretSync;
|
} = 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 {
|
try {
|
||||||
let url = `${IntegrationUrls.HUMANITEC_API_URL}/orgs/${destinationConfig.org}/apps/${destinationConfig.app}`;
|
let url = `${IntegrationUrls.HUMANITEC_API_URL}/orgs/${destinationConfig.org}/apps/${destinationConfig.app}`;
|
||||||
if (destinationConfig.scope === HumanitecSyncScope.Environment) {
|
if (destinationConfig.scope === HumanitecSyncScope.Environment) {
|
||||||
@@ -69,11 +77,12 @@ const createSecret = async (secretSync: THumanitecSyncWithCredentials, secretMap
|
|||||||
}
|
}
|
||||||
} = secretSync;
|
} = secretSync;
|
||||||
|
|
||||||
|
const appLevelSecret = destinationConfig.scope === HumanitecSyncScope.Application ? secretMap[key].value : "";
|
||||||
await request.post(
|
await request.post(
|
||||||
`${IntegrationUrls.HUMANITEC_API_URL}/orgs/${destinationConfig.org}/apps/${destinationConfig.app}/values`,
|
`${IntegrationUrls.HUMANITEC_API_URL}/orgs/${destinationConfig.org}/apps/${destinationConfig.app}/values`,
|
||||||
{
|
{
|
||||||
key,
|
key,
|
||||||
value: "",
|
value: appLevelSecret,
|
||||||
description: secretMap[key].comment || "",
|
description: secretMap[key].comment || "",
|
||||||
is_secret: true
|
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>
|
||||||
<Step title="Create the API Token for the Service User">
|
<Step title="Create the API Token for the Service User">
|
||||||
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.
|
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>
|
||||||
<Step title="Copy the API Token">
|
<Step title="Copy the API Token">
|
||||||
|
|||||||
@@ -908,8 +908,6 @@
|
|||||||
"api-reference/endpoints/app-connections/humanitec/available",
|
"api-reference/endpoints/app-connections/humanitec/available",
|
||||||
"api-reference/endpoints/app-connections/humanitec/get-by-id",
|
"api-reference/endpoints/app-connections/humanitec/get-by-id",
|
||||||
"api-reference/endpoints/app-connections/humanitec/get-by-name",
|
"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"
|
"api-reference/endpoints/app-connections/humanitec/delete"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
+50
-52
@@ -45,58 +45,6 @@ export const HumanitecSyncFields = () => {
|
|||||||
setValue("destinationConfig.env", "");
|
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
|
<Controller
|
||||||
name="destinationConfig.org"
|
name="destinationConfig.org"
|
||||||
control={control}
|
control={control}
|
||||||
@@ -166,6 +114,56 @@ export const HumanitecSyncFields = () => {
|
|||||||
</FormControl>
|
</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 && (
|
{currentScope === HumanitecSyncScope.Environment && (
|
||||||
<Controller
|
<Controller
|
||||||
name="destinationConfig.env"
|
name="destinationConfig.env"
|
||||||
|
|||||||
@@ -76,11 +76,11 @@ export const HUMANITEC_SYNC_SCOPES: Record<
|
|||||||
[HumanitecSyncScope.Application]: {
|
[HumanitecSyncScope.Application]: {
|
||||||
name: "Application",
|
name: "Application",
|
||||||
description:
|
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]: {
|
[HumanitecSyncScope.Environment]: {
|
||||||
name: "Environment",
|
name: "Environment",
|
||||||
description:
|
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