Skip to content

chore: promote staging to staging-promote/e805ec61-23059634819 (2026-03-13 17:11 UTC) - #1134

Merged
henrypark133 merged 29 commits into
staging-promote/e805ec61-23059634819from
staging-promote/bc672520-23062088162
Mar 16, 2026
Merged

henrypark133 merged 29 commits into
staging-promote/e805ec61-23059634819from
staging-promote/bc672520-23062088162

Conversation

@ironclaw-ci

@ironclaw-ci ironclaw-ci Bot commented Mar 13, 2026 •

Copy link
Copy Markdown
Contributor

Auto-promotion from staging CI

Batch range: 1e00b1fed50ac88f78d128e4bd4e9243cecdae3e..bc6725205ada24f26ed30fd042dc4aa6b546cb93
Promotion branch: staging-promote/bc672520-23062088162
Base: staging-promote/e805ec61-23059634819
Triggered by: Staging CI batch at 2026-03-13 17:11 UTC

Commits in this batch (4):

Current commits in this promotion (0)

Current base: staging-promote/e805ec61-23059634819
Current head: staging-promote/bc672520-23062088162
Current range: origin/staging-promote/e805ec61-23059634819..origin/staging-promote/bc672520-23062088162

  • (no non-merge commits in range)

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

ilblackdragon and others added 3 commits March 13, 2026 16:36
…1087)

Add a diff-based CI job and pre-commit hook check that block
panic-inducing calls (.unwrap(), .expect(), assert!, assert_eq!,
assert_ne!) from entering production Rust code. debug_assert is
excluded (compiled out in release). False positives can be suppressed
with an inline `// safety: <reason>` comment.

- pre-commit-safety.sh: add check 6 (PANIC) for staged diffs
- code_style.yml: add `no-panics` job, wire into roll-up gate
- check-boundaries.sh: extend check 2 to also catch assert!()

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
LLMs sometimes pass "" for optional parameters instead of omitting
them. Previously, passing timezone: "" or from_timezone: "" to the
time tool would trigger a parse error ("Unknown timezone ''") rather
than falling back to the context timezone or UTC.

Fix by adding .filter(|s| !s.is_empty()) after .as_str() in
resolve_timezone_for_output and optional_timezone, so empty strings
are treated the same as a missing field.

The same pattern exists in routine.rs (cron trigger timezone and
schedule fields), where "" produces "invalid IANA timezone: ''" or a
cron parse error. That will be addressed separately once routine.rs
has a test harness in place.

Regression tests added for the now and convert operations with
empty timezone strings.

Closes #1127
* fix(http): replace .expect() with match in webhook handler

Replace `.expect("checked is_none above")` with a proper `match` on
`webhook_secret.as_ref()`. The is_none-then-expect pattern was logically
safe but violates the project rule against .expect() in production code.

Update pre-existing test to expect SERVICE_UNAVAILABLE (503) instead of
UNAUTHORIZED (401) when the secret is cleared, since the None check now
returns early before signature verification.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(ci): formatting + suppress no-panics false positive in test

- Collapse multi-line Some() to single line per rustfmt
- Add // safety: comment on test assert_eq to suppress CI grep

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
@github-actions github-actions Bot added size: M 50-199 changed lines scope: tool/builtin Built-in tools scope: ci CI/CD workflows risk: medium Business logic, config, or moderate-risk modules contributor: experienced 6-19 merged PRs and removed size: M 50-199 changed lines labels Mar 13, 2026
ilblackdragon and others added 20 commits March 13, 2026 17:37
* fix(mcp): address 14 audit findings across MCP module

