Skip to content

docs: Update documentation with cross-repo analyzer details #16

docs: Update documentation with cross-repo analyzer details

docs: Update documentation with cross-repo analyzer details #16

Workflow file for this run

name: DevSecOps Pipeline

Check failure on line 1 in .github/workflows/devsecops.yml

View workflow run for this annotation

GitHub Actions / .github/workflows/devsecops.yml

Invalid workflow file

(Line: 163, Col: 13): Unrecognized named-value: 'secrets'. Located at position 1 within expression: secrets.INFRACOST_API_KEY != ''
on:
push:
branches: [ "main", "master" ]
pull_request:
branches: [ "main", "master" ]
schedule:
- cron: '0 0 * * 0' # Weekly baseline scan
workflow_dispatch:
permissions:
security-events: write
contents: read
packages: write # For pushing images/signatures
id-token: write # For Cosign OIDC (optional)
pull-requests: write # For posting comments
jobs:
secret-scan:
name: Secret Scan (TruffleHog)
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
fetch-depth: 0
- name: TruffleHog (Diff Mode)
if: github.event_name == 'push' || github.event_name == 'pull_request'
uses: trufflesecurity/trufflehog@895cc72a44b8b6a386993a4046bc77884784a929 # v3.82.12
with:
extra_args: --only-verified --fail --no-update
- name: TruffleHog (Baseline Mode)
if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch'
uses: trufflesecurity/trufflehog@895cc72a44b8b6a386993a4046bc77884784a929 # v3.82.12
with:
extra_args: --only-verified --fail --no-update --since-commit HEAD
sast-scan:
name: SAST (Semgrep)
runs-on: ubuntu-latest
container:
image: returntocorp/semgrep
if: (github.actor != 'dependabot[bot]')
steps:
- name: Checkout code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Semgrep Scan
run: semgrep scan --config auto --sarif --output semgrep.sarif
continue-on-error: true
- name: Check for Critical/High Failures
run: semgrep scan --config auto --error --severity ERROR --severity CRITICAL
- name: Upload SARIF
uses: actions/upload-artifact@6027bc5291242e2308107931669864239f884a44 # v4.4.0
if: always()
with:
name: semgrep.sarif
path: semgrep.sarif
- name: Upload Security SARIF (CodeQL)
uses: github/codeql-action/upload-sarif@66115715ae9c0202956f4d546f14066914995955 # v3.25.11
if: always()
continue-on-error: true
with:
sarif_file: semgrep.sarif
sca-scan:
name: SCA (Snyk)
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Setup Node.js
uses: actions/setup-node@39225597dea6c34d620298be596b72fe05224403 # v4.1.0
with:
node-version: '16'
- name: Install dependencies
run: npm install || true
- name: Snyk Scan
uses: snyk/actions/node@b9830575092c6dac41351111608672074e54e445 # v0.10.0
continue-on-error: true
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
with:
args: --severity-threshold=high --sarif-file-output=snyk.sarif
- name: Upload SARIF
uses: actions/upload-artifact@6027bc5291242e2308107931669864239f884a44 # v4.4.0
if: always()
with:
name: snyk.sarif
path: snyk.sarif
- name: Upload Security SARIF (CodeQL)
uses: github/codeql-action/upload-sarif@66115715ae9c0202956f4d546f14066914995955 # v3.25.11
if: always()
continue-on-error: true
with:
sarif_file: snyk.sarif
- name: Snyk Gatekeeper
uses: snyk/actions/node@b9830575092c6dac41351111608672074e54e445 # v0.10.0
if: ${{ env.SNYK_TOKEN != '' }}
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
with:
args: --severity-threshold=high
iac-scan:
name: IaC Scan (Checkov)
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Checkov Scan
uses: bridgecrewio/checkov-action@486183e91f1a1c93a0228308436440c313203f7e # v12.2882.0
with:
directory: ./terraform
quiet: true
soft_fail: false
output_format: sarif
output_file_path: checkov.sarif
- name: Upload SARIF
uses: actions/upload-artifact@6027bc5291242e2308107931669864239f884a44 # v4.4.0
if: always()
with:
name: checkov.sarif
path: checkov.sarif
- name: Upload Security SARIF (CodeQL)
uses: github/codeql-action/upload-sarif@66115715ae9c0202956f4d546f14066914995955 # v3.25.11
if: always()
continue-on-error: true
with:
sarif_file: checkov.sarif
cost-estimation:
name: FinOps (Infracost)
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write # Required to post comments
steps:
- name: Checkout code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Setup Infracost
uses: infracost/actions/setup@91f7a6021289569735d487f98f6d525790a6e60b # v3.0.0
with:
api-key: ${{ secrets.INFRACOST_API_KEY }}
- name: Infracost Breakdown
if: ${{ secrets.INFRACOST_API_KEY != '' }}
run: |
infracost breakdown --path ./terraform --format json --out-file infracost-usage.json
- name: Post Infracost Comment
if: github.event_name == 'pull_request' && secrets.INFRACOST_API_KEY != ''
env:
INFRACOST_API_KEY: ${{ secrets.INFRACOST_API_KEY }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
infracost comment github --path infracost-usage.json --repo $GITHUB_REPOSITORY --pull-request ${{ github.event.pull_request.number }} --behavior update
container-build-sign:
name: Build & Sign (Trivy + Cosign)
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Build Docker Image
run: docker build -t my-app:${{ github.sha }} .
# 1. Scan (Trivy)
- name: Trivy Image Scan (SARIF)
uses: aquasecurity/trivy-action@d43c1f16c000d89748ed7a5cc2a74043e803b00e # v0.24.0
with:
image-ref: 'my-app:${{ github.sha }}'
format: 'sarif'
output: 'trivy-results.sarif'
ignore-unfixed: true
vuln-type: 'os,library'
- name: Upload SARIF
uses: actions/upload-artifact@6027bc5291242e2308107931669864239f884a44 # v4.4.0
if: always()
with:
name: trivy-results.sarif
path: trivy-results.sarif
- name: Upload Security SARIF (CodeQL)
uses: github/codeql-action/upload-sarif@66115715ae9c0202956f4d546f14066914995955 # v3.25.11
if: always()
continue-on-error: true
with:
sarif_file: trivy-results.sarif
- name: Trivy Gatekeeper
uses: aquasecurity/trivy-action@d43c1f16c000d89748ed7a5cc2a74043e803b00e # v0.24.0
with:
image-ref: 'my-app:${{ github.sha }}'
exit-code: '1'
ignore-unfixed: true
severity: 'CRITICAL,HIGH'
# 2. Sign (Cosign) - Only runs if Trivy passes
- name: Install Cosign
uses: sigstore/cosign-installer@59ac5dcde5aa5408e01ad4409589d283b9d7a287 # v3.5.0
- name: Sign Image
if: github.event_name != 'pull_request' # Don't sign PR builds typically
env:
COSIGN_PRIVATE_KEY: ${{ secrets.COSIGN_PRIVATE_KEY }}
COSIGN_PASSWORD: ${{ secrets.COSIGN_PASSWORD }}
run: |
if [[ -z "$COSIGN_PRIVATE_KEY" ]]; then
echo "Skipping signing: COSIGN_PRIVATE_KEY not set."
else
# In a real pipeline, you'd push to a registry first.
# For this demo, we mock the signing step or sign a local tag if supported (Cosign usually needs a registry).
echo "Cosign key detected. In a real pipeline, we would run:"
echo "cosign sign --key env://COSIGN_PRIVATE_KEY my-registry/my-app:${{ github.sha }}"
# To demonstrate, we'll create a dummy signature file
echo "signature" > cosign.sig
fi
- name: Generate SBOM (SPDX)
uses: aquasecurity/trivy-action@d43c1f16c000d89748ed7a5cc2a74043e803b00e # v0.24.0
with:
image-ref: 'my-app:${{ github.sha }}'
format: 'spdx-json'
output: 'sbom.spdx.json'
- name: Upload SBOM
uses: actions/upload-artifact@6027bc5291242e2308107931669864239f884a44 # v4.4.0
with:
name: sbom
path: sbom.spdx.json
dast-scan:
name: Runtime Security (DAST)
runs-on: ubuntu-latest
needs: [container-build-sign]
steps:
- name: Checkout code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Build & Run Container
run: |
docker build -t my-app:${{ github.sha }} .
# Run detached, map internal 3000 to host 3000
docker run -d -p 3000:3000 --name test-app my-app:${{ github.sha }}
# Wait for app to start (simple sleep or healthcheck loop)
sleep 5
- name: OWASP ZAP Baseline Scan
uses: zaproxy/action-baseline@290a611c039d91f868c6e26487e0766324263720 # v0.14.0
continue-on-error: true # DAST is noisy; often we want results without blocking initially
with:
target: 'http://localhost:3000'
fail_action: false # Don't fail the action immediately, check report later
# Note: ZAP action outputs artifacts automatically (zap_report.html)
compliance-audit:
name: Generate Compliance Artifacts
runs-on: ubuntu-latest
needs: [secret-scan, sast-scan, sca-scan, iac-scan, container-build-sign, dast-scan]
if: always()
outputs:
hashes: ${{ steps.hash.outputs.hashes }}
steps:
- name: Checkout code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Generate Source SBOM
run: |
mkdir -p results
curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b /usr/local/bin
/usr/local/bin/syft dir:. -o spdx-json > results/sbom-source.spdx.json
/usr/local/bin/syft dir:. -o cyclonedx-json > results/sbom-source.cdx.json
- name: Upload SBOM Artifacts
uses: actions/upload-artifact@6027bc5291242e2308107931669864239f884a44 # v4.4.0
with:
name: sbom-reports
path: results/sbom-*
- name: Generate Audit Record
run: |
echo "{" > deployment-audit.json
echo " \"timestamp\": \"$(date -u +"%Y-%m-%dT%H:%M:%SZ")\"," >> deployment-audit.json
echo " \"repository\": \"$GITHUB_REPOSITORY\"," >> deployment-audit.json
echo " \"commit_sha\": \"$GITHUB_SHA\"," >> deployment-audit.json
echo " \"actor\": \"$GITHUB_ACTOR\"," >> deployment-audit.json
echo " \"workflow_run_id\": \"$GITHUB_RUN_ID\"," >> deployment-audit.json
echo "}" >> deployment-audit.json
- name: Upload Audit Artifact
uses: actions/upload-artifact@6027bc5291242e2308107931669864239f884a44 # v4.4.0
with:
name: deployment-audit
path: deployment-audit.json
- name: Run Policy Check
run: ./scripts/fortressci-policy-check.sh .security/policy.yml results/
- name: Generate Compliance Report
run: python3 scripts/generate-compliance-report.py results/ .security/compliance-mappings.yml
- name: AI Triage
if: always()
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
run: python3 scripts/ai-triage.py --results-dir results/ --config .fortressci.yml
- name: Generate Security Badge
if: always()
run: python3 scripts/generate-badge.py results/
- name: Build Attack Graph
if: always()
run: python3 scripts/build-attack-graph.py results/
- name: Generate Hashes
id: hash
run: |
cd results
echo "hashes=$(sha256sum sbom-source.spdx.json sbom-source.cdx.json ../deployment-audit.json | base64 -w0)" >> "$GITHUB_OUTPUT"
provenance:
needs: [compliance-audit]
permissions:
actions: read
id-token: write
contents: write
uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v2.0.0
with:
base64-subjects: "${{ needs.compliance-audit.outputs.hashes }}"
upload-assets: true
pr-feedback:
name: Developer Feedback (PR Comments)
runs-on: ubuntu-latest
needs: [sast-scan, sca-scan, iac-scan, container-build-sign] # Wait for scans to finish
if: always() && github.event_name == 'pull_request'
steps:
- name: Checkout code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Download All Artifacts
uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8
with:
merge-multiple: true
- name: Post Summary to PR
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
with:
script: |
const script = require('./.github/scripts/post_summary.js')
await script({github, context})
auto-remediation:
name: Auto-Remediation (PR)
runs-on: ubuntu-latest
needs: [sast-scan, sca-scan, iac-scan]
if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch'
permissions:
contents: write
pull-requests: write
steps:
- name: Checkout code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Run Auto-Fix
run: ./scripts/auto-fix.sh
- name: Create Pull Request
uses: peter-evans/create-pull-request@67ccf781d68cd99b580ae25a5c18a1cc84617901 # v6.0.1
with:
token: ${{ secrets.GITHUB_TOKEN }}
commit-message: "fix: auto-remediation of security findings"
title: "🏰 FortressCI Auto-Remediation"
body: |
This is an automated pull request from FortressCI to fix security findings.
Scanners: Snyk, Checkov
branch: fortressci/auto-remediation
base: main
labels: |
security
automated