feat(282): pre-commit secret-scanning defaults #35
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # ============================================================================= | |
| # tachi pytest matrix — init.sh substitution + source-pattern hardening suite | |
| # ============================================================================= | |
| # | |
| # Purpose: Run the F-248 substitution-surface suite AND the F-256 source- | |
| # pattern-hardening suite (`tests/scripts/test_init_sh_*.py` + | |
| # `tests/scripts/test_template_*.py`) on a 2-runner cross-platform matrix to | |
| # catch bash-version regressions: | |
| # | |
| # - macos-latest ships bash 3.2.57 (Apple's bundled /bin/bash). This is | |
| # the OLDEST supported runtime and the strictest gate for compatibility | |
| # constraints in `.aod/scripts/bash/template-substitute.sh`, | |
| # `.aod/scripts/bash/init-input.sh`, `.aod/scripts/bash/template-git.sh`, | |
| # and `.aod/scripts/bash/template-config-load.sh` (NFR-001: bash 3.2.57+; | |
| # no `mapfile`, no associative arrays, no `${var,,}`). | |
| # | |
| # - ubuntu-latest ships bash 5.x. This is the modern reference shell; | |
| # a green ubuntu run on top of a green macOS run proves the test | |
| # suite is portable, not bash-3.2-quirk-locked. | |
| # | |
| # The workflow: | |
| # 1. Checks out the repo at the PR head SHA | |
| # 2. Sets up Python 3.11 (matches `tachi-mmdc-preflight.yml` baseline; | |
| # pytest is installed via `python -m pip install pytest pytest-timeout`) | |
| # 3. Asserts `bash --version` to make the matrix gate visible in logs | |
| # 4. Runs the F-248 init.sh suite + the F-256 template-* suite with | |
| # `--timeout=1080` (per F-250 outer cap rationale; see header comment | |
| # on the pytest step below) | |
| # 5. Both matrix legs MUST pass green | |
| # | |
| # Path filter (NFR-005 alignment + scope discipline): the workflow ONLY | |
| # fires when files in the F-248 + F-256 hardening surfaces change. Pure | |
| # docs edits, ADR text, or unrelated agent-tier changes do NOT trigger | |
| # this job. This mirrors the narrow-scope pattern of `tachi-mmdc-preflight.yml` | |
| # and avoids burning CI minutes on edits that cannot affect substitution or | |
| # config-loading behavior. | |
| # | |
| # Path-filter completeness pattern (F-250 lesson, reinforced by F-256): | |
| # the `paths:` filter and the `pytest` invocation MUST be kept in lock-step. | |
| # When adding a new test file or refactoring a new bash library file, | |
| # update BOTH the `paths:` trigger list AND the `python -m pytest ...` | |
| # command in the same commit. F-256 added 5 new test modules and a new | |
| # canonical helper (`template-config-load.sh`); all are now wired through | |
| # both paths and invocation below. | |
| # | |
| # References: | |
| # - specs/248-substitution-surface-hardening/spec.md (FR-001..FR-011, NFR-001) | |
| # - specs/248-substitution-surface-hardening/tasks.md (T039, T040) | |
| # - specs/250-adversarial-unit-extraction-hotfix/spec.md (timeout philosophy | |
| # + session-scoped fixture rationale) | |
| # - specs/256-source-pattern-hardening/spec.md (FR-1..FR-9, NFR-1..NFR-6, | |
| # SC-1..SC-15) — adds Sites A-D + Stream 4 watchdog + canonical KV-load | |
| # primitive `aod_template_load_kv_file` | |
| # - docs/architecture/02_ADRs/ADR-038-placeholder-substitution-strategy.md | |
| # §Test Coverage (F-248) | |
| # - docs/architecture/02_ADRs/ADR-040-config-file-parsing-hardening.md | |
| # §Test Coverage (F-256) | |
| # ============================================================================= | |
| name: tachi pytest | |
| on: | |
| pull_request: | |
| paths: | |
| - scripts/init.sh | |
| - .aod/scripts/bash/init-input.sh | |
| - .aod/scripts/bash/template-substitute.sh | |
| - .aod/scripts/bash/template-validate.sh | |
| - .aod/scripts/bash/template-git.sh | |
| - .aod/scripts/bash/template-config-load.sh # F-256 | |
| - .aod/templates/constitution-clean.md | |
| - .aod/templates/constitution-instructional.md | |
| - .aod/template-manifest.txt | |
| - stacks/*/defaults.env # F-256 — Site A whitelist surface | |
| - tests/scripts/test_init_sh_substitution.py | |
| - tests/scripts/test_init_sh_adversarial.py | |
| - tests/scripts/test_init_sh_constitution.py | |
| - tests/scripts/test_init_sh_self_delete.py | |
| - tests/scripts/test_template_substitute_unit.py | |
| - tests/scripts/test_init_input_unit.py | |
| - tests/scripts/test_substitute_shim_canary.py | |
| - tests/scripts/test_init_sh_defaults_env.py # F-256 | |
| - tests/scripts/test_template_config_load_unit.py # F-256 | |
| - tests/scripts/test_template_config_load_integration.py # F-256 | |
| - tests/scripts/test_template_git_clone_timeout.py # F-256 | |
| - tests/scripts/test_template_substitute_lint_no_eval.py # F-256 | |
| - tests/scripts/test_init_precommit_matrix.py # F-5 (282) | |
| - tests/scripts/init_sh_helpers.py | |
| - tests/scripts/conftest.py | |
| - tests/fixtures/init-baseline-tree/** | |
| - tests/fixtures/regenerate-baseline.sh | |
| - tests/fixtures/regenerate-config-load-baseline.sh # F-256 | |
| - tests/fixtures/config-load/** # F-256 | |
| - .github/workflows/tachi-pytest.yml | |
| permissions: | |
| contents: read | |
| jobs: | |
| init-sh-suite: | |
| name: pytest init.sh suite — ${{ matrix.os }} | |
| runs-on: ${{ matrix.os }} | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| os: [macos-latest, ubuntu-latest] | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| - name: Set up Python 3.11 | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: "3.11" | |
| - name: Install pytest + pytest-timeout + pyyaml | |
| # Required by the suite + tests/scripts/conftest.py: | |
| # - pytest: runner | |
| # - pytest-timeout: per-test wall-clock cap (--timeout=300) | |
| # - pyyaml: conftest.py imports `yaml` at module scope (cross-suite | |
| # shared with BLP-01 + F-241 detection-agent attestation tests | |
| # which load schemas/finding.yaml + .claude/agents/tachi/*.yml) | |
| run: | | |
| python -m pip install --upgrade pip | |
| python -m pip install 'pytest>=8' 'pytest-timeout>=2' 'pyyaml>=6' | |
| - name: Diagnostic — bash version (NFR-001 compatibility gate) | |
| # Make the matrix runner's bash version visible in CI logs. macOS | |
| # ships /bin/bash 3.2.57 (the strict gate); ubuntu ships /bin/bash | |
| # 5.x (the modern reference). Both must pass the suite. | |
| run: | | |
| echo "uname: $(uname -a)" | |
| echo "/bin/bash --version: $(/bin/bash --version | head -1)" | |
| echo "default bash --version: $(bash --version | head -1)" | |
| - name: Run F-248 + F-256 hardening pytest suite | |
| # Direct invocation: `pytest` resolves to the venv-installed binary. | |
| # `--timeout=1080` is the OUTER pytest per-test cap; the helper's | |
| # subprocess `run_init_in_clone(timeout_sec=900)` is the INNER cap on | |
| # a single init.sh invocation. macos-latest GitHub Actions runners | |
| # are notoriously ~3-4× slower than dev machines for arm64 bash work | |
| # (~140-175s on dev → ~560-700s cold-cache on macos-latest at the | |
| # 4× worst-case multiplier). F-250 promoted `init_run` to a session- | |
| # scoped fixture in conftest.py so the macos cold-cache cost is paid | |
| # ONCE per session instead of once per module — the outer/inner | |
| # timeouts give ~200s/180s slack on the worst observed scenario. | |
| # | |
| # The unit modules (test_template_substitute_unit, test_init_input_unit, | |
| # test_substitute_shim_canary, test_template_config_load_unit) are | |
| # sub-second per case. The integration modules (test_init_sh_*, | |
| # test_template_config_load_integration, test_template_git_clone_timeout) | |
| # take longer because they spawn `init.sh` subprocesses or hanging- | |
| # upstream fixtures. All sit in the same pytest invocation so changes | |
| # to either the substitution surface (F-248) or the source-pattern | |
| # surface (F-256) trigger the full CI run. | |
| # | |
| # F-256 modules added (Wave 3 + Wave 4): | |
| # test_init_sh_defaults_env.py — Site A — stacks/*/defaults.env | |
| # test_template_config_load_unit.py — KV-parser primitive | |
| # test_template_config_load_integration.py — full library round-trip | |
| # test_template_git_clone_timeout.py — Stream 4 watchdog + AOD_FETCH_TIMEOUT | |
| # test_template_substitute_lint_no_eval.py — eval-removal lint guard | |
| run: | | |
| python -m pytest \ | |
| tests/scripts/test_init_sh_substitution.py \ | |
| tests/scripts/test_init_sh_adversarial.py \ | |
| tests/scripts/test_init_sh_constitution.py \ | |
| tests/scripts/test_init_sh_self_delete.py \ | |
| tests/scripts/test_template_substitute_unit.py \ | |
| tests/scripts/test_init_input_unit.py \ | |
| tests/scripts/test_substitute_shim_canary.py \ | |
| tests/scripts/test_init_sh_defaults_env.py \ | |
| tests/scripts/test_template_config_load_unit.py \ | |
| tests/scripts/test_template_config_load_integration.py \ | |
| tests/scripts/test_template_git_clone_timeout.py \ | |
| tests/scripts/test_template_substitute_lint_no_eval.py \ | |
| tests/scripts/test_init_precommit_matrix.py \ | |
| -v --timeout=1080 |