- Replace panicking assert! in new_with_config with Result return (Critical)
- Fix initialize() race condition using tokio::sync::OnceCell (High)
- Fix localhost check bypass via proper URL parsing (High)
- Extract shared stream_transport_send() to deduplicate stdio/unix send logic
- Use atomic write (tmp+rename) for config file persistence
- Filter SSE responses by request_id to prevent wrong-response dispatch
- Share a single reqwest::Client for OAuth via fallible OnceLock
- Log notification send errors instead of silently discarding
- Fix unwrap_or(0) that could steal id=0 responses
- Store InitializeResult in OnceCell so callers can access server capabilities
- Add redirect logging in OAuth discovery
- Reuse is_localhost_url() in auth.rs
- Add McpToolWrapper unit tests and regression tests
- URL-encode PKCE challenge for consistency

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* chore: retrigger CI with skip-regression-check label

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
…nsions (#1106)

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
…2433

chore: promote staging to staging-promote/7d745d54-23066609095 (2026-03-13 20:06 UTC)
* feat(web): add follow-up suggestion chips and ghost text to chat UI

The LLM now always generates 1-3 follow-up command suggestions via
<suggestions> tags in its response. These are extracted server-side,
broadcast as SSE events, and rendered as clickable chips above the
chat input. The first suggestion also appears as ghost text in the
input field (Tab to accept). Includes debug logging for LLM responses
in the agentic loop and removes noisy NEAR AI status logging.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: resolve deferred review items from PR #1156 [skip-regression-check]

- Remove literal backslashes from raw string prompt (reasoning.rs)
- Make WASM channels skip Suggestions status (no-op instead of empty callback)
- Add !e.shiftKey guard to Tab-to-accept ghost text handler
- Cap extracted suggestions at 3 and trim whitespace-only entries
- Extract suggestions in approval-resume path (prevents tag leaking)
- Remove stale .has-ghost class during showSuggestionChips reset

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* refactor(registry): move MCP server entries from code to JSON manifests

Move 8 hardcoded MCP server RegistryEntry structs from
builtin_entries() into data-driven JSON files under
registry/mcp-servers/, matching the existing pattern used by
tools and channels. Exclude the GitHub MCP entry which conflicts
with the WASM GitHub tool's OAuth flow.

Extend ManifestKind with McpServer, make version/source optional
on ExtensionManifest (MCP servers don't need them), and add
url/auth fields for MCP-specific config. Update build.rs,
embedded catalog, catalog loader, installer, and CLI display
to handle the new kind and optional fields.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(registry): address PR review — add missing slack-mcp, remove .expect(), fix fmt

- Add missing slack-mcp.json (was dropped during migration)
- Remove production .expect() in get_strict(), replace with .ok_or_else()
- Clean up unwrap_or_default() in key_for() to use .next() directly
- Log warning for MCP manifests missing url field instead of silent empty
- Run cargo fmt to fix formatting diffs

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* ci: re-trigger CI with correct base branch (staging)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(ci): improve no-panics check to properly exclude test modules

The grep-based filter only excluded lines literally containing
#[cfg(test)], #[test], or 'mod tests' — not lines *inside* test
modules. Use awk to track hunk context from diff @@ headers and
skip all added lines within test module hunks.

[skip-regression-check]

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* refactor(registry): remove slack-mcp MCP entry (conflicts with WASM slack tool)

Remove slack-mcp.json alongside the already-excluded github MCP
entry — both conflict with existing WASM tools of the same name.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(registry): address re-review — skip invalid MCP entries, fix install order

- to_registry_entry() now returns Option<RegistryEntry>; MCP manifests
  missing a url field are skipped with a warning instead of creating
  broken entries with empty URLs
- Move McpServer early-return before require_source() in install paths
  so the error message is clear ("cannot install MCP servers") rather
  than the misleading "missing source spec"
- Add test for MCP manifest with missing URL returning None

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…header, docs inconsistency and security concern (#1162)

Implement industry-standard HMAC-SHA256 header-based webhook authentication
to resolve issue #722. The X-Hub-Signature-256 header follows GitHub's
webhook security model, replacing the non-standard X-IronClaw-Signature header.

**Changes:**
- Rename HTTP webhook signature header from X-IronClaw-Signature to X-Hub-Signature-256
- X-Hub-Signature-256 is the standard used by GitHub, Stripe, and other webhook providers
- HMAC-SHA256 signatures continue to use sha256=<hex> format
- Body 'secret' field remains supported as deprecated fallback for backward compatibility
- All error messages and documentation updated to reflect new header name

**Security impact:**
- Signatures verified via HTTP header instead of request body
- Signature visible in Authorization header only, not logged in request body
- Follows industry best practices for webhook authentication
- Fail-closed policy: rejects requests without authentication

**Backward compatibility:**
- Requests without X-Hub-Signature-256 header fall back to 'secret' field in body (with deprecation warning)
- Deprecation path: migrate to header-based auth, body field support will be removed in a future release

**Test coverage:**

Unit tests (20 tests in src/channels/http.rs):
- 6 header-based auth tests (valid/invalid/malformed signatures, header encoding)
- 2 backward compatibility tests (deprecated body secret fallback)
- 3 error handling tests (missing auth, invalid JSON, content-type validation)
- 4 signature verification unit tests (valid digest, invalid digest, missing prefix, invalid hex)
- 5 advanced tests (concurrency, dynamic updates, header precedence, no deadlocks, runtime clearing)

E2E tests (12 tests in tests/e2e/scenarios/test_webhook.py):
- Valid HMAC-SHA256 signature acceptance
- Invalid/wrong/malformed signature rejection
- Header precedence over body secret
- Deprecated body secret backward compatibility
- Missing auth rejection (fail-closed)
- Content-Type validation
- Invalid JSON handling
- Case-insensitive header lookup
- Message queuing and processing
- Fixture for running server with HTTP_WEBHOOK_SECRET configured

All 3,033 lib tests pass with zero clippy warnings.

**Example usage after fix:**

BODY='{"content": "hello"}'
SECRET="your-webhook-secret"
SIG=$(echo -n "$BODY" | openssl dgst -sha256 -hmac "$SECRET" | sed 's/^.* //')

curl -X POST http://127.0.0.1:9090/webhook \
  -H "Content-Type: application/json" \
  -H "X-Hub-Signature-256: sha256=$SIG" \
  -d "$BODY"

Co-authored-by: Claude Haiku 4.5 <noreply@anthropic.com>
…th (#1164)

* fix: Google Sheets returns 403 PERMISSION_DENIED after completing OAuth

* fix: linter

* fix: linter

* fix: ci

* fix

* fix

* fix

* fix
Python bytecode cache files were accidentally committed. Remove them
from tracking and prevent future occurrences via .gitignore.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(webhook): avoid holding mutex across async shutdown

* test(webhook): add regression coverage for begin_shutdown split path

* test(webhook): satisfy no-panics rule in begin_shutdown regression
#1161)

* fix: Non-transactional multi-step context updates between metadata/token setup and DB

* fix: code style
…1172)

* perf(routines): bound tool-loop history snapshot clone cost

* test(ci): annotate snapshot assertions for no-panics matcher

* test(ci): keep no-panics suppression on single-line assertion

* test(ci): keep snapshot tail assert single-line for no-panics

* Update src/agent/routine_engine.rs

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>

* chore(deps): bump yanked uds_windows in lockfile for cargo-deny

---------

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
* fix(channels): use live owner binding during wasm hot activation

* test(channels): cover owner-id store fallback without panic macros
* fix(llm): add stop_sequences parity for tool completions

* refactor(web-openai): dedupe request builders and satisfy no-panics gate

* test(llm): mark multiline assert with safety comment for CI gate

* test(llm): make safety-marked assert formatting-stable
* fix: N+1 query pattern in event trigger loop (routine_engine)

* fix: linter
* feat(routines): render cron triggers as human-readable summaries

* test(routines): annotate multiline cron assertions for no-panics CI

* test(routines): avoid multiline assert lint false positives
Fixes cargo-deny CI failure due to yanked crate.
[skip-regression-check]

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…5848

chore: promote staging to staging-promote/579c4fdb-23095333790 (2026-03-14 21:05 UTC)
…3790

chore: promote staging to staging-promote/17706632-23094430993 (2026-03-14 20:03 UTC)
…0993

chore: promote staging to staging-promote/f9b880c2-23080458788 (2026-03-14 19:08 UTC)
…8788

chore: promote staging to staging-promote/7d745d54-23066609095 (2026-03-14 04:31 UTC)
…9095

chore: promote staging to staging-promote/f53c1bb1-23064256940 (2026-03-13 19:12 UTC)
…6940

chore: promote staging to staging-promote/bc672520-23062088162 (2026-03-13 18:08 UTC)
@henrypark133
henrypark133 merged commit 4c7afdb into staging-promote/e805ec61-23059634819 Mar 16, 2026
13 of 14 checks passed
@github-actions github-actions Bot added scope: agent Agent core (agent loop, router, scheduler) scope: channel Channel infrastructure scope: channel/cli TUI / CLI channel scope: channel/web Web gateway channel scope: channel/wasm WASM channel runtime scope: tool/wasm WASM tool sandbox scope: tool/mcp MCP client scope: db Database trait / abstraction scope: db/postgres PostgreSQL backend scope: llm LLM integration scope: orchestrator Container orchestrator scope: worker Container worker scope: extensions Extension management scope: dependencies Dependency updates size: XL 500+ changed lines labels Mar 16, 2026
@henrypark133
henrypark133 deleted the staging-promote/bc672520-23062088162 branch March 16, 2026 14:52
@github-actions github-actions Bot added contributor: core 20+ merged PRs and removed contributor: experienced 6-19 merged PRs labels Mar 16, 2026
bkutasi pushed a commit to bkutasi/ironclaw that referenced this pull request Mar 28, 2026
…3062088162

chore: promote staging to staging-promote/e805ec61-23059634819 (2026-03-13 17:11 UTC)
drchirag1991 pushed a commit to drchirag1991/ironclaw that referenced this pull request Apr 8, 2026
…3062088162

chore: promote staging to staging-promote/4524fee0-23059634819 (2026-03-13 17:11 UTC)
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: agent Agent core (agent loop, router, scheduler) scope: channel/cli TUI / CLI channel scope: channel/wasm WASM channel runtime scope: channel/web Web gateway channel scope: channel Channel infrastructure scope: ci CI/CD workflows scope: db/postgres PostgreSQL backend scope: db Database trait / abstraction scope: dependencies Dependency updates scope: extensions Extension management scope: llm LLM integration scope: orchestrator Container orchestrator scope: tool/builtin Built-in tools scope: tool/mcp MCP client scope: tool/wasm WASM tool sandbox scope: worker Container worker size: XL 500+ changed lines staging-promotion

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants