Skip to content

fix(security): gate template tools.py autoload behind PRAISONAI_ALLOW_TEMPLATE_TOOLS#1579

Merged
MervinPraison merged 2 commits into
mainfrom
fix/template-tool-override-autoload-gate
Apr 28, 2026
Merged

fix(security): gate template tools.py autoload behind PRAISONAI_ALLOW_TEMPLATE_TOOLS#1579
MervinPraison merged 2 commits into
mainfrom
fix/template-tool-override-autoload-gate

Conversation

@MervinPraison

@MervinPraison MervinPraison commented Apr 28, 2026

Copy link
Copy Markdown
Owner

Summary

Disable implicit tools.py autoload from CWD and recipe template directories. The legacy behavior is preserved for trusted local workflows behind an explicit PRAISONAI_ALLOW_TEMPLATE_TOOLS=1 opt-in.

Threat

create_tool_registry_with_overrides() walked into the current working directory and the recipe template directory and exec_module()-d any tools.py it found:

# Before
cwd_tools_py = Path.cwd() / "tools.py"
if cwd_tools_py.exists():
    try:
        tools = loader.load_from_file(str(cwd_tools_py))   # <-- exec_module
        ...
if template_dir:
    tools_py = Path(template_dir) / "tools.py"
    if tools_py.exists():
        try:
            tools = loader.load_from_file(str(tools_py))   # <-- exec_module
            ...

When a recipe is fetched from a remote registry (e.g. via the GitHub recipe-share workflow), this gives an unauthenticated attacker arbitrary code execution in the server process the moment the recipe is loaded — the tools.py runs at import time, before any allow-list, sandbox, or approval check fires.

resolve_tools() had the same behavior on the same template directory.

Fix

Gate both autoload sites behind a new helper:

def _autoload_tools_enabled() -> bool:
    val = os.environ.get("PRAISONAI_ALLOW_TEMPLATE_TOOLS", "").strip().lower()
    return val in ("1", "true", "yes", "on")

The default is disabled. Trusted local workflows opt back in with one env var.

What still works (no opt-in needed)

Explicit, caller-controlled entry points are unchanged:

Entry point Status
override_files=[...] (explicit file paths) ✅ unchanged
override_dirs=[...] (explicit directory scan) ✅ unchanged
tools_sources=... (TEMPLATE.yaml directive) ✅ unchanged
registry={...} (caller-built registry) ✅ unchanged
Implicit cwd/tools.py and template_dir/tools.py 🚫 gated by env var

Tests

src/praisonai/tests/unit/templates/test_tool_override_autoload_gate.py (new, 5 tests). The malicious-template fixture writes a tools.py payload that drops a marker file in tempdir on import; the tests assert the marker does not appear under the default-deny behavior:

Test Asserts
test_template_tools_py_not_executed_by_default template tools.py is NOT executed
test_resolve_tools_does_not_execute_template_tools_py_by_default resolve_tools() does not execute it either
test_cwd_tools_py_not_executed_by_default CWD tools.py is NOT executed
test_opt_in_env_var_re_enables_autoload with PRAISONAI_ALLOW_TEMPLATE_TOOLS=1, legacy behavior is preserved
test_explicit_override_files_still_work_without_opt_in regression: explicit override_files keeps working

src/praisonai/tests/unit/test_templates.py::test_tools_py_loaded updated to set PRAISONAI_ALLOW_TEMPLATE_TOOLS=1 via monkeypatch.setenv, since that test pins the legacy contract (which now requires explicit opt-in).

$ PYTHONPATH=src/praisonai-agents:src/praisonai pytest \
    src/praisonai/tests/unit/test_templates.py \
    src/praisonai/tests/unit/templates/ -q
83 passed in 2.65s

