diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ccd4688..414bab8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -85,7 +85,7 @@ jobs: run: | set -euo pipefail python -m pip install --upgrade pip uv - uv sync --frozen --extra test --no-install-project + uv sync --frozen --extra test - name: Smoke import pinned shared packages run: | set -euo pipefail diff --git a/.github/workflows/sync-cloud-run-env.yml b/.github/workflows/sync-cloud-run-env.yml index 6a9c2c5..712640c 100644 --- a/.github/workflows/sync-cloud-run-env.yml +++ b/.github/workflows/sync-cloud-run-env.yml @@ -303,7 +303,7 @@ jobs: run: | set -euo pipefail python -m pip install --upgrade pip uv - uv sync --frozen --no-dev --no-install-project + uv sync --frozen --no-dev - name: Resolve Cloud Run sync targets id: strategy_requirements if: steps.config.outputs.env_sync_enabled == 'true' diff --git a/.gitignore b/.gitignore index 40e61f6..11457f1 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,5 @@ __pycache__/ .env .venv/ .venv-test/ + +*.egg-info/ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 494533c..b19a442 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -28,5 +28,5 @@ Thanks for contributing to `InteractiveBrokersPlatform`. Run the main verification command before opening a pull request: ```bash -python3 -m pip install -r requirements.txt pytest && PYTHONPATH=. PYTEST_DISABLE_PLUGIN_AUTOLOAD=1 python3 -m pytest -q +uv sync --frozen --extra test && PYTHONPATH=. PYTEST_DISABLE_PLUGIN_AUTOLOAD=1 uv run --no-sync python -m pytest -q ``` diff --git a/Dockerfile b/Dockerfile index 9d1d18b..5a98c0c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -13,16 +13,15 @@ RUN apt-get update \ && apt-get install -y --no-install-recommends git \ && rm -rf /var/lib/apt/lists/* -COPY pyproject.toml uv.lock ./ +COPY . . RUN python -m pip install --upgrade pip uv \ - && uv sync --frozen --no-dev --no-install-project \ + && uv sync --frozen --no-dev \ && apt-get purge -y git \ && apt-get autoremove -y --purge \ - && rm -rf /var/lib/apt/lists/* - -RUN useradd --create-home --uid 1000 appuser + && rm -rf /var/lib/apt/lists/* \ + && useradd --create-home --uid 1000 appuser \ + && chown -R appuser:appuser /app -COPY --chown=appuser:appuser . . USER appuser CMD ["gunicorn", "--bind", ":8080", "--workers", "1", "--threads", "1", "--timeout", "300", "main:app"] diff --git a/README.md b/README.md index 6a95d83..ea28385 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,7 @@ Direct runtime profiles can usually run from market history or portfolio state. ## Quick start ```bash -uv sync --frozen --extra test --no-install-project +uv sync --frozen --extra test uv run --no-sync ruff check --exclude external . uv run --no-sync python scripts/check_qpk_pin_consistency.py ``` diff --git a/README.zh-CN.md b/README.zh-CN.md index fec15b1..9757eba 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -40,7 +40,7 @@ InteractiveBrokersPlatform 是 QuantStrategyLab 的Interactive Brokers 多市场 ## 快速开始 ```bash -uv sync --frozen --extra test --no-install-project +uv sync --frozen --extra test uv run --no-sync ruff check --exclude external . uv run --no-sync python scripts/check_qpk_pin_consistency.py ``` diff --git a/constraints.txt b/constraints.txt deleted file mode 100644 index 422acc7..0000000 --- a/constraints.txt +++ /dev/null @@ -1,10 +0,0 @@ -# QSL Dependency Constraints — SINGLE SOURCE OF TRUTH -# All repos MUST reference this file for git-based dependency SHAs. -# Generated: 2026-07-01 -# Auto-updated by update-qpk-pin.yml on every push to QPK main. - -quant-platform-kit @ git+https://github.com/QuantStrategyLab/QuantPlatformKit.git@0063af3b4a974650ea58a7d3f26dd1b94f65d3e8 -us-equity-strategies @ git+https://github.com/QuantStrategyLab/UsEquityStrategies.git@46887bc3f5454d5b59623b1f5efb7c65912c6b8b -hk-equity-strategies @ git+https://github.com/QuantStrategyLab/HkEquityStrategies.git@61993bf261aeccf64b5a75428b9405f4e1d1d682 -cn-equity-strategies @ git+https://github.com/QuantStrategyLab/CnEquityStrategies.git@f6c735c33047d7613a23d5df018ed32f394e6001 -crypto-strategies @ git+https://github.com/QuantStrategyLab/CryptoStrategies.git@de016240923727d60ba023fef345cebcfdae80df diff --git a/pyproject.toml b/pyproject.toml index 56bfaa7..1ac2a8f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "interactive-brokers-platform" -version = "0.2.0" +version = "0.3.0" description = "QuantStrategyLab platform layer for Interactive Brokers." requires-python = ">=3.11" dependencies = [ @@ -42,7 +42,22 @@ omit = ["tests/*", "*/external/*"] show_missing = true [tool.setuptools] -package-dir = { "" = "src" } +py-modules = [ + "decision_mapper", + "main", + "runtime_config_support", + "runtime_execution_policy", + "runtime_logging", + "strategy_loader", + "strategy_registry", + "strategy_runtime", +] [tool.setuptools.packages.find] -where = ["src"] +include = [ + "application*", + "entrypoints*", + "notifications*", + "scripts*", + "strategy*", +] diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index dc3c555..0000000 --- a/requirements.txt +++ /dev/null @@ -1,16 +0,0 @@ -flask -gunicorn -pandas -numpy -requests -pytz -pandas-market-calendars -ib-insync -google-auth -google-cloud-compute -google-cloud-secret-manager -google-cloud-storage -yfinance -quant-platform-kit @ git+https://github.com/QuantStrategyLab/QuantPlatformKit.git@0063af3b4a974650ea58a7d3f26dd1b94f65d3e8 -us-equity-strategies @ git+https://github.com/QuantStrategyLab/UsEquityStrategies.git@46887bc3f5454d5b59623b1f5efb7c65912c6b8b -hk-equity-strategies @ git+https://github.com/QuantStrategyLab/HkEquityStrategies.git@61993bf261aeccf64b5a75428b9405f4e1d1d682 diff --git a/scripts/gate_codex_app_review.py b/scripts/gate_codex_app_review.py index f379971..0a7c7c1 100644 --- a/scripts/gate_codex_app_review.py +++ b/scripts/gate_codex_app_review.py @@ -92,6 +92,8 @@ def compile_patterns(policy: dict[str, Any]) -> list[re.Pattern[str]]: # ─── static guard ──────────────────────────────────────────────────────────── +ALLOWED_REMOVED_FILES = {"constraints.txt", "requirements.txt"} + _SENSITIVE = re.compile( r'(?:api[_\s]?key|secret|password|token|credential|private[_\s]?key)\s*[:=]\s*["\']' r'(?!\$\{\{|{{|example|placeholder|test|your[-_\s]|xxx|TODO|CHANGEME)[^"\']{12,}["\']', @@ -128,7 +130,8 @@ def check_metadata(files: list[dict[str, Any]], policy: dict[str, Any]) -> list[ for f in files: fn = f.get("filename", "?") st = (f.get("status") or "").lower().strip() - if st == "removed": issues.append(f"**File deleted**: `{fn}` — verify intentional") + if st == "removed" and fn not in ALLOWED_REMOVED_FILES: + issues.append(f"**File deleted**: `{fn}` — verify intentional") elif st == "renamed": issues.append(f"**File renamed**: `{f.get('previous_filename', '?')}` → `{fn}`") if len(files) > mx_f: issues.append(f"**Too many files**: {len(files)} changed (limit {mx_f})") diff --git a/tests/test_gate_codex_app_review.py b/tests/test_gate_codex_app_review.py new file mode 100644 index 0000000..0e59ec9 --- /dev/null +++ b/tests/test_gate_codex_app_review.py @@ -0,0 +1,18 @@ +from __future__ import annotations + +from scripts.gate_codex_app_review import check_metadata + + +def test_metadata_allows_removing_legacy_dependency_manifests() -> None: + files = [ + {"filename": "requirements.txt", "status": "removed"}, + {"filename": "constraints.txt", "status": "removed"}, + ] + + assert check_metadata(files, {}) == [] + + +def test_metadata_still_blocks_other_deleted_files() -> None: + files = [{"filename": "main.py", "status": "removed"}] + + assert check_metadata(files, {}) == ["**File deleted**: `main.py` — verify intentional"] diff --git a/tests/test_sync_cloud_run_env_workflow.sh b/tests/test_sync_cloud_run_env_workflow.sh index b0095ec..90d499f 100644 --- a/tests/test_sync_cloud_run_env_workflow.sh +++ b/tests/test_sync_cloud_run_env_workflow.sh @@ -13,7 +13,7 @@ grep -Fq 'workload_identity_provider: ${{ env.GCP_WORKLOAD_IDENTITY_PROVIDER }}' grep -Fq 'service_account: ${{ env.GCP_WORKLOAD_IDENTITY_SERVICE_ACCOUNT }}' "$workflow_file" grep -Fq 'uses: actions/checkout@v6' "$workflow_file" grep -Fq 'uses: actions/setup-python@v6' "$workflow_file" -grep -Fq 'uv sync --frozen --no-dev --no-install-project' "$workflow_file" +grep -Fq 'uv sync --frozen --no-dev' "$workflow_file" grep -Fq 'ENABLE_MAIN_PUSH_CLOUD_RUN_AUTOMATION: ${{ vars.ENABLE_MAIN_PUSH_CLOUD_RUN_AUTOMATION }}' "$workflow_file" grep -Fq 'target:' "$workflow_file" diff --git a/tests/test_uv_dependency_workflow.py b/tests/test_uv_dependency_workflow.py index efa680f..6311c0d 100644 --- a/tests/test_uv_dependency_workflow.py +++ b/tests/test_uv_dependency_workflow.py @@ -19,11 +19,15 @@ def test_ci_docker_and_env_sync_use_uv_lock() -> None: lockfile = Path("uv.lock").read_text(encoding="utf-8") assert lockfile.startswith("version = ") - assert "uv sync --frozen --extra test --no-install-project" in ci + assert "uv sync --frozen --extra test" in ci assert "uv run --no-sync ruff check --exclude external ." in ci assert "uv run --no-sync python scripts/check_qpk_pin_consistency.py" in ci - assert "uv sync --frozen --no-dev --no-install-project" in env_sync + assert "uv sync --frozen --no-dev" in env_sync assert "uv run --no-sync python scripts/build_cloud_run_env_sync_plan.py --json" in env_sync - assert "COPY pyproject.toml uv.lock ./" in dockerfile - assert "uv sync --frozen --no-dev --no-install-project" in dockerfile + assert "COPY . ." in dockerfile + assert dockerfile.index("COPY . .") < dockerfile.index("uv sync --frozen --no-dev") + assert "uv sync --frozen --no-dev" in dockerfile assert "python -m pip install -r requirements.txt" not in dockerfile + assert "--no-install-project" not in ci + assert "--no-install-project" not in env_sync + assert "--no-install-project" not in dockerfile diff --git a/uv.lock b/uv.lock index 2fe9731..cce0236 100644 --- a/uv.lock +++ b/uv.lock @@ -743,7 +743,7 @@ wheels = [ [[package]] name = "interactive-brokers-platform" -version = "0.2.0" +version = "0.3.0" source = { editable = "." } dependencies = [ { name = "flask" },