mirror of
https://github.com/elder-plinius/OBLITERATUS.git
synced 2026-08-18 00:47:23 +02:00
ci: add conditional environment test gates
This commit is contained in:
@@ -0,0 +1,19 @@
|
||||
self-hosted-runner:
|
||||
# Project-owned capability labels used by conditional test runners.
|
||||
labels: [cuda, mps, mlx]
|
||||
|
||||
# Configuration variables in array of strings defined in your repository or
|
||||
# organization. `null` means disabling configuration variables check.
|
||||
# Empty array means no configuration variable is allowed.
|
||||
config-variables: null
|
||||
|
||||
# Configuration for file paths. The keys are glob patterns to match to file
|
||||
# paths relative to the repository root. The values are the configurations for
|
||||
# the file paths. Note that the path separator is always '/'.
|
||||
# The following configurations are available.
|
||||
#
|
||||
# "ignore" is an array of regular expression patterns. Matched error messages
|
||||
# are ignored. This is similar to the "-ignore" command line option.
|
||||
paths:
|
||||
# .github/workflows/**/*.yml:
|
||||
# ignore: []
|
||||
@@ -202,6 +202,9 @@ jobs:
|
||||
scripts/check_coverage_thresholds.py
|
||||
scripts/check_mutation_score.py
|
||||
scripts/check_quality_policy.py
|
||||
scripts/check_conditional_policy.py
|
||||
scripts/conditional_gate_summary.py
|
||||
scripts/run_conditional_gate.py
|
||||
scripts/run_repeat_gate.py
|
||||
scripts/check_supply_chain_policy.py
|
||||
scripts/gemma4_12b_recursive_loop.py
|
||||
@@ -213,6 +216,9 @@ jobs:
|
||||
scripts/check_coverage_thresholds.py
|
||||
scripts/check_mutation_score.py
|
||||
scripts/check_quality_policy.py
|
||||
scripts/check_conditional_policy.py
|
||||
scripts/conditional_gate_summary.py
|
||||
scripts/run_conditional_gate.py
|
||||
scripts/run_repeat_gate.py
|
||||
scripts/check_supply_chain_policy.py
|
||||
scripts/gemma4_12b_recursive_loop.py || true
|
||||
@@ -275,7 +281,7 @@ jobs:
|
||||
run: |
|
||||
mkdir -p test-results
|
||||
"$TEST_ENV/bin/python" -m pytest \
|
||||
-m "not slow and not gpu and not mps and not mlx and not network and not download and not remote" \
|
||||
-m "not slow and not gpu and not mps and not mlx and not network and not download and not remote and not operator_ui" \
|
||||
--cov-branch \
|
||||
--cov-fail-under=0 \
|
||||
--junitxml="test-results/junit-py${{ matrix.python-version }}.xml" \
|
||||
@@ -304,10 +310,11 @@ jobs:
|
||||
--base-ref "$COVERAGE_BASE"
|
||||
|
||||
- name: Enforce mature CPU-scope coverage and immutable quality policy
|
||||
run: >-
|
||||
"$TEST_ENV/bin/python" scripts/check_quality_policy.py
|
||||
--policy ci/test-quality-policy.json
|
||||
--coverage "test-results/coverage-py${{ matrix.python-version }}.json"
|
||||
run: |
|
||||
"$TEST_ENV/bin/python" scripts/check_quality_policy.py \
|
||||
--policy ci/test-quality-policy.json \
|
||||
--coverage "test-results/coverage-py${{ matrix.python-version }}.json"
|
||||
"$TEST_ENV/bin/python" scripts/check_conditional_policy.py
|
||||
|
||||
- name: Upload test and coverage evidence
|
||||
if: always()
|
||||
|
||||
@@ -0,0 +1,368 @@
|
||||
name: Conditional tests
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
run_model:
|
||||
description: Run pinned tiny-model download and evaluation gates
|
||||
type: boolean
|
||||
default: true
|
||||
run_network:
|
||||
description: Run disposable network-service boundary gate
|
||||
type: boolean
|
||||
default: true
|
||||
run_ui:
|
||||
description: Construct the optional operator UI without a listener
|
||||
type: boolean
|
||||
default: true
|
||||
run_cuda:
|
||||
description: Run CUDA and bitsandbytes on the labeled self-hosted runner
|
||||
type: boolean
|
||||
default: false
|
||||
run_mps:
|
||||
description: Run MPS on the labeled Apple Silicon runner
|
||||
type: boolean
|
||||
default: false
|
||||
run_mlx:
|
||||
description: Run MLX on the labeled Apple Silicon runner
|
||||
type: boolean
|
||||
default: false
|
||||
run_remote:
|
||||
description: Run the least-privileged SSH provider gate
|
||||
type: boolean
|
||||
default: false
|
||||
schedule:
|
||||
- cron: "17 6 * * 0"
|
||||
release:
|
||||
types: [published]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: conditional-tests-${{ github.ref }}
|
||||
cancel-in-progress: false
|
||||
|
||||
env:
|
||||
PIP_DISABLE_PIP_VERSION_CHECK: "1"
|
||||
PIP_NO_INPUT: "1"
|
||||
UV_VERSION: "0.12.4"
|
||||
|
||||
jobs:
|
||||
policy:
|
||||
name: Conditional policy
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 5
|
||||
steps:
|
||||
- name: Check out repository
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
- name: Validate gate mappings and evidence policy
|
||||
run: python3 scripts/check_conditional_policy.py
|
||||
|
||||
model_runtime:
|
||||
name: Pinned model runtime and evaluation
|
||||
needs: policy
|
||||
if: github.event_name != 'workflow_dispatch' || inputs.run_model
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 25
|
||||
env:
|
||||
CONDITIONAL_ENV: /tmp/obliteratus-conditional-model
|
||||
HF_HOME: /tmp/obliteratus-hf-cache
|
||||
HF_HUB_DISABLE_TELEMETRY: "1"
|
||||
TOKENIZERS_PARALLELISM: "false"
|
||||
steps:
|
||||
- name: Check out repository
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
|
||||
with:
|
||||
python-version: "3.12"
|
||||
- name: Restore pinned model cache
|
||||
uses: actions/cache@caa296126883cff596d87d8935842f9db880ef25 # v5.0.3
|
||||
with:
|
||||
path: /tmp/obliteratus-hf-cache
|
||||
key: hf-tiny-random-gpt2-71034c5-py3.12-${{ runner.os }}
|
||||
- name: Install locked runtime
|
||||
run: |
|
||||
python -m pip install "uv==${UV_VERSION}"
|
||||
UV_PROJECT_ENVIRONMENT="$CONDITIONAL_ENV" \
|
||||
uv sync --locked --no-default-groups --extra dev --no-editable
|
||||
- name: Run model download and cache replay
|
||||
run: >-
|
||||
"$CONDITIONAL_ENV/bin/python" scripts/run_conditional_gate.py
|
||||
model-download-runtime
|
||||
- name: Run external evaluation adapter
|
||||
run: >-
|
||||
"$CONDITIONAL_ENV/bin/python" scripts/run_conditional_gate.py
|
||||
external-evaluation
|
||||
- name: Upload model-runtime evidence
|
||||
if: always()
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: conditional-model-runtime-${{ github.run_attempt }}
|
||||
path: conditional-evidence/
|
||||
if-no-files-found: error
|
||||
retention-days: 30
|
||||
|
||||
network_services:
|
||||
name: Network service boundary
|
||||
needs: policy
|
||||
if: github.event_name != 'workflow_dispatch' || inputs.run_network
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 10
|
||||
env:
|
||||
CONDITIONAL_ENV: /tmp/obliteratus-conditional-network
|
||||
steps:
|
||||
- name: Check out repository
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
|
||||
with:
|
||||
python-version: "3.12"
|
||||
- name: Install locked runtime
|
||||
run: |
|
||||
python -m pip install "uv==${UV_VERSION}"
|
||||
UV_PROJECT_ENVIRONMENT="$CONDITIONAL_ENV" \
|
||||
uv sync --locked --no-default-groups --extra dev --no-editable
|
||||
- name: Run disposable service probe
|
||||
run: >-
|
||||
"$CONDITIONAL_ENV/bin/python" scripts/run_conditional_gate.py
|
||||
network-services
|
||||
- name: Upload network evidence
|
||||
if: always()
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: conditional-network-${{ github.run_attempt }}
|
||||
path: conditional-evidence/
|
||||
if-no-files-found: error
|
||||
retention-days: 30
|
||||
|
||||
operator_ui:
|
||||
name: Operator UI construction
|
||||
needs: policy
|
||||
if: github.event_name != 'workflow_dispatch' || inputs.run_ui
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 15
|
||||
env:
|
||||
CONDITIONAL_ENV: /tmp/obliteratus-conditional-ui
|
||||
steps:
|
||||
- name: Check out repository
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
|
||||
with:
|
||||
python-version: "3.12"
|
||||
- name: Install locked UI runtime
|
||||
run: |
|
||||
python -m pip install "uv==${UV_VERSION}"
|
||||
UV_PROJECT_ENVIRONMENT="$CONDITIONAL_ENV" \
|
||||
uv sync --locked --all-extras --no-default-groups --no-editable
|
||||
- name: Construct UI without opening a listener
|
||||
run: >-
|
||||
"$CONDITIONAL_ENV/bin/python" scripts/run_conditional_gate.py
|
||||
operator-ui
|
||||
- name: Upload UI evidence
|
||||
if: always()
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: conditional-operator-ui-${{ github.run_attempt }}
|
||||
path: conditional-evidence/
|
||||
if-no-files-found: error
|
||||
retention-days: 30
|
||||
|
||||
cuda:
|
||||
name: CUDA and bitsandbytes runtime
|
||||
needs: policy
|
||||
if: >-
|
||||
(github.event_name == 'workflow_dispatch' && inputs.run_cuda) ||
|
||||
(github.event_name != 'workflow_dispatch' && vars.ENABLE_CUDA_GATE == 'true')
|
||||
runs-on: [self-hosted, linux, x64, cuda]
|
||||
timeout-minutes: 20
|
||||
env:
|
||||
CONDITIONAL_ENV: /tmp/obliteratus-conditional-cuda
|
||||
steps:
|
||||
- name: Check out repository
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
|
||||
with:
|
||||
python-version: "3.12"
|
||||
- name: Install locked CUDA runtime
|
||||
run: |
|
||||
python -m pip install "uv==${UV_VERSION}"
|
||||
UV_PROJECT_ENVIRONMENT="$CONDITIONAL_ENV" \
|
||||
uv sync --locked --no-default-groups --extra dev --no-editable
|
||||
- name: Run CUDA placement and operation probe
|
||||
run: >-
|
||||
"$CONDITIONAL_ENV/bin/python" scripts/run_conditional_gate.py cuda-runtime
|
||||
- name: Run bitsandbytes quantization probe
|
||||
run: >-
|
||||
"$CONDITIONAL_ENV/bin/python" scripts/run_conditional_gate.py bitsandbytes-runtime
|
||||
- name: Upload CUDA evidence
|
||||
if: always()
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: conditional-cuda-${{ github.run_attempt }}
|
||||
path: conditional-evidence/
|
||||
if-no-files-found: error
|
||||
retention-days: 30
|
||||
|
||||
mps:
|
||||
name: Apple MPS runtime
|
||||
needs: policy
|
||||
if: >-
|
||||
(github.event_name == 'workflow_dispatch' && inputs.run_mps) ||
|
||||
(github.event_name != 'workflow_dispatch' && vars.ENABLE_MPS_GATE == 'true')
|
||||
runs-on: [self-hosted, macOS, ARM64, mps]
|
||||
timeout-minutes: 15
|
||||
env:
|
||||
CONDITIONAL_ENV: /tmp/obliteratus-conditional-mps
|
||||
steps:
|
||||
- name: Check out repository
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
|
||||
with:
|
||||
python-version: "3.12"
|
||||
- name: Install locked MPS runtime
|
||||
run: |
|
||||
python -m pip install "uv==${UV_VERSION}"
|
||||
UV_PROJECT_ENVIRONMENT="$CONDITIONAL_ENV" \
|
||||
uv sync --locked --no-default-groups --extra dev --no-editable
|
||||
- name: Run MPS selection and operation probe
|
||||
run: >-
|
||||
"$CONDITIONAL_ENV/bin/python" scripts/run_conditional_gate.py mps-runtime
|
||||
- name: Upload MPS evidence
|
||||
if: always()
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: conditional-mps-${{ github.run_attempt }}
|
||||
path: conditional-evidence/
|
||||
if-no-files-found: error
|
||||
retention-days: 30
|
||||
|
||||
mlx:
|
||||
name: Apple MLX runtime
|
||||
needs: policy
|
||||
if: >-
|
||||
(github.event_name == 'workflow_dispatch' && inputs.run_mlx) ||
|
||||
(github.event_name != 'workflow_dispatch' && vars.ENABLE_MLX_GATE == 'true')
|
||||
runs-on: [self-hosted, macOS, ARM64, mlx]
|
||||
timeout-minutes: 20
|
||||
env:
|
||||
CONDITIONAL_ENV: /tmp/obliteratus-conditional-mlx
|
||||
steps:
|
||||
- name: Check out repository
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
|
||||
with:
|
||||
python-version: "3.12"
|
||||
- name: Install locked MLX runtime
|
||||
run: |
|
||||
python -m pip install "uv==${UV_VERSION}"
|
||||
UV_PROJECT_ENVIRONMENT="$CONDITIONAL_ENV" \
|
||||
uv sync --locked --no-default-groups --extra dev --group mlx --no-editable
|
||||
- name: Run MLX placement and operation probe
|
||||
run: >-
|
||||
"$CONDITIONAL_ENV/bin/python" scripts/run_conditional_gate.py mlx-runtime
|
||||
- name: Upload MLX evidence
|
||||
if: always()
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: conditional-mlx-${{ github.run_attempt }}
|
||||
path: conditional-evidence/
|
||||
if-no-files-found: error
|
||||
retention-days: 30
|
||||
|
||||
remote:
|
||||
name: Least-privileged remote provider
|
||||
needs: policy
|
||||
if: >-
|
||||
(github.event_name == 'workflow_dispatch' && inputs.run_remote) ||
|
||||
(github.event_name != 'workflow_dispatch' && vars.ENABLE_REMOTE_GATE == 'true')
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 10
|
||||
env:
|
||||
CONDITIONAL_ENV: /tmp/obliteratus-conditional-remote
|
||||
OBLITERATUS_REMOTE_HOST: ${{ vars.OBLITERATUS_REMOTE_HOST }}
|
||||
OBLITERATUS_REMOTE_USER: ${{ vars.OBLITERATUS_REMOTE_USER }}
|
||||
OBLITERATUS_REMOTE_PORT: ${{ vars.OBLITERATUS_REMOTE_PORT }}
|
||||
steps:
|
||||
- name: Check out repository
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
|
||||
with:
|
||||
python-version: "3.12"
|
||||
- name: Install locked runtime
|
||||
run: |
|
||||
python -m pip install "uv==${UV_VERSION}"
|
||||
UV_PROJECT_ENVIRONMENT="$CONDITIONAL_ENV" \
|
||||
uv sync --locked --no-default-groups --extra dev --no-editable
|
||||
- name: Materialize protected SSH prerequisites
|
||||
env:
|
||||
REMOTE_KEY_CONTENT: ${{ secrets.OBLITERATUS_REMOTE_KEY }}
|
||||
REMOTE_KNOWN_HOSTS_CONTENT: ${{ secrets.OBLITERATUS_REMOTE_KNOWN_HOSTS }}
|
||||
run: |
|
||||
if [ -z "$OBLITERATUS_REMOTE_HOST" ] || [ -z "$OBLITERATUS_REMOTE_USER" ]; then
|
||||
echo "remote gate selected: configure non-root OBLITERATUS_REMOTE_HOST and OBLITERATUS_REMOTE_USER variables"
|
||||
exit 1
|
||||
fi
|
||||
if [ -z "$REMOTE_KEY_CONTENT" ] || [ -z "$REMOTE_KNOWN_HOSTS_CONTENT" ]; then
|
||||
echo "remote gate selected: configure OBLITERATUS_REMOTE_KEY and pinned OBLITERATUS_REMOTE_KNOWN_HOSTS secrets"
|
||||
exit 1
|
||||
fi
|
||||
install -m 700 -d "$RUNNER_TEMP/obliteratus-ssh"
|
||||
install -m 600 /dev/null "$RUNNER_TEMP/obliteratus-ssh/key"
|
||||
install -m 600 /dev/null "$RUNNER_TEMP/obliteratus-ssh/known_hosts"
|
||||
printf '%s\n' "$REMOTE_KEY_CONTENT" > "$RUNNER_TEMP/obliteratus-ssh/key"
|
||||
printf '%s\n' "$REMOTE_KNOWN_HOSTS_CONTENT" > "$RUNNER_TEMP/obliteratus-ssh/known_hosts"
|
||||
- name: Run remote provider probe
|
||||
env:
|
||||
OBLITERATUS_REMOTE_KEY: ${{ runner.temp }}/obliteratus-ssh/key
|
||||
OBLITERATUS_REMOTE_KNOWN_HOSTS: ${{ runner.temp }}/obliteratus-ssh/known_hosts
|
||||
run: >-
|
||||
"$CONDITIONAL_ENV/bin/python" scripts/run_conditional_gate.py remote-execution
|
||||
- name: Upload remote evidence
|
||||
if: always()
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: conditional-remote-${{ github.run_attempt }}
|
||||
path: conditional-evidence/
|
||||
if-no-files-found: warn
|
||||
retention-days: 30
|
||||
|
||||
summary:
|
||||
name: Conditional result and freshness summary
|
||||
if: always()
|
||||
needs: [policy, model_runtime, network_services, operator_ui, cuda, mps, mlx, remote]
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 5
|
||||
env:
|
||||
CONDITIONAL_RESULTS: >-
|
||||
{"policy":"${{ needs.policy.result }}","model_runtime":"${{ needs.model_runtime.result }}",
|
||||
"network_services":"${{ needs.network_services.result }}","operator_ui":"${{ needs.operator_ui.result }}",
|
||||
"cuda":"${{ needs.cuda.result }}","mps":"${{ needs.mps.result }}","mlx":"${{ needs.mlx.result }}",
|
||||
"remote":"${{ needs.remote.result }}"}
|
||||
CONDITIONAL_SELECTED: >-
|
||||
{"model_runtime":${{ github.event_name != 'workflow_dispatch' || inputs.run_model }},
|
||||
"network_services":${{ github.event_name != 'workflow_dispatch' || inputs.run_network }},
|
||||
"operator_ui":${{ github.event_name != 'workflow_dispatch' || inputs.run_ui }},
|
||||
"cuda":${{ (github.event_name == 'workflow_dispatch' && inputs.run_cuda) || (github.event_name != 'workflow_dispatch' && vars.ENABLE_CUDA_GATE == 'true') }},
|
||||
"mps":${{ (github.event_name == 'workflow_dispatch' && inputs.run_mps) || (github.event_name != 'workflow_dispatch' && vars.ENABLE_MPS_GATE == 'true') }},
|
||||
"mlx":${{ (github.event_name == 'workflow_dispatch' && inputs.run_mlx) || (github.event_name != 'workflow_dispatch' && vars.ENABLE_MLX_GATE == 'true') }},
|
||||
"remote":${{ (github.event_name == 'workflow_dispatch' && inputs.run_remote) || (github.event_name != 'workflow_dispatch' && vars.ENABLE_REMOTE_GATE == 'true') }}}
|
||||
steps:
|
||||
- name: Check out repository
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
- name: Enforce selected job results and publish freshness summary
|
||||
run: python3 scripts/conditional_gate_summary.py
|
||||
- name: Upload conditional summary
|
||||
if: always()
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: conditional-summary-${{ github.run_attempt }}
|
||||
path: conditional-evidence/summary.json
|
||||
if-no-files-found: error
|
||||
retention-days: 30
|
||||
Reference in New Issue
Block a user