Skip to content

Commit

Permalink
feat(ci): add image scanning workflow (ublue-os#1161)
Browse files Browse the repository at this point in the history
  • Loading branch information
p5 authored Apr 21, 2024
1 parent 609dd0e commit 2d9128b
Show file tree
Hide file tree
Showing 6 changed files with 182 additions and 15 deletions.
5 changes: 5 additions & 0 deletions .github/syft.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Exclude some files Syft will never get anything useful from
exclude:
- '/sysroot/ostree/repo/objects/**'
- '/usr/share/icons/**'
- '/usr/share/doc/**'
14 changes: 12 additions & 2 deletions .github/workflows/build-38-bluefin.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ on:
- '**.md'
- 'system_files/kinoite/**'
schedule:
- cron: '42 16 * * *' # 16:42 UTC everyday
- cron: '42 16 * * *' # 16:42 UTC everyday
workflow_dispatch:

jobs:
Expand All @@ -19,4 +19,14 @@ jobs:
secrets: inherit
with:
brand_name: bluefin
fedora_version: 38
fedora_version: 38

scan:
# Scan can still be ran when some builds fail since only successfully built
# images will be stored in the output
if: github.event_name != 'pull_request' && always()
uses: ./.github/workflows/reusable-image-scan.yml
needs: build
secrets: inherit
with:
images: ${{ needs.build.outputs.images }}
12 changes: 11 additions & 1 deletion .github/workflows/build-39-bluefin.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,14 @@ jobs:
secrets: inherit
with:
brand_name: bluefin
fedora_version: 39
fedora_version: 39

scan:
# Scan can still be ran when some builds fail since only successfully built
# images will be stored in the output
if: github.event_name != 'pull_request' && always()
uses: ./.github/workflows/reusable-image-scan.yml
needs: build
secrets: inherit
with:
images: ${{ needs.build.outputs.images }}
12 changes: 11 additions & 1 deletion .github/workflows/build-40-bluefin.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,14 @@ jobs:
secrets: inherit
with:
brand_name: bluefin
fedora_version: 40
fedora_version: 40

scan:
# Scan can still be ran when some builds fail since only successfully built
# images will be stored in the output
if: github.event_name != 'pull_request' && always()
uses: ./.github/workflows/reusable-image-scan.yml
needs: build
secrets: inherit
with:
images: ${{ needs.build.outputs.images }}
81 changes: 70 additions & 11 deletions .github/workflows/reusable-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ on:
description: "'aurora' or 'bluefin'"
required: true
type: string
outputs:
images:
description: 'An array of images built and pushed to the registry'
value: ${{ jobs.check.outputs.images }}
env:
IMAGE_REGISTRY: ghcr.io/${{ github.repository_owner }}

Expand All @@ -22,6 +26,8 @@ jobs:
name: image
runs-on: ubuntu-latest
continue-on-error: false
outputs:
image_full: ${{ steps.generate-outputs.outputs.image }}
strategy:
fail-fast: false
matrix:
Expand Down Expand Up @@ -262,24 +268,77 @@ jobs:
COSIGN_EXPERIMENTAL: false
COSIGN_PRIVATE_KEY: ${{ secrets.SIGNING_SECRET }}

- name: Echo outputs
- name: Generate file containing outputs
if: github.event_name != 'pull_request'
run: |
echo "${{ toJSON(steps.push.outputs) }}"
env:
DIGEST: ${{ steps.push.outputs.digest }}
IMAGE_REGISTRY: ${{ env.IMAGE_REGISTRY }}/${{ env.IMAGE_NAME }}
IMAGE_NAME: ${{ env.IMAGE_NAME }}
IMAGE_FLAVOR: ${{ matrix.image_flavor }}
FEDORA_VERSION: ${{ matrix.fedora_version }}
run:
echo "${IMAGE_REGISTRY}@${DIGEST}" > "${IMAGE_NAME}-${IMAGE_FLAVOR}-${FEDORA_VERSION}.txt"

- name: Upload artifact
if: github.event_name != 'pull_request'
uses: actions/upload-artifact@v4
with:
name: image-${{ env.IMAGE_NAME }}-${{ matrix.image_flavor }}-${{ matrix.fedora_version }}
retention-days: 1
if-no-files-found: error
path: |
${{ env.IMAGE_NAME }}-${{ matrix.image_flavor }}-${{ matrix.fedora_version }}.txt
check:
name: Check all ${{ inputs.brand_name }} ${{ inputs.fedora_version }} builds successful
if: ${{ !cancelled() }}
if: always()
runs-on: ubuntu-latest
needs: [build_container]
outputs:
images: ${{ steps.generate-outputs.outputs.images }}
steps:
- name: Exit on failure
if: ${{ needs.build_container.result == 'failure' }}
shell: bash
run: exit 1
- name: Exit
shell: bash
run: exit 0
- name: Download artifacts
if: github.event_name != 'pull_request'
id: download-artifacts
uses: actions/download-artifact@v4
with:
pattern: image-*
merge-multiple: true

- name: Create output
if: github.event_name != 'pull_request'
id: generate-outputs
env:
JOBS: ${{ toJson(needs) }}
ARTIFACT_PATH: ${{ steps.download-artifacts.outputs.download-path }}
run: |
# Initialize the array
images=()
# Populate the array with each line from each file in the artifacts directory
for file in $ARTIFACT_PATH/*; do
while IFS= read -r line; do
images+=("$line")
done < "$file"
done
# Create the GITHUB_OUTPUT in the format '["image1", "image2", ...]'
echo "images=$(printf '%s\n' "${images[@]}" | jq -R -s -c 'split("\n") | .[:-1]')" >> $GITHUB_OUTPUT
- name: Check Jobs
env:
JOBS: ${{ toJson(needs) }}
run: |
echo "Job status:"
echo $JOBS | jq -r 'to_entries[] | " - \(.key): \(.value.result)"'
for i in $(echo $JOBS | jq -r 'to_entries[] | .value.result'); do
if [ "$i" != "success" ] && [ "$i" != "skipped" ]; then
echo ""
echo "Status check not okay!"
exit 1
fi
done
build_iso:
name: iso
Expand Down
73 changes: 73 additions & 0 deletions .github/workflows/reusable-image-scan.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
name: Scan Image
on:
workflow_call:
inputs:
images:
description: "A comma-separated list of images to scan. E.G. '[\"docker.io/library/alpine:3.14.0\", \"docker.io/library/alpine:3.13.6\"]'"
required: true
type: string

jobs:
generate-matrix:
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.set-matrix.outputs.matrix }}
steps:
- name: Set matrix
id: set-matrix
env:
IMAGES: ${{ inputs.images }}
run: |
echo "matrix=$IMAGES" >> $GITHUB_OUTPUT
scan-image:
needs: generate-matrix
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
image: ${{fromJson(needs.generate-matrix.outputs.matrix)}}
steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Maximize build space
uses: ublue-os/remove-unwanted-software@v6

- name: Install Syft
shell: bash
run: |
curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b /usr/local/bin
syft version
- name: Generate SBOM
env:
IMAGE: ${{ matrix.image }}
run: |
syft ${IMAGE} \
--output cyclonedx-json=sbom.json \
--config ./.github/syft.yml
- name: Scan SBOM
id: scan
uses: anchore/scan-action@3343887d815d7b07465f6fdcd395bd66508d486a # v3
with:
sbom: sbom.json
output-format: json
fail-build: false

- name: Generate artifact name
id: artifact-name
env:
IMAGE: ${{ matrix.image }}
run: |
echo "name=$(echo ${IMAGE} | awk -F'/' '{print $NF}' | sed 's/:/-/g')" >> $GITHUB_OUTPUT
- name: Upload scan results
uses: actions/upload-artifact@v4
with:
name: security-${{ steps.artifact-name.outputs.name }}
if-no-files-found: error
path: |
sbom.json
${{ steps.scan.outputs.json }}

0 comments on commit 2d9128b

Please sign in to comment.