## NIP Launcher Tests ## ## Tests for the NIP launcher that runs applications in isolated namespaces. ## This verifies that applications can be launched with proper sandbox restrictions. import std/[unittest, os, tempfiles, options, strutils, posix] import nip/namespace import nip/manifest_parser import nip/nip_installer import nip/cas suite "NIP Launcher Tests": setup: let tempDir = createTempDir("nip_test_launcher_", "") let casRoot = tempDir / "cas" let installRoot = tempDir / "nips" createDir(casRoot) createDir(installRoot) discard initCasManager(casRoot, casRoot) teardown: removeDir(tempDir) test "Create Launcher from Manifest": ## Verify launcher can be created from a manifest let manifest = PackageManifest( name: "test-app", version: parseSemanticVersion("1.0.0"), license: "MIT", artifactHash: "hash123" ) let launcher = newLauncher(manifest, installRoot, casRoot) check launcher != nil check launcher.manifest.name == "test-app" check launcher.installDir == installRoot check launcher.casRoot == casRoot test "Launcher with Sandbox Configuration": ## Verify launcher respects sandbox configuration var manifest = PackageManifest( name: "sandboxed-app", version: parseSemanticVersion("1.0.0"), license: "MIT", artifactHash: "hash123" ) manifest.sandbox = some(SandboxConfig( level: SandboxStrict, namespaces: @["user", "mount", "pid", "ipc"] )) let launcher = newLauncher(manifest, installRoot, casRoot) check launcher.manifest.sandbox.isSome let sb = launcher.manifest.sandbox.get() check sb.level == SandboxStrict check "user" in sb.namespaces check "mount" in sb.namespaces test "Launcher with Desktop Integration": ## Verify launcher works with desktop-integrated applications var manifest = PackageManifest( name: "desktop-app", version: parseSemanticVersion("1.0.0"), license: "MIT", artifactHash: "hash123" ) manifest.desktop = some(DesktopIntegration( displayName: "Desktop Application", categories: @["Utility", "Development"], icon: some("app-icon"), terminal: false )) let launcher = newLauncher(manifest, installRoot, casRoot) check launcher.manifest.desktop.isSome let dt = launcher.manifest.desktop.get() check dt.displayName == "Desktop Application" check dt.icon.isSome check dt.icon.get() == "app-icon" test "Launcher with Seccomp Profile": ## Verify launcher respects seccomp configuration var manifest = PackageManifest( name: "seccomp-app", version: parseSemanticVersion("1.0.0"), license: "MIT", artifactHash: "hash123" ) manifest.sandbox = some(SandboxConfig( level: SandboxStandard, namespaces: @["user", "mount"], seccompProfile: some("strict") )) let launcher = newLauncher(manifest, installRoot, casRoot) check launcher.manifest.sandbox.isSome let sb = launcher.manifest.sandbox.get() check sb.seccompProfile.isSome check sb.seccompProfile.get() == "strict" test "Launcher with Capabilities": ## Verify launcher respects capability restrictions var manifest = PackageManifest( name: "cap-app", version: parseSemanticVersion("1.0.0"), license: "MIT", artifactHash: "hash123" ) manifest.sandbox = some(SandboxConfig( level: SandboxStandard, namespaces: @["user", "mount"], capabilities: @["CAP_NET_ADMIN", "CAP_SYS_ADMIN"] )) let launcher = newLauncher(manifest, installRoot, casRoot) check launcher.manifest.sandbox.isSome let sb = launcher.manifest.sandbox.get() check sb.capabilities.len == 2 check "CAP_NET_ADMIN" in sb.capabilities check "CAP_SYS_ADMIN" in sb.capabilities test "Launcher with Pledge (BSD)": ## Verify launcher respects pledge configuration (OpenBSD) var manifest = PackageManifest( name: "pledge-app", version: parseSemanticVersion("1.0.0"), license: "MIT", artifactHash: "hash123" ) manifest.sandbox = some(SandboxConfig( level: SandboxStandard, namespaces: @["user"], pledge: some("stdio rpath wpath inet") )) let launcher = newLauncher(manifest, installRoot, casRoot) check launcher.manifest.sandbox.isSome let sb = launcher.manifest.sandbox.get() check sb.pledge.isSome check sb.pledge.get() == "stdio rpath wpath inet" test "Launcher Isolation Levels": ## Verify launcher supports different isolation levels for level in [SandboxStrict, SandboxStandard]: var manifest = PackageManifest( name: "isolation-app", version: parseSemanticVersion("1.0.0"), license: "MIT", artifactHash: "hash123" ) manifest.sandbox = some(SandboxConfig( level: level, namespaces: @["user", "mount"] )) let launcher = newLauncher(manifest, installRoot, casRoot) check launcher.manifest.sandbox.isSome check launcher.manifest.sandbox.get().level == level test "Launcher with CAS Root": ## Verify launcher correctly references CAS root for read-only mounts let manifest = PackageManifest( name: "cas-app", version: parseSemanticVersion("1.0.0"), license: "MIT", artifactHash: "hash123" ) let launcher = newLauncher(manifest, installRoot, casRoot) check launcher.casRoot == casRoot # The launcher should mount casRoot as read-only in the namespace # This is verified by the namespace setup code test "Launcher with Multiple Namespaces": ## Verify launcher can create multiple namespace types var manifest = PackageManifest( name: "multi-ns-app", version: parseSemanticVersion("1.0.0"), license: "MIT", artifactHash: "hash123" ) manifest.sandbox = some(SandboxConfig( level: SandboxStrict, namespaces: @["user", "mount", "pid", "net", "ipc"] )) let launcher = newLauncher(manifest, installRoot, casRoot) check launcher.manifest.sandbox.isSome let sb = launcher.manifest.sandbox.get() check sb.namespaces.len == 5 check "user" in sb.namespaces check "mount" in sb.namespaces check "pid" in sb.namespaces check "net" in sb.namespaces check "ipc" in sb.namespaces test "Launcher Manifest Validation": ## Verify launcher validates manifest before launch let manifest = PackageManifest( name: "valid-app", version: parseSemanticVersion("1.0.0"), license: "MIT", artifactHash: "hash123" ) let launcher = newLauncher(manifest, installRoot, casRoot) # Launcher should have valid manifest check launcher.manifest.name.len > 0 check launcher.manifest.version.major >= 0 check launcher.manifest.license.len > 0 test "Launcher with No Sandbox (Unrestricted)": ## Verify launcher can run without sandbox for trusted applications let manifest = PackageManifest( name: "unrestricted-app", version: parseSemanticVersion("1.0.0"), license: "MIT", artifactHash: "hash123" ) # No sandbox configuration = unrestricted let launcher = newLauncher(manifest, installRoot, casRoot) check launcher.manifest.sandbox.isNone # Launcher should still work, just without isolation test "Launcher with Minimal Sandbox": ## Verify launcher works with minimal sandbox configuration var manifest = PackageManifest( name: "minimal-app", version: parseSemanticVersion("1.0.0"), license: "MIT", artifactHash: "hash123" ) manifest.sandbox = some(SandboxConfig( level: SandboxStandard, namespaces: @[] )) let launcher = newLauncher(manifest, installRoot, casRoot) check launcher.manifest.sandbox.isSome let sb = launcher.manifest.sandbox.get() check sb.level == SandboxStandard check sb.namespaces.len == 0 ## Property-Based Tests suite "NIP Launcher Property Tests": test "Property: Launcher preserves manifest integrity": ## Verify launcher doesn't modify manifest during creation let manifest = PackageManifest( name: "prop-app", version: parseSemanticVersion("1.0.0"), license: "MIT", artifactHash: "hash123" ) let originalName = manifest.name let originalVersion = manifest.version let originalLicense = manifest.license let launcher = newLauncher(manifest, "/tmp/install", "/tmp/cas") check launcher.manifest.name == originalName check launcher.manifest.version == originalVersion check launcher.manifest.license == originalLicense test "Property: Launcher paths are correctly set": ## Verify launcher stores paths correctly let manifest = PackageManifest( name: "path-app", version: parseSemanticVersion("1.0.0"), license: "MIT", artifactHash: "hash123" ) let installDir = "/custom/install" let casRoot = "/custom/cas" let launcher = newLauncher(manifest, installDir, casRoot) check launcher.installDir == installDir check launcher.casRoot == casRoot test "Property: Launcher supports all namespace combinations": ## Verify launcher can handle all namespace combinations var manifest = PackageManifest( name: "ns-app", version: parseSemanticVersion("1.0.0"), license: "MIT", artifactHash: "hash123" ) # Test various namespace combinations let namespaceCombos = @[ @["user"], @["user", "mount"], @["user", "mount", "pid"], @["user", "mount", "pid", "net"], @["user", "mount", "pid", "net", "ipc"] ] for namespaces in namespaceCombos: manifest.sandbox = some(SandboxConfig( level: SandboxStandard, namespaces: namespaces )) let launcher = newLauncher(manifest, "/tmp/install", "/tmp/cas") check launcher.manifest.sandbox.isSome let sb = launcher.manifest.sandbox.get() check sb.namespaces == namespaces