AGENTS.md conformance

  • Wrapper-layer scoped: only touches praisonai/templates/tool_override.py and its tests. No core SDK changes.
  • Safe by default: matches the AGENTS.md invariant "new features are opt-in, not opt-out" — and converts a pre-existing unsafe-by-default behavior into a safe-by-default one with a single, well-documented opt-in.
  • No performance impact: one additional os.environ.get() per registry build, no extra imports.
  • Backward compatible for trusted-local users: setting PRAISONAI_ALLOW_TEMPLATE_TOOLS=1 restores the previous behavior bit-for-bit.
  • Test discipline: 5 new tests covering both the bypass and regressions; pre-existing test updated rather than weakened.
  • Fail-loud-but-narrow: only tools.py autoload is gated; explicit override_* paths still work and remain the supported entry point.

Files changed

File Δ
src/praisonai/praisonai/templates/tool_override.py +43 / −16 (gate helper + two call sites)
src/praisonai/tests/unit/templates/__init__.py new (empty package marker)
src/praisonai/tests/unit/templates/test_tool_override_autoload_gate.py new (115 lines, 5 tests)
src/praisonai/tests/unit/test_templates.py::test_tools_py_loaded + monkeypatch.setenv("PRAISONAI_ALLOW_TEMPLATE_TOOLS", "1")

Summary by CodeRabbit

  • Security

    • Template tools are disabled by default to prevent execution of untrusted code. Legacy behavior can be re-enabled via the PRAISONAI_ALLOW_TEMPLATE_TOOLS environment variable. Explicit user-provided tool overrides continue to load as before. Load failures now emit debug-level logs instead of being silently ignored.
  • Tests

    • Added and updated tests to cover the default-deny behavior and the opt-in legacy paths.

…_TEMPLATE_TOOLS

create_tool_registry_with_overrides() previously walked into the current
working directory and the recipe template directory, exec_module()-ing
any tools.py file it found. When a recipe is fetched from a remote
registry (e.g. GitHub via the recipe-share workflow), this gives an
unauthenticated attacker arbitrary code execution in the server process
the moment the recipe is loaded \u2014 the tools.py runs at import time
before any allow-list / sandbox / approval check fires.

Disable the implicit autoload by default. The legacy behaviour is
preserved for trusted local workflows by setting the env var
PRAISONAI_ALLOW_TEMPLATE_TOOLS=1 (also accepts true/yes/on, case
insensitive).

Explicit, opt-in entry points are unchanged and remain the supported
way to load custom tool modules:
  - override_files=[...]          # explicit file paths
  - override_dirs=[...]           # explicit directory scan
  - tools_sources=...             # TEMPLATE.yaml directive
  - registry={...}                # caller-built registry

Both autoload sites are gated:
  - create_tool_registry_with_overrides(): cwd/tools.py + template_dir/tools.py
  - resolve_tools(): template_dir/tools.py

Tests
-----
Added src/praisonai/tests/unit/templates/test_tool_override_autoload_gate.py
(5 tests). The fixture writes a malicious tools.py that drops a marker
file in tempdir and asserts the marker DOES NOT appear by default:
  - test_template_tools_py_not_executed_by_default
  - test_resolve_tools_does_not_execute_template_tools_py_by_default
  - test_cwd_tools_py_not_executed_by_default
  - test_opt_in_env_var_re_enables_autoload   (legacy compat)
  - test_explicit_override_files_still_work_without_opt_in (regression)

Updated test_templates.py::test_tools_py_loaded to set
PRAISONAI_ALLOW_TEMPLATE_TOOLS=1 via monkeypatch (the test pins the
legacy contract; that contract now requires explicit opt-in).

Verified: 83/83 in src/praisonai/tests/unit/test_templates.py +
src/praisonai/tests/unit/templates/ pass.
Copilot AI review requested due to automatic review settings April 28, 2026 13:07
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Warning

Gemini encountered an error creating the review. You can try again by commenting /gemini review.

@MervinPraison

Copy link
Copy Markdown
Owner Author

@claude You are the Lead Engineer. If the branch is under MervinPraison/PraisonAI (not a fork), you are able to make modifications to this branch and push directly. SCOPE: Focus ONLY on Python packages (praisonaiagents, praisonai). Do NOT modify praisonai-rust or praisonai-ts. Read ALL analysis and reviews above carefully (Gemini, CodeRabbit, Qodo, Copilot, etc).

