From 1a881a419f2ce25f6deee7d7d1024cdc6f465a0d Mon Sep 17 00:00:00 2001 From: kickthemoon0817 Date: Tue, 5 May 2026 19:17:28 +0900 Subject: [PATCH 1/3] ci: add GitHub Actions workflow gating tests + packaging on push Closes the iter15 test-engineer minor finding (no CI workflow runs the suite or the packaging gate). Now meaningful with the post-iter20 100% green baseline. Two jobs: - unit-tests: matrix across Python 3.11 / 3.12 / 3.13 (the project's classifier set). Installs via uv to match local dev workflow. Runs 'pytest tests/' which the addopts default filters down to the fast unit lane (skipping packaging, isaac, unreal_live markers). - packaging-gate: only runs on main + PRs to main since the uv-build-per-test pattern is the slowest job. Overrides the addopts default by passing '-m packaging' last (pytest takes the LAST -m). Security: the workflow only references trusted inputs (matrix.python-version, github.ref, github.event_name) and never interpolates user-controlled fields (issue title, PR body, commit messages, head ref) into run: blocks. The risky-input avoidance is documented inline at the top of the file. --- .github/workflows/ci.yml | 77 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..c3900bc --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,77 @@ +name: CI + +# Security note: this workflow only references trusted inputs +# (matrix-defined Python version, github.ref, github.event_name) +# and never interpolates user-controlled fields (issue title, PR +# body, commit messages, head ref, etc.) into run: blocks. See +# https://github.blog/security/vulnerability-research/how-to-catch-github-actions-workflow-injections-before-attackers-do/ +# for the patterns this workflow deliberately avoids. + +on: + push: + branches: ["**"] + pull_request: + branches: [main] + +jobs: + unit-tests: + name: Unit tests (Python ${{ matrix.python-version }}) + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + python-version: ["3.11", "3.12", "3.13"] + steps: + - uses: actions/checkout@v4 + + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + + - name: Install uv + uses: astral-sh/setup-uv@v3 + with: + enable-cache: true + + - name: Install project (with dev deps) + run: uv pip install --system -e ".[dev]" + + - name: Run unit tests + # The project's pyproject.toml addopts already bakes in + # `-m "not packaging"`, so the bare `pytest tests/` + # invocation skips the long-running wheel-build tests. + # Live engine tests (`isaac`, `unreal_live`) are gated by + # markers and skip automatically when the engine is not + # reachable. Reference baseline: ~495 passed, 0 failed + # (CLAUDE.md tracks the canonical count). + run: pytest tests/ --no-cov + + packaging-gate: + # Pre-publish gate: builds the wheel and inspects its contents + # to catch regressions in iter14's bridge-ext bundling and + # iter15's exclude-package-data rule. Only runs on main + PRs + # to main since it's the slowest job (uv build per test). + name: Packaging regression tests + runs-on: ubuntu-latest + if: github.ref == 'refs/heads/main' || github.event_name == 'pull_request' + steps: + - uses: actions/checkout@v4 + + - name: Set up Python 3.11 + uses: actions/setup-python@v5 + with: + python-version: "3.11" + + - name: Install uv + uses: astral-sh/setup-uv@v3 + with: + enable-cache: true + + - name: Install project (with dev deps) + run: uv pip install --system -e ".[dev]" + + - name: Run packaging-marker tests + # Override the addopts default `-m "not packaging"` by + # passing `-m packaging` last; pytest takes the LAST -m. + run: pytest tests/packaging/ -m packaging --no-cov -v From 204980c41c855d83141a7dcb46232d49c3ce0a70 Mon Sep 17 00:00:00 2001 From: kickthemoon0817 Date: Tue, 5 May 2026 19:17:28 +0900 Subject: [PATCH 2/3] chore: bump version to 0.0.44, 4-file lockstep --- .claude-plugin/plugin.json | 2 +- pyproject.toml | 2 +- src/simul_mcp/__init__.py | 2 +- src/simul_mcp/bridge_ext/khemoo.simul.mcp/config/extension.toml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json index b43ffc2..70f8963 100644 --- a/.claude-plugin/plugin.json +++ b/.claude-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "simul", - "version": "0.0.43", + "version": "0.0.44", "description": "3D simulation and DCC skills — scene setup, physics, materials, camera, scripting, and headless workflows for Isaac Sim, Unreal Engine, Blender, and USD", "author": { "name": "khemoo", diff --git a/pyproject.toml b/pyproject.toml index 38775ac..ad515c3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "simul-mcp" -version = "0.0.43" +version = "0.0.44" description = "MCP server for 3D simulation and DCC tools — USD scene control, Isaac Sim, Blender, and Unreal Engine integration" authors = [ {name = "khemoo"} diff --git a/src/simul_mcp/__init__.py b/src/simul_mcp/__init__.py index f555060..73b7021 100644 --- a/src/simul_mcp/__init__.py +++ b/src/simul_mcp/__init__.py @@ -5,7 +5,7 @@ USD scene understanding, mesh operations, and runtime integration capabilities. """ -__version__ = "0.0.43" +__version__ = "0.0.44" __author__ = "khemoo" __email__ = "" diff --git a/src/simul_mcp/bridge_ext/khemoo.simul.mcp/config/extension.toml b/src/simul_mcp/bridge_ext/khemoo.simul.mcp/config/extension.toml index 15ab3bf..9e117f8 100644 --- a/src/simul_mcp/bridge_ext/khemoo.simul.mcp/config/extension.toml +++ b/src/simul_mcp/bridge_ext/khemoo.simul.mcp/config/extension.toml @@ -1,5 +1,5 @@ [package] -version = "0.0.43" +version = "0.0.44" category = "Utility" title = "Simul MCP Bridge" description = "Production-oriented Isaac Sim bridge transport for Simul MCP with typed requests and VS Code fallback compatibility." From 3682ab146b02a784df9448832a79af1312491682 Mon Sep 17 00:00:00 2001 From: kickthemoon0817 Date: Tue, 5 May 2026 19:21:13 +0900 Subject: [PATCH 3/3] fix: tighten CI workflow from review feedback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Code-reviewer found a HIGH (lockfile bypass) + 2 MEDIUM (double-runs, missing permissions) on the iter22 CI workflow: - HIGH: 'uv pip install --system -e .[dev]' bypasses the tracked uv.lock entirely, so CI resolves transitive deps fresh from PyPI on every run. A transitive-dep break would silently flip CI red unrelated to the PR. Switched to 'uv sync --extra dev' which reads uv.lock and pins all transitive versions to what local dev resolves. Test runs now use 'uv run pytest' to invoke pytest inside the synced project venv. Both jobs (unit-tests + packaging-gate) updated. - MEDIUM: a contributor pushing to a feature branch with an open PR triggered both push + pull_request events, doubling the matrix run. Added a 'concurrency' group keyed on workflow + ref with 'cancel-in-progress: true' — the stale push run is canceled the moment the PR event fires for the same ref. - MEDIUM: GITHUB_TOKEN inherited the repo's default permissions (often write). Added top-level 'permissions: contents: read' since this is a read-only test workflow with no deployments, releases, or comments. Plus 1 LOW addressed inline: - Added a one-sentence note to the packaging-gate comment that a packaging-breaking change pushed to a feature branch without a PR will not be caught until the PR is created (the 'main + PRs' conditional intentionally trades that case for slowest-job cost). - Removed the misleading 'CLAUDE.md tracks the canonical count' parenthetical — the count drifts as tests are added; pytest's own output is the canonical reference. Two LOW items deferred to iter23+: - SHA-pinning of action versions (actions/checkout@v4 etc) — best practice for public repos but over-engineering for v0.0.x. - Lint/type-check job (black/isort/flake8/mypy) — bigger scope improvement worth its own PR. --- .github/workflows/ci.yml | 36 ++++++++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c3900bc..4f28ea7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,6 +13,19 @@ on: pull_request: branches: [main] +# Cancel any in-flight push run when the matching PR event fires +# for the same ref — eliminates the duplicate-runs trap when a +# contributor pushes to a feature branch with an open PR. +concurrency: + group: ci-${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +# Principle of least privilege: this is a read-only test workflow +# (no deployments, no releases, no comments). Drop GITHUB_TOKEN +# down to read-only contents access. +permissions: + contents: read + jobs: unit-tests: name: Unit tests (Python ${{ matrix.python-version }}) @@ -34,8 +47,13 @@ jobs: with: enable-cache: true - - name: Install project (with dev deps) - run: uv pip install --system -e ".[dev]" + - name: Install project from uv.lock (with dev extras) + # uv sync respects uv.lock for reproducibility — the same + # transitive deps that local dev resolves are what CI runs. + # Without this, uv pip install would re-resolve from PyPI + # and a transitive break could flip CI red unrelated to + # the PR. + run: uv sync --extra dev - name: Run unit tests # The project's pyproject.toml addopts already bakes in @@ -43,15 +61,17 @@ jobs: # invocation skips the long-running wheel-build tests. # Live engine tests (`isaac`, `unreal_live`) are gated by # markers and skip automatically when the engine is not - # reachable. Reference baseline: ~495 passed, 0 failed - # (CLAUDE.md tracks the canonical count). - run: pytest tests/ --no-cov + # reachable. + run: uv run pytest tests/ --no-cov packaging-gate: # Pre-publish gate: builds the wheel and inspects its contents # to catch regressions in iter14's bridge-ext bundling and # iter15's exclude-package-data rule. Only runs on main + PRs # to main since it's the slowest job (uv build per test). + # Note: a packaging-breaking change on a feature branch pushed + # without opening a PR will not be caught until the PR is + # created. name: Packaging regression tests runs-on: ubuntu-latest if: github.ref == 'refs/heads/main' || github.event_name == 'pull_request' @@ -68,10 +88,10 @@ jobs: with: enable-cache: true - - name: Install project (with dev deps) - run: uv pip install --system -e ".[dev]" + - name: Install project from uv.lock (with dev extras) + run: uv sync --extra dev - name: Run packaging-marker tests # Override the addopts default `-m "not packaging"` by # passing `-m packaging` last; pytest takes the LAST -m. - run: pytest tests/packaging/ -m packaging --no-cov -v + run: uv run pytest tests/packaging/ -m packaging --no-cov -v