Skip to content

Finish the production Iroh transport rollout - #8484

Merged
azooz2003-bit merged 86 commits into
mainfrom
feat-iroh-final-integration
Jul 19, 2026
Merged

azooz2003-bit merged 86 commits into
mainfrom
feat-iroh-final-integration

Conversation

@azooz2003-bit

@azooz2003-bit azooz2003-bit commented Jul 19, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

  • make authenticated Iroh the default cmux iOS transport with zero-touch same-account discovery
  • keep Tailscale and other private networks as authenticated Iroh path hints, plus old-iOS-to-new-Mac compatibility
  • add server-driven managed relay policy, custom relay preferences, and debug relay-only/direct-only modes
  • harden endpoint binding, challenges, grants, relay credentials, direct UDP ports, reconnect lifecycle, and redacted diagnostics
  • add a real isolated iOS release gate covering terminal, workspace, events, notifications, chat, and artifacts

Verification

  • shared Iroh transport: 407 tests passed
  • web trust and relay policy: 131 tests passed
  • isolated iOS zero-touch reconnect: passed across a force relaunch without QR pairing
  • release gate: Automatic, Relay Only, and Direct Only passed against staging with authenticated Iroh
  • custom relay test harness: 46 transport, 10 macOS settings, and 8 isolated iOS tests passed
  • final security pass: no high findings; legacy new-iOS-to-unchanged-old-Mac raw TCP stays fail-closed and shows the Mac-update migration message

View with Codesmith Autofix with Codesmith
Need help on this PR? Tag /codesmith with what you need. Autofix is disabled.


Summary by cubic

Make authenticated Iroh the default iOS transport with zero-touch same-account discovery. Adds managed/custom relay control, signed direct UDP ports, stronger lifecycle/diagnostics, and a simulator release gate.

  • New Features

    • Default iOS Iroh transport; keep Tailscale/private networks as path hints.
    • Server-driven relay policy plus per-account custom relays (unauthenticated, static token, endpoint‑bound); redacted relay details in diagnostics.
    • Publish signed direct UDP ports in broker registration; prefer them over legacy TCP VPN ports.
    • Privacy-safe diagnostics for session lifecycle and path selection with foreground ownership via CmxTransportSessionPurpose.
    • Canonicalize UUID device IDs across CMUXMobileCore, pairing, backup/restore, discovery, and runtime configs; paired‑Mac store v7 migrates and dedupes case‑only aliases.
    • Debug transport verification modes (automatic/relay‑only/direct‑only) exposed in iOS settings; simulator-only release gate in CmuxMobileShellReleaseGateSupport and a GitHub workflow to validate control, terminal, workspace, events, notifications, chat, and artifacts.
  • Bug Fixes

    • Hardened endpoint binding and relay readiness (wait-for-relay, bind credentials to active endpoints, NAT traversal gating); redacted error logs.
    • Discovery outcomes classified (offline/rate-limited); do not reuse stale snapshots; scrub revoked direct ports.
    • Race/stability fixes for admission, refresh, and reconnect; publish paths only after establishment; more deterministic capacity tests.
    • CI/Deps: extend macOS compatibility timeouts and disable index store; add iroh release-gate workflow; bump iroh-ffi to 1.0.2-cmux.3.

Written for commit 0470a97. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • New Features
    • Added debug transport verification modes: Automatic, Relay Only, and Direct Only.
    • Improved direct-network connectivity by sharing verified IPv4/IPv6 port information.
    • Added privacy-safe transport session diagnostics and lifecycle reporting.
    • Added an automated Iroh release-gate flow for validating mobile connectivity and core interactions.
  • Bug Fixes
    • Standardized UUID-based device identifiers while preserving legacy identifiers.
    • Improved relay readiness handling, connection cleanup, discovery refresh results, and stale socket cleanup.
    • Relay credentials are no longer issued for unbound endpoints.
  • Documentation
    • Added guidance for running transport behavior tests and updated relay architecture documentation.

cmux reload-cloud added 30 commits July 18, 2026 22:38
cmux reload-cloud and others added 20 commits July 19, 2026 04:18
Verified package-native iOS runtime and settings tests. Merges into the Iroh integration branch.
feat(iroh): publish signed direct UDP ports
test(iroh): verify custom relay round trips
@greptile-apps

greptile-apps Bot commented Jul 19, 2026

Copy link
Copy Markdown
Contributor

Too many files changed for review. (173 files found, 100 file limit)

Bypass the limit by tagging @greptile-apps to review.

@coderabbitai

coderabbitai Bot commented Jul 19, 2026 •

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

This PR adds Iroh transport verification controls, relay-readiness handling, session diagnostics, direct-port propagation, UUID device-ID canonicalization, paired-Mac migration, relay catalog hardening, and debug-only iOS release-gate workflows with automated validation.

Changes

Transport and diagnostics

Layer / File(s) Summary
Transport contracts and lifecycle
Packages/Shared/CMUXMobileCore/..., Packages/Shared/CmuxIrohTransport/Sources/...
Transport purposes, lifecycle diagnostics, direct-port payloads, relay readiness, refresh outcomes, session ownership, and ordered admitted-connection shutdown are added or updated.
Runtime and integration tests
Packages/Shared/CmuxIrohTransport/Tests/...
Tests cover refresh outcomes, relay readiness, direct-port routing, session diagnostics, shutdown ordering, and custom relay behavior.

Device identity and mobile integration

Layer / File(s) Summary
Canonical device IDs and storage migration
Packages/iOS/CmuxMobilePairedMac/..., Packages/Shared/CMUXMobileCore/...
UUID device IDs are canonicalized while opaque identifiers remain unchanged; paired-Mac schema v7 merges case-only UUID duplicates and normalizes mutations.
Mobile routing, backup, and settings
Packages/iOS/CmuxMobileShell/..., ios/cmuxPackage/Sources/cmuxFeature/..., Sources/Mobile/...
Canonical IDs are used across pairing, routing, backup/restore, runtime composition, debug transport settings, and listener defaults.

Relay services

Layer / File(s) Summary
Direct-port broker flow
web/services/iroh/..., web/db/...
Signed registrations validate and persist IPv4/IPv6 direct ports, expose them only in authenticated binding catalogs, and clear them on revocation or retention.
Relay catalog integrity and credentials
web/services/relay/..., web/app/api/relay/token/..., web/app/env.ts
Catalog persistence now validates canonical digests and safe transitions; relay credentials require an active endpoint binding and relay runtime configuration is validated.
Web validation coverage
web/tests/...
Database, broker, catalog, token-route, workflow, and environment tests cover the new contracts and failure paths.

