From 9f016dbb291853c8927370eb7b36febcd60ef8b8 Mon Sep 17 00:00:00 2001 From: Paolo Dettori Date: Fri, 13 Mar 2026 14:43:53 -0400 Subject: [PATCH 1/2] feat: add dependabot, scorecard, container build CI, and CI timeout Complete CI baseline for the repo: - .github/dependabot.yml: weekly updates for GitHub Actions, Python dependencies (root + nemocheck plugin), and Docker base image - .github/workflows/scorecard.yml: OpenSSF Scorecard on push to main and weekly schedule; publishes results to GitHub Security tab - .github/workflows/build.yml: multi-arch (amd64+arm64) container image build and push to ghcr.io on tag push or manual trigger; supports optional PLUGIN_DEPS build-arg for baking in specific plugins - .github/workflows/ci.yaml: add timeout-minutes: 15 to prevent hung jobs All actions SHA-pinned (no tag-only references). Assisted-By: Claude (Anthropic AI) Signed-off-by: Paolo Dettori --- .github/dependabot.yml | 64 +++++++++++++++++++++ .github/workflows/build.yml | 99 +++++++++++++++++++++++++++++++++ .github/workflows/ci.yaml | 1 + .github/workflows/scorecard.yml | 68 ++++++++++++++++++++++ 4 files changed, 232 insertions(+) create mode 100644 .github/dependabot.yml create mode 100644 .github/workflows/build.yml create mode 100644 .github/workflows/scorecard.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..1d952c8 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,64 @@ +# Dependabot - Automated dependency updates +# +# Keeps GitHub Actions, Python (pip/uv), and Docker base images up to date. +# Weekly schedule avoids noisy daily PRs while staying current. +# +# Reference: https://docs.github.com/en/code-security/dependabot/dependabot-version-updates +# +version: 2 +updates: + # GitHub Actions - keep workflow action SHAs current + - package-ecosystem: github-actions + directory: / + schedule: + interval: weekly + day: monday + time: "06:00" + reviewers: + - kagenti/maintainers + labels: + - dependencies + - github-actions + + # Python dependencies (root pyproject.toml) + - package-ecosystem: pip + directory: / + schedule: + interval: weekly + day: monday + time: "06:30" + reviewers: + - kagenti/maintainers + labels: + - dependencies + - python + # Limit open PRs to avoid noise; security updates bypass this limit + open-pull-requests-limit: 5 + + # Python dependencies (nemocheck plugin) + - package-ecosystem: pip + directory: /plugins/examples/nemocheck + schedule: + interval: weekly + day: monday + time: "07:00" + reviewers: + - kagenti/maintainers + labels: + - dependencies + - python + - plugins + open-pull-requests-limit: 3 + + # Docker base image (root Dockerfile) + - package-ecosystem: docker + directory: / + schedule: + interval: weekly + day: monday + time: "07:30" + reviewers: + - kagenti/maintainers + labels: + - dependencies + - docker diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..79dab22 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,99 @@ +# Build and Publish - Container image release workflow +# +# Builds and pushes the plugins-adapter container image to GHCR on: +# - Tag push (v*) for versioned releases +# - Manual trigger for on-demand testing +# +# Image: ghcr.io/kagenti/plugins-adapter/plugins-adapter: +# +# Multi-arch: amd64 + arm64 via QEMU emulation. +# Base plugin: no PLUGIN_DEPS baked in — consumers install plugins at deploy time. +# To build with a specific plugin, trigger manually and set PLUGIN_DEPS input. +# +# Usage: +# Tag release: git tag v1.2.3 && git push origin v1.2.3 +# Manual build: Actions → Build and Publish → Run workflow +# +name: Build and Publish + +on: + push: + tags: + - 'v*' + workflow_dispatch: + inputs: + plugin_deps: + description: 'Comma-separated plugin names to bake in (e.g. nemocheck). Leave empty for base image.' + required: false + default: '' + type: string + +# Deny all permissions at workflow level; each job declares only what it needs +permissions: {} + +env: + REGISTRY: ghcr.io + IMAGE_NAME: ${{ github.repository }} + +jobs: + build-and-push: + name: Build and Push Image + runs-on: ubuntu-latest + timeout-minutes: 30 + permissions: + contents: read + packages: write + + steps: + - name: Checkout repository + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + + - name: Set up QEMU (multi-arch support) + uses: docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a # v4.0.0 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0 + + - name: Log in to ghcr.io + uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4.0.0 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract Docker metadata + id: meta + uses: docker/metadata-action@030e881283bb7a6894de51c315a6bfe6a94e05cf # v6.0.0 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + tags: | + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + type=sha,format=short + type=raw,value=latest,enable=${{ github.ref_type == 'tag' }} + + - name: Determine PLUGIN_DEPS + id: plugin-deps + run: | + # Use manual input if provided, otherwise empty (base image) + DEPS="${{ github.event.inputs.plugin_deps }}" + echo "plugin_deps=${DEPS}" >> "$GITHUB_OUTPUT" + if [ -n "$DEPS" ]; then + echo "Building with plugins: $DEPS" + else + echo "Building base image (no plugins baked in)" + fi + + - name: Build and push + uses: docker/build-push-action@d08e5c354a6adb9ed34480a06d141179aa583294 # v7.0.0 + with: + context: . + file: ./Dockerfile + platforms: linux/amd64,linux/arm64 + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + build-args: | + PLUGIN_DEPS=${{ steps.plugin-deps.outputs.plugin_deps }} + cache-from: type=gha + cache-to: type=gha,mode=max diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index cd1ab1d..8492e05 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -12,6 +12,7 @@ permissions: jobs: build: runs-on: ubuntu-latest + timeout-minutes: 15 strategy: matrix: diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml new file mode 100644 index 0000000..a4be434 --- /dev/null +++ b/.github/workflows/scorecard.yml @@ -0,0 +1,68 @@ +# OpenSSF Scorecard - Security health metrics for Open Source +# +# Measures repository security posture across 18+ checks: +# token permissions, branch protection, dependency update tools, +# fuzzing, SAST, vulnerabilities, and more. +# +# Results are uploaded to the GitHub Security tab and OpenSSF Scorecard API. +# View badge at: https://api.securityscorecards.dev/projects/github.com/kagenti/plugins-adapter +# +# NOTE: Scorecard only works on 'schedule' and 'push' triggers, NOT 'pull_request' +# This is a GitHub/Scorecard limitation for result publishing. +# See: https://github.com/ossf/scorecard-action#workflow-restrictions +# +# Token Requirements: +# - id-token: write for OIDC verification when publishing results +# - security-events: write to upload SARIF to Security tab +# +name: OpenSSF Scorecard + +on: + # Run weekly on Monday at 6:30 AM UTC (offset from kagenti/kagenti to spread load) + schedule: + - cron: '30 6 * * 1' + # Run on push to main to track regressions immediately + push: + branches: [main] + # Allow manual trigger + workflow_dispatch: + +# Deny all permissions at workflow level; each job declares only what it needs +# Required by Scorecard: https://github.com/ossf/scorecard-action#workflow-restrictions +permissions: {} + +jobs: + scorecard: + name: Scorecard Analysis + runs-on: ubuntu-latest + timeout-minutes: 15 + permissions: + security-events: write # Upload SARIF to Security tab + id-token: write # OIDC token for result verification and publishing + contents: read # Read repository contents + actions: read # Read workflow runs (needed for Token-Permissions check) + steps: + - name: Checkout repository + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + persist-credentials: false + + - name: Run OpenSSF Scorecard + uses: ossf/scorecard-action@4eaacf0543bb3f2c246792bd56e8cdeffafb205a # v2.4.3 + with: + results_file: scorecard.sarif + results_format: sarif + # Publish results to OpenSSF API (enables public badge and tracking) + publish_results: true + + - name: Upload SARIF to GitHub Security tab + uses: github/codeql-action/upload-sarif@0d579ffd059c29b07949a3cce3983f0780820c98 # v4 + with: + sarif_file: scorecard.sarif + + - name: Upload Scorecard results as artifact + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 + with: + name: scorecard-results + path: scorecard.sarif + retention-days: 30 From 9a7abb68162e9a8c54e3bfb4b085c636427ed4f3 Mon Sep 17 00:00:00 2001 From: Paolo Dettori Date: Fri, 13 Mar 2026 15:31:05 -0400 Subject: [PATCH 2/2] chore: drop build.yml per reviewer feedback The multi-arch container build workflow is not needed at this stage. Remove it per evaline-ju's suggestion in PR review. Assisted-By: Claude (Anthropic AI) Signed-off-by: Paolo Dettori --- .github/workflows/build.yml | 99 ------------------------------------- 1 file changed, 99 deletions(-) delete mode 100644 .github/workflows/build.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml deleted file mode 100644 index 79dab22..0000000 --- a/.github/workflows/build.yml +++ /dev/null @@ -1,99 +0,0 @@ -# Build and Publish - Container image release workflow -# -# Builds and pushes the plugins-adapter container image to GHCR on: -# - Tag push (v*) for versioned releases -# - Manual trigger for on-demand testing -# -# Image: ghcr.io/kagenti/plugins-adapter/plugins-adapter: -# -# Multi-arch: amd64 + arm64 via QEMU emulation. -# Base plugin: no PLUGIN_DEPS baked in — consumers install plugins at deploy time. -# To build with a specific plugin, trigger manually and set PLUGIN_DEPS input. -# -# Usage: -# Tag release: git tag v1.2.3 && git push origin v1.2.3 -# Manual build: Actions → Build and Publish → Run workflow -# -name: Build and Publish - -on: - push: - tags: - - 'v*' - workflow_dispatch: - inputs: - plugin_deps: - description: 'Comma-separated plugin names to bake in (e.g. nemocheck). Leave empty for base image.' - required: false - default: '' - type: string - -# Deny all permissions at workflow level; each job declares only what it needs -permissions: {} - -env: - REGISTRY: ghcr.io - IMAGE_NAME: ${{ github.repository }} - -jobs: - build-and-push: - name: Build and Push Image - runs-on: ubuntu-latest - timeout-minutes: 30 - permissions: - contents: read - packages: write - - steps: - - name: Checkout repository - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 - - - name: Set up QEMU (multi-arch support) - uses: docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a # v4.0.0 - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0 - - - name: Log in to ghcr.io - uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4.0.0 - with: - registry: ${{ env.REGISTRY }} - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Extract Docker metadata - id: meta - uses: docker/metadata-action@030e881283bb7a6894de51c315a6bfe6a94e05cf # v6.0.0 - with: - images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} - tags: | - type=semver,pattern={{version}} - type=semver,pattern={{major}}.{{minor}} - type=sha,format=short - type=raw,value=latest,enable=${{ github.ref_type == 'tag' }} - - - name: Determine PLUGIN_DEPS - id: plugin-deps - run: | - # Use manual input if provided, otherwise empty (base image) - DEPS="${{ github.event.inputs.plugin_deps }}" - echo "plugin_deps=${DEPS}" >> "$GITHUB_OUTPUT" - if [ -n "$DEPS" ]; then - echo "Building with plugins: $DEPS" - else - echo "Building base image (no plugins baked in)" - fi - - - name: Build and push - uses: docker/build-push-action@d08e5c354a6adb9ed34480a06d141179aa583294 # v7.0.0 - with: - context: . - file: ./Dockerfile - platforms: linux/amd64,linux/arm64 - push: true - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} - build-args: | - PLUGIN_DEPS=${{ steps.plugin-deps.outputs.plugin_deps }} - cache-from: type=gha - cache-to: type=gha,mode=max