Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .agents/skills/ci-consumer-adoption/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ still bills, and a repository that is routed to hardware its jobs cannot use.
Do not choose a tier by reading prose. Resolve it:

```bash
python3 scripts/resolve_profile.py --visibility private --plan enterprise-cloud \
.venv/bin/python -I -B scripts/check_python_execution_contract.py --launch resolve_profile.py -- --visibility private --plan enterprise-cloud \
--code-security --secret-protection --code-quality
```

Expand Down
12 changes: 7 additions & 5 deletions .agents/skills/nddev-repo-flow/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,20 +36,22 @@ it explains, so a reversal is deliberate.
2. Update `catalog/capabilities.yml`, and `catalog/tools.yml` if you added or
bumped an action. `used_by` and tool registration are both derived from the
tree by `check_tool_registry.py`, so an omission fails rather than rots.
3. `python3 scripts/generate_docs.py`.
3. Run `generate_docs.py` through the repository's isolated Python launcher.
4. Add a caller example under `examples/`. `check_examples.py` fails a reusable
with no example — it is the only executable statement of a caller contract.
5. Sync prose: `README.md`, the tier docs, the matching example.
6. `python3 scripts/sync_skills.py` if you touched a skill.
6. Run `sync_skills.py` through the isolated launcher if you touched a skill.
7. `CHANGELOG.md` under `[Unreleased]`.
8. Validate, then PR.

## Validate

```bash
uv pip install --system --require-hashes -r requirements-ci.txt
python3 scripts/validate_all.py --tier core # what ci-gate blocks on
python3 scripts/validate_all.py # all three tiers
python3.13 -I -B -m venv --copies .venv
uv pip install --python .venv/bin/python --require-hashes -r requirements-ci.txt
.venv/bin/python -I -B scripts/check_python_syntax.py
.venv/bin/python -I -B scripts/check_python_execution_contract.py --launch validate_all.py -- --tier core
.venv/bin/python -I -B scripts/check_python_execution_contract.py --launch validate_all.py --
actionlint
GH_TOKEN=$(gh auth token) uvx zizmor@1.26.1 --persona regular --min-severity low .github/workflows
```
Expand Down
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
source=.agents/skills/ci-consumer-adoption/SKILL.md
sha256=349d73b940434016b11ee2ec99ee7edf011896d0f5b259282f2722252743341c
sha256=e92e2f643b1646e2bcdca8e9d1c11550a02732c5192944b20b28428078318173
2 changes: 1 addition & 1 deletion .claude/skills/ci-consumer-adoption/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ still bills, and a repository that is routed to hardware its jobs cannot use.
Do not choose a tier by reading prose. Resolve it:

```bash
python3 scripts/resolve_profile.py --visibility private --plan enterprise-cloud \
.venv/bin/python -I -B scripts/check_python_execution_contract.py --launch resolve_profile.py -- --visibility private --plan enterprise-cloud \
--code-security --secret-protection --code-quality
```

Expand Down
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
source=.agents/skills/nddev-repo-flow/SKILL.md
sha256=f97f89810a01582fb14f3f8978fdb0ae856d14c5760e547e8e45528e5fe4fe56
sha256=c32d871d397a4f1dabff335d9d7bdbf54f92d4c7b4f6306daff89b3772e8f5a3
12 changes: 7 additions & 5 deletions .claude/skills/nddev-repo-flow/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,20 +36,22 @@ it explains, so a reversal is deliberate.
2. Update `catalog/capabilities.yml`, and `catalog/tools.yml` if you added or
bumped an action. `used_by` and tool registration are both derived from the
tree by `check_tool_registry.py`, so an omission fails rather than rots.
3. `python3 scripts/generate_docs.py`.
3. Run `generate_docs.py` through the repository's isolated Python launcher.
4. Add a caller example under `examples/`. `check_examples.py` fails a reusable
with no example — it is the only executable statement of a caller contract.
5. Sync prose: `README.md`, the tier docs, the matching example.
6. `python3 scripts/sync_skills.py` if you touched a skill.
6. Run `sync_skills.py` through the isolated launcher if you touched a skill.
7. `CHANGELOG.md` under `[Unreleased]`.
8. Validate, then PR.

