Skip to content

Release v0.7.0 — Phase 14 multi-stage pipelines + SSRF hardening #81

Release v0.7.0 — Phase 14 multi-stage pipelines + SSRF hardening

Release v0.7.0 — Phase 14 multi-stage pipelines + SSRF hardening #81

name: Validate user-manuals
# On pull requests that touch the user-manual sources or the build tool,
# verify the build script can compile every markdown file without errors
# and that every page declared in `_meta.yaml` has at least an English
# source. Catches structural problems before they hit main.
on:
push:
branches: [main, development]
paths:
- "docs/usermanuals/**"
- "tools/build_usermanuals.py"
pull_request:
branches: [main]
paths:
- "docs/usermanuals/**"
- "tools/build_usermanuals.py"
# Mirror CI's operator identity so any future pytest invocation does not
# raise on distroless runners where USER is unset.
env:
FORGELM_OPERATOR: ci-smoke
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/setup-python@v6
with:
python-version: "3.11"
- name: Install dependencies
run: pip install markdown pyyaml
- name: Build user-manuals
run: python3 tools/build_usermanuals.py
- name: Smoke-test that core pages have English content
# If somebody renamed a section in _meta.yaml without moving the
# markdown source, the build silently falls back to a placeholder.
# Fail the build instead so the PR author notices.
run: |
python3 - <<'PY'
import json, pathlib, re
src = pathlib.Path("site/js/usermanuals/en.js").read_text(encoding="utf-8")
# Each "missing": true entry is a page whose markdown source
# could not be found at all (no English fallback even).
missing = re.findall(r'"([^"]+)":\s*\{[^{}]*"missing":\s*true', src)
if missing:
print("ERROR: pages declared in _meta.yaml but missing markdown:")
for m in sorted(set(missing)):
print(f" - {m}")
raise SystemExit(1)
print("OK — every declared page has an English source.")
PY
- name: Orphan-markdown detection (strict)
# The reverse of the smoke test above: a markdown file under
# docs/usermanuals/<lang>/<section>/<page>.md that is NOT declared
# in _meta.yaml will silently never appear on the site. Strict
# mode fails the build so abandoned drafts are caught before
# they merge to main.
run: |
python3 - <<'PY'
import pathlib, sys, yaml
meta = yaml.safe_load(pathlib.Path("docs/usermanuals/_meta.yaml").read_text(encoding="utf-8"))
declared = set()
for sec in meta.get("sections", []):
for page in sec.get("pages", []):
declared.add(f"{sec['id']}/{page['id']}.md")
root = pathlib.Path("docs/usermanuals")
orphans = []
for md in root.rglob("*.md"):
rel = md.relative_to(root)
parts = rel.parts
if len(parts) < 3:
continue
# parts = (lang, section, page.md, ...). Only the <section>/<page>.md
# portion is matched against _meta.yaml.
key = "/".join(parts[1:])
if key not in declared:
orphans.append(str(rel))
if orphans:
print("ERROR: markdown files not declared in _meta.yaml (strict orphan check):")
for o in sorted(orphans):
print(f" - {o}")
sys.exit(1)
print("OK — no orphan markdown under docs/usermanuals/.")
PY