Release gate and CI

Layer / File(s) Summary
Release-gate pipeline
.github/workflows/iroh-release-gate.yml, scripts/run-iroh-release-gate.sh, scripts/mobile-dev-launch.sh
A manual workflow and simulator script launch mode-specific apps, wait for a redacted report, validate schema and verification flags, and report success or failure.
Debug iOS release gate
ios/cmuxPackage/Sources/CmuxIrohReleaseGateSupport/..., Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShellReleaseGateSupport/...
Debug-only views, runners, probes, response validators, and result types exercise host status, workspace, terminal, events, notifications, chat sessions, and artifact scans.
macOS CI reliability
.github/workflows/ci-macos-compat.yml
Compatibility timeouts increase to 60 minutes and both unit-test and smoke-test builds disable the Xcode compiler index store.

Estimated code review effort: 5 (Critical) | ~120 minutes

Possibly related issues

  • manaflow-ai/cmux-dev-artifacts#4305 — macOS CI reliability changes address the same unit-test execution path.
  • manaflow-ai/cmux-dev-artifacts#4303 — macOS timeout and compiler-index changes relate directly to the reported macOS build failure.
  • manaflow-ai/cmux-dev-artifacts#4304 — The CI compilation reliability changes correspond to the reported macOS compilation failure.
  • manaflow-ai/cmux-dev-artifacts#4383 — The macOS xcodebuild changes concern the same Swift compilation behavior.

Possibly related PRs

Suggested reviewers: lawrencecchen


Important

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