Phase 1: Review per AGENTS.md

  1. Protocol-driven: check heavy implementations vs core SDK
  2. Backward compatible: ensure zero feature regressions
  3. Performance: no hot-path regressions

Phase 2: FIX Valid Issues
4. For any VALID bugs or architectural flaws found by Gemini, CodeRabbit, Qodo, Copilot, or any other reviewer: implement the fix
5. Push all code fixes directly to THIS branch (do NOT create a new PR)
6. Comment a summary of exact files modified and what you skipped

Phase 3: Final Verdict
7. If all issues are resolved, approve the PR / close the Issue
8. If blocking issues remain, request changes / leave clear action items

@coderabbitai

coderabbitai Bot commented Apr 28, 2026

Copy link
Copy Markdown
Contributor

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: f52790cf-09e4-4e0e-a7a6-365a970b970f

📥 Commits

Reviewing files that changed from the base of the PR and between 9ae9d6b and 0892578.

📒 Files selected for processing (2)
  • src/praisonai/praisonai/templates/tool_override.py
  • src/praisonai/tests/unit/templates/test_tool_override_autoload_gate.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/praisonai/tests/unit/templates/test_tool_override_autoload_gate.py

📝 Walkthrough

Walkthrough

Introduces an environment-variable-controlled gate (PRAISONAI_ALLOW_TEMPLATE_TOOLS) that disables implicit loading/execution of tools.py from the current working directory and template directories by default. Adds _autoload_tools_enabled() and a logger, and updates autoload points to honor the gate and emit debug logs on failures.

Changes

Cohort / File(s) Summary
Core Security Gate Implementation
src/praisonai/praisonai/templates/tool_override.py
Added _autoload_tools_enabled() and logger; wrapped legacy implicit autoloads for ./tools.py and template_dir/tools.py with the opt-in gate; replaced silent exception swallowing with debug-level logs (exc_info=True). Explicit override paths remain unchanged.
Security Regression Test Coverage
src/praisonai/tests/unit/templates/test_tool_override_autoload_gate.py
New tests verifying default-deny behavior: template and CWD tools.py are not executed by default, marker file not created; opt-in via PRAISONAI_ALLOW_TEMPLATE_TOOLS=1 restores legacy autoload; explicit override_files still loads tools.py.
Existing Test Update
src/praisonai/tests/unit/test_templates.py
Updated TestSimplifiedRecipeStructure.test_tools_py_loaded to set PRAISONAI_ALLOW_TEMPLATE_TOOLS=1 during the test and clarified test docs about default-disabled autoloading for security.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 A cautious rabbit guards the gate,
No wandering scripts decide my fate.
Flip the sign to let the old ways through,
Otherwise the meadow stays safe and new. 🥕✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 40.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 accurately summarizes the main change: disabling implicit tools.py autoload by default and requiring an environment variable opt-in for security.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/template-tool-override-autoload-gate

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 and usage tips.

@MervinPraison

Copy link
Copy Markdown
Owner Author

@copilot Do a thorough review of this PR. Read ALL existing reviewer comments above from Qodo, Coderabbit, and Gemini first — incorporate their findings.

Review areas:

  1. Bloat check: Are changes minimal and focused? Any unnecessary code or scope creep?
  2. Security: Any hardcoded secrets, unsafe eval/exec, missing input validation?
  3. Performance: Any module-level heavy imports? Hot-path regressions?
  4. Tests: Are tests included? Do they cover the changes adequately?
  5. Backward compat: Any public API changes without deprecation?
  6. Code quality: DRY violations, naming conventions, error handling?
  7. Address reviewer feedback: If Qodo, Coderabbit, or Gemini flagged valid issues, include them in your review
  8. Suggest specific improvements with code examples where possible

@greptile-apps

greptile-apps Bot commented Apr 28, 2026

