Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ updates:
- package-ecosystem: gomod
directory: /
schedule:
interval: weekly
interval: monthly
groups:
minor:
update-types:
Expand All @@ -12,4 +12,4 @@ updates:
- package-ecosystem: github-actions
directory: /
schedule:
interval: weekly
interval: monthly
8 changes: 4 additions & 4 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@ name: Run CI
on:
workflow_dispatch:
push:
pull_request:
branches:
- "main"
tags:
- 'v*'
pull_request:

permissions:
contents: read
Expand All @@ -20,8 +22,6 @@ jobs:
name: gitctl
uses: ./.github/workflows/reusable-go-ci.yaml
with:
name: gitctl
module: .
run_build_image: true
run_tests: true
image_ref: "ghcr.io/bjoernkarma/gitctl"
ko_build_path: "main.go"
93 changes: 57 additions & 36 deletions .github/workflows/reusable-go-ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,25 @@ on:
description: "The Go module to process"
required: true
type: string
name:
description: "Name of the module for display purposes"
required: true
type: string
run_tests:
description: "Set to true to run unit tests and code coverage"
required: false
type: boolean
default: true
default: ${{ github.event_name == 'pull_request' || github.ref_name == 'main' }}
allow_tests_failure:
description: "Set to true to allow tests to fail without failing the job"
required: false
type: boolean
default: false
run_build_image:
description: "Set to true to build the container image using Ko"
required: false
type: boolean
default: true
default: ${{ github.event_name == 'pull_request' || github.ref_name == 'main' }}
ko_build_path:
description: "Path to the main package for ko build (e.g., cmd/main.go or ./cmd/server)"
required: false
Expand All @@ -26,17 +35,17 @@ on:
description: "Set to true to run govulncheck"
required: false
type: boolean
default: ${{ github.event_name == 'pull_request' }}
default: ${{ github.event_name == 'pull_request' || github.ref_name == 'main' }}
run_code_analysis:
description: "Set to true to run CodeQL analysis"
required: false
type: boolean
default: ${{ github.event_name == 'pull_request' }}
default: ${{ github.event_name == 'pull_request' || github.ref_name == 'main' }}
run_lint:
description: "Set to true to run golangci-lint"
required: false
type: boolean
default: ${{ github.event_name == 'pull_request' }}
default: ${{ github.event_name == 'pull_request' || github.ref_name == 'main' }}
github_repository:
description: "GitHub repository (owner/repo), e.g., github.repository. Required if run_build_image is true."
required: false
Expand All @@ -52,16 +61,11 @@ on:
required: false
type: string
default: "ghcr.io"
image_ref:
description: "Container image reference for Ko. If not provided, defaults to container_registry/github_repository/module."
required: false
type: string
default: ${{ inputs.container_registry }}/${{ inputs.github_repository }}/${{ inputs.module }}
image_tags:
description: "Comma-separated list of tags to apply to the built image. If empty, GITHUB_REF_SLUG will be used."
description: "Comma-separated list of tags to apply to the built image. If empty, GITHUB_HEAD_REF_SLUG or latest will be used."
required: false
type: string
default: ""
default: ${{ github.event_name == 'schedule' && 'nightly' || '' }}

outputs:
image_digest:
Expand All @@ -70,8 +74,8 @@ on:

jobs:
static_checks:
name: "Static Checks for ${{ inputs.module }}"
if: ${{ inputs.run_lint }}
name: "Static Checks for ${{ inputs.name }}"
if: ${{ inputs.run_lint || inputs.run_check_generated_files }}
runs-on: ubuntu-latest
steps:
- name: Checkout Code
Expand Down Expand Up @@ -104,7 +108,7 @@ jobs:
args: --timeout 5m --issues-exit-code=0 --config .golangci.yml

tests:
name: "Tests & Coverage for ${{ inputs.module }}"
name: "Tests & Coverage for ${{ inputs.name }}"
if: ${{ inputs.run_tests }}
runs-on: ubuntu-latest
outputs:
Expand Down Expand Up @@ -133,6 +137,8 @@ jobs:

- name: Set up gotestfmt
uses: gotesttools/gotestfmt-action@v2
with:
token: ${{ secrets.GITHUB_TOKEN }}

- name: Build
shell: bash
Expand All @@ -142,6 +148,7 @@ jobs:
- name: Run Tests
shell: bash
working-directory: ${{ inputs.module }}
continue-on-error: ${{ inputs.allow_tests_failure }}
run: |
set -euo pipefail
go test -coverprofile cover.out -json -v ./... 2>&1 | tee gotest.log | gotestfmt
Expand All @@ -162,7 +169,7 @@ jobs:
if: ${{ always() }} # Upload even if previous steps fail
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # pin@v6.0.0
with:
name: ${{ inputs.module }}-gotest.log
name: ${{ inputs.name }}-gotest.log
path: ${{ inputs.module }}/gotest.log
if-no-files-found: error

Expand All @@ -171,7 +178,7 @@ jobs:
if: ${{ always() }} # Upload even if previous steps fail
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # pin@v6.0.0
with:
name: ${{ inputs.module }}-test-report
name: ${{ inputs.name }}-test-report
path: |
${{ inputs.module }}/cover.out
${{ inputs.module }}/coverage.html
Expand All @@ -183,7 +190,7 @@ jobs:
uses: mikepenz/action-junit-report@v6
with:
report_paths: "${{ inputs.module }}/junit.xml"
check_name: "Test Report (${{ inputs.module }})"
check_name: "Test Report (${{ inputs.name }})"
comment: true
include_passed: true

