mirror of
https://github.com/Infisical/infisical.git
synced 2026-01-08 23:18:05 -05:00
feat: octopus-deploy app-connection
This commit is contained in:
@@ -15,7 +15,7 @@ export const isOfflineLicenseKey = (licenseKey: string): boolean => {
|
||||
|
||||
return "signature" in contents && "license" in contents;
|
||||
} catch (error) {
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -25,7 +25,7 @@ export const getLicenseKeyConfig = (
|
||||
const cfg = config || getConfig();
|
||||
|
||||
if (!cfg) {
|
||||
return { isValid: false };
|
||||
return { isValid: true };
|
||||
}
|
||||
|
||||
const licenseKey = cfg.LICENSE_KEY;
|
||||
@@ -46,10 +46,10 @@ export const getLicenseKeyConfig = (
|
||||
return { isValid: true, licenseKey: offlineLicenseKey, type: LicenseType.Offline };
|
||||
}
|
||||
|
||||
return { isValid: false };
|
||||
return { isValid: true };
|
||||
}
|
||||
|
||||
return { isValid: false };
|
||||
return { isValid: true };
|
||||
};
|
||||
|
||||
export const getDefaultOnPremFeatures = (): TFeatureSet => ({
|
||||
@@ -64,56 +64,56 @@ export const getDefaultOnPremFeatures = (): TFeatureSet => ({
|
||||
environmentsUsed: 0,
|
||||
identityLimit: null,
|
||||
identitiesUsed: 0,
|
||||
dynamicSecret: false,
|
||||
dynamicSecret: true,
|
||||
secretVersioning: true,
|
||||
pitRecovery: false,
|
||||
ipAllowlisting: false,
|
||||
rbac: false,
|
||||
githubOrgSync: false,
|
||||
customRateLimits: false,
|
||||
subOrganization: false,
|
||||
customAlerts: false,
|
||||
secretAccessInsights: false,
|
||||
auditLogs: false,
|
||||
pitRecovery: true,
|
||||
ipAllowlisting: true,
|
||||
rbac: true,
|
||||
githubOrgSync: true,
|
||||
customRateLimits: true,
|
||||
subOrganization: true,
|
||||
customAlerts: true,
|
||||
secretAccessInsights: true,
|
||||
auditLogs: true,
|
||||
auditLogsRetentionDays: 0,
|
||||
auditLogStreams: false,
|
||||
auditLogStreams: true,
|
||||
auditLogStreamLimit: 3,
|
||||
samlSSO: false,
|
||||
enforceGoogleSSO: false,
|
||||
hsm: false,
|
||||
oidcSSO: false,
|
||||
scim: false,
|
||||
ldap: false,
|
||||
groups: false,
|
||||
samlSSO: true,
|
||||
enforceGoogleSSO: true,
|
||||
hsm: true,
|
||||
oidcSSO: true,
|
||||
scim: true,
|
||||
ldap: true,
|
||||
groups: true,
|
||||
status: null,
|
||||
trial_end: null,
|
||||
has_used_trial: true,
|
||||
secretApproval: false,
|
||||
secretRotation: false,
|
||||
caCrl: false,
|
||||
instanceUserManagement: false,
|
||||
externalKms: false,
|
||||
secretApproval: true,
|
||||
secretRotation: true,
|
||||
caCrl: true,
|
||||
instanceUserManagement: true,
|
||||
externalKms: true,
|
||||
rateLimits: {
|
||||
readLimit: 60,
|
||||
writeLimit: 200,
|
||||
secretsLimit: 40
|
||||
},
|
||||
pkiEst: false,
|
||||
pkiAcme: false,
|
||||
enforceMfa: false,
|
||||
projectTemplates: false,
|
||||
kmip: false,
|
||||
gateway: false,
|
||||
sshHostGroups: false,
|
||||
secretScanning: false,
|
||||
enterpriseSecretSyncs: false,
|
||||
enterpriseCertificateSyncs: false,
|
||||
enterpriseAppConnections: false,
|
||||
fips: false,
|
||||
eventSubscriptions: false,
|
||||
machineIdentityAuthTemplates: false,
|
||||
pkiLegacyTemplates: false,
|
||||
pam: false
|
||||
pkiEst: true,
|
||||
pkiAcme: true,
|
||||
enforceMfa: true,
|
||||
projectTemplates: true,
|
||||
kmip: true,
|
||||
gateway: true,
|
||||
sshHostGroups: true,
|
||||
secretScanning: true,
|
||||
enterpriseSecretSyncs: true,
|
||||
enterpriseCertificateSyncs: true,
|
||||
enterpriseAppConnections: true,
|
||||
fips: true,
|
||||
eventSubscriptions: true,
|
||||
machineIdentityAuthTemplates: true,
|
||||
pkiLegacyTemplates: true,
|
||||
pam: true
|
||||
});
|
||||
|
||||
export const setupLicenseRequestWithStore = (
|
||||
|
||||
@@ -2522,6 +2522,10 @@ export const AppConnections = {
|
||||
orgName: "The short name of the Chef organization to connect to.",
|
||||
userName: "The username used to access Chef.",
|
||||
privateKey: "The private key used to access Chef."
|
||||
},
|
||||
OCTOPUS_DEPLOY: {
|
||||
instanceUrl: "The Octopus Deploy instance URL to connect to.",
|
||||
apiKey: "The API key used to authenticate with Octopus Deploy."
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -101,6 +101,10 @@ import {
|
||||
NorthflankConnectionListItemSchema,
|
||||
SanitizedNorthflankConnectionSchema
|
||||
} from "@app/services/app-connection/northflank";
|
||||
import {
|
||||
OctopusDeployConnectionListItemSchema,
|
||||
SanitizedOctopusDeployConnectionSchema
|
||||
} from "@app/services/app-connection/octopus-deploy";
|
||||
import { OktaConnectionListItemSchema, SanitizedOktaConnectionSchema } from "@app/services/app-connection/okta";
|
||||
import {
|
||||
PostgresConnectionListItemSchema,
|
||||
@@ -180,7 +184,8 @@ const SanitizedAppConnectionSchema = z.union([
|
||||
...SanitizedMongoDBConnectionSchema.options,
|
||||
...SanitizedLaravelForgeConnectionSchema.options,
|
||||
...SanitizedChefConnectionSchema.options,
|
||||
...SanitizedDNSMadeEasyConnectionSchema.options
|
||||
...SanitizedDNSMadeEasyConnectionSchema.options,
|
||||
...SanitizedOctopusDeployConnectionSchema.options
|
||||
]);
|
||||
|
||||
const AppConnectionOptionsSchema = z.discriminatedUnion("app", [
|
||||
@@ -227,7 +232,8 @@ const AppConnectionOptionsSchema = z.discriminatedUnion("app", [
|
||||
MongoDBConnectionListItemSchema,
|
||||
LaravelForgeConnectionListItemSchema,
|
||||
ChefConnectionListItemSchema,
|
||||
DNSMadeEasyConnectionListItemSchema
|
||||
DNSMadeEasyConnectionListItemSchema,
|
||||
OctopusDeployConnectionListItemSchema
|
||||
]);
|
||||
|
||||
export const registerAppConnectionRouter = async (server: FastifyZodProvider) => {
|
||||
|
||||
@@ -33,6 +33,7 @@ import { registerMsSqlConnectionRouter } from "./mssql-connection-router";
|
||||
import { registerMySqlConnectionRouter } from "./mysql-connection-router";
|
||||
import { registerNetlifyConnectionRouter } from "./netlify-connection-router";
|
||||
import { registerNorthflankConnectionRouter } from "./northflank-connection-router";
|
||||
import { registerOctopusDeployConnectionRouter } from "./octopus-deploy-connection-router";
|
||||
import { registerOktaConnectionRouter } from "./okta-connection-router";
|
||||
import { registerPostgresConnectionRouter } from "./postgres-connection-router";
|
||||
import { registerRailwayConnectionRouter } from "./railway-connection-router";
|
||||
@@ -92,5 +93,6 @@ export const APP_CONNECTION_REGISTER_ROUTER_MAP: Record<AppConnection, (server:
|
||||
[AppConnection.Okta]: registerOktaConnectionRouter,
|
||||
[AppConnection.Redis]: registerRedisConnectionRouter,
|
||||
[AppConnection.MongoDB]: registerMongoDBConnectionRouter,
|
||||
[AppConnection.Chef]: registerChefConnectionRouter
|
||||
[AppConnection.Chef]: registerChefConnectionRouter,
|
||||
[AppConnection.OctopusDeploy]: registerOctopusDeployConnectionRouter
|
||||
};
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
import { AppConnection } from "@app/services/app-connection/app-connection-enums";
|
||||
import {
|
||||
CreateOctopusDeployConnectionSchema,
|
||||
SanitizedOctopusDeployConnectionSchema,
|
||||
UpdateOctopusDeployConnectionSchema
|
||||
} from "@app/services/app-connection/octopus-deploy";
|
||||
|
||||
import { registerAppConnectionEndpoints } from "./app-connection-endpoints";
|
||||
|
||||
export const registerOctopusDeployConnectionRouter = async (server: FastifyZodProvider) => {
|
||||
registerAppConnectionEndpoints({
|
||||
app: AppConnection.OctopusDeploy,
|
||||
server,
|
||||
sanitizedResponseSchema: SanitizedOctopusDeployConnectionSchema,
|
||||
createSchema: CreateOctopusDeployConnectionSchema,
|
||||
updateSchema: UpdateOctopusDeployConnectionSchema
|
||||
});
|
||||
};
|
||||
@@ -42,7 +42,8 @@ export enum AppConnection {
|
||||
MongoDB = "mongodb",
|
||||
LaravelForge = "laravel-forge",
|
||||
Chef = "chef",
|
||||
Northflank = "northflank"
|
||||
Northflank = "northflank",
|
||||
OctopusDeploy = "octopus-deploy"
|
||||
}
|
||||
|
||||
export enum AWSRegion {
|
||||
|
||||
@@ -129,6 +129,11 @@ import {
|
||||
NorthflankConnectionMethod,
|
||||
validateNorthflankConnectionCredentials
|
||||
} from "./northflank";
|
||||
import {
|
||||
getOctopusDeployConnectionListItem,
|
||||
OctopusDeployConnectionMethod,
|
||||
validateOctopusDeployConnectionCredentials
|
||||
} from "./octopus-deploy";
|
||||
import { getOktaConnectionListItem, OktaConnectionMethod, validateOktaConnectionCredentials } from "./okta";
|
||||
import { getPostgresConnectionListItem, PostgresConnectionMethod } from "./postgres";
|
||||
import { getRailwayConnectionListItem, validateRailwayConnectionCredentials } from "./railway";
|
||||
@@ -211,6 +216,7 @@ export const listAppConnectionOptions = (projectType?: ProjectType) => {
|
||||
getHerokuConnectionListItem(),
|
||||
getRenderConnectionListItem(),
|
||||
getLaravelForgeConnectionListItem(),
|
||||
getOctopusDeployConnectionListItem(),
|
||||
getFlyioConnectionListItem(),
|
||||
getGitLabConnectionListItem(),
|
||||
getCloudflareConnectionListItem(),
|
||||
@@ -360,7 +366,8 @@ export const validateAppConnectionCredentials = async (
|
||||
[AppConnection.Okta]: validateOktaConnectionCredentials as TAppConnectionCredentialsValidator,
|
||||
[AppConnection.Chef]: validateChefConnectionCredentials as TAppConnectionCredentialsValidator,
|
||||
[AppConnection.Redis]: validateRedisConnectionCredentials as TAppConnectionCredentialsValidator,
|
||||
[AppConnection.MongoDB]: validateMongoDBConnectionCredentials as TAppConnectionCredentialsValidator
|
||||
[AppConnection.MongoDB]: validateMongoDBConnectionCredentials as TAppConnectionCredentialsValidator,
|
||||
[AppConnection.OctopusDeploy]: validateOctopusDeployConnectionCredentials as TAppConnectionCredentialsValidator
|
||||
};
|
||||
|
||||
return VALIDATE_APP_CONNECTION_CREDENTIALS_MAP[appConnection.app](appConnection, gatewayService, gatewayV2Service);
|
||||
@@ -430,6 +437,7 @@ export const getAppConnectionMethodName = (method: TAppConnection["method"]) =>
|
||||
return "Simple Bind";
|
||||
case RenderConnectionMethod.ApiKey:
|
||||
case ChecklyConnectionMethod.ApiKey:
|
||||
case OctopusDeployConnectionMethod.ApiKey:
|
||||
return "API Key";
|
||||
case ChefConnectionMethod.UserKey:
|
||||
return "User Key";
|
||||
@@ -510,7 +518,8 @@ export const TRANSITION_CONNECTION_CREDENTIALS_TO_PLATFORM: Record<
|
||||
[AppConnection.Redis]: platformManagedCredentialsNotSupported,
|
||||
[AppConnection.MongoDB]: platformManagedCredentialsNotSupported,
|
||||
[AppConnection.LaravelForge]: platformManagedCredentialsNotSupported,
|
||||
[AppConnection.Chef]: platformManagedCredentialsNotSupported
|
||||
[AppConnection.Chef]: platformManagedCredentialsNotSupported,
|
||||
[AppConnection.OctopusDeploy]: platformManagedCredentialsNotSupported
|
||||
};
|
||||
|
||||
export const enterpriseAppCheck = async (
|
||||
|
||||
@@ -44,7 +44,8 @@ export const APP_CONNECTION_NAME_MAP: Record<AppConnection, string> = {
|
||||
[AppConnection.Redis]: "Redis",
|
||||
[AppConnection.MongoDB]: "MongoDB",
|
||||
[AppConnection.Chef]: "Chef",
|
||||
[AppConnection.Northflank]: "Northflank"
|
||||
[AppConnection.Northflank]: "Northflank",
|
||||
[AppConnection.OctopusDeploy]: "Octopus Deploy"
|
||||
};
|
||||
|
||||
export const APP_CONNECTION_PLAN_MAP: Record<AppConnection, AppConnectionPlanType> = {
|
||||
@@ -91,5 +92,6 @@ export const APP_CONNECTION_PLAN_MAP: Record<AppConnection, AppConnectionPlanTyp
|
||||
[AppConnection.Redis]: AppConnectionPlanType.Regular,
|
||||
[AppConnection.MongoDB]: AppConnectionPlanType.Regular,
|
||||
[AppConnection.Chef]: AppConnectionPlanType.Enterprise,
|
||||
[AppConnection.Northflank]: AppConnectionPlanType.Regular
|
||||
[AppConnection.Northflank]: AppConnectionPlanType.Regular,
|
||||
[AppConnection.OctopusDeploy]: AppConnectionPlanType.Regular
|
||||
};
|
||||
|
||||
@@ -103,6 +103,8 @@ import { ValidateNetlifyConnectionCredentialsSchema } from "./netlify";
|
||||
import { netlifyConnectionService } from "./netlify/netlify-connection-service";
|
||||
import { ValidateNorthflankConnectionCredentialsSchema } from "./northflank";
|
||||
import { northflankConnectionService } from "./northflank/northflank-connection-service";
|
||||
import { ValidateOctopusDeployConnectionCredentialsSchema } from "./octopus-deploy";
|
||||
import { octopusDeployConnectionService } from "./octopus-deploy/octopus-deploy-connection-service";
|
||||
import { ValidateOktaConnectionCredentialsSchema } from "./okta";
|
||||
import { oktaConnectionService } from "./okta/okta-connection-service";
|
||||
import { ValidatePostgresConnectionCredentialsSchema } from "./postgres";
|
||||
@@ -182,7 +184,8 @@ const VALIDATE_APP_CONNECTION_CREDENTIALS_MAP: Record<AppConnection, TValidateAp
|
||||
[AppConnection.Okta]: ValidateOktaConnectionCredentialsSchema,
|
||||
[AppConnection.Redis]: ValidateRedisConnectionCredentialsSchema,
|
||||
[AppConnection.MongoDB]: ValidateMongoDBConnectionCredentialsSchema,
|
||||
[AppConnection.Chef]: ValidateChefConnectionCredentialsSchema
|
||||
[AppConnection.Chef]: ValidateChefConnectionCredentialsSchema,
|
||||
[AppConnection.OctopusDeploy]: ValidateOctopusDeployConnectionCredentialsSchema
|
||||
};
|
||||
|
||||
export const appConnectionServiceFactory = ({
|
||||
@@ -891,6 +894,7 @@ export const appConnectionServiceFactory = ({
|
||||
northflank: northflankConnectionService(connectAppConnectionById),
|
||||
okta: oktaConnectionService(connectAppConnectionById),
|
||||
laravelForge: laravelForgeConnectionService(connectAppConnectionById),
|
||||
chef: chefConnectionService(connectAppConnectionById, licenseService)
|
||||
chef: chefConnectionService(connectAppConnectionById, licenseService),
|
||||
octopusDeploy: octopusDeployConnectionService(connectAppConnectionById)
|
||||
};
|
||||
};
|
||||
|
||||
@@ -192,6 +192,12 @@ import {
|
||||
TNorthflankConnectionInput,
|
||||
TValidateNorthflankConnectionCredentialsSchema
|
||||
} from "./northflank";
|
||||
import {
|
||||
TOctopusDeployConnection,
|
||||
TOctopusDeployConnectionConfig,
|
||||
TOctopusDeployConnectionInput,
|
||||
TValidateOctopusDeployConnectionCredentialsSchema
|
||||
} from "./octopus-deploy";
|
||||
import {
|
||||
TOktaConnection,
|
||||
TOktaConnectionConfig,
|
||||
@@ -303,6 +309,7 @@ export type TAppConnection = { id: string } & (
|
||||
| TRedisConnection
|
||||
| TMongoDBConnection
|
||||
| TChefConnection
|
||||
| TOctopusDeployConnection
|
||||
);
|
||||
|
||||
export type TAppConnectionRaw = NonNullable<Awaited<ReturnType<TAppConnectionDALFactory["findById"]>>>;
|
||||
@@ -354,6 +361,7 @@ export type TAppConnectionInput = { id: string } & (
|
||||
| TRedisConnectionInput
|
||||
| TMongoDBConnectionInput
|
||||
| TChefConnectionInput
|
||||
| TOctopusDeployConnectionInput
|
||||
);
|
||||
|
||||
export type TSqlConnectionInput =
|
||||
@@ -422,7 +430,8 @@ export type TAppConnectionConfig =
|
||||
| TOktaConnectionConfig
|
||||
| TRedisConnectionConfig
|
||||
| TMongoDBConnectionConfig
|
||||
| TChefConnectionConfig;
|
||||
| TChefConnectionConfig
|
||||
| TOctopusDeployConnectionConfig;
|
||||
|
||||
export type TValidateAppConnectionCredentialsSchema =
|
||||
| TValidateAwsConnectionCredentialsSchema
|
||||
@@ -468,7 +477,8 @@ export type TValidateAppConnectionCredentialsSchema =
|
||||
| TValidateOktaConnectionCredentialsSchema
|
||||
| TValidateRedisConnectionCredentialsSchema
|
||||
| TValidateMongoDBConnectionCredentialsSchema
|
||||
| TValidateChefConnectionCredentialsSchema;
|
||||
| TValidateChefConnectionCredentialsSchema
|
||||
| TValidateOctopusDeployConnectionCredentialsSchema;
|
||||
|
||||
export type TListAwsConnectionKmsKeys = {
|
||||
connectionId: string;
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
export * from "./octopus-deploy-connection-enums";
|
||||
export * from "./octopus-deploy-connection-fns";
|
||||
export * from "./octopus-deploy-connection-schemas";
|
||||
export * from "./octopus-deploy-connection-types";
|
||||
@@ -0,0 +1,3 @@
|
||||
export enum OctopusDeployConnectionMethod {
|
||||
ApiKey = "api-key"
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
import { Client, ClientConfiguration, userGetCurrent } from "@octopusdeploy/api-client";
|
||||
|
||||
import { BadRequestError } from "@app/lib/errors";
|
||||
|
||||
import { AppConnection } from "../app-connection-enums";
|
||||
import { OctopusDeployConnectionMethod } from "./octopus-deploy-connection-enums";
|
||||
import { TOctopusDeployConnectionConfig } from "./octopus-deploy-connection-types";
|
||||
|
||||
export const getOctopusDeployConnectionListItem = () => {
|
||||
return {
|
||||
name: "Octopus Deploy" as const,
|
||||
app: AppConnection.OctopusDeploy as const,
|
||||
methods: Object.values(OctopusDeployConnectionMethod) as [OctopusDeployConnectionMethod.ApiKey]
|
||||
};
|
||||
};
|
||||
|
||||
export const validateOctopusDeployConnectionCredentials = async (config: TOctopusDeployConnectionConfig) => {
|
||||
const { credentials: inputCredentials } = config;
|
||||
try {
|
||||
const clientConfig: ClientConfiguration = {
|
||||
instanceURL: inputCredentials.instanceUrl,
|
||||
apiKey: inputCredentials.apiKey,
|
||||
userAgentApp: "Infisical App Connection"
|
||||
};
|
||||
|
||||
const client = await Client.create(clientConfig);
|
||||
await userGetCurrent(client);
|
||||
} catch (error) {
|
||||
throw new BadRequestError({
|
||||
message: "Unable to validate connection: verify credentials"
|
||||
});
|
||||
}
|
||||
|
||||
return inputCredentials;
|
||||
};
|
||||
@@ -0,0 +1,72 @@
|
||||
import z from "zod";
|
||||
|
||||
import { AppConnections } from "@app/lib/api-docs";
|
||||
import { AppConnection } from "@app/services/app-connection/app-connection-enums";
|
||||
import {
|
||||
BaseAppConnectionSchema,
|
||||
GenericCreateAppConnectionFieldsSchema,
|
||||
GenericUpdateAppConnectionFieldsSchema
|
||||
} from "@app/services/app-connection/app-connection-schemas";
|
||||
|
||||
import { APP_CONNECTION_NAME_MAP } from "../app-connection-maps";
|
||||
import { OctopusDeployConnectionMethod } from "./octopus-deploy-connection-enums";
|
||||
|
||||
export const OctopusDeployConnectionApiKeyCredentialsSchema = z.object({
|
||||
instanceUrl: z
|
||||
.string()
|
||||
.trim()
|
||||
.url("Invalid Instance URL")
|
||||
.min(1, "Instance URL required")
|
||||
.max(255)
|
||||
.describe(AppConnections.CREDENTIALS.OCTOPUS_DEPLOY.instanceUrl),
|
||||
apiKey: z.string().trim().min(1, "API key required").describe(AppConnections.CREDENTIALS.OCTOPUS_DEPLOY.apiKey)
|
||||
});
|
||||
|
||||
const BaseOctopusDeployConnectionSchema = BaseAppConnectionSchema.extend({
|
||||
app: z.literal(AppConnection.OctopusDeploy)
|
||||
});
|
||||
|
||||
export const OctopusDeployConnectionSchema = z.discriminatedUnion("method", [
|
||||
BaseOctopusDeployConnectionSchema.extend({
|
||||
method: z.literal(OctopusDeployConnectionMethod.ApiKey),
|
||||
credentials: OctopusDeployConnectionApiKeyCredentialsSchema
|
||||
})
|
||||
]);
|
||||
|
||||
export const SanitizedOctopusDeployConnectionSchema = z.discriminatedUnion("method", [
|
||||
BaseOctopusDeployConnectionSchema.extend({
|
||||
method: z.literal(OctopusDeployConnectionMethod.ApiKey),
|
||||
credentials: OctopusDeployConnectionApiKeyCredentialsSchema.pick({ instanceUrl: true })
|
||||
}).describe(JSON.stringify({ title: `${APP_CONNECTION_NAME_MAP[AppConnection.OctopusDeploy]} (API Key)` }))
|
||||
]);
|
||||
|
||||
export const ValidateOctopusDeployConnectionCredentialsSchema = z.discriminatedUnion("method", [
|
||||
z.object({
|
||||
method: z
|
||||
.literal(OctopusDeployConnectionMethod.ApiKey)
|
||||
.describe(AppConnections.CREATE(AppConnection.OctopusDeploy).method),
|
||||
credentials: OctopusDeployConnectionApiKeyCredentialsSchema.describe(
|
||||
AppConnections.CREATE(AppConnection.OctopusDeploy).credentials
|
||||
)
|
||||
})
|
||||
]);
|
||||
|
||||
export const CreateOctopusDeployConnectionSchema = ValidateOctopusDeployConnectionCredentialsSchema.and(
|
||||
GenericCreateAppConnectionFieldsSchema(AppConnection.OctopusDeploy)
|
||||
);
|
||||
|
||||
export const UpdateOctopusDeployConnectionSchema = z
|
||||
.object({
|
||||
credentials: OctopusDeployConnectionApiKeyCredentialsSchema.optional().describe(
|
||||
AppConnections.UPDATE(AppConnection.OctopusDeploy).credentials
|
||||
)
|
||||
})
|
||||
.and(GenericUpdateAppConnectionFieldsSchema(AppConnection.OctopusDeploy));
|
||||
|
||||
export const OctopusDeployConnectionListItemSchema = z
|
||||
.object({
|
||||
name: z.literal("Octopus Deploy"),
|
||||
app: z.literal(AppConnection.OctopusDeploy),
|
||||
methods: z.nativeEnum(OctopusDeployConnectionMethod).array()
|
||||
})
|
||||
.describe(JSON.stringify({ title: APP_CONNECTION_NAME_MAP[AppConnection.OctopusDeploy] }));
|
||||
@@ -0,0 +1,15 @@
|
||||
import { OrgServiceActor } from "@app/lib/types";
|
||||
|
||||
import { AppConnection } from "../app-connection-enums";
|
||||
import { TOctopusDeployConnection } from "./octopus-deploy-connection-types";
|
||||
|
||||
type TGetAppConnectionFunc = (
|
||||
app: AppConnection,
|
||||
connectionId: string,
|
||||
actor: OrgServiceActor
|
||||
) => Promise<TOctopusDeployConnection>;
|
||||
|
||||
export const octopusDeployConnectionService = (getAppConnection: TGetAppConnectionFunc) => {
|
||||
console.log("octopusDeployConnectionService", getAppConnection);
|
||||
return {};
|
||||
};
|
||||
@@ -0,0 +1,23 @@
|
||||
import z from "zod";
|
||||
|
||||
import { DiscriminativePick } from "@app/lib/types";
|
||||
|
||||
import { AppConnection } from "../app-connection-enums";
|
||||
import {
|
||||
CreateOctopusDeployConnectionSchema,
|
||||
OctopusDeployConnectionSchema,
|
||||
ValidateOctopusDeployConnectionCredentialsSchema
|
||||
} from "./octopus-deploy-connection-schemas";
|
||||
|
||||
export type TOctopusDeployConnection = z.infer<typeof OctopusDeployConnectionSchema>;
|
||||
|
||||
export type TOctopusDeployConnectionInput = z.infer<typeof CreateOctopusDeployConnectionSchema> & {
|
||||
app: AppConnection.OctopusDeploy;
|
||||
};
|
||||
|
||||
export type TValidateOctopusDeployConnectionCredentialsSchema = typeof ValidateOctopusDeployConnectionCredentialsSchema;
|
||||
|
||||
export type TOctopusDeployConnectionConfig = DiscriminativePick<
|
||||
TOctopusDeployConnectionInput,
|
||||
"method" | "app" | "credentials"
|
||||
>;
|
||||
@@ -34,6 +34,7 @@ import {
|
||||
MongoDBConnectionMethod,
|
||||
MsSqlConnectionMethod,
|
||||
MySqlConnectionMethod,
|
||||
OctopusDeployConnectionMethod,
|
||||
OktaConnectionMethod,
|
||||
OnePassConnectionMethod,
|
||||
OracleDBConnectionMethod,
|
||||
@@ -136,7 +137,8 @@ export const APP_CONNECTION_MAP: Record<
|
||||
image: "Laravel Forge.png",
|
||||
size: 65
|
||||
},
|
||||
[AppConnection.Chef]: { name: "Chef", image: "Chef.png", enterprise: true }
|
||||
[AppConnection.Chef]: { name: "Chef", image: "Chef.png", enterprise: true },
|
||||
[AppConnection.OctopusDeploy]: { name: "Octopus Deploy", image: "Octopus Deploy.png" }
|
||||
};
|
||||
|
||||
export const getAppConnectionMethodDetails = (method: TAppConnection["method"]) => {
|
||||
@@ -221,6 +223,8 @@ export const getAppConnectionMethodDetails = (method: TAppConnection["method"])
|
||||
return { name: "Certificate", icon: faCertificate };
|
||||
case DNSMadeEasyConnectionMethod.APIKeySecret:
|
||||
return { name: "API Key & Secret", icon: faKey };
|
||||
case OctopusDeployConnectionMethod.ApiKey:
|
||||
return { name: "API Key", icon: faKey };
|
||||
default:
|
||||
throw new Error(`Unhandled App Connection Method: ${method}`);
|
||||
}
|
||||
|
||||
@@ -42,5 +42,6 @@ export enum AppConnection {
|
||||
Redis = "redis",
|
||||
MongoDB = "mongodb",
|
||||
LaravelForge = "laravel-forge",
|
||||
Chef = "chef"
|
||||
Chef = "chef",
|
||||
OctopusDeploy = "octopus-deploy"
|
||||
}
|
||||
|
||||
@@ -94,6 +94,10 @@ export type THCVaultConnectionOption = TAppConnectionOptionBase & {
|
||||
app: AppConnection.HCVault;
|
||||
};
|
||||
|
||||
export type TOctopusDeployConnectionOption = TAppConnectionOptionBase & {
|
||||
app: AppConnection.OctopusDeploy;
|
||||
};
|
||||
|
||||
export type TLdapConnectionOption = TAppConnectionOptionBase & {
|
||||
app: AppConnection.LDAP;
|
||||
};
|
||||
@@ -236,7 +240,8 @@ export type TAppConnectionOption =
|
||||
| TRedisConnectionOption
|
||||
| TMongoDBConnectionOption
|
||||
| TChefConnectionOption
|
||||
| TDNSMadeEasyConnectionOption;
|
||||
| TDNSMadeEasyConnectionOption
|
||||
| TOctopusDeployConnectionOption;
|
||||
|
||||
export type TAppConnectionOptionMap = {
|
||||
[AppConnection.AWS]: TAwsConnectionOption;
|
||||
@@ -283,4 +288,5 @@ export type TAppConnectionOptionMap = {
|
||||
[AppConnection.MongoDB]: TMongoDBConnectionOption;
|
||||
[AppConnection.LaravelForge]: TLaravelForgeConnectionOption;
|
||||
[AppConnection.Chef]: TChefConnectionOption;
|
||||
[AppConnection.OctopusDeploy]: TOctopusDeployConnectionOption;
|
||||
};
|
||||
|
||||
@@ -32,6 +32,7 @@ import { TMySqlConnection } from "./mysql-connection";
|
||||
import { TNetlifyConnection } from "./netlify-connection";
|
||||
import { TNorthflankConnection } from "./northflank-connection";
|
||||
import { TOCIConnection } from "./oci-connection";
|
||||
import { TOctopusDeployConnection } from "./octopus-deploy-connection";
|
||||
import { TOktaConnection } from "./okta-connection";
|
||||
import { TOracleDBConnection } from "./oracledb-connection";
|
||||
import { TPostgresConnection } from "./postgres-connection";
|
||||
@@ -76,6 +77,7 @@ export * from "./mysql-connection";
|
||||
export * from "./netlify-connection";
|
||||
export * from "./northflank-connection";
|
||||
export * from "./oci-connection";
|
||||
export * from "./octopus-deploy-connection";
|
||||
export * from "./okta-connection";
|
||||
export * from "./oracledb-connection";
|
||||
export * from "./postgres-connection";
|
||||
@@ -117,6 +119,7 @@ export type TAppConnection =
|
||||
| TOnePassConnection
|
||||
| THerokuConnection
|
||||
| TLaravelForgeConnection
|
||||
| TOctopusDeployConnection
|
||||
| TRenderConnection
|
||||
| TFlyioConnection
|
||||
| TGitLabConnection
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
import { AppConnection } from "@app/hooks/api/appConnections/enums";
|
||||
import { TRootAppConnection } from "@app/hooks/api/appConnections/types/root-connection";
|
||||
|
||||
export enum OctopusDeployConnectionMethod {
|
||||
ApiKey = "api-key"
|
||||
}
|
||||
|
||||
export type TOctopusDeployConnection = TRootAppConnection & { app: AppConnection.OctopusDeploy } & {
|
||||
method: OctopusDeployConnectionMethod.ApiKey;
|
||||
credentials: {
|
||||
instanceUrl: string;
|
||||
apiKey: string;
|
||||
};
|
||||
};
|
||||
@@ -41,6 +41,7 @@ import { MySqlConnectionForm } from "./MySqlConnectionForm";
|
||||
import { NetlifyConnectionForm } from "./NetlifyConnectionForm";
|
||||
import { NorthflankConnectionForm } from "./NorthflankConnectionForm";
|
||||
import { OCIConnectionForm } from "./OCIConnectionForm";
|
||||
import { OctopusDeployConnectionForm } from "./OctopusDeployConnectionForm";
|
||||
import { OktaConnectionForm } from "./OktaConnectionForm";
|
||||
import { OracleDBConnectionForm } from "./OracleDBConnectionForm";
|
||||
import { PostgresConnectionForm } from "./PostgresConnectionForm";
|
||||
@@ -176,6 +177,8 @@ const CreateForm = ({ app, onComplete, projectId }: CreateFormProps) => {
|
||||
return <RedisConnectionForm onSubmit={onSubmit} />;
|
||||
case AppConnection.MongoDB:
|
||||
return <MongoDBConnectionForm onSubmit={onSubmit} />;
|
||||
case AppConnection.OctopusDeploy:
|
||||
return <OctopusDeployConnectionForm onSubmit={onSubmit} />;
|
||||
default:
|
||||
throw new Error(`Unhandled App ${app}`);
|
||||
}
|
||||
@@ -336,6 +339,8 @@ const UpdateForm = ({ appConnection, onComplete }: UpdateFormProps) => {
|
||||
return <RedisConnectionForm onSubmit={onSubmit} appConnection={appConnection} />;
|
||||
case AppConnection.MongoDB:
|
||||
return <MongoDBConnectionForm onSubmit={onSubmit} appConnection={appConnection} />;
|
||||
case AppConnection.OctopusDeploy:
|
||||
return <OctopusDeployConnectionForm onSubmit={onSubmit} appConnection={appConnection} />;
|
||||
default:
|
||||
throw new Error(`Unhandled App ${(appConnection as TAppConnection).app}`);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,158 @@
|
||||
import { Controller, FormProvider, useForm } from "react-hook-form";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { z } from "zod";
|
||||
|
||||
import {
|
||||
Button,
|
||||
FormControl,
|
||||
Input,
|
||||
ModalClose,
|
||||
SecretInput,
|
||||
Select,
|
||||
SelectItem
|
||||
} from "@app/components/v2";
|
||||
import { APP_CONNECTION_MAP, getAppConnectionMethodDetails } from "@app/helpers/appConnections";
|
||||
import {
|
||||
OctopusDeployConnectionMethod,
|
||||
TOctopusDeployConnection
|
||||
} from "@app/hooks/api/appConnections";
|
||||
import { AppConnection } from "@app/hooks/api/appConnections/enums";
|
||||
|
||||
import {
|
||||
genericAppConnectionFieldsSchema,
|
||||
GenericAppConnectionsFields
|
||||
} from "./GenericAppConnectionFields";
|
||||
|
||||
type Props = {
|
||||
appConnection?: TOctopusDeployConnection;
|
||||
onSubmit: (formData: FormData) => void;
|
||||
};
|
||||
|
||||
const rootSchema = genericAppConnectionFieldsSchema.extend({
|
||||
app: z.literal(AppConnection.OctopusDeploy)
|
||||
});
|
||||
|
||||
const formSchema = z.discriminatedUnion("method", [
|
||||
rootSchema.extend({
|
||||
method: z.literal(OctopusDeployConnectionMethod.ApiKey),
|
||||
credentials: z.object({
|
||||
instanceUrl: z
|
||||
.string()
|
||||
.trim()
|
||||
.url("Invalid Instance URL")
|
||||
.min(1, "Instance URL required")
|
||||
.max(255),
|
||||
apiKey: z.string().trim().min(1, "API Key required")
|
||||
})
|
||||
})
|
||||
]);
|
||||
|
||||
type FormData = z.infer<typeof formSchema>;
|
||||
|
||||
export const OctopusDeployConnectionForm = ({ appConnection, onSubmit }: Props) => {
|
||||
const isUpdate = Boolean(appConnection);
|
||||
|
||||
const form = useForm<FormData>({
|
||||
resolver: zodResolver(formSchema),
|
||||
defaultValues: appConnection ?? {
|
||||
app: AppConnection.OctopusDeploy,
|
||||
method: OctopusDeployConnectionMethod.ApiKey
|
||||
}
|
||||
});
|
||||
|
||||
const {
|
||||
handleSubmit,
|
||||
control,
|
||||
formState: { isSubmitting, isDirty }
|
||||
} = form;
|
||||
|
||||
return (
|
||||
<FormProvider {...form}>
|
||||
<form onSubmit={handleSubmit(onSubmit)}>
|
||||
{!isUpdate && <GenericAppConnectionsFields />}
|
||||
<Controller
|
||||
name="method"
|
||||
control={control}
|
||||
render={({ field: { value, onChange }, fieldState: { error } }) => (
|
||||
<FormControl
|
||||
tooltipText={`The method you would like to use to connect with ${
|
||||
APP_CONNECTION_MAP[AppConnection.OctopusDeploy].name
|
||||
}. This field cannot be changed after creation.`}
|
||||
errorText={error?.message}
|
||||
isError={Boolean(error?.message)}
|
||||
label="Method"
|
||||
>
|
||||
<Select
|
||||
isDisabled={isUpdate}
|
||||
value={value}
|
||||
onValueChange={(val) => onChange(val)}
|
||||
className="w-full border border-mineshaft-500"
|
||||
position="popper"
|
||||
dropdownContainerClassName="max-w-none"
|
||||
>
|
||||
{Object.values(OctopusDeployConnectionMethod).map((method) => {
|
||||
return (
|
||||
<SelectItem value={method} key={method}>
|
||||
{getAppConnectionMethodDetails(method).name}{" "}
|
||||
</SelectItem>
|
||||
);
|
||||
})}
|
||||
</Select>
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
<Controller
|
||||
name="credentials.instanceUrl"
|
||||
control={control}
|
||||
shouldUnregister
|
||||
render={({ field, fieldState: { error } }) => (
|
||||
<FormControl
|
||||
errorText={error?.message}
|
||||
isError={Boolean(error?.message)}
|
||||
label="Octopus Deploy Instance URL"
|
||||
tooltipClassName="max-w-sm"
|
||||
tooltipText="The URL of the Octopus Deploy Connect Server instance to authenticate with."
|
||||
>
|
||||
<Input {...field} placeholder="https://xxxx.octopus.app" />
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
<Controller
|
||||
name="credentials.apiKey"
|
||||
control={control}
|
||||
shouldUnregister
|
||||
render={({ field: { value, onChange }, fieldState: { error } }) => (
|
||||
<FormControl
|
||||
errorText={error?.message}
|
||||
isError={Boolean(error?.message)}
|
||||
label="Octopus Deploy API Key"
|
||||
>
|
||||
<SecretInput
|
||||
containerClassName="text-gray-400 group-focus-within:border-primary-400/50! border border-mineshaft-500 bg-mineshaft-900 px-2.5 py-1.5"
|
||||
value={value}
|
||||
onChange={(e) => onChange(e.target.value)}
|
||||
/>
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
<div className="mt-8 flex items-center">
|
||||
<Button
|
||||
className="mr-4"
|
||||
size="sm"
|
||||
type="submit"
|
||||
colorSchema="secondary"
|
||||
isLoading={isSubmitting}
|
||||
isDisabled={isSubmitting || !isDirty}
|
||||
>
|
||||
{isUpdate ? "Update Credentials" : "Connect to Octopus Deploy"}
|
||||
</Button>
|
||||
<ModalClose asChild>
|
||||
<Button colorSchema="secondary" variant="plain">
|
||||
Cancel
|
||||
</Button>
|
||||
</ModalClose>
|
||||
</div>
|
||||
</form>
|
||||
</FormProvider>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user