revert(registry): restore strict sev_enabled check in update_subnet#9956
revert(registry): restore strict sev_enabled check in update_subnet#9956
Conversation
There was a problem hiding this comment.
This pull request changes code owned by the Governance team. Therefore, make sure that
you have considered the following (for Governance-owned code):
-
Update
unreleased_changelog.md(if there are behavior changes, even if they are
non-breaking). -
Are there BREAKING changes?
-
Is a data migration needed?
-
Security review?
How to Satisfy This Automatic Review
-
Go to the bottom of the pull request page.
-
Look for where it says this bot is requesting changes.
-
Click the three dots to the right.
-
Select "Dismiss review".
-
In the text entry box, respond to each of the numbered items in the previous
section, declare one of the following:
-
Done.
-
$REASON_WHY_NO_NEED. E.g. for
unreleased_changelog.md, "No
canister behavior changes.", or for item 2, "Existing APIs
behave as before.".
Brief Guide to "Externally Visible" Changes
"Externally visible behavior change" is very often due to some NEW canister API.
Changes to EXISTING APIs are more likely to be "breaking".
If these changes are breaking, make sure that clients know how to migrate, how to
maintain their continuity of operations.
If your changes are behind a feature flag, then, do NOT add entrie(s) to
unreleased_changelog.md in this PR! But rather, add entrie(s) later, in the PR
that enables these changes in production.
Reference(s)
For a more comprehensive checklist, see here.
GOVERNANCE_CHECKLIST_REMINDER_DEDUP
| let attempting_to_disable = | ||
| subnet_features.sev_enabled == Some(true) && update_features.sev_enabled == Some(false); | ||
| if attempting_to_disable { | ||
| if let Some(sev_enabled) = features.sev_enabled { |
There was a problem hiding this comment.
It doesn't seem to be right, because (surprisingly to me at least) the features are REPLACED when updating the subnet, and null seems to be treated the same as Some(false). In other words, a proposal can still disable SEV by setting the features to Some(SubnetFeatures { ..., sev_enabled: None}).
I think the problem was introduced by #3044, and I believe the right solution is to compare against the existing sev_enabled like pre-#3044, while still avoiding the unnecessary panic.
Other solutions came to mind but I don't think they are the right choice:
- do a "merge" of the features from the payload to the existing record, it changes semantics and could be confusing when the features has a mixture of
boolandopt bool - separate the types of SubnetFeatures between record and payload which introduces API changes and potentially data change
Partially reverts #9038. `sev_enabled` can once again only be set at subnet creation; any attempt to change it via `do_update_subnet` now panics, as it did before. The SEV invariant added in the same PR (SEV-enabled subnets must contain only nodes with a chip ID) is kept intact.
Per @jasonz-dfinity's review on #9956: because `merge_subnet_record` wholesale-replaces `subnet_record.features` via `maybe_set_option!`, a proposal could disable SEV on an SEV-enabled subnet by setting `features = Some(SubnetFeatures { ..., sev_enabled: None })`. The restored strict check (introduced in #3044) only panicked when `payload.features.sev_enabled` was explicitly `Some(_)`, so this implicit transition slipped through. Compare the effective `sev_enabled` (post-replacement) against the existing record via the rust-level `SubnetFeatures`, which collapses `None` and `Some(false)` to `false`. This catches both explicit and implicit changes while still permitting no-op updates (the case #3044 originally fixed). Adds two regression tests (explicit and implicit disable) plus a no-op test, against an SEV-enabled fixture seeded with chip-ID'd nodes so the SEV invariant stays satisfied.
5ca6791 to
2e5ad74
Compare
Partially reverts #9038:
validate_update_sev_featureindo_update_subnet—sev_enabledcan once again only be set at subnet creation; any update that setsfeatures.sev_enablednow panics, as it did before.check_sev_subnet_invariantsinrs/registry/canister/src/invariants/subnet.rsand its tests).