Copy link
Copy Markdown

Greptile Summary

This PR gates the implicit tools.py autoload from CWD and recipe template directories behind a new PRAISONAI_ALLOW_TEMPLATE_TOOLS env-var check, preventing arbitrary code execution when recipes are fetched from remote registries. The fix is applied consistently to both autoload sites in create_tool_registry_with_overrides() and resolve_tools(), explicit override paths are untouched, and 6 tests cover default-deny, opt-in, and regression scenarios — including the CWD opt-in path flagged in a previous review round.

Confidence Score: 5/5

Safe to merge — the security fix is correct, consistent across both autoload sites, and fully covered by new tests including the CWD opt-in path that was flagged in the prior review round.

All findings from the previous review round have been addressed (CWD opt-in test added as test_opt_in_env_var_re_enables_cwd_autoload). No P0 or P1 issues remain. The gate logic is simple and correct, tests are comprehensive, and explicit override paths are unaffected.

No files require special attention.

Important Files Changed

Filename Overview
src/praisonai/praisonai/templates/tool_override.py Adds _autoload_tools_enabled() helper and gates both CWD and template-dir tools.py implicit autoloads behind it; improves silent-exception handling with DEBUG-level logging.
src/praisonai/tests/unit/templates/test_tool_override_autoload_gate.py New test file with 6 tests covering default-deny for template and CWD paths, opt-in restoration for both paths, and regression for explicit override_files.
src/praisonai/tests/unit/test_templates.py Updates test_tools_py_loaded to set PRAISONAI_ALLOW_TEMPLATE_TOOLS=1 via monkeypatch, preserving the legacy-contract assertion under the new security default.
src/praisonai/tests/unit/templates/init.py Empty package marker; no logic changes.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[create_tool_registry_with_overrides / resolve_tools] --> B{_autoload_tools_enabled?\nPRAISONAI_ALLOW_TEMPLATE_TOOLS}
    B -- "No (default)" --> C[Skip implicit autoload\nlog at DEBUG if needed]
    B -- "Yes (opt-in)" --> D[Load CWD tools.py\nif exists]
    D --> E[Load template_dir/tools.py\nif exists]
    E --> F[registry.update]
    C --> G[Explicit override_files / override_dirs\ntools_sources — always runs]
    F --> G
    G --> H[Return registry]
Loading

Reviews (2): Last reviewed commit: "fix(review): address coderabbit + grepti..." | Re-trigger Greptile

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

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 the current code and only fix it if needed.

Inline comments:
In `@src/praisonai/praisonai/templates/tool_override.py`:
- Around line 360-364: The try/except around loader.load_from_file(...) that
currently swallows all Exceptions should be changed to catch specific
predictable errors (e.g., FileNotFoundError, ImportError, SyntaxError,
ValueError) and call the module/process logger at debug level including the
exception info before continuing; keep the skip-on-error behavior (do not
re-raise) so registry.update(...) only runs on success. Apply the same change to
the second identical block later in the file so both implicit-template tool
loads log debug messages with exception details while preserving opt-in silent
skip semantics (reference loader.load_from_file, registry.update and the
PRAISONAI_ALLOW_TEMPLATE_TOOLS path).

In `@src/praisonai/tests/unit/templates/test_tool_override_autoload_gate.py`:
- Around line 28-37: The test payload uses a shared marker path (_MARKER) inside
PAYLOAD which causes race conditions when tests run in parallel; update PAYLOAD
(and the other occurrences at the other two places) to generate a unique
per-process marker filename (for example by appending os.getpid() or using
tempfile.NamedTemporaryFile()/tempfile.mkstemp()) instead of
tempfile.gettempdir()+'praisonai_autoload_marker.txt', ensuring the marker
variable (_MARKER) is constructed deterministically inside the payload string so
each test process writes to its own file and avoids cross-test interference
(keep references to _MARKER and evil_tool intact).
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: 728e1d29-e837-4852-8b1c-ae8b6bf23d81

