chore(release): prepare public source release
This commit is contained in:
@@ -0,0 +1,23 @@
|
||||
[package]
|
||||
name = "msudo"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
rust-version.workspace = true
|
||||
license.workspace = true
|
||||
authors.workspace = true
|
||||
readme.workspace = true
|
||||
publish.workspace = true
|
||||
keywords.workspace = true
|
||||
categories.workspace = true
|
||||
description = "Launch Windows commands as admin, SYSTEM, or TrustedInstaller with Mercury-friendly output."
|
||||
|
||||
[dependencies]
|
||||
common = { path = "../common", default-features = false }
|
||||
lexopt.workspace = true
|
||||
serde.workspace = true
|
||||
serde_json.workspace = true
|
||||
windowsupport = { path = "../windowsupport" }
|
||||
|
||||
[dev-dependencies]
|
||||
assert_cmd.workspace = true
|
||||
predicates.workspace = true
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,6 @@
|
||||
//! Binary entry point for `msudo`.
|
||||
#![allow(clippy::multiple_crate_versions)]
|
||||
|
||||
fn main() {
|
||||
std::process::exit(msudo::main_entry());
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
use assert_cmd::Command;
|
||||
use predicates::prelude::*;
|
||||
use serde_json::Value;
|
||||
|
||||
fn cargo_command() -> Command {
|
||||
Command::cargo_bin("msudo").expect("binary")
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn help_mentions_dangerous_flag_and_shell_presets() {
|
||||
let mut command = cargo_command();
|
||||
command
|
||||
.arg("--help")
|
||||
.assert()
|
||||
.success()
|
||||
.stdout(predicate::str::contains(
|
||||
"current-process, current-user, admin, system, trustedinstaller",
|
||||
))
|
||||
.stdout(predicate::str::contains("--dangerous"))
|
||||
.stdout(predicate::str::contains("trustedinstaller"))
|
||||
.stdout(predicate::str::contains("Shell preset"))
|
||||
.stdout(predicate::str::contains("pwsh"))
|
||||
.stdout(predicate::str::contains("git-bash"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn status_json_exposes_stable_top_level_fields() {
|
||||
let output = cargo_command()
|
||||
.args(["status", "--json"])
|
||||
.assert()
|
||||
.success()
|
||||
.get_output()
|
||||
.stdout
|
||||
.clone();
|
||||
|
||||
let report: Value = serde_json::from_slice(&output).expect("valid status json");
|
||||
let object = report.as_object().expect("status json object");
|
||||
for field in [
|
||||
"ok",
|
||||
"host",
|
||||
"supports_runas",
|
||||
"is_elevated",
|
||||
"is_admin_member",
|
||||
"integrity",
|
||||
"current_user",
|
||||
"session_id",
|
||||
"active_session_id",
|
||||
"can_admin",
|
||||
"can_current_user",
|
||||
"can_system",
|
||||
"can_trustedinstaller",
|
||||
"trustedinstaller_installed",
|
||||
"trustedinstaller_running",
|
||||
"shells",
|
||||
] {
|
||||
assert!(object.contains_key(field), "missing status field: {field}");
|
||||
}
|
||||
|
||||
assert_eq!(object.get("ok").and_then(Value::as_bool), Some(true));
|
||||
assert!(matches!(object.get("host"), Some(Value::String(_))));
|
||||
assert!(matches!(object.get("supports_runas"), Some(Value::Bool(_))));
|
||||
assert!(matches!(object.get("is_elevated"), Some(Value::Bool(_))));
|
||||
assert!(matches!(
|
||||
object.get("is_admin_member"),
|
||||
Some(Value::Bool(_))
|
||||
));
|
||||
assert!(matches!(object.get("integrity"), Some(Value::String(_))));
|
||||
assert!(matches!(
|
||||
object.get("current_user"),
|
||||
Some(Value::Null | Value::String(_))
|
||||
));
|
||||
assert!(matches!(
|
||||
object.get("session_id"),
|
||||
Some(Value::Null | Value::Number(_))
|
||||
));
|
||||
assert!(matches!(
|
||||
object.get("active_session_id"),
|
||||
Some(Value::Null | Value::Number(_))
|
||||
));
|
||||
for field in [
|
||||
"can_admin",
|
||||
"can_current_user",
|
||||
"can_system",
|
||||
"can_trustedinstaller",
|
||||
"trustedinstaller_installed",
|
||||
"trustedinstaller_running",
|
||||
] {
|
||||
assert!(
|
||||
matches!(object.get(field), Some(Value::Bool(_))),
|
||||
"status field should be boolean: {field}"
|
||||
);
|
||||
}
|
||||
|
||||
let shells = object
|
||||
.get("shells")
|
||||
.and_then(Value::as_array)
|
||||
.expect("shells array");
|
||||
assert!(!shells.is_empty(), "shell preset list should not be empty");
|
||||
|
||||
let first_shell = shells[0].as_object().expect("shell status object");
|
||||
for field in ["preset", "available", "executable", "error"] {
|
||||
assert!(
|
||||
first_shell.contains_key(field),
|
||||
"missing shell status field: {field}"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn help_mentions_console_and_window_launch_controls() {
|
||||
let mut command = cargo_command();
|
||||
command
|
||||
.arg("--help")
|
||||
.assert()
|
||||
.success()
|
||||
.stdout(predicate::str::contains(
|
||||
"current-process, current-user, admin, system, trustedinstaller",
|
||||
))
|
||||
.stdout(predicate::str::contains("--same-console"))
|
||||
.stdout(predicate::str::contains("Reuse the current console"))
|
||||
.stdout(predicate::str::contains("--new-window"))
|
||||
.stdout(predicate::str::contains(
|
||||
"Force a new window for the launched process",
|
||||
));
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
use assert_cmd::Command;
|
||||
use predicates::prelude::*;
|
||||
|
||||
fn cargo_command() -> Command {
|
||||
Command::cargo_bin("msudo").expect("binary")
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn system_user_requires_dangerous_flag() {
|
||||
let mut command = cargo_command();
|
||||
command
|
||||
.args(["--user", "system", "--", "cmd", "/d", "/c", "whoami"])
|
||||
.assert()
|
||||
.code(2)
|
||||
.stderr(predicate::str::contains("--dangerous"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn run_subcommand_without_payload_is_usage_error() {
|
||||
let mut command = cargo_command();
|
||||
command
|
||||
.arg("run")
|
||||
.assert()
|
||||
.code(2)
|
||||
.stderr(predicate::str::contains(
|
||||
"provide a command after -- or select --shell <preset>",
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn current_process_user_rejects_token_shaping_before_launch() {
|
||||
let mut command = cargo_command();
|
||||
command
|
||||
.args([
|
||||
"--user",
|
||||
"current-process",
|
||||
"--privileges",
|
||||
"enable-all",
|
||||
"--",
|
||||
"cmd",
|
||||
])
|
||||
.assert()
|
||||
.code(2)
|
||||
.stderr(predicate::str::contains(
|
||||
"--user current-process cannot be combined with token shaping options",
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn current_user_identity_is_accepted_by_the_installed_cli_parser() {
|
||||
let mut command = cargo_command();
|
||||
command
|
||||
.args([
|
||||
"--user",
|
||||
"current-user",
|
||||
"--same-console",
|
||||
"--new-window",
|
||||
"--",
|
||||
"cmd",
|
||||
])
|
||||
.assert()
|
||||
.code(2)
|
||||
.stderr(predicate::str::contains(
|
||||
"--same-console cannot be combined with --new-window",
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn short_nsudo_style_user_values_are_not_native_cli() {
|
||||
let mut command = cargo_command();
|
||||
command
|
||||
.args(["--user", "p", "--privileges", "enable-all", "--", "cmd"])
|
||||
.assert()
|
||||
.code(2)
|
||||
.stderr(predicate::str::contains("invalid --user value 'p'"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn run_help_mentions_same_console_and_new_window_defaults() {
|
||||
let mut command = cargo_command();
|
||||
command
|
||||
.args(["run", "--help"])
|
||||
.assert()
|
||||
.success()
|
||||
.stdout(predicate::str::contains("--format <FORMAT>"))
|
||||
.stdout(predicate::str::contains("--json"))
|
||||
.stdout(predicate::str::contains("--toon"))
|
||||
.stdout(predicate::str::contains("--same-console"))
|
||||
.stdout(predicate::str::contains("--new-window"))
|
||||
.stdout(predicate::str::contains(
|
||||
"Interactive shells open in a new window by default",
|
||||
));
|
||||
}
|
||||
Reference in New Issue
Block a user