Re-gate auto-update to Base+Premium now that paid activation works
end-to-end (absorbs #271), and align the Rust entitlement layer with the
TS matrix shipped in #297:
- FEATURE_TIERS: auto-update -> [base, premium]; the 'temporarily open'
carve-out and its test are gone (free_allows_auto_update_temporarily
-> free_denied_auto_update). Dead rows web-sync, cloud-backup and
advanced-reports are purged (no call-site anywhere; advanced-reports
-> Premium contradicted the TS reports-advanced -> Base+ matrix).
Only auto-update remains on the Rust side.
- features[] override, fail-closed in Free (CWE-863): new
current_entitlements() resolves the edition AND the signed features[]
through the same machine-binding path — every downgrade path returns
('free', []) so a copied license.key can never keep its signed
features. check_entitlement combines them via the new pure
is_entitled(): is_feature_allowed(feature, edition) ||
features.contains(feature), with a defense-in-depth free short-circuit
mirroring the TS isEntitled. current_edition() now delegates to
current_entitlements() — single resolution path, no drift possible.
- dev-override: new Cargo feature (off by default, never in a release
feature set — CWE-489: debug_assertions could be flipped on a custom
release build and become a Premium backdoor). Only when compiled in,
SR_DEV_EDITION forces the edition (free|base|premium) to test tiers
locally. A feature-off test proves the env var has zero effect in
normal builds; feature-on companions (env access serialized by a
mutex) cover cargo test --features dev-override.
No Tauri command signature changes: check_entitlement keeps its
(feature: String) -> Result<bool, String> contract for useUpdater.ts
and ErrorPage.tsx.
Validation: cargo check + cargo test (106 passed, feature off) +
cargo test --features dev-override + npm test (871) + npm run build.
Resolves#301
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>