Expand All @@ -204,14 +211,14 @@ jobs:
if: ${{ always() && (github.event_name == 'pull_request') }}
uses: marocchino/sticky-pull-request-comment@v2
with:
header: module-coverage-${{ inputs.module }}
header: module-coverage-${{ inputs.name }}
message: |
**Coverage for ${{ inputs.module }}**
**Coverage for ${{ inputs.name }}**
${{ steps.prepare_coverage_comment_step.outputs.markdown }}
Download the latest HTML coverage report for ${{ inputs.module }} [here](${{ github.server_url }}/${{ inputs.github_repository }}/actions/runs/${{ github.run_id }}/artifacts/${{ steps.upload_test_reports_artifact_step.outputs.artifact-id }}).
Download the latest HTML coverage report for ${{ inputs.name }} [here](${{ github.server_url }}/${{ inputs.github_repository }}/actions/runs/${{ github.run_id }}/artifacts/${{ steps.upload_test_reports_artifact_step.outputs.artifact-id }}).

source_scan:
name: "Source Vulnerability Scan for ${{ inputs.module }}"
name: "Source Vulnerability Scan for ${{ inputs.name }}"
if: ${{ inputs.run_vulnerability_check }}
runs-on: ubuntu-latest
steps:
Expand Down Expand Up @@ -244,7 +251,7 @@ jobs:
work-dir: ${{ inputs.module }}

codeql:
name: "CodeQL Analysis for ${{ inputs.module }}"
name: "CodeQL Analysis for ${{ inputs.name }}"
if: ${{ inputs.run_code_analysis }}
runs-on: ubuntu-latest
steps:
Expand Down Expand Up @@ -279,24 +286,24 @@ jobs:
shell: bash
working-directory: ${{ inputs.module }}
run: |
echo "Attempting to build ${{ inputs.module }} for CodeQL analysis..."
if [ -f Makefile ] && grep -q -E "^build[:[:space:]]" Makefile; then
echo "Found Makefile with build target. Running make build..."
make build
elif [ -f go.mod ]; then
echo "Attempting to build ${{ inputs.name }} for CodeQL analysis..."
if [ -f go.mod ]; then
echo "Found go.mod. Running go build ./..."
go build ./...
elif [ -f Makefile ] && grep -q -E "^build[:[:space:]]" Makefile; then
echo "Found Makefile with build target. Running make build..."
make build
else
echo "WARNING: No Makefile with a 'build' target or go.mod found in ${{ inputs.module }}. CodeQL may not analyze effectively."
echo "WARNING: No Makefile with a 'build' target or go.mod found in ${{ inputs.name }}. CodeQL may not analyze effectively."
fi

- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@f443b600d91635bebf5b0d9ebc620189c0d6fba5 # pinv4.30.8
with:
category: "/language:go"
category: "/language:go/${{ inputs.name }}"

build:
name: "Build Image for ${{ inputs.module }}"
name: "Build Image for ${{ inputs.name }}"
if: ${{ inputs.run_build_image && (needs.static_checks.result != 'failure') && (needs.tests.result != 'failure') }}
needs: [tests]
runs-on: ubuntu-latest
Expand Down Expand Up @@ -335,38 +342,52 @@ jobs:
shell: bash
working-directory: ${{ inputs.module }}
env:
KO_DOCKER_REPO: ${{ inputs.image_ref }}
KO_CONFIG_PATH: ${{ github.workspace }}/.ko.yaml
run: |
if [ -z "${{ inputs.github_repository }}" ] || [ -z "${{ inputs.github_ref }}" ]; then
echo "Error: github_repository and github_ref inputs are required when run_build_image is true."
exit 1
fi

# Convert repository name to lowercase for registry
REPO_LOWER=$(echo "${{ inputs.github_repository }}" | tr '[:upper:]' '[:lower:]')
export KO_DOCKER_REPO="${{ inputs.container_registry }}/${REPO_LOWER}"

effective_tags=""
if [ -n "${{ inputs.image_tags }}" ]; then
effective_tags="${{ inputs.image_tags }}"
else
effective_tags="${GITHUB_REF_SLUG}"
effective_tags="${GITHUB_HEAD_REF_SLUG:-latest}"
fi

echo "Building with tags: $effective_tags"
echo "Using KO_DOCKER_REPO: ${KO_DOCKER_REPO}"
export VERSION=$(git describe --tags --always --dirty || echo 'develop')
export BUILD_TIME=$(date -u +"%Y-%m-%dT%H:%M:%SZ")

output=$(ko build ${{ inputs.ko_build_path }} --bare --tags "$effective_tags")
echo "Ko output: $output"
digest=$(echo "$output" | grep -o 'sha256:[a-f0-9]\{64\}')
echo "digest=$digest" >> $GITHUB_OUTPUT
echo "image_ref=${KO_DOCKER_REPO}@${digest}" >> $GITHUB_OUTPUT

image_scan:
name: "Image Vulnerability Scan for ${{ inputs.module }}"
name: "Image Vulnerability Scan for ${{ inputs.name }}"
if: ${{ inputs.run_build_image && needs.build.result == 'success' }}
needs: [build]
runs-on: ubuntu-latest
steps:
# No checkout or Go setup needed if only running Trivy on a remote image
- name: Convert repository name to lowercase
id: repo_lower
shell: bash
run: |
REPO_LOWER=$(echo "${{ inputs.github_repository }}" | tr '[:upper:]' '[:lower:]')
echo "repo=${REPO_LOWER}" >> $GITHUB_OUTPUT

- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@0.33.1
with:
image-ref: ${{ inputs.image_ref }}@${{ needs.build.outputs.image_digest }}
image-ref: ${{ inputs.container_registry }}/${{ steps.repo_lower.outputs.repo }}@${{ needs.build.outputs.image_digest }}
exit-code: "1"
vuln-type: "os,library"
severity: "CRITICAL,HIGH"
Loading