name: ci on: pull_request: push: branches: - main workflow_dispatch: permissions: contents: read concurrency: group: ci-${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true env: PYTHON_VERSION: "3.11" CI: "1" LEOCLEAN_RUNTIME_POSTGRES_IMAGE: "postgres@sha256:eb4759788a2182f08257135e61a34f2cfc3c2914079f3465d64ee62350f4d081" jobs: lint: name: Focused lint runs-on: ubuntu-latest timeout-minutes: 10 steps: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 with: python-version: ${{ env.PYTHON_VERSION }} - name: Install run: | python -m pip install --upgrade pip python -m pip install -e ".[dev]" - name: Ruff focused surface run: | python -m ruff check \ lib/agent_routing.py \ lib/config.py \ lib/db.py \ lib/evaluate.py \ lib/llm.py \ lib/post_extract.py \ docker/leoclean-nosend/entrypoint.py \ ops/apply_gcp_iam_split.py \ ops/attest_gcp_reasoning_compute.py \ ops/capture_vps_canonical_postgres_snapshot.py \ ops/check_gcp_leoclean_nosend_preflight.py \ ops/check_gcp_infra_readiness.py \ ops/run_gcp_infra_execute_canary.py \ ops/apply_gcp_runtime_baseline.py \ ops/check_gcp_service_communications.py \ ops/derive_leoclean_runtime_query_contract.py \ ops/gcp_leoclean_nosend_package.py \ ops/plan_gcp_iam_split.py \ ops/private_receipt_io.py \ ops/run_local_canonical_postgres_rebuild.py \ ops/redact_sqlite_postgres_restore_canary.py \ ops/restore_gcp_generated_postgres_snapshot.py \ ops/sqlite_to_postgres_dump.py \ ops/verify_gcp_cloudsql_restore_readback.py \ ops/verify_gcp_leoclean_runtime_permissions.py \ ops/verify_gcp_leoclean_service_environment.py \ ops/verify_gcp_canonical_lifecycle.py \ ops/verify_postgres_parity_manifest.py \ ops/verify_vps_canonical_snapshot_delta.py \ telegram/approvals.py \ hermes-agent/patches/enforce_leoclean_learning_policy.py \ hermes-agent/leoclean-bin/kb_tool.py \ hermes-agent/leoclean-bin/cloudsql_memory_tool.py \ hermes-agent/runtime/leoclean-nosend/bootstrap.py \ hermes-agent/runtime/leoclean-nosend/profile-sources/cloudsql_memory_runtime.py \ hermes-agent/runtime/leoclean-nosend/profile-sources/leo_db_context.py \ hermes-agent/runtime/leoclean-nosend/profile-sources/operational_contracts.py \ scripts/check_crabbox_ci_contract.py \ scripts/check_llm_refinement_contract.py \ scripts/build_working_leo_m3taversal_outcome_sandbox.py \ scripts/leo_behavior_manifest.py \ scripts/leo_identity_manifest.py \ scripts/leo_tool_trace.py \ scripts/compile_leoclean_nosend_runtime.py \ scripts/replay_decision_engine_eval.py \ scripts/prove_phase1b_local.py \ scripts/run_gcp_generated_db_direct_claim_suite.py \ scripts/run_gcp_generated_db_working_leo_suite.py \ scripts/run_gcp_generated_db_blind_claim_canary.py \ scripts/run_leo_direct_claim_handler_suite.py \ scripts/run_leo_m3taversal_oos_handler_suite.py \ scripts/verify_leo_db_first_oos_canary.py \ scripts/run_leo_clone_bound_handler_checkpoint.py \ scripts/run_gcp_leoclean_nosend_oci_smoke.py \ scripts/working_leo_m3taversal_oos_benchmark.py \ scripts/working_leo_open_ended_benchmark.py \ scripts/verify_leoclean_nosend_runtime.py \ tests/test_agent_routing.py \ tests/test_attest_gcp_reasoning_compute.py \ tests/test_assemble_telegram_visible_direct_claim_capture_receipt.py \ tests/test_build_working_leo_m3taversal_outcome_sandbox.py \ tests/test_decision_engine_replay.py \ tests/test_evaluate_agent_routing.py \ tests/test_gcp_artifact_workflow.py \ tests/test_capture_vps_canonical_postgres_snapshot.py \ tests/test_gcp_infra_execute_canary.py \ tests/test_gcp_infra_readiness_checker.py \ tests/test_gcp_leoclean_nosend_preflight.py \ tests/test_gcp_leoclean_runtime_permissions.py \ tests/test_gcp_leoclean_nosend_package.py \ tests/test_gcp_leoclean_nosend_oci_smoke.py \ tests/test_gcp_leoclean_service_environment.py \ tests/test_gcp_runtime_baseline_apply.py \ tests/test_gcp_service_communications.py \ tests/test_gcp_cloudsql_restore_drill.py \ tests/test_gcp_cloudsql_restore_readback.py \ tests/test_gcp_iam_split_apply.py \ tests/test_gcp_iam_split_plan.py \ tests/test_gcp_readiness_workflow.py \ tests/test_gcp_generated_db_direct_claim_suite.py \ tests/test_gcp_generated_db_working_leo_suite.py \ tests/test_gcp_generated_db_blind_claim_canary.py \ tests/test_hermes_leoclean_kb_bridge_source.py \ tests/test_hermes_leoclean_db_context_plugin.py \ tests/test_hermes_leoclean_skill_surfaces.py \ tests/test_leoclean_nosend_runtime.py \ tests/test_leo_behavior_manifest.py \ tests/test_leo_tool_trace.py \ tests/test_verify_leo_db_first_oos_canary.py \ tests/test_compile_kb_source_packet.py \ tests/test_verify_postgres_parity_manifest.py \ tests/test_verify_gcp_canonical_lifecycle.py \ tests/test_verify_vps_canonical_snapshot_delta.py \ tests/test_working_leo_m3taversal_oos_benchmark.py \ tests/test_working_leo_open_ended_benchmark.py \ tests/test_phase1b_end_to_end.py \ tests/test_private_receipt_io.py \ tests/test_restore_gcp_generated_postgres_snapshot.py \ tests/test_run_local_canonical_postgres_rebuild.py \ tests/test_run_local_genesis_ledger_rebuild.py \ tests/test_sqlite_to_postgres_dump.py \ tests/test_sqlite_postgres_restore_canary_capsule.py \ tests/test_teleo_agent_systemd.py \ tests/test_eval_parse.py \ tests/test_contributor.py \ tests/test_search.py - name: Shell syntax run: | bash -n \ deploy/sync-gcp-leoclean-runtime.sh \ hermes-agent/leoclean-bin/teleo-kb \ hermes-agent/leoclean-bin/teleo-kb-gcp \ ops/backup_vps_sqlite_kb.sh \ ops/provision_gcp_leoclean_runtime_role.sh \ ops/run_gcp_cloudsql_restore_drill.sh \ ops/run_sqlite_postgres_restore_canary.sh \ scripts/run_leoclean_nosend_runtime_canary.sh test: name: Unit tests runs-on: ubuntu-latest timeout-minutes: 20 steps: - uses: actions/checkout@v4 with: fetch-depth: 0 - uses: actions/setup-python@v5 with: python-version: ${{ env.PYTHON_VERSION }} - name: Install run: | python -m pip install --upgrade pip python -m pip install -e ".[dev]" - name: Pull digest-pinned PostgreSQL permission canary image run: docker pull "${LEOCLEAN_RUNTIME_POSTGRES_IMAGE}" - name: Pytest env: TELEO_RUN_LEOCLEAN_RUNTIME_POSTGRES_CANARY: "1" run: | mkdir -p .crabbox-results python -m pytest --junitxml=.crabbox-results/pytest.xml - name: Upload test artifact if: always() uses: actions/upload-artifact@v4 with: name: teleo-infrastructure-pytest path: .crabbox-results/pytest.xml if-no-files-found: warn - name: Remove interrupted PostgreSQL permission canaries if: always() run: | mapfile -t containers < <(docker ps -aq --filter "label=livingip.r2.permission-canary") if ((${#containers[@]})); then docker rm --force "${containers[@]}" fi test -z "$(docker ps -aq --filter 'label=livingip.r2.permission-canary')" repo-contracts: name: Repo contracts runs-on: ubuntu-latest timeout-minutes: 10 steps: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 with: python-version: ${{ env.PYTHON_VERSION }} - name: Install run: | python -m pip install --upgrade pip python -m pip install -e ".[dev]" - name: Validate repo-owned contract run: | python scripts/check_crabbox_ci_contract.py \ --output .crabbox-results/crabbox-ci-contract.json python scripts/check_llm_refinement_contract.py \ --output .crabbox-results/llm-refinement-contract.json python scripts/replay_decision_engine_eval.py \ --output .crabbox-results/decision-engine-eval.json - name: Upload contract artifacts if: always() uses: actions/upload-artifact@v4 with: name: teleo-infrastructure-repo-contracts path: | .crabbox-results/crabbox-ci-contract.json .crabbox-results/llm-refinement-contract.json .crabbox-results/decision-engine-eval.json if-no-files-found: error leoclean-nosend-runtime: name: Leoclean no-send runtime runs-on: ubuntu-latest timeout-minutes: 45 steps: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 with: python-version: "3.11.9" - name: Install exact uv toolchain run: python -m pip install 'uv==0.9.30' 'PyYAML==6.0.3' - name: Pull digest-pinned OCI bases run: | docker pull --platform=linux/amd64 "ghcr.io/astral-sh/uv:0.9.30@sha256:538e0b39736e7feae937a65983e49d2ab75e1559d35041f9878b7b7e51de91e4" docker pull --platform=linux/amd64 "docker.io/library/python:3.11.9-slim-bookworm@sha256:8fb099199b9f2d70342674bd9dbccd3ed03a258f26bbd1d556822c6dfc60c317" docker pull --platform=linux/amd64 "docker.io/library/postgres:16.14-bookworm@sha256:92620daddcd947f8d5ab5ba66e848702fe443d87fed30c4cea8e389fd78dfc55" - name: Compile and exercise release artifact env: LEOCLEAN_NOSEND_ARTIFACT_OUTPUT: ${{ runner.temp }}/leoclean-nosend-artifact run: scripts/run_leoclean_nosend_runtime_canary.sh - name: Build and exercise one disposable OCI image run: | python scripts/run_gcp_leoclean_nosend_oci_smoke.py \ --artifact "${RUNNER_TEMP}/leoclean-nosend-artifact" \ --runtime-receipt .crabbox-results/leoclean-nosend-runtime.json \ --output .crabbox-results/gcp-leoclean-nosend-oci-smoke.json - name: Upload no-send runtime receipt if: always() uses: actions/upload-artifact@v4 with: name: teleo-infrastructure-leoclean-nosend-runtime path: | .crabbox-results/leoclean-nosend-runtime.json .crabbox-results/gcp-leoclean-nosend-oci-smoke.json if-no-files-found: error - name: Remove interrupted no-send OCI smokes if: always() run: | container_inventory="$(docker ps -aq --filter 'label=livingip.leoclean-nosend-smoke')" if [[ -n "${container_inventory}" ]]; then mapfile -t containers <<<"${container_inventory}" docker rm --force "${containers[@]}" fi image_inventory="$(docker images -q --filter 'label=livingip.leoclean-nosend-smoke')" if [[ -n "${image_inventory}" ]]; then mapfile -t images <<<"${image_inventory}" docker image rm --force "${images[@]}" fi remaining_containers="$(docker ps -aq --filter 'label=livingip.leoclean-nosend-smoke')" remaining_images="$(docker images -q --filter 'label=livingip.leoclean-nosend-smoke')" test -z "${remaining_containers}" test -z "${remaining_images}" phase1b-local-proof: name: Phase 1B local proof runs-on: ubuntu-latest needs: - lint - test - repo-contracts timeout-minutes: 20 env: PHASE1B_AGENT_ROUTING_ENABLED: "true" steps: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 with: python-version: ${{ env.PYTHON_VERSION }} - name: Install run: | python -m pip install --upgrade pip python -m pip install -e ".[dev]" - name: Run proof wrapper run: | scripts/crabbox_phase1b_proof.sh - name: Upload proof artifacts if: always() uses: actions/upload-artifact@v4 with: name: teleo-infrastructure-phase1b-proof path: | .crabbox-results/crabbox-ci-contract.json proof/phase1b-local-e2e-proof.json .crabbox-results/phase1b-pytest.xml .crabbox-results/phase1b-proof-summary.json if-no-files-found: warn