Skip to content

fix: address security vulnerabilities, bugs, and robustness issues - #24

Merged
enkerewpo merged 3 commits into
devfrom
claude/code-review-and-fixes-xMgod
Apr 6, 2026
Merged

enkerewpo merged 3 commits into
devfrom
claude/code-review-and-fixes-xMgod

Conversation

@enkerewpo

@enkerewpo enkerewpo commented Apr 6, 2026 •

Copy link
Copy Markdown
Member

Summary

Full code review of the robonix codebase — fixes security vulnerabilities, bugs, CI failures, and adds 19 regression tests.

Commit 1: Security & Bug Fixes

Security (HIGH)

  • Path traversal in builtin tools: read_file, write_file, patch_file, list_dir accepted arbitrary paths (e.g. ../../../etc/passwd). Added safe_resolve() to confine file access within workspace root (ROBONIX_WORKSPACE env or cwd).
  • Command execution hardening: Added 8KB command length limit and 120s execution timeout to run_command.
  • Shell injection in docker-entrypoint.sh: Unquoted heredoc <<EOF expanded env vars into ~/.bashrc — malicious env values could inject arbitrary shell commands. Changed to quoted <<'EOF'.
  • Silent bad JSON in MCP dispatch: unwrap_or_default() masked invalid tool arguments. Now returns explicit error.

Bugs (MEDIUM-HIGH)

  • truncate() UTF-8 panic: Slicing &s[..max] could split multi-byte chars (Chinese/emoji), panicking at runtime. Now uses floor_char_boundary().
  • Spinner flush().unwrap() panics: 3 sites in CLI crashed if stdout was closed (piped to dead process). Changed to let _ = flush().
  • Integer overflow in BufferSpec::frame_bytes()/stride(): width * height * channels * bpe with large u32 values silently wrapped. Now uses checked_mul().
  • pyrightconfig.json: Trailing comma made file invalid JSON, breaking Pyright type checking.
  • Null pointer dereference in rbnx_buffer.py: FFI header_ptr used without null check in open() and attach().
  • File handle leaks in benchmark.py: json.load(open(...)) never closed file handles. Replaced with with context managers.

Commit 2: CI & Clippy Fixes

  • Fix CI workflow: ci.yml referenced nonexistent make ci-rust / make ci-full targets. Replaced with actual steps (cargo fmt --check, cargo clippy, cargo build). Added dev to trigger branches.
  • Fix all clippy warnings across entire workspace (collapsible_if, manual_flatten, too_many_arguments, should_implement_trait, wildcard_in_or_patterns, manual_contains, cloned_ref_to_slice_refs, lines_filter_map_ok, etc.)
  • Fix all cargo fmt formatting issues.
  • make check now passes cleanly with zero errors.

Commit 3: Systematic Regression Tests (19 tests)

Category Tests What's verified
Path traversal 5 ../ rejected, absolute path outside workspace rejected, write blocked, read blocked, in-workspace allowed
Command hardening 2 >8KB command rejected, normal echo hello succeeds
UTF-8 truncation 3 ASCII, Chinese 3-byte, emoji 4-byte — no panic at mid-char boundary
Buffer overflow 4 u32::MAX overflow panics with message (not silent wrap), normal 1920x1080 correct
Buffer format/header 3 All 17 formats roundtrip, unknown returns None, header == 64 bytes
Misc 2 Unknown builtin errors, total_bytes includes header

Additionally validated externally:

  • pyrightconfig.json parses as valid JSON
  • Python files pass py_compile syntax check
  • docker-entrypoint.sh passes bash -n syntax check + injection simulation test
  • CI workflow YAML validates with correct structure and dev branch triggers

Test plan

  • cargo test -p robonix-buffer -p robonix-executor — 19/19 passed
  • make build — compiles successfully
  • make check (fmt + clippy) — zero errors
  • pyrightconfig.json — valid JSON
  • Python syntax check — benchmark.py, rbnx_buffer.py pass
  • Shell injection test — <<'EOF' prevents variable expansion
  • CI workflow YAML — valid structure, includes dev branch

Note: 2 pre-existing robonix-atlas tests fail due to port binding in this environment (not related to this PR).

https://claude.ai/code/session_01RnU7NBm6mxcKqgTGox4jyh

Security:
- Add path traversal protection to builtin file operations (read/write/patch/list_dir)
  by resolving paths against a workspace root and rejecting escapes
- Add command length limit and execution timeout to run_command
- Fix shell variable injection in docker-entrypoint.sh by using quoted heredoc
- Replace silent JSON parse fallback in MCP dispatch with explicit error

Bugs:
- Fix truncate() panic on multi-byte UTF-8 boundaries using floor_char_boundary
- Fix flush().unwrap() panics in CLI Spinner that crash on closed stdout
- Fix integer overflow in BufferSpec::frame_bytes/stride using checked arithmetic
- Fix pyrightconfig.json invalid trailing comma breaking type checking
- Add null pointer checks for buffer header reads in rbnx_buffer.py
- Fix file handle leaks in benchmark.py using context managers

https://claude.ai/code/session_01RnU7NBm6mxcKqgTGox4jyh
@enkerewpo
enkerewpo changed the base branch from main to dev April 6, 2026 16:09
claude added 2 commits April 6, 2026 22:22
- Fix all clippy warnings across workspace (collapsible_if, manual_flatten,
  too_many_arguments, should_implement_trait, wildcard_in_or_patterns,
  manual_contains, cloned_ref_to_slice_refs, lines_filter_map_ok, etc.)
- Run cargo fmt to fix formatting inconsistencies
- Fix CI workflow: replace nonexistent make targets (ci-rust, ci-full)
  with actual build steps (fmt --check, clippy, cargo build)
- Add #[allow(dead_code)] for intentionally unused pilot session fields
  and enum variants that match IDL definitions

https://claude.ai/code/session_01RnU7NBm6mxcKqgTGox4jyh
Add 19 tests verifying all critical fixes:

Path traversal protection (5 tests):
- ../../../etc/passwd traversal rejected
- Absolute path /etc/hostname outside workspace rejected
- Path within workspace allowed
- read_file() integration test for traversal
- write_file() integration test prevents file creation outside workspace

Command execution hardening (2 tests):
- Oversized command (>8KB) rejected with clear error
- Normal command executes successfully

UTF-8 truncation safety (3 tests):
- ASCII truncation works correctly
- Multi-byte Chinese chars (3-byte UTF-8) don't panic at mid-char boundary
- Emoji (4-byte UTF-8) doesn't panic at mid-char boundary

Buffer integer overflow (4 tests):
- frame_bytes() panics on u32::MAX overflow instead of wrapping
- stride() panics on overflow
- Normal 1920x1080 RGB8 computes correctly
- Float32 format computes correctly

Buffer format/header (3 tests):
- All 17 format values roundtrip through from_u32
- Unknown format returns None
- Header size is exactly 64 bytes

Misc (2 tests):
- Unknown builtin tool returns error
- total_bytes() includes HEADER_SIZE

https://claude.ai/code/session_01RnU7NBm6mxcKqgTGox4jyh
@enkerewpo
enkerewpo merged commit 6029992 into dev Apr 6, 2026
2 checks passed
@enkerewpo
enkerewpo deleted the claude/code-review-and-fixes-xMgod branch April 6, 2026 22:42
enkerewpo added a commit that referenced this pull request Apr 25, 2026
Two related cleanups in atlas.proto + service.rs:

(1) CapabilityInfo → CapabilityInterface, with the request/record field
    renamed `capabilities` → `interfaces`. The struct describes ONE
    capability interface (a single contract_id binding), not the whole
    instance — its old name conflated the two.

(2) DeclareInterface no longer takes `uint32 listen_port`. Port numbers
    are TCP-specific and don't belong on a transport-agnostic interface
    declaration. Replaced with a `string endpoint` that the caller
    proposes; Atlas resolves the actual stored endpoint per these rules
    (documented inline in the proto):

      empty proposal + atlas-mintable transport (ros2 / shared_memory)
                             -> Atlas mints "/rbnx/<contract>/<uuid8>"
      empty + non-mintable transport (grpc, ...)
                             -> InvalidArgument
      non-empty + no collision        -> stored verbatim
      non-empty + collision + mintable transport
                             -> Atlas appends "~<uuid8>"
      non-empty + collision + non-mintable transport
                             -> AlreadyExists (caller rebinds and retries)

    The response carries the AUTHORITATIVE endpoint (may differ from the
    request when Atlas rewrote to disambiguate); caller MUST use the
    returned value.

Drops:
  - AtomicU16 port pool / `next_port()` (Atlas no longer allocates ports)
  - AtlasService.data_plane_host (Atlas does not synthesize host:port)
  - resolve_endpoint impl on AtlasService (now a freestanding fn over State)
  - serve_atlas's data_plane_host arg

Atlas's responsibilities are now: storage, uniqueness checks, and name
minting for transports where minting is meaningful — nothing else.

Renamed env var ROBONIX_META_GRPC_ADDR → ROBONIX_ATLAS_LISTEN; dropped
ROBONIX_META_GRPC_ENDPOINT (no longer needed). Aligns with task #24.

Verified: `cargo check -p robonix-atlas` clean (workspace check is still
blocked by sdk/buffer/interfaces deletions in flight).
enkerewpo added a commit that referenced this pull request Apr 26, 2026
A sim stack publishes raw sensor data + accepts /cmd_vel — that's the
primitive layer. Move it from examples/webots/services/ to
examples/webots/primitives/ to match.

Also collapse the now-empty deploy manifest: drop the long preamble,
the legacy RUST_LOG / ROBONIX_META_GRPC_ENDPOINT env (covered by per-
service `log:` and tracked in #24), and the now-empty service/skill
entries that referenced packages this branch deleted (vlm_service is
embedded in pilot, memsearch lives under system/, clawhub_skills is
out of scope here).
Chenyantt pushed a commit to Chenyantt/robonix that referenced this pull request Aug 8, 2026
Two related cleanups in atlas.proto + service.rs:

(1) CapabilityInfo → CapabilityInterface, with the request/record field
    renamed `capabilities` → `interfaces`. The struct describes ONE
    capability interface (a single contract_id binding), not the whole
    instance — its old name conflated the two.

(2) DeclareInterface no longer takes `uint32 listen_port`. Port numbers
    are TCP-specific and don't belong on a transport-agnostic interface
    declaration. Replaced with a `string endpoint` that the caller
    proposes; Atlas resolves the actual stored endpoint per these rules
    (documented inline in the proto):

      empty proposal + atlas-mintable transport (ros2 / shared_memory)
                             -> Atlas mints "/rbnx/<contract>/<uuid8>"
      empty + non-mintable transport (grpc, ...)
                             -> InvalidArgument
      non-empty + no collision        -> stored verbatim
      non-empty + collision + mintable transport
                             -> Atlas appends "~<uuid8>"
      non-empty + collision + non-mintable transport
                             -> AlreadyExists (caller rebinds and retries)

    The response carries the AUTHORITATIVE endpoint (may differ from the
    request when Atlas rewrote to disambiguate); caller MUST use the
    returned value.

Drops:
  - AtomicU16 port pool / `next_port()` (Atlas no longer allocates ports)
  - AtlasService.data_plane_host (Atlas does not synthesize host:port)
  - resolve_endpoint impl on AtlasService (now a freestanding fn over State)
  - serve_atlas's data_plane_host arg

Atlas's responsibilities are now: storage, uniqueness checks, and name
minting for transports where minting is meaningful — nothing else.

Renamed env var ROBONIX_META_GRPC_ADDR → ROBONIX_ATLAS_LISTEN; dropped
ROBONIX_META_GRPC_ENDPOINT (no longer needed). Aligns with task syswonder#24.

Verified: `cargo check -p robonix-atlas` clean (workspace check is still
blocked by sdk/buffer/interfaces deletions in flight).
Chenyantt pushed a commit to Chenyantt/robonix that referenced this pull request Aug 8, 2026
A sim stack publishes raw sensor data + accepts /cmd_vel — that's the
primitive layer. Move it from examples/webots/services/ to
examples/webots/primitives/ to match.

Also collapse the now-empty deploy manifest: drop the long preamble,
the legacy RUST_LOG / ROBONIX_META_GRPC_ENDPOINT env (covered by per-
service `log:` and tracked in syswonder#24), and the now-empty service/skill
entries that referenced packages this branch deleted (vlm_service is
embedded in pilot, memsearch lives under system/, clawhub_skills is
out of scope here).
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