❌ Failed checks (4 errors, 1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Cmux Swift Blocking Runtime ❌ Error Production Swift adds waitForUsableHomeRelay() with ContinuousClock().sleep(for:), a new timeout-based wait used by host/client startup. Replace the sleep-based timeout with an actor-owned readiness signal/async sequence and cancellation-aware completion; avoid timing waits in shipped runtime code.
Cmux Architecture Rethink ❌ Error start() now blocks on waitForUsableHomeRelay(), which adds a new waiter cache plus task-group timeout to paper over relay-startup ordering. Move relay readiness into one endpoint activation state/transition and have host startup consume that single source of truth, removing the extra waiter cache and timeout wait.
Cmux No Test Or Debug Seam In Production Source ❌ Error MobileIrohRuntimeComposition.swift adds a #if DEBUG conformance/method in production Sources/ (lines 2214-2226), and no dedicated debug file was added. Move the debug-settings conformance into a dedicated debug-only file/folder, or expose needed state internally and observe it from tests via @testable import.
Cmux No Ambient Global State ❌ Error Packages/Shared/CMUXMobileCore/Sources/CMUXMobileCore/CmxDeviceIDCanonicalization.swift:7 adds a new public top-level free function, which the rule flags as ambient API surface. Move canonicalization off file-scope API—either keep it private/fileprivate where used, or put it on a constructable owned service/type and inject it at the call sites.
Docstring Coverage ⚠️ Warning Docstring coverage is 15.04% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Cmux Cache Substitution Correctness ❓ Inconclusive placeholder need final evidence
✅ Passed checks (19 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Cmux Swift Actor Isolation ✅ Passed No production isolation regression found: changed value models are plain top-level structs/enums, and actor/UI-bound types remain explicitly isolated.
Cmux Browser Automation Off-Main ✅ Passed Browser wait/callback commands stay in socketWorkerMethods/worker router, use explicit main hops for WebKit/AppKit, and policy tests pin the routing.
Cmux Expensive Synchronous Load ✅ Passed No changed production Swift path adds/moves RestorableAgentSessionIndex.load or similar heavy sync agent-history/file parsing onto main-actor or interactive code paths.
Cmux No Hacky Sleeps ✅ Passed The new shell waits are event-driven (kqueue/notifyutil/process wait), and the sleep/poll loops in changed files are pre-existing or bounded data processing, not race-masking delays.
Cmux Algorithmic Complexity ✅ Passed Changed production paths use one-pass maps/sets or DB queries; I found no new nested scans, per-target rescans, or repeated sort/filter hot-path regressions.
Cmux Swift Concurrency ✅ Passed PASS: changed Swift code uses stored/cancelled Tasks or AsyncStream/actor boundaries; no new DispatchQueue, Combine, or completion-handler APIs appear in the touched files.
Cmux Swift @Concurrent ✅ Passed The changed Swift files are only opt-in live tests/helper env code and add no invalid @concurrent or nonisolated-async usage; no UI-bound heavy helper violation appears.
Cmux Swift Package Boundaries ✅ Passed The reusable Iroh/device-ID/session logic lives in SwiftPM packages; app-target edits are UI/lifecycle glue and settings bridging, which the rule allows.
Cmux Swiftpm Lockfiles ✅ Passed HEAD diff only changes two test files, so there are no SwiftPM package/Xcode project/.gitignore/workflow/dependency changes to validate against the lockfile rule.
Cmux Swift Logging ✅ Passed No new production Swift logging violations found; the only added logger calls are in the DEBUG-only release-gate support, and existing production loggers were unchanged.
Cmux User-Facing Error Privacy ✅ Passed Only test files changed in this commit, and the rule explicitly allows tests; no user-facing error copy was introduced.
Cmux Full Internationalization ✅ Passed New iOS user-facing strings use L10n/String(localized:) and the added Localizable.xcstrings entries are translated for en and ja; other text changes are debug-only, tests, docs, or protocol tokens.
Cmux Swiftui State Layout ✅ Passed Changed SwiftUI files use top-level wrappers only; no new ObservableObject/@published, GeometryReader, lazy-row store refs, or render-time state writes found.
Cmux Swift Auxiliary Window Close Shortcuts ✅ Passed The diff only adds a debug-only scene/view wrapper inside the existing app WindowGroup; no new standalone NSWindow/WindowGroup or cmuxAuxiliaryWindowIdentifiers changes appeared.
Cmux Source Artifacts ✅ Passed All changed paths are intentional source, tests, docs, config, localization, migrations, or workflow files; no temp/cache/build/artifact directories appear.
Title check ✅ Passed The title matches the main change: finishing the production Iroh transport rollout.
Description check ✅ Passed The description covers the summary and verification well, but it omits the template's Testing, Demo Video, Review Trigger, and Checklist sections.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat-iroh-final-integration

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@azooz2003-bit
azooz2003-bit merged commit 288f1e1 into main Jul 19, 2026
4 of 5 checks passed

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/PairedMacRestore.swift (1)

64-80: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Canonicalize the UUID in tombstoneIDs and the liveRecords filter.

While cmxCanonicalDeviceID is correctly applied during the upsert loop (line 139), it is missing from both the canonicalPairingID helper and the liveRecords filter. If a backup contains a tombstone with a different UUID casing than the live record, the raw string mismatch will cause the .contains check to fail and the live record will bypass the tombstone filter. The subsequent store.remove will delete the local row, but the bypassed live record will be resurrected by store.upsertIfNewer.

Wrap the macDeviceID in cmxCanonicalDeviceID in both places to ensure tombstones reliably match their target records regardless of UUID casing.

🐛 Proposed fix
         func canonicalPairingID(_ value: String) -> String? {
             let trimmed = value.trimmingCharacters(in: .whitespacesAndNewlines)
             guard !trimmed.isEmpty else { return nil }
             let identity = MobilePairedMac.pairingIdentity(from: trimmed)
             return MobilePairedMac.pairingID(
-                macDeviceID: identity.macDeviceID,
+                macDeviceID: cmxCanonicalDeviceID(identity.macDeviceID),
                 instanceTag: identity.instanceTag
             )
         }
         let tombstoneIDs = Set(snapshot.deletedMacDeviceIDs.compactMap(canonicalPairingID))
             .union(locallyDeletedMacDeviceIDs.compactMap(canonicalPairingID))
         let liveRecords = snapshot.records.filter { record in
             !tombstoneIDs.contains(MobilePairedMac.pairingID(
-                macDeviceID: record.macDeviceID,
+                macDeviceID: cmxCanonicalDeviceID(record.macDeviceID),
                 instanceTag: record.instanceTag
             ))
         }
🤖 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 `@Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/PairedMacRestore.swift`
around lines 64 - 80, Apply cmxCanonicalDeviceID to the macDeviceID passed to
MobilePairedMac.pairingIdentity in canonicalPairingID, and to the
record.macDeviceID passed to MobilePairedMac.pairingID in the liveRecords
filter. Preserve the existing tombstone matching and filtering flow while
ensuring UUID casing is normalized consistently.
web/services/relay/repository.ts (1)

146-162: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Idempotent same-sequence accept skips the catalog-body integrity check.

The sequence-advance branch verifies relayCatalogDigest(previous) !== current.catalogDigest before trusting the persisted catalog body (lines 170-175), but the same-sequence branch (146-162) only relies on assertCatalogAdvance's digest-column comparison and never parses/re-hashes current.catalog itself. If the stored JSON body ever diverges from catalog_digest without the sequence changing, repeated idempotent acceptCatalog calls at that sequence would silently miss the corruption that the very next rotation would catch.

♻️ Proposed fix to also self-check the persisted body at same-sequence
             if (catalog.sequence === current.catalogSequence) {
-              if (current.catalog === null) {
-                await tx
-                  .update(irohRelayCatalogState)
-                  .set({ catalog })
-                  .where(eq(irohRelayCatalogState.id, "managed"));
-              }
+              if (current.catalog === null) {
+                await tx
+                  .update(irohRelayCatalogState)
+                  .set({ catalog })
+                  .where(eq(irohRelayCatalogState.id, "managed"));
+              } else if (
+                relayCatalogDigest(parseRelayCatalog(JSON.stringify(current.catalog))) !==
+                current.catalogDigest
+              ) {
+                throw new RelayCatalogIntegrityError({
+                  reason: "persisted_catalog_digest_mismatch",
+                });
+              }
               return;
             }
🤖 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 `@web/services/relay/repository.ts` around lines 146 - 162, Update the
same-sequence branch of acceptCatalog around assertCatalogAdvance to validate
the persisted current.catalog body by computing its relayCatalogDigest and
comparing it with current.catalogDigest before accepting or updating the
catalog. Preserve the existing idempotent behavior for valid data and ensure
corrupted same-sequence state follows the same integrity-failure path as the
sequence-advance branch.
🤖 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 @.github/workflows/iroh-release-gate.yml:
- Around line 3-19: add a workflow-level concurrency group for the manual gate
using the github.ref-based identifier and set cancel-in-progress to false,
ensuring concurrent dispatches queue rather than overlap while preserving the
existing workflow_dispatch inputs and behavior.
- Around line 67-76: Harden the workflow step using matrix.mode by assigning it
to a step-level environment variable such as MODE, then replace direct `${{
matrix.mode }}` interpolation in the case statement and release-gate command
with `$MODE`. Preserve the existing mode-to-TAG mapping and report filename
behavior while ensuring the expression is treated as runtime data rather than
shell code.

In `@ios/cmuxPackage/Sources/cmuxFeature/MobileIrohRuntimeComposition.swift`:
- Around line 2213-2237: Move the DEBUG-only CmxIrohDebugSettingsControlling
extension for MobileIrohRuntimeComposition into a dedicated
MobileIrohRuntimeComposition+DebugSettings.swift file, preserving
setIrohDebugTransportVerificationMode behavior and its `#if` DEBUG guard. Remove
the inlined extension and conditional block from the main production file.

In
`@Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/PairedMacBackupListResponse.swift`:
- Line 1: Import CMUXMobileCore and update the mapped device identifier used to
construct each backup pairing ID, applying cmxCanonicalDeviceID to
identity.macDeviceID before passing it to MobilePairedMac.pairingID. Preserve
the existing instance-tag mapping and ensure all affected mapping paths use the
canonicalized device ID so local deletion keys match the store.

In `@web/db/migrations/20260719120000_iroh_direct_ports/migration.sql`:
- Around line 1-13: Update the direct_port_v4 and direct_port_v6 CHECK
constraints in this migration to use NOT VALID when added, avoiding the blocking
table scan. Add subsequent VALIDATE CONSTRAINT statements, or a follow-up
migration matching the iroh_relay_status_validation pattern, so both constraints
are eventually validated.

---

Outside diff comments:
In `@Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/PairedMacRestore.swift`:
- Around line 64-80: Apply cmxCanonicalDeviceID to the macDeviceID passed to
MobilePairedMac.pairingIdentity in canonicalPairingID, and to the
record.macDeviceID passed to MobilePairedMac.pairingID in the liveRecords
filter. Preserve the existing tombstone matching and filtering flow while
ensuring UUID casing is normalized consistently.

In `@web/services/relay/repository.ts`:
- Around line 146-162: Update the same-sequence branch of acceptCatalog around
assertCatalogAdvance to validate the persisted current.catalog body by computing
its relayCatalogDigest and comparing it with current.catalogDigest before
accepting or updating the catalog. Preserve the existing idempotent behavior for
valid data and ensure corrupted same-sequence state follows the same
integrity-failure path as the sequence-advance branch.
🪄 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: ASSERTIVE

Plan: Pro

Run ID: 8ef73fc9-8df6-4acd-9904-54299cf01f03

📥 Commits

Reviewing files that changed from the base of the PR and between 41756f7 and 0470a97.

⛔ Files ignored due to path filters (4)
  • Packages/Shared/CmuxIrohTransport/Package.resolved is excluded by !**/Package.resolved
  • cmux.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved is excluded by !**/Package.resolved
  • ios/cmux.xcworkspace/xcshareddata/swiftpm/Package.resolved is excluded by !**/Package.resolved
  • ios/cmuxPackage/Package.resolved is excluded by !**/Package.resolved
📒 Files selected for processing (169)
  • .github/workflows/ci-macos-compat.yml
  • .github/workflows/iroh-release-gate.yml
  • Packages/Shared/CMUXMobileCore/Sources/CMUXMobileCore/CmxByteTransportRequest.swift
  • Packages/Shared/CMUXMobileCore/Sources/CMUXMobileCore/CmxDeviceIDCanonicalization.swift
  • Packages/Shared/CMUXMobileCore/Sources/CMUXMobileCore/CmxIrohDebugSettingsControlling.swift
  • Packages/Shared/CMUXMobileCore/Sources/CMUXMobileCore/CmxIrohSettingsSnapshot.swift
  • Packages/Shared/CMUXMobileCore/Sources/CMUXMobileCore/CmxIrohTransportVerificationMode.swift
  • Packages/Shared/CMUXMobileCore/Sources/CMUXMobileCore/CmxTransport.swift
  • Packages/Shared/CMUXMobileCore/Sources/CMUXMobileCore/CmxTransportSessionPurpose.swift
  • Packages/Shared/CMUXMobileCore/Sources/CMUXMobileCore/DiagnosticEventCode.swift
  • Packages/Shared/CMUXMobileCore/Sources/CMUXMobileCore/DiagnosticReport.swift
  • Packages/Shared/CMUXMobileCore/Sources/CMUXMobileCore/DiagnosticTaxonomy.swift
  • Packages/Shared/CMUXMobileCore/Sources/CMUXMobileCore/MobileSyncProtocol.swift
  • Packages/Shared/CMUXMobileCore/Tests/CMUXMobileCoreTests/CmxDeviceIDCanonicalizationTests.swift
  • Packages/Shared/CMUXMobileCore/Tests/CMUXMobileCoreTests/CmxIrohSettingsSnapshotTests.swift
  • Packages/Shared/CMUXMobileCore/Tests/CMUXMobileCoreTests/DiagnosticLogTests.swift
  • Packages/Shared/CmuxIrohTransport/Package.swift
  • Packages/Shared/CmuxIrohTransport/README.md
  • Packages/Shared/CmuxIrohTransport/Sources/CmuxIrohTransport/CmxIrohAdmittedConnectionSupervisor.swift
  • Packages/Shared/CmuxIrohTransport/Sources/CmuxIrohTransport/CmxIrohBrokerModels.swift
  • Packages/Shared/CmuxIrohTransport/Sources/CmuxIrohTransport/CmxIrohClientRuntime+Policy.swift
  • Packages/Shared/CmuxIrohTransport/Sources/CmuxIrohTransport/CmxIrohClientRuntime+PolicyRefresh.swift
  • Packages/Shared/CmuxIrohTransport/Sources/CmuxIrohTransport/CmxIrohClientRuntime.swift
  • Packages/Shared/CmuxIrohTransport/Sources/CmuxIrohTransport/CmxIrohClientRuntimeConfiguration.swift
  • Packages/Shared/CmuxIrohTransport/Sources/CmuxIrohTransport/CmxIrohClientSessionPool.swift
  • Packages/Shared/CmuxIrohTransport/Sources/CmuxIrohTransport/CmxIrohDiagnosticFailure.swift
  • Packages/Shared/CmuxIrohTransport/Sources/CmuxIrohTransport/CmxIrohDirectPorts.swift
  • Packages/Shared/CmuxIrohTransport/Sources/CmuxIrohTransport/CmxIrohEndpointSupervisor.swift
  • Packages/Shared/CmuxIrohTransport/Sources/CmuxIrohTransport/CmxIrohEndpointSupervisorError.swift
  • Packages/Shared/CmuxIrohTransport/Sources/CmuxIrohTransport/CmxIrohHostRuntime+PolicyRefresh.swift
  • Packages/Shared/CmuxIrohTransport/Sources/CmuxIrohTransport/CmxIrohHostRuntime.swift
  • Packages/Shared/CmuxIrohTransport/Sources/CmuxIrohTransport/CmxIrohHostRuntimeConfiguration.swift
  • Packages/Shared/CmuxIrohTransport/Sources/CmuxIrohTransport/CmxIrohLANDiscoveryResolver.swift
  • Packages/Shared/CmuxIrohTransport/Sources/CmuxIrohTransport/CmxIrohLANPeerDiscovery.swift
  • Packages/Shared/CmuxIrohTransport/Sources/CmuxIrohTransport/CmxIrohLibEndpointFactory.swift
  • Packages/Shared/CmuxIrohTransport/Sources/CmuxIrohTransport/CmxIrohLiveDiscoveryRefreshOutcome.swift
  • Packages/Shared/CmuxIrohTransport/Sources/CmuxIrohTransport/CmxIrohPooledByteTransport.swift
  • Packages/Shared/CmuxIrohTransport/Sources/CmuxIrohTransport/CmxIrohRegistrationPayload.swift
  • Packages/Shared/CmuxIrohTransport/Sources/CmuxIrohTransport/CmxIrohRegistryContextProvider.swift
  • Packages/Shared/CmuxIrohTransport/Sources/CmuxIrohTransport/CmxIrohRelayDiagnosticsSnapshot.swift
  • Packages/Shared/CmuxIrohTransport/Sources/CmuxIrohTransport/CmxIrohRelayPolicyResolution.swift
  • Packages/Shared/CmuxIrohTransport/Sources/CmuxIrohTransport/CmxIrohRelayPolicyService.swift
  • Packages/Shared/CmuxIrohTransport/Tests/CmuxIrohTransportTests/CmxIrohAdmittedConnectionSupervisorTests.swift
  • Packages/Shared/CmuxIrohTransport/Tests/CmuxIrohTransportTests/CmxIrohClientRuntimeLifecycleRaceTests.swift
  • Packages/Shared/CmuxIrohTransport/Tests/CmuxIrohTransportTests/CmxIrohClientRuntimeTests.swift
  • Packages/Shared/CmuxIrohTransport/Tests/CmuxIrohTransportTests/CmxIrohClientSessionPoolTests.swift
  • Packages/Shared/CmuxIrohTransport/Tests/CmuxIrohTransportTests/CmxIrohCustomRelayLiveEnvironment.swift
  • Packages/Shared/CmuxIrohTransport/Tests/CmuxIrohTransportTests/CmxIrohCustomRelayLiveTests.swift
  • Packages/Shared/CmuxIrohTransport/Tests/CmuxIrohTransportTests/CmxIrohDirectPortsTests.swift
  • Packages/Shared/CmuxIrohTransport/Tests/CmuxIrohTransportTests/CmxIrohEndpointServerTests+Capacity.swift
  • Packages/Shared/CmuxIrohTransport/Tests/CmuxIrohTransportTests/CmxIrohEndpointServerTests.swift
  • Packages/Shared/CmuxIrohTransport/Tests/CmuxIrohTransportTests/CmxIrohEndpointSupervisorTests.swift
  • Packages/Shared/CmuxIrohTransport/Tests/CmuxIrohTransportTests/CmxIrohHostRuntimeLifecycleRaceTests.swift
  • Packages/Shared/CmuxIrohTransport/Tests/CmuxIrohTransportTests/CmxIrohHostRuntimeTests.swift
  • Packages/Shared/CmuxIrohTransport/Tests/CmuxIrohTransportTests/CmxIrohRegistrationSignerTests.swift
  • Packages/Shared/CmuxIrohTransport/Tests/CmuxIrohTransportTests/CmxIrohRegistryContextProviderFallbackTests.swift
  • Packages/Shared/CmuxIrohTransport/Tests/CmuxIrohTransportTests/CmxIrohRegistryContextProviderTests.swift
  • Packages/Shared/CmuxIrohTransport/Tests/CmuxIrohTransportTests/CmxIrohRelayPolicyCustomProfileTests.swift
  • Packages/Shared/CmuxIrohTransport/Tests/CmuxIrohTransportTests/CmxIrohRelayPolicyServiceTests+Preferences.swift
  • Packages/Shared/CmuxIrohTransport/Tests/CmuxIrohTransportTests/CmxIrohRelayPolicyServiceTests.swift
  • Packages/Shared/CmuxIrohTransport/Tests/CmuxIrohTransportTests/CmxIrohRuntimeConfigurationDeviceIDTests.swift
  • Packages/Shared/CmuxIrohTransport/Tests/CmuxIrohTransportTests/TestHangingDialEndpoint.swift
  • Packages/Shared/CmuxIrohTransport/Tests/CmuxIrohTransportTests/TestIrohProtocolConfiguration.swift
  • Packages/iOS/CmuxMobilePairedMac/Sources/CmuxMobilePairedMac/MobilePairedMac.swift
  • Packages/iOS/CmuxMobilePairedMac/Sources/CmuxMobilePairedMac/MobilePairedMacStore+DeviceIDCanonicalization.swift
  • Packages/iOS/CmuxMobilePairedMac/Sources/CmuxMobilePairedMac/MobilePairedMacStore.swift
  • Packages/iOS/CmuxMobilePairedMac/Tests/CmuxMobilePairedMacTests/MobilePairedMacDeviceIDCanonicalizationTests.swift
  • Packages/iOS/CmuxMobileRPC/Sources/CmuxMobileRPC/MobileCoreRPCClient.swift
  • Packages/iOS/CmuxMobileRPC/Sources/CmuxMobileRPC/MobileHostStatusResponse.swift
  • Packages/iOS/CmuxMobileRPC/Tests/CmuxMobileRPCTests/MobileTerminalDTODecodeTests.swift
  • Packages/iOS/CmuxMobileShell/Package.swift
  • Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/BackingUpPairedMacStore+AuthorizedRoutes.swift
  • Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/BackingUpPairedMacStore+ConditionalRestore.swift
  • Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/BackingUpPairedMacStore.swift
  • Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/MobileMacInstanceTagAuthority.swift
  • Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/MobileShellComposite+InstanceAuthority.swift
  • Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/MobileShellComposite+ManualAttachTicket.swift
  • Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/MobileShellComposite+PairedMacCoalescing.swift
  • Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/MobileShellComposite+TerminalLane.swift
  • Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/MobileShellComposite+ZeroTouchIroh.swift
  • Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/MobileShellComposite.swift
  • Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/PairedMacBackupListResponse.swift
  • Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/PairedMacBackupOpWire.swift
  • Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/PairedMacBackupRecord.swift
  • Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/PairedMacBackupRecordWire.swift
  • Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/PairedMacRestore.swift
  • Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShellReleaseGateSupport/MobileIrohReleaseGateProbeFailure.swift
  • Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShellReleaseGateSupport/MobileIrohReleaseGateProbeResult.swift
  • Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShellReleaseGateSupport/MobileIrohReleaseGateResponseValidator.swift
  • Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShellReleaseGateSupport/MobileShellComposite+IrohReleaseGate.swift
  • Packages/iOS/CmuxMobileShell/Tests/CmuxMobileShellTests/MobileIrohReleaseGateResponseValidatorTests.swift
  • Packages/iOS/CmuxMobileShell/Tests/CmuxMobileShellTests/MobileMacInstanceTagAuthorityTests.swift
  • Packages/iOS/CmuxMobileShell/Tests/CmuxMobileShellTests/MobileShellCompositeForgottenMacRefreshTests.swift
  • Packages/iOS/CmuxMobileShell/Tests/CmuxMobileShellTests/PairedMacBackupTests.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/MobileIrohSettingsModel.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/MobileIrohSettingsView.swift
  • Packages/iOS/CmuxMobileShellUI/Tests/CmuxMobileShellUITests/MobileIrohSettingsModelTests.swift
  • Packages/macOS/CmuxBrowser/Sources/CmuxBrowser/DesignMode/BrowserDesignModeAnnotationCapture.swift
  • Packages/macOS/CmuxBrowser/Sources/CmuxBrowser/DesignMode/BrowserDesignModeAnnotationCaptureRequest.swift
  • Packages/macOS/CmuxBrowser/Sources/CmuxBrowser/DesignMode/BrowserDesignModeEdit.swift
  • Packages/macOS/CmuxBrowser/Sources/CmuxBrowser/DesignMode/BrowserDesignModeEditKind.swift
  • Packages/macOS/CmuxBrowser/Sources/CmuxBrowser/DesignMode/BrowserDesignModePageURL.swift
  • Packages/macOS/CmuxBrowser/Sources/CmuxBrowser/DesignMode/BrowserDesignModePromptContext.swift
  • Packages/macOS/CmuxBrowser/Sources/CmuxBrowser/DesignMode/BrowserDesignModePromptFormatter.swift
  • Packages/macOS/CmuxBrowser/Sources/CmuxBrowser/DesignMode/BrowserDesignModePromptRun.swift
  • Packages/macOS/CmuxBrowser/Sources/CmuxBrowser/DesignMode/BrowserDesignModeRect.swift
  • Packages/macOS/CmuxBrowser/Sources/CmuxBrowser/DesignMode/BrowserDesignModeScript.swift
  • Packages/macOS/CmuxBrowser/Sources/CmuxBrowser/DesignMode/BrowserDesignModeSelection.swift
  • Packages/macOS/CmuxBrowser/Sources/CmuxBrowser/DesignMode/BrowserDesignModeSnapshot.swift
  • Packages/macOS/CmuxBrowser/Sources/CmuxBrowser/DesignMode/BrowserDesignModeViewport.swift
  • Packages/macOS/CmuxBrowser/Tests/CmuxBrowserTests/DesignMode/BrowserDesignModePromptPayload.swift
  • Packages/macOS/CmuxSettingsUI/Tests/CmuxSettingsUITests/IrohSettingsModelTests.swift
  • Packages/macOS/CmuxWorkspaces/Sources/CmuxWorkspaces/Values/WorkspaceChecklistAttachment.swift
  • Packages/macOS/CmuxWorkspaces/Sources/CmuxWorkspaces/Values/WorkspaceChecklistItem.swift
  • Sources/AboutLicenseContent.swift
  • Sources/AgentForkTimeoutResumeGate.swift
  • Sources/IrohTransportDebugMenuButtons.swift
  • Sources/Mobile/MobileHostIdentity.swift
  • Sources/Mobile/MobileHostIrohRuntime+Activation.swift
  • Sources/Mobile/MobileHostIrohRuntime+SettingsSnapshot.swift
  • Sources/Mobile/MobileHostService.swift
  • Sources/Panels/BrowserInsecureHTTPNavigationResolution.swift
  • Sources/SessionPersistence+Todos.swift
  • Sources/ShortcutRecorderRejectedAttempt.swift
  • Sources/SidebarWorkspaceStatusPopover.swift
  • cmuxTests/MobileHostConnectionLifecycleTests.swift
  • cmuxTests/MobileHostIdentityTests.swift
  • cmuxTests/MobileHostIrohAdmissionTests.swift
  • cmuxTests/MobileHostServiceSettingsTests.swift
  • docs/iroh-app-transport-architecture.md
  • ios/cmux-ios.xcodeproj/project.pbxproj
  • ios/cmux/Resources/Localizable.xcstrings
  • ios/cmux/cmuxApp.swift
  • ios/cmuxPackage/Package.swift
  • ios/cmuxPackage/Sources/CmuxIrohReleaseGateSupport/MobileIrohReleaseGateHostView.swift
  • ios/cmuxPackage/Sources/CmuxIrohReleaseGateSupport/MobileIrohReleaseGateRunner.swift
  • ios/cmuxPackage/Sources/CmuxIrohReleaseGateSupport/MobileIrohReleaseGateScene.swift
  • ios/cmuxPackage/Sources/cmuxFeature/CMUXMobileRootScene.swift
  • ios/cmuxPackage/Sources/cmuxFeature/MobileIrohRouteCatalog.swift
  • ios/cmuxPackage/Sources/cmuxFeature/MobileIrohRuntimeComposition.swift
  • ios/cmuxPackage/Tests/cmuxFeatureTests/MobileIrohReleaseGateRunnerTests.swift
  • ios/cmuxPackage/Tests/cmuxFeatureTests/MobileIrohRuntimeCompositionTests.swift
  • ios/cmuxPackage/Tests/cmuxFeatureTests/MobileIrohTransportVerificationModeTests.swift
  • scripts/lib/mobile-attach.sh
  • scripts/lib/mobile-attach.test.mjs
  • scripts/mobile-dev-launch.sh
  • scripts/run-iroh-release-gate.sh
  • web/app/api/relay/token/route.ts
  • web/app/env.ts
  • web/db/migrations/20260718120000_iroh_relay_status_validation/migration.sql
  • web/db/migrations/20260718121000_iroh_relay_catalog_body/migration.sql
  • web/db/migrations/20260719120000_iroh_direct_ports/migration.sql
  • web/db/schema.ts
  • web/services/iroh/README.md
  • web/services/iroh/model.ts
  • web/services/iroh/repository.ts
  • web/services/iroh/trustBroker.ts
  • web/services/relay/catalog.ts
  • web/services/relay/errors.ts
  • web/services/relay/http.ts
  • web/services/relay/repository.ts
  • web/services/relay/workflows.ts
  • web/tests/client-config-env.test.ts
  • web/tests/iroh-db-behavior.test.ts
  • web/tests/iroh-model-crypto.test.ts
  • web/tests/iroh-trust-broker.test.ts
  • web/tests/relay-policy.test.ts
  • web/tests/relay-token-route.test.ts
  • web/tests/relay-workflows.test.ts

Comment on lines +3 to +19
on:
workflow_dispatch:
inputs:
ref:
description: Branch or SHA to verify
required: false
default: ""
mode:
description: Iroh transport mode
required: true
default: all
type: choice
options:
- all
- automatic
- relay-only
- direct-only

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Consider a concurrency: group for the manual gate.

Nothing prevents two concurrent dispatches from overlapping and racing on the shared staging account (CMUX_DOGFOOD_STACK_EMAIL/PASSWORD) or relay-policy state. A simple concurrency: iroh-release-gate-${{ github.ref }} with cancel-in-progress: false would remove the risk cheaply.

🧰 Tools
🪛 zizmor (1.26.1)

[warning] 3-19: insufficient job-level concurrency limits (concurrency-limits): workflow is missing concurrency setting

(concurrency-limits)

🤖 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 @.github/workflows/iroh-release-gate.yml around lines 3 - 19, add a
workflow-level concurrency group for the manual gate using the github.ref-based
identifier and set cancel-in-progress to false, ensuring concurrent dispatches
queue rather than overlap while preserving the existing workflow_dispatch inputs
and behavior.

Source: Linters/SAST tools

Comment on lines +67 to +76
case "${{ matrix.mode }}" in
automatic) TAG=irgaut ;;
relay-only) TAG=irgrel ;;
direct-only) TAG=irgdir ;;
esac
./scripts/run-iroh-release-gate.sh \
--mode "${{ matrix.mode }}" \
--tag "$TAG" \
--report-output "$RUNNER_TEMP/iroh-release-gate-${{ matrix.mode }}.json"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

