Adds integration tests for per path access lists, fixes ipv6 jsv,

and enforces host-wide access list when location access list is not set
This commit is contained in:
Jamie Curnow
2026-09-24 12:21:49 +10:00
parent c41ec008bb
commit 2cfd3395cf
21 changed files with 518 additions and 103 deletions
+26 -9
View File
@@ -1,4 +1,4 @@
import { IconLock, IconLockOpen2 } from "@tabler/icons-react";
import { IconArrowBackUp, IconLock, IconLockOpen2 } from "@tabler/icons-react";
import { Field, useFormikContext } from "formik";
import type { ReactNode } from "react";
import Select, { type ActionMeta, components, type OptionProps } from "react-select";
@@ -32,8 +32,16 @@ interface Props {
name?: string;
label?: string;
onFormChange?: (value: number) => void;
// When set, the 0 option inherits the host's access list instead of being public
inheritHost?: boolean;
}
export function AccessField({ name = "accessListId", label = "access-list", id = "accessListId", onFormChange }: Props) {
export function AccessField({
name = "accessListId",
label = "access-list",
id = "accessListId",
onFormChange,
inheritHost = false,
}: Props) {
const { locale } = useLocaleState();
const { isLoading, isError, error, data } = useAccessLists(["owner", "items", "clients"]);
const { setFieldValue } = useFormikContext();
@@ -60,13 +68,22 @@ export function AccessField({ name = "accessListId", label = "access-list", id =
icon: <IconLock size={14} className="text-lime" />,
})) || [];
// Public option
options?.unshift({
value: 0,
label: intl.formatMessage({ id: "access-list.public" }),
subLabel: intl.formatMessage({ id: "access-list.public.subtitle" }),
icon: <IconLockOpen2 size={14} className="text-red" />,
});
// Public or inherit option
options?.unshift(
inheritHost
? {
value: 0,
label: intl.formatMessage({ id: "access-list.inherit" }),
subLabel: intl.formatMessage({ id: "access-list.inherit.subtitle" }),
icon: <IconArrowBackUp size={14} className="text-secondary" />,
}
: {
value: 0,
label: intl.formatMessage({ id: "access-list.public" }),
subLabel: intl.formatMessage({ id: "access-list.public.subtitle" }),
icon: <IconLockOpen2 size={14} className="text-red" />,
},
);
return (
<Field name={name}>
@@ -312,6 +312,7 @@ export function LocationsFields({ initialValues, name = "locations" }: Props) {
label="access-list"
id={`locations-access-list-${row.id}`}
onFormChange={(value) => handleAccessListChange(row.id, value)}
inheritHost
/>
{advVisible.includes(row.id) && (
<div className="">
+6
View File
@@ -71,6 +71,12 @@
"access-list.help.rules-order": {
"defaultMessage": "Note that the allow and deny directives will be applied in the order they are defined."
},
"access-list.inherit": {
"defaultMessage": "Inherit from Proxy Host"
},
"access-list.inherit.subtitle": {
"defaultMessage": "Uses the proxy host's access list"
},
"access-list.pass-auth": {
"defaultMessage": "Pass Auth to Upstream"
},
+6
View File
@@ -71,6 +71,12 @@
"access-list.help.rules-order": {
"defaultMessage": "Luba ja keela reeglid rakenduvad selles järjekorras, milles need on kirjas."
},
"access-list.inherit": {
"defaultMessage": "Päri puhverserverilt"
},
"access-list.inherit.subtitle": {
"defaultMessage": "Kasutab puhverserveri juurdepääsuloendit"
},
"access-list.pass-auth": {
"defaultMessage": "Edasta autentimine sihtserverile"
},