mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-05 10:26:35 +00:00
Review fixes
This commit is contained in:
@@ -366,7 +366,7 @@ export const initEnvConfig = (logger?: CustomLogger) => {
|
|||||||
export const overwriteSchema: {
|
export const overwriteSchema: {
|
||||||
[key: string]: {
|
[key: string]: {
|
||||||
name: string;
|
name: string;
|
||||||
fields: { key: keyof z.input<typeof envSchema>; description?: string }[];
|
fields: { key: keyof TEnvConfig; description?: string }[];
|
||||||
};
|
};
|
||||||
} = {
|
} = {
|
||||||
google_sso: {
|
google_sso: {
|
||||||
@@ -395,7 +395,7 @@ export const overwriteSchema: {
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
github: {
|
gitlab_sso: {
|
||||||
name: "GitLab SSO",
|
name: "GitLab SSO",
|
||||||
fields: [
|
fields: [
|
||||||
{
|
{
|
||||||
@@ -415,7 +415,9 @@ export const overwriteSchema: {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const overridableKeys = new Set(Object.values(overwriteSchema).flatMap(({ fields }) => fields.map(({ key }) => key)));
|
export const overridableKeys = new Set(
|
||||||
|
Object.values(overwriteSchema).flatMap(({ fields }) => fields.map(({ key }) => key))
|
||||||
|
);
|
||||||
|
|
||||||
export const overrideEnvConfig = (config: Record<string, string>) => {
|
export const overrideEnvConfig = (config: Record<string, string>) => {
|
||||||
const allowedOverrides = Object.fromEntries(
|
const allowedOverrides = Object.fromEntries(
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import {
|
|||||||
SuperAdminSchema,
|
SuperAdminSchema,
|
||||||
UsersSchema
|
UsersSchema
|
||||||
} from "@app/db/schemas";
|
} from "@app/db/schemas";
|
||||||
import { getConfig } from "@app/lib/config/env";
|
import { getConfig, overridableKeys } from "@app/lib/config/env";
|
||||||
import { BadRequestError } from "@app/lib/errors";
|
import { BadRequestError } from "@app/lib/errors";
|
||||||
import { invalidateCacheLimit, readLimit, writeLimit } from "@app/server/config/rateLimiter";
|
import { invalidateCacheLimit, readLimit, writeLimit } from "@app/server/config/rateLimiter";
|
||||||
import { getTelemetryDistinctId } from "@app/server/lib/telemetry";
|
import { getTelemetryDistinctId } from "@app/server/lib/telemetry";
|
||||||
@@ -112,11 +112,13 @@ export const registerAdminRouter = async (server: FastifyZodProvider) => {
|
|||||||
message: "Page frame content contains unsafe HTML."
|
message: "Page frame content contains unsafe HTML."
|
||||||
})
|
})
|
||||||
.optional(),
|
.optional(),
|
||||||
envOverrides: z.record(z.string(), z.string()).optional()
|
envOverrides: z.record(z.enum(Array.from(overridableKeys) as [string, ...string[]]), z.string()).optional()
|
||||||
}),
|
}),
|
||||||
response: {
|
response: {
|
||||||
200: z.object({
|
200: z.object({
|
||||||
config: SuperAdminSchema.extend({
|
config: SuperAdminSchema.omit({
|
||||||
|
encryptedEnvOverrides: true
|
||||||
|
}).extend({
|
||||||
defaultAuthOrgSlug: z.string().nullable()
|
defaultAuthOrgSlug: z.string().nullable()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
import { SecretSync } from "@app/services/secret-sync/secret-sync-enums";
|
|
||||||
import { registerSyncSecretsEndpoints } from "./secret-sync-endpoints";
|
|
||||||
import {
|
import {
|
||||||
CloudflarePagesSyncSchema,
|
CloudflarePagesSyncSchema,
|
||||||
CreateCloudflarePagesSyncSchema,
|
CreateCloudflarePagesSyncSchema,
|
||||||
UpdateCloudflarePagesSyncSchema
|
UpdateCloudflarePagesSyncSchema
|
||||||
} from "@app/services/secret-sync/cloudflare-pages/cloudflare-pages-schema";
|
} from "@app/services/secret-sync/cloudflare-pages/cloudflare-pages-schema";
|
||||||
|
import { SecretSync } from "@app/services/secret-sync/secret-sync-enums";
|
||||||
|
|
||||||
|
import { registerSyncSecretsEndpoints } from "./secret-sync-endpoints";
|
||||||
|
|
||||||
export const registerCloudflarePagesSyncRouter = async (server: FastifyZodProvider) =>
|
export const registerCloudflarePagesSyncRouter = async (server: FastifyZodProvider) =>
|
||||||
registerSyncSecretsEndpoints({
|
registerSyncSecretsEndpoints({
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import z from "zod";
|
import z from "zod";
|
||||||
|
|
||||||
import { AppConnections } from "@app/lib/api-docs";
|
import { AppConnections } from "@app/lib/api-docs";
|
||||||
|
import { CharacterType, characterValidator } from "@app/lib/validator/validate-string";
|
||||||
import { AppConnection } from "@app/services/app-connection/app-connection-enums";
|
import { AppConnection } from "@app/services/app-connection/app-connection-enums";
|
||||||
import {
|
import {
|
||||||
BaseAppConnectionSchema,
|
BaseAppConnectionSchema,
|
||||||
@@ -9,7 +10,6 @@ import {
|
|||||||
} from "@app/services/app-connection/app-connection-schemas";
|
} from "@app/services/app-connection/app-connection-schemas";
|
||||||
|
|
||||||
import { CloudflareConnectionMethod } from "./cloudflare-connection-enum";
|
import { CloudflareConnectionMethod } from "./cloudflare-connection-enum";
|
||||||
import { CharacterType, characterValidator } from "@app/lib/validator/validate-string";
|
|
||||||
|
|
||||||
const accountIdCharacterValidator = characterValidator([
|
const accountIdCharacterValidator = characterValidator([
|
||||||
CharacterType.AlphaNumeric,
|
CharacterType.AlphaNumeric,
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { TEnvConfig } from "@app/lib/config/env";
|
||||||
|
|
||||||
export type TAdminSignUpDTO = {
|
export type TAdminSignUpDTO = {
|
||||||
email: string;
|
email: string;
|
||||||
password: string;
|
password: string;
|
||||||
@@ -78,6 +80,6 @@ export type TAdminIntegrationConfig = {
|
|||||||
export interface EnvOverrides {
|
export interface EnvOverrides {
|
||||||
[key: string]: {
|
[key: string]: {
|
||||||
name: string;
|
name: string;
|
||||||
fields: { key: string; value: string; hasEnvEntry: boolean; description?: string }[];
|
fields: { key: keyof TEnvConfig; value: string; hasEnvEntry: boolean; description?: string }[];
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-1
@@ -164,7 +164,10 @@ export const MinimizedOrgSidebar = () => {
|
|||||||
const handleCopyToken = async () => {
|
const handleCopyToken = async () => {
|
||||||
try {
|
try {
|
||||||
await window.navigator.clipboard.writeText(getAuthToken());
|
await window.navigator.clipboard.writeText(getAuthToken());
|
||||||
createNotification({ type: "success", text: "Copied current login session token to clipboard" });
|
createNotification({
|
||||||
|
type: "success",
|
||||||
|
text: "Copied current login session token to clipboard"
|
||||||
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error);
|
console.log(error);
|
||||||
createNotification({ type: "error", text: "Failed to copy user token to clipboard" });
|
createNotification({ type: "error", text: "Failed to copy user token to clipboard" });
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { Helmet } from "react-helmet";
|
|||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
import { PageHeader } from "@app/components/v2";
|
import { PageHeader } from "@app/components/v2";
|
||||||
|
|
||||||
import { EnvironmentPageForm } from "./components";
|
import { EnvironmentPageForm } from "./components";
|
||||||
|
|
||||||
export const EnvironmentPage = () => {
|
export const EnvironmentPage = () => {
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
import { useCallback, useEffect, useMemo, useState } from "react";
|
import { useCallback, useEffect, useMemo, useState } from "react";
|
||||||
import { Controller, useForm, useWatch } from "react-hook-form";
|
import { Controller, useForm, useWatch } from "react-hook-form";
|
||||||
|
import { faExclamationTriangle, faMagnifyingGlass } from "@fortawesome/free-solid-svg-icons";
|
||||||
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||||
import { zodResolver } from "@hookform/resolvers/zod";
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
import { createNotification } from "@app/components/notifications";
|
import { createNotification } from "@app/components/notifications";
|
||||||
import { Button, FormControl, Input, SecretInput, Tooltip } from "@app/components/v2";
|
import { Button, FormControl, Input, SecretInput, Tooltip } from "@app/components/v2";
|
||||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
|
||||||
import { faExclamationTriangle, faMagnifyingGlass } from "@fortawesome/free-solid-svg-icons";
|
|
||||||
import { useGetEnvOverrides, useUpdateServerConfig } from "@app/hooks/api";
|
import { useGetEnvOverrides, useUpdateServerConfig } from "@app/hooks/api";
|
||||||
|
|
||||||
type TForm = Record<string, string>;
|
type TForm = Record<string, string>;
|
||||||
@@ -55,14 +55,11 @@ export const EnvironmentPageForm = () => {
|
|||||||
|
|
||||||
return Object.values(envOverrides)
|
return Object.values(envOverrides)
|
||||||
.map((group) => {
|
.map((group) => {
|
||||||
const filteredFields = group.fields.filter((field) => {
|
const filteredFields = group.fields.filter(
|
||||||
const value = formValues?.[field.key] ?? "";
|
(field) =>
|
||||||
return (
|
|
||||||
field.key.toLowerCase().includes(searchTerm) ||
|
field.key.toLowerCase().includes(searchTerm) ||
|
||||||
(field.description ?? "").toLowerCase().includes(searchTerm) ||
|
(field.description ?? "").toLowerCase().includes(searchTerm)
|
||||||
value.toLowerCase().includes(searchTerm)
|
);
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
if (filteredFields.length > 0) {
|
if (filteredFields.length > 0) {
|
||||||
return { ...group, fields: filteredFields };
|
return { ...group, fields: filteredFields };
|
||||||
@@ -103,91 +100,89 @@ export const EnvironmentPageForm = () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<form
|
||||||
<form
|
className="flex flex-col gap-4 rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-4"
|
||||||
className="flex flex-col gap-4 rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-4"
|
onSubmit={handleSubmit(onSubmit)}
|
||||||
onSubmit={handleSubmit(onSubmit)}
|
>
|
||||||
>
|
<div className="flex w-full flex-row items-center justify-between">
|
||||||
<div className="flex w-full flex-row items-center justify-between">
|
<div>
|
||||||
<div>
|
<div className="flex items-start gap-1">
|
||||||
<div className="flex items-start gap-1">
|
<p className="text-xl font-semibold text-mineshaft-100">Overrides</p>
|
||||||
<p className="text-xl font-semibold text-mineshaft-100">Overrides</p>
|
|
||||||
</div>
|
|
||||||
<p className="text-sm text-bunker-300">Override specific environment variables.</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="flex flex-row gap-2">
|
|
||||||
<Button
|
|
||||||
type="submit"
|
|
||||||
variant="outline_bg"
|
|
||||||
isLoading={isSubmitting}
|
|
||||||
isDisabled={isSubmitting || !isDirty}
|
|
||||||
>
|
|
||||||
Save Overrides
|
|
||||||
</Button>
|
|
||||||
</div>
|
</div>
|
||||||
|
<p className="text-sm text-bunker-300">Override specific environment variables.</p>
|
||||||
</div>
|
</div>
|
||||||
<Input
|
|
||||||
value={search}
|
|
||||||
onChange={(e) => setSearch(e.target.value)}
|
|
||||||
leftIcon={<FontAwesomeIcon icon={faMagnifyingGlass} />}
|
|
||||||
placeholder="Search for keys, descriptions, and values..."
|
|
||||||
className="flex-1"
|
|
||||||
/>
|
|
||||||
<div className="flex flex-col gap-4">
|
|
||||||
{filteredData.map((group) => (
|
|
||||||
<div key={group!.name}>
|
|
||||||
<span className="mb-2 text-sm text-mineshaft-300">{group!.name}</span>
|
|
||||||
<div className="rounded-lg border border-mineshaft-700 bg-mineshaft-800">
|
|
||||||
<div className="flex flex-col">
|
|
||||||
{group!.fields.map((field, i) => (
|
|
||||||
<div
|
|
||||||
key={field.key}
|
|
||||||
className={`flex items-center justify-between gap-4 border-mineshaft-500 p-4 ${
|
|
||||||
i === 0 ? "" : "border-t"
|
|
||||||
}`}
|
|
||||||
>
|
|
||||||
<div className="flex max-w-lg flex-col">
|
|
||||||
<span className="text-sm">{field.key}</span>
|
|
||||||
<span className="text-sm text-mineshaft-400">{field.description}</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="flex grow items-center justify-end gap-2">
|
<div className="flex flex-row gap-2">
|
||||||
{field.hasEnvEntry && (
|
<Button
|
||||||
<Tooltip
|
type="submit"
|
||||||
content="Setting this value will override an existing environment variable"
|
variant="outline_bg"
|
||||||
className="text-center"
|
isLoading={isSubmitting}
|
||||||
>
|
isDisabled={isSubmitting || !isDirty}
|
||||||
<FontAwesomeIcon icon={faExclamationTriangle} className="text-red" />
|
>
|
||||||
</Tooltip>
|
Save Overrides
|
||||||
)}
|
</Button>
|
||||||
|
</div>
|
||||||
<Controller
|
</div>
|
||||||
control={control}
|
<Input
|
||||||
name={field.key}
|
value={search}
|
||||||
render={({ field: formGenField, fieldState: { error } }) => (
|
onChange={(e) => setSearch(e.target.value)}
|
||||||
<FormControl
|
leftIcon={<FontAwesomeIcon icon={faMagnifyingGlass} />}
|
||||||
isError={Boolean(error)}
|
placeholder="Search for keys, descriptions, and values..."
|
||||||
errorText={error?.message}
|
className="flex-1"
|
||||||
className="mb-0 w-full max-w-sm"
|
/>
|
||||||
>
|
<div className="flex flex-col gap-4">
|
||||||
<SecretInput
|
{filteredData.map((group) => (
|
||||||
{...formGenField}
|
<div key={group!.name}>
|
||||||
autoComplete="off"
|
<span className="mb-2 text-sm text-mineshaft-300">{group!.name}</span>
|
||||||
containerClassName="text-bunker-300 hover:border-mineshaft-400 border border-mineshaft-600 bg-bunker-600 px-2 py-1.5"
|
<div className="rounded-lg border border-mineshaft-700 bg-mineshaft-800">
|
||||||
/>
|
<div className="flex flex-col">
|
||||||
</FormControl>
|
{group!.fields.map((field, i) => (
|
||||||
)}
|
<div
|
||||||
/>
|
key={field.key}
|
||||||
</div>
|
className={`flex items-center justify-between gap-4 border-mineshaft-500 p-4 ${
|
||||||
|
i === 0 ? "" : "border-t"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<div className="flex max-w-lg flex-col">
|
||||||
|
<span className="text-sm">{field.key}</span>
|
||||||
|
<span className="text-sm text-mineshaft-400">{field.description}</span>
|
||||||
</div>
|
</div>
|
||||||
))}
|
|
||||||
</div>
|
<div className="flex grow items-center justify-end gap-2">
|
||||||
|
{field.hasEnvEntry && (
|
||||||
|
<Tooltip
|
||||||
|
content="Setting this value will override an existing environment variable"
|
||||||
|
className="text-center"
|
||||||
|
>
|
||||||
|
<FontAwesomeIcon icon={faExclamationTriangle} className="text-red" />
|
||||||
|
</Tooltip>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<Controller
|
||||||
|
control={control}
|
||||||
|
name={field.key}
|
||||||
|
render={({ field: formGenField, fieldState: { error } }) => (
|
||||||
|
<FormControl
|
||||||
|
isError={Boolean(error)}
|
||||||
|
errorText={error?.message}
|
||||||
|
className="mb-0 w-full max-w-sm"
|
||||||
|
>
|
||||||
|
<SecretInput
|
||||||
|
{...formGenField}
|
||||||
|
autoComplete="off"
|
||||||
|
containerClassName="text-bunker-300 hover:border-mineshaft-400 border border-mineshaft-600 bg-bunker-600 px-2 py-1.5"
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
))}
|
</div>
|
||||||
</div>
|
))}
|
||||||
</form>
|
</div>
|
||||||
</>
|
</form>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user