Skip to main content
QueryContext lets you check what operations would be permitted by a capability set without actually applying the sandbox. This is useful for validation, testing, and building permission-checking UIs.

Constructor

QueryContext(caps: CapabilitySet)
Create a query context from a capability set.
caps
CapabilitySet
required
The capability set to query against.
from nono_py import CapabilitySet, AccessMode, QueryContext

caps = CapabilitySet()
caps.allow_path("/tmp", AccessMode.READ_WRITE)
caps.block_network()

ctx = QueryContext(caps)
The context captures a snapshot of the capabilities at creation time. Changes to the original CapabilitySet after creating the context are not reflected.

Methods

query_path

query_path(path: str, mode: AccessMode) -> dict
Check if a path operation would be permitted.
path
str
required
Path to check.
mode
AccessMode
required
Requested access mode.
Returns: Dictionary with query result.

Allowed Result

When the operation would be permitted:
{
    "status": "allowed",
    "reason": "granted_path",
    "granted_path": "/private/tmp",
    "access": "read+write"
}
FieldDescription
statusAlways "allowed"
reasonAlways "granted_path"
granted_pathThe capability that grants access
accessThe access level of that capability

Denied Results

When the operation would be blocked: Path not granted:
{
    "status": "denied",
    "reason": "path_not_granted"
}
Insufficient access level:
{
    "status": "denied",
    "reason": "insufficient_access",
    "granted": "read",
    "requested": "write"
}
FieldDescription
statusAlways "denied"
reason"path_not_granted" or "insufficient_access"
granted(Only for insufficient_access) The granted access level
requested(Only for insufficient_access) The requested access level

Example

from nono_py import CapabilitySet, AccessMode, QueryContext

caps = CapabilitySet()
caps.allow_path("/tmp", AccessMode.READ)

ctx = QueryContext(caps)

# Allowed: path is covered with sufficient access
result = ctx.query_path("/tmp/file.txt", AccessMode.READ)
print(result)
# {'status': 'allowed', 'reason': 'granted_path',
#  'granted_path': '/private/tmp', 'access': 'read'}

# Denied: insufficient access
result = ctx.query_path("/tmp/file.txt", AccessMode.WRITE)
print(result)
# {'status': 'denied', 'reason': 'insufficient_access',
#  'granted': 'read', 'requested': 'write'}

# Denied: path not granted
result = ctx.query_path("/etc/passwd", AccessMode.READ)
print(result)
# {'status': 'denied', 'reason': 'path_not_granted'}

query_network

query_network() -> dict
Check if network access would be permitted. Returns: Dictionary with query result.

Allowed Result

{
    "status": "allowed",
    "reason": "network_allowed"
}

Denied Result

{
    "status": "denied",
    "reason": "network_blocked"
}

Example

from nono_py import CapabilitySet, QueryContext

# Network allowed by default
caps = CapabilitySet()
ctx = QueryContext(caps)

result = ctx.query_network()
print(result)  # {'status': 'allowed', 'reason': 'network_allowed'}

# Block network
caps.block_network()
ctx = QueryContext(caps)

result = ctx.query_network()
print(result)  # {'status': 'denied', 'reason': 'network_blocked'}

Use Cases

Configuration Validation

Validate a capability configuration before deployment:
def validate_config(caps: CapabilitySet, required_paths: list[tuple[str, AccessMode]]) -> bool:
    ctx = QueryContext(caps)

    for path, mode in required_paths:
        result = ctx.query_path(path, mode)
        if result["status"] == "denied":
            print(f"Missing permission: {path} ({mode})")
            return False

    return True

# Check that all required paths are covered
caps = CapabilitySet()
caps.allow_path("/data", AccessMode.READ_WRITE)

required = [
    ("/data/input", AccessMode.READ),
    ("/data/output", AccessMode.WRITE),
]

if validate_config(caps, required):
    apply(caps)

Permission Checking UI

Build an interactive permission checker:
def check_operation(ctx: QueryContext, path: str, mode: AccessMode) -> str:
    result = ctx.query_path(path, mode)

    if result["status"] == "allowed":
        return f"ALLOWED via {result['granted_path']}"
    elif result["reason"] == "insufficient_access":
        return f"DENIED: have {result['granted']}, need {result['requested']}"
    else:
        return "DENIED: path not granted"

Testing Capability Sets

Write tests for your sandbox configuration:
import pytest
from nono_py import CapabilitySet, AccessMode, QueryContext

def test_sandbox_config():
    caps = CapabilitySet()
    caps.allow_path("/tmp", AccessMode.READ_WRITE)
    caps.allow_path("/data", AccessMode.READ)
    caps.block_network()

    ctx = QueryContext(caps)

    # Verify expected permissions
    assert ctx.query_path("/tmp/file", AccessMode.WRITE)["status"] == "allowed"
    assert ctx.query_path("/data/input", AccessMode.READ)["status"] == "allowed"
    assert ctx.query_path("/data/input", AccessMode.WRITE)["status"] == "denied"
    assert ctx.query_network()["status"] == "denied"