Skip to content

ci: modernize GoReleaser config and GitHub Actions workflows - #1607

Merged
nicholas-fedor merged 5 commits into
mainfrom
refactor/ci-cd-pipeline-modernization
May 10, 2026
Merged

ci: modernize GoReleaser config and GitHub Actions workflows#1607
nicholas-fedor merged 5 commits into
mainfrom
refactor/ci-cd-pipeline-modernization

Conversation

@nicholas-fedor

@nicholas-fedor nicholas-fedor commented May 9, 2026

Copy link
Copy Markdown
Owner

This PR modernizes the CI/CD pipeline by migrating GoReleaser to the dockers_v2 format, restructuring GitHub Actions workflows for better maintainability, and implementing supply-chain security best practices including Cosign signing and OSSF Scorecard analysis.

Problem

Both GoReleaser and GitHub updates were resulting in builds no longer functioning. In addition, there were a number of miscellaneous issues that needed to be resolved.

  • Missing Cosign signing for Docker images and checksums
  • No OSSF Scorecard analysis for supply-chain security
  • Changelog updates required GPG keys and PAT tokens instead of using built-in GITHUB_TOKEN
  • Inconsistent step naming conventions across workflows
  • Lint workflow was combined with pull-request workflow, reducing reusability

Solution

  • Migrated from dockers to dockers_v2 with native multi-platform manifest support, eliminating the need for a separate manifest workflow
  • Renamed release-dev.yamlrelease-nightly.yaml and release-prod.yamlrelease-stable.yaml with clearer terminology
  • Added change detection to nightly releases to skip when no code changes exist
  • Implemented Cosign keyless OIDC signing for Docker images and checksums
  • Added OSSF Scorecard workflow for automated supply-chain security analysis
  • Restructured changelog workflow to use GITHUB_TOKEN with create-pull-request action instead of GPG keys/PAT
  • Split lint and test workflows for independent reusability across trigger events
  • Added reusable composite action clean-cache for cache cleanup operations
  • Updated all workflows with consistent naming conventions (PascalCase for step names, explicit permissions per job)
  • Updated action versions to latest releases (checkout v6, setup-go v6, etc.)

Changes

  • build/goreleaser/: Replaced prod.yml with stable.yaml using dockers_v2 format
    • Multi-platform manifest with single watchtower-manifest entry
    • Platform-specific images with architecture-prefixed tags
    • Cosign signing for Docker images and checksums
    • Verifiable builds via gomod.proxy configuration
    • Source archive generation enabled
  • .github/workflows/:
    • build.yaml: Restructured with BUILD_TYPE and DRY_RUN inputs, added Cosign and SBOM upload steps
    • release-stable.yaml: New production release workflow (tag-triggered)
    • release-nightly.yaml: New nightly release workflow with change detection
    • update-changelog.yaml: Restructured to use GITHUB_TOKEN with auto-merge PR
    • lint-go.yaml: New dedicated Go linting workflow
    • clean-cache.yaml: Refactored to use composite action
    • scorecard.yml: New OSSF Scorecard supply-chain security analysis
    • security.yaml: Added daily scheduled scans, SARIF categories, updated action versions
    • test.yaml: Added direct triggers, updated to windows-2025, improved test command
    • publish-docs.yaml: Updated dependencies, fixed cache key, removed deprecated mike delete
    • Deleted: create-manifests.yaml, release-prod.yaml, release-dev.yaml, pull-request.yaml, lint.yaml
  • .github/actions/clean-cache/: New composite action for cache cleanup
  • .github/renovate.json: Enabled vulnerability alerts
  • .github/dependabot.yml: Removed (consolidated into renovate)
  • .editorconfig: Updated formatting rules (toml indent size 2, space-based indentation)

Summary by CodeRabbit

  • New Features

    • Added multiple CI workflows (linting, supply‑chain scorecard, changelog updater, staged release pipelines) and a reusable cache‑cleanup action; new stable/nightly release pipelines and release configs.
  • Bug Fixes

    • Improved multi‑platform Docker build outputs and hardened example session cookie handling.
  • Chores

    • Reorganized CI/CD configurations, removed Dependabot jobs, enabled Renovate vulnerability alerts, and applied formatting/editorconfig adjustments.

