Merge remote-tracking branch 'origin' into cert-mgmt

This commit is contained in:
Tuan Dang
2024-06-06 23:20:17 -04:00
22 changed files with 504 additions and 8 deletions
+1
View File
@@ -661,6 +661,7 @@ export const INTEGRATION = {
targetServiceId: targetServiceId:
"The service based grouping identifier ID of the external provider. Used in Terraform cloud, Checkly, Railway and NorthFlank", "The service based grouping identifier ID of the external provider. Used in Terraform cloud, Checkly, Railway and NorthFlank",
owner: "External integration providers service entity owner. Used in Github.", owner: "External integration providers service entity owner. Used in Github.",
url: "The self-hosted URL of the platform to integrate with",
path: "Path to save the synced secrets. Used by Gitlab, AWS Parameter Store, Vault", path: "Path to save the synced secrets. Used by Gitlab, AWS Parameter Store, Vault",
region: "AWS region to sync secrets to.", region: "AWS region to sync secrets to.",
scope: "Scope of the provider. Used by Github, Qovery", scope: "Scope of the provider. Used by Github, Qovery",
@@ -42,6 +42,7 @@ export const registerIntegrationRouter = async (server: FastifyZodProvider) => {
targetService: z.string().trim().optional().describe(INTEGRATION.CREATE.targetService), targetService: z.string().trim().optional().describe(INTEGRATION.CREATE.targetService),
targetServiceId: z.string().trim().optional().describe(INTEGRATION.CREATE.targetServiceId), targetServiceId: z.string().trim().optional().describe(INTEGRATION.CREATE.targetServiceId),
owner: z.string().trim().optional().describe(INTEGRATION.CREATE.owner), owner: z.string().trim().optional().describe(INTEGRATION.CREATE.owner),
url: z.string().trim().optional().describe(INTEGRATION.CREATE.url),
path: z.string().trim().optional().describe(INTEGRATION.CREATE.path), path: z.string().trim().optional().describe(INTEGRATION.CREATE.path),
region: z.string().trim().optional().describe(INTEGRATION.CREATE.region), region: z.string().trim().optional().describe(INTEGRATION.CREATE.region),
scope: z.string().trim().optional().describe(INTEGRATION.CREATE.scope), scope: z.string().trim().optional().describe(INTEGRATION.CREATE.scope),
@@ -199,6 +199,7 @@ export const integrationAuthServiceFactory = ({
projectId, projectId,
namespace, namespace,
integration, integration,
url,
algorithm: SecretEncryptionAlgo.AES_256_GCM, algorithm: SecretEncryptionAlgo.AES_256_GCM,
keyEncoding: SecretKeyEncoding.UTF8, keyEncoding: SecretKeyEncoding.UTF8,
...(integration === Integrations.GCP_SECRET_MANAGER ...(integration === Integrations.GCP_SECRET_MANAGER
@@ -30,7 +30,8 @@ export enum Integrations {
DIGITAL_OCEAN_APP_PLATFORM = "digital-ocean-app-platform", DIGITAL_OCEAN_APP_PLATFORM = "digital-ocean-app-platform",
CLOUD_66 = "cloud-66", CLOUD_66 = "cloud-66",
NORTHFLANK = "northflank", NORTHFLANK = "northflank",
HASURA_CLOUD = "hasura-cloud" HASURA_CLOUD = "hasura-cloud",
RUNDECK = "rundeck"
} }
export enum IntegrationType { export enum IntegrationType {
@@ -368,6 +369,15 @@ export const getIntegrationOptions = async () => {
type: "pat", type: "pat",
clientId: "", clientId: "",
docsLink: "" docsLink: ""
},
{
name: "Rundeck",
slug: "rundeck",
image: "Rundeck.svg",
isAvailable: true,
type: "pat",
clientId: "",
docsLink: ""
} }
]; ];
@@ -3355,6 +3355,82 @@ const syncSecretsHasuraCloud = async ({
} }
}; };
/** Sync/push [secrets] to Rundeck
* @param {Object} obj
* @param {TIntegrations} obj.integration - integration details
* @param {Object} obj.secrets - secrets to push to integration (object where keys are secret keys and values are secret values)
* @param {String} obj.accessToken - access token for Rundeck integration
*/
const syncSecretsRundeck = async ({
integration,
secrets,
accessToken
}: {
integration: TIntegrations;
secrets: Record<string, { value: string; comment?: string }>;
accessToken: string;
}) => {
interface RundeckSecretResource {
name: string;
}
interface RundeckSecretsGetRes {
resources: RundeckSecretResource[];
}
let existingRundeckSecrets: string[] = [];
try {
const listResult = await request.get<RundeckSecretsGetRes>(
`${integration.url}/api/44/storage/${integration.path}`,
{
headers: {
"X-Rundeck-Auth-Token": accessToken
}
}
);
existingRundeckSecrets = listResult.data.resources.map((res) => res.name);
} catch (err) {
logger.info("No existing rundeck secrets");
}
try {
for await (const [key, value] of Object.entries(secrets)) {
if (existingRundeckSecrets.includes(key)) {
await request.put(`${integration.url}/api/44/storage/${integration.path}/${key}`, value.value, {
headers: {
"X-Rundeck-Auth-Token": accessToken,
"Content-Type": "application/x-rundeck-data-password"
}
});
} else {
await request.post(`${integration.url}/api/44/storage/${integration.path}/${key}`, value.value, {
headers: {
"X-Rundeck-Auth-Token": accessToken,
"Content-Type": "application/x-rundeck-data-password"
}
});
}
}
for await (const existingSecret of existingRundeckSecrets) {
if (!(existingSecret in secrets)) {
await request.delete(`${integration.url}/api/44/storage/${integration.path}/${existingSecret}`, {
headers: {
"X-Rundeck-Auth-Token": accessToken
}
});
}
}
} catch (err: unknown) {
throw new Error(
`Ensure that the provided Rundeck URL is accessible by Infisical and that the linked API token has sufficient permissions.\n\n${
(err as Error).message
}`
);
}
};
/** /**
* Sync/push [secrets] to [app] in integration named [integration] * Sync/push [secrets] to [app] in integration named [integration]
* *
@@ -3621,6 +3697,13 @@ export const syncIntegrationSecrets = async ({
accessToken accessToken
}); });
break; break;
case Integrations.RUNDECK:
await syncSecretsRundeck({
integration,
secrets,
accessToken
});
break;
default: default:
throw new BadRequestError({ message: "Invalid integration" }); throw new BadRequestError({ message: "Invalid integration" });
} }
@@ -43,6 +43,7 @@ export const integrationServiceFactory = ({
scope, scope,
actorId, actorId,
region, region,
url,
isActive, isActive,
metadata, metadata,
secretPath, secretPath,
@@ -87,6 +88,7 @@ export const integrationServiceFactory = ({
region, region,
scope, scope,
owner, owner,
url,
appId, appId,
path, path,
app, app,
@@ -12,6 +12,7 @@ export type TCreateIntegrationDTO = {
targetService?: string; targetService?: string;
targetServiceId?: string; targetServiceId?: string;
owner?: string; owner?: string;
url?: string;
path?: string; path?: string;
region?: string; region?: string;
scope?: string; scope?: string;
Binary file not shown.

After

Width:  |  Height:  |  Size: 521 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 529 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 308 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 707 KiB

+39
View File
@@ -0,0 +1,39 @@
---
title: "Rundeck"
description: "How to sync secrets from Infisical to Rundeck"
---
Prerequisites:
- Set up and add envars to [Infisical Cloud](https://app.infisical.com)
<Steps>
<Step title="Authorize Infisical for Rundeck">
Obtain a User API Token in the Profile settings of Rundeck
![integrations rundeck token](../../images/integrations/rundeck/integrations-rundeck-token.png)
Navigate to your project's integrations tab in Infisical.
![integrations](../../images/integrations.png)
Press on the Rundeck tile and input your Rundeck instance Base URL and User API token to grant Infisical access to manage Rundeck keys
![integrations rundeck authorization](../../images/integrations/rundeck/integrations-rundeck-auth.png)
<Info>
If this is your project's first cloud integration, then you'll have to grant
Infisical access to your project's environment variables. Although this step
breaks E2EE, it's necessary for Infisical to sync the environment variables to
the cloud platform.
</Info>
</Step>
<Step title="Start integration">
Select which Infisical environment secrets you want to sync to a Rundeck Key Storage Path and press create integration to start syncing secrets to Rundeck.
![create integration rundeck](../../images/integrations/rundeck/integrations-rundeck-create.png)
![integrations rundeck](../../images/integrations/rundeck/integrations-rundeck.png)
</Step>
</Steps>
+5 -4
View File
@@ -26,14 +26,14 @@ Missing an integration? [Throw in a request](https://github.com/Infisical/infisi
| [Supabase](/integrations/cloud/supabase) | Cloud | Available | | [Supabase](/integrations/cloud/supabase) | Cloud | Available |
| [Northflank](/integrations/cloud/northflank) | Cloud | Available | | [Northflank](/integrations/cloud/northflank) | Cloud | Available |
| [Cloudflare Pages](/integrations/cloud/cloudflare-pages) | Cloud | Available | | [Cloudflare Pages](/integrations/cloud/cloudflare-pages) | Cloud | Available |
| [Cloudflare Workers](/integrations/cloud/cloudflare-workers) | Cloud | Available | | [Cloudflare Workers](/integrations/cloud/cloudflare-workers) | Cloud | Available |
| [Checkly](/integrations/cloud/checkly) | Cloud | Available | | [Checkly](/integrations/cloud/checkly) | Cloud | Available |
| [Qovery](/integrations/cloud/qovery) | Cloud | Available | | [Qovery](/integrations/cloud/qovery) | Cloud | Available |
| [HashiCorp Vault](/integrations/cloud/hashicorp-vault) | Cloud | Available | | [HashiCorp Vault](/integrations/cloud/hashicorp-vault) | Cloud | Available |
| [AWS Parameter Store](/integrations/cloud/aws-parameter-store) | Cloud | Available | | [AWS Parameter Store](/integrations/cloud/aws-parameter-store) | Cloud | Available |
| [AWS Secrets Manager](/integrations/cloud/aws-secret-manager) | Cloud | Available | | [AWS Secrets Manager](/integrations/cloud/aws-secret-manager) | Cloud | Available |
| [Azure Key Vault](/integrations/cloud/azure-key-vault) | Cloud | Available | | [Azure Key Vault](/integrations/cloud/azure-key-vault) | Cloud | Available |
| [GCP Secret Manager](/integrations/cloud/gcp-secret-manager) | Cloud | Available | | [GCP Secret Manager](/integrations/cloud/gcp-secret-manager) | Cloud | Available |
| [Windmill](/integrations/cloud/windmill) | Cloud | Available | | [Windmill](/integrations/cloud/windmill) | Cloud | Available |
| [BitBucket](/integrations/cicd/bitbucket) | CI/CD | Available | | [BitBucket](/integrations/cicd/bitbucket) | CI/CD | Available |
| [Codefresh](/integrations/cicd/codefresh) | CI/CD | Available | | [Codefresh](/integrations/cicd/codefresh) | CI/CD | Available |
@@ -41,6 +41,7 @@ Missing an integration? [Throw in a request](https://github.com/Infisical/infisi
| [GitLab](/integrations/cicd/gitlab) | CI/CD | Available | | [GitLab](/integrations/cicd/gitlab) | CI/CD | Available |
| [CircleCI](/integrations/cicd/circleci) | CI/CD | Available | | [CircleCI](/integrations/cicd/circleci) | CI/CD | Available |
| [Travis CI](/integrations/cicd/travisci) | CI/CD | Available | | [Travis CI](/integrations/cicd/travisci) | CI/CD | Available |
| [Rundeck](/integrations/cicd/rundeck) | CI/CD | Available |
| [React](/integrations/frameworks/react) | Framework | Available | | [React](/integrations/frameworks/react) | Framework | Available |
| [Vue](/integrations/frameworks/vue) | Framework | Available | | [Vue](/integrations/frameworks/vue) | Framework | Available |
| [Express](/integrations/frameworks/express) | Framework | Available | | [Express](/integrations/frameworks/express) | Framework | Available |
+1
View File
@@ -344,6 +344,7 @@
"pages": [ "pages": [
"integrations/cicd/circleci", "integrations/cicd/circleci",
"integrations/cicd/travisci", "integrations/cicd/travisci",
"integrations/cicd/rundeck",
"integrations/cicd/codefresh", "integrations/cicd/codefresh",
"integrations/cloud/checkly" "integrations/cloud/checkly"
] ]
+2 -1
View File
@@ -32,7 +32,8 @@ const integrationSlugNameMapping: Mapping = {
northflank: "Northflank", northflank: "Northflank",
windmill: "Windmill", windmill: "Windmill",
"gcp-secret-manager": "GCP Secret Manager", "gcp-secret-manager": "GCP Secret Manager",
"hasura-cloud": "Hasura Cloud" "hasura-cloud": "Hasura Cloud",
rundeck: "Rundeck"
}; };
const envMapping: Mapping = { const envMapping: Mapping = {
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="64" height="64" viewBox="45.359 114.637 60.122 58.576"><path d="M46.83 113.864l7.608 12.01H92.5l-7.543-12.01zm15.26 23.98l3.684 5.754-3.968 6.32h38.4l3.815-6.017-3.815-5.907h-38.04zm-7.826 24.13l-7.455 11.77v.24h38.148l7.564-12.012z" fill="#f91629"/></svg>

After

Width:  |  Height:  |  Size: 303 B

@@ -7,6 +7,7 @@ export type IntegrationAuth = {
updatedAt: string; updatedAt: string;
algorithm: string; algorithm: string;
keyEncoding: string; keyEncoding: string;
url?: string;
teamId?: string; teamId?: string;
}; };
@@ -41,6 +41,7 @@ export const useCreateIntegration = () => {
owner, owner,
path, path,
region, region,
url,
scope, scope,
secretPath, secretPath,
metadata metadata
@@ -56,6 +57,7 @@ export const useCreateIntegration = () => {
targetService?: string; targetService?: string;
targetServiceId?: string; targetServiceId?: string;
owner?: string; owner?: string;
url?: string;
path?: string; path?: string;
region?: string; region?: string;
scope?: string; scope?: string;
@@ -85,6 +87,7 @@ export const useCreateIntegration = () => {
targetEnvironmentId, targetEnvironmentId,
targetService, targetService,
targetServiceId, targetServiceId,
url,
owner, owner,
path, path,
scope, scope,
@@ -0,0 +1,129 @@
import { useState } from "react";
import { Controller, useForm } from "react-hook-form";
import Head from "next/head";
import Image from "next/image";
import Link from "next/link";
import { useRouter } from "next/router";
import { faArrowUpRightFromSquare, faBookOpen } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { zodResolver } from "@hookform/resolvers/zod";
import z from "zod";
import { Button, Card, CardTitle, FormControl, Input } from "@app/components/v2";
import { useSaveIntegrationAccessToken } from "@app/hooks/api";
const schema = z.object({
authToken: z.string().trim().min(1, { message: "Rundeck Auth Token is required" }),
rundeckURL: z.string().trim().min(1, {
message: "Rundeck URL is required"
})
});
type FormData = z.infer<typeof schema>;
export default function RundeckAuthorizeIntegrationPage() {
const router = useRouter();
const [isLoading, setIsLoading] = useState(false);
const { mutateAsync } = useSaveIntegrationAccessToken();
const { control, handleSubmit } = useForm<FormData>({
resolver: zodResolver(schema),
defaultValues: {
authToken: "",
rundeckURL: ""
}
});
const onFormSubmit = async ({ authToken, rundeckURL }: FormData) => {
try {
setIsLoading(true);
const integrationAuth = await mutateAsync({
workspaceId: localStorage.getItem("projectData.id"),
integration: "rundeck",
accessToken: authToken,
url: rundeckURL.trim()
});
setIsLoading(false);
router.push(`/integrations/rundeck/create?integrationAuthId=${integrationAuth.id}`);
} catch (err) {
setIsLoading(false);
console.error(err);
}
};
return (
<div className="flex h-full w-full items-center justify-center">
<Head>
<title>Authorize Rundeck Integration</title>
<link rel="icon" href="/infisical.ico" />
</Head>
<Card className="mb-12 max-w-lg rounded-md border border-mineshaft-600">
<CardTitle
className="px-6 text-left text-xl"
subTitle="After adding your URL and auth token, you will be prompted to set up an integration for a particular Infisical project and environment."
>
<div className="flex flex-row items-center">
<div className="flex items-center pb-0.5">
<Image
src="/images/integrations/Rundeck.svg"
height={30}
width={30}
alt="Rundeck logo"
/>
</div>
<span className="ml-2.5">Rundeck Integration </span>
<Link href="https://infisical.com/docs/integrations/cicd/rundeck" passHref>
<a target="_blank" rel="noopener noreferrer">
<div className="ml-2 mb-1 inline-block cursor-default rounded-md bg-yellow/20 px-1.5 pb-[0.03rem] pt-[0.04rem] text-sm text-yellow opacity-80 hover:opacity-100">
<FontAwesomeIcon icon={faBookOpen} className="mr-1.5" />
Docs
<FontAwesomeIcon
icon={faArrowUpRightFromSquare}
className="ml-1.5 mb-[0.07rem] text-xxs"
/>
</div>
</a>
</Link>
</div>
</CardTitle>
<form onSubmit={handleSubmit(onFormSubmit)} className="px-6 pb-8 text-right">
<Controller
control={control}
name="rundeckURL"
render={({ field, fieldState: { error } }) => (
<FormControl label="URL" errorText={error?.message} isError={Boolean(error)}>
<Input {...field} placeholder="https://self-hosted-rundeck.com" />
</FormControl>
)}
/>
<Controller
control={control}
name="authToken"
render={({ field, fieldState: { error } }) => (
<FormControl
label="Rundeck Auth Token"
errorText={error?.message}
isError={Boolean(error)}
>
<Input {...field} placeholder="" />
</FormControl>
)}
/>
<Button
colorSchema="primary"
variant="outline_bg"
className="mt-2 w-min"
size="sm"
type="submit"
isLoading={isLoading}
>
Connect to Rundeck
</Button>
</form>
</Card>
</div>
);
}
RundeckAuthorizeIntegrationPage.requireAuth = true;
@@ -0,0 +1,217 @@
import { Controller, useForm } from "react-hook-form";
import Head from "next/head";
import Image from "next/image";
import Link from "next/link";
import { useRouter } from "next/router";
import { faArrowUpRightFromSquare, faBookOpen, faBugs } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { zodResolver } from "@hookform/resolvers/zod";
import queryString from "query-string";
import { z } from "zod";
import {
Button,
Card,
CardTitle,
FormControl,
Input,
Select,
SelectItem
} from "@app/components/v2";
import { SecretPathInput } from "@app/components/v2/SecretPathInput";
import { useCreateIntegration } from "@app/hooks/api";
import { useGetIntegrationAuthById } from "@app/hooks/api/integrationAuth";
import { useGetWorkspaceById } from "@app/hooks/api/workspace";
const schema = z.object({
keyStoragePath: z.string().trim().min(1, { message: "Rundeck Key Storage path is required" }),
secretPath: z.string().trim().min(1, { message: "Secret path is required" }),
sourceEnvironment: z.string().trim().min(1, { message: "Source environment is required" })
});
type TFormSchema = z.infer<typeof schema>;
export default function RundeckCreateIntegrationPage() {
const {
control,
handleSubmit,
watch,
formState: { isSubmitting }
} = useForm<TFormSchema>({
resolver: zodResolver(schema),
defaultValues: {
secretPath: "/"
}
});
const router = useRouter();
const { mutateAsync } = useCreateIntegration();
const { integrationAuthId } = queryString.parse(router.asPath.split("?")[1]);
const { data: workspace } = useGetWorkspaceById(localStorage.getItem("projectData.id") ?? "");
const { data: integrationAuth, isLoading: isIntegrationAuthLoading } = useGetIntegrationAuthById(
(integrationAuthId as string) ?? ""
);
const selectedSourceEnvironment = watch("sourceEnvironment");
const onFormSubmit = async ({ secretPath, sourceEnvironment, keyStoragePath }: TFormSchema) => {
try {
if (!integrationAuth?.id) return;
await mutateAsync({
integrationAuthId: integrationAuth?.id,
isActive: true,
path: keyStoragePath,
sourceEnvironment,
url: integrationAuth.url,
secretPath
});
router.push(`/integrations/${localStorage.getItem("projectData.id")}`);
} catch (err) {
console.error(err);
}
};
return integrationAuth && workspace ? (
<div className="flex h-full w-full flex-col items-center justify-center">
<Head>
<title>Set Up Rundeck Integration</title>
<link rel="icon" href="/infisical.ico" />
</Head>
<Card className="max-w-lg rounded-md border border-mineshaft-600">
<CardTitle
className="px-6 text-left text-xl"
subTitle="Choose which environment or folder in Infisical you want to sync to the Rundeck Key Storage."
>
<div className="flex flex-row items-center">
<div className="flex items-center pb-0.5">
<Image
src="/images/integrations/Rundeck.svg"
height={30}
width={30}
alt="Rundeck logo"
/>
</div>
<span className="ml-2.5">Rundeck Integration </span>
<Link href="https://infisical.com/docs/integrations/cloud/flyio" passHref>
<a target="_blank" rel="noopener noreferrer">
<div className="ml-2 mb-1 inline-block cursor-default rounded-md bg-yellow/20 px-1.5 pb-[0.03rem] pt-[0.04rem] text-sm text-yellow opacity-80 hover:opacity-100">
<FontAwesomeIcon icon={faBookOpen} className="mr-1.5" />
Docs
<FontAwesomeIcon
icon={faArrowUpRightFromSquare}
className="ml-1.5 mb-[0.07rem] text-xxs"
/>
</div>
</a>
</Link>
</div>
</CardTitle>
<form onSubmit={handleSubmit(onFormSubmit)} className="flex w-full flex-col px-6">
<Controller
control={control}
name="sourceEnvironment"
render={({ field, fieldState: { error } }) => (
<FormControl
label="Project Environment"
errorText={error?.message}
isError={Boolean(error)}
>
<Select
className="w-full border border-mineshaft-500"
value={field.value}
onValueChange={(val) => {
field.onChange(val);
}}
>
{workspace?.environments.map((sourceEnvironment) => (
<SelectItem
value={sourceEnvironment.slug}
key={`source-environment-${sourceEnvironment.slug}`}
>
{sourceEnvironment.name}
</SelectItem>
))}
</Select>
</FormControl>
)}
/>
<Controller
control={control}
name="secretPath"
render={({ field, fieldState: { error } }) => (
<FormControl label="Secrets Path" errorText={error?.message} isError={Boolean(error)}>
<SecretPathInput {...field} environment={selectedSourceEnvironment} />
</FormControl>
)}
/>
<Controller
control={control}
name="keyStoragePath"
render={({ field, fieldState: { error } }) => (
<FormControl
label="Rundeck Key Storage Path"
errorText={error?.message}
isError={Boolean(error)}
>
<Input
placeholder={`keys/project/${workspace.name
.toLowerCase()
.replace(/ /g, "-")}/${selectedSourceEnvironment}`}
{...field}
/>
</FormControl>
)}
/>
<Button
type="submit"
color="mineshaft"
variant="outline_bg"
className="mb-6 mt-2 ml-auto"
isLoading={isSubmitting}
>
Create Integration
</Button>
</form>
</Card>
</div>
) : (
<div className="flex h-full w-full items-center justify-center">
<Head>
<title>Set Up Rundeck Integration</title>
<link rel="icon" href="/infisical.ico" />
</Head>
{isIntegrationAuthLoading ? (
<img
src="/images/loading/loading.gif"
height={70}
width={120}
alt="infisical loading indicator"
/>
) : (
<div className="flex h-max max-w-md flex-col rounded-md border border-mineshaft-600 bg-mineshaft-800 p-6 text-center text-mineshaft-200">
<FontAwesomeIcon icon={faBugs} className="inlineli my-2 text-6xl" />
<p>
Something went wrong. Please contact{" "}
<a
className="inline cursor-pointer text-mineshaft-100 underline decoration-primary-500 underline-offset-4 opacity-80 duration-200 hover:opacity-100"
target="_blank"
rel="noopener noreferrer"
href="mailto:[email protected]"
>
support@infisical.com
</a>{" "}
if the issue persists.
</p>
</div>
)}
</div>
);
}
RundeckCreateIntegrationPage.requireAuth = true;
@@ -128,6 +128,9 @@ export const redirectForProviderAuth = (integrationOption: TCloudIntegration) =>
case "hasura-cloud": case "hasura-cloud":
link = `${window.location.origin}/integrations/hasura-cloud/authorize`; link = `${window.location.origin}/integrations/hasura-cloud/authorize`;
break; break;
case "rundeck":
link = `${window.location.origin}/integrations/rundeck/authorize`;
break;
default: default:
break; break;
} }
@@ -141,7 +141,8 @@ export const IntegrationsSection = ({
label={ label={
(integration.integration === "qovery" && integration?.scope) || (integration.integration === "qovery" && integration?.scope) ||
(integration.integration === "aws-secret-manager" && "Secret") || (integration.integration === "aws-secret-manager" && "Secret") ||
(integration.integration === "aws-parameter-store" && "Path") || (["aws-parameter-store", "rundeck"].includes(integration.integration) &&
"Path") ||
(integration?.integration === "terraform-cloud" && "Project") || (integration?.integration === "terraform-cloud" && "Project") ||
(integration?.scope === "github-org" && "Organization") || (integration?.scope === "github-org" && "Organization") ||
(["github-repo", "github-env"].includes(integration?.scope as string) && (["github-repo", "github-env"].includes(integration?.scope as string) &&
@@ -153,7 +154,7 @@ export const IntegrationsSection = ({
{(integration.integration === "hashicorp-vault" && {(integration.integration === "hashicorp-vault" &&
`${integration.app} - path: ${integration.path}`) || `${integration.app} - path: ${integration.path}`) ||
(integration.scope === "github-org" && `${integration.owner}`) || (integration.scope === "github-org" && `${integration.owner}`) ||
(integration.integration === "aws-parameter-store" && (["aws-parameter-store", "rundeck"].includes(integration.integration) &&
`${integration.path}`) || `${integration.path}`) ||
(integration.scope?.startsWith("github-") && (integration.scope?.startsWith("github-") &&
`${integration.owner}/${integration.app}`) || `${integration.owner}/${integration.app}`) ||