Skip to content

Commit

Permalink
Merge branch 'main' into ROCKS-973/allow-expired-eol-values
Browse files Browse the repository at this point in the history
  • Loading branch information
linostar committed Sep 17, 2024
2 parents f04fa27 + cd77b32 commit 6ff5357
Show file tree
Hide file tree
Showing 13 changed files with 237 additions and 17 deletions.
38 changes: 38 additions & 0 deletions .github/actions/validate-actor/action.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
name: Validate Access
description: 'Check if the workflow is triggered by an admin user'

# This callable workflow checks if the workflow is triggered by
# a code owner or an image maintainer by testing the github.actor
# variable against the CODEOWNERS file and the contacts.yaml file
# under oci/* path

inputs:
admin-only:
description: 'The protected workflow should only be triggered as a code owner or an image maintainer'
required: true
default: 'false'
image-path:
description: 'The path to the image to be built'
required: true
github-token:
description: 'The GITHUB_TOKEN for the GitHub CLI'
required: true

runs:
using: "composite"
steps:
- name: Check if the workflow is triggered by an admin user
id: check-if-permitted
shell: bash
env:
GITHUB_TOKEN: ${{ inputs.github-token }}
run: ./.github/actions/validate-actor/validate-actor.sh ${{ github.actor }} ${{ inputs.admin-only }} ${{ github.workspace }} ${{ inputs.image-path }}

- name: Cancel the remaining workflow if the actor is not permitted
if: ${{ !cancelled() && steps.check-if-permitted.outcome == 'failure' }}
shell: bash
env:
GITHUB_TOKEN: ${{ github.token }}
run: |
echo "The workflow is not triggered by a permitted user. Cancelling the workflow."
gh run cancel ${{ github.run_id }}
46 changes: 46 additions & 0 deletions .github/actions/validate-actor/test-validate-actor.bats
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#!/usr/bin/env bats

SOURCE_DIR=$(dirname -- "${BASH_SOURCE[0]}")

setup() {
workdir=$(mktemp -d)
mkdir -p $workdir/img
echo -n "* @code-owner" > $workdir/CODEOWNERS
echo -e "maintainers:\n - maintainer" > $workdir/img/contacts.yaml
}

@test "blocks non-code-owner-non-maintainer user" {
{
output=$(${BATS_TEST_DIRNAME}/validate-actor.sh "random" "true" $workdir "img" 2>&1)
exit_status=$?
} || true
[[ $exit_status -eq 1 ]]
[[ $(echo "${output}"| tail -n 1) = "The workflow is triggered by a user neither as a code owner nor a maintainer of the image img" ]]
}

@test "allows code owner" {
output=$(${BATS_TEST_DIRNAME}/validate-actor.sh "code-owner" "true" $workdir "img" 2>&1)
[[ $(echo "${output}"| tail -n 1) = "The workflow is triggered by code-owner as the code owner" ]]
}

@test "allows image maintainer" {
output=$(${BATS_TEST_DIRNAME}/validate-actor.sh "maintainer" "true" $workdir "img")
[[ $(echo "${output}"| tail -n 1) = "The workflow is triggered by maintainer as a maintainer of the image img" ]]
}

@test "allows non-code-owner-non-maintainer user" {
output=$(${BATS_TEST_DIRNAME}/validate-actor.sh "random" "false" $workdir "img")
[[ $(echo "${output}"| tail -n 1) = "The workflow is not restricted to non-code-owner or non-maintainer users" ]]
}

@test "user as both code-owner and maintainer is triggered as code owner" {
echo -n " @maintainer" >> $workdir/CODEOWNERS
output=$(${BATS_TEST_DIRNAME}/validate-actor.sh "maintainer" "true" $workdir "img")
[[ $(echo "${output}"| tail -n 1) = "The workflow is triggered by maintainer as the code owner" ]]
}

@test "teams are expanded to team members" {
echo -n "@canonical/rocks" >> $workdir/CODEOWNERS
output=$(${BATS_TEST_DIRNAME}/validate-actor.sh "ROCKsBot" "true" $workdir "img")
[[ $(echo "${output}"| tail -n 1) = "The workflow is triggered by ROCKsBot as the code owner" ]]
}
36 changes: 36 additions & 0 deletions .github/actions/validate-actor/validate-actor.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#!/bin/bash -e

actor=$1
admin_only=$2
workspace=$3
image_path=$4

echo "github.actor: ${actor}"
echo "admin-only: ${admin_only}"
if [[ ${admin_only} == true ]]; then
exit_status=0
echo "Expanding team mentions in the CODEOWNERS file"
cp ${workspace}/CODEOWNERS ${workspace}/CODEOWNERS.bak
teams=$(grep -oE '@[[:alnum:]_.-]+\/[[:alnum:]_.-]+' ${workspace}/CODEOWNERS || true | sort | uniq)

