Skip to content

Clarify that mount= + os= routes unmounted filesystem ops to os= #350

@alexmojaki

Description

@alexmojaki

Summary

The current pydantic_monty docs/comments around mount= + os= are inconsistent.

Some code comments and test docs describe os= as a fallback for non-filesystem OS operations when mounts are configured, but the runtime intentionally also routes filesystem operations for unmounted paths into os=.

I think this should be documented clearly because it is easy for an embedder to assume that mount= is a complete filesystem allowlist once mounts are configured.

Current behavior

The runtime intentionally falls through to os= for unmounted filesystem paths:

  • crates/monty-python/src/monty_cls.rs
    • handle_mount_os_call() says the mount table returns None for non-filesystem ops and for paths that don't match any mount
    • it also has the comment: Intentional: unmounted paths fall through to os=
  • crates/monty-python/src/repl.rs
    • same behavior in handle_repl_os_call()

So with something like:

Monty(code).run(mount=MountDir('/data', ...), os=my_callback)

Path('/other/file.txt').read_text() can still be sent to my_callback.

Misleading wording

These places currently describe os= more narrowly:

  • crates/monty-python/src/mount.rs
    • fallback: Option<Py<PyAny>> is documented as an optional callable for non-filesystem OS operations
    • from_run_args() documents os as a fallback for non-filesystem OS operations
  • crates/monty-python/tests/test_mount_table.py
    • module docstring says mounts run with optional Python fallback for non-filesystem ops via os=
    • section header says Fallback via os= for non-filesystem ops

The public stub is not explicitly wrong, but it is incomplete:

  • crates/monty-python/python/pydantic_monty/_monty.pyi
    • run(..., os=...) says os is an optional callback for OS calls, but does not explain the interaction with mount= or that unmounted filesystem ops also reach the callback

Why this matters

This looks like a documentation bug / embedding footgun, not necessarily a core sandbox bug.

A caller could reasonably read the current wording and assume:

  • mounted paths are handled by mount=
  • non-filesystem ops are handled by os=
  • unmounted filesystem paths are denied

But the actual behavior is:

  • mounted filesystem paths are handled by mount=
  • non-filesystem ops go to os=
  • unmounted filesystem paths also go to os=

That difference feels important enough to document explicitly.

Suggested fix

  • Update the misleading wording in mount.rs and test_mount_table.py
  • Add user-facing docs for run(..., mount=..., os=...) / feed_run(..., mount=..., os=...) clarifying that os= also receives OS operations not handled by mounts, including filesystem operations on unmounted paths
  • Consider adding a test that explicitly documents this behavior

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions