#[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("$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 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" ); } }