diff --git a/.github/workflows/demo-validation.yml b/.github/workflows/demo-validation.yml new file mode 100644 index 0000000..58dee71 --- /dev/null +++ b/.github/workflows/demo-validation.yml @@ -0,0 +1,75 @@ +name: demo validation + +on: + pull_request: + paths: + - ".github/workflows/demo-validation.yml" + - ".gitattributes" + - "docs/demos/docgen.yaml" + - "docs/demos/narration/**" + - "docs/demos/animations/**" + - "docs/demos/terminal/**" + - "docs/demos/recordings/**" + push: + branches: + - main + paths: + - ".github/workflows/demo-validation.yml" + - ".gitattributes" + - "docs/demos/docgen.yaml" + - "docs/demos/narration/**" + - "docs/demos/animations/**" + - "docs/demos/terminal/**" + - "docs/demos/recordings/**" + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: demo-validation-${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} + +jobs: + validate: + name: A/V, narration, streams, and terminal OCR + runs-on: ubuntu-latest + timeout-minutes: 30 + env: + DOCGEN_GIT_REF: b880ba7a96c35fa32672f217e68c3e3592fb2be1 + steps: + - name: Checkout recordings from Git LFS + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 + with: + lfs: true + + - name: Set up Python + uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7 + with: + python-version: "3.11" + cache: pip + + - name: Install media validation dependencies + run: | + sudo apt-get update + sudo apt-get install --yes --no-install-recommends ffmpeg tesseract-ocr + python -m pip install --upgrade pip + pip install "docgen @ git+https://github.com/jmjava/documentation-generator.git@${DOCGEN_GIT_REF}" + + - name: Validate committed demo artifacts + working-directory: docs/demos + run: | + docgen validate --pre-push 2>&1 | tee "${RUNNER_TEMP}/docgen-validation.log" + if grep -E '^WARN \[[^]]+\] ocr_scan:' "${RUNNER_TEMP}/docgen-validation.log"; then + echo "Terminal error text or an unavailable OCR engine must fail CI." >&2 + exit 1 + fi + + - name: Retain validation log + if: always() + uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 + with: + name: docgen-validation-${{ github.run_id }}-${{ github.run_attempt }} + path: ${{ runner.temp }}/docgen-validation.log + if-no-files-found: error + retention-days: 14 diff --git a/libs/tekton-dag-common/tests/test_m17_demo_validation.py b/libs/tekton-dag-common/tests/test_m17_demo_validation.py new file mode 100644 index 0000000..25cd450 --- /dev/null +++ b/libs/tekton-dag-common/tests/test_m17_demo_validation.py @@ -0,0 +1,43 @@ +"""Static acceptance checks for the M17.9 demo validation gate.""" + +import re +from pathlib import Path + +ROOT = Path(__file__).resolve().parents[3] +WORKFLOW = ROOT / ".github/workflows/demo-validation.yml" + + +def test_demo_sources_trigger_pre_push_validation(): + workflow = WORKFLOW.read_text() + + for path in ( + "docs/demos/docgen.yaml", + "docs/demos/narration/**", + "docs/demos/animations/**", + "docs/demos/terminal/**", + "docs/demos/recordings/**", + ): + assert path in workflow + + assert "docgen validate --pre-push" in workflow + assert "lfs: true" in workflow + + +def test_demo_validation_installs_authoritative_media_checks(): + workflow = WORKFLOW.read_text() + + assert "ffmpeg tesseract-ocr" in workflow + assert "A/V, narration, streams, and terminal OCR" in workflow + assert "DOCGEN_GIT_REF: b880ba7a96c35fa32672f217e68c3e3592fb2be1" in workflow + assert r"grep -E '^WARN \[[^]]+\] ocr_scan:'" in workflow + assert "unavailable OCR engine must fail CI" in workflow + assert "if-no-files-found: error" in workflow + + +def test_demo_validation_actions_are_immutable(): + workflow = WORKFLOW.read_text() + uses = re.findall(r"^\s*uses:\s*(\S+)", workflow, flags=re.MULTILINE) + + assert uses + for action in uses: + assert re.fullmatch(r"[^@\s]+@[0-9a-f]{40}", action), action diff --git a/milestones/milestone-17.md b/milestones/milestone-17.md index 97da2ef..5a96df5 100644 --- a/milestones/milestone-17.md +++ b/milestones/milestone-17.md @@ -77,18 +77,22 @@ regression criteria in `docs/AGENT-REGRESSION.md` are satisfied. ShellCheck, actionlint, strict YAML/JSON parsing, both frontend lint/build matrices, and staged/package Helm renders. -- [ ] **M17.8 Add supply-chain automation** +- [x] **M17.8 Add supply-chain automation** - Dependabot/Renovate-equivalent updates for actions, npm, Go, Python, Maven, and Composer. - Add dependency and container scanning; remove known production dependency findings; pin CI tools and runtime images by version/digest where practical. - Acceptance: no unresolved critical/high production findings without an expiring, documented exception. + - Evidence: supply-chain run `34974127479` passed filesystem/secret scanning + and all three production image gates after the M17.8 hotfix. -- [ ] **M17.9 Enforce demo validation** +- [x] **M17.9 Enforce demo validation** - Run `docgen validate --pre-push` in CI for demo-source changes. - Acceptance: A/V drift, narration lint, missing streams, and broken terminal recordings fail CI. + - Evidence: demo-validation run `34975666059` fetched committed Git LFS + recordings and passed stream, A/V drift, narration, and OCR validation. ## P2 — Test-depth gaps