## Validate

```bash
uv pip install --system --require-hashes -r requirements-ci.txt
python3 scripts/validate_all.py --tier core # what ci-gate blocks on
python3 scripts/validate_all.py # all three tiers
python3.13 -I -B -m venv --copies .venv
uv pip install --python .venv/bin/python --require-hashes -r requirements-ci.txt
.venv/bin/python -I -B scripts/check_python_syntax.py
.venv/bin/python -I -B scripts/check_python_execution_contract.py --launch validate_all.py -- --tier core
.venv/bin/python -I -B scripts/check_python_execution_contract.py --launch validate_all.py --
actionlint
GH_TOKEN=$(gh auth token) uvx zizmor@1.26.1 --persona regular --min-severity low .github/workflows
```
Expand Down
74 changes: 54 additions & 20 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,17 +53,25 @@ jobs:
with:
persist-credentials: false
- name: Set up Python
id: python
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: "3.13"
update-environment: false
- name: Set up uv
uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0
with:
version: 0.11.30
- name: Install validator dependencies
run: uv pip install --system --require-hashes -r requirements-ci.txt
env:
PYTHON_PATH: ${{ steps.python.outputs.python-path }}
run: |
"$PYTHON_PATH" -I -B -m venv --copies .venv
uv pip install --python .venv/bin/python --require-hashes -r requirements-ci.txt
- name: Run static validators
run: python3 scripts/validate_all.py --tier core
run: |
.venv/bin/python -I -B scripts/check_python_syntax.py
.venv/bin/python -I -B scripts/check_python_execution_contract.py --launch validate_all.py -- --tier core

# Blocking, but scoped: a product fact is checked for expiry only when the
# changed capability declares it, and a runtime-coverage waiver only when its
Expand Down Expand Up @@ -95,15 +103,21 @@ jobs:
fetch-depth: 0
persist-credentials: false
- name: Set up Python
id: python
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: "3.13"
update-environment: false
- name: Set up uv
uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0
with:
version: 0.11.30
- name: Install validator dependencies
run: uv pip install --system --require-hashes -r requirements-ci.txt
env:
PYTHON_PATH: ${{ steps.python.outputs.python-path }}
run: |
"$PYTHON_PATH" -I -B -m venv --copies .venv
uv pip install --python .venv/bin/python --require-hashes -r requirements-ci.txt
- name: Resolve the change base
id: base
env:
Expand Down Expand Up @@ -131,11 +145,12 @@ jobs:
BASE_REF: ${{ steps.base.outputs.ref }}
run: |
set -euo pipefail
.venv/bin/python -I -B scripts/check_python_syntax.py
if [ -z "$BASE_REF" ]; then
echo "no resolvable base; running the full sweep instead of scoping to nothing"
python3 scripts/validate_all.py --tier scheduled
.venv/bin/python -I -B scripts/check_python_execution_contract.py --launch validate_all.py -- --tier scheduled
else
python3 scripts/validate_all.py --tier touched --changed-from "$BASE_REF"
.venv/bin/python -I -B scripts/check_python_execution_contract.py --launch validate_all.py -- --tier touched --changed-from "$BASE_REF"
fi

actionlint:
Expand Down Expand Up @@ -202,57 +217,67 @@ jobs:
with:
terraform_wrapper: false

- name: Set up Python
id: python
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: '3.13'
update-environment: false

- name: Set up uv
uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0
with:
version: 0.11.30
python-version: '3.13'
activate-environment: true
enable-cache: false

- name: Install the probe's dependency and both Python fixtures
env:
PYTHON_PATH: ${{ steps.python.outputs.python-path }}
run: |
set -euo pipefail
"$PYTHON_PATH" -I -B -m venv --copies .venv
# The probe reads workflow YAML through the repository's strict
# loader, so it needs PyYAML — from the hash-locked file CI already
# uses, not an ad-hoc install.
uv pip install --require-hashes -r requirements-ci.txt
uv pip install --python .venv/bin/python --require-hashes -r requirements-ci.txt
# Both fixture packages must be importable in one environment: the
# probe runs the same step twice and only the directory changes.
uv pip install -e tests/fixtures/python -e tests/fixtures/negative/python pytest
uv pip install --python .venv/bin/python \
-e tests/fixtures/python -e tests/fixtures/negative/python pytest

