sbom.yml 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. name: Generate SBOM
  2. on:
  3. workflow_run:
  4. workflows: ["Build and Publish Release"]
  5. types:
  6. - completed
  7. workflow_dispatch:
  8. inputs:
  9. release_version:
  10. description: "Version of the release to generate SBOM for"
  11. required: true
  12. pull_request:
  13. branches:
  14. - develop
  15. permissions: read-all
  16. concurrency:
  17. group: sbom-${{ github.ref }}
  18. cancel-in-progress: true
  19. env:
  20. REGISTRY: ghcr.io
  21. jobs:
  22. generate-sbom:
  23. runs-on: ubuntu-latest
  24. if: github.event_name != 'workflow_run' || github.event.workflow_run.conclusion == 'success'
  25. permissions:
  26. contents: ${{ github.event_name == 'pull_request' && 'read' || 'write' }}
  27. actions: read
  28. packages: read
  29. steps:
  30. - name: Checkout Repo (for version detection)
  31. if: github.event_name == 'workflow_run'
  32. uses: actions/checkout@v4
  33. with:
  34. fetch-depth: 0
  35. - name: Get Version From Workflow Run
  36. id: tag
  37. if: github.event_name == 'workflow_run'
  38. run: |
  39. # Get the SHA from the workflow run
  40. SHA="${{ github.event.workflow_run.head_sha }}"
  41. # Find the tag pointing to this SHA
  42. TAG=$(git tag --points-at $SHA | grep '^v[0-9]' | head -1)
  43. if [ -z "$TAG" ]; then
  44. echo "Error: No version tag found for SHA $SHA"
  45. exit 1
  46. fi
  47. echo "TRIGGERED_TAG=$TAG" >> $GITHUB_ENV
  48. echo "Found tag: $TAG"
  49. - name: Determine Version Number
  50. id: version_number
  51. run: |
  52. if [ "${{ github.event_name }}" == "workflow_run" ]; then
  53. version=$TRIGGERED_TAG
  54. elif [ -n "${{ inputs.release_version }}" ]; then
  55. version=${{ inputs.release_version }}
  56. else
  57. version=""
  58. fi
  59. if [[ ${version:0:1} == "v" ]];
  60. then
  61. echo "RELEASE_VERSION=${version:1}" >> $GITHUB_OUTPUT
  62. else
  63. echo "RELEASE_VERSION=$version" >> $GITHUB_OUTPUT
  64. fi
  65. - name: Make Branch Name
  66. id: branch
  67. if: github.event_name != 'pull_request'
  68. env:
  69. RELEASE_VERSION: ${{ steps.version_number.outputs.RELEASE_VERSION }}
  70. run: |
  71. echo "BRANCH_NAME=v${RELEASE_VERSION%.*}" >> $GITHUB_OUTPUT
  72. - name: Checkout Repo
  73. if: github.event_name != 'workflow_run'
  74. uses: actions/checkout@v4
  75. with:
  76. ref: ${{ github.event_name != 'pull_request' && steps.branch.outputs.BRANCH_NAME || '' }}
  77. - name: Set OpenCost Image Tag
  78. id: image_tag
  79. if: github.event_name != 'pull_request'
  80. env:
  81. REPO_OWNER: ${{ github.repository_owner }}
  82. RELEASE_VERSION: ${{ steps.version_number.outputs.RELEASE_VERSION }}
  83. run: |
  84. echo "IMAGE_TAG=ghcr.io/$REPO_OWNER/opencost:$RELEASE_VERSION" >> $GITHUB_OUTPUT
  85. # Generate SBOM for source code
  86. - name: Generate SBOM for Source Code
  87. uses: anchore/sbom-action@v0
  88. with:
  89. path: .
  90. artifact-name: opencost-source-sbom.spdx.json
  91. output-file: opencost-source-sbom.spdx.json
  92. format: spdx-json
  93. # Generate SBOM for container image
  94. - name: Generate SBOM for Container Image
  95. if: github.event_name != 'pull_request'
  96. uses: anchore/sbom-action@v0
  97. with:
  98. image: ${{ steps.image_tag.outputs.IMAGE_TAG }}
  99. artifact-name: opencost-container-sbom.spdx.json
  100. output-file: opencost-container-sbom.spdx.json
  101. format: spdx-json
  102. # Generate CycloneDX format as well for broader compatibility
  103. - name: Generate CycloneDX SBOM for Source Code
  104. uses: anchore/sbom-action@v0
  105. with:
  106. path: .
  107. artifact-name: opencost-source-sbom.cyclonedx.json
  108. output-file: opencost-source-sbom.cyclonedx.json
  109. format: cyclonedx-json
  110. # Display SBOM contents on PRs for review
  111. - name: Display SBOM Contents
  112. if: github.event_name == 'pull_request'
  113. run: |
  114. echo "## SBOM Contents (SPDX Format)" >> $GITHUB_STEP_SUMMARY
  115. echo "" >> $GITHUB_STEP_SUMMARY
  116. echo "### Package Count" >> $GITHUB_STEP_SUMMARY
  117. PACKAGE_COUNT=$(jq '.packages | length' opencost-source-sbom.spdx.json)
  118. echo "Total packages: $PACKAGE_COUNT" >> $GITHUB_STEP_SUMMARY
  119. echo "" >> $GITHUB_STEP_SUMMARY
  120. echo "### Top-level Packages" >> $GITHUB_STEP_SUMMARY
  121. echo '```' >> $GITHUB_STEP_SUMMARY
  122. jq -r '.packages[] | select(.name != null) | "\(.name) - \(.versionInfo // "unknown")"' opencost-source-sbom.spdx.json | head -50 >> $GITHUB_STEP_SUMMARY
  123. echo '```' >> $GITHUB_STEP_SUMMARY
  124. echo "" >> $GITHUB_STEP_SUMMARY
  125. echo "<details>" >> $GITHUB_STEP_SUMMARY
  126. echo "<summary>Full SPDX SBOM (click to expand)</summary>" >> $GITHUB_STEP_SUMMARY
  127. echo "" >> $GITHUB_STEP_SUMMARY
  128. echo '```json' >> $GITHUB_STEP_SUMMARY
  129. cat opencost-source-sbom.spdx.json >> $GITHUB_STEP_SUMMARY
  130. echo '```' >> $GITHUB_STEP_SUMMARY
  131. echo "</details>" >> $GITHUB_STEP_SUMMARY
  132. - name: Generate CycloneDX SBOM for Container Image
  133. if: github.event_name != 'pull_request'
  134. uses: anchore/sbom-action@v0
  135. with:
  136. image: ${{ steps.image_tag.outputs.IMAGE_TAG }}
  137. artifact-name: opencost-container-sbom.cyclonedx.json
  138. output-file: opencost-container-sbom.cyclonedx.json
  139. format: cyclonedx-json
  140. # Publish SBOMs to GitHub release (only for releases, not PRs)
  141. - name: Attach SBOMs to GitHub Release
  142. if: github.event_name != 'pull_request'
  143. uses: anchore/sbom-action/publish-sbom@v0
  144. with:
  145. sbom-artifact-match: ".*\\.spdx\\.json$|.*\\.cyclonedx\\.json$"
  146. # Create a summary of the SBOM generation
  147. - name: Generate Summary
  148. run: |
  149. echo "## SBOM Generation Summary" >> $GITHUB_STEP_SUMMARY
  150. echo "" >> $GITHUB_STEP_SUMMARY
  151. echo "✅ Generated SBOMs for OpenCost ${{ steps.version_number.outputs.RELEASE_VERSION || 'PR build' }}" >> $GITHUB_STEP_SUMMARY
  152. echo "" >> $GITHUB_STEP_SUMMARY
  153. echo "### Generated Artifacts:" >> $GITHUB_STEP_SUMMARY
  154. echo "- Source Code SBOM (SPDX)" >> $GITHUB_STEP_SUMMARY
  155. echo "- Source Code SBOM (CycloneDX)" >> $GITHUB_STEP_SUMMARY
  156. if [ "${{ github.event_name }}" != "pull_request" ]; then
  157. echo "- Container Image SBOM (SPDX)" >> $GITHUB_STEP_SUMMARY
  158. echo "- Container Image SBOM (CycloneDX)" >> $GITHUB_STEP_SUMMARY
  159. fi
  160. echo "" >> $GITHUB_STEP_SUMMARY
  161. if [ "${{ github.event_name }}" != "pull_request" ]; then
  162. echo "📦 SBOMs have been attached to the GitHub release" >> $GITHUB_STEP_SUMMARY
  163. fi