Review Change Stack

- Restructure release model from prod/dev to stable/nightly
- Standardize and update existing workflows
- Update Dockerfiles
- Disable goconst golangi-lint linter
- Apply minor code updates with slices.Backward(), secure cookie attributes, and removal of stale lint directives
@coderabbitai

coderabbitai Bot commented May 9, 2026

Copy link
Copy Markdown
Contributor

Caution

Review failed

Pull request was closed or merged during review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 51df4a35-178d-4198-b596-561d8d963bcd

📥 Commits

Reviewing files that changed from the base of the PR and between dd89e14 and 22d5063.

📒 Files selected for processing (1)
  • examples/lifecycle-hooks/synology-stop/synology-stop.go

Walkthrough

This PR restructures CI/CD: replaces legacy dev/prod release workflows with nightly/stable flows, reorganizes GoReleaser configs, modernizes Docker multi-platform builds, adds linting and supply-chain scans, removes several workflows and Dependabot, and applies small code cleanups and editor/config updates.

Changes

Release Pipeline & Build Orchestration

Layer / File(s) Summary
Build Workflow Interface Updates
.github/workflows/build.yaml
Build workflow inputs renamed to uppercase (BUILD_TYPE, DRY_RUN) and introduce ENVIRONMENT; permissions and environment variables explicitly declared and post-build SBOM/provenance steps conditioned on build type.
Cache Cleanup Infrastructure
.github/actions/clean-cache/action.yml, .github/workflows/clean-cache.yaml
New composite action for branch-scoped cache deletion; clean-cache workflow refactored to checkout then invoke the local action with gh CLI.
GoReleaser Configuration Reorganization
build/goreleaser/dev.yml, build/goreleaser/prod.yml, build/goreleaser/nightly.yaml, build/goreleaser/stable.yaml
Removed dev/prod configs; added nightly and stable configs with distinct build/signing/publishing rules (nightly: snapshot images; stable: archives, SBOM, multi-arch images, cosign signing).
Legacy Workflows Removed
.github/workflows/release-dev.yaml, .github/workflows/release-prod.yaml, .github/workflows/pull-request.yaml, .github/workflows/create-manifests.yaml, .github/workflows/changelog-update.yaml
Removed legacy release and orchestration workflows that belonged to the prior model.
New Release Workflows
.github/workflows/release-nightly.yaml, .github/workflows/release-stable.yaml
Nightly workflow adds change-detection to skip unchanged runs; stable workflow triggers on semver tags and manual dispatch and orchestrates test/build/update-go-docs.
Workflow Infrastructure Updates
.github/dependabot.yml, .github/renovate.json
Removed Dependabot config; enabled Renovate vulnerabilityAlerts.

Docker & Container Build Modernization

Layer / File(s) Summary
Multi-Platform Docker Builds
build/docker/Dockerfile, build/docker/Dockerfile.self-github, build/docker/Dockerfile.self-local
Dockerfiles refactored to use BUILDPLATFORM/TARGETPLATFORM, configurable BASE_IMAGE, builder stages, CA/timezone copying, and platform-specific binary sourcing into a scratch final stage.

Linting, Security & Developer Automation

Layer / File(s) Summary
Linting Infrastructure Updates
.github/workflows/lint-go.yaml, .github/workflows/lint.yaml, .github/workflows/test.yaml
Added lint-go workflow for PR-triggered golangci-lint; removed prior lint.yaml; test workflow extended with workflow_dispatch and pull_request triggers, Windows runner updated, and test command/coverage mode changed.
Security Scanning & Changelog Automation
.github/workflows/scorecard.yml, .github/workflows/security.yaml, .github/workflows/update-changelog.yaml
Added OSSF Scorecard workflow (weekly/push); security workflow updated with daily cron and categorized SARIF uploads; added update-changelog workflow that regenerates CHANGELOG.md and auto-merges PRs.
Documentation Publishing
.github/workflows/publish-docs.yaml, .github/workflows/update-go-docs.yaml
Publish-docs pinned Python to 3.14.4, uses deterministic cache key, and updates mike deploy logic; update-go-docs renamed job and supplies explicit goproxy/import_path inputs.