Harden matrix.mode interpolation per zizmor's template-injection finding.

${{ matrix.mode }} is expanded directly into the case statement and CLI args inside run:. GitHub does validate choice inputs against the declared options, so this isn't exploitable today, but it's still the flagged anti-pattern — move it into a step env: var and reference $MODE from the script so it's treated as data, not code, consistent with standard defense-in-depth for run: blocks.

🔒 Proposed fix
       - name: Run staging Iroh gate
+        env:
+          MODE: ${{ matrix.mode }}
         run: |
           set -euo pipefail
-          case "${{ matrix.mode }}" in
+          case "$MODE" in
             automatic) TAG=irgaut ;;
             relay-only) TAG=irgrel ;;
             direct-only) TAG=irgdir ;;
           esac
           ./scripts/run-iroh-release-gate.sh \
-            --mode "${{ matrix.mode }}" \
+            --mode "$MODE" \
             --tag "$TAG" \
-            --report-output "$RUNNER_TEMP/iroh-release-gate-${{ matrix.mode }}.json"
+            --report-output "$RUNNER_TEMP/iroh-release-gate-${MODE}.json"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
case "${{ matrix.mode }}" in
automatic) TAG=irgaut ;;
relay-only) TAG=irgrel ;;
direct-only) TAG=irgdir ;;
esac
./scripts/run-iroh-release-gate.sh \
--mode "${{ matrix.mode }}" \
--tag "$TAG" \
--report-output "$RUNNER_TEMP/iroh-release-gate-${{ matrix.mode }}.json"
- name: Run staging Iroh gate
env:
MODE: ${{ matrix.mode }}
run: |
set -euo pipefail
case "$MODE" in
automatic) TAG=irgaut ;;
relay-only) TAG=irgrel ;;
direct-only) TAG=irgdir ;;
esac
./scripts/run-iroh-release-gate.sh \
--mode "$MODE" \
--tag "$TAG" \
--report-output "$RUNNER_TEMP/iroh-release-gate-${MODE}.json"
🧰 Tools
🪛 zizmor (1.26.1)

