Repository navigation
Make recovery fail closed and let later-added devices recover - #25
Merged
Merged
Conversation
Recovery may override a head only when it is proven invalid, but it treated any unrecognised error as Invalid, skipped candidates it could not classify, and kept going after exhausting its budget. A corrupt local cache, a future schema, or budget exhaustion could therefore make recovery publish from an incomplete view and discard a valid head, including a revocation. - InvalidState marks only failures of authenticated content: AEAD and signature failures, content-id mismatch, malformed HEAD/manifest/policy bytes and failed validation of authenticated structures. Only that type classifies as Invalid; anything unrecognised is Unverifiable and blocks. - BudgetExhausted during candidate discovery aborts recovery. - A candidate that is not Valid or proven Invalid blocks publication instead of being skipped. - Manifest headers and policies read their format version and authorization variant before full decoding, so future schemas and multi-admin thresholds are Unsupported rather than malformed. - A candidate in the local floor chain is a replay, decided by ID before any unwrap. Recovery no longer opens pre-admission heads with a later-added device's key, so such devices can recover.
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.
Step 1 of the refactoring plan from the whole-codebase reviews (Opus 1.1 and 1.2, Astra Category 1 highs 1 and 3).
Recovery may override a head only when it is proven invalid. Before this change, it:
So a corrupt local cache, a future schema, or budget exhaustion could make
recover --publishbuild on an incomplete view and discard a valid head, including a revocation.Change
Positive Invalid. A new
InvalidStateerror marks only failures of authenticated content:Only
InvalidStateclassifies as Invalid. Anything unrecognised, including ioInvalidData, is now Unverifiable, which blocks publication. A junk HEAD is still Invalid and still recoverable.Budget exhaustion is fatal.
BudgetExhaustedduring candidate discovery or the floor chain aborts recovery.Unclassifiable candidates block. Only Invalid candidates are skipped. Unavailable, Unverifiable, Unsupported and Discontinuous candidates block publication, and the reason is reported.
Version first. Manifest headers and policies read
format_version, and the manifest authorization variant, before full decoding. A future schema or a multi-admin threshold is Unsupported, not malformed. A threshold of 0 is invalid.Later-added devices can recover. A candidate whose ID is in the local floor chain is a replay, and this is decided before any unwrap. Before, recovery opened pre-admission heads with the device's own key and was blocked as "unverifiable" for every device except the owner. A head at or below the floor that is not in the floor chain is still opened and never offered: proven Invalid is skipped, anything else blocks.
docs/spec.mdstates the new rules. No recovery class was added, and storage format v6 is unchanged.Tests
Each new test fails on
mainand passes here; this was checked by restoring the original sources.recovery_classification_ignores_storage_controlled_message_text,recovery_classification_follows_error_types_through_context(updated: unknown → Unverifiable)recovery_budget_exhaustion_inside_candidate_discovery_is_fatal(main published)recovery_refuses_to_skip_a_discontinuous_historical_head(main published)a_future_header_schema_is_unsupported_not_malformed,an_unknown_authorization_variant_is_unsupported_not_malformed,a_future_policy_schema_is_unsupported_not_malformed,a_multi_admin_threshold_is_unsupported_and_zero_is_invalid,recover_refuses_a_head_with_a_future_manifest_schema(main: Invalid)carrier_recovery_works_for_a_writer_added_after_genesis(main: blocked as unverifiable) and the controlcarrier_recovery_works_for_the_ownercargo fmt --check,cargo clippy --all-targets -- -D warnings,cargo test --all-targets(167 passed).Errors from chain authentication now begin with "authenticated repository state is invalid:".