fix(kb): check_okf.py flags control bytes (NUL etc.) outside \t\n\r
The validator only ever parsed frontmatter fields — it never scanned body content, so a file with literal NUL bytes pasted in from a psql SELECT (kb/audits/wiki-kompilat-recon-2026-08-26.md) passed silently. Adds a whole-file scan for control bytes other than tab/newline/CR, one error per offending line. Covered by scripts/kb/tests/test_check_okf.py.
This commit is contained in:
parent
e20845ae1b
commit
2df4f1dbc3
|
|
@ -18,6 +18,8 @@ reguły tego repo:
|
|||
10. Wpisy `contradicts` wyglądające jak ścieżka .md też muszą istnieć;
|
||||
pozostałe wpisy to wolny tekst.
|
||||
11. `stub` — o ile obecne — musi być boolem.
|
||||
12. Brak bajtów kontrolnych poza \t \n \r w całym pliku (łapie wklejki NUL/inne
|
||||
binarne śmieci wklejone z zewnętrznych źródeł, np. wyników SELECT-ów).
|
||||
|
||||
Zakres domyślny: kb/ oraz docs/sessions/, z wyłączeniem README-wskaźników
|
||||
(POINTER_GLOBS) — te są nawigacją do kb-doca, nie dokumentami KB, i celowo nie
|
||||
|
|
@ -71,6 +73,7 @@ POINTER_GLOBS = (
|
|||
EXCLUDE_DIRS = ("build",)
|
||||
|
||||
DATE_RE = re.compile(r"^\d{4}-\d{2}-\d{2}$")
|
||||
CONTROL_CHAR_RE = re.compile(r"[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]")
|
||||
|
||||
|
||||
def is_pointer(rel: str) -> bool:
|
||||
|
|
@ -232,6 +235,17 @@ def check_file(path: Path, root: Path) -> list[str]:
|
|||
f"{rel}: `contradicts` wskazuje na nieistniejący plik: {item}"
|
||||
)
|
||||
|
||||
seen_lines: set[int] = set()
|
||||
for m in CONTROL_CHAR_RE.finditer(text):
|
||||
line_no = text.count("\n", 0, m.start()) + 1
|
||||
if line_no in seen_lines:
|
||||
continue
|
||||
seen_lines.add(line_no)
|
||||
errors.append(
|
||||
f"{rel}: bajt kontrolny {ord(m.group()):#04x} w linii {line_no} "
|
||||
"(dozwolone tylko \\t \\n \\r)"
|
||||
)
|
||||
|
||||
return errors
|
||||
|
||||
|
||||
|
|
|
|||
62
scripts/kb/tests/test_check_okf.py
Normal file
62
scripts/kb/tests/test_check_okf.py
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
"""Tests for check_okf.py — the OKF v0.1 frontmatter validator.
|
||||
|
||||
Covers the control-character check added 2026-08-27: a file that otherwise has
|
||||
valid frontmatter must still fail if its body contains a NUL byte or other
|
||||
control byte outside \\t \\n \\r (the class of bug found in
|
||||
kb/audits/wiki-kompilat-recon-2026-08-26.md — raw bytes pasted in from a psql
|
||||
SELECT over the mail corpus).
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
|
||||
import check_okf # noqa: E402
|
||||
|
||||
VALID_FRONTMATTER = """---
|
||||
okf: "0.1"
|
||||
type: decision
|
||||
visibility: private
|
||||
status: active
|
||||
updated: 2026-08-27
|
||||
links: []
|
||||
---
|
||||
"""
|
||||
|
||||
|
||||
def _write(tmp_path: Path, body: str) -> Path:
|
||||
p = tmp_path / "doc.md"
|
||||
p.write_text(VALID_FRONTMATTER + body, encoding="utf-8")
|
||||
return p
|
||||
|
||||
|
||||
def test_clean_file_has_no_control_char_errors(tmp_path):
|
||||
path = _write(tmp_path, "# Title\n\nZwykła treść z \t tabulatorem i \r\n końcem linii.\n")
|
||||
errors = check_okf.check_file(path, tmp_path)
|
||||
assert errors == []
|
||||
|
||||
|
||||
def test_nul_byte_in_body_is_flagged(tmp_path):
|
||||
path = _write(tmp_path, "# Title\n\nZawiera bajt NUL: \x00 w tym miejscu.\n")
|
||||
errors = check_okf.check_file(path, tmp_path)
|
||||
assert any("bajt kontrolny" in e and "0x0" in e for e in errors)
|
||||
|
||||
|
||||
def test_control_char_error_reports_correct_line(tmp_path):
|
||||
body = "linia 1\nlinia 2\nzepsuta \x00 linia 3\nlinia 4\n"
|
||||
path = _write(tmp_path, body)
|
||||
errors = check_okf.check_file(path, tmp_path)
|
||||
control_errors = [e for e in errors if "bajt kontrolny" in e]
|
||||
assert len(control_errors) == 1
|
||||
# Frontmatter occupies 7 lines before the body starts.
|
||||
frontmatter_lines = VALID_FRONTMATTER.count("\n")
|
||||
expected_line = frontmatter_lines + 3
|
||||
assert f"w linii {expected_line}" in control_errors[0]
|
||||
|
||||
|
||||
def test_multiple_control_chars_same_line_reported_once(tmp_path):
|
||||
path = _write(tmp_path, "para \x00 z dwoma \x00 bajtami na tej samej linii\n")
|
||||
errors = check_okf.check_file(path, tmp_path)
|
||||
control_errors = [e for e in errors if "bajt kontrolny" in e]
|
||||
assert len(control_errors) == 1
|
||||
Loading…
Reference in a new issue