Skip to content

fix(eval-runner): require trusted adapter configuration - #104

Open
ComicBit wants to merge 2 commits into
bmad-code-org:mainfrom
ComicBit:fix/103-trusted-eval-adapters
Open

fix(eval-runner): require trusted adapter configuration#104
ComicBit wants to merge 2 commits into
bmad-code-org:mainfrom
ComicBit:fix/103-trusted-eval-adapters

Conversation

@ComicBit

@ComicBit ComicBit commented Aug 2, 2026

Copy link
Copy Markdown

What

Remove implicit adapter discovery from untrusted evaluation bundles.

Why

adapter.json beside a cases or queries file controlled the executable argv and optional host-environment forwarding passed to subprocess.run. A developer running a third-party bundle could therefore execute arbitrary local commands as the evaluator user. The same root cause affected both eval runners.

Fixes #103

How

  • Centralize adapter selection and execution-environment helpers.
  • Accept only explicit --adapter or operator-controlled BMAD_EVAL_ADAPTER configuration.
  • Ignore sibling adapter files and document the trust boundary.
  • Add regression coverage for both runners.

Testing

  • python3 -m pytest -q skills/bmad-eval-runner/scripts/tests — 15 passed.
  • Plain self-checks for all three runner test files pass.
  • git diff --check passes.
  • JS lint/format could not run because dependencies are not installed; npm test is not defined in this package.

Summary by CodeRabbit

  • Bug Fixes

    • Improved adapter selection using explicitly configured paths or the BMAD_EVAL_ADAPTER environment setting.
    • Prevented untrusted adapter files beside evaluation data from being used.
    • Added safer adapter validation and controlled execution environments.
    • Evaluation runs now fall back to staging-only when no adapter is configured, with an explicit Claude Code default path.
  • Tests

    • Added coverage for adapter precedence, environment-based configuration, and ignored adjacent adapter files.

@coderabbitai

coderabbitai Bot commented Aug 2, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 76b07446-4a80-4079-8ec3-e008a8b2610a

📥 Commits

Reviewing files that changed from the base of the PR and between dba806d and 8b2ff04.

📒 Files selected for processing (4)
  • skills/bmad-eval-runner/scripts/adapter.py
  • skills/bmad-eval-runner/scripts/run_evals.py
  • skills/bmad-eval-runner/scripts/run_triggers.py
  • skills/bmad-eval-runner/scripts/tests/test_adapter_resolution.py
🚧 Files skipped from review as they are similar to previous changes (3)
  • skills/bmad-eval-runner/scripts/run_triggers.py
  • skills/bmad-eval-runner/scripts/adapter.py
  • skills/bmad-eval-runner/scripts/run_evals.py

Walkthrough

Adapter resolution is centralized in shared helpers. Sibling adapter files are no longer discovered. Explicit paths and BMAD_EVAL_ADAPTER remain supported. Adapter validation, command expansion, environment construction, documentation, and regression tests were updated.

Changes

Adapter trust boundary

Layer / File(s) Summary
Trusted adapter helper implementation
skills/bmad-eval-runner/scripts/adapter.py
Adds trusted adapter selection, JSON validation, invocation placeholder expansion, and restricted subprocess environment construction.
Runner integration and configuration guidance
skills/bmad-eval-runner/scripts/run_evals.py, skills/bmad-eval-runner/scripts/run_triggers.py, skills/bmad-eval-runner/SKILL.md, skills/bmad-eval-runner/references/platform-adapter.md
Both runners use the shared adapter helpers. CLI help and platform guidance describe explicit configuration and BMAD_EVAL_ADAPTER fallback behavior.
Adapter resolution regression coverage
skills/bmad-eval-runner/scripts/tests/test_adapter_resolution.py
Tests verify sibling adapter rejection, explicit adapter precedence, environment-based adapter selection, and empty invocation rejection for both runners.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Poem

A rabbit checks the adapter gate,
No sibling file can change its fate.
Explicit paths guide the way,
Safe commands run today.
Hop, test, and stage with care!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the trusted adapter configuration security fix.
Linked Issues check ✅ Passed The changes remove sibling adapter discovery, centralize trusted resolution, document the boundary, and add regression tests for issue #103.
Out of Scope Changes check ✅ Passed The implementation, documentation, refactoring, and tests directly support the linked issue objectives.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@greptile-apps

greptile-apps Bot commented Aug 2, 2026

Copy link
Copy Markdown

Greptile Summary

This PR removes the implicit adapter.json sibling-file discovery that allowed an untrusted eval bundle to control subprocess argv and environment variable forwarding. Adapter selection is now centralised in a new adapter.py module and restricted to explicit --adapter CLI flags or the operator-controlled BMAD_EVAL_ADAPTER environment variable.

  • adapter.py (new): Single source of truth for find_adapter, load_adapter, build_argv, and build_case_env; sibling-directory lookup removed, expanduser() applied consistently, and load_adapter now rejects an empty invocation list.
  • run_evals.py / run_triggers.py: Both runners replace their inline adapter implementations with thin wrappers that delegate to adapter.py; --adapter help text updated to reflect the new trust boundary.
  • test_adapter_resolution.py (new): Four regression tests covering sibling-adapter suppression, explicit-path precedence, env-var configuration, and empty-invocation rejection.

