From 4b50302e6036f5a983296c5f806a5f6ee62ac66d Mon Sep 17 00:00:00 2001 From: Pigbibi <20649888+Pigbibi@users.noreply.github.com> Date: Wed, 10 Jun 2026 20:49:36 +0800 Subject: [PATCH] Apply audit remediation --- .github/workflows/ci.yml | 5 ++- .github/workflows/dependabot_auto_merge.yml | 1 + .../workflows/execution-report-heartbeat.yml | 5 +++ .github/workflows/runtime-guard.yml | 5 +++ .github/workflows/sync-cloud-run-env.yml | 5 +++ .python-version | 1 + tests/test_request_handling.py | 39 +++++++++++++++++++ 7 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 .python-version diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 12347ec..3e5ddc1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -5,9 +5,13 @@ on: push: branches: [main] +permissions: + contents: read + jobs: test: runs-on: ubuntu-latest + timeout-minutes: 20 steps: - uses: actions/checkout@v6 - uses: actions/setup-python@v6 @@ -19,4 +23,3 @@ jobs: python -m pip install -r requirements.txt - name: Run tests run: python -m pytest -q - diff --git a/.github/workflows/dependabot_auto_merge.yml b/.github/workflows/dependabot_auto_merge.yml index bf7a789..9d605e8 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 0a978a5..79e0405 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/1088907247379/locations/global/workloadIdentityPools/github-actions/providers/github-main GCP_WORKLOAD_IDENTITY_SERVICE_ACCOUNT: firstrade-platform-deploy@firstradequant.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 1d9c46d..2f3b94a 100644 --- a/.github/workflows/runtime-guard.yml +++ b/.github/workflows/runtime-guard.yml @@ -32,10 +32,15 @@ env: GCP_WORKLOAD_IDENTITY_PROVIDER: projects/1088907247379/locations/global/workloadIdentityPools/github-actions/providers/github-main GCP_WORKLOAD_IDENTITY_SERVICE_ACCOUNT: firstrade-platform-deploy@firstradequant.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 8c0a68a..b5cf1e2 100644 --- a/.github/workflows/sync-cloud-run-env.yml +++ b/.github/workflows/sync-cloud-run-env.yml @@ -14,10 +14,15 @@ env: GCP_ARTIFACT_REGISTRY_HOSTNAME: us-central1-docker.pkg.dev GCP_ARTIFACT_REGISTRY_REPOSITORY: cloud-run-source-deploy +concurrency: + group: ${{ github.workflow }}-${{ github.ref_name }} + cancel-in-progress: false + jobs: deploy-cloud-run: name: Deploy 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 c7d6812..a6f2018 100644 --- a/tests/test_request_handling.py +++ b/tests/test_request_handling.py @@ -7,6 +7,45 @@ import main +def route_methods(): + methods_by_route = {} + for rule in main.app.url_map.iter_rules(): + methods_by_route.setdefault(rule.rule, set()).update(rule.methods - {"HEAD", "OPTIONS"}) + return {route: sorted(methods) for route, methods in methods_by_route.items()} + + +def test_cloud_run_route_contracts_are_registered(): + assert route_methods() == { + "/": ["GET", "POST"], + "/profiles": ["GET"], + "/smoke": ["GET"], + "/session-check": ["GET", "POST"], + "/run": ["GET", "POST"], + "/precheck": ["GET", "POST"], + "/probe": ["GET", "POST"], + "/static/": ["GET"], + } + + +def test_health_route_returns_service_contract(monkeypatch): + monkeypatch.setenv("FIRSTRADE_RUN_SMOKE_ON_HTTP", "true") + monkeypatch.delenv("FIRSTRADE_RUN_SESSION_CHECK_ON_HTTP", raising=False) + monkeypatch.delenv("FIRSTRADE_RUN_STRATEGY_ON_HTTP", raising=False) + client = main.app.test_client() + + response = client.get("/") + + assert response.status_code == 200 + payload = response.get_json() + assert payload["service"] == "firstrade-platform" + assert payload["api_kind"] == "unofficial-reverse-engineered" + assert payload["strategy_domain"] == "us_equity" + assert payload["smoke_on_http"] is True + assert payload["session_check_on_http"] is False + assert payload["strategy_run_on_http"] is False + assert "as_of" in payload + + def test_run_endpoint_is_disabled_without_explicit_http_gate(monkeypatch): monkeypatch.delenv("FIRSTRADE_RUN_STRATEGY_ON_HTTP", raising=False) client = main.app.test_client()