refactor(core): validate object shapes at boundaries - #6640
Conversation
Signed-off-by: Carlos Villela <cvillela@nvidia.com>
📝 WalkthroughWalkthroughThis change centralizes object-shape type guards, distinguishing general object records from plain objects. The guards are applied across Hermes, NemoClaw, messaging, state, registry, OpenClaw merge, scripts, tooling, and tests, with registry persistence behavior additionally updated and covered by new tests. ChangesObject-shape validation
Estimated code review effort: 4 (Complex) | ~45 minutes Possibly related PRs
Suggested labels: Suggested reviewers: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
Code Coverage OverviewLanguages: TypeScript TypeScript / code-coverage/pluginThe overall coverage in the Show a code coverage summary of the most impacted files.
TypeScript / code-coverage/cliThe overall coverage in the Show a code coverage summary of the most impacted files.
Updated |
E2E Advisor RecommendationRequired E2E: Dispatch hint: Full advisor summaryE2E Recommendation AdvisorBase: Required E2E
Optional E2E
New E2E recommendations
Dispatch hint
|
E2E Target RecommendationRequired E2E targets: Dispatch required E2E targets:
Full E2E target advisor summaryE2E Target AdvisorBase: Required E2E targets
Optional E2E targets
Relevant changed files
|
PR Review Advisor — No blocking findingsMerge posture: No blocking advisor findings Action checklist
Test follow-ups to resolve or justifyIf these cover changed behavior, prefer adding them in this PR; otherwise state why existing coverage is enough or link the follow-up.
This is an automated, non-binding review; it still expects maintainers and agents to respond to each required or warning item. Treat suggestions as current-PR improvements when they touch changed code; defer only with maintainer rationale or a linked follow-up. A human maintainer must make the final merge decision. |
PR Review Advisor (Nemotron Ultra) — No blocking findingsMerge posture: No blocking advisor findings Action checklist
Test follow-ups to resolve or justifyIf these cover changed behavior, prefer adding them in this PR; otherwise state why existing coverage is enough or link the follow-up.
This is an automated, non-binding review; it still expects maintainers and agents to respond to each required or warning item. Treat suggestions as current-PR improvements when they touch changed code; defer only with maintainer rationale or a linked follow-up. A human maintainer must make the final merge decision. |
Signed-off-by: Carlos Villela <cvillela@nvidia.com>
|
PR Review Advisor follow-up:
|
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/lib/messaging/channels/teams/hooks/host-forward-port-conflict.ts (1)
211-229: 📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick winExtract duplicated
parseRegistryEntriesinto a shared helper.The guard swap to
isObjectRecordis fine, but this whole function (and itsTeamsHostForwardPortConflictRegistryEntry-shaped type) is duplicated verbatim insrc/lib/messaging/channels/slack/hooks/socket-mode-gateway-conflict.tsandsocket-mode-gateway-status.ts. Consolidating into a shared messaging-hook utility would avoid future drift between channels for this security-relevant registry-entry parsing.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/lib/messaging/channels/teams/hooks/host-forward-port-conflict.ts` around lines 211 - 229, Extract the duplicated parseRegistryEntries logic and its registry-entry type into a shared messaging-hook utility, then import and reuse that helper from the Teams hook and both Slack hooks (socket-mode-gateway-conflict.ts and socket-mode-gateway-status.ts). Preserve the existing isObjectRecord validation, name checks, and messaging.plan extraction so all channels use identical parsing behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@scripts/install.sh`:
- Around line 1710-1712: Update isObjectRecord or the associated registry-name
validation around entry.name to reject names that are empty or contain only
whitespace, using a trimmed-value check before accepting the record. Ensure the
validation used by upgrade/count decisions enforces the nonblank-name invariant.
---
Outside diff comments:
In `@src/lib/messaging/channels/teams/hooks/host-forward-port-conflict.ts`:
- Around line 211-229: Extract the duplicated parseRegistryEntries logic and its
registry-entry type into a shared messaging-hook utility, then import and reuse
that helper from the Teams hook and both Slack hooks
(socket-mode-gateway-conflict.ts and socket-mode-gateway-status.ts). Preserve
the existing isObjectRecord validation, name checks, and messaging.plan
extraction so all channels use identical parsing behavior.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Enterprise
Run ID: ab486c12-6553-4a65-9f51-f580f18454ed
📒 Files selected for processing (55)
agents/hermes/config/build-env.tsagents/hermes/config/hermes-config.tsagents/hermes/config/model-specific-setup.tsagents/hermes/config/object-record.tsnemoclaw/src/blueprint/runner.tsnemoclaw/src/blueprint/state.tsnemoclaw/src/commands/migration-state.tsnemoclaw/src/onboard/config.tsnemoclaw/src/shared/object-record.test.tsnemoclaw/src/shared/object-record.tsscripts/bench/lib.tsscripts/check-test-file-size-budget.tsscripts/install.shscripts/patch-openclaw-tool-catalog.jsscripts/validate-openclaw-tool-search.mtssrc/lib/agent/manifest-readers.tssrc/lib/agent/runtime-manifest.tssrc/lib/core/json-types.test.tssrc/lib/core/json-types.tssrc/lib/messaging/applier/agent-config.tssrc/lib/messaging/applier/setup-applier.tssrc/lib/messaging/channels/openclaw-bridge-health.tssrc/lib/messaging/channels/slack/hooks/socket-mode-gateway-conflict.tssrc/lib/messaging/channels/slack/hooks/socket-mode-gateway-status.tssrc/lib/messaging/channels/teams/hooks/host-forward-port-conflict.tssrc/lib/messaging/channels/telegram/hooks/get-me-reachability.tssrc/lib/messaging/channels/telegram/hooks/openclaw-bridge-health.tssrc/lib/messaging/compiler/engines/agent-render-engine.tssrc/lib/messaging/plan-validation.tssrc/lib/onboard/agents-manifest.tssrc/lib/onboard/initial-policy.tssrc/lib/openclaw/agent-json-provenance.tssrc/lib/policy/preset-parsing.tssrc/lib/policy/tiers.tssrc/lib/security/credential-filter.tssrc/lib/shields/index.tssrc/lib/shields/timer-control.tssrc/lib/shields/timer.tssrc/lib/skill-install.tssrc/lib/state/onboard-session.tssrc/lib/state/openclaw-config-merge.test.tssrc/lib/state/openclaw-config-merge.tssrc/lib/state/openclaw-plugin-restore.tssrc/lib/state/registry-mcp.tssrc/lib/state/registry-normalization.test.tssrc/lib/state/registry.tssrc/lib/state/sandbox.tssrc/lib/status-command-deps.tssrc/lib/tunnel/services.tstest/credential-rotation.test.tstest/e2e/registry/manifests.tstest/messaging-plan-test-helper.tstools/advisors/json.mtstools/e2e-advisor/post-merge-risk-gate.mtstools/pr-review-advisor/analyze.mts
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/lib/state/registry-normalization.ts`:
- Around line 27-30: Update the default sandbox validation logic to verify that
defaultSandbox is an own property of sandboxes before reading
sandboxes[defaultSandbox]. In the relevant normalization function, use an
ownership check such as Object.prototype.hasOwnProperty.call, then retain the
existing entry and pendingRouteReservation checks.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Enterprise
Run ID: 78a5e903-dd3f-44d4-a44e-4df144d87091
📒 Files selected for processing (2)
src/lib/state/registry-normalization.tssrc/lib/state/registry.ts
🚧 Files skipped from review as they are similar to previous changes (1)
- src/lib/state/registry.ts
Signed-off-by: Carlos Villela <cvillela@nvidia.com>
Signed-off-by: Carlos Villela <cvillela@nvidia.com>
<!-- markdownlint-disable MD041 --> ## Summary Consolidate ambiguous `isRecord` predicates into explicit `isObjectRecord` and `isPlainObject` helpers, then keep those checks at real trust boundaries. Serialized YAML, JSON, environment, and process data is validated once into a domain type; internal TypeScript paths trust that type instead of defensively rechecking it. This also hardens malformed sandbox-registry normalization without changing supported user-facing configuration. ## Changes - Add shared object-record helpers and semantic tests for the CLI, plugin, and Hermes compilation boundaries; retain the immutable integrity-pinned credential helper unchanged. - Decode messaging setup plans once through the canonical `parseSandboxMessagingPlan` boundary, removing the duplicate plan validator, nine typed-plan rechecks, and the custom recursive JSON-serializability walk. - Read the sandbox registry as `unknown`, validate its object shape and entries during load, and let typed serialization iterate `SandboxRegistry` directly. - Refine the OpenShell policy parser's return type so the runner can trust validated `version` and `network_policies` fields. - Remove object checks made redundant by TypeScript narrowing, successful native `import()`, and prior Hermes plan narrowing. - Require registry entry names to be nonblank and match their map keys, preserve stale-default diagnostics, and repair invalid defaults with the correct ownership revision on persistence. - Reject non-plain prototype objects at the OpenClaw config-merge boundary, where prototype identity is a real runtime invariant. ## Type of Change - [x] Code change (feature, bug fix, or refactor) - [ ] Code change with doc updates - [ ] Doc only (prose changes, no code sample modifications) - [ ] Doc only (includes code sample changes) ## Quality Gates <!-- Check exactly one tests line and one docs line. Check other lines when applicable. Add every requested justification or approval reference. --> - [x] Tests added or updated for changed behavior - [ ] Existing tests cover changed behavior — justification: - [ ] Tests not applicable — justification: - [ ] Docs updated for user-facing behavior changes - [x] Docs not applicable — justification: a documentation-writer review confirmed that commands, flags, supported configuration, persisted schemas, and workflows are unchanged; the changes are internal boundary/type semantics. - [x] Sensitive paths changed (security, policy, credentials, preflight, onboarding, inference, runner, sandbox, or messaging) - [x] Sensitive-path review completed or maintainer-approved waiver recorded — reviewer/approval link/justification: a full provenance audit classified each guard by input source, retained checks at external boundaries, and removed only checks proven redundant by validated domain types or language/runtime guarantees; CodeQL, CodeRabbit, and both PR review advisors pass on the final commit. - [ ] Non-success, skipped, or missing CI check accepted by maintainer — check name, approval link, and follow-up issue: ## Verification <!-- Check each applicable item only when supported by the requested evidence. Run targeted tests once per relevant change set and rerun after later edits or hook autofixes that can affect that behavior. Do not rerun hook-covered checks. --> - [x] PR description includes the DCO sign-off declaration and every commit appears as `Verified` in GitHub - [x] Normal `pre-commit`, `commit-msg`, and `pre-push` hooks passed, or `npm run check:diff` passed when hooks were skipped or unavailable - [x] Targeted behavior tests pass for the current change set, or tests are marked not applicable above — command/result or justification: final focused suites passed 80 CLI tests, 55 integration tests, and 117 plugin tests; the previously flaky gateway-recovery file passed 11/11 locally. - [x] Applicable broad gate passed — `npm test` for broad runtime/test-harness changes; `npm run check` for repo-wide validation/coverage changes — command/result: `env -u SSH_CONNECTION -u SSH_CLIENT -u SSH_TTY npm run check` passed on final commit `af7907afc`, including full CLI/integration and plugin coverage. - [x] Quality Gates section completed with required justifications or waivers - [x] No secrets, API keys, or credentials committed - [ ] `npm run docs` builds without warnings (doc changes only) - [ ] Doc pages follow the [style guide](https://github.com/NVIDIA/NemoClaw/blob/main/docs/CONTRIBUTING.md) (doc changes only) - [ ] New doc pages include SPDX header and frontmatter (new pages only) --- <!-- DCO sign-off is required in this PR description, and every commit must appear as Verified in GitHub. Run: git config user.name && git config user.email --> Signed-off-by: Carlos Villela <cvillela@nvidia.com> <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Improved and standardized validation for configuration, manifests, policies, messaging plans, and runtime data. * Rejected malformed or non-plain object shapes more consistently across parsing and merge flows. * Prevented stale sandbox default selections from being persisted, with stricter registry entry handling during normalization and merges. * Tightened enablement checks and serialization behavior for persisted registry state. * **Tests** * Added tests for object-record/plain-object guards. * Added/updated coverage for sandbox registry normalization and invalid config/merge inputs. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Signed-off-by: Carlos Villela <cvillela@nvidia.com>
Summary
Consolidate ambiguous
isRecordpredicates into explicitisObjectRecordandisPlainObjecthelpers, then keep those checks at real trust boundaries. Serialized YAML, JSON, environment, and process data is validated once into a domain type; internal TypeScript paths trust that type instead of defensively rechecking it.This also hardens malformed sandbox-registry normalization without changing supported user-facing configuration.
Changes
parseSandboxMessagingPlanboundary, removing the duplicate plan validator, nine typed-plan rechecks, and the custom recursive JSON-serializability walk.unknown, validate its object shape and entries during load, and let typed serialization iterateSandboxRegistrydirectly.versionandnetwork_policiesfields.import(), and prior Hermes plan narrowing.Type of Change
Quality Gates
Verification
Verifiedin GitHubpre-commit,commit-msg, andpre-pushhooks passed, ornpm run check:diffpassed when hooks were skipped or unavailablenpm testfor broad runtime/test-harness changes;npm run checkfor repo-wide validation/coverage changes — command/result:env -u SSH_CONNECTION -u SSH_CLIENT -u SSH_TTY npm run checkpassed on final commitaf7907afc, including full CLI/integration and plugin coverage.npm run docsbuilds without warnings (doc changes only)Signed-off-by: Carlos Villela cvillela@nvidia.com
Summary by CodeRabbit