feat: establish native desktop update trust root

This commit is contained in:
冰朔 2026-08-12 10:29:00 +08:00
commit cff488bb03
29 changed files with 8485 additions and 60 deletions

View file

@ -0,0 +1,12 @@
mod release_trust;
#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
tauri::Builder::default()
.setup(|app| {
release_trust::install_updater_if_provisioned(app.handle())?;
Ok(())
})
.run(tauri::generate_context!())
.expect("failed to run HoloLake native desktop");
}

View file

@ -0,0 +1,5 @@
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
fn main() {
hololake_native_desktop_lib::run();
}

View file

@ -0,0 +1,179 @@
use serde::Deserialize;
use tauri::{AppHandle, Runtime, Url};
use tauri_plugin_updater::UpdaterExt;
const EMBEDDED_RELEASE_TRUST: &str = include_str!("../release-trust.json");
#[derive(Debug, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
struct ReleaseTrust {
schema: String,
state: TrustState,
endpoints: Vec<String>,
public_key: String,
allowed_release_hosts: Vec<String>,
automatic_check_on_startup: bool,
automatic_download: bool,
human_opt_in_install_required: bool,
automatic_restart: bool,
}
#[derive(Debug, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
enum TrustState {
UnprovisionedFailClosed,
Provisioned,
}
enum ValidatedReleaseTrust {
Disabled,
Enabled {
endpoints: Vec<Url>,
public_key: String,
},
}
fn validate_release_trust(raw: &str) -> Result<ValidatedReleaseTrust, String> {
let trust: ReleaseTrust = serde_json::from_str(raw)
.map_err(|error| format!("invalid HoloLake release trust document: {error}"))?;
if trust.schema != "hololake.release-trust/v1" {
return Err("unsupported HoloLake release trust schema".into());
}
if trust.automatic_check_on_startup || trust.automatic_download || trust.automatic_restart {
return Err("automatic check, download and restart must remain disabled".into());
}
if !trust.human_opt_in_install_required {
return Err("human opt-in installation is required".into());
}
match trust.state {
TrustState::UnprovisionedFailClosed => {
if !trust.endpoints.is_empty()
|| !trust.public_key.is_empty()
|| !trust.allowed_release_hosts.is_empty()
{
return Err(
"unprovisioned trust must not contain endpoint or public key material".into(),
);
}
Ok(ValidatedReleaseTrust::Disabled)
}
TrustState::Provisioned => {
if trust.endpoints.len() != 1 {
return Err("exactly one HoloLake release endpoint is required".into());
}
if trust.public_key.trim().is_empty() {
return Err("the HoloLake updater public key is required".into());
}
if trust.allowed_release_hosts.len() != 1 {
return Err("exactly one HoloLake-owned release host is required".into());
}
let allowed_host = trust.allowed_release_hosts[0].trim();
if allowed_host.is_empty() || allowed_host.contains('/') || allowed_host.contains(':') {
return Err("the HoloLake release host must be a bare DNS name".into());
}
let endpoint = Url::parse(&trust.endpoints[0])
.map_err(|error| format!("invalid HoloLake release endpoint: {error}"))?;
if endpoint.scheme() != "https" {
return Err("the HoloLake release endpoint must use HTTPS".into());
}
if endpoint.host_str() != Some(allowed_host) {
return Err(
"the updater endpoint is not owned by the configured HoloLake host".into(),
);
}
Ok(ValidatedReleaseTrust::Enabled {
endpoints: vec![endpoint],
public_key: trust.public_key,
})
}
}
}
pub fn install_updater_if_provisioned<R: Runtime>(
app: &AppHandle<R>,
) -> Result<(), Box<dyn std::error::Error>> {
match validate_release_trust(EMBEDDED_RELEASE_TRUST)? {
ValidatedReleaseTrust::Disabled => Ok(()),
ValidatedReleaseTrust::Enabled {
endpoints,
public_key,
} => {
let updater = tauri_plugin_updater::Builder::new()
.pubkey(public_key)
.build();
app.plugin(updater)?;
app.updater_builder().endpoints(endpoints)?.build()?;
Ok(())
}
}
}
#[cfg(test)]
mod tests {
use super::{validate_release_trust, ValidatedReleaseTrust};
fn document(state: &str, endpoint: &str, public_key: &str, allowed_host: &str) -> String {
format!(
r#"{{
"schema":"hololake.release-trust/v1",
"state":"{state}",
"endpoints":[{endpoint}],
"publicKey":"{public_key}",
"allowedReleaseHosts":[{allowed_host}],
"automaticCheckOnStartup":false,
"automaticDownload":false,
"humanOptInInstallRequired":true,
"automaticRestart":false
}}"#
)
}
#[test]
fn unprovisioned_document_disables_update_networking() {
let trust =
validate_release_trust(&document("UNPROVISIONED_FAIL_CLOSED", "", "", "")).unwrap();
assert!(matches!(trust, ValidatedReleaseTrust::Disabled));
}
#[test]
fn accepts_https_shape_but_rejects_insecure_endpoints() {
let owned_shape = document(
"PROVISIONED",
"\"https://releases.example.test/latest.json\"",
"public",
"\"releases.example.test\"",
);
assert!(
validate_release_trust(&owned_shape).is_ok(),
"endpoint ownership is additionally checked by release provisioning"
);
let insecure = document(
"PROVISIONED",
"\"http://releases.example.test/latest.json\"",
"public",
"\"releases.example.test\"",
);
assert!(validate_release_trust(&insecure).is_err());
let mismatched_host = document(
"PROVISIONED",
"\"https://upstream.example.test/latest.json\"",
"public",
"\"releases.example.test\"",
);
assert!(validate_release_trust(&mismatched_host).is_err());
}
#[test]
fn rejects_automatic_or_nonconsensual_install_policy() {
let automatic = document("UNPROVISIONED_FAIL_CLOSED", "", "", "")
.replace("\"automaticDownload\":false", "\"automaticDownload\":true");
assert!(validate_release_trust(&automatic).is_err());
let no_opt_in = document("UNPROVISIONED_FAIL_CLOSED", "", "", "").replace(
"\"humanOptInInstallRequired\":true",
"\"humanOptInInstallRequired\":false",
);
assert!(validate_release_trust(&no_opt_in).is_err());
}
}