Confidence Score: 5/5

Safe to merge — the core trust-boundary fix is correct and well-tested.

The security-relevant change is implemented correctly in the single canonical location in adapter.py and is guarded by regression tests. Both runners delegate cleanly to the shared module. The only new issues are a naming collision between the adapter module and the adapter local variable in each runner's main(), and a slightly misleading error message for an empty invocation list — neither affects current runtime behaviour.

Files Needing Attention: The adapter: dict | None = None local variable in the main() functions of both run_evals.py and run_triggers.py shadows the newly-imported adapter module; worth renaming to avoid future confusion.

Important Files Changed

Filename Overview
skills/bmad-eval-runner/scripts/adapter.py New centralised adapter module — sibling-directory lookup removed, expanduser() applied to both explicit and env paths, and load_adapter now rejects an empty invocation list. Core security fix is correct.
skills/bmad-eval-runner/scripts/run_evals.py Delegates adapter logic to the new module. Local variable `adapter: dict
skills/bmad-eval-runner/scripts/run_triggers.py Same delegation pattern as run_evals.py, same adapter local-variable shadowing of the newly-imported module in main().
skills/bmad-eval-runner/scripts/tests/test_adapter_resolution.py Good regression coverage for the trust boundary. Both FINDERS proxy to the same adapter.find_adapter, so the loop verifies the shared impl twice rather than two independent code paths (see existing thread).
skills/bmad-eval-runner/SKILL.md Step 5 updated to document the new trust-boundary rule — no sibling adapter lookup, explicit config only.
skills/bmad-eval-runner/references/platform-adapter.md Discovery rule 3 (sibling adapter.json) removed; new paragraph explains the trust boundary and why the sibling lookup was eliminated.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    CLI["--adapter path"] -->|explicit Path| FA
    ENV["BMAD_EVAL_ADAPTER env var"] -->|env_path| FA
    BUNDLE["Sibling adapter.json (untrusted bundle)"] -->|IGNORED| FA
    FA["adapter.find_adapter()"]
    FA -->|Path found| LA["adapter.load_adapter() validate dict + non-empty invocation"]
    FA -->|None| SKIP["Degrade to staging-only all cases skipped"]
    LA -->|valid cfg| BA["adapter.build_argv() expand placeholders"]
    LA -->|ValueError| SKIP
    BA --> SUB["subprocess.run(argv, env=...)"]
    ENV2["adapter.build_case_env() PATH + HOME + CLAUDE_CONFIG_DIR + passthrough"] --> SUB
Loading

Reviews (2): Last reviewed commit: "test(eval-runner): address adapter revie..." | Re-trigger Greptile

Comment thread skills/bmad-eval-runner/scripts/tests/test_adapter_resolution.py Outdated
Comment thread skills/bmad-eval-runner/scripts/adapter.py Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@skills/bmad-eval-runner/scripts/adapter.py`:
- Around line 41-42: Update the invocation validation in the adapter
configuration handling to reject an empty list as well as missing or non-list
values. Ensure the existing ValueError path for the “invocation” configuration
treats a zero-length argv list as invalid, preventing it from reaching
subprocess execution.

In `@skills/bmad-eval-runner/scripts/tests/test_adapter_resolution.py`:
- Around line 25-64: Update test_sibling_adapter_is_ignored and
test_explicit_adapter_is_used_even_beside_bundle to create both adapter.json and
.bmad-eval-adapter.json sibling files. In
test_explicit_adapter_is_used_even_beside_bundle, configure BMAD_EVAL_ADAPTER
with a different valid adapter path while asserting every FINDERS implementation
still returns the explicit path.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: bd946feb-aa20-44db-b422-844a33c46961

📥 Commits

Reviewing files that changed from the base of the PR and between e6935f2 and dba806d.

📒 Files selected for processing (6)
  • skills/bmad-eval-runner/SKILL.md
  • skills/bmad-eval-runner/references/platform-adapter.md
  • skills/bmad-eval-runner/scripts/adapter.py
  • skills/bmad-eval-runner/scripts/run_evals.py
  • skills/bmad-eval-runner/scripts/run_triggers.py
  • skills/bmad-eval-runner/scripts/tests/test_adapter_resolution.py

Comment thread skills/bmad-eval-runner/scripts/adapter.py Outdated
Comment thread skills/bmad-eval-runner/scripts/tests/test_adapter_resolution.py Outdated
@ComicBit

ComicBit commented Aug 2, 2026

Copy link
Copy Markdown
Author

Addressed all four unresolved review requests in commit 8b2ff04:

  • Added runner-local find_adapter seams so the regression tests exercise run_evals and run_triggers independently.
  • Applied expanduser() to explicit adapter paths, matching BMAD_EVAL_ADAPTER behavior.
  • Rejected empty invocation lists during adapter validation.
  • Covered both sibling filenames (adapter.json and .bmad-eval-adapter.json) and verified explicit --adapter takes precedence over BMAD_EVAL_ADAPTER.

Validation:

  • python3 -m pytest -q skills/bmad-eval-runner/scripts/tests — 16 passed.
  • All three test files also pass their plain Python self-checks.
  • git diff --check passes.

The docstring-coverage warning remains informational; no repository enforcement gate for it is configured.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Security: do not auto-discover adapters from untrusted eval bundles

1 participant