fix(task-2): close the trailing-newline tag hole and gate DXF-illegal layer names
Two ways a malformed block_define request slipped past the pre-write validator and reached the engine: * `ATTDEF_TAG_RE.match` with a `$` anchor accepts 'TAG\n' because `$` matches before a trailing newline. ezdxf strips the newline on write, so 'TAG\n' + 'TAG' landed as two ATTDEFs with one tag, defeating the duplicate-tag refusal, and the tag-keyed attribute readers then dropped one silently. Now `fullmatch`. * `_layer` only required a non-empty string, so a DXF-illegal name such as 'BAD<LAYER' passed and ezdxf raised DXFValueError mid-loop, after the block existed and earlier primitives were written (with overwrite=True, after the old definition was already wiped). The gate now refuses on the same forbidden-character rule `sanitize_symbol_name` uses, exposed as `security.illegal_symbol_name_chars`, with a TypeError naming `entities[i]` and 'layer'. Tests cover both repros and fail against the previous code. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FKFStjEFzpGyLq5bMpWxTd
This commit is contained in:
co-authored by
Claude Opus 5
parent
2cc4008fe8
commit
41585757c9
+12
-1
@@ -384,6 +384,17 @@ _FORBIDDEN_SYMBOL_CHARS = set('<>/\\":;?*|,=`') | set("\n\r\t")
|
||||
_MAX_SYMBOL_NAME = 255
|
||||
|
||||
|
||||
def illegal_symbol_name_chars(name: str) -> list[str]:
|
||||
"""The characters in `name` that DXF forbids in a symbol-table name, sorted.
|
||||
|
||||
The one rule behind every symbol-name gate in this repo: `sanitize_symbol_name`
|
||||
refuses on it for macro interpolation, and pre-write validators (block
|
||||
primitive specs, for one) refuse on it so ezdxf's own `DXFValueError` never
|
||||
fires mid-write after earlier entities have already landed.
|
||||
"""
|
||||
return sorted({c for c in name if c in _FORBIDDEN_SYMBOL_CHARS or ord(c) < 32})
|
||||
|
||||
|
||||
def sanitize_symbol_name(name: str, *, kind: str = "symbol") -> str:
|
||||
"""Return `name` if it is a legal DXF symbol-table name, else refuse.
|
||||
|
||||
@@ -397,7 +408,7 @@ def sanitize_symbol_name(name: str, *, kind: str = "symbol") -> str:
|
||||
raise ToolError(f"{kind} name rejected: empty.")
|
||||
if len(candidate) > _MAX_SYMBOL_NAME:
|
||||
raise ToolError(f"{kind} name rejected: longer than {_MAX_SYMBOL_NAME} characters.")
|
||||
offenders = sorted({c for c in candidate if c in _FORBIDDEN_SYMBOL_CHARS or ord(c) < 32})
|
||||
offenders = illegal_symbol_name_chars(candidate)
|
||||
if offenders:
|
||||
shown = ", ".join(repr(c) for c in offenders)
|
||||
raise ToolError(
|
||||
|
||||
Reference in New Issue
Block a user