[warning] 67-67: code injection via template expansion (template-injection): may expand into attacker-controllable code

(template-injection)


[warning] 73-73: code injection via template expansion (template-injection): may expand into attacker-controllable code

(template-injection)


[warning] 75-75: code injection via template expansion (template-injection): may expand into attacker-controllable code

(template-injection)

🤖 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 @.github/workflows/iroh-release-gate.yml around lines 67 - 76, Harden the
workflow step using matrix.mode by assigning it to a step-level environment
variable such as MODE, then replace direct `${{ matrix.mode }}` interpolation in
the case statement and release-gate command with `$MODE`. Preserve the existing
mode-to-TAG mapping and report filename behavior while ensuring the expression
is treated as runtime data rather than shell code.

Source: Linters/SAST tools

Comment on lines +2213 to +2237

#if DEBUG
extension MobileIrohRuntimeComposition: CmxIrohDebugSettingsControlling {
public func setIrohDebugTransportVerificationMode(
_ mode: CmxIrohTransportVerificationMode
) async throws {
guard transportVerificationMode != mode else { return }
guard let debugDefaults else { throw SettingsError.unavailable }

debugDefaults.set(
mode.rawValue,
forKey: CmxIrohTransportVerificationMode.debugDefaultsKey
)
transportVerificationMode = mode
publishIrohSettingsUpdate()

guard let accountID = observedAccountID ?? activeAccountID else { return }
await scheduleReconcile(
targetAccountID: accountID,
eraseAccountState: false,
restartActiveRuntime: true
).value
}
}
#endif

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Move the #if DEBUG conformance into a dedicated debug file.

