some review changes

This commit is contained in:
x032205
2025-10-22 19:22:49 -04:00
parent e6a76187a2
commit 4a7f4e101b
4 changed files with 141 additions and 75 deletions

View File

@@ -208,7 +208,7 @@ export const GatewayCliDeploymentMethod = () => {
placeholder="Enter gateway name..."
isError={Boolean(errors.name)}
/>
{errors.name && <p className="mt-1 text-sm text-red-500">{errors.name}</p>}
{errors.name && <p className="mt-1 text-sm text-red">{errors.name}</p>}
<FormLabel label="Relay" tooltipText="The relay to use with your gateway." className="mt-4" />
<FilterableSelect
@@ -236,7 +236,7 @@ export const GatewayCliDeploymentMethod = () => {
getOptionValue={(option) => option.id}
components={{ Option: RelayOption }}
/>
{errors.relay && <p className="mt-1 text-sm text-red-500">{errors.relay}</p>}
{errors.relay && <p className="mt-1 text-sm text-red">{errors.relay}</p>}
<FormLabel
label="Instance Domain"
@@ -249,9 +249,7 @@ export const GatewayCliDeploymentMethod = () => {
placeholder="https://app.infisical.com"
isError={Boolean(errors.instanceDomain)}
/>
{errors.instanceDomain && (
<p className="mt-1 text-sm text-red-500">{errors.instanceDomain}</p>
)}
{errors.instanceDomain && <p className="mt-1 text-sm text-red">{errors.instanceDomain}</p>}
<FormLabel
label="Identity"
@@ -274,7 +272,7 @@ export const GatewayCliDeploymentMethod = () => {
getOptionValue={(option) => option.id}
getOptionLabel={(option) => option.name}
/>
{errors.identity && <p className="mt-1 text-sm text-red-500">{errors.identity}</p>}
{errors.identity && <p className="mt-1 text-sm text-red">{errors.identity}</p>}
<div className="mt-6 flex items-center">
<Button

View File

@@ -25,7 +25,7 @@ export const GatewayDeploymentMethodSelect = ({ onSelect }: Props) => {
};
return (
<div className="grid h-118 grid-cols-4 content-start gap-2">
<div className="grid h-fit grid-cols-4 content-start gap-2">
{deploymentOptions.map((option) => {
const { image, name, method } = option;

View File

@@ -13,7 +13,13 @@ import {
Input,
ModalClose
} from "@app/components/v2";
import { useOrganization } from "@app/context";
import {
OrgPermissionIdentityActions,
OrgPermissionSubjects,
useOrganization,
useOrgPermission
} from "@app/context";
import {
useAddIdentityTokenAuth,
useCreateTokenIdentityTokenAuth,
@@ -22,11 +28,13 @@ import {
} from "@app/hooks/api";
import { slugSchema } from "@app/lib/schemas";
const formSchema = z.object({
const baseFormSchema = z.object({
name: slugSchema({ field: "name" }),
host: z.string().min(1, "Host is required"),
instanceDomain: z.string().url("Must be a valid URL").or(z.literal(""))
});
instanceDomain: z.string().url("Must be a valid URL").or(z.literal("")),
const formSchemaWithIdentity = baseFormSchema.extend({
identity: z
.object(
{
@@ -39,11 +47,16 @@ const formSchema = z.object({
.refine((val) => val !== null, { message: "Identity is required" })
});
const formSchemaWithToken = baseFormSchema.extend({
identityToken: z.string().min(1, "Token is required")
});
export const RelayCliDeploymentMethod = () => {
const { protocol, hostname, port } = window.location;
const portSuffix = port && port !== "80" ? `:${port}` : "";
const siteURL = `${protocol}//${hostname}${portSuffix}`;
const [addTokenManually, setAddTokenManually] = useState(false);
const [step, setStep] = useState<"form" | "command">("form");
const [name, setName] = useState("");
const [host, setHost] = useState("");
@@ -69,6 +82,12 @@ export const RelayCliDeploymentMethod = () => {
const { currentOrg } = useOrganization();
const organizationId = currentOrg?.id || "";
const { permission } = useOrgPermission();
const canCreateToken = permission.can(
OrgPermissionIdentityActions.CreateToken,
OrgPermissionSubjects.Identity
);
const { data: identityMembershipOrgsData, isPending: isIdentitiesLoading } =
useGetIdentityMembershipOrgs({
organizationId,
@@ -84,48 +103,63 @@ export const RelayCliDeploymentMethod = () => {
const handleGenerateCommand = async () => {
setFormErrors([]);
const validation = formSchema.safeParse({ name, host, instanceDomain, identity });
if (!validation.success) {
setFormErrors(validation.error.issues);
return;
}
const validatedIdentity = validation.data.identity;
try {
const { data: identityTokenAuth } = await refetch();
if (!identityTokenAuth) {
await addIdentityTokenAuth({
identityId: validatedIdentity.id,
organizationId,
accessTokenTTL: 2592000,
accessTokenMaxTTL: 2592000,
accessTokenNumUsesLimit: 0,
accessTokenTrustedIps: [{ ipAddress: "0.0.0.0/0" }, { ipAddress: "::/0" }]
});
createNotification({
text: "Token authentication has been automatically enabled for the selected identity. By default, it is configured to allow all IP addresses with a default token TTL of 30 days. You can manage these settings in Access Control.",
type: "warning"
});
if (canCreateToken) {
const validation = formSchemaWithIdentity.safeParse({ name, host, instanceDomain, identity });
if (!validation.success) {
setFormErrors(validation.error.issues);
return;
}
const token = await createToken({
identityId: validatedIdentity.id,
name: `relay token for ${name} (autogenerated)`
});
setIdentityToken(token.accessToken);
createNotification({
text: "Automatically generated a token for the selected identity.",
type: "info"
const validatedIdentity = validation.data.identity;
try {
const { data: identityTokenAuth } = await refetch();
if (!identityTokenAuth) {
await addIdentityTokenAuth({
identityId: validatedIdentity.id,
organizationId,
accessTokenTTL: 2592000,
accessTokenMaxTTL: 2592000,
accessTokenNumUsesLimit: 0,
accessTokenTrustedIps: [{ ipAddress: "0.0.0.0/0" }, { ipAddress: "::/0" }]
});
createNotification({
text: "Token authentication has been automatically enabled for the selected identity. By default, it is configured to allow all IP addresses with a default token TTL of 30 days. You can manage these settings in Access Control.",
type: "warning"
});
}
const token = await createToken({
identityId: validatedIdentity.id,
name: `relay token for ${name} (autogenerated)`
});
setIdentityToken(token.accessToken);
createNotification({
text: "Automatically generated a token for the selected identity.",
type: "info"
});
setStep("command");
} catch (err) {
console.error(err);
createNotification({
text: "Failed to generate token for the selected identity",
type: "error"
});
setIdentityToken("");
}
} else {
const validation = formSchemaWithToken.safeParse({
name,
host,
instanceDomain,
identityToken
});
if (!validation.success) {
setFormErrors(validation.error.issues);
return;
}
setStep("command");
} catch (err) {
console.error(err);
createNotification({
text: "Failed to generate token for the selected identity",
type: "error"
});
setIdentityToken("");
}
};
@@ -194,7 +228,7 @@ export const RelayCliDeploymentMethod = () => {
placeholder="Enter relay name..."
isError={Boolean(errors.name)}
/>
{errors.name && <p className="mt-1 text-sm text-red-500">{errors.name}</p>}
{errors.name && <p className="mt-1 text-sm text-red">{errors.name}</p>}
<FormLabel
label="Host"
@@ -207,7 +241,7 @@ export const RelayCliDeploymentMethod = () => {
placeholder="0.0.0.0"
isError={Boolean(errors.host)}
/>
{errors.host && <p className="mt-1 text-sm text-red-500">{errors.host}</p>}
{errors.host && <p className="mt-1 text-sm text-red">{errors.host}</p>}
<FormLabel
label="Instance Domain"
@@ -220,32 +254,66 @@ export const RelayCliDeploymentMethod = () => {
placeholder="https://app.infisical.com"
isError={Boolean(errors.instanceDomain)}
/>
{errors.instanceDomain && (
<p className="mt-1 text-sm text-red-500">{errors.instanceDomain}</p>
)}
{errors.instanceDomain && <p className="mt-1 text-sm text-red">{errors.instanceDomain}</p>}
<FormLabel
label="Identity"
tooltipText="The identity that your relay will use for authentication."
className="mt-4"
/>
<FilterableSelect
value={identity}
onChange={(e) =>
handleIdentityChange(
e as SingleValue<{
id: string;
name: string;
}>
)
}
isLoading={isIdentitiesLoading}
placeholder="Select identity..."
options={identityMembershipOrgs.map((membership) => membership.identity)}
getOptionValue={(option) => option.id}
getOptionLabel={(option) => option.name}
/>
{errors.identity && <p className="mt-1 text-sm text-red-500">{errors.identity}</p>}
{canCreateToken && !addTokenManually ? (
<>
<FormLabel
label="Identity"
tooltipText="The identity that your relay will use for authentication."
className="mt-4"
/>
<FilterableSelect
value={identity}
onChange={(e) =>
handleIdentityChange(
e as SingleValue<{
id: string;
name: string;
}>
)
}
isLoading={isIdentitiesLoading}
placeholder="Select identity..."
options={identityMembershipOrgs.map((membership) => membership.identity)}
getOptionValue={(option) => option.id}
getOptionLabel={(option) => option.name}
/>
<p className="mt-1 text-xs text-yellow">
Selecting an identity will automatically enable token auth and generate a token.{" "}
<button
onClick={() => setAddTokenManually(true)}
className="cursor-pointer underline transition-opacity hover:opacity-70"
>
Add token manually
</button>
</p>
{errors.identity && <p className="mt-1 text-sm text-red">{errors.identity}</p>}
</>
) : (
<>
<FormLabel
label="Identity Token"
tooltipText="The identity token that your relay will use for authentication."
className="mt-4"
/>
<Input
value={identityToken}
onChange={(e) => setIdentityToken(e.target.value)}
placeholder="Enter identity token..."
isError={Boolean(errors.identityToken)}
/>
{canCreateToken && (
<button
onClick={() => setAddTokenManually(false)}
className="mt-1 cursor-pointer text-xs text-mineshaft-400 underline transition-opacity hover:opacity-70"
>
Autogenerate token for identity
</button>
)}
{errors.identityToken && <p className="mt-1 text-sm text-red">{errors.identityToken}</p>}
</>
)}
<div className="mt-6 flex items-center">
<Button

View File

@@ -25,7 +25,7 @@ export const RelayDeploymentMethodSelect = ({ onSelect }: Props) => {
};
return (
<div className="grid h-118 grid-cols-4 content-start gap-2">
<div className="grid h-fit grid-cols-4 content-start gap-2">
{deploymentOptions.map((option) => {
const { image, name, method } = option;