- name: terraform-ci must reject unformatted HCL
run: |
python3 -I scripts/negative_gate_probe.py \
.venv/bin/python -I -B scripts/check_python_syntax.py
.venv/bin/python -I -B scripts/check_python_execution_contract.py --launch negative_gate_probe.py -- \
--workflow .github/workflows/terraform-ci.yml --job terraform \
--step 'Format check' \
--bad tests/fixtures/negative/terraform --good tests/fixtures/terraform

- name: go-ci must report a failing test
run: |
python3 -I scripts/negative_gate_probe.py \
.venv/bin/python -I -B scripts/check_python_execution_contract.py --launch negative_gate_probe.py -- \
--workflow .github/workflows/go-ci.yml --job go \
--step 'Run tests' \
--bad tests/fixtures/negative/go --good tests/fixtures/go

- name: sql-ci must reject SQL the dialect refuses
run: |
python3 -I scripts/negative_gate_probe.py \
.venv/bin/python -I -B scripts/check_python_execution_contract.py --launch negative_gate_probe.py -- \
--workflow .github/workflows/sql-ci.yml --job sql \
--step 'Lint' \
--bad tests/fixtures/negative/sql --good tests/fixtures/sql

- name: python-ci must report a failing test
run: |
python3 -I scripts/negative_gate_probe.py \
.venv/bin/python -I -B scripts/check_python_execution_contract.py --launch negative_gate_probe.py -- \
--workflow .github/workflows/python-ci.yml --job python \
--step 'Run tests' \
--bad tests/fixtures/negative/python --good tests/fixtures/python \
--input test_command='python -m pytest -q'
--python-input test_command='-m pytest -q'

- name: docs-ci must reject a broken relative link
run: |
python3 -I scripts/negative_gate_probe.py \
.venv/bin/python -I -B scripts/check_python_execution_contract.py --launch negative_gate_probe.py -- \
--workflow .github/workflows/docs-ci.yml --job docs \
--step 'Check relative Markdown links' \
--bad . --good . \
Expand All @@ -266,7 +291,7 @@ jobs:
env:
GITHUB_TOKEN: ${{ github.token }}
run: |
python3 -I scripts/negative_gate_probe.py \
.venv/bin/python -I -B scripts/check_python_execution_contract.py --launch negative_gate_probe.py -- \
--workflow .github/workflows/zizmor-no-sarif.yml --job zizmor \
--step 'Run zizmor (plain, enforced)' \
--bad . --good . \
Expand All @@ -289,25 +314,34 @@ jobs:
with:
persist-credentials: false

- name: Set up Python
id: python
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: '3.13'
update-environment: false

- name: Set up uv
uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0
with:
version: 0.11.30
python-version: '3.13'
activate-environment: true
enable-cache: false

- name: Install the probe's dependency
env:
PYTHON_PATH: ${{ steps.python.outputs.python-path }}
run: |
set -euo pipefail
uv pip install --require-hashes -r requirements-ci.txt
"$PYTHON_PATH" -I -B -m venv --copies .venv
uv pip install --python .venv/bin/python --require-hashes -r requirements-ci.txt

# hadolint varies by input rather than by directory, and its binary is
# installed by an earlier step of the workflow itself, so --before runs
# that download instead of assuming a hadolint is already present.
- name: hadolint-ci must reject an unpinned base and package
run: |
python3 -I scripts/negative_gate_probe.py \
.venv/bin/python -I -B scripts/check_python_syntax.py
.venv/bin/python -I -B scripts/check_python_execution_contract.py --launch negative_gate_probe.py -- \
--workflow .github/workflows/hadolint-ci.yml --job hadolint \
--before 'Download hadolint (pinned + checksum-verified)' \
--step 'Run hadolint' \
Expand Down
11 changes: 9 additions & 2 deletions .github/workflows/maintenance.yml
Original file line number Diff line number Diff line change
Expand Up @@ -59,25 +59,32 @@ jobs:
persist-credentials: false

