name: Dependency Pinning Scan

on:
  workflow_call:
    inputs:
      threshold:
        description: 'Compliance threshold percentage (0-100)'
        required: false
        type: number
        default: 95
      dependency-types:
        description: 'Comma-separated list of dependency types to check'
        required: false
        type: string
        default: 'github-actions,npm,workflow-npm-commands'
      soft-fail:
        description: 'Whether to continue on compliance violations'
        required: false
        type: boolean
        default: false
      upload-sarif:
        description: 'Whether to upload SARIF results to Security tab'
        required: false
        type: boolean
        default: false
      upload-artifact:
        description: 'Whether to upload results as artifact'
        required: false
        type: boolean
        default: true
    outputs:
      compliance-score:
        description: 'Compliance score percentage'
        value: ${{ jobs.scan.outputs.compliance-score }}
      unpinned-count:
        description: 'Number of unpinned dependencies found'
        value: ${{ jobs.scan.outputs.unpinned-count }}
      is-compliant:
        description: 'Whether repository meets compliance threshold'
        value: ${{ jobs.scan.outputs.is-compliant }}

permissions:
  contents: read

jobs:
  scan:
    name: Validate SHA Pinning Compliance
    runs-on: ubuntu-latest
    permissions:
      contents: read
      security-events: write  # Required for SARIF upload to Security tab
    outputs:
      compliance-score: ${{ steps.pinning.outputs.compliance-score }}
      unpinned-count: ${{ steps.pinning.outputs.unpinned-count }}
      is-compliant: ${{ steps.pinning.outputs.is-compliant }}
    steps:
      - name: Checkout code
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          persist-credentials: false

      - name: Run Dependency Pinning Validation
        id: pinning
        shell: pwsh
        run: |
          Write-Host "Validating dependency SHA pinning compliance..."
          
          # Ensure logs directory exists
          New-Item -ItemType Directory -Force -Path logs | Out-Null
          
          # Build parameter list for JSON output (always generate)
          $params = @{
            Path = '.'
            Format = 'json'
            OutputPath = 'logs/dependency-pinning-results.json'
          }
          
          # Enable failure on threshold violations unless soft-fail is requested
          if ('${{ inputs.soft-fail }}' -ne 'true') {
            $params['FailOnUnpinned'] = $true
          }
          
          # Pass dependency types filter to script
          if ('${{ inputs.dependency-types }}') {
            $params['IncludeTypes'] = '${{ inputs.dependency-types }}'
          }
          
          # Pass compliance threshold to script (script handles enforcement)
          if ('${{ inputs.threshold }}') {
            $params['Threshold'] = [int]'${{ inputs.threshold }}'
          }
          
          # Run validation script (JSON format)
          & scripts/security/Test-DependencyPinning.ps1 @params
          $jsonExitCode = $LASTEXITCODE
          
          # Generate SARIF format if requested
          if ('${{ inputs.upload-sarif }}' -eq 'true') {
            Write-Host "Generating SARIF format for Security tab..."
            $params['Format'] = 'sarif'
            $params['OutputPath'] = 'logs/dependency-pinning-results.sarif'
            
            & scripts/security/Test-DependencyPinning.ps1 @params
          }
          
          # Extract metrics from JSON report
          if (Test-Path logs/dependency-pinning-results.json) {
            $report = Get-Content logs/dependency-pinning-results.json | ConvertFrom-Json
            $complianceScore = $report.ComplianceScore
            $unpinnedCount = $report.UnpinnedDependencies
            
            # Extract threshold from report metadata (script calculated compliance)
            $threshold = $report.Metadata.ComplianceThreshold
            $isCompliant = $complianceScore -ge $threshold
            
            "compliance-score=$complianceScore" >> $env:GITHUB_OUTPUT
            "unpinned-count=$unpinnedCount" >> $env:GITHUB_OUTPUT
            "is-compliant=$($isCompliant.ToString().ToLower())" >> $env:GITHUB_OUTPUT
            
            Write-Host "Compliance Score: $complianceScore%"
            Write-Host "Unpinned Dependencies: $unpinnedCount"
            Write-Host "Is Compliant (>=$threshold%): $isCompliant"
          }
          else {
            Write-Error "Failed to generate dependency pinning report"
            exit 1
          }

      - name: Upload SARIF to Security tab
        if: inputs.upload-sarif && always()
        uses: github/codeql-action/upload-sarif@ce729e4d353d580e6cacd6a8cf2921b72e5e310a # v3.27.0
        with:
          sarif_file: logs/dependency-pinning-results.sarif
          category: dependency-pinning
        continue-on-error: true

      - name: Upload validation report
        if: inputs.upload-artifact && always()
        uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
        with:
          name: dependency-pinning-results
          path: logs/dependency-pinning-results.json
          retention-days: 90

      - name: Add job summary
        if: always()
        shell: pwsh
        run: |
          $complianceScore = '${{ steps.pinning.outputs.compliance-score }}'
          $unpinnedCount = '${{ steps.pinning.outputs.unpinned-count }}'
          $isCompliant = '${{ steps.pinning.outputs.is-compliant }}'
          
          @"
          ## Dependency Pinning Scan Results
          
          | Metric | Value |
          |--------|-------|
          | Compliance Score | $complianceScore% |
          | Unpinned Dependencies | $unpinnedCount |
          | Status | $(if ($isCompliant -eq 'true') { '✅ Compliant' } else { '⚠️ Non-Compliant' }) |
          
          $(if ($unpinnedCount -ne '0') {
            @"
          
          ### ⚠️ Action Required
          
          **$unpinnedCount dependencies are not properly pinned.**
          
          Review the warnings in the workflow log and pin dependencies to specific SHA commits.
          
          "@
          } else {
            @"
          
          ### ✅ All Dependencies Pinned
          
          All dependencies are properly pinned.
          
          "@
          })
          "@ | Out-File -FilePath $env:GITHUB_STEP_SUMMARY -Encoding UTF8
