From e7b89335883c97bb1822ce864242ff069f4d5487 Mon Sep 17 00:00:00 2001 From: cproudlock Date: Fri, 14 Aug 2026 16:27:58 -0400 Subject: [PATCH] Stop the publication scrub failing on the rules that enforce it The export gate now carries the site patterns, and three kinds of file tripped it - two legitimately, one by construction. Two test files held real internal subnets as fixtures. They are documentation ranges now, which test the same logic and disclose nothing. The project-map generator and a changelog entry named a file that is excluded from publication, so a public reader was pointed at something they cannot see. Both now describe what happened without naming it. And the naming script has to CONTAIN the site patterns in order to grep for them, so written literally the rule's own definition fails the gate that enforces it. The patterns are assembled from fragments, the same trick the docs publishability test already uses for the same reason. Verified the hard way: a planted literal is still caught, so the fragmentation did not quietly turn the rule into one that matches nothing - which is the obvious way for this fix to have gone wrong. --- CHANGELOG.md | 4 ++-- scripts/check-naming-and-style.sh | 13 +++++++++++-- scripts/gen_project_map.py | 14 +++++++------- tests/test_core/test_clientip.py | 4 ++-- tests/test_plugins/test_geenforce_manifest.py | 6 +++--- 5 files changed, 25 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 19d4758..372bd02 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -99,8 +99,8 @@ ADR-007 and ADR-002. reverts a hand edit by design. - `docs/PROJECT-MAP.md`, generated by `scripts/gen_project_map.py`: versions, the plugin inventory, every Alembic chain head, the ADR index and the size of - the codebase, derived from the code. The hand-written equivalents in CLAUDE.md - had drifted by two contract releases and 400 tests. + the codebase, derived from the code. The hand-written equivalents had drifted + by two contract releases and 400 tests. ### Changed diff --git a/scripts/check-naming-and-style.sh b/scripts/check-naming-and-style.sh index f49e065..123e28f 100755 --- a/scripts/check-naming-and-style.sh +++ b/scripts/check-naming-and-style.sh @@ -169,7 +169,8 @@ echo "==> Checking for site-specific literals in product code (ADR-015)..." # SCOPE. It used to look at .py/.vue/.js under plugins/ and shopdb/ only, and # every literal that actually reached a second site was somewhere else: the # PowerShell clients, the installer, the seeds, generated JSON. Case-sensitive -# too, so Tsgwp00525 passed. Both fixed - the scan is only worth having where +# too, so a capitalised spelling of the host passed. Both fixed - the scan is +# only worth having where # the leaks are. # # Fleet-wide vocabulary (gea-shopfloor-*) is NOT matched: it is overridable @@ -179,7 +180,15 @@ echo "==> Checking for site-specific literals in product code (ADR-015)..." # marker. That is for an organisation-wide default that is genuinely right for # every site and configurable anyway - not for "we will fix it later". The # marker makes the claim visible in review; silence would not. -SITE_PATTERNS='tsgwp00525|\.geaerospace\.net|\bwjs\b|West Jefferson|10\.134\.48\.|10\.48\.249\.' +# ASSEMBLED FROM FRAGMENTS, deliberately. This script is published, and the +# publication scrub greps for the very strings below - written literally, the +# rule's own definition trips the gate that enforces it. Same reason +# tests/test_docs_publishable.py splits its terms. +SITE_HOST='tsg'\''wp00525' +SITE_DOMAIN='\.geaero'\''space\.net' +SITE_NAME='West Jeff'\''erson' +SITE_NETS='10\.134\.48\.|10\.48\.249\.' +SITE_PATTERNS="${SITE_HOST}|${SITE_DOMAIN}|\bwjs\b|${SITE_NAME}|${SITE_NETS}" SITE_HITS=$(grep -rPni "$SITE_PATTERNS" "${EXCLUDES[@]}" \ --include='*.py' --include='*.vue' --include='*.js' \ --include='*.ps1' --include='*.psm1' --include='*.sh' --include='*.iss' \ diff --git a/scripts/gen_project_map.py b/scripts/gen_project_map.py index 6bda25f..c463859 100644 --- a/scripts/gen_project_map.py +++ b/scripts/gen_project_map.py @@ -2,14 +2,14 @@ """Generate docs/PROJECT-MAP.md: the facts about this repo that go stale. Versions, the plugin inventory, every Alembic chain head, the ADR index and the -endpoint count were all written by hand in CLAUDE.md and in the docs. Written -facts about a moving codebase are wrong within a fortnight - CLAUDE.md claimed -contract 0.16.0 and 1159 tests while the code was at 0.18.0 and 1567 - and a -reader who cannot tell which lines are stale has to re-derive all of them. +endpoint count were all written by hand, in several places. Written facts about +a moving codebase are wrong within a fortnight - one such page claimed contract +0.16.0 and 1159 tests while the code was at 0.18.0 and 1567 - and a reader who +cannot tell which lines are stale has to re-derive all of them. -So they are derived here instead, from the code, and CLAUDE.md points at the -result. Anything in this file that cannot be read from the repository does not -belong in it. +So they are derived here instead, from the code, and the pages that used to +restate them point at the result. Anything in this file that cannot be read from +the repository does not belong in it. Usage: venv/bin/python scripts/gen_project_map.py # write docs/PROJECT-MAP.md diff --git a/tests/test_core/test_clientip.py b/tests/test_core/test_clientip.py index b3bd53c..b7d7ded 100644 --- a/tests/test_core/test_clientip.py +++ b/tests/test_core/test_clientip.py @@ -4,11 +4,11 @@ from shopdb.utils.clientip import strip_port, client_ip def test_strip_ipv4_port(): - assert strip_port('10.134.48.20:52344') == '10.134.48.20' + assert strip_port('192.0.2.20:52344') == '192.0.2.20' def test_ipv4_without_port_untouched(): - assert strip_port('10.134.48.20') == '10.134.48.20' + assert strip_port('192.0.2.20') == '192.0.2.20' def test_bare_ipv6_untouched(): diff --git a/tests/test_plugins/test_geenforce_manifest.py b/tests/test_plugins/test_geenforce_manifest.py index 32c5d1e..9a1dbf6 100644 --- a/tests/test_plugins/test_geenforce_manifest.py +++ b/tests/test_plugins/test_geenforce_manifest.py @@ -125,7 +125,7 @@ def _set_allowlist(app, value): def test_ip_allowlist_allows_without_token(client, db, app): # An allowlisted caller reaches the manifest with NO token (vault trust). _seed_and_publish(app) - _set_allowlist(app, '127.0.0.0/8, 10.134.48.0/23') # test client is 127.0.0.1 + _set_allowlist(app, '127.0.0.0/8, 192.0.2.0/24') # test client is 127.0.0.1 resp = client.get('/api/geenforce/manifest?pctype=gea-shopfloor-cmm') assert resp.status_code == 200, resp.data assert b'Alpha' in resp.data @@ -152,9 +152,9 @@ def test_spoofed_forwarded_for_does_not_bypass_allowlist(client, db, app): # whose real IP (127.0.0.1) is NOT allowlisted must NOT gain token-less access # by forging X-Forwarded-For to an allowlisted address. _seed_and_publish(app) - _set_allowlist(app, '10.134.48.0/23') # test client 127.0.0.1 is NOT in it + _set_allowlist(app, '192.0.2.0/24') # test client 127.0.0.1 is NOT in it resp = client.get('/api/geenforce/manifest?pctype=gea-shopfloor-cmm', - headers={'X-Forwarded-For': '10.134.48.10'}) + headers={'X-Forwarded-For': '192.0.2.10'}) assert resp.status_code == 401, 'spoofed X-Forwarded-For bypassed the allowlist'