📥 Commits

Reviewing files that changed from the base of the PR and between 9a06d57 and 9ae9d6b.

📒 Files selected for processing (4)
  • src/praisonai/praisonai/templates/tool_override.py
  • src/praisonai/tests/unit/templates/__init__.py
  • src/praisonai/tests/unit/templates/test_tool_override_autoload_gate.py
  • src/praisonai/tests/unit/test_templates.py

Comment thread src/praisonai/praisonai/templates/tool_override.py Outdated
Comment on lines +28 to +37
PAYLOAD = textwrap.dedent(
"""
import os, tempfile
_MARKER = os.path.join(tempfile.gettempdir(), 'praisonai_autoload_marker.txt')
with open(_MARKER, 'w') as f:
f.write('pwned')
def evil_tool():
return 'evil'
"""
).strip()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check if repo test config/CI enables parallel pytest runs (xdist / -n), which would increase collision risk.
fd -HI 'pyproject.toml|pytest.ini|tox.ini|.*\.ya?ml' | xargs rg -n 'pytest|xdist|-n\s*(auto|[0-9]+)'

Repository: MervinPraison/PraisonAI

Length of output: 5542


🏁 Script executed:

# First, check if the test file exists and examine its full content
cat -n "src/praisonai/tests/unit/templates/test_tool_override_autoload_gate.py" | head -80

Repository: MervinPraison/PraisonAI

Length of output: 2856


🏁 Script executed:

# Check pytest.ini configuration for src/praisonai
cat "src/praisonai/pytest.ini"

Repository: MervinPraison/PraisonAI

Length of output: 1554


Use per-process marker filenames to prevent race conditions in parallel test execution.

The shared marker file in tempfile.gettempdir() creates a race condition when tests run concurrently (-n 4 in CI). The autouse cleanup fixture cannot prevent cross-test interference; tests may fail intermittently depending on execution order.