- name: Set up Python
id: python
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: "3.13"
update-environment: false

- name: Set up uv
uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0
with:
version: 0.11.30

- name: Install validator dependencies
run: uv pip install --system --require-hashes -r requirements-ci.txt
env:
PYTHON_PATH: ${{ steps.python.outputs.python-path }}
run: |
"$PYTHON_PATH" -I -B -m venv --copies .venv
uv pip install --python .venv/bin/python --require-hashes -r requirements-ci.txt

- name: Run the advisory sweep
id: sweep
run: |
set -uo pipefail
.venv/bin/python -I -B scripts/check_python_syntax.py
# Deliberately not `set -e`: a finding is the expected outcome and
# must be reported, not abort the job before it can be filed.
python3 scripts/validate_all.py --tier scheduled > sweep.txt 2>&1
.venv/bin/python -I -B scripts/check_python_execution_contract.py --launch validate_all.py -- --tier scheduled > sweep.txt 2>&1
status=$?
cat sweep.txt
printf 'status=%s\n' "$status" >> "$GITHUB_OUTPUT"
Expand Down
12 changes: 10 additions & 2 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,11 @@ jobs:
with:
persist-credentials: false
- name: Set up Python
id: python
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: "3.13"
update-environment: false

- name: Set up uv
uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0
Expand All @@ -80,14 +82,20 @@ jobs:
enable-cache: false

- name: Install validator dependencies
run: uv pip install --system --require-hashes -r requirements-ci.txt
env:
PYTHON_PATH: ${{ steps.python.outputs.python-path }}
run: |
"$PYTHON_PATH" -I -B -m venv --copies .venv
uv pip install --python .venv/bin/python --require-hashes -r requirements-ci.txt

# A release is the one place where the full sweep is the right gate: an
# immutable artifact must not ship carrying an expired external fact or a
# runtime-coverage waiver that is already past due. Pull requests get the
# scoped tiers; a release gets everything.
- name: Full validation sweep
run: python3 -I scripts/validate_all.py
run: |
.venv/bin/python -I -B scripts/check_python_syntax.py
.venv/bin/python -I -B scripts/check_python_execution_contract.py --launch validate_all.py --

- name: Resolve and validate version
id: v
Expand Down
26 changes: 24 additions & 2 deletions .github/workflows/runtime-fixtures-event-write.yml
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,17 @@ jobs:
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Set up isolated Python contract runtime
id: python
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: '3.13'
update-environment: false
- name: Provision isolated Python contract runtime
env:
PYTHON_PATH: ${{ steps.python.outputs.python-path }}
run: >-
"$PYTHON_PATH" -I -B -m venv --copies .venv
- name: Render benchmark evidence
env:
RESULTS: ${{ toJSON(needs) }}
Expand All @@ -155,7 +166,7 @@ jobs:
GUARDS: '{"fixture-benchmark":["cleanup-benchmark"]}'
run: |
set -euo pipefail
python3 -I scripts/render_runtime_evidence.py
.venv/bin/python -I -B scripts/check_python_execution_contract.py --launch render_runtime_evidence.py --

prepare-pr-hygiene:
if: ${{ github.event_name == 'pull_request' }}
Expand Down Expand Up @@ -283,6 +294,17 @@ jobs:
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Set up isolated Python contract runtime
id: python
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: '3.13'
update-environment: false
- name: Provision isolated Python contract runtime
env:
PYTHON_PATH: ${{ steps.python.outputs.python-path }}
run: >-
"$PYTHON_PATH" -I -B -m venv --copies .venv
- name: Render PR-hygiene evidence
env:
RESULTS: ${{ toJSON(needs) }}
Expand All @@ -291,4 +313,4 @@ jobs:
GUARDS: '{"fixture-pr-hygiene":["cleanup-pr-hygiene"]}'
run: |
set -euo pipefail
python3 -I scripts/render_runtime_evidence.py
.venv/bin/python -I -B scripts/check_python_execution_contract.py --launch render_runtime_evidence.py --
Loading
Loading