nip/tests/test_namespace.nim

71 lines
2.5 KiB
Nim

import std/[unittest, os, posix, strutils]
import nip/namespace
import nip/manifest_parser
# Import unshare for testing availability
proc unshare(flags: cint): cint {.importc: "unshare", header: "<sched.h>".}
const CLONE_NEWUSER = 0x10000000
# Note: Testing namespaces usually requires root or unprivileged user namespace support enabled.
# Most CI/Docker environments might block this.
# We will check if we can unshare first.
proc canUnshare(): bool =
# Try to unshare user namespace
if unshare(CLONE_NEWUSER) == 0:
return true
return false
suite "NIP Namespace Isolation Tests":
test "Initialize Launcher":
let manifest = PackageManifest(name: "test-app", version: parseSemanticVersion("1.0.0"), license: "MIT")
let launcher = newLauncher(manifest, "/tmp/install", "/tmp/cas")
check launcher != nil
check launcher.manifest.name == "test-app"
test "Sandbox Execution (Mock/Check)":
# This test is tricky without actually running it.
# We verify the logic compiles and basic object creation works.
# Actual execution requires a binary to run.
if not canUnshare():
echo "User namespaces not supported in this environment - SKIPPING"
else:
# If we can unshare, we can try a minimal test
# But 'run' does execv which replaces the process.
# We need to fork first in the test.
let pid = fork()
if pid == 0:
# Child
try:
let manifest = PackageManifest(name: "true", version: parseSemanticVersion("1.0.0"), license: "MIT")
# We point installDir to /bin so it finds 'true' (assuming logic looks in bin/)
# Wait, the logic looks in installDir/bin/<name>
# So we need to fake that.
createDir("/tmp/nip_test_ns/bin")
copyFile("/bin/true", "/tmp/nip_test_ns/bin/true")
let launcher = newLauncher(manifest, "/tmp/nip_test_ns", "/tmp")
# This will replace the process
launcher.run(@[])
# Should not reach here
quit(1)
except Exception as e:
if "Operation not permitted" in e.msg:
echo "SKIPPING: Unshare not permitted in child (likely CI restriction)"
quit(0)
else:
echo "Child exception: ", e.msg
quit(1)
else:
# Parent
var status: cint
discard waitpid(pid, status, 0)
check WIFEXITED(status)
check WEXITSTATUS(status) == 0