fix(permissions): make profile snapshots authoritative

This commit is contained in:
2026-07-09 21:56:36 -04:00
parent c28ec2bee8
commit b422ac1631
47 changed files with 1918 additions and 403 deletions
+26
View File
@@ -136,6 +136,32 @@ fn export_local_data_command_opens_privacy_security_page() -> Result<(), Box<dyn
Ok(())
}
#[test]
fn local_data_export_omits_ephemeral_allow_once_state() -> Result<(), Box<dyn Error>> {
let mut core = BrowserCore::new(InitialBrowserConfig::ely_defaults()?)?;
let profile_id = core.snapshot()?.active_profile_id;
let origin = SiteOrigin::parse("https://example.com")?;
let feature = SitePermissionFeature::Camera;
core.set_site_permission(origin.clone(), feature, SitePermissionDecision::AllowOnce)?;
let document: serde_json::Value =
serde_json::from_str(&core.export_local_data_package_json()?)?;
let inventory = core.active_profile_local_data_inventory();
assert_eq!(inventory.site_permissions(), 0);
assert_eq!(array_len(&document, "site_permissions"), 0);
assert_eq!(array_len(&document, "site_permission_audit_events"), 1);
let revision = core.site_permission_revision(&profile_id, &origin, feature);
assert!(core.transfer_site_permission_once(&profile_id, &origin, feature, revision)?);
assert!(core.finish_site_permission_once(&profile_id, &origin, feature, revision)?);
let consumed: serde_json::Value =
serde_json::from_str(&core.export_local_data_package_json()?)?;
assert_eq!(array_len(&consumed, "site_permission_audit_events"), 3);
assert_eq!(consumed["site_permission_audit_events"][2]["action"]["kind"], "consumed");
Ok(())
}
fn array_len(document: &serde_json::Value, field: &str) -> usize {
document[field].as_array().map_or(0, Vec::len)
}
+10 -1
View File
@@ -91,8 +91,17 @@ fn clear_active_profile_site_data_reports_removed_counts() -> Result<(), Box<dyn
core.set_site_permission(
origin.clone(),
SitePermissionFeature::Camera,
SitePermissionDecision::AllowAlways,
SitePermissionDecision::AllowOnce,
)?;
let profile_id = core.snapshot()?.active_profile_id;
let revision =
core.site_permission_revision(&profile_id, &origin, SitePermissionFeature::Camera);
assert!(core.transfer_site_permission_once(
&profile_id,
&origin,
SitePermissionFeature::Camera,
revision,
)?);
core.set_site_permission(
origin,
SitePermissionFeature::Notifications,
@@ -140,6 +140,73 @@ fn clear_site_permissions_without_entries_is_empty_change() -> Result<(), Box<dy
Ok(())
}
#[test]
fn allow_once_transfer_and_finish_require_the_token_revision() -> Result<(), Box<dyn Error>> {
let mut core = BrowserCore::new(InitialBrowserConfig::ely_defaults()?)?;
let snapshot = core.snapshot()?;
let profile_id = snapshot.active_profile_id;
let origin = SiteOrigin::parse("https://example.com")?;
let feature = SitePermissionFeature::Camera;
core.set_site_permission(origin.clone(), feature, SitePermissionDecision::AllowOnce)?;
let revision = core.site_permission_revision(&profile_id, &origin, feature);
assert!(!core.transfer_site_permission_once(&profile_id, &origin, feature, revision + 1,)?);
assert!(core.transfer_site_permission_once(&profile_id, &origin, feature, revision)?);
let snapshot = core.snapshot()?;
assert_eq!(snapshot.site_permissions.len(), 1);
assert_eq!(
snapshot.site_permission_audit_events.last().map(|event| event.action()),
Some(&SitePermissionAuditAction::Transferred),
);
assert!(!core.finish_site_permission_once(&profile_id, &origin, feature, revision + 1)?);
assert!(core.finish_site_permission_once(&profile_id, &origin, feature, revision)?);
let snapshot = core.snapshot()?;
assert!(snapshot.site_permissions.is_empty());
assert_eq!(
snapshot.site_permission_audit_events.last().map(|event| event.action()),
Some(&SitePermissionAuditAction::Consumed),
);
Ok(())
}
#[test]
fn clear_site_permissions_revokes_transferred_allow_once() -> Result<(), Box<dyn Error>> {
let mut core = BrowserCore::new(InitialBrowserConfig::ely_defaults()?)?;
let profile_id = core.snapshot()?.active_profile_id;
let origin = SiteOrigin::parse("https://example.com")?;
let feature = SitePermissionFeature::Camera;
core.set_site_permission(origin.clone(), feature, SitePermissionDecision::AllowOnce)?;
let revision = core.site_permission_revision(&profile_id, &origin, feature);
assert!(core.transfer_site_permission_once(&profile_id, &origin, feature, revision)?);
assert_eq!(core.clear_active_profile_site_permissions()?, 1);
let snapshot = core.snapshot()?;
assert!(snapshot.site_permissions.is_empty());
assert_eq!(
snapshot.site_permission_audit_events.last().map(|event| event.action()),
Some(&SitePermissionAuditAction::Revoked),
);
Ok(())
}
#[test]
fn revoke_then_readd_advances_permission_revision() -> Result<(), Box<dyn Error>> {
let mut core = BrowserCore::new(InitialBrowserConfig::ely_defaults()?)?;
let profile_id = core.snapshot()?.active_profile_id;
let origin = SiteOrigin::parse("https://example.com")?;
let feature = SitePermissionFeature::Location;
core.set_site_permission(origin.clone(), feature, SitePermissionDecision::AllowOnce)?;
let first_revision = core.site_permission_revision(&profile_id, &origin, feature);
core.revoke_site_permission(&origin, feature)?;
core.set_site_permission(origin.clone(), feature, SitePermissionDecision::AllowOnce)?;
assert!(core.site_permission_revision(&profile_id, &origin, feature) > first_revision);
Ok(())
}
#[test]
fn site_settings_command_opens_active_origin() -> Result<(), Box<dyn Error>> {
let mut core = BrowserCore::new(InitialBrowserConfig::ely_defaults()?)?;
@@ -98,3 +98,25 @@ fn sync_snapshot_omits_paused_site_permissions() -> Result<(), Box<dyn Error>> {
assert!(snapshot.site_permissions.is_empty());
Ok(())
}
#[test]
fn sync_snapshot_omits_allow_once_permissions() -> Result<(), Box<dyn Error>> {
let mut source = BrowserCore::new(InitialBrowserConfig::ely_defaults()?)?;
let source_home_tab_id = source.snapshot()?.active_tab_id;
source.set_tab_sync_enabled(&source_home_tab_id, false)?;
source.set_site_permission(
SiteOrigin::parse("https://example.com")?,
SitePermissionFeature::Camera,
SitePermissionDecision::AllowOnce,
)?;
let bytes = source.build_sync_snapshot_bytes()?;
let mut target = BrowserCore::new(InitialBrowserConfig::ely_defaults()?)?;
let summary = target.apply_sync_snapshot_bytes(&bytes)?;
assert_eq!(summary.imported(), 0);
assert_eq!(summary.updated(), 0);
assert_eq!(summary.skipped(), 0);
assert!(target.snapshot()?.site_permissions.is_empty());
Ok(())
}