Skip to content

chore: promote staging to staging-promote/c8f87537-24658689024 (2026-04-20 14:07 UTC) - #2733

Merged
henrypark133 merged 1 commit into
mainfrom
staging-promote/038853f8-24671092908
Apr 21, 2026
Merged

henrypark133 merged 1 commit into
mainfrom
staging-promote/038853f8-24671092908

Conversation

@ironclaw-ci

@ironclaw-ci ironclaw-ci Bot commented Apr 20, 2026 •

Copy link
Copy Markdown
Contributor

Auto-promotion from staging CI

Batch range: 7fb41555a9e55677d1aaea29ca567a5b369c2b05..038853f8ee651cce156565aab9a50294f550d778
Promotion branch: staging-promote/038853f8-24671092908
Base: staging-promote/c8f87537-24658689024
Triggered by: Staging CI batch at 2026-04-20 14:07 UTC

Commits in this batch (42):

Current commits in this promotion (1)

Current base: staging-promote/c8f87537-24658689024
Current head: staging-promote/038853f8-24671092908
Current range: origin/staging-promote/c8f87537-24658689024..origin/staging-promote/038853f8-24671092908

Auto-updated by staging promotion metadata workflow

Waiting for gates:

  • Tests: pending
  • E2E: pending
  • Claude Code review: pending (will post comments on this PR)

Auto-created by staging-ci workflow

…2681)

* refactor(types): adopt MissionId in router + introduce McpServerName

- src/bridge/router.rs response DTO now uses engine's MissionId(Uuid)
  instead of String
- McpServerName newtype in ironclaw_common encapsulates the allowlist
  validation added in #2400

Closes the type gap for two identifiers flagged in the recent
audit of string-typed values in the system.

* refactor(mcp): address review feedback — validate server names at construction

- McpClient::new and new_with_name: validate through McpServerName::new
  with a canonical "unknown" fallback + debug log, instead of
  from_trusted. Closes two HIGH-severity allowlist bypasses (e.g. IPv6
  bracketed hosts and caller-supplied bad names).
- McpClient::new: apply the same hyphen→underscore fold as the other
  constructors (only when a hyphen is present) for consistency.
- identity.rs: extract validate_mcp_server_name() helper so
  TryFrom<String> consumes the owned buffer without re-allocating;
  MAX_MCP_SERVER_NAME_LEN aliased to MAX_NAME_LEN to prevent drift.
- factory.rs: capture validated McpServerName and thread .as_str()
  through hottest downstream uses; TODO left for full threading.
- Adds regression tests covering the IPv6-host and invalid-caller-name
  paths against the caller (McpClient::new / new_with_name).

* fix(mcp): annotate panic-safe McpServerName::new("unknown") .expect() calls

The no-panics CI check flagged two `.expect()` calls on `McpServerName::new("unknown")`
fallbacks inside `McpClient::new` and `McpClient::new_with_name`. The literal
`"unknown"` always satisfies the alnum-only validation rule, so the call is
infallible. Document that with an inline `// safety: ...` comment per the
project's panic-check suppression convention.

* refactor(mcp): validate HttpMcpTransport::new server_name with safe fallback

* refactor(mcp): validate McpClient constructor server names with safe fallback

Address PR #2681 Copilot review comments 3108427003,
3108427048, and 3108427073. The three remaining constructors
(`new_with_transport`, `new_with_config`, `new_authenticated`) were
wrapping caller-provided names with `McpServerName::from_trusted`,
allowing invalid values to enter the typed field.

Beyond bypassing the allowlist, the `_with_config` and `_authenticated`
paths also diverged from `HttpMcpTransport::new`, which independently
validates and falls back to `"unknown"` — so an invalid name could
leave the client keyed one way and the transport another, silently
breaking `Mcp-Session-Id` tracking.

Each constructor now runs the same canonicalize-with-fallback pattern
used by `McpClient::new`, `new_with_name`, and `HttpMcpTransport::new`,
and threads the single validated name into both the transport and the
client's typed field so the two cannot diverge.

