diff --git a/.github/actions/setup-python-safe/action.yml b/.github/actions/setup-python-safe/action.yml index 614ecef46f..a47b476862 100644 --- a/.github/actions/setup-python-safe/action.yml +++ b/.github/actions/setup-python-safe/action.yml @@ -20,6 +20,15 @@ inputs: runs: using: "composite" steps: + - name: Prepare writable tool cache + shell: bash + run: | + set -euo pipefail + TOOL_CACHE="${RUNNER_TEMP:-/tmp}/hostedtoolcache" + mkdir -p "${TOOL_CACHE}" + echo "AGENT_TOOLSDIRECTORY=${TOOL_CACHE}" >> "${GITHUB_ENV}" + echo "RUNNER_TOOL_CACHE=${TOOL_CACHE}" >> "${GITHUB_ENV}" + - name: Set up Python ${{ inputs.python-version }} id: setup-python uses: actions/setup-python@v5 @@ -33,13 +42,57 @@ runs: if: steps.setup-python.outcome == 'failure' shell: bash run: | + set -euo pipefail echo "::warning::actions/setup-python failed — falling back to system Python" + PY_BIN="" for cmd in python${{ inputs.python-version }} python3 python; do if command -v "$cmd" &>/dev/null; then echo "Found $cmd: $("$cmd" --version)" - sudo ln -sf "$(command -v "$cmd")" /usr/local/bin/python - sudo ln -sf "$(command -v "$cmd")" /usr/local/bin/python3 + PY_BIN="$(command -v "$cmd")" break fi done - python --version || { echo "::error::No Python interpreter found"; exit 1; } + + # actions/setup-python may download and unpack a requested interpreter + # before failing to install into the hosted tool cache. Reuse that + # unpacked binary when available. + if [[ -z "${PY_BIN}" && -n "${RUNNER_TEMP:-}" ]]; then + DISCOVERED_PY="$(find "${RUNNER_TEMP}" -type f -name "python${{ inputs.python-version }}" -perm -u+x 2>/dev/null | head -n 1 || true)" + if [[ -n "${DISCOVERED_PY}" ]]; then + PY_BIN="${DISCOVERED_PY}" + echo "Found unpacked interpreter in RUNNER_TEMP: ${PY_BIN}" + "${PY_BIN}" --version || true + fi + fi + + if [[ -z "${PY_BIN}" ]]; then + echo "::error::No Python interpreter found" + exit 1 + fi + + LOCAL_BIN="${RUNNER_TEMP:-$HOME}/setup-python-safe-bin" + mkdir -p "${LOCAL_BIN}" + cat > "${LOCAL_BIN}/python" < "${LOCAL_BIN}/pip" <> "${GITHUB_PATH}" + export PATH="${LOCAL_BIN}:${PATH}" + + "${LOCAL_BIN}/python" --version + "${LOCAL_BIN}/python" -m pip --version diff --git a/.github/workflows/aragora-review-gate.yml b/.github/workflows/aragora-review-gate.yml index de6803ba02..8085953199 100644 --- a/.github/workflows/aragora-review-gate.yml +++ b/.github/workflows/aragora-review-gate.yml @@ -132,7 +132,7 @@ jobs: - name: Install Aragora run: | python -m pip install --upgrade pip - pip install -e . 2>/dev/null || pip install -r requirements.txt + python -m pip install -e . 2>/dev/null || python -m pip install -r requirements.txt - name: Run Aragora Review id: review diff --git a/.github/workflows/autopilot-worktree-e2e.yml b/.github/workflows/autopilot-worktree-e2e.yml index 1e86705025..9012411fc1 100644 --- a/.github/workflows/autopilot-worktree-e2e.yml +++ b/.github/workflows/autopilot-worktree-e2e.yml @@ -114,8 +114,8 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install -e ".[dev,test]" - pip install pytest-timeout + python -m pip install -e ".[dev,test]" + python -m pip install pytest-timeout - name: Run autopilot API end-to-end test env: diff --git a/.github/workflows/backup-verification.yml b/.github/workflows/backup-verification.yml index ba8eeadbf3..0c263f9ebf 100644 --- a/.github/workflows/backup-verification.yml +++ b/.github/workflows/backup-verification.yml @@ -68,7 +68,7 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install -e ".[dev]" + python -m pip install -e ".[dev]" - name: Run backup manager tests run: | @@ -128,7 +128,7 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install -e ".[dev]" + python -m pip install -e ".[dev]" - name: Run DR drill tests run: | @@ -182,7 +182,7 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install -e ".[dev]" + python -m pip install -e ".[dev]" - name: Run backup handler tests run: | diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index 8d8bbe6e1d..d7a1dca741 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -76,7 +76,7 @@ jobs: run: | python -m pip install --upgrade pip bash scripts/ci_install_project.sh --extras test - pip install pytest-benchmark + python -m pip install pytest-benchmark - name: Run benchmark tests run: | @@ -235,7 +235,7 @@ jobs: run: | python -m pip install --upgrade pip bash scripts/ci_install_project.sh --extras test - pip install pytest-benchmark + python -m pip install pytest-benchmark - name: Run PR benchmarks run: | diff --git a/.github/workflows/benchmarks.yml b/.github/workflows/benchmarks.yml index 9161b34e6f..c981c95e87 100644 --- a/.github/workflows/benchmarks.yml +++ b/.github/workflows/benchmarks.yml @@ -130,9 +130,9 @@ jobs: run: | python -m venv /tmp/main-venv source /tmp/main-venv/bin/activate - pip install --upgrade pip - pip install -e "main-branch/[test]" - pip install pytest-benchmark + python -m pip install --upgrade pip + python -m pip install -e "main-branch/[test]" + python -m pip install pytest-benchmark cd main-branch pytest tests/benchmarks/test_performance.py \ --benchmark-only \ diff --git a/.github/workflows/capability-gap.yml b/.github/workflows/capability-gap.yml index 53b7c20017..6a1578f327 100644 --- a/.github/workflows/capability-gap.yml +++ b/.github/workflows/capability-gap.yml @@ -68,7 +68,7 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install -e . + python -m pip install -e . - name: Generate report (markdown) run: | diff --git a/.github/workflows/contract-drift-governance.yml b/.github/workflows/contract-drift-governance.yml index d7b32c6925..6c092e5c9f 100644 --- a/.github/workflows/contract-drift-governance.yml +++ b/.github/workflows/contract-drift-governance.yml @@ -62,7 +62,7 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install -e . + python -m pip install -e . - name: Generate drift summary and planning artifacts run: | diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 993834c08f..1cef4d252c 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -59,7 +59,7 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install -e ".[dev,test]" + python -m pip install -e ".[dev,test]" - name: Run tests with coverage run: | @@ -260,7 +260,7 @@ jobs: if: steps.changed.outputs.files != '' run: | echo "Changed files: ${{ steps.changed.outputs.files }}" - pip install -e ".[dev,test]" + python -m pip install -e ".[dev,test]" # Run coverage on changed files only python -m pytest tests/ \ diff --git a/.github/workflows/deploy-canary.yml b/.github/workflows/deploy-canary.yml index 392329a91a..d40cc1354c 100644 --- a/.github/workflows/deploy-canary.yml +++ b/.github/workflows/deploy-canary.yml @@ -233,7 +233,7 @@ jobs: "sudo -u ec2-user git checkout main || sudo -u ec2-user git checkout -b main origin/main", "sudo -u ec2-user git reset --hard origin/main", "source venv/bin/activate", - "pip install -e . --quiet --no-cache-dir", + "python -m pip install -e . --quiet --no-cache-dir", "python -c \"from aragora.server.unified_server import UnifiedServer; print(\\\"Import OK\\\")\"", "sudo mkdir -p /etc/systemd/system/aragora.service.d/", "echo \"[Service]\" | sudo tee /etc/systemd/system/aragora.service.d/secrets.conf", @@ -512,7 +512,7 @@ jobs: "sudo -u ec2-user git checkout main || sudo -u ec2-user git checkout -b main origin/main", "sudo -u ec2-user git reset --hard origin/main", "source venv/bin/activate", - "pip install -e . --quiet --no-cache-dir", + "python -m pip install -e . --quiet --no-cache-dir", "sudo mkdir -p /etc/systemd/system/aragora.service.d/", "echo \"[Service]\" | sudo tee /etc/systemd/system/aragora.service.d/secrets.conf", "echo \"Environment=ARAGORA_USE_SECRETS_MANAGER=true\" | sudo tee -a /etc/systemd/system/aragora.service.d/secrets.conf", @@ -624,7 +624,7 @@ jobs: "if [ -f /tmp/aragora_canary_state ]; then source /tmp/aragora_canary_state; fi", "if [ -n \"$PREVIOUS_COMMIT\" ]; then sudo -u ec2-user git checkout $PREVIOUS_COMMIT; fi", "source venv/bin/activate", - "pip install -e . --quiet --no-cache-dir", + "python -m pip install -e . --quiet --no-cache-dir", "sudo systemctl restart aragora", "rm -f /tmp/aragora_canary_state", "echo \"Canary rollback complete\"" diff --git a/.github/workflows/deploy-ec2.yml b/.github/workflows/deploy-ec2.yml index 691ff51991..26826aa728 100644 --- a/.github/workflows/deploy-ec2.yml +++ b/.github/workflows/deploy-ec2.yml @@ -146,7 +146,7 @@ jobs: "sudo -u ec2-user git reset --hard origin/main", "sudo chown -R ec2-user:ec2-user /home/ec2-user/aragora/venv || true", "sudo chown -R ec2-user:ec2-user /home/ec2-user/.npm /home/ec2-user/.cache || true", - "sudo -u ec2-user bash -c 'cd /home/ec2-user/aragora && source venv/bin/activate && pip install -e . --quiet --no-cache-dir'", + "sudo -u ec2-user bash -c 'cd /home/ec2-user/aragora && source venv/bin/activate && python -m pip install -e . --quiet --no-cache-dir'", "find /home/ec2-user/aragora/venv/lib/python3.11/site-packages -maxdepth 1 -name \"~*\" -type d -exec rm -rf {} + 2>/dev/null || true", "sudo -u ec2-user bash -c 'cd /home/ec2-user/aragora && source venv/bin/activate && python -c \"from aragora.server.unified_server import UnifiedServer; print(\\\"Import OK\\\")\"'", "sudo systemctl restart aragora", @@ -295,7 +295,7 @@ jobs: "if [ -f /tmp/aragora_deploy_state ]; then source /tmp/aragora_deploy_state; fi", "if [ -n \"$PREVIOUS_COMMIT\" ]; then sudo -u ec2-user git checkout $PREVIOUS_COMMIT; fi", "source venv/bin/activate", - "pip install -e . --quiet --no-cache-dir", + "python -m pip install -e . --quiet --no-cache-dir", "sudo systemctl restart aragora", "rm -f /tmp/aragora_deploy_state", "echo \"Canary rollback complete\"" @@ -361,7 +361,7 @@ jobs: "sudo -u ec2-user git reset --hard origin/main", "sudo chown -R ec2-user:ec2-user /home/ec2-user/aragora/venv || true", "sudo chown -R ec2-user:ec2-user /home/ec2-user/.npm /home/ec2-user/.cache || true", - "sudo -u ec2-user bash -c 'cd /home/ec2-user/aragora && source venv/bin/activate && pip install -e . --quiet --no-cache-dir'", + "sudo -u ec2-user bash -c 'cd /home/ec2-user/aragora && source venv/bin/activate && python -m pip install -e . --quiet --no-cache-dir'", "find /home/ec2-user/aragora/venv/lib/python3.11/site-packages -maxdepth 1 -name \"~*\" -type d -exec rm -rf {} + 2>/dev/null || true", "sudo -u ec2-user bash -c 'cd /home/ec2-user/aragora && source venv/bin/activate && python -c \"from aragora.server.unified_server import UnifiedServer; print(\\\"Import OK\\\")\"'", "sudo systemctl restart aragora", @@ -546,7 +546,7 @@ jobs: "if [ -f /tmp/aragora_deploy_state ]; then source /tmp/aragora_deploy_state; fi", "if [ -n \"$PREVIOUS_COMMIT\" ]; then sudo -u ec2-user git checkout $PREVIOUS_COMMIT; fi", "source venv/bin/activate", - "pip install -e . --quiet --no-cache-dir", + "python -m pip install -e . --quiet --no-cache-dir", "sudo systemctl restart aragora", "rm -f /tmp/aragora_deploy_state", "echo \"Worker rollback complete\"" diff --git a/.github/workflows/deploy-lightsail.yml b/.github/workflows/deploy-lightsail.yml index ae630cd112..591863c3b0 100644 --- a/.github/workflows/deploy-lightsail.yml +++ b/.github/workflows/deploy-lightsail.yml @@ -106,7 +106,7 @@ jobs: # Install source venv/bin/activate 2>/dev/null || source .venv/bin/activate 2>/dev/null || true - pip install -e . --quiet --no-cache-dir 2>/dev/null || true + python -m pip install -e . --quiet --no-cache-dir 2>/dev/null || true # Import check python -c "from aragora.server.unified_server import UnifiedServer; print('Import OK')" diff --git a/.github/workflows/deploy-secure.yml b/.github/workflows/deploy-secure.yml index 21f6ac518b..0e42e09ea1 100644 --- a/.github/workflows/deploy-secure.yml +++ b/.github/workflows/deploy-secure.yml @@ -339,7 +339,7 @@ jobs: "source venv/bin/activate", "echo \"Cleaning corrupted pip distributions...\"", "find venv/lib/python3.11/site-packages -maxdepth 1 -name '~*' -type d -exec rm -rf {} + 2>/dev/null || true", - "pip install -e . --quiet --no-cache-dir", + "python -m pip install -e . --quiet --no-cache-dir", "find venv/lib/python3.11/site-packages -maxdepth 1 -name '~*' -type d -exec rm -rf {} + 2>/dev/null || true", "python -c \"from aragora.server.unified_server import UnifiedServer; print(\\\"Import OK\\\")\"", "echo \"Setting up secrets manager for systemd...\"", @@ -615,7 +615,7 @@ jobs: "if [ -f /tmp/aragora_deploy_state ]; then source /tmp/aragora_deploy_state; fi", "if [ -n \"$PREVIOUS_COMMIT\" ]; then sudo -u ec2-user git checkout $PREVIOUS_COMMIT; fi", "source venv/bin/activate", - "pip install -e . --quiet --no-cache-dir", + "python -m pip install -e . --quiet --no-cache-dir", "sudo systemctl restart aragora", "rm -f /tmp/aragora_deploy_state", "echo \"Rollback complete\"" @@ -772,7 +772,7 @@ jobs: "source venv/bin/activate", "echo \"Cleaning corrupted pip distributions...\"", "find venv/lib/python3.11/site-packages -maxdepth 1 -name '~*' -type d -exec rm -rf {} + 2>/dev/null || true", - "pip install -e . --quiet --no-cache-dir", + "python -m pip install -e . --quiet --no-cache-dir", "find venv/lib/python3.11/site-packages -maxdepth 1 -name '~*' -type d -exec rm -rf {} + 2>/dev/null || true", "python -c \"from aragora.server.unified_server import UnifiedServer; print(\\\"Import OK\\\")\"", "echo \"Setting up secrets manager for systemd...\"", @@ -877,7 +877,7 @@ jobs: "sudo -u ec2-user git reset --hard origin/main", "source venv/bin/activate", "find venv/lib/python3.11/site-packages -maxdepth 1 -name ~* -type d -exec rm -rf {} + 2>/dev/null || true", - "pip install -e . --quiet --no-cache-dir", + "python -m pip install -e . --quiet --no-cache-dir", "find venv/lib/python3.11/site-packages -maxdepth 1 -name ~* -type d -exec rm -rf {} + 2>/dev/null || true", "python -c \"from aragora.server.unified_server import UnifiedServer; print(\\\"Import OK\\\")\"", "echo \"Setting up secrets manager for systemd...\"", @@ -1062,7 +1062,7 @@ jobs: "if [ -f /tmp/aragora_deploy_state ]; then source /tmp/aragora_deploy_state; fi", "if [ -n \"$PREVIOUS_COMMIT\" ]; then sudo -u ec2-user git checkout $PREVIOUS_COMMIT; fi", "source venv/bin/activate", - "pip install -e . --quiet --no-cache-dir", + "python -m pip install -e . --quiet --no-cache-dir", "sudo systemctl restart aragora", "rm -f /tmp/aragora_deploy_state", "echo \"Rollback complete\"" @@ -1175,7 +1175,7 @@ jobs: "source venv/bin/activate", "echo \"Cleaning corrupted pip distributions...\"", "find venv/lib/python3.11/site-packages -maxdepth 1 -name '~*' -type d -exec rm -rf {} + 2>/dev/null || true", - "pip install -e . --quiet --no-cache-dir", + "python -m pip install -e . --quiet --no-cache-dir", "find venv/lib/python3.11/site-packages -maxdepth 1 -name '~*' -type d -exec rm -rf {} + 2>/dev/null || true", "python -c \"from aragora.server.unified_server import UnifiedServer; print(\\\"Import OK\\\")\"", "echo \"Setting up secrets manager for systemd...\"", diff --git a/.github/workflows/docs-build.yml b/.github/workflows/docs-build.yml index c5d283a0f7..14f1c262b1 100644 --- a/.github/workflows/docs-build.yml +++ b/.github/workflows/docs-build.yml @@ -72,7 +72,7 @@ jobs: - name: Install Python dependencies run: | python -m pip install --upgrade pip - pip install -e . + python -m pip install -e . - name: Setup Node.js uses: actions/setup-node@v4 diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index 0f521f4c0d..9133f8db29 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -75,7 +75,7 @@ jobs: - name: Install Python dependencies run: | python -m pip install --upgrade pip - pip install -e ".[dev,test]" + python -m pip install -e ".[dev,test]" - name: Start Aragora backend run: | @@ -243,8 +243,8 @@ jobs: - name: Install Python dependencies run: | python -m pip install --upgrade pip - pip install -e ".[dev]" - pip install pytest pytest-asyncio pytest-timeout aiohttp + python -m pip install -e ".[dev]" + python -m pip install pytest pytest-asyncio pytest-timeout aiohttp - name: Run Python E2E tests run: | diff --git a/.github/workflows/integration-gate.yml b/.github/workflows/integration-gate.yml index 8ae6d21ec8..0ef49c72f1 100644 --- a/.github/workflows/integration-gate.yml +++ b/.github/workflows/integration-gate.yml @@ -61,8 +61,8 @@ jobs: run: | python -m pip install --upgrade pip # Keep smoke gate dependency footprint lean to avoid CI install stalls/timeouts. - pip install -e ".[dev,test]" - pip install pytest-timeout + python -m pip install -e ".[dev,test]" + python -m pip install pytest-timeout # --------------------------------------------------------------- # Smoke test script (backend-focused; frontend has its own gate) @@ -123,7 +123,7 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install -e ".[dev,test]" + python -m pip install -e ".[dev,test]" # --------------------------------------------------------------- # OpenAPI spec drift detection @@ -194,7 +194,7 @@ jobs: python-version: "3.11" - name: Install parity test deps - run: pip install pytest pytest-timeout pydantic pydantic-settings + run: python -m pip install pytest pytest-timeout pydantic pydantic-settings - name: "BLOCKING: SDK contract parity" run: | diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml index ee1f59ee79..46a269a6b4 100644 --- a/.github/workflows/integration.yml +++ b/.github/workflows/integration.yml @@ -60,7 +60,7 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install pyyaml + python -m pip install pyyaml - name: Validate production compose + env example run: | @@ -194,8 +194,8 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install -e ".[dev,test]" - pip install pytest-timeout + python -m pip install -e ".[dev,test]" + python -m pip install pytest-timeout - name: Run E2E harness tests run: | @@ -345,12 +345,12 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install -e ".[dev,test]" - pip install pytest-timeout psycopg2-binary + python -m pip install -e ".[dev,test]" + python -m pip install pytest-timeout psycopg2-binary - name: Run integration tests with coverage run: | - pip install pytest-cov + python -m pip install pytest-cov mkdir -p test-results # Integration tests focus on specific scenarios, not comprehensive coverage # Override the global 45% threshold from pyproject.toml @@ -487,8 +487,8 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install -e ".[dev,test]" - pip install pytest pytest-asyncio pytest-timeout redis + python -m pip install -e ".[dev,test]" + python -m pip install pytest pytest-asyncio pytest-timeout redis - name: Run control plane tests run: | diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 5bb693a721..92f5f6456c 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -162,6 +162,9 @@ jobs: - name: Enforce required-check-priority keep-list policy run: ${{ steps.lint_python.outputs.python_bin }} scripts/check_required_check_priority_policy.py + - name: Enforce workflow pip install policy + run: ${{ steps.lint_python.outputs.python_bin }} scripts/check_workflow_pip_install_policy.py + - name: Enforce execution-gate default hardening policy run: ${{ steps.lint_python.outputs.python_bin }} scripts/check_execution_gate_defaults.py diff --git a/.github/workflows/load-tests.yml b/.github/workflows/load-tests.yml index 39790ca1ba..b0e76f2116 100644 --- a/.github/workflows/load-tests.yml +++ b/.github/workflows/load-tests.yml @@ -91,7 +91,7 @@ jobs: - name: Install Python dependencies run: | python -m pip install --upgrade pip - pip install -e ".[dev,redis,test]" + python -m pip install -e ".[dev,redis,test]" - name: Configure AWS credentials id: aws-creds @@ -459,8 +459,8 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install -e ".[dev,redis]" - pip install memory_profiler psutil + python -m pip install -e ".[dev,redis]" + python -m pip install memory_profiler psutil - name: Start server with memory monitoring run: | diff --git a/.github/workflows/migration-tests.yml b/.github/workflows/migration-tests.yml index 59e7d3caaa..8afbbfa212 100644 --- a/.github/workflows/migration-tests.yml +++ b/.github/workflows/migration-tests.yml @@ -64,7 +64,7 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install -e ".[dev]" + python -m pip install -e ".[dev]" - name: Run migration runner tests run: | diff --git a/.github/workflows/new-features.yml b/.github/workflows/new-features.yml index da9d5d5c0b..007bcc5925 100644 --- a/.github/workflows/new-features.yml +++ b/.github/workflows/new-features.yml @@ -51,7 +51,7 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install -e ".[dev]" + python -m pip install -e ".[dev]" - name: Run migration tests run: | @@ -117,7 +117,7 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install -e ".[dev]" + python -m pip install -e ".[dev]" - name: Test worker imports run: | @@ -175,7 +175,7 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install -e ".[dev]" + python -m pip install -e ".[dev]" - name: Run E2E tests for new features run: | @@ -223,8 +223,8 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install -e ".[dev]" - pip install prometheus-client + python -m pip install -e ".[dev]" + python -m pip install prometheus-client - name: Test metrics initialization run: | diff --git a/.github/workflows/nightly-execution-gate-adversarial.yml b/.github/workflows/nightly-execution-gate-adversarial.yml index cd2911372c..08c9ab4bb2 100644 --- a/.github/workflows/nightly-execution-gate-adversarial.yml +++ b/.github/workflows/nightly-execution-gate-adversarial.yml @@ -28,7 +28,7 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install -e ".[dev]" + python -m pip install -e ".[dev]" - name: Run adversarial regression suite run: | diff --git a/.github/workflows/nightly-integration.yml b/.github/workflows/nightly-integration.yml index f381acd5f8..b45cac075f 100644 --- a/.github/workflows/nightly-integration.yml +++ b/.github/workflows/nightly-integration.yml @@ -49,7 +49,7 @@ jobs: python-version: "3.11" - name: Install - run: pip install -e ".[dev]" + run: python -m pip install -e ".[dev]" - name: Run 1-round debate with real API env: @@ -118,7 +118,7 @@ jobs: python-version: "3.11" - name: Install build tools - run: pip install build twine + run: python -m pip install build twine - name: Build sdist and wheel run: python -m build diff --git a/.github/workflows/nomic-ci.yml b/.github/workflows/nomic-ci.yml index 3e48f87edd..c00821e49a 100644 --- a/.github/workflows/nomic-ci.yml +++ b/.github/workflows/nomic-ci.yml @@ -45,8 +45,8 @@ jobs: python-version: "3.11" - name: Install dependencies run: | - pip install -e ".[dev,test]" - pip install pytest-timeout + python -m pip install -e ".[dev,test]" + python -m pip install pytest-timeout - name: Determine changed files id: changes run: | diff --git a/.github/workflows/onramp-integration.yml b/.github/workflows/onramp-integration.yml index c398be3d6e..86ddb69ffa 100644 --- a/.github/workflows/onramp-integration.yml +++ b/.github/workflows/onramp-integration.yml @@ -38,7 +38,7 @@ jobs: python-version: "3.11" - name: Install and run quickstart run: | - pip install -e . + python -m pip install -e . timeout 300 python examples/quickstart.py env: ARAGORA_OFFLINE: "1" diff --git a/.github/workflows/pr-admission-controller.yml b/.github/workflows/pr-admission-controller.yml index d7e132eacd..3f3279e7ff 100644 --- a/.github/workflows/pr-admission-controller.yml +++ b/.github/workflows/pr-admission-controller.yml @@ -40,11 +40,23 @@ jobs: - name: Checkout uses: actions/checkout@v4 + - name: Prepare writable tool cache + shell: bash + run: | + set -euo pipefail + TOOL_CACHE="${RUNNER_TEMP:-/tmp}/hostedtoolcache" + mkdir -p "${TOOL_CACHE}" + echo "AGENT_TOOLSDIRECTORY=${TOOL_CACHE}" >> "${GITHUB_ENV}" + echo "RUNNER_TOOL_CACHE=${TOOL_CACHE}" >> "${GITHUB_ENV}" + - name: Set up Python id: setup-python uses: actions/setup-python@v5 with: python-version: "3.11" + env: + AGENT_TOOLSDIRECTORY: ${{ env.AGENT_TOOLSDIRECTORY }} + RUNNER_TOOL_CACHE: ${{ env.RUNNER_TOOL_CACHE }} continue-on-error: true - name: Fallback to system Python @@ -61,24 +73,45 @@ jobs: break fi done + + if [[ -z "${PY_BIN}" && -n "${RUNNER_TEMP:-}" ]]; then + DISCOVERED_PY="$(find "${RUNNER_TEMP}" -type f -name "python3.11" -perm -u+x 2>/dev/null | head -n 1 || true)" + if [[ -n "${DISCOVERED_PY}" ]]; then + PY_BIN="${DISCOVERED_PY}" + echo "Found unpacked interpreter in RUNNER_TEMP: ${PY_BIN}" + "${PY_BIN}" --version || true + fi + fi + if [[ -z "${PY_BIN}" ]]; then echo "::error::No Python interpreter found" exit 1 fi - sudo ln -sf "${PY_BIN}" /usr/local/bin/python - sudo ln -sf "${PY_BIN}" /usr/local/bin/python3 - /usr/local/bin/python -m ensurepip --upgrade || true + LOCAL_BIN="${RUNNER_TEMP:-$HOME}/setup-python-safe-bin" + mkdir -p "${LOCAL_BIN}" + cat > "${LOCAL_BIN}/python" </dev/null + cat > "${LOCAL_BIN}/pip" <> "${GITHUB_PATH}" + export PATH="${LOCAL_BIN}:${PATH}" - python --version - pip --version || /usr/local/bin/python -m pip --version + "${LOCAL_BIN}/python" --version + "${LOCAL_BIN}/python" -m pip --version - name: Resolve PR number id: resolve @@ -105,7 +138,7 @@ jobs: fi set +e - python3 scripts/pr_admission_controller.py \ + python scripts/pr_admission_controller.py \ --repo "${GITHUB_REPOSITORY}" \ --pr-number "${{ steps.resolve.outputs.pr_number }}" \ --max-ready-per-stream "${MAX_READY}" \ diff --git a/.github/workflows/pr-debate.yml b/.github/workflows/pr-debate.yml index 20ed718d09..825b36e7c9 100644 --- a/.github/workflows/pr-debate.yml +++ b/.github/workflows/pr-debate.yml @@ -130,8 +130,8 @@ jobs: - name: Install aragora from base branch if: github.event_name == 'workflow_dispatch' run: | - pip install --upgrade pip - pip install -e . + python -m pip install --upgrade pip + python -m pip install -e . - name: Get PR diff if: github.event_name == 'workflow_dispatch' diff --git a/.github/workflows/publish-aragora-debate.yml b/.github/workflows/publish-aragora-debate.yml index f82b249a50..2976c087f1 100644 --- a/.github/workflows/publish-aragora-debate.yml +++ b/.github/workflows/publish-aragora-debate.yml @@ -101,7 +101,7 @@ jobs: python-version: "${{" - name: Install package with dev deps - run: pip install -e ".[dev]" + run: python -m pip install -e ".[dev]" - name: Run tests run: python -m pytest tests/ -v @@ -153,7 +153,7 @@ jobs: python-version: "3.12" - name: Install build tools - run: pip install build + run: python -m pip install build - name: Set version in source files env: @@ -170,7 +170,7 @@ jobs: - name: Verify package run: | - pip install dist/aragora_debate-*.whl + python -m pip install dist/aragora_debate-*.whl python -c "import aragora_debate; print(f'Version: {aragora_debate.__version__}')" python -c "from aragora_debate import Arena, Debate, EvidencePoweredTrickster; print('All imports OK')" python -c "from aragora_debate import ConvergenceDetector, CrossProposalAnalyzer; print('Analysis imports OK')" @@ -192,12 +192,12 @@ jobs: Install: ```bash - pip install aragora-debate==${{ needs.resolve-version.outputs.version }} + python -m pip install aragora-debate==${{ needs.resolve-version.outputs.version }} ``` With all providers: ```bash - pip install "aragora-debate[all]==${{ needs.resolve-version.outputs.version }}" + python -m pip install "aragora-debate[all]==${{ needs.resolve-version.outputs.version }}" ``` [Changelog](https://github.com/an0mium/aragora/blob/main/aragora-debate/CHANGELOG.md) | diff --git a/.github/workflows/publish-aragora.yml b/.github/workflows/publish-aragora.yml index 0fca3f049e..4f7e1f116b 100644 --- a/.github/workflows/publish-aragora.yml +++ b/.github/workflows/publish-aragora.yml @@ -53,7 +53,7 @@ jobs: python-version: "3.11" - name: Install package - run: pip install -e ".[dev]" + run: python -m pip install -e ".[dev]" - name: Run smoke tests run: make test-smoke @@ -95,7 +95,7 @@ jobs: python-version: "3.11" - name: Install build tools - run: pip install build twine + run: python -m pip install build twine - name: Update version run: | @@ -139,7 +139,7 @@ jobs: The Decision Integrity Platform — orchestrate 42+ agent types to adversarially vet decisions. ```bash - pip install aragora==${{ github.event.inputs.version }} + python -m pip install aragora==${{ github.event.inputs.version }} ``` See [documentation](https://docs.aragora.ai) for usage. diff --git a/.github/workflows/publish-sdk-python.yml b/.github/workflows/publish-sdk-python.yml index 87060689c3..f0d3c88a16 100644 --- a/.github/workflows/publish-sdk-python.yml +++ b/.github/workflows/publish-sdk-python.yml @@ -74,7 +74,7 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install -e ".[dev]" + python -m pip install -e ".[dev]" - name: Lint run: python -m ruff check aragora_sdk/ tests/ @@ -127,7 +127,7 @@ jobs: python-version: "3.11" - name: Install build tools - run: pip install build hatchling twine + run: python -m pip install build hatchling twine - name: Determine version id: version @@ -163,7 +163,7 @@ jobs: - name: Check version not already published if: ${{ !(github.event_name == 'workflow_dispatch' && github.event.inputs.dry_run == 'true') }} run: | - pip install aragora-sdk==${{ steps.version.outputs.version }} --dry-run 2>/dev/null && { + python -m pip install aragora-sdk==${{ steps.version.outputs.version }} --dry-run 2>/dev/null && { echo "::error::Version ${{ steps.version.outputs.version }} already exists on PyPI" exit 1 } || echo "Version ${{ steps.version.outputs.version }} not yet published -- OK" @@ -200,7 +200,7 @@ jobs: Install with: ```bash - pip install aragora-sdk==${{ steps.version.outputs.version }} + python -m pip install aragora-sdk==${{ steps.version.outputs.version }} ``` See [documentation](https://docs.aragora.ai/sdk/python) for usage. diff --git a/.github/workflows/quality-smoke.yml b/.github/workflows/quality-smoke.yml index cb070cbfd3..b75efed0ed 100644 --- a/.github/workflows/quality-smoke.yml +++ b/.github/workflows/quality-smoke.yml @@ -100,7 +100,7 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install -e ".[dev]" + python -m pip install -e ".[dev]" - name: Run output quality tests run: | diff --git a/.github/workflows/release-readiness.yml b/.github/workflows/release-readiness.yml index e5960a78e0..0565c32c10 100644 --- a/.github/workflows/release-readiness.yml +++ b/.github/workflows/release-readiness.yml @@ -31,7 +31,7 @@ jobs: release-readiness: if: github.event_name != 'pull_request' || !github.event.pull_request.draft name: Release Readiness - runs-on: aragora + runs-on: ubuntu-latest timeout-minutes: 35 steps: @@ -77,7 +77,7 @@ jobs: - name: Install (dev) run: | python -m pip install --upgrade pip - python -m pip install -e ".[dev]" + python -m pip install -e ".[dev,test]" - name: Run release-readiness gate # Keep this gate deterministic: never rely on optional external diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 296af672d8..cbe1cdb511 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -109,7 +109,7 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install -e . + python -m pip install -e . - name: Regenerate API docs run: | @@ -169,8 +169,8 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install -e ".[dev,research,code-intel,test,monitoring]" - pip install pytest-timeout pytest-xdist + python -m pip install -e ".[dev,research,code-intel,test,monitoring]" + python -m pip install pytest-timeout pytest-xdist - name: Verify required test dependencies run: python scripts/check_test_dependencies.py @@ -228,7 +228,7 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install -e ".[dev,test]" + python -m pip install -e ".[dev,test]" npm --prefix sdk/typescript ci - name: SDK parity strict gate @@ -305,8 +305,8 @@ jobs: - name: Install security tools run: | python -m pip install --upgrade pip - pip install bandit[toml] pip-audit safety - pip install -e . + python -m pip install bandit[toml] pip-audit safety + python -m pip install -e . # Bandit: fail on HIGH severity findings (-lll = high only) - name: Bandit security scan (HIGH severity blocking) @@ -446,7 +446,7 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install -e ".[dev,test]" + python -m pip install -e ".[dev,test]" - name: Skip baseline enforcement run: | @@ -550,8 +550,8 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install -e ".[dev,research,code-intel,test,monitoring]" - pip install pytest-timeout + python -m pip install -e ".[dev,research,code-intel,test,monitoring]" + python -m pip install pytest-timeout - name: Run smoke test harness (--skip-server) run: python scripts/smoke_test.py --skip-server --quick --verbose @@ -633,7 +633,7 @@ jobs: - name: Install build tools run: | python -m pip install --upgrade pip - pip install build twine + python -m pip install build twine - name: Update version in pyproject.toml run: | diff --git a/.github/workflows/sbom.yml b/.github/workflows/sbom.yml index 784533c748..d2161342a2 100644 --- a/.github/workflows/sbom.yml +++ b/.github/workflows/sbom.yml @@ -52,8 +52,8 @@ jobs: - name: Install dependencies run: | - pip install cyclonedx-bom pip-tools - pip install -e . + python -m pip install cyclonedx-bom pip-tools + python -m pip install -e . - name: Generate CycloneDX SBOM run: | diff --git a/.github/workflows/sdk-generate.yml b/.github/workflows/sdk-generate.yml index 7baf4dd672..e49a203571 100644 --- a/.github/workflows/sdk-generate.yml +++ b/.github/workflows/sdk-generate.yml @@ -66,12 +66,12 @@ jobs: - name: Install dependencies run: | - pip install datamodel-code-generator pyyaml + python -m pip install datamodel-code-generator pyyaml - name: Generate OpenAPI spec (if needed) run: | if [ ! -f docs/api/openapi.json ]; then - pip install -e . + python -m pip install -e . python scripts/generate_openapi.py --output docs/api/openapi.json fi diff --git a/.github/workflows/sdk-test.yml b/.github/workflows/sdk-test.yml index 05dc33eb0e..50e530570c 100644 --- a/.github/workflows/sdk-test.yml +++ b/.github/workflows/sdk-test.yml @@ -125,7 +125,7 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - cd sdk/python && pip install -e ".[dev]" + cd sdk/python && python -m pip install -e ".[dev]" - name: Run SDK tests run: | @@ -247,9 +247,9 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install -e . - pip install -e sdk/python/ - pip install pytest pytest-timeout pytest-rerunfailures pytest-asyncio + python -m pip install -e . + python -m pip install -e sdk/python/ + python -m pip install pytest pytest-timeout pytest-rerunfailures pytest-asyncio - name: Run SDK integration tests run: | diff --git a/.github/workflows/security-gate.yml b/.github/workflows/security-gate.yml index 8cd1b559f6..ca37929621 100644 --- a/.github/workflows/security-gate.yml +++ b/.github/workflows/security-gate.yml @@ -33,7 +33,7 @@ jobs: python-security: if: github.event_name != 'pull_request' || !github.event.pull_request.draft name: Python Security Scan - runs-on: aragora + runs-on: ubuntu-latest timeout-minutes: 15 steps: @@ -83,16 +83,16 @@ jobs: - name: "BLOCKING: Bandit security scan (HIGH severity)" run: | echo "--- Full report (informational) ---" - bandit -r aragora/ -c pyproject.toml -f json -o bandit-report.json || true + python -m bandit -r aragora/ -c pyproject.toml -f json -o bandit-report.json || true echo "--- Blocking check: HIGH severity findings ---" - bandit -r aragora/ -c pyproject.toml -lll + python -m bandit -r aragora/ -c pyproject.toml -lll # --------------------------------------------------------------- # pip-audit: check installed Python packages for known CVEs # --------------------------------------------------------------- - name: "BLOCKING: Python dependency audit (pip-audit)" run: | - pip-audit --strict --vulnerability-service osv \ + python -m pip_audit --strict --vulnerability-service osv \ --ignore-vuln CVE-2025-14009 # --------------------------------------------------------------- @@ -124,7 +124,7 @@ jobs: npm-security: if: github.event_name != 'pull_request' || !github.event.pull_request.draft name: npm Security Scan - runs-on: aragora + runs-on: ubuntu-latest timeout-minutes: 10 steps: @@ -217,7 +217,7 @@ jobs: security-summary: name: Security Gate Summary - runs-on: aragora + runs-on: ubuntu-latest needs: [python-security, npm-security] if: (github.event_name != 'pull_request' || !github.event.pull_request.draft) && (always()) timeout-minutes: 2 diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml index 419aef1da1..1c178522b4 100644 --- a/.github/workflows/security.yml +++ b/.github/workflows/security.yml @@ -104,7 +104,7 @@ jobs: python-version: "3.11" - name: Install Bandit - run: pip install bandit[toml] + run: python -m pip install bandit[toml] - name: Run Bandit run: | @@ -158,7 +158,7 @@ jobs: python-version: "3.11" - name: Install dependencies - run: pip install -e ".[dev]" 2>/dev/null || pip install -e . || true + run: python -m pip install -e ".[dev]" 2>/dev/null || python -m pip install -e . || true - name: Run Aragora Security Scanner id: security-scan @@ -210,10 +210,10 @@ jobs: python-version: "3.11" - name: Install security tools - run: pip install safety pip-audit + run: python -m pip install safety pip-audit - name: Install package - run: pip install -e . 2>/dev/null || true + run: python -m pip install -e . 2>/dev/null || true - name: Run Safety check id: safety diff --git a/.github/workflows/smoke-offline.yml b/.github/workflows/smoke-offline.yml index 2bc476917e..13594b7434 100644 --- a/.github/workflows/smoke-offline.yml +++ b/.github/workflows/smoke-offline.yml @@ -21,7 +21,7 @@ jobs: offline-demo: if: github.event_name != 'pull_request' || !github.event.pull_request.draft name: Offline Demo Smoke - runs-on: aragora + runs-on: ubuntu-latest timeout-minutes: 10 steps: @@ -62,7 +62,7 @@ jobs: - name: Run offline golden-path unit tests run: | - pytest tests/cli/test_offline_golden_path.py -v --timeout=60 --tb=short \ + python -m pytest tests/cli/test_offline_golden_path.py -v --timeout=60 --tb=short \ -W error::ResourceWarning \ -W error::pytest.PytestUnraisableExceptionWarning env: @@ -138,7 +138,7 @@ jobs: sudo iptables -A OUTPUT -p tcp -m state --state NEW -j REJECT # Run ask --demo which uses the debate engine with demo agents - aragora ask "Should we use microservices?" --demo --rounds 1 2>&1 | tee /tmp/ask_demo_output.txt + python -m aragora.cli.main ask "Should we use microservices?" --demo --rounds 1 2>&1 | tee /tmp/ask_demo_output.txt ASK_EXIT=$? # Restore network diff --git a/.github/workflows/smoke.yml b/.github/workflows/smoke.yml index 23ea083b71..53e1e01622 100644 --- a/.github/workflows/smoke.yml +++ b/.github/workflows/smoke.yml @@ -21,8 +21,8 @@ jobs: smoke: if: github.event_name != 'pull_request' || !github.event.pull_request.draft name: Smoke Tests - runs-on: aragora - timeout-minutes: 10 + runs-on: ubuntu-latest + timeout-minutes: 15 steps: - name: Checkout @@ -59,6 +59,7 @@ jobs: run: | python -m pip install --upgrade pip python -m pip install -e ".[dev,test]" + python -m pip install reportlab - name: Run smoke tests run: | @@ -82,7 +83,7 @@ jobs: offline-golden-path: if: github.event_name != 'pull_request' || !github.event.pull_request.draft name: Offline Golden Path - runs-on: aragora + runs-on: ubuntu-latest timeout-minutes: 10 steps: @@ -123,7 +124,7 @@ jobs: - name: Verify offline/demo behavior tests run: | - pytest tests/cli/test_offline_golden_path.py -v --timeout=60 --tb=short \ + python -m pytest tests/cli/test_offline_golden_path.py -v --timeout=60 --tb=short \ -W error::ResourceWarning \ -W error::pytest.PytestUnraisableExceptionWarning env: @@ -134,12 +135,12 @@ jobs: ARAGORA_OFFLINE: "1" PYTHONWARNINGS: "error::ResourceWarning" run: | - aragora ask "Offline mode smoke" --demo --rounds 1 + python -m aragora.cli.main ask "Offline mode smoke" --demo --rounds 1 server-smoke: if: github.event_name != 'pull_request' || !github.event.pull_request.draft name: Server Smoke Tests - runs-on: aragora + runs-on: ubuntu-latest timeout-minutes: 10 steps: @@ -180,7 +181,7 @@ jobs: - name: Run server smoke tests run: | - pytest tests/e2e/test_server_smoke.py -v --timeout=120 --tb=short + python -m pytest tests/e2e/test_server_smoke.py -v --timeout=120 --tb=short env: PYTHONPATH: . ARAGORA_CI: "true" @@ -200,7 +201,7 @@ jobs: decision-action-smoke: if: github.event_name != 'pull_request' || !github.event.pull_request.draft name: Decision-to-Action Smoke - runs-on: aragora + runs-on: ubuntu-latest timeout-minutes: 10 steps: @@ -244,7 +245,7 @@ jobs: PYTHONPATH: . DECISION_ACTION_SMOKE_ARTIFACT_DIR: test-results/decision-action-smoke run: | - pytest tests/e2e/test_decision_action_smoke.py -v --tb=short --timeout=120 + python -m pytest tests/e2e/test_decision_action_smoke.py -v --tb=short --timeout=120 - name: Upload decision-to-action smoke artifacts if: always() diff --git a/.github/workflows/status-page.yml b/.github/workflows/status-page.yml index 34b961f2a7..86e7b5e643 100644 --- a/.github/workflows/status-page.yml +++ b/.github/workflows/status-page.yml @@ -328,7 +328,7 @@ jobs: - name: Install dependencies run: | - pip install python-socketio websocket-client + python -m pip install python-socketio websocket-client - name: Provision monitors env: diff --git a/.github/workflows/templates/aragora-gauntlet-template.yml b/.github/workflows/templates/aragora-gauntlet-template.yml index e685c4dccf..2886fd4ceb 100644 --- a/.github/workflows/templates/aragora-gauntlet-template.yml +++ b/.github/workflows/templates/aragora-gauntlet-template.yml @@ -83,7 +83,7 @@ jobs: cache: 'pip' - name: Install Aragora - run: pip install aragora + run: python -m pip install aragora - name: Check API Keys id: check-keys diff --git a/.github/workflows/templates/aragora-review-template.yml b/.github/workflows/templates/aragora-review-template.yml index 7e3668801e..189202b4d5 100644 --- a/.github/workflows/templates/aragora-review-template.yml +++ b/.github/workflows/templates/aragora-review-template.yml @@ -71,7 +71,7 @@ jobs: gh --version | head -1 - name: Install Aragora - run: pip install aragora + run: python -m pip install aragora - name: Check API Keys id: check-keys diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 99dbd007c4..ce7e566520 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -92,7 +92,7 @@ jobs: - name: Install OpenAPI generation dependencies run: | python -m pip install --upgrade pip - pip install -e ".[dev]" + python -m pip install -e ".[dev]" - name: Check version alignment run: python scripts/check_version_alignment.py @@ -115,7 +115,7 @@ jobs: - name: Check Python SDK types are up to date run: | - pip install datamodel-code-generator + python -m pip install datamodel-code-generator python scripts/generate_python_sdk_types.py --openapi docs/api/openapi_generated.json --check - name: Check capability matrix is up to date @@ -215,7 +215,7 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install -e ".[dev]" + python -m pip install -e ".[dev]" - name: Install TypeScript SDK dependencies working-directory: sdk/typescript @@ -270,7 +270,7 @@ jobs: - name: Install baseline test dependencies run: | python -m pip install --upgrade pip - pip install -e ".[dev,research,test]" + python -m pip install -e ".[dev,research,test]" - name: Verify deterministic baseline command run: python scripts/run_test_baseline.py @@ -389,7 +389,7 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install -e . + python -m pip install -e . - name: Run status reconciliation run: | @@ -449,7 +449,7 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install -e ".[dev,test]" + python -m pip install -e ".[dev,test]" - name: Check for new zero-coverage files run: | @@ -551,8 +551,8 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install -e ".[dev,research,test]" - pip install pytest-timeout pytest-xdist + python -m pip install -e ".[dev,research,test]" + python -m pip install pytest-timeout pytest-xdist - name: Run ${{ matrix.category.name }} tests run: | @@ -611,8 +611,8 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install -e ".[dev,research,test]" - pip install pytest-timeout + python -m pip install -e ".[dev,research,test]" + python -m pip install pytest-timeout - name: Run epistemic hygiene + settlement gate run: bash scripts/run_epistemic_settlement_gate.sh @@ -731,8 +731,8 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install -e ".[dev,research,test]" - pip install pytest-timeout + python -m pip install -e ".[dev,research,test]" + python -m pip install pytest-timeout - name: Run integration minimal marker suite run: | @@ -802,8 +802,8 @@ jobs: if: steps.changes.outputs.high_risk == 'true' run: | python -m pip install --upgrade pip - pip install -e ".[dev,research,test]" - pip install pytest-timeout + python -m pip install -e ".[dev,research,test]" + python -m pip install pytest-timeout - name: Run integration smoke tests if: steps.changes.outputs.high_risk == 'true' @@ -868,8 +868,8 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install -e ".[dev,research,test]" - pip install pytest-timeout pytest-xdist pytest-randomly + python -m pip install -e ".[dev,research,test]" + python -m pip install pytest-timeout pytest-xdist pytest-randomly - name: Compute dynamic seed id: dynamic-seed @@ -946,7 +946,7 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install -e ".[dev]" + python -m pip install -e ".[dev]" - name: Run golden-path harness (fast) run: | @@ -995,7 +995,7 @@ jobs: - name: Install aragora-debate with dev deps run: | python -m pip install --upgrade pip - pip install -e "aragora-debate[dev]" + python -m pip install -e "aragora-debate[dev]" - name: Run aragora-debate tests run: | @@ -1101,8 +1101,8 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install -e ".[dev,research,test]" - pip install pytest-cov pytest-timeout pytest-xdist + python -m pip install -e ".[dev,research,test]" + python -m pip install pytest-cov pytest-timeout pytest-xdist - name: Run tests – shard ${{ matrix.shard.name }} (parallel with xdist) run: | @@ -1198,7 +1198,7 @@ jobs: - name: Install coverage tools run: | python -m pip install --upgrade pip - pip install coverage + python -m pip install coverage - name: Download all coverage artifacts uses: actions/download-artifact@v4 @@ -1380,7 +1380,7 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install -e . + python -m pip install -e . - name: Smoke - demo ask run: | @@ -1474,8 +1474,8 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install -e ".[dev,research,test]" - pip install pytest-timeout + python -m pip install -e ".[dev,research,test]" + python -m pip install pytest-timeout - name: Run slow/load/e2e/benchmark tier run: | @@ -1675,7 +1675,7 @@ jobs: cache-dependency-path: pyproject.toml - name: Install bandit - run: pip install bandit[toml] + run: python -m pip install bandit[toml] - name: Run bandit security scan run: | @@ -1732,8 +1732,8 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install -e ".[dev]" - pip install mypy types-requests types-aiofiles + python -m pip install -e ".[dev]" + python -m pip install mypy types-requests types-aiofiles - name: Run mypy run: | @@ -1801,8 +1801,8 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install -e ".[dev]" - pip install alembic psycopg2-binary asyncpg + python -m pip install -e ".[dev]" + python -m pip install alembic psycopg2-binary asyncpg - name: Verify migration files run: | @@ -1915,8 +1915,8 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install -e ".[dev,test,research]" - pip install mcp || true + python -m pip install -e ".[dev,test,research]" + python -m pip install mcp || true - name: Run optional-deps test suite run: | @@ -1984,7 +1984,7 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install -e ".[dev]" + python -m pip install -e ".[dev]" - name: RBAC coverage audit run: python scripts/audit_rbac_coverage.py @@ -2035,8 +2035,8 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install -e ".[dev]" - pip install pytest-rerunfailures + python -m pip install -e ".[dev]" + python -m pip install pytest-rerunfailures - name: Run tests with JUnit output id: tests diff --git a/.github/workflows/testfixer-auto.yml b/.github/workflows/testfixer-auto.yml index 5cd4c73a3b..2f3f2f4a86 100644 --- a/.github/workflows/testfixer-auto.yml +++ b/.github/workflows/testfixer-auto.yml @@ -79,7 +79,7 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install -e ".[dev,test]" + python -m pip install -e ".[dev,test]" - name: Guard secrets id: guard diff --git a/docs/plans/dogfood_benchmark_2026-03-06_pipeline_hardening.json b/docs/plans/dogfood_benchmark_2026-03-06_pipeline_hardening.json new file mode 100644 index 0000000000..2d3f11abd1 --- /dev/null +++ b/docs/plans/dogfood_benchmark_2026-03-06_pipeline_hardening.json @@ -0,0 +1,113 @@ +{ + "generated_at": "2026-03-06T03:56:28.266568+00:00", + "base_report": "docs/plans/dogfood_pipeline_self_improve_base_report.json", + "command": [ + "python3", + "-m", + "aragora.cli.main", + "pipeline", + "self-improve", + "Please describe the relationship between the completed dogfood stress test, the ideas-to-execution pipeline, the self-improvement pipeline, the heterogeneous agent codebase assessment/coding-change pipeline, and the self bug-fixing pipeline. Can all of these be more tightly integrated? This is intentionally vague and poorly specified; treat it as a dogfooding prompt and produce an execution-ready integration plan.", + "--dry-run", + "--pipeline-mode", + "live", + "--plan-quality-min-score", + "6.0", + "--plan-quality-min-practicality", + "5.0", + "--max-goals", + "1" + ], + "strict_timeout_seconds": 180, + "runs": [ + { + "duration_seconds": 210.02, + "exit_code": 124, + "timed_out": true, + "quality": { + "present": false, + "verdict": null, + "score": null, + "practicality": null, + "loops": null, + "upgraded": null + }, + "pipeline_checks": { + "present": false, + "execution_path": null, + "live_stages_completed": null, + "provider_calls_detected": null, + "quality_gate_verdict": null, + "top_track": null, + "track_lines": [], + "checks": { + "execution_path_live": null, + "quality_gate_pass": null, + "top_track_is_infra_or_security": null, + "no_cross_track_clones": null + }, + "required_checks_present": false, + "hard_checks_pass": false + }, + "runtime_blockers": [ + "debate_timeout", + "generic_timeout" + ], + "warning_signals": [ + "resource_warning", + "tracemalloc_hint" + ], + "warning_only": false, + "stdout_excerpt": "", + "stderr_excerpt": "/Users/armand/Development/aragora/.worktrees/codex-auto/codex-20260306-032004-0dc2a00b/aragora/nomic/learning_bus.py:290: RuntimeWarning: coroutine 'LearningBus._load_historical_findings_async' was never awaited\n logger.debug(\"Could not load historical findings from KM\")\nRuntimeWarning: Enable tracemalloc to get the object allocation traceback\n/Users/armand/.pyenv/versions/3.11.11/lib/python3.11/site-packages/rlm/core/lm_handler.py:177: ResourceWarning: unclosed \n self._server = None\nResourceWarning: Enable tracemalloc to get the object allocation traceback\n\nDebate timed out after 180s" + } + ], + "summary": { + "total_runs": 1, + "non_timeout_runs": 0, + "successful_runs": 0, + "quality_present_runs": 0, + "passed_quality_and_practicality_runs": 0, + "pass_rate": 0.0, + "duration_seconds": { + "mean": 210.02, + "median": 210.02, + "min": 210.02, + "max": 210.02 + }, + "quality_score_10": { + "mean": null, + "median": null, + "min": null, + "max": null + }, + "practicality_score_10": { + "mean": null, + "median": null, + "min": null, + "max": null + }, + "loops_used": { + "mean": null, + "median": null, + "min": null, + "max": null + }, + "pipeline_hard_checks": { + "present_runs": 0, + "required_checks_present_runs": 0, + "hard_check_pass_runs": 0, + "hard_check_pass_rate": null, + "check_pass_rates": { + "execution_path_live": null, + "quality_gate_pass": null, + "top_track_is_infra_or_security": null, + "no_cross_track_clones": null + } + }, + "runtime_blockers": { + "debate_timeout": 1, + "generic_timeout": 1 + } + } +} \ No newline at end of file diff --git a/scripts/check_workflow_pip_install_policy.py b/scripts/check_workflow_pip_install_policy.py new file mode 100644 index 0000000000..82c06eba38 --- /dev/null +++ b/scripts/check_workflow_pip_install_policy.py @@ -0,0 +1,135 @@ +#!/usr/bin/env python3 +"""Enforce `python -m pip install` usage in GitHub workflows.""" + +from __future__ import annotations + +import argparse +from dataclasses import dataclass +from pathlib import Path +import re + + +@dataclass(frozen=True) +class Violation: + path: str + line: int + column: int + message: str + + +WORKFLOW_ROOT = Path(".github/workflows") +WORKFLOW_GLOBS = ("*.yml", "*.yaml") +BARE_PIP_INSTALL_PATTERN = re.compile(r"(? list[tuple[int, int, str]]: + """Return violations as (line, column, message) tuples.""" + violations: list[tuple[int, int, str]] = [] + run_line_re = re.compile(r"^\s*(?:-\s*)?run:\s*(.*)$") + in_run_block = False + run_block_indent = 0 + + for line_number, line in enumerate(workflow_text.splitlines(), start=1): + stripped = line.strip() + indent = len(line) - len(line.lstrip(" ")) + + if in_run_block: + if stripped and indent <= run_block_indent: + in_run_block = False + else: + if not stripped or stripped.startswith("#"): + continue + match = BARE_PIP_INSTALL_PATTERN.search(line) + if match is not None: + violations.append( + ( + line_number, + match.start() + 1, + "use `python -m pip install` instead of bare `pip install`", + ) + ) + continue + + run_match = run_line_re.match(line) + if run_match is None: + continue + + run_value = run_match.group(1).strip() + if run_value.startswith("|") or run_value.startswith(">"): + in_run_block = True + run_block_indent = line.find("run:") + continue + + if not run_value or run_value.startswith("#"): + continue + + match = BARE_PIP_INSTALL_PATTERN.search(run_value) + if match is not None: + value_start = line.find(run_value) + violations.append( + ( + line_number, + value_start + match.start() + 1, + "use `python -m pip install` instead of bare `pip install`", + ) + ) + return violations + + +def _iter_workflow_files(repo_root: Path) -> list[Path]: + files: list[Path] = [] + workflow_dir = repo_root / WORKFLOW_ROOT + if not workflow_dir.exists(): + return files + for pattern in WORKFLOW_GLOBS: + files.extend(sorted(workflow_dir.rglob(pattern))) + return sorted(set(files)) + + +def check_repo(repo_root: Path) -> list[Violation]: + violations: list[Violation] = [] + workflow_files = _iter_workflow_files(repo_root) + + if not workflow_files: + return [ + Violation( + path=str(WORKFLOW_ROOT), + line=1, + column=1, + message="workflow directory not found or empty", + ) + ] + + for workflow_file in workflow_files: + text = workflow_file.read_text(encoding="utf-8") + rel = workflow_file.relative_to(repo_root) + for line, column, message in find_bare_pip_install_violations(text): + violations.append(Violation(path=str(rel), line=line, column=column, message=message)) + + return violations + + +def main() -> int: + parser = argparse.ArgumentParser( + description="Enforce python -m pip install usage in workflow run commands." + ) + parser.add_argument( + "--repo-root", + default=str(Path(__file__).resolve().parents[1]), + help="Repository root to check", + ) + args = parser.parse_args() + + violations = check_repo(Path(args.repo_root).resolve()) + if not violations: + print("Workflow pip policy check passed") + return 0 + + print("Workflow pip policy violations detected:") + for v in violations: + print(f"- {v.path}:{v.line}:{v.column}: {v.message}") + return 1 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/scripts/ci_release_readiness.sh b/scripts/ci_release_readiness.sh index ddfc1960f1..cc4bf263f4 100755 --- a/scripts/ci_release_readiness.sh +++ b/scripts/ci_release_readiness.sh @@ -21,14 +21,14 @@ python3 scripts/check_execution_gate_policy_control.py python3 scripts/check_prometheus_rules.py echo "[release-readiness] debate/workflow" -pytest -q \ +python3 -m pytest -q \ tests/debate/test_orchestrator_comprehensive.py \ tests/debate/test_orchestrator_execution.py \ tests/debate/test_orchestrator_init.py \ tests/workflow/nodes/test_debate.py echo "[release-readiness] handlers/openclaw" -pytest -q \ +python3 -m pytest -q \ tests/test_handlers_system.py \ tests/test_handlers_integration.py \ tests/server/handlers/bots/test_google_chat_handler.py \ @@ -37,13 +37,13 @@ pytest -q \ tests/server/handlers/test_openclaw_persistent_store.py echo "[release-readiness] observability/logging" -pytest -q \ +python3 -m pytest -q \ tests/observability/test_otel.py \ tests/server/startup/test_observability.py \ tests/test_logging_config.py echo "[release-readiness] sdk parity/contracts" -PYTHONPATH=. pytest -q \ +PYTHONPATH=. python3 -m pytest -q \ tests/sdk/test_sdk_parity.py \ tests/sdk/test_contract_parity.py \ tests/server/openapi/test_sdk_namespace_contracts.py \ diff --git a/scripts/test_tiers.sh b/scripts/test_tiers.sh index cb73b0f5a7..524ddd46fd 100755 --- a/scripts/test_tiers.sh +++ b/scripts/test_tiers.sh @@ -23,6 +23,7 @@ set -euo pipefail tier="${1:-fast}" +PYTEST_BIN="${PYTEST_BIN:-python -m pytest}" # Color output RED='\033[0;31m' @@ -34,7 +35,7 @@ echo -e "${GREEN}Running test tier: ${tier}${NC}" case "$tier" in smoke) - pytest -m smoke \ + ${PYTEST_BIN} -m smoke \ --timeout=60 \ -v \ --tb=short \ @@ -44,7 +45,7 @@ case "$tier" in fast) # Quick tests for local dev - exclude slow, load, e2e, integration - pytest tests/ -m "not slow and not load and not e2e and not integration and not integration_minimal and not benchmark and not performance" \ + ${PYTEST_BIN} tests/ -m "not slow and not load and not e2e and not integration and not integration_minimal and not benchmark and not performance" \ --timeout=30 \ -q \ --tb=line \ @@ -57,7 +58,7 @@ case "$tier" in unit) # Unit tests with extended timeout - ideal for quick feedback - pytest tests/ -m "not slow and not load and not e2e and not integration and not integration_minimal and not benchmark and not performance" \ + ${PYTEST_BIN} tests/ -m "not slow and not load and not e2e and not integration and not integration_minimal and not benchmark and not performance" \ --timeout=120 \ -v \ --tb=short \ @@ -72,7 +73,7 @@ case "$tier" in # CI tier - balanced coverage vs speed # Skip slow/e2e/load/benchmark/integration tests # Coverage threshold: 50% (raised from 30%) - pytest tests/ \ + ${PYTEST_BIN} tests/ \ -m "not slow and not load and not e2e and not benchmark and not integration and not integration_minimal" \ --timeout=120 \ --cov=aragora \ @@ -87,7 +88,7 @@ case "$tier" in full) # Full test suite with extended timeouts - pytest tests/ \ + ${PYTEST_BIN} tests/ \ --timeout=300 \ --cov=aragora \ --cov-report=term-missing \ @@ -98,7 +99,7 @@ case "$tier" in slow) # Only slow-marked tests - pytest tests/ -m "slow" \ + ${PYTEST_BIN} tests/ -m "slow" \ --timeout=600 \ -v \ --tb=short @@ -106,7 +107,7 @@ case "$tier" in integration) # Integration tests (services required) - pytest tests/integration/ -m "integration or integration_minimal" \ + ${PYTEST_BIN} tests/integration/ -m "integration or integration_minimal" \ --timeout=180 \ -v \ --tb=short @@ -114,7 +115,7 @@ case "$tier" in nightly) # Nightly tier: slow/load/e2e/benchmark - pytest tests/ -m "slow or load or e2e or benchmark" \ + ${PYTEST_BIN} tests/ -m "slow or load or e2e or benchmark" \ --timeout=600 \ -v \ --tb=short @@ -122,7 +123,7 @@ case "$tier" in benchmark) # Benchmark-only tests - pytest tests/ -m "benchmark" \ + ${PYTEST_BIN} tests/ -m "benchmark" \ --benchmark-only \ --benchmark-sort=mean \ --benchmark-warmup=on \ @@ -131,7 +132,7 @@ case "$tier" in handlers) # Handler tests only - quick feedback on API changes - pytest tests/server/handlers/ \ + ${PYTEST_BIN} tests/server/handlers/ \ --timeout=120 \ -v \ --tb=short @@ -139,7 +140,7 @@ case "$tier" in security) # Security-related tests - pytest tests/security/ tests/server/handlers/test_admin.py tests/server/handlers/test_privacy.py tests/server/middleware/ \ + ${PYTEST_BIN} tests/security/ tests/server/handlers/test_admin.py tests/server/handlers/test_privacy.py tests/server/middleware/ \ --timeout=120 \ -v \ --tb=short @@ -147,7 +148,7 @@ case "$tier" in storage) # Storage/database tests - pytest tests/storage/ tests/ranking/ tests/memory/ \ + ${PYTEST_BIN} tests/storage/ tests/ranking/ tests/memory/ \ --timeout=120 \ -v \ --tb=short @@ -155,7 +156,7 @@ case "$tier" in privacy) # Privacy handler tests only - pytest tests/server/handlers/test_privacy.py \ + ${PYTEST_BIN} tests/server/handlers/test_privacy.py \ --timeout=60 \ -v \ --tb=short diff --git a/tests/nomic/test_meta_planner.py b/tests/nomic/test_meta_planner.py index bb7fcb6b88..408d7f3c2e 100644 --- a/tests/nomic/test_meta_planner.py +++ b/tests/nomic/test_meta_planner.py @@ -251,6 +251,15 @@ def test_infer_core_track(self): ) assert track == Track.CORE + def test_infer_infrastructure_integration_prompt_not_sme(self): + """Infrastructure integration objectives should not be mapped to SME.""" + planner = MetaPlanner() + track = planner._infer_track( + "Tightly integrate pipeline self-improve, testfixer feedback loops, and quality gates", + [Track.SME, Track.CORE, Track.SELF_HOSTED, Track.SECURITY, Track.QA], + ) + assert track in {Track.CORE, Track.SELF_HOSTED, Track.SECURITY} + def test_infer_defaults_to_first(self): """Should default to first available track.""" planner = MetaPlanner() @@ -310,14 +319,16 @@ def test_generates_goals_for_all_tracks(self): def test_generic_objective_not_broadcast_to_all_tracks(self): """Fallback heuristic should pick one best track, not clone to all tracks.""" planner = MetaPlanner() + objective = "Create a shared WorkItem protocol and UnifiedCycleOrchestrator" goals = planner._heuristic_prioritize( - "Create a shared WorkItem protocol and UnifiedCycleOrchestrator", + objective, [Track.SME, Track.QA, Track.CORE, Track.SELF_HOSTED, Track.SECURITY], ) assert len(goals) == 1 assert goals[0].track in {Track.CORE, Track.SELF_HOSTED, Track.SECURITY} assert goals[0].track != Track.SME + assert planner._goal_fidelity_score(objective, goals[0].description) >= 0.2 @pytest.mark.asyncio async def test_prioritize_work_recovers_when_objective_fidelity_is_low(self): diff --git a/tests/scripts/test_check_workflow_pip_install_policy.py b/tests/scripts/test_check_workflow_pip_install_policy.py new file mode 100644 index 0000000000..3dbfae52e3 --- /dev/null +++ b/tests/scripts/test_check_workflow_pip_install_policy.py @@ -0,0 +1,62 @@ +from __future__ import annotations + +from pathlib import Path + +from scripts.check_workflow_pip_install_policy import ( + check_repo, + find_bare_pip_install_violations, +) + + +def test_detects_bare_pip_install() -> None: + text = """ +jobs: + build: + steps: + - run: pip install -e . +""" + violations = find_bare_pip_install_violations(text) + assert violations + assert violations[0][0] == 5 + assert "python -m pip install" in violations[0][2] + + +def test_allows_python_module_pip_install() -> None: + text = """ +jobs: + build: + steps: + - run: python -m pip install -e . +""" + violations = find_bare_pip_install_violations(text) + assert violations == [] + + +def test_detects_fallback_bare_pip_install() -> None: + text = """ +jobs: + build: + steps: + - run: python -m pip install -e . || pip install -e . || true +""" + violations = find_bare_pip_install_violations(text) + assert violations + assert len(violations) == 1 + + +def test_ignores_step_name_text() -> None: + text = """ +jobs: + lint: + steps: + - name: Enforce workflow pip install policy + run: python -m pip install -e . +""" + violations = find_bare_pip_install_violations(text) + assert violations == [] + + +def test_repo_policy_passes_for_current_tree() -> None: + repo_root = Path(__file__).resolve().parents[2] + violations = check_repo(repo_root) + assert violations == []