feat(frost): no-coarse-fallback mode for coarse-path retirement (default off)#4101
Merged
mswilkison merged 4 commits intoJun 21, 2026
Conversation
…ult off) The reversible, un-gated half of coarse-path retirement (RFC-21 Phase 7.3). Adds a default-OFF KEEP_CORE_FROST_INTERACTIVE_SIGNING_ONLY gate; when set, the executor REFUSES to fall through to the coarse signing primitive: if interactive signing did not run (its audit gate off, or no engine), the attempt fails CLOSED rather than silently signing over the retired coarse path. The hard-fail on a committed interactive failure is unchanged; this only converts the (nil signature, nil error) "interactive not enabled -> coarse" fall-through into a refusal. Default off, so production is unchanged: coarse stays the path until an operator flips this on. Flipping it on IS the tECDSA->FROST cutover for that node (the coarse fallback is gone), so it stays off until the frost-secp256k1-tr external audit clears and the recovery-leaf decision lands - the actual code deletion of the transitional coarse primitive is the irreversible follow-up, deliberately deferred. Tests: TestEntry_InteractiveOnly_RefusesCoarseFallback (orchestration active + interactive audit gate off + this flag on -> the executor returns a refusal naming the env var, no signature) and TestEntry_InteractiveSigningOnlyEnabled_ParsesFlag. Existing static-fallback executor tests unchanged (the flag defaults off). Builds clean across the tag combos; cgo vet + gofmt clean. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 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 |
…n point Codex review (PR #4101 P2): the interactive-only check sat in attemptRoastRetryOrchestrationFromRequest, AFTER the drive - so the earlier static-fallback returns (readiness gate off, no coordinator registered, unsupported signer material) returned (nil, nil, nil) before the check ran, and the adapter then proceeded to the coarse primitive. KEEP_CORE_FROST_INTERACTIVE_SIGNING_ONLY was bypassed on exactly the misconfigured/cutover paths it was meant to protect. Move the enforcement to native_ffi_executor_adapter, the SINGLE point where the coarse primitive is invoked: when the orchestration yields no interactive signature for ANY reason (audit gate off, no engine, or any static fallback) and interactive-only mode is on, the adapter fails CLOSED before nefea.primitive.Sign instead of falling through. Revert the partial executor-entry check. Test moves to the adapter level: TestNativeExecutionFFIExecutorAdapter_Execute_ InteractiveOnlyRefusesCoarse runs in the DEFAULT build, where the orchestration helper is a no-op (nil,nil,nil) - the ultimate static fallback - and asserts the adapter returns a refusal AND the coarse primitive's signCalls == 0 (never invoked). Plus the flag-parsing test. Builds across all tag combos; existing adapter + executor-entry tests unchanged; gofmt clean. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Fold of two Codex #4101 P2 findings: - P2-1 (suppress outer fallbacks): the interactive-only guard lived only inside the FFI adapter, so when the native FFI path was unavailable (ErrNativeCryptographyUnavailable before the adapter's guard) the OUTER buildTaggedNativeExecutionBridge/Adapter still delegated to the legacy backend, because nativeExecutionFallbackAllowed() stayed true. Gate that single function on the flag: interactive-only now returns false there, closing every outer legacy/coarse fallback (the bridge + adapter consult it before delegating). New backend test asserts the suppression. - P2-2 (terminal classification): the adapter's refusal returned a plain error, so the tBTC signingRetryLoop (which only aborts on ErrTerminalSigningFailure) treated this deterministic configuration failure as retryable and spun to timeout. Wrap the refusal with %w ErrTerminalSigningFailure; the adapter test now asserts errors.Is. Also folds my own review's scope notes into the gate doc: interactive-only is format-agnostic (refuses coarse for every signer format the native executor handles), closes both the inner FFI primitive and the outer fallbacks, and fails all native signing closed in a build without the interactive engine - so enable it only on a frost_native node with the audit gate on. Builds across all tag combos; full default + frost_native/frost_roast_retry suites pass; gofmt clean. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…coarse flag Fold of a third round of Codex #4101 P2 findings - the flag's fail-closed behavior still had two holes, both now enforced at the backend Execute (the action) so they cannot be bypassed by a caller: - The DEFAULT backend fails OPEN. KEEP_CORE_FROST_INTERACTIVE_SIGNING_ONLY was checked only in nativeExecutionFallbackAllowed + the native FFI adapter. A node left at the documented default (""/legacy) signs straight through legacyExecutionBackend.Execute (the tECDSA/coarse signer), never touching those guards - so the safety switch failed open under the default config. legacyExecutionBackend.Execute now refuses with a terminal error when the flag is on. - Outer native refusals were retryable. When the native path is unavailable before the FFI adapter's terminal refusal can run (no FFI executor, or the bridge returns ErrNativeCryptographyUnavailable with the fallback suppressed), the bridge/adapter return a bare ErrNativeCryptographyUnavailable; the tBTC signingRetryLoop only aborts on ErrTerminalSigningFailure, so it retried this deterministic failure to timeout. nativeExecutionBackend.Execute now promotes that unavailable error to terminal when the flag is on (and leaves it untouched when off). Tests: legacy terminal refusal; native unavailable->terminal promotion plus a flag-off pass-through (no regression). Builds across all tag combos; full default + frost_native/frost_roast_retry suites pass; gofmt clean. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
d1589fa
into
feat/frost-schnorr-migration-scaffold
15 of 16 checks passed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
The reversible, un-gated first half of coarse-path retirement (RFC-21 Phase 7.3). Adds a default-off
KEEP_CORE_FROST_INTERACTIVE_SIGNING_ONLYgate; when set, the executor refuses to fall through to the coarse signing primitive — if interactive signing did not run (its audit gate off, or no engine registered), the attempt fails closed rather than silently signing over the retired coarse path.Only the
(nil signature, nil error)"interactive not enabled → coarse" fall-through becomes a refusal; the hard-fail on a committed interactive failure is unchanged.Safety / sequencing
frost-secp256k1-trexternal audit clears and the recovery-leaf decision lands.Tests
TestEntry_InteractiveOnly_RefusesCoarseFallback— orchestration active + interactive audit gate off + this flag on → the executor returns a refusal naming the env var, no signature.TestEntry_InteractiveSigningOnlyEnabled_ParsesFlag— flag parsing.🤖 Generated with Claude Code