Regression tests added (per .claude/rules/testing.md, "Test Through
the Caller"): invalid config/transport inputs fall back to "unknown";
valid inputs survive; client and transport names agree for both cases.

* fix(mcp): migrate legacy overlong server names at load instead of dropping

Address PR #2681 review comment 3110617080. Before the
`McpServerName` newtype landed, `McpServerConfig::validate()` only
enforced non-empty + `[A-Za-z0-9_-]`. Delegating validation to
`McpServerName::new` added a 64-byte length cap — and `load_mcp_servers_from*`
silently dropped invalid configs via `retain(...)`, so a legacy persisted
server name >64 bytes would vanish from the loaded config on upgrade.

The load paths now in-place truncate overlong names at a char boundary
(safe even if the pre-validation string contains multi-byte UTF-8),
emit a `warn!` documenting the migration, and let the (now
cap-satisfying) entry pass validation. Invalid-char cases still drop
via `retain`, matching the pre-PR behavior for that class.

Regression tests cover both the happy path (ASCII overlong name kept,
truncated to exactly the cap) and char-boundary safety (multi-byte
sequence straddling byte 64 must not panic).
@github-actions github-actions Bot added scope: tool/mcp MCP client size: XL 500+ changed lines risk: medium Business logic, config, or moderate-risk modules contributor: core 20+ merged PRs labels Apr 20, 2026
@claude

claude Bot commented Apr 20, 2026

Copy link
Copy Markdown

Code review

Found 4 issues:

  1. [HIGH:95] Unnecessary string allocation in hot tool-iteration loop — line 768-779 in src/tools/mcp/client.rs

The code calls .as_str().to_string() for each tool when populating the cache:

provider_extension: self.server_name.as_str().to_string(),

Since McpServerName implements Clone, this should use .clone() instead to avoid allocating on each iteration (a few dozen times per server). With 30-50 tools per MCP server, this creates unnecessary heap pressure during tool initialization.

https://github.com/anthropics/ironclaw/blob/0a98a96c13d87b1e26e67d9cb0a99fad3fef4302/src/tools/mcp/client.rs#L768-L779

  1. [MEDIUM:75] DRY violation — fallback validation boilerplate repeated 6+ times across MCP module

The pattern appears identically in McpClient::new, new_with_name, new_with_config, new_authenticated, new_with_transport, and HttpMcpTransport::new:

McpServerName::new(&raw).unwrap_or_else(|e| {
    tracing::debug!(...);
    McpServerName::new("unknown")
        .expect("'unknown' is a valid...")
})

Recommend extracting to a helper method (e.g., McpServerName::with_fallback(raw: &str) -> Self) to reduce duplication and ensure consistency.

  1. [MEDIUM:50] Incomplete type migration creates temporal coupling with follow-up PR

The code has TODO comments indicating that McpServerConfig.name should become McpServerName in PR 4/4. Until that lands, the factory must clone String and re-validate at multiple steps. This is mitigated by the fallback pattern, but represents temporary architectural debt.

https://github.com/anthropics/ironclaw/blob/0a98a96c13d87b1e26e67d9cb0a99fad3fef4302/src/tools/mcp/factory.rs#L710-L720

  1. [LOW:70] Inconsistent micro-optimization in hyphen replacement — lines 699, 138-139, 110-113 in src/tools/mcp/client.rs and factory.rs

Line 111 checks if name_str.contains('-') before calling .replace(), but lines 138-139 and factory.rs:699 do not. Standardize to avoid allocations when hyphens are absent.

https://github.com/anthropics/ironclaw/blob/0a98a96c13d87b1e26e67d9cb0a99fad3fef4302/src/tools/mcp/client.rs#L110-L113

Overall: The PR is well-architected and security-sound. All issues are improvements to reduce duplication and allocations; no bugs or security vulnerabilities detected.

🤖 Generated with Claude Code

Base automatically changed from staging-promote/c8f87537-24658689024 to main April 21, 2026 03:18
@henrypark133
henrypark133 merged commit 038853f into main Apr 21, 2026
52 of 67 checks passed
@henrypark133
henrypark133 deleted the staging-promote/038853f8-24671092908 branch April 21, 2026 03:18

This branch had an error being deployed

1 failed and 5 inactive deployments
cosmose-ironclaw / production — 038853f8 Deployed Apr 20, 2026 by railway-app[bot]
Ironclaw-QA / production — 038853f8 Deployed Apr 20, 2026 by railway-app[bot]
ironclaw-nearai / production — 038853f8 Deployed Apr 20, 2026 by railway-app[bot]
venice-ironclaw / production — 038853f8 Deployed Apr 20, 2026 by railway-app[bot]
humble-cat / staging-cameron — 038853f8 Deployed Apr 20, 2026 by railway-app[bot]
Near Foundation Ironclaw / production — 038853f8 Deployed Apr 20, 2026 by railway-app[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

contributor: core 20+ merged PRs risk: medium Business logic, config, or moderate-risk modules scope: tool/mcp MCP client size: XL 500+ changed lines staging-promotion

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants