ci(test): add restricted-environment hermetic validation lane
This commit is contained in:
parent
69232d0eaa
commit
7a07f2b90f
34
.github/workflows/ci-run.yml
vendored
34
.github/workflows/ci-run.yml
vendored
@ -225,6 +225,32 @@ jobs:
|
||||
if-no-files-found: ignore
|
||||
retention-days: 14
|
||||
|
||||
restricted-hermetic:
|
||||
name: Restricted Hermetic Validation
|
||||
needs: [changes]
|
||||
if: needs.changes.outputs.rust_changed == 'true'
|
||||
runs-on: [self-hosted, Linux, X64, aws-india, blacksmith-2vcpu-ubuntu-2404, hetzner]
|
||||
timeout-minutes: 45
|
||||
env:
|
||||
CARGO_HOME: ${{ github.workspace }}/.ci-rust/${{ github.run_id }}-${{ github.run_attempt }}-${{ github.job }}/cargo
|
||||
RUSTUP_HOME: ${{ github.workspace }}/.ci-rust/${{ github.run_id }}-${{ github.run_attempt }}-${{ github.job }}/rustup
|
||||
CARGO_TARGET_DIR: ${{ github.workspace }}/.ci-rust/${{ github.run_id }}-${{ github.run_attempt }}-${{ github.job }}/target
|
||||
steps:
|
||||
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
||||
- name: Self-heal Rust toolchain cache
|
||||
shell: bash
|
||||
run: ./scripts/ci/self_heal_rust_toolchain.sh 1.92.0
|
||||
- uses: dtolnay/rust-toolchain@631a55b12751854ce901bb631d5902ceb48146f7 # stable
|
||||
with:
|
||||
toolchain: 1.92.0
|
||||
- uses: Swatinem/rust-cache@779680da715d629ac1d338a641029a2f4372abb5 # v3
|
||||
with:
|
||||
prefix-key: ci-run-restricted-hermetic
|
||||
cache-bin: false
|
||||
- name: Run restricted-profile hermetic subset
|
||||
shell: bash
|
||||
run: ./scripts/ci/restricted_profile.sh
|
||||
|
||||
build:
|
||||
name: Build (Smoke)
|
||||
needs: [changes]
|
||||
@ -501,7 +527,7 @@ jobs:
|
||||
ci-required:
|
||||
name: CI Required Gate
|
||||
if: always()
|
||||
needs: [changes, lint, workspace-check, package-check, test, build, cross-platform-vm, linux-distro-container, docker-smoke, docs-only, non-rust, docs-quality, lint-feedback, license-file-owner-guard]
|
||||
needs: [changes, lint, workspace-check, package-check, test, restricted-hermetic, build, cross-platform-vm, linux-distro-container, docker-smoke, docs-only, non-rust, docs-quality, lint-feedback, license-file-owner-guard]
|
||||
runs-on: [self-hosted, Linux, X64, aws-india, light, cpu40]
|
||||
steps:
|
||||
- name: Enforce required status
|
||||
@ -558,6 +584,7 @@ jobs:
|
||||
workspace_check_result="${{ needs.workspace-check.result }}"
|
||||
package_check_result="${{ needs.package-check.result }}"
|
||||
test_result="${{ needs.test.result }}"
|
||||
restricted_hermetic_result="${{ needs.restricted-hermetic.result }}"
|
||||
build_result="${{ needs.build.result }}"
|
||||
cross_platform_vm_result="${{ needs.cross-platform-vm.result }}"
|
||||
linux_distro_container_result="${{ needs.linux-distro-container.result }}"
|
||||
@ -567,6 +594,7 @@ jobs:
|
||||
echo "workspace-check=${workspace_check_result}"
|
||||
echo "package-check=${package_check_result}"
|
||||
echo "test=${test_result}"
|
||||
echo "restricted-hermetic=${restricted_hermetic_result}"
|
||||
echo "build=${build_result}"
|
||||
echo "cross-platform-vm=${cross_platform_vm_result}"
|
||||
echo "linux-distro-container=${linux_distro_container_result}"
|
||||
@ -576,8 +604,8 @@ jobs:
|
||||
|
||||
check_pr_governance
|
||||
|
||||
if [ "$lint_result" != "success" ] || [ "$workspace_check_result" != "success" ] || [ "$package_check_result" != "success" ] || [ "$test_result" != "success" ] || [ "$build_result" != "success" ] || [ "$cross_platform_vm_result" != "success" ] || [ "$linux_distro_container_result" != "success" ] || [ "$docker_smoke_result" != "success" ]; then
|
||||
echo "Required CI jobs did not pass: lint=${lint_result} workspace-check=${workspace_check_result} package-check=${package_check_result} test=${test_result} build=${build_result} cross-platform-vm=${cross_platform_vm_result} linux-distro-container=${linux_distro_container_result} docker-smoke=${docker_smoke_result}"
|
||||
if [ "$lint_result" != "success" ] || [ "$workspace_check_result" != "success" ] || [ "$package_check_result" != "success" ] || [ "$test_result" != "success" ] || [ "$restricted_hermetic_result" != "success" ] || [ "$build_result" != "success" ] || [ "$cross_platform_vm_result" != "success" ] || [ "$linux_distro_container_result" != "success" ] || [ "$docker_smoke_result" != "success" ]; then
|
||||
echo "Required CI jobs did not pass: lint=${lint_result} workspace-check=${workspace_check_result} package-check=${package_check_result} test=${test_result} restricted-hermetic=${restricted_hermetic_result} build=${build_result} cross-platform-vm=${cross_platform_vm_result} linux-distro-container=${linux_distro_container_result} docker-smoke=${docker_smoke_result}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
@ -12,7 +12,8 @@ Merge-blocking checks should stay small and deterministic. Optional checks are u
|
||||
|
||||
- `.github/workflows/ci-run.yml` (`CI`)
|
||||
- Purpose: Rust validation (`cargo fmt --all -- --check`, `cargo clippy --locked --all-targets -- -D clippy::correctness`, strict delta lint gate on changed Rust lines, `test`, release build smoke) + docs quality checks when docs change (`markdownlint` blocks only issues on changed lines; link check scans only links added on changed lines)
|
||||
- Additional behavior: for Rust-impacting PRs and pushes, `CI Required Gate` requires `lint` + `test` + `build` (no PR build-only bypass)
|
||||
- Additional behavior: for Rust-impacting PRs and pushes, `CI Required Gate` requires `lint` + `test` + `restricted-hermetic` + `build` (no PR build-only bypass)
|
||||
- Additional behavior: includes `Restricted Hermetic Validation` lane (`./scripts/ci/restricted_profile.sh`) that runs a capability-aware subset with isolated `HOME`/workspace/config roots and no external provider credentials
|
||||
- Additional behavior: rust-cache is partitioned per job role via `prefix-key` to reduce cache churn across lint/test/build/flake-probe lanes
|
||||
- Additional behavior: emits `test-flake-probe` artifact from single-retry probe when tests fail; optional blocking can be enabled with repository variable `CI_BLOCK_ON_FLAKE_SUSPECTED=true`
|
||||
- Additional behavior: PRs that change `.github/workflows/**` require at least one approving review from a login in `WORKFLOW_OWNER_LOGINS` (repository variable fallback: `theonlyhennygod,willsarg`)
|
||||
@ -137,6 +138,7 @@ Merge-blocking checks should stay small and deterministic. Optional checks are u
|
||||
- Keep required check naming stable and documented in `docs/operations/required-check-mapping.md` before changing branch protection settings.
|
||||
- Follow `docs/release-process.md` for verify-before-publish release cadence and tag discipline.
|
||||
- Keep merge-blocking rust quality policy aligned across `.github/workflows/ci-run.yml`, `dev/ci.sh`, and `.githooks/pre-push` (`./scripts/ci/rust_quality_gate.sh` + `./scripts/ci/rust_strict_delta_gate.sh`).
|
||||
- Reproduce restricted/hermetic CI behavior locally with `./scripts/ci/restricted_profile.sh` before changing workspace/home-sensitive runtime code.
|
||||
- Use `./scripts/ci/rust_strict_delta_gate.sh` (or `./dev/ci.sh lint-delta`) as the incremental strict merge gate for changed Rust lines.
|
||||
- Run full strict lint audits regularly via `./scripts/ci/rust_quality_gate.sh --strict` (for example through `./dev/ci.sh lint-strict`) and track cleanup in focused PRs.
|
||||
- Keep docs markdown gating incremental via `./scripts/ci/docs_quality_gate.sh` (block changed-line issues, report baseline issues separately).
|
||||
|
||||
64
scripts/ci/restricted_profile.sh
Executable file
64
scripts/ci/restricted_profile.sh
Executable file
@ -0,0 +1,64 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# Restricted-profile CI lane:
|
||||
# - isolates HOME/XDG paths into a throwaway directory
|
||||
# - forces workspace/config roots away from developer machine defaults
|
||||
# - runs capability-aware tests that should not require external network access
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
REPO_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)"
|
||||
cd "${REPO_ROOT}"
|
||||
|
||||
TMP_ROOT="$(mktemp -d "${TMPDIR:-/tmp}/zeroclaw-restricted-profile.XXXXXX")"
|
||||
cleanup() {
|
||||
rm -rf "${TMP_ROOT}"
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
RESTRICTED_HOME="${TMP_ROOT}/home"
|
||||
RESTRICTED_WORKSPACE="${TMP_ROOT}/workspace-root"
|
||||
mkdir -p "${RESTRICTED_HOME}" "${RESTRICTED_WORKSPACE}"
|
||||
chmod 700 "${RESTRICTED_HOME}" "${RESTRICTED_WORKSPACE}"
|
||||
|
||||
ORIGINAL_HOME="${HOME:-}"
|
||||
if [ -z "${RUSTUP_HOME:-}" ] && [ -n "${ORIGINAL_HOME}" ]; then
|
||||
export RUSTUP_HOME="${ORIGINAL_HOME}/.rustup"
|
||||
fi
|
||||
if [ -z "${CARGO_HOME:-}" ] && [ -n "${ORIGINAL_HOME}" ]; then
|
||||
export CARGO_HOME="${ORIGINAL_HOME}/.cargo"
|
||||
fi
|
||||
if [ -n "${CARGO_HOME:-}" ] && [ -d "${CARGO_HOME}/bin" ]; then
|
||||
case ":${PATH}:" in
|
||||
*":${CARGO_HOME}/bin:"*) ;;
|
||||
*) export PATH="${CARGO_HOME}/bin:${PATH}" ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
export HOME="${RESTRICTED_HOME}"
|
||||
export USERPROFILE="${RESTRICTED_HOME}"
|
||||
export XDG_CONFIG_HOME="${RESTRICTED_HOME}/.config"
|
||||
export XDG_CACHE_HOME="${RESTRICTED_HOME}/.cache"
|
||||
export XDG_DATA_HOME="${RESTRICTED_HOME}/.local/share"
|
||||
export ZEROCLAW_WORKSPACE="${RESTRICTED_WORKSPACE}"
|
||||
mkdir -p "${XDG_CONFIG_HOME}" "${XDG_CACHE_HOME}" "${XDG_DATA_HOME}"
|
||||
|
||||
# Keep credential/network assumptions explicit for this lane.
|
||||
unset GEMINI_OAUTH_CLIENT_ID GEMINI_OAUTH_CLIENT_SECRET OPENAI_API_KEY ANTHROPIC_API_KEY
|
||||
unset HTTP_PROXY HTTPS_PROXY ALL_PROXY
|
||||
export NO_PROXY="127.0.0.1,localhost"
|
||||
|
||||
tests=(
|
||||
"skills::tests::load_skills_with_config_reads_open_skills_dir_without_network"
|
||||
"onboard::wizard::tests::run_models_refresh_uses_fresh_cache_without_network"
|
||||
"onboard::wizard::tests::quick_setup_respects_zero_claw_workspace_env_layout"
|
||||
"config::schema::tests::load_or_init_workspace_override_uses_workspace_root_for_config"
|
||||
)
|
||||
|
||||
echo "Running restricted-profile hermetic subset (${#tests[@]} tests)"
|
||||
for test_name in "${tests[@]}"; do
|
||||
echo "==> cargo test --locked --lib ${test_name}"
|
||||
cargo test --locked --lib "${test_name}"
|
||||
done
|
||||
|
||||
echo "Restricted-profile hermetic subset completed successfully."
|
||||
Loading…
Reference in New Issue
Block a user