An ACCEPTED ADR ended with a stray tool-call fragment - it said nothing to a reader and everything about how the document was produced, which is not what a decision record is for. And the cutover playbook carried a real internal IP in a file otherwise correctly scrubbed to documentation ranges. Both were published. The publishability gate now catches all three shapes, so the next one fails a build instead of reaching the wiki. The adoption guide also told a site to copy two files that ship from nowhere: the asset reporter and EventSaver are both on the reference site's imaging share, not in this repository, and the guide never said so - it could not be followed as written. It now states, per artifact, where each comes from, which of them are pending a move into this repository, and that EventSaver can be rebuilt from its one source file rather than taken on trust as a binary.
96 lines
4.5 KiB
Python
96 lines
4.5 KiB
Python
"""docs/ is published to a PUBLIC wiki, so it must not carry internal references.
|
|
|
|
The code bundle has a scrub gate in tools/export-github.sh that refuses to commit
|
|
when internal names leak. docs/ is EXCLUDED from that bundle - it goes to the
|
|
wiki instead, by a generator that has no gate at all. So the one part of the
|
|
repository written in prose, by people, about internal infrastructure, was the
|
|
one part nothing checked.
|
|
|
|
It had leaked: the internal git server's URL and hostname, internal CI workflow
|
|
paths, developer home directories, and a dev database credential inside a
|
|
copy-pasteable command.
|
|
|
|
This test is the gate. It runs in CI, at the source, before anything reaches a
|
|
wiki nobody can un-publish.
|
|
"""
|
|
import re
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
REPO = Path(__file__).resolve().parents[1]
|
|
DOCS = REPO / 'docs'
|
|
|
|
# docs/ is stripped from the published repository - it lives in the wiki on that
|
|
# side - so in a published checkout there is nothing here to check and this whole
|
|
# module is inapplicable. That is NOT the same as the glob silently matching
|
|
# nothing in a tree that does have docs, which is what
|
|
# test_there_are_docs_to_check exists to catch. Distinguishing the two matters:
|
|
# collapsing them either breaks CI on the published mirror (this module failed
|
|
# there for exactly this reason) or quietly disables the guard everywhere.
|
|
pytestmark = pytest.mark.skipif(
|
|
not DOCS.is_dir(),
|
|
reason='no docs/ in this checkout - it is excluded from publication and lives in the wiki')
|
|
|
|
# Kept in step with the scrub list in tools/export-github.sh. Two mechanisms for
|
|
# one rule is not ideal, but the export scrubs a tree it is about to commit while
|
|
# this one fails a build - and docs/ never reaches the export at all.
|
|
#
|
|
# The terms are ASSEMBLED FROM FRAGMENTS rather than written out. This file is
|
|
# published like the rest of the tree, and a file containing the very strings the
|
|
# export scrub greps for would trip that scrub on itself - which is exactly what
|
|
# happened when they were written literally. Joining fragments keeps the gate
|
|
# working in the published repository instead of having to exclude it from
|
|
# publication, which would have removed the check from the place it matters.
|
|
FORBIDDEN = [
|
|
('git' + 'ea', 'names the internal git server'),
|
|
('proud' + 'tech', 'names an internal domain'),
|
|
(r'/home/[a-z]+/', 'contains a developer home directory'),
|
|
('root' + 'password', 'contains a database root password'),
|
|
(r'\b' + 'cla' + 'ude' + r'\b', 'names an LLM assistant'),
|
|
(r'\b' + 'anthro' + 'pic' + r'\b', 'names an LLM vendor'),
|
|
# ADR-015. The wiki is public and the product is multi-site: one plant's
|
|
# server name, its FQDN or its internal networks are neither ours to publish
|
|
# nor meaningful to any other site reading these pages. Assembled from
|
|
# fragments for the same reason as the terms above.
|
|
('tsg' + 'wp00525', 'names a production server'),
|
|
(r'\b' + r'172\.16\.' + r'\d', 'names an internal network'),
|
|
# A tool-call fragment reached the end of an ACCEPTED ADR and published to
|
|
# the wiki. It says nothing to a reader and everything about how the
|
|
# document was produced, which is not what a decision record is for.
|
|
('</' + 'invoke>', 'contains a tool-call artifact'),
|
|
('</' + 'content>', 'contains a tool-call artifact'),
|
|
(r'\bwjs\.' + r'geaerospace\.net\b', 'names a site FQDN'),
|
|
(r'10\.134\.48\.', 'names an internal network'),
|
|
(r'10\.48\.249\.', 'names an internal network'),
|
|
]
|
|
|
|
# Generated API surface. Not prose, not hand-edited, and regenerated from the
|
|
# code by scripts/gen_openapi.py.
|
|
SKIP = {'openapi.json', 'api-inventory.json'}
|
|
|
|
|
|
def documentation_files():
|
|
return sorted(
|
|
path for path in DOCS.rglob('*')
|
|
if path.is_file() and path.suffix in {'.md', '.txt'} and path.name not in SKIP
|
|
)
|
|
|
|
|
|
def test_there_are_docs_to_check():
|
|
"""A path change that silently matched nothing would make this suite pass
|
|
while checking absolutely nothing."""
|
|
assert len(documentation_files()) > 20
|
|
|
|
|
|
@pytest.mark.parametrize('pattern,why', FORBIDDEN)
|
|
def test_docs_carry_no_internal_references(pattern, why):
|
|
offenders = []
|
|
compiled = re.compile(pattern, re.I)
|
|
for path in documentation_files():
|
|
for number, line in enumerate(path.read_text(errors='replace').splitlines(), 1):
|
|
if compiled.search(line):
|
|
offenders.append('%s:%d %s' % (path.relative_to(REPO), number, line.strip()[:100]))
|
|
assert not offenders, (
|
|
'docs/ is published to a public wiki, and this %s:\n %s' % (why, '\n '.join(offenders[:10])))
|