Code Refactoring & Configuration

Layer / File(s) Summary
Code Cleanup
internal/actions/update.go, pkg/metrics/metrics.go, pkg/notifications/shoutrrr.go, pkg/registry/auth/auth.go, examples/lifecycle-hooks/synology-stop/synology-stop.go
Replaced manual reverse loop with slices.Backward; removed several //nolint:gosec directives; Synology example now sets session cookie attributes Secure/HttpOnly/SameSite=Strict and validates SYNO_URL.
Configuration Updates
.editorconfig, build/golangci-lint/golangci-lint.yaml, cliff.toml
EditorConfig adjusted (MD trailing whitespace preserved, TOML indent_size=2, shell/Dockerfile indent->spaces); golangci-lint entry repositioned; cliff.toml commit parsing/footer logic refined.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title directly describes the main change: modernizing GoReleaser config and GitHub Actions workflows, which aligns with the extensive CI/CD pipeline restructuring shown throughout the changeset.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@codacy-production

codacy-production Bot commented May 9, 2026

Copy link
Copy Markdown

Not up to standards ⛔

🔴 Issues 1 high

Alerts:
⚠ 1 issue (≤ 0 issues of at least minor severity)

Results:
1 new issue

Category Results
Security 1 high

View in Codacy

🟢 Metrics 0 duplication

Metric Results
Duplication 0

View in Codacy

NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.

@codecov

codecov Bot commented May 9, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 5.00000% with 38 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
...les/lifecycle-hooks/synology-stop/synology-stop.go 0.00% 38 Missing ⚠️

Impacted file tree graph

@@            Coverage Diff             @@
##             main    #1607      +/-   ##
==========================================
- Coverage   75.13%   75.06%   -0.07%     
==========================================
  Files          58       58              
  Lines        9763     9795      +32     
==========================================
+ Hits         7335     7353      +18     
- Misses       2168     2181      +13     
- Partials      260      261       +1     
Files with missing lines Coverage Δ
internal/actions/update.go 84.93% <100.00%> (ø)
pkg/metrics/metrics.go 92.50% <ø> (ø)
pkg/notifications/shoutrrr.go 85.71% <ø> (+4.35%) ⬆️
pkg/registry/auth/auth.go 79.38% <ø> (ø)
...les/lifecycle-hooks/synology-stop/synology-stop.go 0.00% <0.00%> (ø)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
.github/workflows/build.yaml (1)

21-24: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Make Docker Hub secrets optional at the workflow boundary to enable DRY_RUN in restricted contexts.

Lines 21-24 require DockerHub secrets unconditionally at the workflow-call boundary. This prevents callers from invoking this reusable workflow with DRY_RUN=true when secrets are unavailable (e.g., in forks or restricted environments), even though the if: ${{ !inputs.DRY_RUN }} guards on the Docker Hub login steps would skip them. Currently, both production callers (release-stable.yaml and release-nightly.yaml) always provide secrets, so this doesn't affect existing workflows, but it unnecessarily restricts flexibility.

Solution: Change required: true to required: false for both secrets and add a runtime validation step that enforces credential presence only when DRY_RUN=false, allowing dry-run invocations without secrets.

Suggested patch
 on:
   workflow_call:
     secrets:
       DOCKERHUB_USERNAME:
-        required: true
+        required: false
       DOCKERHUB_TOKEN:
-        required: true
+        required: false

     steps:
       - name: Validate BUILD_TYPE input
         env:
           BUILD_TYPE: ${{ inputs.BUILD_TYPE }}
         run: |
           if [[ "${BUILD_TYPE}" != "stable" && "${BUILD_TYPE}" != "nightly" ]]; then
             echo "Error: BUILD_TYPE must be 'stable' or 'nightly', got '${BUILD_TYPE}'"
             exit 1
           fi
+
+      - name: Validate Docker Hub credentials for publish mode
+        if: ${{ !inputs.DRY_RUN }}
+        env:
+          DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }}
+          DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }}
+        run: |
+          if [[ -z "${DOCKERHUB_USERNAME}" || -z "${DOCKERHUB_TOKEN}" ]]; then
+            echo "Error: DOCKERHUB_USERNAME and DOCKERHUB_TOKEN are required when DRY_RUN=false"
+            exit 1
+          fi
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/build.yaml around lines 21 - 24, Change the workflow
inputs DOCKERHUB_USERNAME and DOCKERHUB_TOKEN from required: true to required:
false so callers can invoke with DRY_RUN=true without secrets, and add a runtime
validation step that checks inputs.DRY_RUN and only fails if DRY_RUN is false
and either DOCKERHUB_USERNAME or DOCKERHUB_TOKEN is missing; reference the input
names DOCKERHUB_USERNAME, DOCKERHUB_TOKEN and the DRY_RUN input and ensure the
validation runs before any steps that assume the credentials (i.e., before the
Docker login step guarded by if: ${{ !inputs.DRY_RUN }}).
🧹 Nitpick comments (1)
internal/actions/update.go (1)

1317-1318: 💤 Low value

Consider eliminating the intermediate variable.

The value variable v is immediately assigned to c without any transformation. You can simplify by using c directly in the range statement.

