Skip to content

docs: verify bounded workflow adoption planning #1289

docs: verify bounded workflow adoption planning

docs: verify bounded workflow adoption planning #1289

Workflow file for this run

# yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json
# yamllint disable rule:line-length rule:truthy
name: Docs Review
on:
pull_request:
branches: [main, dev]
push:
branches: [main, dev]
paths:
- "**/*.md"
- "**/*.mdc"
- ".github/**"
- "docs/**"
- "resources/**"
- "src/specfact_cli/resources/**"
- "docs/.doc-frontmatter-enforced"
- "tests/unit/docs/**"
- "tests/unit/workflows/test_docs_module_fixture.py"
- "tests/unit/workflows/test_docs_module_authentication.py"
- "tests/unit/scripts/test_doc_frontmatter/**"
- "tests/integration/scripts/test_doc_frontmatter/**"
- "tests/helpers/doc_frontmatter.py"
- "tests/helpers/doc_frontmatter_fixtures.py"
- "tests/helpers/doc_frontmatter_types.py"
- "scripts/check-docs-commands.py"
- "scripts/check-command-contract.py"
- "scripts/check-documentation-accountability.py"
- "scripts/generate-command-overview.py"
- "scripts/verify_docs_module_source.py"
- "docs/reference/commands.generated.*"
- "llms.txt"
- "scripts/check-cross-site-links.py"
- "scripts/check_doc_frontmatter.py"
- "scripts/validate_agent_rule_applies_when.py"
- "scripts/check_version_sources.py"
- "docs/agent-rules/INDEX.md"
- "pyproject.toml"
- "uv.lock"
- "requirements/ci/locked.txt"
- "ci/docs-module-fixture.lock.json"
- ".github/actions/setup-frozen-python/**"
- ".github/workflows/docs-review.yml"
workflow_dispatch:
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
permissions:
contents: read
jobs:
docs-review:
name: Docs Review
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10
with:
persist-credentials: false
- name: Read immutable module fixture
id: modules-fixture
shell: bash
run: |
set -euo pipefail
repository="$(python -c 'import json; print(json.load(open("ci/docs-module-fixture.lock.json", encoding="utf-8"))["repository"])')"
commit="$(python -c 'import json; print(json.load(open("ci/docs-module-fixture.lock.json", encoding="utf-8"))["commit"])')"
[[ "$repository" =~ ^[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+$ ]]
test "$repository" = "nold-ai/specfact-cli-modules"
tree="$(python -c 'import json; print(json.load(open("ci/docs-module-fixture.lock.json", encoding="utf-8"))["tree"])')"
[[ "$commit" =~ ^[0-9a-f]{40}$ ]]
[[ "$tree" =~ ^[0-9a-f]{40}$ ]]
printf 'repository=%s\n' "$repository" >> "$GITHUB_OUTPUT"
printf 'commit=%s\n' "$commit" >> "$GITHUB_OUTPUT"
- name: Checkout module command sources
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10
with:
repository: ${{ steps.modules-fixture.outputs.repository }}
path: specfact-cli-modules
ref: ${{ steps.modules-fixture.outputs.commit }}
persist-credentials: false
- name: Verify immutable module fixture
shell: bash
run: |
set -euo pipefail
expected_repository="$(python -c 'import json; print(json.load(open("ci/docs-module-fixture.lock.json", encoding="utf-8"))["repository"])')"
expected="$(python -c 'import json; print(json.load(open("ci/docs-module-fixture.lock.json", encoding="utf-8"))["commit"])')"
test "$expected_repository" = "${{ steps.modules-fixture.outputs.repository }}"
actual="$(git -C specfact-cli-modules rev-parse HEAD)"
test "$actual" = "$expected"
expected_tree="$(python -c 'import json; print(json.load(open("ci/docs-module-fixture.lock.json", encoding="utf-8"))["tree"])')"
actual_tree="$(git -C specfact-cli-modules rev-parse 'HEAD^{tree}')"
test "$actual_tree" = "$expected_tree"
test -z "$(git -C specfact-cli-modules status --porcelain --untracked-files=all)"
- name: Set up Python 3.12
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405
with:
python-version: "3.12"
- name: Set up frozen documentation dependencies
uses: ./.github/actions/setup-frozen-python
- name: Checkout trusted module verifier
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10
with:
ref: ${{ github.event.pull_request.base.sha || github.sha }}
path: trusted-core-docs
persist-credentials: false
- name: Authenticate module command sources
shell: bash
run: |
set -euo pipefail
python -I - <<'PY'
import importlib.util
from pathlib import Path
modules = Path("specfact-cli-modules").resolve(strict=True)
trusted = Path("trusted-core-docs").resolve(strict=True)
verifier_path = (trusted / "scripts/verify-modules-signature.py").resolve(strict=True)
key_path = (trusted / "resources/keys/module-signing-public.pem").resolve(strict=True)
for path in (verifier_path, key_path):
if not path.is_relative_to(trusted) or path.is_relative_to(modules):
raise ValueError("Authentication inputs must come from the separate base checkout")
spec = importlib.util.spec_from_file_location("trusted_docs_module_verifier", verifier_path)
if spec is None or spec.loader is None:
raise ValueError("Cannot load the base module verifier")
verifier = importlib.util.module_from_spec(spec)
spec.loader.exec_module(verifier)
required = {f"specfact-{name}" for name in (
"backlog", "codebase", "code-review", "govern", "project", "requirements", "spec"
)}
bundles = {source.parent.name: source.parent for source in (modules / "packages").glob("*/src")
if source.is_dir()}
if missing := required - bundles.keys():
raise ValueError(f"Missing required documentation bundles: {', '.join(sorted(missing))}")
public_key = key_path.read_text(encoding="utf-8")
for name, bundle in sorted(bundles.items()):
manifest = bundle / "module-package.yaml"
if not manifest.is_file():
raise ValueError(f"Missing documentation module manifest: {name}")
verifier.verify_manifest(
manifest, require_signature=True, public_key_pem=public_key,
payload_from_filesystem=True, verify_checksum=True,
)
print(f"Authenticated {len(bundles)} documentation bundles using the base verifier.")
PY
- name: Export module command source path
run: |
echo "SPECFACT_MODULES_REPO=${GITHUB_WORKSPACE}/specfact-cli-modules" >> "$GITHUB_ENV"
echo "SPECFACT_DOCS_MODULES_REPO=${GITHUB_WORKSPACE}/specfact-cli-modules" >> "$GITHUB_ENV"
- name: Validate docs dependency security floor
run: python -m pytest tests/unit/docs/test_docs_validation_scripts.py::test_docs_json_gem_uses_the_patched_security_floor -q
- name: Validate documentation fixture and Code Review command parity
run: |
test -n "${SPECFACT_DOCS_MODULES_REPO:?Documentation fixture is required}"
python -m pytest \
tests/unit/docs/test_code_review_command_parity.py \
tests/unit/docs/test_llms_overview_freshness.py \
tests/unit/workflows/test_docs_module_fixture.py \
tests/unit/workflows/test_docs_module_authentication.py -q
- name: Validate docs command examples
run: python scripts/check-docs-commands.py
- name: Validate generated command overview
run: python scripts/generate-command-overview.py --check
- name: Validate generated command contract
run: python scripts/check-command-contract.py
- name: Validate documentation accountability
run: python scripts/check-documentation-accountability.py
- name: Cross-site links (warn-only; live site may lag deploys)
continue-on-error: true
run: python scripts/check-cross-site-links.py --warn-only
- name: Validate documentation frontmatter (enforced paths; aligns with local docs-validate / pre-commit)
run: python scripts/check_doc_frontmatter.py
- name: Validate agent-rules applies_when canonical task signals
run: python scripts/validate_agent_rule_applies_when.py
- name: Run docs review test suites
run: |
mkdir -p logs/docs-review
DOCS_REVIEW_LOG="logs/docs-review/docs-review_$(date -u +%Y%m%d_%H%M%S).log"
python -m pytest tests/unit/docs/ tests/unit/scripts/test_doc_frontmatter/ tests/integration/scripts/test_doc_frontmatter/ -q 2>&1 | tee "$DOCS_REVIEW_LOG"
exit "${PIPESTATUS[0]:-$?}"
- name: Upload docs review logs
if: always()
uses: actions/upload-artifact@v4
with:
name: docs-review-logs
path: logs/docs-review/
if-no-files-found: ignore