From 1c3fdfc38a74b3106416dbb2cc266d14c9c742a2 Mon Sep 17 00:00:00 2001 From: Michel Paulissen <862400+MichelPaulissen@users.noreply.github.com> Date: Fri, 3 Jul 2026 23:59:58 +0200 Subject: [PATCH] Sync public tree for logout alias --- DISASMER_PUBLIC_TREE.json | 4 +- crates/disasmer-cli/src/main.rs | 44 ++++++++++++++++++++- scripts/cli-first-contract-smoke.js | 2 + scripts/website-inventory-contract-smoke.js | 8 ++++ 4 files changed, 55 insertions(+), 3 deletions(-) diff --git a/DISASMER_PUBLIC_TREE.json b/DISASMER_PUBLIC_TREE.json index 8922fa5..372a315 100644 --- a/DISASMER_PUBLIC_TREE.json +++ b/DISASMER_PUBLIC_TREE.json @@ -1,7 +1,7 @@ { "kind": "disasmer-filtered-public-tree", - "source_commit": "0dc80fb7a350886260d9504cd7daf6d122d3a6a5", - "release_name": "dryrun-0dc80fb7a350", + "source_commit": "d0ea56e226f6a5fa409ab5284d5c4e550afe2f35", + "release_name": "dryrun-d0ea56e226f6", "filtered_out": [ "private/**", "experiments/**", diff --git a/crates/disasmer-cli/src/main.rs b/crates/disasmer-cli/src/main.rs index 171a60c..6e95a5a 100644 --- a/crates/disasmer-cli/src/main.rs +++ b/crates/disasmer-cli/src/main.rs @@ -36,6 +36,7 @@ struct Cli { enum Commands { Doctor(DoctorArgs), Login(LoginArgs), + Logout(AuthLogoutArgs), Auth { #[command(subcommand)] command: AuthCommands, @@ -819,6 +820,10 @@ fn auth_status_report(args: AuthStatusArgs, cwd: PathBuf) -> Result { } fn auth_logout_report(args: AuthLogoutArgs, cwd: PathBuf) -> Result { + logout_report(args, cwd, "auth logout") +} + +fn logout_report(args: AuthLogoutArgs, cwd: PathBuf, command: &str) -> Result { let session_file = session_config_file(&cwd); let existed = session_file.exists(); if existed { @@ -826,7 +831,7 @@ fn auth_logout_report(args: AuthLogoutArgs, cwd: PathBuf) -> Result { .with_context(|| format!("failed to remove {}", session_file.display()))?; } Ok(json!({ - "command": "auth logout", + "command": command, "requires_confirmation": !args.yes, "removed_cli_session_file": existed, "node_credentials_untouched": true, @@ -2589,6 +2594,11 @@ fn run_cli() -> Result<()> { emit_report(&plan, json_output)?; } } + Commands::Logout(args) => { + let json_output = args.scope.json; + let report = logout_report(args, std::env::current_dir()?, "logout")?; + emit_report(&report, json_output)?; + } Commands::Auth { command } => { let (report, json_output) = match command { AuthCommands::Status(args) => { @@ -5823,6 +5833,7 @@ mod tests { for args in [ &["disasmer", "doctor"][..], &["disasmer", "auth", "status"], + &["disasmer", "logout", "--yes"], &["disasmer", "auth", "logout", "--yes"], &[ "disasmer", @@ -5876,11 +5887,42 @@ mod tests { } } + #[test] + fn top_level_logout_alias_removes_only_cli_session_state() { + let temp = tempfile::tempdir().unwrap(); + let session_file = session_config_file(temp.path()); + fs::create_dir_all(session_file.parent().unwrap()).unwrap(); + fs::write(&session_file, br#"{"kind":"human","token":"local"}"#).unwrap(); + + let report = logout_report( + AuthLogoutArgs { + yes: true, + scope: CliScopeArgs { + coordinator: None, + tenant: "tenant".to_owned(), + project: "project".to_owned(), + user: "user".to_owned(), + json: false, + }, + }, + temp.path().to_path_buf(), + "logout", + ) + .unwrap(); + + assert_eq!(report["command"], "logout"); + assert_eq!(report["requires_confirmation"], false); + assert_eq!(report["removed_cli_session_file"], true); + assert_eq!(report["node_credentials_untouched"], true); + assert!(!session_file.exists()); + } + #[test] fn cli_first_json_mode_parses_for_primary_commands() { for args in [ &["disasmer", "doctor", "--json"][..], &["disasmer", "login", "--json"], + &["disasmer", "logout", "--yes", "--json"], &["disasmer", "auth", "status", "--json"], &[ "disasmer", diff --git a/scripts/cli-first-contract-smoke.js b/scripts/cli-first-contract-smoke.js index 2000bf7..58b67e8 100644 --- a/scripts/cli-first-contract-smoke.js +++ b/scripts/cli-first-contract-smoke.js @@ -139,6 +139,7 @@ assert.doesNotMatch( for (const [name, pattern] of [ ["top-level version metadata", /#\[command\(name = "disasmer", version, arg_required_else_help = true\)\]/], + ["top-level logout command", /enum Commands[\s\S]*Logout\(AuthLogoutArgs\)[\s\S]*Auth \{/], ["human report renderer", /fn human_report\(value: &Value\) -> String/], ["shared report emitter", /fn emit_report\(report: &T, json_output: bool\) -> Result<\(\)>/], ["doctor command", /Doctor\(DoctorArgs\)/], @@ -178,6 +179,7 @@ for (const [name, pattern] of [ ["run coordinator active-process coverage", /fn run_contacts_configured_coordinator_and_reports_active_process_conflicts\(\)/], ["CLI error classifier coverage", /fn cli_error_classifier_distinguishes_mvp_failure_categories\(\)/], ["CLI command exit-code coverage", /fn command_report_exit_code_marks_command_failures_only\(\)/], + ["CLI top-level logout alias coverage", /fn top_level_logout_alias_removes_only_cli_session_state\(\)/], ["CLI run rejection category coverage", /fn run_rejection_reports_machine_readable_error_category\(\)/], ["node attach grant disclosure coverage", /fn node_attach_discloses_dangerous_capability_grants\(\)/], ["quota local status coverage", /fn quota_status_uses_project_config_and_generic_public_limits\(\)/], diff --git a/scripts/website-inventory-contract-smoke.js b/scripts/website-inventory-contract-smoke.js index 7625f36..191711a 100644 --- a/scripts/website-inventory-contract-smoke.js +++ b/scripts/website-inventory-contract-smoke.js @@ -40,6 +40,10 @@ expect( "no duplicate work note", /does not automatically mean new product code, a new feature, or even actual implementation work is required/ ); +expect( + "prove existing behavior before implementation", + /prefer proving, documenting, or tightening that existing behavior over duplicating capability or overengineering a parallel website mechanism/ +); expect( "barebones no CSS", /barebones functional HTML with no CSS/ @@ -52,6 +56,10 @@ expect( "billing is not MVP website work", /Do not build billing\/upgrade flows into the minimal website for this MVP/ ); +expect( + "billing-only surfaces are postponed", + /If a website route, API, database field, control, or acceptance item exists only for billing, paid plans, hosted business operations, broad admin\/moderation, team management, provider setup, secret management, or durable account\/business-process management, postpone it instead of building it for this MVP\./ +); assert.doesNotMatch(source, /community-tier/, "use `community tier`, not `community-tier`"); const lines = criterionLines();