for team in ${teams}; do
org=$(echo ${team} | cut -d'/' -f1 | sed 's/@//')
team_name=$(echo ${team} | cut -d'/' -f2)
members=$(gh api "/orgs/${org}/teams/${team_name}/members" | jq -r '.[].login')
replacement=$(echo "${members}" | xargs -I {} echo -n "@{} " | awk '{$1=$1};1')
sed -i "s|${team}|${replacement}|g" ${workspace}/CODEOWNERS
done

if grep -wq "@${actor}" ${workspace}/CODEOWNERS; then
echo "The workflow is triggered by ${actor} as the code owner"
elif cat ${workspace}/${image_path}/contacts.yaml | yq ".maintainers" | grep "\- " | grep -wq "${actor}"; then
echo "The workflow is triggered by ${actor} as a maintainer of the image ${image_path}"
else
echo "The workflow is triggered by a user neither as a code owner nor a maintainer of the image ${image_path}"
exit_status=1
fi
mv ${workspace}/CODEOWNERS.bak ${workspace}/CODEOWNERS
exit ${exit_status}
else
echo "The workflow is not restricted to non-code-owner or non-maintainer users"
fi
8 changes: 8 additions & 0 deletions .github/workflows/Announcements.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,14 @@ jobs:
fi
done
- name: Validate access to triggered image
uses: ./.github/actions/validate-actor
if: ${{ github.repository == 'canonical/oci-factory' }}
with:
admin-only: true
image-path: "oci/${{ steps.get-image-name.outputs.img-name }}"
github-token: ${{ secrets.ROCKSBOT_TOKEN }}

- name: Get contacts for ${{ steps.get-image-name.outputs.img-name }}
id: get-contacts
working-directory: oci/${{ steps.get-image-name.outputs.img-name }}
Expand Down
10 changes: 10 additions & 0 deletions .github/workflows/Build-Rock.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,17 @@ jobs:
if: ${{ steps.clone-image-repo.outcome == 'failure' }}
run: |
git clone ${{ inputs.rock-repo }} .
- name: Validate access to triggered image
uses: ./.github/actions/validate-actor
if: ${{ github.repository == 'canonical/oci-factory' }}
with:
admin-only: true
image-path: ${{ inputs.oci-factory-path }}
github-token: ${{ secrets.ROCKSBOT_TOKEN }}

- run: git checkout ${{ inputs.rock-repo-commit }}

- run: sudo snap install yq --channel=v4/stable
- name: Validate image naming and base
working-directory: ${{ inputs.rockfile-directory }}
Expand Down
12 changes: 11 additions & 1 deletion .github/workflows/Documentation.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ on:
push:
paths:
- "oci/*/documentation.y*ml"
branches:
- main
workflow_dispatch:
inputs:
oci-image-name:
Expand Down Expand Up @@ -40,6 +42,14 @@ jobs:

- uses: actions/checkout@v4

- name: Validate access to triggered image
uses: ./.github/actions/validate-actor
if: ${{ github.repository == 'canonical/oci-factory' }}
with:
admin-only: true
image-path: "oci/${{ inputs.oci-image-name }}"
github-token: ${{ secrets.ROCKSBOT_TOKEN }}

- name: Infer images to document
uses: tj-actions/changed-files@v35
id: changed-files
Expand Down Expand Up @@ -149,7 +159,7 @@ jobs:
runs-on: ubuntu-22.04
name: Notify on failure
needs: [validate-documentation-request, do-documentation]
if: ${{ always() && contains(needs.*.result, 'failure') && github.event_name != 'workflow_dispatch' }}
if: ${{ !cancelled() && contains(needs.*.result, 'failure') && github.event_name != 'workflow_dispatch' }}
steps:
- uses: actions/checkout@v4

Expand Down
12 changes: 10 additions & 2 deletions .github/workflows/Image.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,14 @@ jobs:
echo "img-name=$(basename ${img_path})" >> "$GITHUB_OUTPUT"
echo "img-path=${img_path}" >> "$GITHUB_OUTPUT"
- name: Validate access to triggered image
uses: ./.github/actions/validate-actor
if: ${{ github.repository == 'canonical/oci-factory' }}
with:
admin-only: true
image-path: ${{ steps.validate-image.outputs.img-path }}
github-token: ${{ secrets.ROCKSBOT_TOKEN }}

- name: Use custom image trigger
if: ${{ inputs.b64-image-trigger != '' }}
run: echo ${{ inputs.b64-image-trigger }} | base64 -d > ${{ steps.validate-image.outputs.img-path }}/image.yaml
Expand All @@ -113,7 +121,7 @@ jobs:
./src/image/prepare_single_image_build_matrix.py \
--oci-path ${{ steps.validate-image.outputs.img-path }} \
--revision-data-dir ${{ env.DATA_DIR }} \
--revision-data-dir ${{ env.DATA_DIR }}
run-build:
needs: [prepare-build]
Expand Down Expand Up @@ -568,7 +576,7 @@ jobs:
runs-on: ubuntu-22.04
name: Notify
needs: [prepare-build, run-build, upload, prepare-releases, generate-provenance]
if: ${{ always() && contains(needs.*.result, 'failure') && github.event_name != 'pull_request' }}
if: ${{ !cancelled() && contains(needs.*.result, 'failure') && github.event_name != 'pull_request' }}
steps:
- uses: actions/checkout@v4

