Skip to content

Commit 5ada732

Browse files
chore: add security/trust model and suppress some SAST findings (#254)
Signed-off-by: Barabanov, Alexander <alexander.barabanov@intel.com> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
1 parent 8e40217 commit 5ada732

6 files changed

Lines changed: 69 additions & 3 deletions

File tree

.github/scripts/skills/agent_skills.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
import os
1111
import platform
1212
import re
13-
import subprocess
13+
import subprocess # nosec: B404
1414
import sys
1515
from pathlib import Path
1616

@@ -88,7 +88,9 @@ def _create_windows_link(link: Path, abs_target: Path) -> None:
8888
try:
8989
link.symlink_to(abs_target, target_is_directory=True)
9090
except OSError:
91-
subprocess.run(
91+
# Local CI script, link/abs_target come from this repo's own
92+
# skills/ directory listing, not external input
93+
subprocess.run( # nosec: B607, B603
9294
["cmd", "/c", "mklink", "/J", str(link), str(abs_target)],
9395
check=True,
9496
capture_output=True,

docs/getting-started/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ This section contains short tutorials for the first successful PhysicalAI workfl
77
1. [Installation](installation.md)
88
2. [Quickstart](quickstart.md)
99
3. [Run a Policy](run-a-policy.md)
10+
4. [Security Model](security.md)
1011

1112
## Minimal Path
1213

docs/getting-started/security.md

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# Security Model
2+
3+
The runtime treats several categories of input as trusted by design and does not sandbox them further. If you
4+
load a config, manifest, or exported policy you did not author or fully review, you are running that content
5+
with the same privileges as the `physicalai` process itself. The sections below describe each trust boundary.
6+
7+
## Configs and manifests can execute arbitrary code
8+
9+
YAML/JSON configs passed via `--config` flag and an exported policy's `manifest.json` both use `class_path` values to
10+
dynamically import and construct Python objects - robots, cameras, preprocessors, postprocessors, action
11+
sources, callbacks. Currently, nothing restricts which class a `class_path` may name.
12+
13+
Only load configs, exported policies, and manifests from sources you trust. See also the `class_path` note in
14+
[Config Schema Reference](../reference/config-schema.md#security).
15+
16+
## Use only trusted, reviewed policies
17+
18+
An exported policy package (`manifest.json` plus artifacts) runs with the same privileges as the
19+
`physicalai` process.
20+
21+
**Loading via `InferenceModel.from_pretrained()`:** pin `revision` to the commit SHA of a version you have
22+
reviewed and trust, rather than a mutable branch or tag, so the content you reviewed is exactly what gets
23+
loaded on every run.
24+
25+
**Loading via `export_dir`:** `physicalai run` and direct `InferenceModel(export_dir=...)` construction both
26+
load whatever package is already in that local directory. Only place a reviewed, trusted export there.
27+
Treat populating that directory (downloading, copying, extracting) as the point where you decide to trust
28+
its contents.
29+
30+
## Remote robot sharing has no built-in security controls
31+
32+
The `SharedRobot` network transport (used to share one robot connection across processes) has no
33+
authentication, access control or encryption of its own.
34+
35+
If you enable `allow_remote=True` (`--allow_remote` on `physicalai robot serve`/`discover`), use it only on
36+
an isolated, firewalled robot-cell network (VLAN/firewall) or with Zenoh ACL/TLS configured yourself — the
37+
same requirement documented in [CLI Reference](../reference/cli.md#physicalai-robot-serve). Without one of
38+
those, anyone who can reach that network can observe robot state and, if nothing else restricts it, send
39+
actions to the robot.
40+
41+
## Runtime callbacks run with full trust
42+
43+
Callbacks registered with `RobotRuntime` (see
44+
[Add Runtime Callbacks](../how-to/runtime/add-runtime-callbacks.md)) can inspect and modify the
45+
action sent to the robot on every control tick. Currently, the runtime does not validate a callback's output before
46+
sending it to hardware.
47+
48+
Only register callbacks you wrote or have reviewed, especially any callback that can transform the outgoing
49+
action.
50+
51+
## CLI subcommands load from the active Python environment
52+
53+
`physicalai <subcommand>` discovers third-party subcommands via Python entry points registered by packages
54+
installed in the current environment. There is no allow-list of which packages may register a subcommand.
55+
56+
Treat installing a package into the same environment as granting it the ability to run as a `physicalai`
57+
subcommand and apply the same security review you would to any other dependency.

docs/reference/config-schema.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,4 +68,5 @@ manifest unification is a separate design decision.
6868

6969
`class_path` is executable local configuration. `instantiate()` is for
7070
trusted application and user-authored configs only, never metadata or control
71-
messages received from peers.
71+
messages received from peers. See [Security Model](../getting-started/security.md)
72+
for the full set of deployment-time trust assumptions.

mkdocs.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ nav:
2424
- Installation: getting-started/installation.md
2525
- Quickstart: getting-started/quickstart.md
2626
- Run a Policy: getting-started/run-a-policy.md
27+
- Security Model: getting-started/security.md
2728
- How-To:
2829
- Overview: how-to/README.md
2930
- Runtime:

src/physicalai/capture/transport/_publisher_worker.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,10 @@ def build_camera(config: dict) -> Camera:
145145
# Validate / reject flat keys even on the factory-override path.
146146
spec = CameraPublisherConfig.from_json_dict(config)
147147
module_path, _, attr = factory_override.rpartition(":")
148+
# _factory_override is a private, test-only constructor kwarg
149+
# delivered over a stdin pipe this same process's CameraPublisher.start()
150+
# writes, no production call site or external input sets it.
151+
# nosemgrep: python.lang.security.audit.non-literal-import.non-literal-import
148152
mod = importlib.import_module(module_path)
149153
factory = getattr(mod, attr)
150154
init_args = spec.camera.get("init_args", {})

0 commit comments

Comments
 (0)