This whole extension is debug-only and inlined in the main production type. As per coding guidelines, "A genuinely unavoidable debug-only facility must be isolated in a dedicated debug file or folder, rather than inlined into the main production type." Consider extracting it to MobileIrohRuntimeComposition+DebugSettings.swift (also aligning with the TypeName+*.swift extension convention).

🤖 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 `@ios/cmuxPackage/Sources/cmuxFeature/MobileIrohRuntimeComposition.swift`
around lines 2213 - 2237, Move the DEBUG-only CmxIrohDebugSettingsControlling
extension for MobileIrohRuntimeComposition into a dedicated
MobileIrohRuntimeComposition+DebugSettings.swift file, preserving
setIrohDebugTransportVerificationMode behavior and its `#if` DEBUG guard. Remove
the inlined extension and conditional block from the main production file.

Source: Coding guidelines

@@ -1,3 +1,4 @@
internal import CmuxMobilePairedMac

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Canonicalize the mapped device identifier to ensure reliable deletion.

The incoming pairingID strings from the server might contain legacy uncanonicalized device IDs. Since MobilePairedMac.pairingID(macDeviceID:instanceTag:) concatenates its inputs without altering them, identity.macDeviceID must be passed through cmxCanonicalDeviceID here; otherwise, the resulting local deletion keys won't match the new canonical format in the local store, leaving stale records orphaned.