Expand Down
8 changes: 8 additions & 0 deletions .github/workflows/Release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,14 @@ jobs:

- uses: actions/checkout@v4

- name: Validate access to triggered image
uses: ./.github/actions/validate-actor
if: ${{ github.repository == 'canonical/oci-factory' }}
with:
admin-only: true
image-path: "oci/${{ inputs.oci-image-name }}"
github-token: ${{ secrets.ROCKSBOT_TOKEN }}

- name: Infer number of image triggers
uses: tj-actions/changed-files@v35
id: changed-files
Expand Down
13 changes: 13 additions & 0 deletions .github/workflows/Tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,22 @@ env:
DIVE_IMAGE: 'wagoodman/dive:v0.12'

jobs:
access-check:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- name: Validate access to triggered image
uses: ./.github/actions/validate-actor
if: ${{ github.repository == 'canonical/oci-factory' }}
with:
admin-only: true
image-path: ${{ inputs.oci-image-path }}
github-token: ${{ secrets.ROCKSBOT_TOKEN }}

fetch-oci-image:
runs-on: ubuntu-22.04
name: Fetch OCI image for testing
needs: [access-check]
outputs:
test-cache-key: ${{ steps.cache.outputs.key }}
steps:
Expand Down
16 changes: 12 additions & 4 deletions .github/workflows/Vulnerability-Scan.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,14 @@ jobs:
steps:
- uses: actions/checkout@v4

- name: Validate access to triggered image
uses: ./.github/actions/validate-actor
if: ${{ github.repository == 'canonical/oci-factory' }}
with:
admin-only: true
image-path: ${{ inputs.oci-image-path }}
github-token: ${{ secrets.ROCKSBOT_TOKEN }}

- id: vulnerability-report
run: |
full_name="${{ inputs.oci-image-name }}${{ inputs.vulnerability-report-suffix }}"
Expand Down Expand Up @@ -104,7 +112,7 @@ jobs:
image-ref: '${{ steps.to-docker-daemon.outputs.name }}'

- name: Process report
if: ${{ always() }}
if: ${{ !cancelled() }}
id: check-report
run: |
report="${{ steps.vulnerability-report.outputs.name }}"
Expand Down Expand Up @@ -134,13 +142,13 @@ jobs:
done
- uses: actions/cache/save@v4
if: ${{ always() }}
if: ${{ !cancelled() }}
with:
path: ${{ steps.vulnerability-report.outputs.name }}
key: ${{ github.run_id }}-${{ steps.vulnerability-report.outputs.name }}

- uses: actions/upload-artifact@v4
if: ${{ always() }}
if: ${{ !cancelled() }}
with:
name: ${{ steps.vulnerability-report.outputs.name }}
path: ${{ steps.vulnerability-report.outputs.name }}
Expand All @@ -153,7 +161,7 @@ jobs:
name: Notify on failure
needs:
- test-vulnerabilities
if: ${{ always() && needs.test-vulnerabilities.outputs.notify == 'true' }}
if: ${{ !cancelled() && needs.test-vulnerabilities.outputs.notify == 'true' }}
steps:
- uses: actions/checkout@v4

Expand Down
34 changes: 34 additions & 0 deletions .github/workflows/_Test-OCI-Factory.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ on:
push:
paths:
- ".github/workflows/*"
- ".github/actions/**"
- "!.github/workflows/CLA-Check.yaml"
- "!.github/workflows/PR-Validator.yaml"
- "!.github/workflows/_Auto-updates.yaml"
Expand All @@ -25,6 +26,16 @@ env:


jobs:
access-check:
name: Validate access to mock-rock
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/validate-actor
with:
admin-only: true
image-path: "oci/mock-rock"
github-token: ${{ secrets.ROCKSBOT_TOKEN }}

pytest:
# Trigger python unit tests across the repository
Expand Down Expand Up @@ -64,8 +75,31 @@ jobs:
path: ${{ env.PYTEST_RESULT_PATH }}
if-no-files-found: error

bats-test:
# Trigger bash unit tests across the repository
name: bats
runs-on: ubuntu-22.04
steps:

# Job Setup
- uses: actions/checkout@v4
with:
fetch-depth: 1

- name: Install bats
run: |
sudo apt-get update
sudo apt-get install -y bats
- name: Run bats
env:
GITHUB_TOKEN: ${{ secrets.ROCKSBOT_TOKEN }}
run: |
find ${{ github.workspace }} -name 'test-*.bats' | xargs bats
test-workflows:
name: Trigger internal tests for mock-rock
needs: [access-check]
uses: ./.github/workflows/Image.yaml
with:
oci-image-name: "mock-rock"
Expand Down
1 change: 1 addition & 0 deletions CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* @canonical/rocks
Loading

0 comments on commit 6ff5357

Please sign in to comment.