Repository navigation
Prove live Iroh relay token rollover before release - #8499
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughThe PR adds relay rollover and relay expiry release-gate scenarios, propagates transport continuity and closure evidence through Iroh and mobile RPC layers, makes relay credential refresh configurable, and updates simulator workflows, reports, validation, and tests. ChangesIroh relay continuity and release gate
Estimated code review effort: 4 (Complex) | ~60 minutes Possibly related PRs
Sequence Diagram(s)sequenceDiagram
participant GateScript
participant MobileIrohReleaseGateRunner
participant MobileIrohRuntimeComposition
participant MobileShellComposite
participant CmxIrohPooledByteTransport
GateScript->>MobileIrohReleaseGateRunner: launch selected scenario
MobileIrohReleaseGateRunner->>MobileIrohRuntimeComposition: read endpoint identity and credential expiry
MobileIrohReleaseGateRunner->>MobileShellComposite: run scenario probe
MobileShellComposite->>CmxIrohPooledByteTransport: inspect continuity and closure
CmxIrohPooledByteTransport-->>MobileShellComposite: return continuity or closure evidence
MobileShellComposite-->>MobileIrohReleaseGateRunner: return scenario verification result
MobileIrohReleaseGateRunner-->>GateScript: emit schema v3 report
Suggested reviewers: Important Pre-merge checks failedPlease resolve all errors before merging. Addressing warnings is optional. ❌ Failed checks (1 error, 1 warning, 1 inconclusive)
✅ Passed checks (22 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
Greptile SummaryThis PR adds a Debug-only relay credential rollover/expiry release gate that proves live Iroh connections survive JWT rollover and disconnect correctly on hard expiry, without changing
Confidence Score: 5/5Safe to merge; all gate code is #if DEBUG-only, production changes are narrow and well-tested. Production changes are limited to: a tested shouldReconcileAuthObservation static extraction in the auth lifecycle, a one-shot verified-discovery cache in CmxIrohRegistryContextProvider, and the automaticRelayCredentialRefreshEnabled flag plumbed through CmxIrohClientRuntime to CmxIrohRelayCredentialCoordinator (always true in release builds). All release-gate additions are guarded by #if DEBUG. The iroh-ffi bump to 1.0.2-cmux.4 is reflected in all three cmux-owned Package.resolved lockfiles. No files require special attention. Important Files Changed
Sequence Diagram%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
participant Gate as run-iroh-release-gate.sh
participant Runner as MobileIrohReleaseGateRunner
participant Probe as MobileShellComposite+IrohReleaseGate
participant Coord as CmxIrohRelayCredentialCoordinator
participant Conn as CmxIrohLibConnection
Gate->>Runner: "CMUX_IROH_RELEASE_GATE_SCENARIO=relay_rollover"
Runner->>Probe: runIrohReleaseGateProbe(scenario:.relayRollover, soakDurationSeconds:330)
Probe->>Conn: connectionContinuityID() - connectionBefore
Probe->>Coord: relayCredentialExpiresAt() - expiryBefore
Probe->>Probe: waitForArtifact 32 MiB flow-controlled
loop 330 s soak
Probe->>Runner: workspace.list heartbeat
end
Probe->>Conn: connectionContinuityID() - connectionAfter
Probe->>Coord: relayCredentialExpiresAt() - expiryAfter
Probe-->>Probe: "assert connectionAfter == connectionBefore"
Probe-->>Probe: "assert expiryAfter > expiryBefore"
Probe->>Probe: control-stream round-trip
Probe->>Probe: reassert event subscription
Probe->>Probe: drain artifact bytes
Runner->>Gate: Report schemaVersion 3 passed true
Gate->>Runner: "CMUX_IROH_RELEASE_GATE_SCENARIO=relay_expiry"
Runner->>Coord: "automaticRefreshEnabled=false"
Runner->>Probe: verifyUnrefreshedRelayExpiry
Probe->>Conn: transportClosureObservation()
loop poll until expiry+20s
Probe->>Runner: workspace.list heartbeat
alt connectionClosed near expiry
Probe->>Conn: closureObservation.waitUntilClosed()
Probe-->>Runner: "unrefreshedExpiryDisconnectVerified=true"
end
end
Runner->>Gate: Report scenario relay_expiry passed
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
participant Gate as run-iroh-release-gate.sh
participant Runner as MobileIrohReleaseGateRunner
participant Probe as MobileShellComposite+IrohReleaseGate
participant Coord as CmxIrohRelayCredentialCoordinator
participant Conn as CmxIrohLibConnection
Gate->>Runner: "CMUX_IROH_RELEASE_GATE_SCENARIO=relay_rollover"
Runner->>Probe: runIrohReleaseGateProbe(scenario:.relayRollover, soakDurationSeconds:330)
Probe->>Conn: connectionContinuityID() - connectionBefore
Probe->>Coord: relayCredentialExpiresAt() - expiryBefore
Probe->>Probe: waitForArtifact 32 MiB flow-controlled
loop 330 s soak
Probe->>Runner: workspace.list heartbeat
end
Probe->>Conn: connectionContinuityID() - connectionAfter
Probe->>Coord: relayCredentialExpiresAt() - expiryAfter
Probe-->>Probe: "assert connectionAfter == connectionBefore"
Probe-->>Probe: "assert expiryAfter > expiryBefore"
Probe->>Probe: control-stream round-trip
Probe->>Probe: reassert event subscription
Probe->>Probe: drain artifact bytes
Runner->>Gate: Report schemaVersion 3 passed true
Gate->>Runner: "CMUX_IROH_RELEASE_GATE_SCENARIO=relay_expiry"
Runner->>Coord: "automaticRefreshEnabled=false"
Runner->>Probe: verifyUnrefreshedRelayExpiry
Probe->>Conn: transportClosureObservation()
loop poll until expiry+20s
Probe->>Runner: workspace.list heartbeat
alt connectionClosed near expiry
Probe->>Conn: closureObservation.waitUntilClosed()
Probe-->>Runner: "unrefreshedExpiryDisconnectVerified=true"
end
end
Runner->>Gate: Report scenario relay_expiry passed
Reviews (6): Last reviewed commit: "fix(iroh): reuse verified discovery for ..." | Re-trigger Greptile |
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 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
`@ios/cmuxPackage/Sources/CmuxIrohReleaseGateSupport/MobileIrohReleaseGateRunner.swift`:
- Around line 136-151: Consolidate the relay rollover timing values into shared
type-level constants, including the soak duration and scenario timeout values.
Update the runProbe wiring, scenarioPassed threshold, and timeout configuration
to reference Self.relayRolloverSoakDurationSeconds and the corresponding timeout
constants, eliminating duplicated 330/90/420 literals while preserving current
behavior.
- Around line 312-330: Update the relay-expiry settings observation loop in the
operation flow to check Task.isCancelled on each iteration, matching the
cancellation handling in the readiness and post-probe path loops. When
cancellation is detected, exit the loop and propagate the existing
cancellation/timeout outcome so the suspended operation and settings
subscription do not remain active.
In
`@Packages/Shared/CmuxIrohTransport/Sources/CmuxIrohTransport/CmxIrohClientSession.swift`:
- Around line 202-213: Update connectionContinuityID() to use a single guard
that verifies the session is open, unwraps connection, and casts it to any
CmxIrohConnection & CmxIrohConnectionContinuityIdentifying before calling
isClosed(). Check isClosed() only after the continuity-capable cast succeeds,
preserving nil for closed, missing, or unsupported connections.
🪄 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: 24d88de7-68d9-43e3-a462-f111617caa14
📒 Files selected for processing (32)
.github/workflows/iroh-release-gate.ymlPackages/Shared/CMUXMobileCore/Sources/CMUXMobileCore/CmxTransport.swiftPackages/Shared/CmuxIrohTransport/Sources/CmuxIrohTransport/CmxIrohClientRuntime+Policy.swiftPackages/Shared/CmuxIrohTransport/Sources/CmuxIrohTransport/CmxIrohClientRuntime+RelayPolicy.swiftPackages/Shared/CmuxIrohTransport/Sources/CmuxIrohTransport/CmxIrohClientRuntime.swiftPackages/Shared/CmuxIrohTransport/Sources/CmuxIrohTransport/CmxIrohClientSession.swiftPackages/Shared/CmuxIrohTransport/Sources/CmuxIrohTransport/CmxIrohConnectionContinuityIdentifying.swiftPackages/Shared/CmuxIrohTransport/Sources/CmuxIrohTransport/CmxIrohLibConnection.swiftPackages/Shared/CmuxIrohTransport/Sources/CmuxIrohTransport/CmxIrohPooledByteTransport.swiftPackages/Shared/CmuxIrohTransport/Sources/CmuxIrohTransport/CmxIrohRelayCredentialCoordinator.swiftPackages/Shared/CmuxIrohTransport/Tests/CmuxIrohTransportTests/CmxIrohClientSessionTests.swiftPackages/Shared/CmuxIrohTransport/Tests/CmuxIrohTransportTests/CmxIrohRelayCredentialCoordinatorTests+Refresh.swiftPackages/Shared/CmuxIrohTransport/Tests/CmuxIrohTransportTests/TestIrohConnection.swiftPackages/iOS/CmuxMobileRPC/Sources/CmuxMobileRPC/MobileCoreRPCClient.swiftPackages/iOS/CmuxMobileRPC/Sources/CmuxMobileRPC/MobileCoreRPCSession.swiftPackages/iOS/CmuxMobileShell/Sources/CmuxMobileShellReleaseGateSupport/MobileIrohReleaseGateProbeFailure.swiftPackages/iOS/CmuxMobileShell/Sources/CmuxMobileShellReleaseGateSupport/MobileIrohReleaseGateProbeResult.swiftPackages/iOS/CmuxMobileShell/Sources/CmuxMobileShellReleaseGateSupport/MobileIrohReleaseGateResponseValidator.swiftPackages/iOS/CmuxMobileShell/Sources/CmuxMobileShellReleaseGateSupport/MobileIrohReleaseGateScenario.swiftPackages/iOS/CmuxMobileShell/Sources/CmuxMobileShellReleaseGateSupport/MobileShellComposite+IrohReleaseGate.swiftPackages/iOS/CmuxMobileShell/Tests/CmuxMobileShellTests/MobileIrohReleaseGateResponseValidatorTests.swiftdocs/iroh-app-transport-architecture.mdios/cmux/cmuxApp.swiftios/cmuxPackage/Sources/CmuxIrohReleaseGateSupport/MobileIrohReleaseGateHostView.swiftios/cmuxPackage/Sources/CmuxIrohReleaseGateSupport/MobileIrohReleaseGateRunner.swiftios/cmuxPackage/Sources/CmuxIrohReleaseGateSupport/MobileIrohReleaseGateScene.swiftios/cmuxPackage/Sources/cmuxFeature/MobileIrohRuntimeComposition.swiftios/cmuxPackage/Tests/cmuxFeatureTests/MobileIrohReleaseGateRunnerTests.swiftscripts/lib/mobile-attach.test.mjsscripts/mobile-dev-launch.shscripts/run-iroh-release-gate.shweb/services/relay/token.ts
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 `@Packages/iOS/CmuxMobileRPC/Sources/CmuxMobileRPC/MobileCoreRPCClient.swift`:
- Around line 148-153: Move the release-gate-only transportClosureObservation()
accessors out of production type definitions into dedicated `#if` DEBUG extension
files, preserving the client-to-session delegation and existing visibility.
Update
Packages/iOS/CmuxMobileRPC/Sources/CmuxMobileRPC/MobileCoreRPCClient.swift#L148-L153
and
Packages/iOS/CmuxMobileRPC/Sources/CmuxMobileRPC/MobileCoreRPCSession.swift#L193-L201;
both sites require removal from the main files and relocation to the debug
extensions.
🪄 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: 6ea1e4e0-1fa2-4e1d-93af-0d176d844c19
📒 Files selected for processing (8)
Packages/Shared/CMUXMobileCore/Sources/CMUXMobileCore/CmxTransport.swiftPackages/Shared/CmuxIrohTransport/Sources/CmuxIrohTransport/CmxIrohPooledByteTransport.swiftPackages/Shared/CmuxIrohTransport/Tests/CmuxIrohTransportTests/CmxIrohClientSessionPoolTests.swiftPackages/iOS/CmuxMobileRPC/Sources/CmuxMobileRPC/MobileCoreRPCClient.swiftPackages/iOS/CmuxMobileRPC/Sources/CmuxMobileRPC/MobileCoreRPCSession.swiftPackages/iOS/CmuxMobileShell/Sources/CmuxMobileShellReleaseGateSupport/MobileShellComposite+IrohReleaseGate.swiftios/cmuxPackage/Sources/cmuxFeature/MobileIrohRuntimeComposition+ReleaseGate.swiftios/cmuxPackage/Sources/cmuxFeature/MobileIrohRuntimeComposition.swift
Summary
Verification
Residual risk
The artifact proof assumes the pinned noq per-stream receive window remains below 32 MiB. A dependency update that increases the window must increase the gated payload too.
Need help on this PR? Tag
/codesmithwith what you need. Autofix is disabled.Summary by cubic
Adds a Debug-only release gate to prove live Iroh relay credential rollover and hard-expiry using local continuity evidence and scenario-driven timeouts. Now consumes
iroh-ffi@1.0.2-cmux.4for stable connection identity and reuses verified discovery on first dial to avoid broker rate-limit drops.Bug Fixes
Migration
scripts/run-iroh-release-gate.sh --mode relay-only --tag <tag>(330s soak).scripts/run-iroh-release-gate.sh --mode relay-expiry --tag <tag>(refresh auto-disabled).CMUX_IROH_RELEASE_GATE_SCENARIO=standard|relay_rollover|relay_expiry.CMUX_IROH_DISABLE_RELAY_CREDENTIAL_REFRESH=1for expiry.Written for commit b2899a1. Summary will update on new commits.
Summary by CodeRabbit
relay-expiryrelease-gate support alongside standard and relay-rollover scenarios.