Files
buzz/desktop/src-tauri/src/reset_demo_tests.rs
Logan Johnson 4a9de1a3a1 feat(desktop): add isolated named demo builds (#6407)
🤖 I’m Larry, updating this description on Logan’s behalf.

## Summary

Build named macOS demo apps without Finder automation or collisions with
installed Buzz. `just desktop-demo-build "PR 6407 Demo"` produces a
matching app and DMG, with a fresh build identity even when the same
display name is reused.

- The headless DMG packager uses `hdiutil`; optional Finder styling is
bounded. The existing production release recipe is unchanged.
- Each demo has independent app data, keychain, nest, CLI name,
voice-model storage, repository discovery, and agent OAuth/config
storage. Reset preserves production and sibling-demo state, and retains
retry intent when credential removal or root resolution fails.
- Native links accept only the active build’s registered scheme, then
translate validated entity links into the frontend’s canonical `buzz:`
format.
- The recipe builds all six executable sidecars. Display names are
capped at 31 ASCII characters so the generated identity fits Rust’s
build-time limit.

**Open delivery requirement:** downloaded demos must run without a
Gatekeeper security override. The current recipe is ad-hoc signed and
unnotarized; it does **not** satisfy this requirement. Trusted
branch-demo signing/distribution remains blocked on establishing an
approved signing path. This PR is not being presented as complete
download-and-run delivery.

### Related issue

N/A — reported in the Buzz DMG-packaging workstream.

### Testing

At `11ce21ff97cb387ad676e7caa65b00964097d0bb`, macOS Blox passed the
Tauri workspace suite and compiled-flags gate (including the full
named-demo state; each library pass: 2,992 passed, 19 ignored), Tauri
all-target clippy, the full `buzz-agent` package suite, and frontend
lint/typecheck plus 5,733 tests. Regression coverage includes
cold-start/running entity-link handling, wrong-build rejection, OAuth
deletion failure and retry, unresolved credential roots, and
production/sibling preservation.

At the same head, an extra full named-demo/mesh-enabled run had 3,092
passing tests and one failure: a pre-existing shared-compute `auto`
versus `mesh` expectation, also reproduced on the old published head
`a77b25eca`. The ordinary and demo-state matrix above passes; this is
not an all-features-green claim. Live macOS Launch Services delivery
remains unverified.

GitHub CI completed with 30 successful checks and 9 skipped. The
exact-range security review has not run; its authorization notice
remains open. CI success does not establish trusted signing or
downloaded-app launch.

Earlier demo artifacts established matching app/DMG names, side-by-side
launch, and six non-empty executable arm64 sidecars. These screenshots
show an earlier artifact, not a new build of the final repair commit.
Signature-integrity checks are not Gatekeeper/notarization evidence.

<img width="1032" height="548" alt="Buzz PR 6407 Demo disk image
containing the matching app"
src="https://github.com/user-attachments/assets/bca0277e-db03-4308-b280-fcad55e6d601"
/>

<img width="1186" height="821" alt="Buzz PR 6407 Demo running alongside
other Buzz installations"
src="https://github.com/user-attachments/assets/b4bf4ae5-c341-4e15-8090-9d2ea7c623b6"
/>

---------

Signed-off-by: Logan Johnson <loganj@squareup.com>
Signed-off-by: Larry <8cf5a83f590ec0955b11647d1c88f796a98e088c30a492c58e0e46c3026ae7a4@buzz.block.builderlab.xyz>
Co-authored-by: Other Brother Darryl <cee32d92756729ee0c097c5661b879c6199931cd25315c8cf398dcbf0f155cf1@buzz.block.builderlab.xyz>
Co-authored-by: Larry <loganj+sandbox-larry@squareup.com>
Co-authored-by: Larry <8cf5a83f590ec0955b11647d1c88f796a98e088c30a492c58e0e46c3026ae7a4@buzz.block.builderlab.xyz>
2026-08-31 21:14:19 -04:00

170 lines
6.0 KiB
Rust

use super::*;
#[test]
fn test_demo_reset_preserves_shared_and_other_build_state() {
let tmp = TempDir::new().unwrap();
let home = tmp.path().join("home");
let app_data = tmp
.path()
.join("Application Support")
.join("xyz.block.buzz.app.demo.current-1234567812345678");
let demo_nest = home.join(".buzz-demo-current-1234567812345678");
let prod_nest = home.join(".buzz");
let other_demo_nest = home.join(".buzz-demo-other-8765432187654321");
let shared_sprout = home.join(".sprout");
let shared_agent = home.join(".config").join("buzz-agent");
let demo_config = home
.join("Library")
.join("Application Support")
.join("buzz-demo-current-1234567812345678");
let demo_oauth = demo_config.join("buzz-agent").join("oauth");
let other_demo_config = home
.join("Library")
.join("Application Support")
.join("buzz-demo-other-8765432187654321");
let other_demo_oauth = other_demo_config.join("buzz-agent").join("oauth");
for path in [
&app_data,
&demo_nest,
&prod_nest,
&other_demo_nest,
&shared_sprout,
&shared_agent,
&demo_oauth,
&other_demo_oauth,
] {
std::fs::create_dir_all(path).unwrap();
}
write_sentinel(&app_data).unwrap();
let kc = FakeKeychain::ok();
let ctx = ResetContext {
app_data_dir: &app_data,
legacy_app_data_dir: None,
nest_dir: Some(demo_nest.clone()),
keychain: &kc,
home_dir: Some(home),
is_dev: false,
demo_config_dir: Some(demo_config.clone()),
is_demo: true,
};
let outcome = run_boot_reset_with_keychain(ctx);
assert!(outcome.completed, "demo reset must complete");
assert!(!app_data.exists(), "demo app data must be wiped");
assert!(!demo_nest.exists(), "selected demo nest must be wiped");
assert!(
!demo_config.exists(),
"selected demo auth root must be wiped"
);
assert!(
other_demo_oauth.exists(),
"another demo's concrete auth root must survive"
);
assert!(prod_nest.exists(), "production nest must survive");
assert!(other_demo_nest.exists(), "another demo nest must survive");
assert!(shared_sprout.exists(), "shared legacy state must survive");
assert!(
shared_agent.exists(),
"shared agent auth state must survive"
);
}
#[test]
fn demo_config_delete_failure_keeps_sentinel_until_retry() {
let tmp = TempDir::new().unwrap();
let app_data = make_app_data(&tmp);
let config = tmp.path().join("demo-config");
let production = tmp.path().join("production/oauth/token.json");
let sibling = tmp.path().join("sibling/oauth/token.json");
for path in [&production, &sibling] {
std::fs::create_dir_all(path.parent().unwrap()).unwrap();
std::fs::write(path, "preserve").unwrap();
}
// A file at the directory path makes remove_dir_all fail on every platform,
// independent of the test user's privileges.
std::fs::write(&config, "obstruction").unwrap();
write_sentinel(&app_data).unwrap();
let kc = FakeKeychain::ok();
let run = || {
let mut ctx = make_ctx(&app_data, &kc, false);
ctx.is_demo = true;
ctx.demo_config_dir = Some(config.clone());
run_boot_reset_with_keychain(ctx)
};
let first = run();
assert!(first.failed && !first.completed);
assert!(check_sentinel(&app_data));
assert!(config.exists());
std::fs::remove_file(&config).unwrap();
let token = config.join("buzz-agent/oauth/databricks/token.json");
std::fs::create_dir_all(token.parent().unwrap()).unwrap();
std::fs::write(&token, "demo credential").unwrap();
let second = run();
assert!(second.completed && !second.failed);
assert!(!check_sentinel(&app_data));
assert!(!config.exists());
for path in [&production, &sibling] {
assert_eq!(std::fs::read_to_string(path).unwrap(), "preserve");
}
// A retry after a crash that already removed the root must also succeed.
write_sentinel(&app_data).unwrap();
assert!(run().completed);
assert!(!check_sentinel(&app_data));
}
#[cfg(unix)]
#[test]
fn demo_oauth_permission_failure_preserves_retry_intent() {
use std::os::unix::fs::PermissionsExt;
let tmp = TempDir::new().unwrap();
let app_data = make_app_data(&tmp);
let config = tmp.path().join("demo-config");
let oauth = config.join("buzz-agent/oauth/databricks");
let token = oauth.join("token.json");
std::fs::create_dir_all(&oauth).unwrap();
std::fs::write(&token, "demo credential").unwrap();
write_sentinel(&app_data).unwrap();
let kc = FakeKeychain::ok();
let run = || {
let mut ctx = make_ctx(&app_data, &kc, false);
ctx.is_demo = true;
ctx.demo_config_dir = Some(config.clone());
run_boot_reset_with_keychain(ctx)
};
std::fs::set_permissions(&oauth, std::fs::Permissions::from_mode(0o500)).unwrap();
let first = run();
// Restore permissions before assertions so a failure never leaves test debris.
if oauth.exists() {
std::fs::set_permissions(&oauth, std::fs::Permissions::from_mode(0o700)).unwrap();
}
assert!(first.failed && !first.completed);
assert!(check_sentinel(&app_data));
assert_eq!(std::fs::read_to_string(&token).unwrap(), "demo credential");
assert!(run().completed);
assert!(!config.exists());
assert!(!check_sentinel(&app_data));
}
#[test]
fn unresolved_demo_config_keeps_reset_pending_without_deleting_state() {
let tmp = TempDir::new().unwrap();
let app_data = make_app_data(&tmp);
write_sentinel(&app_data).unwrap();
let kc = FakeKeychain::ok();
let mut ctx = make_ctx(&app_data, &kc, false);
ctx.is_demo = true;
assert!(ctx.demo_config_dir.is_none());
let outcome = run_boot_reset_with_keychain(ctx);
assert!(outcome.failed && !outcome.completed);
assert!(check_sentinel(&app_data));
assert!(
app_data.exists(),
"unresolved root must refuse before wiping"
);
}