name: PR-tests

on:
  pull_request:
    branches:
      - master
      - main
    paths-ignore:
      - '.github/**'

  workflow_dispatch:

jobs:
  Build_and_test_winpeas_pr:
    runs-on: windows-latest
    
    # environment variables
    env:
      Solution_Path: 'winPEAS\winPEASexe\winPEAS.sln'
      Configuration: 'Release'

    steps:
      # checkout
      - name: Checkout
        uses: actions/checkout@v5
        with:
          ref: ${{ github.head_ref || github.ref_name }}
      
      - name: Download regexes
        run: |
          powershell.exe -ExecutionPolicy Bypass -File build_lists/download_regexes.ps1
            
      # Add MSBuild to the PATH
      - name: Setup MSBuild.exe
        uses: microsoft/setup-msbuild@v2
       
      # Setup NuGet
      - name: Setup NuGet.exe
        uses: nuget/setup-nuget@v2
        
      # Restore the packages for testing
      - name: Restore the application       
        run: nuget restore $env:Solution_Path
        
      # build
      - name: run MSBuild
        run: msbuild $env:Solution_Path /p:Configuration=$env:Configuration /p:UseSharedCompilation=false

      # Execute unit tests in the solution
      - name: Execute unit tests
        run: dotnet test $env:Solution_Path --configuration $env:Configuration
        
      # Build all versions
      - name: Build all versions
        run: |
            echo "build x64"
            msbuild -m $env:Solution_Path /t:Rebuild /p:Configuration=$env:Configuration /p:Platform="x64" /p:UseSharedCompilation=false
            
            echo "build x86"
            msbuild -m $env:Solution_Path /t:Rebuild /p:Configuration=$env:Configuration /p:Platform="x86" /p:UseSharedCompilation=false
            
            echo "build Any CPU"
            msbuild -m $env:Solution_Path /t:Rebuild /p:Configuration=$env:Configuration /p:Platform="Any CPU" /p:UseSharedCompilation=false
      
      - name: Execute winPEAS -h
        shell: pwsh
        run: |
          $Configuration = "Release"
          $exePath = "winPEAS/winPEASexe/winPEAS/bin/$Configuration/winPEAS.exe"
          if (Test-Path $exePath) {
            & $exePath -h
          } else {
            Write-Error "winPEAS.exe not found at $exePath"
          }

      - name: Execute winPEAS cloudinfo
        shell: pwsh
        run: |
          $Configuration = "Release"
          $exePath = "winPEAS/winPEASexe/winPEAS/bin/$Configuration/winPEAS.exe"
          if (Test-Path $exePath) {
            & $exePath cloudinfo
          } else {
            Write-Error "winPEAS.exe not found at $exePath"
          }

      - name: Execute winPEAS systeminfo
        shell: pwsh
        run: |
          $Configuration = "Release"
          $exePath = "winPEAS/winPEASexe/winPEAS/bin/$Configuration/winPEAS.exe"
          if (Test-Path $exePath) {
            & $exePath systeminfo
          } else {
            Write-Error "winPEAS.exe not found at $exePath"
          }

      - name: Execute winPEAS online package vulnerability lookup with mock
        shell: pwsh
        run: |
          $Configuration = "Release"
          $exePath = "winPEAS/winPEASexe/winPEAS/bin/$Configuration/winPEAS.exe"
          if (!(Test-Path $exePath)) {
            Write-Error "winPEAS.exe not found at $exePath"
          }

          $serverPath = Join-Path $env:RUNNER_TEMP "mock_host_checker.py"
          $bodyPath = Join-Path $env:RUNNER_TEMP "host_checker_body.json"
          $countPath = Join-Path $env:RUNNER_TEMP "host_checker_count.txt"
          @"
          from http.server import BaseHTTPRequestHandler, HTTPServer
          import json
          import sys

          body_path = sys.argv[1]
          count_path = sys.argv[2]

          class Handler(BaseHTTPRequestHandler):
              def do_POST(self):
                  length = int(self.headers.get("content-length", "0"))
                  body = self.rfile.read(length).decode("utf-8", "replace")
                  with open(body_path, "w", encoding="utf-8") as f:
                      f.write(body)
                  with open(count_path, "w", encoding="utf-8") as f:
                      f.write("1")
                  vulns = []
                  for i in range(1, 56):
                      vulns.append({
                          "name": f"pkg{i}",
                          "version": f"1.{i}.0",
                          "manager": "windows-registry",
                          "vulns": [f"CVE-2026-{10000 + i}"],
                      })
                  response = {
                      "malicious": False,
                      "results": [],
                      "package_vulnerabilities": {
                          "checked": 300,
                          "affected": 55,
                          "vulnerable_packages": vulns,
                      },
                  }
                  data = json.dumps(response).encode("utf-8")
                  self.send_response(200)
                  self.send_header("Content-Type", "application/json")
                  self.send_header("Content-Length", str(len(data)))
                  self.end_headers()
                  self.wfile.write(data)

              def log_message(self, fmt, *args):
                  pass

          HTTPServer(("127.0.0.1", 18768), Handler).handle_request()
          "@ | Set-Content -Path $serverPath -Encoding utf8

          $server = Start-Process python -ArgumentList "`"$serverPath`" `"$bodyPath`" `"$countPath`"" -PassThru -NoNewWindow
          try {
            Start-Sleep -Seconds 2
            $env:HACKTRICKS_HOST_CHECKER_URL = "http://127.0.0.1:18768/api/host-checker"
            $output = & $exePath applicationsinfo -vulnpackages notcolor 2>&1 | Out-String

            if ($output -notmatch "Online package vulnerabilities found: 55 vulnerable package\(s\), checked 300\.") {
              Write-Error "The package vulnerability summary was not printed as expected.`n$output"
            }
            $vulnLines = ([regex]::Matches($output, "(?m)^\s+- pkg\d+ ")).Count
            if ($vulnLines -ne 50) {
              Write-Error "Expected 50 vulnerable package lines, got $vulnLines.`n$output"
            }
            if ($output -notmatch "\.\.\. 5 more vulnerable package\(s\) not shown\.") {
              Write-Error "The hidden vulnerable package count was not printed.`n$output"
            }
            if ($output -match "package_vulnerabilities") {
              Write-Error "Raw package_vulnerabilities JSON leaked into the rendered output.`n$output"
            }

            $requestCount = Get-Content $countPath -Raw
            if ([int]$requestCount.Trim() -ne 1) {
              Write-Error "Expected exactly one host-checker request, got $requestCount"
            }
            $request = Get-Content $bodyPath -Raw | ConvertFrom-Json
            if (!$request.hostname) {
              Write-Error "The host-checker payload did not include hostname."
            }
            if (!$request.packages -or $request.packages.Count -lt 1) {
              Write-Error "The host-checker payload did not include installed packages."
            }
          } finally {
            if (!$server.HasExited) {
              Stop-Process -Id $server.Id -Force
            }
          }
      
      - name: Execute winPEAS networkinfo
        shell: pwsh
        run: |
          $Configuration = "Release"
          $exePath = "winPEAS/winPEASexe/winPEAS/bin/$Configuration/winPEAS.exe"
          if (Test-Path $exePath) {
            & $exePath networkinfo
          } else {
            Write-Error "winPEAS.exe not found at $exePath"
          }

  Build_and_test_linpeas_pr:
    runs-on: ubuntu-latest

    steps:
      # Download repo
      - uses: actions/checkout@v5
        with:
          ref: ${{ github.head_ref || github.ref_name }}
      
      # Setup go
      - uses: actions/setup-go@v6
        with:
          go-version: '1.23'
          cache: false
      - run: go version
      
      # Build linpeas
      - name: Build linpeas
        run: |
          python3 -m pip install PyYAML
          cd linPEAS
          python3 -m builder.linpeas_builder --all --output linpeas_fat.sh
          python3 -m builder.linpeas_builder --all-no-fat --output linpeas.sh
          python3 -m builder.linpeas_builder --small --output linpeas_small.sh

      - name: Run linPEAS module metadata tests
        run: python3 -m unittest linPEAS.tests.test_modules_metadata

      - name: Run linPEAS builder tests
        run: python3 -m unittest discover -s linPEAS/tests -p "test_*.py"
      
      # Run linpeas help as quick test
      - name: Run linpeas help
        run: linPEAS/linpeas_fat.sh -h && linPEAS/linpeas.sh -h && linPEAS/linpeas_small.sh -h
      
      # Run linpeas as a test
      - name: Run linpeas system_information
        run: linPEAS/linpeas_fat.sh -o system_information -a
      
      - name: Run linpeas container
        run: linPEAS/linpeas_fat.sh -o container -a
      
      - name: Run linpeas cloud
        run: linPEAS/linpeas_fat.sh -o cloud -a
      
      - name: Run linpeas procs_crons_timers_srvcs_sockets
        run: linPEAS/linpeas_fat.sh -o procs_crons_timers_srvcs_sockets -a
      
      - name: Run linpeas network_information
        run: linPEAS/linpeas_fat.sh -o network_information -t -a
      
      - name: Run linpeas users_information
        run: linPEAS/linpeas_fat.sh -o users_information -a
      
      - name: Run linpeas software_information
        run: linPEAS/linpeas_fat.sh -o software_information -a
      
      - name: Run linpeas interesting_perms_files
        run: linPEAS/linpeas_fat.sh -o interesting_perms_files -a
      
      - name: Run linpeas interesting_files
        run: linPEAS/linpeas_fat.sh -o interesting_files -a

  Build_and_test_macpeas_pr:
    runs-on: macos-latest

    steps:
      # Download repo
      - uses: actions/checkout@v5
        with:
          ref: ${{ github.head_ref || github.ref_name }}
      
      # Build linpeas (macpeas)
      - name: Build macpeas
        run: |
          python3 -m pip install PyYAML --break-system-packages
          python3 -m pip install requests --break-system-packages
          cd linPEAS
          python3 -m builder.linpeas_builder --all --output linpeas_fat.sh
      
      # Run linpeas help as quick test
      - name: Run macpeas help
        run: linPEAS/linpeas_fat.sh -h
      
      # Run macpeas parts to test it
      - name: Run macpeas system_information
        run: linPEAS/linpeas_fat.sh -o system_information -a
      
      # - name: Run macpeas container
      #   run: linPEAS/linpeas_fat.sh -o container -a
      
      # - name: Run macpeas cloud
      #   run: linPEAS/linpeas_fat.sh -o cloud -a
      
      # - name: Run macpeas procs_crons_timers_srvcs_sockets
      #   run: linPEAS/linpeas_fat.sh -o procs_crons_timers_srvcs_sockets -a
      
      # - name: Run macpeas network_information
      #   run: linPEAS/linpeas_fat.sh -o network_information -t -a
      
      # - name: Run macpeas users_information
      #   run: linPEAS/linpeas_fat.sh -o users_information -a
      
      # - name: Run macpeas software_information
      #   run: linPEAS/linpeas_fat.sh -o software_information -a
