name: hermes-ci on: push: branches: [main, master] pull_request: workflow_dispatch: permissions: contents: read concurrency: group: hermes-ci-${{ github.ref }} cancel-in-progress: true env: PYTHONPATH: hermes_overlay TRADING_MODE: paper HERMES_EXECUTION_ENABLED: "false" HERMES_NONPAPER_EXECUTION_ENABLED: "false" jobs: quality-and-tests: runs-on: ubuntu-latest timeout-minutes: 25 steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 with: python-version: "3.13.5" cache: pip cache-dependency-path: | requirements.lock requirements-ci.lock - name: Install locked dependencies run: | python -m pip install --upgrade pip python -m pip install -r requirements.lock -r requirements-ci.lock python -m pip check - name: Verify deterministic metadata and inventory run: | npm ci --ignore-scripts --no-audit --no-fund npm run check:js python scripts/generate_dependency_inventory.py --check python scripts/verify_repository_metadata.py - name: Compile Python run: python -m compileall hermes_overlay scripts app.py -q - name: Lint Python run: python -m ruff check hermes_overlay scripts app.py - name: Type-check execution-critical Python run: | python -m mypy \ hermes_overlay/trading/config_validation.py \ hermes_overlay/trading/domain/execution_service.py \ hermes_overlay/trading/domain/plan_revalidation.py \ hermes_overlay/trading/provider_contracts.py \ scripts/validate_runbook_consistency.py - name: Check shell and JavaScript syntax run: | bash -n scripts/entrypoint.sh node --check scripts/dns-fix.cjs find hermes_overlay -type f -name '*.js' -print0 | xargs -0 -r -n1 node --check - name: Run complete test suite with branch coverage run: | python -m pytest hermes_overlay/tests -q \ --cov=hermes_overlay \ --cov=scripts \ --cov-branch \ --cov-report=term-missing \ --cov-report=json:coverage.json \ --cov-report=xml:coverage.xml - name: Enforce critical-module branch coverage run: python scripts/check_critical_coverage.py coverage.json - name: Prove failing tests block CI run: python scripts/verify_ci_failure_contract.py - name: Upload coverage artifact uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: coverage path: coverage.xml if-no-files-found: error security-and-data-gates: runs-on: ubuntu-latest timeout-minutes: 15 steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 with: python-version: "3.13.5" cache: pip cache-dependency-path: | requirements.lock requirements-ci.lock - name: Install locked dependencies run: python -m pip install -r requirements.lock -r requirements-ci.lock - name: Secret scan run: python scripts/ci_secret_scan.py - name: Python dependency vulnerability scan run: python -m pip_audit -r requirements.lock --no-deps --disable-pip --strict - name: Dependency license inventory run: >- python scripts/check_dependency_licenses.py --declared-from requirements.lock requirements-ci.lock --output dependency-licenses.json - name: Migration verification run: python scripts/check_migrations.py - name: Required negative/failure gates run: python scripts/verify_required_failures.py - name: Strict runbook consistency run: python scripts/validate_runbook_consistency.py - name: Upload dependency evidence uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: dependency-evidence path: | docs/dependency_inventory.json dependency-licenses.json if-no-files-found: error container-build: runs-on: ubuntu-latest timeout-minutes: 75 needs: [quality-and-tests, security-and-data-gates] steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Verify immutable Docker inputs run: python -m pytest hermes_overlay/tests/test_build_reproducibility.py hermes_overlay/tests/test_upstream_integration_preflight.py -q - name: Build exact-pinned container run: | docker build \ --pull \ --build-arg HERMES_UPSTREAM_REF=8fc278207b0f5b25e567966f9615e1b1737f62af \ --tag hermesface:${{ github.sha }} \ . - name: Inspect pinned upstream marker run: | test "$(docker run --rm --entrypoint cat hermesface:${{ github.sha }} /opt/hermes/HERMES_UPSTREAM_COMMIT)" = \ "8fc278207b0f5b25e567966f9615e1b1737f62af" - name: Container vulnerability scan run: | docker run --rm \ -v /var/run/docker.sock:/var/run/docker.sock \ aquasec/trivy:0.72.0 image \ --exit-code 1 --ignore-unfixed --severity HIGH,CRITICAL \ hermesface:${{ github.sha }}