Fix parallel test isolation
+MARKER_FILENAME = f"praisonai_autoload_marker_{os.getpid()}.txt"
+
 PAYLOAD = textwrap.dedent(
-    """
+    f"""
     import os, tempfile
-    _MARKER = os.path.join(tempfile.gettempdir(), 'praisonai_autoload_marker.txt')
+    _MARKER = os.path.join(tempfile.gettempdir(), '{MARKER_FILENAME}')
     with open(_MARKER, 'w') as f:
         f.write('pwned')
     def evil_tool():
         return 'evil'
     """
 ).strip()
...
-    marker = Path(tempfile.gettempdir()) / "praisonai_autoload_marker.txt"
+    marker = Path(tempfile.gettempdir()) / MARKER_FILENAME
...
-    return Path(tempfile.gettempdir()) / "praisonai_autoload_marker.txt"
+    return Path(tempfile.gettempdir()) / MARKER_FILENAME

Also applies to: lines 51, 67

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/praisonai/tests/unit/templates/test_tool_override_autoload_gate.py`
around lines 28 - 37, The test payload uses a shared marker path (_MARKER)
inside PAYLOAD which causes race conditions when tests run in parallel; update
PAYLOAD (and the other occurrences at the other two places) to generate a unique
per-process marker filename (for example by appending os.getpid() or using
tempfile.NamedTemporaryFile()/tempfile.mkstemp()) instead of
tempfile.gettempdir()+'praisonai_autoload_marker.txt', ensuring the marker
variable (_MARKER) is constructed deterministically inside the payload string so
each test process writes to its own file and avoids cross-test interference
(keep references to _MARKER and evil_tool intact).

Copilot AI 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.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

CodeRabbit Minor (blind 'except Exception: pass' in implicit-load
paths):
The three implicit-load sites (cwd autoload, template autoload in
create_tool_registry_with_overrides, template autoload in
resolve_tools) silently swallowed every failure, making it impossible
for opt-in operators to debug a broken tools.py. Add a module-level
'logger = logging.getLogger(__name__)' and replace each 'pass' with
'logger.debug("failed to autoload ...", exc_info=True)'. The
skip-on-error contract is preserved (these blocks are best-effort by
design); only the silent failure mode is removed.

Greptile P2 (opt-in test misses CWD autoload path):
test_opt_in_env_var_re_enables_autoload only verified the template_dir
opt-in path. Added test_opt_in_env_var_re_enables_cwd_autoload as a
parallel test for the cwd path, so legacy-behaviour-preservation
coverage is symmetric with the default-deny tests
(test_cwd_tools_py_not_executed_by_default vs the new opt-in mirror).

Verification:
  - test_tool_override_autoload_gate.py: 6/6 pass (was 5)
  - test_templates.py: 78/78 pass (no regressions)
@MervinPraison MervinPraison merged commit 0f6af9c into main Apr 28, 2026
2 checks passed
@MervinPraison MervinPraison deleted the fix/template-tool-override-autoload-gate branch April 28, 2026 16:44
MervinPraison added a commit that referenced this pull request Apr 29, 2026
…er/push/ag2) (#1580)

* fix(tests): clear 25 pre-existing test-infrastructure failures

Targeted, test-only cleanup. **No production code changes.**

Confirmed via triage that none of the 67 wrapper+core SDK test failures
post-v4.6.32 are functional regressions from PRs #1577/#1578/#1579 — all
are stale tests, missing skip guards, fixture bugs, or timing flakes
that pre-date the release.

This commit fixes the four highest-confidence categories:

* sandbox/test_sandlock_sandbox.py: macOS resolves /var/folders via the
  /private/var/folders symlink, so _safe_sandbox_path() returns the
  realpath form while sandbox._temp_dir holds the unresolved mkdtemp
  output. Compare via os.path.realpath() so the assertion holds on both
  macOS and Linux. Implementation is correct and unchanged.

* test_profiler_advanced.py: relax flaky timing bounds for
  test_api_call_context_manager and test_streaming_tracker. time.sleep
  precision is too coarse on busy CI runners to reliably exceed 10ms
  with a 10ms sleep; bumped to 50ms and asserted only that the recorded
  duration is positive. Matches AGENTS.md guidance that tests must not
  depend on timing.

* test_push_client.py: PushClient._send checks
  self._transport.is_connected (not the internal _connected flag), so
  the mock transport must report itself as connected. The fixture set
  c._connected=True but forgot mock_transport.connected=True, causing
  every send-path test to raise ConnectionError. Single-line fixture
  fix unblocks 8 tests.

* test_ag2_adapter.py: PR #1561 refactored framework validation to
  delegate to FrameworkAdapter.is_available(), which performs a real
  ag2 import. Existing tests still patch the legacy AG2_AVAILABLE flag
  and so fail with ImportError when ag2 is not installed. Added
  pytest.importorskip('ag2') at module scope to skip the suite when
  the SDK is missing — re-enable by updating mocks to patch the
  adapter directly.

Verified locally:
- 12 sandbox + profiler tests: PASS (was 3 failing)
- 10 push_client tests: PASS (was 8 failing)
- 14 ag2 tests: SKIP when ag2 missing (was 14 failing)

Net wrapper-suite improvement: 25 fewer failures (38 -> 13).

* fix(tests): strengthen timing assertions and sandbox path validation

Addresses reviewer feedback from CodeRabbit:
- Profiler tests: Change timing assertions from >0 to >=5ms to catch unit errors
- Sandbox tests: Tighten path prefix assertion with os.sep for directory boundaries

These changes improve test reliability and catch potential regressions while
maintaining tolerance for CI timing variations.

Co-authored-by: Mervin Praison <MervinPraison@users.noreply.github.com>

---------

Co-authored-by: Cascade <cascade@windsurf.dev>
Co-authored-by: praisonai-triage-agent[bot] <272766704+praisonai-triage-agent[bot]@users.noreply.github.com>
Co-authored-by: Mervin Praison <MervinPraison@users.noreply.github.com>
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.

2 participants