diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8771282..21ec12a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -5,9 +5,13 @@ on: branches: [ main ] pull_request: +permissions: + contents: read + jobs: test: runs-on: ubuntu-latest + timeout-minutes: 20 steps: - name: Checkout uses: actions/checkout@v6 @@ -75,7 +79,7 @@ jobs: - name: Setup Python uses: actions/setup-python@v6 with: - python-version: "3.11" + python-version: "3.12" - name: Install dependencies run: | diff --git a/.github/workflows/dependabot_auto_merge.yml b/.github/workflows/dependabot_auto_merge.yml index f3f9f1a..a3a4988 100644 --- a/.github/workflows/dependabot_auto_merge.yml +++ b/.github/workflows/dependabot_auto_merge.yml @@ -9,6 +9,7 @@ jobs: auto-merge: if: github.event.workflow_run.conclusion == 'success' && startsWith(github.event.workflow_run.head_branch, 'dependabot/') runs-on: ubuntu-latest + timeout-minutes: 10 permissions: contents: write pull-requests: write diff --git a/.github/workflows/execution-report-heartbeat.yml b/.github/workflows/execution-report-heartbeat.yml index 57b398b..78b951a 100644 --- a/.github/workflows/execution-report-heartbeat.yml +++ b/.github/workflows/execution-report-heartbeat.yml @@ -24,10 +24,15 @@ env: GCP_WORKLOAD_IDENTITY_PROVIDER: projects/303168642265/locations/global/workloadIdentityPools/github-actions/providers/github-main GCP_WORKLOAD_IDENTITY_SERVICE_ACCOUNT: ibkr-platform-deploy@interactivebrokersquant.iam.gserviceaccount.com +concurrency: + group: ${{ github.workflow }}-${{ github.ref_name }} + cancel-in-progress: false + jobs: heartbeat: name: Check execution report heartbeat runs-on: ubuntu-latest + timeout-minutes: 15 permissions: contents: read id-token: write diff --git a/.github/workflows/runtime-guard.yml b/.github/workflows/runtime-guard.yml index 6c03323..99edef1 100644 --- a/.github/workflows/runtime-guard.yml +++ b/.github/workflows/runtime-guard.yml @@ -32,10 +32,15 @@ env: GCP_WORKLOAD_IDENTITY_PROVIDER: projects/303168642265/locations/global/workloadIdentityPools/github-actions/providers/github-main GCP_WORKLOAD_IDENTITY_SERVICE_ACCOUNT: ibkr-platform-deploy@interactivebrokersquant.iam.gserviceaccount.com +concurrency: + group: ${{ github.workflow }}-${{ github.ref_name }} + cancel-in-progress: false + jobs: guard: name: Check Cloud Run runtime runs-on: ubuntu-latest + timeout-minutes: 15 permissions: contents: read id-token: write diff --git a/.github/workflows/sync-cloud-run-env.yml b/.github/workflows/sync-cloud-run-env.yml index db509e4..13a6542 100644 --- a/.github/workflows/sync-cloud-run-env.yml +++ b/.github/workflows/sync-cloud-run-env.yml @@ -49,10 +49,15 @@ env: GCP_RUNTIME_SERVICE_ACCOUNT: ibkr-platform-runtime@interactivebrokersquant.iam.gserviceaccount.com GCP_ARTIFACT_REGISTRY_REPOSITORY: cloud-run-source-deploy +concurrency: + group: ${{ github.workflow }}-${{ github.ref_name }} + cancel-in-progress: false + jobs: sync-cloud-run-env: name: Deploy / Sync Cloud Run runs-on: ubuntu-latest + timeout-minutes: 20 permissions: contents: read id-token: write diff --git a/.python-version b/.python-version new file mode 100644 index 0000000..e4fba21 --- /dev/null +++ b/.python-version @@ -0,0 +1 @@ +3.12 diff --git a/tests/test_request_handling.py b/tests/test_request_handling.py index 3b90ace..ffd2e68 100644 --- a/tests/test_request_handling.py +++ b/tests/test_request_handling.py @@ -3,6 +3,31 @@ from application.cycle_result import StrategyCycleResult +def route_methods(strategy_module): + return { + rule.rule: sorted(rule.methods - {"HEAD", "OPTIONS"}) + for rule in strategy_module.app.url_map.iter_rules() + } + + +def test_cloud_run_route_contracts_are_registered(strategy_module): + assert route_methods(strategy_module) == { + "/": ["GET", "POST"], + "/precheck": ["GET", "POST"], + "/probe": ["GET", "POST"], + "/health": ["GET"], + "/static/": ["GET"], + } + + +def test_health_route_returns_ok(strategy_module): + with strategy_module.app.test_request_context("/health", method="GET"): + body, status = strategy_module.health() + + assert status == 200 + assert body == "OK" + + def test_handle_request_get_returns_safe_message(strategy_module, monkeypatch): def fail_if_called(): raise AssertionError("GET should not execute strategy")