ci / test (push) Waiting to run
ci / fuzz-smoke (push) Waiting to run
ci / windows-client (push) Waiting to run
ci / package-release (linux-x86_64, ubuntu-latest) (push) Waiting to run
ci / package-release (macos-aarch64, macos-14) (push) Waiting to run
ci / package-release (macos-x86_64, macos-13) (push) Waiting to run
ci / package-release (windows-x86_64, windows-latest) (push) Waiting to run
ci / publish-gitea-release (push) Blocked by required conditions
ci / remote-bench (push) Waiting to run
263 lines
9.8 KiB
Rust
263 lines
9.8 KiB
Rust
#[test]
|
|
fn quiet_update_keeps_prebuilt_enabled_by_default() {
|
|
let install = include_str!("../install.sh");
|
|
assert!(install.contains("use_prebuilt=\"${DOSH_USE_PREBUILT:-1}\""));
|
|
assert!(
|
|
!install.contains("use_prebuilt=0"),
|
|
"quiet updates must not force source builds"
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn release_scripts_skip_stale_artifacts_when_auto_discovering() {
|
|
let upload = include_str!("../scripts/upload-gitea-release.sh");
|
|
assert!(upload.contains("skipping $artifact: version"));
|
|
assert!(upload.contains("expected_version"));
|
|
|
|
let publish = include_str!("../scripts/publish-gitea-release.sh");
|
|
assert!(publish.contains("skipping stale artifact"));
|
|
assert!(publish.contains("actual=\"$(artifact_version \"$artifact\" || true)\""));
|
|
}
|
|
|
|
#[test]
|
|
fn release_upload_refuses_partial_platform_sets_by_default() {
|
|
let upload = include_str!("../scripts/upload-gitea-release.sh");
|
|
assert!(upload.contains("require_complete_release_artifacts \"$@\""));
|
|
assert!(upload.contains("DOSH_RELEASE_ALLOW_PARTIAL=1"));
|
|
assert!(upload.contains("refusing partial release upload"));
|
|
for name in [
|
|
"dosh-linux-x86_64.tar.gz",
|
|
"dosh-macos-aarch64.tar.gz",
|
|
"dosh-macos-x86_64.tar.gz",
|
|
"dosh-windows-x86_64.zip",
|
|
] {
|
|
assert!(
|
|
upload.contains(name),
|
|
"release upload completeness check must require {name}"
|
|
);
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn release_upload_marks_prerelease_tags_as_prereleases() {
|
|
let upload = include_str!("../scripts/upload-gitea-release.sh");
|
|
assert!(upload.contains("release_prerelease=false"));
|
|
assert!(upload.contains("*-*) release_prerelease=true"));
|
|
assert!(upload.contains("\"prerelease\":%s"));
|
|
assert!(upload.contains("metadata_payload="));
|
|
assert!(
|
|
upload.contains("-X PATCH"),
|
|
"existing Gitea releases must be corrected when prerelease metadata changes"
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn installers_skip_stale_latest_release_prebuilts() {
|
|
let install = include_str!("../install.sh");
|
|
assert!(install.contains("latest_release_is_stale"));
|
|
assert!(install.contains("current_source_version"));
|
|
assert!(install.contains("latest release $latest is older than source $current"));
|
|
assert!(install.contains("version_prerelease"));
|
|
assert!(install.contains("prerelease_less_than"));
|
|
assert!(
|
|
install.contains("if latest_release_is_stale; then"),
|
|
"unix installer must skip stale latest before downloading a prebuilt"
|
|
);
|
|
|
|
let ps1 = include_str!("../install.ps1");
|
|
assert!(ps1.contains("Latest-ReleaseIsStale"));
|
|
assert!(ps1.contains("Current-SourceVersion"));
|
|
assert!(ps1.contains("latest release $latestVersion is older than source $current"));
|
|
assert!(ps1.contains("Version-Prerelease"));
|
|
assert!(ps1.contains("Compare-Prerelease"));
|
|
assert!(
|
|
ps1.contains("if (Latest-ReleaseIsStale)"),
|
|
"windows installer must skip stale latest before downloading a prebuilt"
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn installers_refuse_prebuilts_without_checksums() {
|
|
let install = include_str!("../install.sh");
|
|
assert!(install.contains("verify_archive_checksum"));
|
|
assert!(install.contains("refusing unverified binary for $url"));
|
|
assert!(
|
|
!install.contains("continuing without sidecar verification"),
|
|
"unix installer must not silently install an unverifiable prebuilt"
|
|
);
|
|
|
|
let ps1 = include_str!("../install.ps1");
|
|
assert!(ps1.contains("Verify-ArchiveChecksum"));
|
|
assert!(ps1.contains("refusing unverified binary for $Url"));
|
|
assert!(
|
|
!ps1.contains("continuing without sidecar verification"),
|
|
"windows installer must not silently install an unverifiable prebuilt"
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn windows_installer_reuses_persistent_source_update_cache() {
|
|
let ps1 = include_str!("../install.ps1");
|
|
assert!(ps1.contains("DOSH_UPDATE_CACHE"));
|
|
assert!(ps1.contains("Assert-NoRelativePathSegments($Path)"));
|
|
assert!(ps1.contains("Assert-NoRelativePathSegments $Path"));
|
|
assert!(ps1.contains("$segment -eq \".\" -or $segment -eq \"..\""));
|
|
assert!(ps1.contains("$sourceCache = Assert-SafeUpdateCache $UpdateCache"));
|
|
assert!(ps1.contains("git -C $sourceCache fetch --depth 1 origin main"));
|
|
assert!(ps1.contains("git -C $sourceCache checkout -q -B main FETCH_HEAD"));
|
|
assert!(ps1.contains("git clone --depth 1 --branch main $Repo $sourceCache"));
|
|
assert!(
|
|
!ps1.contains("git clone --depth 1 $Repo $tmp"),
|
|
"Windows source updates should reuse a persistent cache instead of recloning into temp"
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn unix_installer_rejects_unsafe_source_update_cache_paths() {
|
|
let install = include_str!("../install.sh");
|
|
assert!(install.contains("normalize_update_cache_path()"));
|
|
assert!(install.contains("safe_update_cache_path()"));
|
|
assert!(install.contains("update_cache=\"$(safe_update_cache_path \"$update_cache\")\""));
|
|
for pattern in [
|
|
"\"\"|\"/\"|\"$home_norm\"|\"$home_cache_norm\"",
|
|
"\".\"|\"..\"|./*|../*|*/.|*/..|*/./*|*/../*",
|
|
] {
|
|
assert!(
|
|
install.contains(pattern),
|
|
"Unix installer must reject unsafe update cache pattern {pattern}"
|
|
);
|
|
}
|
|
assert!(
|
|
install.contains("rm -rf \"$update_cache\""),
|
|
"source cache replacement remains the destructive operation guarded by safe_update_cache_path"
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn installers_generate_same_native_auth_client_defaults() {
|
|
let install = include_str!("../install.sh");
|
|
let ps1 = include_str!("../install.ps1");
|
|
for setting in [
|
|
"auth_preference = \"native,ssh\"",
|
|
"trust_on_first_use = false",
|
|
"native_auth_timeout_ms = 700",
|
|
"known_hosts = \"~/.config/dosh/known_hosts\"",
|
|
"identity_files = [\"~/.ssh/id_ed25519\"]",
|
|
"use_ssh_agent = true",
|
|
"forward_agent = false",
|
|
] {
|
|
assert!(
|
|
install.contains(setting),
|
|
"Unix installer missing client default {setting}"
|
|
);
|
|
assert!(
|
|
ps1.contains(setting),
|
|
"Windows installer missing client default {setting}"
|
|
);
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn windows_installer_generates_hosts_config_like_unix() {
|
|
let install = include_str!("../install.sh");
|
|
let ps1 = include_str!("../install.ps1");
|
|
for setting in [
|
|
"hosts.toml",
|
|
"# default_command = \"tm\"",
|
|
"[default]",
|
|
"predict = true",
|
|
] {
|
|
assert!(
|
|
install.contains(setting),
|
|
"Unix installer missing host config setting {setting}"
|
|
);
|
|
assert!(
|
|
ps1.contains(setting),
|
|
"Windows installer missing host config setting {setting}"
|
|
);
|
|
}
|
|
assert!(ps1.contains("$hostUdp = if ($DoshHost) { $DoshHost } else { $defaultServer }"));
|
|
assert!(ps1.contains("Set-Content -NoNewline -Encoding utf8 $hostsConfig"));
|
|
}
|
|
|
|
#[test]
|
|
fn package_check_verifies_only_artifacts_it_builds() {
|
|
let makefile = include_str!("../Makefile");
|
|
let verify = include_str!("../scripts/verify-release-artifacts.sh");
|
|
assert!(
|
|
verify.contains("if [ \"$#\" -gt 0 ]; then"),
|
|
"release verifier must accept an explicit artifact list"
|
|
);
|
|
let package_check = makefile
|
|
.split("package-check:")
|
|
.nth(1)
|
|
.and_then(|tail| tail.split("\ninstall:").next())
|
|
.expect("package-check target");
|
|
assert!(package_check.contains("package-release-linux"));
|
|
assert!(package_check.contains("package-release-windows"));
|
|
assert!(package_check.contains("dosh-linux-x86_64.tar.gz"));
|
|
assert!(package_check.contains("dosh-windows-x86_64.zip"));
|
|
assert!(
|
|
!package_check.contains("dosh-macos-aarch64.tar.gz"),
|
|
"Linux package-check does not build macOS artifacts, so it must not depend on one"
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn complete_release_verifier_requires_both_macos_architectures() {
|
|
let verify = include_str!("../scripts/verify-release-artifacts.sh");
|
|
assert!(verify.contains("dosh-linux-x86_64.tar.gz"));
|
|
assert!(verify.contains("dosh-macos-aarch64.tar.gz"));
|
|
assert!(verify.contains("dosh-macos-x86_64.tar.gz"));
|
|
assert!(verify.contains("dosh-windows-x86_64.zip"));
|
|
}
|
|
|
|
#[test]
|
|
fn package_release_stamps_git_build_info() {
|
|
let package = include_str!("../scripts/package-release.sh");
|
|
let build = include_str!("../build.rs");
|
|
for name in [
|
|
"DOSH_BUILD_GIT_HASH",
|
|
"DOSH_BUILD_COMMIT_DATE",
|
|
"DOSH_BUILD_GIT_DIRTY",
|
|
] {
|
|
assert!(package.contains(name), "package script must export {name}");
|
|
assert!(build.contains(name), "build.rs must consume {name}");
|
|
}
|
|
assert!(package.contains("git rev-parse --short=12 HEAD"));
|
|
assert!(package.contains("git show -s --format=%cs HEAD"));
|
|
assert!(build.contains("cargo:rerun-if-env-changed=DOSH_BUILD_GIT_HASH"));
|
|
}
|
|
|
|
#[test]
|
|
fn systemd_service_does_not_sandbox_remote_shells() {
|
|
let service = include_str!("../packaging/systemd/dosh-server.service");
|
|
let install = include_str!("../install.sh");
|
|
for raw in [service, install] {
|
|
assert!(raw.contains("KillMode=process"));
|
|
assert!(
|
|
raw.contains("Restart=always"),
|
|
"dosh-server should come back after accidental SIGTERM while preserving child shells"
|
|
);
|
|
for directive in [
|
|
"NoNewPrivileges=",
|
|
"PrivateTmp=",
|
|
"ProtectSystem=",
|
|
"ProtectHome=",
|
|
"RestrictAddressFamilies=",
|
|
"RestrictRealtime=",
|
|
"LockPersonality=",
|
|
"MemoryDenyWriteExecute=",
|
|
] {
|
|
assert!(
|
|
!raw.contains(directive),
|
|
"dosh sessions are user shells; systemd sandbox directive {directive} changes terminal/app behavior"
|
|
);
|
|
}
|
|
assert!(
|
|
!raw.contains("ReadWritePaths="),
|
|
"remote shells must not be restricted to dosh config/data paths"
|
|
);
|
|
}
|
|
}
|