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.
This commit is contained in:
@@ -99,8 +99,8 @@ ADR-007 and ADR-002.
|
|||||||
reverts a hand edit by design.
|
reverts a hand edit by design.
|
||||||
- `docs/PROJECT-MAP.md`, generated by `scripts/gen_project_map.py`: versions,
|
- `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 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
|
the codebase, derived from the code. The hand-written equivalents had drifted
|
||||||
had drifted by two contract releases and 400 tests.
|
by two contract releases and 400 tests.
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
# 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
|
# every literal that actually reached a second site was somewhere else: the
|
||||||
# PowerShell clients, the installer, the seeds, generated JSON. Case-sensitive
|
# 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.
|
# the leaks are.
|
||||||
#
|
#
|
||||||
# Fleet-wide vocabulary (gea-shopfloor-*) is NOT matched: it is overridable
|
# 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
|
# 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
|
# every site and configurable anyway - not for "we will fix it later". The
|
||||||
# marker makes the claim visible in review; silence would not.
|
# 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[@]}" \
|
SITE_HITS=$(grep -rPni "$SITE_PATTERNS" "${EXCLUDES[@]}" \
|
||||||
--include='*.py' --include='*.vue' --include='*.js' \
|
--include='*.py' --include='*.vue' --include='*.js' \
|
||||||
--include='*.ps1' --include='*.psm1' --include='*.sh' --include='*.iss' \
|
--include='*.ps1' --include='*.psm1' --include='*.sh' --include='*.iss' \
|
||||||
|
|||||||
@@ -2,14 +2,14 @@
|
|||||||
"""Generate docs/PROJECT-MAP.md: the facts about this repo that go stale.
|
"""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
|
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
|
endpoint count were all written by hand, in several places. Written facts about
|
||||||
facts about a moving codebase are wrong within a fortnight - CLAUDE.md claimed
|
a moving codebase are wrong within a fortnight - one such page claimed contract
|
||||||
contract 0.16.0 and 1159 tests while the code was at 0.18.0 and 1567 - and a
|
0.16.0 and 1159 tests while the code was at 0.18.0 and 1567 - and a reader who
|
||||||
reader who cannot tell which lines are stale has to re-derive all of them.
|
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
|
So they are derived here instead, from the code, and the pages that used to
|
||||||
result. Anything in this file that cannot be read from the repository does not
|
restate them point at the result. Anything in this file that cannot be read from
|
||||||
belong in it.
|
the repository does not belong in it.
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
venv/bin/python scripts/gen_project_map.py # write docs/PROJECT-MAP.md
|
venv/bin/python scripts/gen_project_map.py # write docs/PROJECT-MAP.md
|
||||||
|
|||||||
@@ -4,11 +4,11 @@ from shopdb.utils.clientip import strip_port, client_ip
|
|||||||
|
|
||||||
|
|
||||||
def test_strip_ipv4_port():
|
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():
|
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():
|
def test_bare_ipv6_untouched():
|
||||||
|
|||||||
@@ -125,7 +125,7 @@ def _set_allowlist(app, value):
|
|||||||
def test_ip_allowlist_allows_without_token(client, db, app):
|
def test_ip_allowlist_allows_without_token(client, db, app):
|
||||||
# An allowlisted caller reaches the manifest with NO token (vault trust).
|
# An allowlisted caller reaches the manifest with NO token (vault trust).
|
||||||
_seed_and_publish(app)
|
_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')
|
resp = client.get('/api/geenforce/manifest?pctype=gea-shopfloor-cmm')
|
||||||
assert resp.status_code == 200, resp.data
|
assert resp.status_code == 200, resp.data
|
||||||
assert b'Alpha' in 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
|
# 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.
|
# by forging X-Forwarded-For to an allowlisted address.
|
||||||
_seed_and_publish(app)
|
_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',
|
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'
|
assert resp.status_code == 401, 'spoofed X-Forwarded-For bypassed the allowlist'
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user