marker: tighten marker name max length from 128 to 32

128 characters was far beyond any realistic marker label (icmp, arp, tcp-syn)
and would have collided with the pcap filename budget once a tag prefix is
added later. Cap the user-facing name at 32 in both MarkerCreate and
MarkerDefinitionCreate; the compute-side name guard now also rejects names
longer than 48, which covers the `global-{def_name}` inherited form (≤ 39).
This commit is contained in:
YueGuobin 2026-08-05 00:49:37 +08:00
parent 75f278228b
commit f7b19dae99
No known key found for this signature in database
4 changed files with 19 additions and 3 deletions

View File

@ -340,6 +340,8 @@ direction relative to the capture node; see [Direction](#direction).
filter, the pcap filename, and `MARK` signal routing — so rename is a delete + recreate,
not a field update. PUT ignores the body `name`; the `{name}` path parameter identifies
the target, and only `bpf / tag / color / enabled / highlight_duration` are changeable.
Names are 132 chars (`[A-Za-z0-9][A-Za-z0-9_.-]*`); inherited copies carry a `global-`
prefix, so their filter names reach ~39.
- **`global` prefix reserved.** User-chosen names may not start with `global`; inherited
markers are stored as `global-{definition_name}` so the two namespaces cannot collide.
Omitting `name` on create yields an auto-generated, prefix-free name.

View File

@ -1115,7 +1115,10 @@ class BaseNode:
# marker definitions (inherit_marker). The prefix is only forbidden at the
# user-facing schema layer, not at the uBridge boundary.
_MARKER_NAME_RE = re.compile(r"^[A-Za-z0-9][A-Za-z0-9_.-]*$")
if not _MARKER_NAME_RE.match(name):
# Defense-in-depth vs hand-edited topology: the user-facing name is capped
# at 32 by the schema; inherited copies carry a ``global-`` prefix (≤ 39),
# so allow up to 48 here.
if not _MARKER_NAME_RE.match(name) or len(name) > 48:
raise UbridgeError(f"Invalid marker name: {name!r}")
cmd = 'bridge add_packet_filter {bridge} {name} mark "{bpf}"'.format(
bridge=bridge_name, name=name, bpf=bpf

View File

@ -152,7 +152,7 @@ class MarkerCreate(BaseModel):
name: Optional[str] = Field(
None,
pattern=r"^[A-Za-z0-9][A-Za-z0-9_.-]*$",
max_length=128,
max_length=32,
description='Unique marker name on the link. Auto-generated when absent.',
)
bpf: str
@ -236,7 +236,7 @@ class MarkerDefinitionCreate(BaseModel):
name: Optional[str] = Field(
None,
pattern=r"^[A-Za-z0-9][A-Za-z0-9_.-]*$",
max_length=128,
max_length=32,
description="Unique definition name. Auto-generated when absent.",
)
bpf: str

View File

@ -105,6 +105,17 @@ class TestMarkerRoutes:
)
assert response.status_code == status.HTTP_422_UNPROCESSABLE_ENTITY
async def test_create_marker_name_too_long_rejected(self, app: FastAPI, client: AsyncClient, project: Project) -> None:
link = UDPLink(project)
project._links = {link.id: link}
response = await client.post(
app.url_path_for("create_marker", project_id=project.id, link_id=link.id),
json={"name": "x" * 33, "bpf": "icmp"}, # max_length is 32
)
assert response.status_code == status.HTTP_422_UNPROCESSABLE_ENTITY
async def test_get_markers(self, app: FastAPI, client: AsyncClient, project: Project) -> None:
link = UDPLink(project)