Please import CMUXMobileCore and apply canonicalization to the device ID segment.

🐛 Proposed fix
+internal import CMUXMobileCore
 internal import CmuxMobilePairedMac
 
 struct PairedMacBackupListResponse: Decodable {
// ...
             .map { pairingID in
                 let identity = MobilePairedMac.pairingIdentity(from: pairingID)
                 return MobilePairedMac.pairingID(
-                    macDeviceID: identity.macDeviceID,
+                    macDeviceID: cmxCanonicalDeviceID(identity.macDeviceID),
                     instanceTag: identity.instanceTag
                 )
             }

Also applies to: 24-30

🤖 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
`@Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/PairedMacBackupListResponse.swift`
at line 1, Import CMUXMobileCore and update the mapped device identifier used to
construct each backup pairing ID, applying cmxCanonicalDeviceID to
identity.macDeviceID before passing it to MobilePairedMac.pairingID. Preserve
the existing instance-tag mapping and ensure all affected mapping paths use the
canonicalized device ID so local deletion keys match the store.

Comment on lines +1 to +13
ALTER TABLE "iroh_endpoint_bindings"
ADD COLUMN "direct_port_v4" integer;
--> statement-breakpoint
ALTER TABLE "iroh_endpoint_bindings"
ADD COLUMN "direct_port_v6" integer;
--> statement-breakpoint
ALTER TABLE "iroh_endpoint_bindings"
ADD CONSTRAINT "iroh_endpoint_bindings_direct_port_v4_check"
CHECK ("direct_port_v4" IS NULL OR "direct_port_v4" BETWEEN 1 AND 65535);
--> statement-breakpoint
ALTER TABLE "iroh_endpoint_bindings"
ADD CONSTRAINT "iroh_endpoint_bindings_direct_port_v6_check"
CHECK ("direct_port_v6" IS NULL OR "direct_port_v6" BETWEEN 1 AND 65535);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🔴 Critical | ⚡ Quick win

Use NOT VALID when adding constraints to avoid table locking.

Adding a CHECK constraint without NOT VALID acquires an ACCESS EXCLUSIVE lock and performs a full table scan, blocking all writes to iroh_endpoint_bindings until the scan finishes. This can cause severe production availability issues.

Append NOT VALID to the constraint definitions here, and execute a VALIDATE CONSTRAINT command in a subsequent statement or migration (similar to how the iroh_relay_status_validation migration is structured).

🔒️ Proposed fix to add NOT VALID
 ALTER TABLE "iroh_endpoint_bindings"
   ADD COLUMN "direct_port_v6" integer;
 --> statement-breakpoint
 ALTER TABLE "iroh_endpoint_bindings"
   ADD CONSTRAINT "iroh_endpoint_bindings_direct_port_v4_check"
-  CHECK ("direct_port_v4" IS NULL OR "direct_port_v4" BETWEEN 1 AND 65535);
+  CHECK ("direct_port_v4" IS NULL OR "direct_port_v4" BETWEEN 1 AND 65535) NOT VALID;
 --> statement-breakpoint
 ALTER TABLE "iroh_endpoint_bindings"
   ADD CONSTRAINT "iroh_endpoint_bindings_direct_port_v6_check"
-  CHECK ("direct_port_v6" IS NULL OR "direct_port_v6" BETWEEN 1 AND 65535);
+  CHECK ("direct_port_v6" IS NULL OR "direct_port_v6" BETWEEN 1 AND 65535) NOT VALID;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
ALTER TABLE "iroh_endpoint_bindings"
ADD COLUMN "direct_port_v4" integer;
--> statement-breakpoint
ALTER TABLE "iroh_endpoint_bindings"
ADD COLUMN "direct_port_v6" integer;
--> statement-breakpoint
ALTER TABLE "iroh_endpoint_bindings"
ADD CONSTRAINT "iroh_endpoint_bindings_direct_port_v4_check"
CHECK ("direct_port_v4" IS NULL OR "direct_port_v4" BETWEEN 1 AND 65535);
--> statement-breakpoint
ALTER TABLE "iroh_endpoint_bindings"
ADD CONSTRAINT "iroh_endpoint_bindings_direct_port_v6_check"
CHECK ("direct_port_v6" IS NULL OR "direct_port_v6" BETWEEN 1 AND 65535);
ALTER TABLE "iroh_endpoint_bindings"
ADD COLUMN "direct_port_v4" integer;
--> statement-breakpoint
ALTER TABLE "iroh_endpoint_bindings"
ADD COLUMN "direct_port_v6" integer;
--> statement-breakpoint
ALTER TABLE "iroh_endpoint_bindings"
ADD CONSTRAINT "iroh_endpoint_bindings_direct_port_v4_check"
CHECK ("direct_port_v4" IS NULL OR "direct_port_v4" BETWEEN 1 AND 65535) NOT VALID;
--> statement-breakpoint
ALTER TABLE "iroh_endpoint_bindings"
ADD CONSTRAINT "iroh_endpoint_bindings_direct_port_v6_check"
CHECK ("direct_port_v6" IS NULL OR "direct_port_v6" BETWEEN 1 AND 65535) NOT VALID;
🧰 Tools
🪛 Squawk (2.59.0)

[warning] 2-2: Using 32-bit integer fields can result in hitting the max int limit. Use 64-bit integer values instead to prevent hitting this limit.

(prefer-bigint-over-int)


[warning] 5-5: Using 32-bit integer fields can result in hitting the max int limit. Use 64-bit integer values instead to prevent hitting this limit.

(prefer-bigint-over-int)


[warning] 8-9: By default new constraints require a table scan and block writes to the table while that scan occurs. Use NOT VALID with a later VALIDATE CONSTRAINT call.

(constraint-missing-not-valid)


[warning] 12-13: By default new constraints require a table scan and block writes to the table while that scan occurs. Use NOT VALID with a later VALIDATE CONSTRAINT call.

(constraint-missing-not-valid)

🤖 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 `@web/db/migrations/20260719120000_iroh_direct_ports/migration.sql` around
lines 1 - 13, Update the direct_port_v4 and direct_port_v6 CHECK constraints in
this migration to use NOT VALID when added, avoiding the blocking table scan.
Add subsequent VALIDATE CONSTRAINT statements, or a follow-up migration matching
the iroh_relay_status_validation pattern, so both constraints are eventually
validated.

Source: Linters/SAST tools

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