♻️ Proposed simplification
-	for i, v := range slices.Backward(containers) {
-		c := v
+	for i, c := range slices.Backward(containers) {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/actions/update.go` around lines 1317 - 1318, The loop creates an
unnecessary intermediate variable `c` by assigning `v` to `c`; change the range
to bind `c` directly (e.g., use `for i, c := range slices.Backward(containers)
{`) and remove the redundant `c := v` assignment so the loop body uses `c`
directly; this touches the loop over `slices.Backward(containers)` and the
variables `v` and `c`.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/build.yaml:
- Around line 119-125: The "Upload Binary SBOMs" upload step uses the wrong glob
and silent-ignore behavior: change the artifact path from "dist/*.sbom" to
"dist/*.sbom.json" to match GoReleaser output and remove or change
"if-no-files-found: ignore" so missing SBOMs fail the job (e.g., delete that
line or set it to "error"); update the step that uses actions/upload-artifact
and relies on inputs.DRY_RUN/inputs.BUILD_TYPE accordingly so uploads don't
silently skip when SBOMs are absent.

In @.github/workflows/clean-cache.yaml:
- Around line 18-35: The condition includes workflow_dispatch but the Clean
Cache step always sets branch to refs/pull/${{ github.event.pull_request.number
}}/merge which is undefined for manual triggers; fix by making the branch
parameter conditional or pluggable: add a workflow_dispatch input (e.g.,
inputs.branch) and change the Clean Cache step’s branch to use the input when
present, or alter the if/condition to only allow the step when
github.event.pull_request exists (i.e., remove workflow_dispatch or guard the
branch assignment), updating the Clean Cache usage that references
gh-repo/branch accordingly.

In @.github/workflows/lint-go.yaml:
- Around line 7-13: The PR path filter in .github/workflows/lint-go.yaml
currently only lists source code and go.mod files; update the paths: section to
include lint and workflow configuration files (e.g., add build/**, .github/** or
the specific config directory like build/golangci-lint/** and any top-level CI
config files) so changes to lint/workflow configs will trigger this workflow;
modify the paths array in lint-go.yaml accordingly to include those config
locations.

In @.github/workflows/publish-docs.yaml:
- Around line 14-16: The workflow currently sets the repository contents
permission to read via the permissions: contents: read setting which prevents
the job from pushing commits when running mike deploy --push; update the
workflow permissions so the job can push by changing the contents permission to
write (e.g., permissions: contents: write) or scoping a write permission to the
specific job that runs mike deploy (refer to the step invoking mike deploy
--push) so the push step (lines around the mike deploy --push invocation) has
the必要 write permission.

In @.github/workflows/release-nightly.yaml:
- Around line 27-37: The job currently sets job-level permissions only to
"actions: read" which prevents actions/checkout from accessing repository
contents; update the job permissions to include "contents: read" so the
"Checkout Repository" step (uses: actions/checkout) can succeed (keep the
existing conditional if: ${{ inputs.FORCE_RELEASE != 'true' }} unchanged).

In `@examples/lifecycle-hooks/synology-stop/synology-stop.go`:
- Around line 357-363: The Secure cookie flag is being set unconditionally which
breaks HTTP connections; modify the configuration loader to parse config.SynoURL
(use net/url.Parse) and add a boolean field like Config.IsHTTPS (true when
scheme == "https"), then update all cookie creations in authenticate(),
stopContainer(), and logout() to set Cookie.Secure = cfg.IsHTTPS instead of true
so the session cookie is only marked Secure for HTTPS endpoints.

---

Outside diff comments:
In @.github/workflows/build.yaml:
- Around line 21-24: Change the workflow inputs DOCKERHUB_USERNAME and
DOCKERHUB_TOKEN from required: true to required: false so callers can invoke
with DRY_RUN=true without secrets, and add a runtime validation step that checks
inputs.DRY_RUN and only fails if DRY_RUN is false and either DOCKERHUB_USERNAME
or DOCKERHUB_TOKEN is missing; reference the input names DOCKERHUB_USERNAME,
DOCKERHUB_TOKEN and the DRY_RUN input and ensure the validation runs before any
steps that assume the credentials (i.e., before the Docker login step guarded by
if: ${{ !inputs.DRY_RUN }}).

---

Nitpick comments:
In `@internal/actions/update.go`:
- Around line 1317-1318: The loop creates an unnecessary intermediate variable
`c` by assigning `v` to `c`; change the range to bind `c` directly (e.g., use
`for i, c := range slices.Backward(containers) {`) and remove the redundant `c
:= v` assignment so the loop body uses `c` directly; this touches the loop over
`slices.Backward(containers)` and the variables `v` and `c`.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 4b1836a7-c9b2-45f0-afc7-e1e505b994b2

📥 Commits

Reviewing files that changed from the base of the PR and between 66f0ab2 and d4530bc.

📒 Files selected for processing (35)
  • .editorconfig
  • .github/actions/clean-cache/action.yml
  • .github/dependabot.yml
  • .github/renovate.json
  • .github/workflows/build.yaml
  • .github/workflows/changelog-update.yaml
  • .github/workflows/clean-cache.yaml
  • .github/workflows/create-manifests.yaml
  • .github/workflows/lint-go.yaml
  • .github/workflows/lint.yaml
  • .github/workflows/publish-docs.yaml
  • .github/workflows/pull-request.yaml
  • .github/workflows/release-dev.yaml
  • .github/workflows/release-nightly.yaml
  • .github/workflows/release-prod.yaml
  • .github/workflows/release-stable.yaml
  • .github/workflows/scorecard.yml
  • .github/workflows/security.yaml
  • .github/workflows/test.yaml
  • .github/workflows/update-changelog.yaml
  • .github/workflows/update-go-docs.yaml
  • build/docker/Dockerfile
  • build/docker/Dockerfile.self-github
  • build/docker/Dockerfile.self-local
  • build/golangci-lint/golangci-lint.yaml
  • build/goreleaser/dev.yml
  • build/goreleaser/nightly.yaml
  • build/goreleaser/prod.yml
  • build/goreleaser/stable.yaml
  • cliff.toml
  • examples/lifecycle-hooks/synology-stop/synology-stop.go
  • internal/actions/update.go
  • pkg/metrics/metrics.go
  • pkg/notifications/shoutrrr.go
  • pkg/registry/auth/auth.go
💤 Files with no reviewable changes (10)
  • pkg/registry/auth/auth.go
  • .github/workflows/release-dev.yaml
  • .github/workflows/lint.yaml
  • .github/dependabot.yml
  • .github/workflows/pull-request.yaml
  • build/goreleaser/prod.yml
  • .github/workflows/changelog-update.yaml
  • .github/workflows/release-prod.yaml
  • .github/workflows/create-manifests.yaml
  • build/goreleaser/dev.yml

Comment on lines +119 to +125
- name: Upload Binary SBOMs
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
if: ${{ !inputs.DRY_RUN && inputs.BUILD_TYPE == 'stable' }}
with:
name: ${{ inputs.BUILD_TYPE }}-binary-sboms
path: dist/*.sbom
if-no-files-found: ignore

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Workflow SBOM upload configuration:"
rg -n 'Upload Binary SBOMs|path:|if-no-files-found' .github/workflows/build.yaml -C2

echo
echo "GoReleaser stable SBOM output configuration:"
rg -n 'sbom|sboms|name_template|format' build/goreleaser/stable.yaml -C3

Repository: nicholas-fedor/watchtower

Length of output: 2491


🏁 Script executed:

cat -n build/goreleaser/stable.yaml | sed -n '280,320p'

Repository: nicholas-fedor/watchtower

Length of output: 1645


🏁 Script executed:

rg -n 'sbom' build/goreleaser/stable.yaml -A 10 -B 2

Repository: nicholas-fedor/watchtower

Length of output: 733


🌐 Web query:

GoReleaser SBOM default output naming format files

💡 Result:

GoReleaser SBOMs default output filename templates (written into dist) are configured via the sboms[].documents option. 1) Default sbom id - The default SBOM config id is “default” when sboms[].id is omitted. [1] 2) Default documents (filenames) depending on sboms[].artifacts - If artifacts: "binary", default documents is: {{.Binary }}{{.Version }}{{.Os }}_{{.Arch }}.sbom.json [2][1] - If artifacts: "any", there are no default documents (empty list), so no SBOM outputs are produced unless you set sboms[].documents yourself. [2][1] - Otherwise (e.g., artifacts: "archive" or “source”), default documents is: {{.ArtifactName }}.sbom.json [2][1] 3) What the generated files look like in dist - A typical generated SBOM file corresponds to each cataloged artifact filename with a “.sbom.json” suffix. For example, an archive named my-cmd_1.2.3_linux_arm64.tar.gz results in my-cmd_1.2.3_linux_arm64.tar.gz.sbom.json. [3] 4) Note about.json - GoReleaser’s SBOM docs/defaults include the “.sbom.json” suffix (not just “.sbom”), reflecting an update that appended the “.json” to the default SBOM output naming. [2][4]

Citations:


🌐 Web query:

GoReleaser sbom artifacts default name_template

💡 Result:

GoReleaser SBOM artifacts: the default SBOM document filename is When binary: {{.Binary }}{{.Version }}{{.Os }}_{{.Arch }}.sbom.json When any: [] Otherwise (e.g., archive/source installers): {{.ArtifactName }}.sbom.json [1] So there is no single “sbom artifacts default name_template” setting; instead GoReleaser uses the SBOM configuration field documents (templates allowed) whose default value depends on whether sbom is run for binaries or for other artifact types [1]. How it works in config - In sboms section, use documents to control SBOM output names/filenames; this is where name templates are applied (e.g. ${artifact}.spdx.json in docs) [1]. - The default documents value is computed as described above, depending on sbom config (binary vs any vs other) [1]. Example override You can override document templates by setting sboms[].documents in.goreleaser.yaml (templates allowed) [1]. For example, the docs show documents: ["${artifact}.spdx.json"] [1].

Citations:


Fix SBOM upload pattern to match GoReleaser's default output format.

Line 125 uses if-no-files-found: ignore, which allows releases to proceed without SBOM artifacts. Additionally, the glob pattern dist/*.sbom will not match any files—GoReleaser generates SBOMs with .sbom.json suffix by default (e.g., watchtower_1.2.3_linux_amd64.tar.gz.sbom.json), so the upload silently fails.

Suggested patch
       - name: Upload Binary SBOMs
         uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
         if: ${{ !inputs.DRY_RUN && inputs.BUILD_TYPE == 'stable' }}
         with:
           name: ${{ inputs.BUILD_TYPE }}-binary-sboms
-          path: dist/*.sbom
-          if-no-files-found: ignore
+          path: dist/*.sbom*
+          if-no-files-found: error
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- name: Upload Binary SBOMs
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
if: ${{ !inputs.DRY_RUN && inputs.BUILD_TYPE == 'stable' }}
with:
name: ${{ inputs.BUILD_TYPE }}-binary-sboms
path: dist/*.sbom
if-no-files-found: ignore
- name: Upload Binary SBOMs
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
if: ${{ !inputs.DRY_RUN && inputs.BUILD_TYPE == 'stable' }}
with:
name: ${{ inputs.BUILD_TYPE }}-binary-sboms
path: dist/*.sbom*
if-no-files-found: error
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/build.yaml around lines 119 - 125, The "Upload Binary
SBOMs" upload step uses the wrong glob and silent-ignore behavior: change the
artifact path from "dist/*.sbom" to "dist/*.sbom.json" to match GoReleaser
output and remove or change "if-no-files-found: ignore" so missing SBOMs fail
the job (e.g., delete that line or set it to "error"); update the step that uses
actions/upload-artifact and relies on inputs.DRY_RUN/inputs.BUILD_TYPE
accordingly so uploads don't silently skip when SBOMs are absent.

Comment on lines +18 to +35
if: github.event_name == 'workflow_dispatch' || github.event.pull_request.merged
steps:
- name: Harden the runner (Audit all outbound calls)
- name: Harden the Runner (Step Security)
uses: step-security/harden-runner@a5ad31d6a139d249332a2605b85202e8c0b78450 # v2.19.1
with:
egress-policy: audit

- name: Cleanup
run: |
echo "Fetching list of cache key"
cacheKeysForPR=$(gh cache list --ref "$BRANCH" --limit 100 --json id --jq '.[].id')
- name: Checkout Repo
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false

## Setting this to not fail the workflow while deleting cache keys.
set +e
echo "Deleting caches..."
for cacheKey in $cacheKeysForPR
do
gh cache delete "$cacheKey"
done
echo "Done"
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GH_REPO: ${{ github.repository }}
BRANCH: refs/pull/${{ github.event.pull_request.number }}/merge
- name: Clean Cache
uses: ./.github/actions/clean-cache
with:
gh-token: ${{ secrets.GITHUB_TOKEN }}
gh-repo: ${{ github.repository }}
branch: refs/pull/${{ github.event.pull_request.number }}/merge

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Critical: workflow_dispatch trigger will fail due to undefined PR number.

The workflow allows manual triggering via workflow_dispatch (line 18 condition), but the branch parameter on line 35 always references github.event.pull_request.number, which is undefined when triggered manually. This will produce an invalid branch reference like refs/pull//merge, causing the cleanup action to fail.

🔧 Proposed fix: Add workflow_dispatch input or restrict the condition

Option 1 (Recommended): Add a branch input for workflow_dispatch

 on:
-  workflow_dispatch: {}
+  workflow_dispatch:
+    inputs:
+      branch:
+        description: 'Branch reference to clean (e.g., refs/pull/123/merge or refs/heads/feature-branch)'
+        required: true
+        type: string
   pull_request:
     types:
       - closed

Then update the branch parameter to use the input when available:

       - name: Clean Cache
         uses: ./.github/actions/clean-cache
         with:
           gh-token: ${{ secrets.GITHUB_TOKEN }}
           gh-repo: ${{ github.repository }}
-          branch: refs/pull/${{ github.event.pull_request.number }}/merge
+          branch: ${{ github.event_name == 'workflow_dispatch' && inputs.branch || format('refs/pull/{0}/merge', github.event.pull_request.number) }}

Option 2: Remove workflow_dispatch from the condition if manual triggering isn't needed

-    if: github.event_name == 'workflow_dispatch' || github.event.pull_request.merged
+    if: github.event.pull_request.merged
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if: github.event_name == 'workflow_dispatch' || github.event.pull_request.merged
steps:
- name: Harden the runner (Audit all outbound calls)
- name: Harden the Runner (Step Security)
uses: step-security/harden-runner@a5ad31d6a139d249332a2605b85202e8c0b78450 # v2.19.1
with:
egress-policy: audit
- name: Cleanup
run: |
echo "Fetching list of cache key"
cacheKeysForPR=$(gh cache list --ref "$BRANCH" --limit 100 --json id --jq '.[].id')
- name: Checkout Repo
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
## Setting this to not fail the workflow while deleting cache keys.
set +e
echo "Deleting caches..."
for cacheKey in $cacheKeysForPR
do
gh cache delete "$cacheKey"
done
echo "Done"
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GH_REPO: ${{ github.repository }}
BRANCH: refs/pull/${{ github.event.pull_request.number }}/merge
- name: Clean Cache
uses: ./.github/actions/clean-cache
with:
gh-token: ${{ secrets.GITHUB_TOKEN }}
gh-repo: ${{ github.repository }}
branch: refs/pull/${{ github.event.pull_request.number }}/merge
if: github.event.pull_request.merged
steps:
- name: Harden the Runner (Step Security)
uses: step-security/harden-runner@a5ad31d6a139d249332a2605b85202e8c0b78450 # v2.19.1
with:
egress-policy: audit
- name: Checkout Repo
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: Clean Cache
uses: ./.github/actions/clean-cache
with:
gh-token: ${{ secrets.GITHUB_TOKEN }}
gh-repo: ${{ github.repository }}
branch: refs/pull/${{ github.event.pull_request.number }}/merge
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/clean-cache.yaml around lines 18 - 35, The condition
includes workflow_dispatch but the Clean Cache step always sets branch to
refs/pull/${{ github.event.pull_request.number }}/merge which is undefined for
manual triggers; fix by making the branch parameter conditional or pluggable:
add a workflow_dispatch input (e.g., inputs.branch) and change the Clean Cache
step’s branch to use the input when present, or alter the if/condition to only
allow the step when github.event.pull_request exists (i.e., remove
workflow_dispatch or guard the branch assignment), updating the Clean Cache
usage that references gh-repo/branch accordingly.

Comment on lines +7 to +13
paths:
- cmd/**
- internal/**
- pkg/**
- go.mod
- go.sum
- main.go

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Include lint/workflow config files in PR path filters.

Currently, a PR that changes only lint config (for example build/golangci-lint/golangci-lint.yaml) won’t run this workflow, even though Line 46 depends on it. Add those paths so CI validates config-only changes too.

Suggested patch
   pull_request:
     paths:
       - cmd/**
       - internal/**
       - pkg/**
       - go.mod
       - go.sum
       - main.go
+      - build/golangci-lint/**
+      - .github/workflows/lint-go.yaml
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/lint-go.yaml around lines 7 - 13, The PR path filter in
.github/workflows/lint-go.yaml currently only lists source code and go.mod
files; update the paths: section to include lint and workflow configuration
files (e.g., add build/**, .github/** or the specific config directory like
build/golangci-lint/** and any top-level CI config files) so changes to
lint/workflow configs will trigger this workflow; modify the paths array in
lint-go.yaml accordingly to include those config locations.

Comment thread .github/workflows/publish-docs.yaml
Comment thread .github/workflows/release-nightly.yaml
Comment thread examples/lifecycle-hooks/synology-stop/synology-stop.go Outdated
- add ErrInvalidSynoURL for malformed SYNO_URL validation
- introduce IsHTTPS field to detect secure endpoint scheme
- create buildCookie helper for dynamic Secure flag based on protocol
- refactor HTTP request calls to pass config context

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@examples/lifecycle-hooks/synology-stop/synology-stop.go`:
- Around line 205-211: The URL validation in loadConfig currently allows any
non-empty scheme; update the parsedURL check to accept only "http" or "https":
after parsing config.SynoURL, verify parsedURL.Scheme is either "http" or
"https" and return ErrInvalidSynoURL otherwise, then set config.IsHTTPS =
(parsedURL.Scheme == "https"); reference parsedURL, config.SynoURL,
config.IsHTTPS and ErrInvalidSynoURL when making the change.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: d3e063c0-79dd-4891-aab1-b822e843b4e3

📥 Commits

Reviewing files that changed from the base of the PR and between 10b721f and dd89e14.

📒 Files selected for processing (2)
  • .github/workflows/release-nightly.yaml
  • examples/lifecycle-hooks/synology-stop/synology-stop.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • .github/workflows/release-nightly.yaml

Comment thread examples/lifecycle-hooks/synology-stop/synology-stop.go
…tion

- validate URL parsing errors separately from scheme validation
- normalize scheme to lowercase before http/https comparison
- ensure robust handling of mixed-case URL schemes
@nicholas-fedor
nicholas-fedor merged commit 9925601 into main May 10, 2026
16 of 19 checks passed
@nicholas-fedor
nicholas-fedor deleted the refactor/ci-cd-pipeline-modernization branch May 10, 2026 00:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant