Skip to content

feat: Phase 3 - Registry & Compatibility#5

Merged
ric03uec merged 19 commits intomainfrom
gsd/phase-03-registry-compatibility
Mar 22, 2026
Merged

feat: Phase 3 - Registry & Compatibility#5
ric03uec merged 19 commits intomainfrom
gsd/phase-03-registry-compatibility

Conversation

@ric03uec
Copy link
Owner

@ric03uec ric03uec commented Mar 21, 2026

Summary

  • Implement claw registry system with manifest loading via importlib.resources
  • Add OS detection to HardwareInfo from Ansible facts
  • Create sparse matrix compatibility checking with specific failure reasons
  • Add clm registry list and clm registry show CLI commands
  • Include OpenClaw (x86_64) and ZeroClaw (Raspberry Pi/ARM) manifests
  • Security hardening: path traversal prevention, Rich markup escaping

Requirements Completed

ID Description Status
REG-01 System loads claw manifests from registry
REG-02 User can list available claw types
REG-03 System validates claw compatibility vs host

Test plan

  • uv run clm registry list shows openclaw and zeroclaw
  • uv run clm registry show openclaw displays platform matrix
  • uv run clm registry show zeroclaw shows Raspberry Pi support
  • All tests pass (make test)
  • Manual test: clm host info kevin + verify zeroclaw compatibility

ATX Review History

Review 1: Rating 2/5

Fixed:

  • Path traversal via claw_name → validate_claw_name() added
  • Rich markup injection → escape() wrapper
  • Uncaught ManifestParseError → exception handler
  • Raspbian vs Debian mismatch → changed to debian
  • None OS crash → or fallback
  • Dead dependency code → removed

Review 2: Rating 3/5

Fixed:

  • ManifestParseError in list_registry loop
  • is_relative_to() in keys.py (was startswith)
  • Specific exceptions in ssh_connection.py
  • Table row escaping in registry CLI

Review 3: Rating 3/5

Blocking (pre-existing, outside Phase 3):

  1. hosts.py TOCTOU race in add_host/remove_host
  2. ssh_connection.py key saved after network error
  3. cli/host.py TOFU not re-verified in host init

Blocking (Phase 3):
4. Registry CLI tests need mocking

Recommendation: Merge Phase 3, file issues for #1-3 tech debt.


🤖 Generated with Claude Code

Co-Authored-By: @atx-ci 269048218+atx-ci@users.noreply.github.com

Devashish and others added 19 commits March 21, 2026 15:14
4 plans in 2 waves:
- Wave 1: 03-01 (registry loader), 03-02 (OS detection)
- Wave 2: 03-03 (compatibility check), 03-04 (CLI commands)

Requirements covered:
- REG-01: System loads claw manifests from registry
- REG-02: User can list available claw types (clm registry list/show)
- REG-03: System validates claw compatibility against host capabilities

Key decisions honored from CONTEXT.md:
- D-01 through D-06: YAML manifest structure with sparse matrix
- D-07 through D-09: OS detection via Ansible facts
- D-10 through D-13: Binary pass/fail compatibility with specific reasons
- D-14 through D-16: Rich table CLI output

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Test OS field extraction from ansible_distribution (lowercased)
- Test os_version field extraction from ansible_distribution_version
- Test default to 'unknown' when OS facts missing
- Test gather_hardware includes OS fields in result

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add pyyaml>=6.0.0 and packaging>=24.0 dependencies
- Create platform.registry package structure
- Add OpenClaw manifest with Ubuntu 24.04 and 22.04 entries
- Implement load_manifest(), list_claws(), get_claw_info() functions
- Add ManifestNotFoundError and ManifestParseError exceptions
- Use importlib.resources for bundled manifest access
- Extend HardwareInfo TypedDict with os and os_version fields
- Extract ansible_distribution to os field (lowercased)
- Extract ansible_distribution_version to os_version field
- Default to 'unknown' when OS facts are missing
- Update docstring to include os and os_version in return values

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add CompatibilityResult TypedDict for check results
- Implement check_compatibility() function with sparse matrix matching
- Validate OS, OS version, architecture, memory, and GPU requirements
- Use packaging.specifiers for dependency version checking
- Provide specific failure reasons for incompatibilities
- All 8 compatibility tests passing
- VERIFICATION.md: All 12 must-haves passed
- STATE.md: Phase 03 complete, advancing to phase 04
- Requirements REG-01, REG-02, REG-03 all satisfied

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Supports raspbian 11/12 on armv7l (Raspberry Pi)
- Supports ubuntu 22.04/24.04 on aarch64
- Lightweight requirements: 1GB RAM, no GPU required
- Dependencies: python >=3.9, nodejs >=18

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add validate_claw_name() to prevent path traversal in registry loading
- Escape Rich markup in CLI to prevent injection from manifest fields
- Catch ManifestParseError and InvalidClawNameError in CLI show command
- Fix None OS crash in hardware.py with 'or' fallback
- Use .get() with defaults for requirements dict access
- Remove dead _check_dependency_version function (TODO for future)
- Change zeroclaw manifest from raspbian to debian (matches Ansible facts)
- Wrap Version() parsing in try/except InvalidVersion

ATX Review Summary
Review 1: Rating 2/5
Blocking issues fixed:
| # | Issue | Fix |
|---|-------|-----|
| 1 | Path traversal via claw_name | Added validate_claw_name() with regex |
| 2 | Rich markup injection | Added escape() wrapper |
| 3 | Uncaught ManifestParseError | Added except block in show() |

Warnings addressed:
- Raspbian vs Debian mismatch: Changed to debian
- Dead dependency checking: Removed, added TODO
- None OS crash: Fixed with 'or' fallback
- Unguarded dict access: Added .get() defaults

Remaining (for next session):
- Fake tests need rewriting (4, 5)
- Add zeroclaw to test assertions

Co-Authored-By: @atx-ci <269048218+atx-ci@users.noreply.github.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- B1: Catch ManifestParseError in list_registry() loop
- B2: (deferred - needs RegistryUnavailableError design)
- B3: Use is_relative_to() instead of startswith() in keys.py
- B4: Replace bare except with specific (socket.timeout, OSError), raise auth_timeout to 5s
- W2: Escape all manifest fields in table rows

ATX Review Summary
Review 2: Rating 3/5
Blocking issues fixed: B1, B3, B4
Remaining for next session: B2, B5, B6 (test coverage)

Co-Authored-By: @atx-ci <269048218+atx-ci@users.noreply.github.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@ric03uec ric03uec merged commit 8568ee8 into main Mar 22, 2026
1 check passed
@ric03uec ric03uec deleted the gsd/phase-03-registry-compatibility branch March 22, 2026 02:57
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.

1 participant