Repository navigation
FinOps Scan #7
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: FinOps Scan | |
| on: | |
| schedule: | |
| - cron: '0 6 * * 1' # Weekly Monday 06:00 UTC | |
| workflow_dispatch: | |
| permissions: | |
| contents: read | |
| security-events: write | |
| id-token: write | |
| jobs: | |
| psrule-scan: | |
| runs-on: ubuntu-latest | |
| strategy: | |
| matrix: | |
| app: ['001', '002', '003', '004', '005'] | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: actions/checkout@v4 | |
| with: | |
| repository: devopsabcs-engineering/finops-demo-app-${{ matrix.app }} | |
| token: ${{ secrets.ORG_ADMIN_TOKEN }} | |
| path: target-app | |
| - name: Run PSRule | |
| uses: microsoft/ps-rule@v2.9.0 | |
| with: | |
| inputPath: target-app/infra/ | |
| modules: PSRule.Rules.Azure | |
| outputFormat: Sarif | |
| outputPath: reports/psrule-${{ matrix.app }}.sarif | |
| option: src/config/ps-rule.yaml | |
| baseline: Azure.GA_2024_12 | |
| continue-on-error: true | |
| - uses: actions/upload-artifact@v4 | |
| with: | |
| name: sarif-psrule-${{ matrix.app }} | |
| path: reports/psrule-${{ matrix.app }}.sarif | |
| checkov-scan: | |
| runs-on: ubuntu-latest | |
| strategy: | |
| matrix: | |
| app: ['001', '002', '003', '004', '005'] | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| repository: devopsabcs-engineering/finops-demo-app-${{ matrix.app }} | |
| token: ${{ secrets.ORG_ADMIN_TOKEN }} | |
| - name: Run Checkov | |
| uses: bridgecrewio/checkov-action@v12 | |
| with: | |
| directory: infra/ | |
| output_format: sarif | |
| output_file_path: reports/ | |
| soft_fail: true | |
| - uses: actions/upload-artifact@v4 | |
| with: | |
| name: sarif-checkov-${{ matrix.app }} | |
| path: reports/results_sarif.sarif | |
| custodian-scan: | |
| runs-on: ubuntu-latest | |
| continue-on-error: true | |
| strategy: | |
| matrix: | |
| app: ['001', '002', '003', '004', '005'] | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: azure/login@v2 | |
| with: | |
| client-id: ${{ secrets.AZURE_CLIENT_ID }} | |
| tenant-id: ${{ secrets.AZURE_TENANT_ID }} | |
| subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} | |
| - name: Install Cloud Custodian | |
| run: pip install c7n c7n-azure | |
| - name: Run Cloud Custodian | |
| env: | |
| AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }} | |
| run: | | |
| mkdir -p output reports | |
| # Run each policy file individually | |
| # Cloud Custodian filters resources at query time, so we rely on | |
| # the policy filters already defined in the YAML files. | |
| # The subscription-level scan will find resources across all RGs, | |
| # and the cross-repo-upload job routes results to the correct repo. | |
| for policy_file in src/config/custodian/*.yml; do | |
| echo "Running: $(basename $policy_file)" | |
| custodian run -s output/ "$policy_file" --cache-period 0 2>&1 || true | |
| done | |
| # List what was found | |
| echo "=== Custodian output ===" | |
| find output/ -name "resources.json" -exec sh -c 'echo " $(dirname {} | xargs basename): $(cat {} | python3 -c "import sys,json; print(len(json.load(sys.stdin)))" 2>/dev/null || echo 0) resources"' \; | |
| echo "Custodian scan complete for app ${{ matrix.app }}" | |
| - name: Convert to SARIF | |
| run: | | |
| mkdir -p reports | |
| if [ -d "output/" ] && [ "$(ls -A output/)" ]; then | |
| python src/converters/custodian-to-sarif.py output/ reports/custodian-${{ matrix.app }}.sarif | |
| else | |
| echo "No custodian output to convert, creating empty SARIF" | |
| echo '{"version":"2.1.0","$schema":"https://raw.githubusercontent.com/oasis-tcs/sarif-spec/main/sarif-2.1/schema/sarif-schema-2.1.0.json","runs":[{"tool":{"driver":{"name":"custodian-to-sarif","version":"1.0.0","informationUri":"https://cloudcustodian.io","rules":[]}},"results":[]}]}' > reports/custodian-${{ matrix.app }}.sarif | |
| fi | |
| - uses: actions/upload-artifact@v4 | |
| with: | |
| name: sarif-custodian-${{ matrix.app }} | |
| path: reports/custodian-${{ matrix.app }}.sarif | |
| cross-repo-upload: | |
| needs: [psrule-scan, checkov-scan, custodian-scan] | |
| if: always() && (needs.psrule-scan.result == 'success' || needs.checkov-scan.result == 'success') | |
| runs-on: ubuntu-latest | |
| strategy: | |
| matrix: | |
| app: ['001', '002', '003', '004', '005'] | |
| steps: | |
| - uses: actions/download-artifact@v4 | |
| with: | |
| pattern: sarif-*-${{ matrix.app }} | |
| merge-multiple: true | |
| path: reports/ | |
| - name: Upload SARIF to target repo | |
| env: | |
| GH_TOKEN: ${{ secrets.ORG_ADMIN_TOKEN }} | |
| run: | | |
| for sarif_file in reports/*.sarif; do | |
| if [ ! -f "$sarif_file" ]; then continue; fi | |
| SARIF_CONTENT=$(gzip -c "$sarif_file" | base64 -w0) | |
| COMMIT_SHA=$(gh api repos/devopsabcs-engineering/finops-demo-app-${{ matrix.app }}/commits/main --jq '.sha') | |
| gh api \ | |
| --method POST \ | |
| repos/devopsabcs-engineering/finops-demo-app-${{ matrix.app }}/code-scanning/sarifs \ | |
| -f "commit_sha=$COMMIT_SHA" \ | |
| -f "ref=refs/heads/main" \ | |
| -f "sarif=$SARIF_CONTENT" | |
| echo "Uploaded $(basename $sarif_file) to finops-demo-app-${{ matrix.app }}" | |
| done |