feat(lite): runtime kill-switch + staged-rollout gate (M5b)
Adds a fail-open, local-only gate that decides whether the lite wallet may run,
so a post-release issue can disable it and rollout can be staged — without any
phone-home (privacy posture: no runtime network fetch; the per-install rollout
bucket is a hashed, never-transmitted local id).
- wallet/lite_rollout_policy.{h,cpp}: a pure decision core. Order — emergency env
kill-switch (absolute) -> local override -> manifest gates (global enable /
version floor-ceiling / blocklist / staged-rollout permille) -> fail-open allow.
Plus a JSON manifest loader (missing/invalid -> fail-open) and FNV-1a bucketing.
- Threads the decision through LiteWalletController -> LiteWalletLifecycleService:
new availability() reason RolloutDisabled blocks create/open/restore and surfaces
the gate's user-facing message via the lifecycle status.
- App::rebuildLiteWallet() resolves it from: DRAGONX_LITE_KILL_SWITCH (env), the
lite_rollout setting (auto/force_on/force_off), and a locally-cached manifest at
<config-dir>/lite_rollout.json. install id generated once via libsodium.
- Settings: persist lite_rollout override + the install id.
A signed remote fetcher can populate the manifest cache later without touching the
policy. Unit-tested (version compare, bucketing, override/env precedence, manifest
gates, staged rollout, loader fail-open, controller integration) and runtime-verified
on Linux (env kill-switch, manifest disable, control sync). Both variants build;
full suite passes; hygiene clean.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -20,6 +20,7 @@
|
||||
#include "lite_connection_service.h"
|
||||
#include "lite_wallet_lifecycle_service.h"
|
||||
#include "lite_wallet_gateway.h"
|
||||
#include "lite_rollout_policy.h"
|
||||
#include "lite_sync_service.h"
|
||||
#include "lite_wallet_state_mapper.h"
|
||||
#include "wallet_backend.h"
|
||||
@@ -53,6 +54,8 @@ void applyLiteRefreshModelToWalletState(const LiteWalletAppRefreshModel& model,
|
||||
|
||||
struct LiteWalletControllerOptions {
|
||||
bool allowBridgeCalls = true;
|
||||
bool rolloutBlocked = false; // runtime kill-switch / staged-rollout gate is blocking
|
||||
std::string rolloutMessage; // user-facing reason when rolloutBlocked
|
||||
};
|
||||
|
||||
struct LiteNewAddressResult {
|
||||
@@ -133,10 +136,13 @@ public:
|
||||
LiteWalletController(const LiteWalletController&) = delete;
|
||||
LiteWalletController& operator=(const LiteWalletController&) = delete;
|
||||
|
||||
// Production factory: links the SDXL backend compiled into this build.
|
||||
// Production factory: links the SDXL backend compiled into this build. The optional rollout
|
||||
// decision (runtime kill-switch / staged rollout) gates lifecycle execution: when not allowed,
|
||||
// availability() reports RolloutDisabled and create/open/restore are blocked with its message.
|
||||
static std::unique_ptr<LiteWalletController> createLinked(
|
||||
WalletCapabilities capabilities,
|
||||
LiteConnectionSettings connectionSettings);
|
||||
LiteConnectionSettings connectionSettings,
|
||||
LiteRolloutDecision rollout = LiteRolloutDecision{});
|
||||
|
||||
// Invoked after a wallet becomes ready, so the owner can persist settings.
|
||||
void setPersistCallback(std::function<void()> callback) { persist_ = std::move(callback); }
|
||||
|
||||
Reference in New Issue
Block a user