fix(ci): resolve YAML indentation error in CLI integration test #5
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| --- | |
| name: Security | |
| on: | |
| push: | |
| branches: [main, develop] | |
| pull_request: | |
| branches: [main, develop] | |
| schedule: | |
| # Run weekly security scans on Sundays at 2 AM UTC | |
| - cron: '0 2 * * 0' | |
| workflow_dispatch: | |
| inputs: | |
| full_scan: | |
| description: 'Run full security scan (all scanners)' | |
| required: false | |
| default: false | |
| type: boolean | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: ${{ github.event_name != 'schedule' }} | |
| permissions: | |
| contents: read | |
| security-events: write | |
| actions: read | |
| env: | |
| FORCE_COLOR: "1" | |
| jobs: | |
| # ==== SECRETS DETECTION ==== | |
| secrets-scan: | |
| name: Secrets Detection | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Run Gitleaks | |
| uses: gitleaks/gitleaks-action@v2 | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Upload Gitleaks results | |
| if: always() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: gitleaks-report-${{ github.sha }} | |
| path: results.sarif | |
| retention-days: 30 | |
| # ==== DEPENDENCY SCANNING ==== | |
| dependency-scan: | |
| name: Dependency Security | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 15 | |
| strategy: | |
| matrix: | |
| scan-type: [python, infrastructure] | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Setup environment (Python dependencies) | |
| if: matrix.scan-type == 'python' | |
| uses: astral-sh/setup-uv@v6 | |
| with: | |
| enable-cache: true | |
| cache-dependency-glob: "uv.lock" | |
| - name: Setup Python (Python dependencies) | |
| if: matrix.scan-type == 'python' | |
| run: uv python install | |
| - name: Generate dependency files (Python) | |
| if: matrix.scan-type == 'python' | |
| run: | | |
| uv export --format requirements-txt --output-file requirements.txt | |
| uv export --format requirements-txt --only-dev --output-file requirements-dev.txt | |
| - name: Run Trivy scanner | |
| uses: aquasecurity/trivy-action@master | |
| with: | |
| scan-type: 'fs' | |
| scan-ref: ${{ matrix.scan-type == 'python' && '.' || 'terraform/' }} | |
| format: 'sarif' | |
| output: 'trivy-${{ matrix.scan-type }}-results.sarif' | |
| scanners: ${{ matrix.scan-type == 'python' && 'vuln' || 'vuln,config' }} | |
| severity: 'CRITICAL,HIGH,MEDIUM' | |
| - name: Ensure Trivy SARIF file exists | |
| run: | | |
| sarif_file="trivy-${{ matrix.scan-type }}-results.sarif" | |
| if [[ ! -f "$sarif_file" ]]; then | |
| echo "Trivy did not generate SARIF file, creating minimal SARIF structure" | |
| cat > "$sarif_file" << 'EOF' | |
| { | |
| "$schema": "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json", | |
| "version": "2.1.0", | |
| "runs": [ | |
| { | |
| "tool": { | |
| "driver": { | |
| "name": "trivy", | |
| "informationUri": "https://github.com/aquasecurity/trivy", | |
| "version": "latest" | |
| } | |
| }, | |
| "results": [] | |
| } | |
| ] | |
| } | |
| EOF | |
| fi | |
| - name: Upload Trivy results | |
| uses: github/codeql-action/upload-sarif@v3 | |
| if: always() | |
| with: | |
| sarif_file: 'trivy-${{ matrix.scan-type }}-results.sarif' | |
| category: 'trivy-${{ matrix.scan-type }}' | |
| - name: Run Safety check (Python only) | |
| if: matrix.scan-type == 'python' | |
| run: | | |
| uv sync --frozen | |
| uv run pip install safety | |
| uv run safety check --json --output safety-report.json || true | |
| - name: Upload Safety results | |
| if: matrix.scan-type == 'python' | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: safety-report-${{ github.sha }} | |
| path: safety-report.json | |
| retention-days: 30 | |
| # ==== INFRASTRUCTURE SECURITY ==== | |
| infrastructure-scan: | |
| name: Infrastructure Security | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 20 | |
| strategy: | |
| matrix: | |
| tool: [tfsec, ansible-config] | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Run TFSec (Terraform) | |
| if: matrix.tool == 'tfsec' | |
| uses: aquasecurity/[email protected] | |
| with: | |
| working_directory: terraform/ | |
| format: sarif | |
| soft_fail: true | |
| - name: Ensure TFSec SARIF file exists | |
| if: matrix.tool == 'tfsec' | |
| run: | | |
| if [[ ! -f "results.sarif" ]]; then | |
| echo "TFSec did not generate SARIF file, creating minimal SARIF structure" | |
| cat > results.sarif << 'EOF' | |
| { | |
| "$schema": "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json", | |
| "version": "2.1.0", | |
| "runs": [ | |
| { | |
| "tool": { | |
| "driver": { | |
| "name": "tfsec", | |
| "informationUri": "https://github.com/aquasecurity/tfsec", | |
| "version": "1.0.3" | |
| } | |
| }, | |
| "results": [] | |
| } | |
| ] | |
| } | |
| EOF | |
| fi | |
| - name: Upload TFSec results | |
| if: matrix.tool == 'tfsec' && always() | |
| uses: github/codeql-action/upload-sarif@v3 | |
| with: | |
| sarif_file: results.sarif | |
| category: 'tfsec' | |
| - name: Scan Ansible configurations | |
| if: matrix.tool == 'ansible-config' | |
| uses: aquasecurity/trivy-action@master | |
| with: | |
| scan-type: 'config' | |
| scan-ref: 'ansible/' | |
| format: 'sarif' | |
| output: 'trivy-ansible-config.sarif' | |
| scanners: 'config' | |
| - name: Ensure Ansible config SARIF file exists | |
| if: matrix.tool == 'ansible-config' | |
| run: | | |
| if [[ ! -f "trivy-ansible-config.sarif" ]]; then | |
| echo "Trivy did not generate SARIF file for Ansible configs, creating minimal SARIF structure" | |
| cat > trivy-ansible-config.sarif << 'EOF' | |
| { | |
| "$schema": "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json", | |
| "version": "2.1.0", | |
| "runs": [ | |
| { | |
| "tool": { | |
| "driver": { | |
| "name": "trivy", | |
| "informationUri": "https://github.com/aquasecurity/trivy", | |
| "version": "latest" | |
| } | |
| }, | |
| "results": [] | |
| } | |
| ] | |
| } | |
| EOF | |
| fi | |
| - name: Upload Ansible config results | |
| if: matrix.tool == 'ansible-config' && always() | |
| uses: github/codeql-action/upload-sarif@v3 | |
| with: | |
| sarif_file: 'trivy-ansible-config.sarif' | |
| category: 'ansible-config' | |
| # ==== STATIC ANALYSIS ==== | |
| sast-scan: | |
| name: Static Analysis | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 20 | |
| if: github.event_name != 'schedule' || inputs.full_scan | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Initialize CodeQL | |
| uses: github/codeql-action/init@v3 | |
| with: | |
| languages: python | |
| queries: security-extended | |
| - name: Setup uv | |
| uses: astral-sh/setup-uv@v6 | |
| with: | |
| enable-cache: true | |
| cache-dependency-glob: "uv.lock" | |
| - name: Setup Python and install dependencies | |
| run: | | |
| uv python install | |
| uv sync --frozen | |
| - name: Perform CodeQL Analysis | |
| uses: github/codeql-action/analyze@v3 | |
| with: | |
| category: "codeql-python" | |
| - name: Run Bandit (Python Security) | |
| run: | | |
| uv run pip install bandit[toml] | |
| uv run bandit -r scripts/ -f sarif -o bandit-results.sarif || true | |
| - name: Ensure Bandit SARIF file exists | |
| run: | | |
| if [[ ! -f "bandit-results.sarif" ]]; then | |
| echo "Bandit did not generate SARIF file, creating minimal SARIF structure" | |
| cat > bandit-results.sarif << 'EOF' | |
| { | |
| "$schema": "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json", | |
| "version": "2.1.0", | |
| "runs": [ | |
| { | |
| "tool": { | |
| "driver": { | |
| "name": "bandit", | |
| "informationUri": "https://github.com/PyCQA/bandit", | |
| "version": "1.7.0" | |
| } | |
| }, | |
| "results": [] | |
| } | |
| ] | |
| } | |
| EOF | |
| fi | |
| - name: Upload Bandit results | |
| uses: github/codeql-action/upload-sarif@v3 | |
| if: always() | |
| with: | |
| sarif_file: 'bandit-results.sarif' | |
| category: 'bandit' | |
| # ==== CONTAINER SECURITY ==== | |
| container-scan: | |
| name: Container Security | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 15 | |
| if: github.event_name == 'schedule' || inputs.full_scan | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Find Docker configurations | |
| id: docker_files | |
| run: | | |
| # Find docker-compose files and Dockerfiles | |
| docker_files=$(find . -name "*docker-compose*.yml" -o -name "*compose*.yml" -o -name "Dockerfile*" | head -10) | |
| if [[ -n "$docker_files" ]]; then | |
| echo "found=true" >> $GITHUB_OUTPUT | |
| echo "files<<EOF" >> $GITHUB_OUTPUT | |
| echo "$docker_files" >> $GITHUB_OUTPUT | |
| echo "EOF" >> $GITHUB_OUTPUT | |
| else | |
| echo "found=false" >> $GITHUB_OUTPUT | |
| fi | |
| - name: Scan Docker configurations | |
| if: steps.docker_files.outputs.found == 'true' | |
| uses: aquasecurity/trivy-action@master | |
| with: | |
| scan-type: 'config' | |
| scan-ref: '.' | |
| format: 'sarif' | |
| output: 'trivy-docker-config.sarif' | |
| scanners: 'config' | |
| - name: Ensure Docker config SARIF file exists | |
| if: steps.docker_files.outputs.found == 'true' | |
| run: | | |
| if [[ ! -f "trivy-docker-config.sarif" ]]; then | |
| echo "Trivy did not generate SARIF file for Docker configs, creating minimal SARIF structure" | |
| cat > trivy-docker-config.sarif << 'EOF' | |
| { | |
| "$schema": "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json", | |
| "version": "2.1.0", | |
| "runs": [ | |
| { | |
| "tool": { | |
| "driver": { | |
| "name": "trivy", | |
| "informationUri": "https://github.com/aquasecurity/trivy", | |
| "version": "latest" | |
| } | |
| }, | |
| "results": [] | |
| } | |
| ] | |
| } | |
| EOF | |
| fi | |
| - name: Upload Docker scan results | |
| if: steps.docker_files.outputs.found == 'true' && always() | |
| uses: github/codeql-action/upload-sarif@v3 | |
| with: | |
| sarif_file: 'trivy-docker-config.sarif' | |
| category: 'docker-config' | |
| # ==== SECURITY SUMMARY ==== | |
| security-summary: | |
| name: Security Summary | |
| runs-on: ubuntu-latest | |
| needs: [secrets-scan, dependency-scan, infrastructure-scan, sast-scan, container-scan] | |
| if: always() && !cancelled() | |
| timeout-minutes: 5 | |
| steps: | |
| - name: Generate security summary | |
| run: | | |
| echo "# π Security Scan Summary" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "## Scan Results" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "| Security Check | Status | Details |" >> $GITHUB_STEP_SUMMARY | |
| echo "|----------------|--------|---------|" >> $GITHUB_STEP_SUMMARY | |
| # Secrets Detection | |
| if [[ "${{ needs.secrets-scan.result }}" == "success" ]]; then | |
| echo "| π Secrets Detection | β Passed | No secrets found in code |" >> $GITHUB_STEP_SUMMARY | |
| elif [[ "${{ needs.secrets-scan.result }}" == "failure" ]]; then | |
| echo "| π Secrets Detection | β Failed | Potential secrets detected |" >> $GITHUB_STEP_SUMMARY | |
| else | |
| echo "| π Secrets Detection | βοΈ Skipped | - |" >> $GITHUB_STEP_SUMMARY | |
| fi | |
| # Dependency Scanning | |
| if [[ "${{ needs.dependency-scan.result }}" == "success" ]]; then | |
| echo "| π¦ Dependency Scan | β Passed | No critical vulnerabilities |" >> $GITHUB_STEP_SUMMARY | |
| elif [[ "${{ needs.dependency-scan.result }}" == "failure" ]]; then | |
| echo "| π¦ Dependency Scan | β οΈ Issues Found | Check SARIF reports |" >> $GITHUB_STEP_SUMMARY | |
| else | |
| echo "| π¦ Dependency Scan | βοΈ Skipped | - |" >> $GITHUB_STEP_SUMMARY | |
| fi | |
| # Infrastructure Security | |
| if [[ "${{ needs.infrastructure-scan.result }}" == "success" ]]; then | |
| echo "| ποΈ Infrastructure | β Passed | No security issues found |" >> $GITHUB_STEP_SUMMARY | |
| elif [[ "${{ needs.infrastructure-scan.result }}" == "failure" ]]; then | |
| echo "| ποΈ Infrastructure | β οΈ Issues Found | Review Terraform/Ansible configs |" >> $GITHUB_STEP_SUMMARY | |
| else | |
| echo "| ποΈ Infrastructure | βοΈ Skipped | - |" >> $GITHUB_STEP_SUMMARY | |
| fi | |
| # Static Analysis | |
| if [[ "${{ needs.sast-scan.result }}" == "success" ]]; then | |
| echo "| π¬ Static Analysis | β Passed | No security issues in code |" >> $GITHUB_STEP_SUMMARY | |
| elif [[ "${{ needs.sast-scan.result }}" == "failure" ]]; then | |
| echo "| π¬ Static Analysis | β οΈ Issues Found | Review CodeQL/Bandit reports |" >> $GITHUB_STEP_SUMMARY | |
| elif [[ "${{ needs.sast-scan.result }}" == "skipped" ]]; then | |
| echo "| π¬ Static Analysis | βοΈ Skipped | Scheduled runs only |" >> $GITHUB_STEP_SUMMARY | |
| fi | |
| # Container Security | |
| if [[ "${{ needs.container-scan.result }}" == "success" ]]; then | |
| echo "| π³ Container Security | β Passed | Docker configs secure |" >> $GITHUB_STEP_SUMMARY | |
| elif [[ "${{ needs.container-scan.result }}" == "failure" ]]; then | |
| echo "| π³ Container Security | β οΈ Issues Found | Review Docker configurations |" >> $GITHUB_STEP_SUMMARY | |
| elif [[ "${{ needs.container-scan.result }}" == "skipped" ]]; then | |
| echo "| π³ Container Security | βοΈ Skipped | Scheduled/manual runs only |" >> $GITHUB_STEP_SUMMARY | |
| fi | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| # Overall Security Status | |
| failed_scans="" | |
| if [[ "${{ needs.secrets-scan.result }}" == "failure" ]]; then | |
| failed_scans="$failed_scans secrets-detection" | |
| fi | |
| if [[ "${{ needs.dependency-scan.result }}" == "failure" ]]; then | |
| failed_scans="$failed_scans dependency-scan" | |
| fi | |
| if [[ "${{ needs.infrastructure-scan.result }}" == "failure" ]]; then | |
| failed_scans="$failed_scans infrastructure-scan" | |
| fi | |
| if [[ "${{ needs.sast-scan.result }}" == "failure" ]]; then | |
| failed_scans="$failed_scans static-analysis" | |
| fi | |
| if [[ "${{ needs.container-scan.result }}" == "failure" ]]; then | |
| failed_scans="$failed_scans container-scan" | |
| fi | |
| if [[ -z "$failed_scans" ]]; then | |
| echo "## β Overall Security Status: GOOD" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "All security scans completed successfully. No critical issues detected." >> $GITHUB_STEP_SUMMARY | |
| else | |
| echo "## β οΈ Overall Security Status: NEEDS ATTENTION" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "The following security scans found issues: $failed_scans" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "Please review the Security tab in GitHub for detailed SARIF reports." >> $GITHUB_STEP_SUMMARY | |
| fi | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "---" >> $GITHUB_STEP_SUMMARY | |
| echo "π‘ **Tip**: Check the Security tab in your repository for detailed vulnerability reports." >> $GITHUB_STEP_SUMMARY |