Mayhem CI #274
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: Mayhem CI | |
| on: | |
| push: | |
| branches: [ "main" ] | |
| pull_request: | |
| branches: [ "main" ] | |
| workflow_call: | |
| inputs: | |
| mayhem_url: | |
| description: 'Mayhem URL' | |
| required: true | |
| default: 'https://app.mayhem.security' | |
| type: string | |
| workspace: | |
| description: 'Mayhem Workspace' | |
| required: true | |
| default: 'platform-demo' | |
| type: string | |
| secrets: | |
| mayhem-token: | |
| description: 'Mayhem Token' | |
| required: false | |
| workflow_dispatch: | |
| env: | |
| REGISTRY: ghcr.io | |
| jobs: | |
| build: | |
| runs-on: ubuntu-latest | |
| if: github.event.pull_request.draft == false | |
| steps: | |
| - name: Set Mayhem token | |
| run: | | |
| if [ -z "${{ secrets.mayhem-token }}" ]; then | |
| echo "::add-mask::${{ secrets.MAYHEM_TOKEN }}" | |
| echo "MAYHEM_TOKEN=${{ secrets.MAYHEM_TOKEN }}" >> $GITHUB_ENV | |
| else | |
| echo "::add-mask::${{ secrets.mayhem-token }}" | |
| echo "MAYHEM_TOKEN=${{ secrets.mayhem-token }}" >> $GITHUB_ENV | |
| fi | |
| - name: Set default inputs if not provided | |
| run: | | |
| echo "MAYHEM_URL=${{ inputs.mayhem_url || 'https://app.mayhem.security' }}" >> $GITHUB_ENV | |
| echo "WORKSPACE=${{ inputs.workspace || 'platform-demo' }}" >> $GITHUB_ENV | |
| - name: lowercase github.repository | |
| run: echo "REPO_NAME=`echo ${{github.repository}} | tr '[:upper:]' '[:lower:]'`" >>${GITHUB_ENV} | |
| # checkout repository | |
| - uses: actions/checkout@v3 | |
| with: | |
| submodules: recursive | |
| - name: Login to docker | |
| run: echo "${{ secrets.DOCKER_PASSWORD }}" | docker login -u ${{ secrets.DOCKER_USERNAME }} --password-stdin | |
| - name: Install Docker Scout | |
| run: curl -sSfL https://raw.githubusercontent.com/docker/scout-cli/main/install.sh | sh -s -- | |
| - name: Install mdsbom | |
| run: curl -sSL $MAYHEM_URL/cli/mdsbom/linux/latest/mdsbom.deb -O && sudo dpkg -i mdsbom.deb && sudo usermod -aG mdsbom $USER | |
| - name: Update /etc/docker/daemon.json to use mdsbom | |
| run: | | |
| echo '{ | |
| "runtimes": { | |
| "mdsbom": { | |
| "path": "/usr/bin/mdsbom", | |
| "runtimeArgs": [ | |
| "runc", | |
| "--", | |
| "runc" | |
| ] | |
| } | |
| }, | |
| "default-runtime": "mdsbom" | |
| }' | sudo tee /etc/docker/daemon.json > /dev/null | |
| - name: Setup sync | |
| run: | | |
| echo "[sync] | |
| api_token = \"${{ env.MAYHEM_TOKEN }}\" | |
| upstream_url = \"${{ env.MAYHEM_URL }}\" | |
| workspace = \"${{ env.WORKSPACE }}\" | |
| " | sudo tee -a /etc/mdsbom/config.toml | |
| - name: Restart services | |
| run: | | |
| sudo systemctl restart docker || sudo journalctl -xeu docker; | |
| sudo systemctl restart mdsbom || sudo journalctl -xeu mdsbom | |
| - name: MDSBOM login | |
| run: mdsbom login ${{ env.MAYHEM_URL }} ${{ env.MAYHEM_TOKEN }} | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@v3 | |
| - name: Login to GitHub Container Registry | |
| uses: docker/login-action@v3 | |
| with: | |
| registry: ${{ env.REGISTRY }} | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Build and push the app images | |
| id: build | |
| run: | | |
| docker compose pull --ignore-buildable -q | |
| # Build car image, with metadata | |
| docker build -t ${{ env.REGISTRY }}/${{ env.REPO_NAME }}/car:${{ github.sha }} --metadata-file metadata.json car/ | |
| # Push with commit sha | |
| SHA=${{ github.sha }} docker compose build | |
| SHA=${{ github.sha }} docker compose push -q | |
| # Push with latest | |
| docker compose build | |
| docker compose push -q | |
| env: | |
| SOURCE_DATE_EPOCH: 0 | |
| BUILDX_METADATA_PROVENANCE: max | |
| DOCKER_BUILDKIT: 1 | |
| - name: Upload buildkit metadata artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: metadata-${{ github.sha }} | |
| path: metadata.json | |
| - name: Bring up the app | |
| run: SHA=${{ github.sha }} docker compose up -d && sleep 1 && docker ps | |
| - name: Wait for the API to be up | |
| run: bash -c 'while ! curl -ks https://localhost:8443/openapi.json; do sleep 1; done' | |
| - name: Start API analysis | |
| uses: forallsecure/mapi-action@v1 | |
| continue-on-error: true | |
| env: | |
| MAPI_BASIC_AUTH: "me@me.com:123456" | |
| with: | |
| mayhem-url: ${{ env.MAYHEM_URL }} | |
| mayhem-token: ${{ env.MAYHEM_TOKEN }} | |
| target: ${{ env.WORKSPACE }}/mayhem-demo/api | |
| api-url: https://localhost:8443 | |
| api-spec: https://localhost:8443/openapi.json | |
| sarif-report: api.sarif | |
| run-args: | | |
| --experimental-rules | |
| --ignore-rule | |
| internal-server-error | |
| - name: Upload SARIF file | |
| uses: github/codeql-action/upload-sarif@v3 | |
| with: | |
| sarif_file: api.sarif | |
| # - name: Start ZAP API analysis | |
| # uses: forallsecure/mapi-action@v1 | |
| # continue-on-error: true | |
| # with: | |
| # mayhem-token: $MAYHEM_TOKEN | |
| # target: $WORKSPACE/mayhem-demo/api-zap | |
| # api-url: https://localhost:8443 | |
| # api-spec: https://localhost:8443/openapi.json | |
| # sarif-report: api-zap.sarif | |
| # run-args: | | |
| # --ignore-rule auth-bypass | |
| # --ignore-rule command-injection | |
| # --ignore-rule internal-server-error | |
| # --ignore-rule invalid-request-spec | |
| # --ignore-rule invalid-response-spec | |
| # --ignore-rule timeout | |
| # --ignore-rule verb-tampering | |
| # --ignore-rule nosql-injection | |
| # zap-api-scan: true | |
| - name: Start Code analysis | |
| uses: forallsecure/mcode-action@v1 | |
| with: | |
| mayhem-url: ${{ env.MAYHEM_URL }} | |
| mayhem-token: ${{ env.MAYHEM_TOKEN }} | |
| owner: ${{ env.WORKSPACE }} | |
| args: -f car/Mayhemfile --image ${{ env.REGISTRY }}/${{ env.REPO_NAME }}/car:${{ github.sha }} --duration 600 | |
| sarif-output: code-sarif/ | |
| coverage-output: car-coverage/ | |
| - name: Add car prefix to SARIF | |
| shell: bash | |
| run: | | |
| jq '.runs[0].results[].locations[].physicalLocation.artifactLocation.uri |= "car/" + . | |
| | .runs[0].results[].locations[].physicalLocation.artifactLocation.uri |= sub("app/"; "") | |
| | .runs[0].results[].locations[].physicalLocation.artifactLocation.uri |= sub("/rc/"; "/src/")' \ | |
| code-sarif/car.sarif > code-sarif/car2.sarif | |
| mv -f code-sarif/car2.sarif code-sarif/car.sarif | |
| - name: Upload SARIF file | |
| uses: github/codeql-action/upload-sarif@v3 | |
| with: | |
| sarif_file: code-sarif/ | |
| category: Mayhem-for-Code | |
| checkout_path: ${{ github.workspace }}/car | |
| - name: Archive Code SARIF report | |
| if: always() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: car.sarif | |
| path: code-sarif/car.sarif | |
| - name: Upload coverage to Codecov | |
| if: always() | |
| uses: codecov/codecov-action@v4 | |
| env: | |
| CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} | |
| with: | |
| files: car-coverage/* | |
| flags: Mayhem-for-Code | |
| name: mayhem | |
| - name: Bring down the app | |
| run: SHA=${{ github.sha }} docker compose down -v | |
| # - name: Pause to let mdsbom sync run | |
| # run: sleep 15 && mdsbom query --workspace ${{ env.WORKSPACE }} containers -a | |
| - name: Upload coverage to Codecov | |
| uses: codecov/codecov-action@v4 | |
| env: | |
| CODECOV_TOKEN: "${{ secrets.CODECOV_TOKEN }}" | |
| with: | |
| files: coverage/coverage.xml | |
| flags: Mayhem-for-API | |
| fail_ci_if_error: true | |
| # - name: Run Dynamic SBOM scan | |
| # run: | | |
| # sudo -u $USER mdsbom scout ${{ env.REGISTRY }}/${{ env.REPO_NAME }}/car:${{ github.sha }} --sca-report-out dsbom-car.sarif --workspace ${{ env.WORKSPACE }} | |
| # sudo -u $USER mdsbom scout ${{ env.REGISTRY }}/${{ env.REPO_NAME }}/api:${{ github.sha }} --sca-report-out dsbom-api.sarif --workspace ${{ env.WORKSPACE }} | |
| # - name: Patch docker scout SARIF report for CodeQL | |
| # run : | | |
| # jq 'walk(if type == "object" and has("startLine") and .startLine == 0 then .startLine = 1 else . end | | |
| # if type == "object" and has("endLine") and .endLine == 0 then .endLine = 1 else . end | | |
| # if type == "object" and has("endColumn") and .endColumn == 0 then .endColumn = 1 else . end | | |
| # if type == "object" and has("startColumn") and .startColumn == 0 then .startColumn = 1 else . end)' dsbom-api.sarif > dsbom-api-patched.sarif | |
| # jq 'walk(if type == "object" and has("startLine") and .startLine == 0 then .startLine = 1 else . end | | |
| # if type == "object" and has("endLine") and .endLine == 0 then .endLine = 1 else . end | | |
| # if type == "object" and has("endColumn") and .endColumn == 0 then .endColumn = 1 else . end | | |
| # if type == "object" and has("startColumn") and .startColumn == 0 then .startColumn = 1 else . end)' dsbom-car.sarif > dsbom-car-patched.sarif | |
| # - name: Upload SARIF file | |
| # id: upload-api | |
| # uses: github/codeql-action/upload-sarif@v3 | |
| # with: | |
| # sarif_file: dsbom-api-patched.sarif | |
| # category: Dynamic-SBOM/api | |
| # - name: Dismiss issues that were not observed at runtime | |
| # uses: advanced-security/dismiss-alerts@v1 | |
| # with: | |
| # sarif-id: ${{ steps.upload-api.outputs.sarif-id }} | |
| # sarif-file: dsbom-api-patched.sarif | |
| # env: | |
| # GITHUB_TOKEN: "${{ github.token }}" | |
| # Disabled d/t: rejecting SARIF, as there are more related locations per result than allowed (2277 > 1000) | |
| # - name: Upload SARIF file | |
| # id: upload-car | |
| # uses: github/codeql-action/upload-sarif@v3 | |
| # with: | |
| # sarif_file: dsbom-car-patched.sarif | |
| # category: Dynamic-SBOM/car | |
| # - name: Dismiss issues that were not observed at runtime | |
| # uses: advanced-security/dismiss-alerts@v1 | |
| # with: | |
| # # specify a 'sarif-id' and 'sarif-file' | |
| # sarif-id: ${{ steps.upload-car.outputs.sarif-id }} | |
| # sarif-file: dsbom-car-patched.sarif | |
| # env: | |
| # GITHUB_TOKEN: "${{ github.token }}" |