fix: restore golangci-lint in CI pipeline and enforce blocking behavior

This commit is contained in:
GitHub Actions
2026-02-08 06:53:38 +00:00
parent bc0023a4b2
commit 8693569bc6
4 changed files with 382 additions and 273 deletions

View File

@@ -29,10 +29,6 @@ on:
default: true
type: boolean
concurrency:
group: ci-manual-pipeline-${{ github.workflow }}-${{ github.ref_name }}
cancel-in-progress: true
permissions:
contents: read
@@ -70,6 +66,19 @@ jobs:
chmod +x scripts/scan-gorm-security.sh
./scripts/scan-gorm-security.sh --check
- name: Set up Go
uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6
with:
go-version: ${{ env.GO_VERSION }}
cache-dependency-path: backend/go.sum
- name: Run golangci-lint (fast)
uses: golangci/golangci-lint-action@1e7e51e771db61008b38414a730f564565cf7c20 # v9.2.0
with:
version: v1.64.5
working-directory: backend
args: --config=.golangci-fast.yml --timeout=2m
- name: Check frontend lockfile
id: frontend-lockfile
run: |
@@ -105,6 +114,9 @@ jobs:
name: Build and Publish Image
runs-on: ubuntu-latest
needs: lint
concurrency:
group: ci-build-image-${{ github.workflow }}-${{ github.ref_name }}
cancel-in-progress: true
permissions:
contents: read
packages: write
@@ -150,10 +162,57 @@ jobs:
fi
fi
sanitize_tag() {
local raw="$1"
local max_len="$2"
local sanitized
sanitized=$(echo "$raw" | tr '[:upper:]' '[:lower:]')
sanitized=$(echo "$sanitized" | sed 's/[^a-z0-9-]/-/g' | sed 's/--*/-/g')
sanitized=$(echo "$sanitized" | sed 's/^[^a-z0-9]*//' | sed 's/[^a-z0-9-]*$//')
if [ -z "$sanitized" ]; then
sanitized="branch"
fi
sanitized=$(echo "$sanitized" | cut -c1-"$max_len")
sanitized=$(echo "$sanitized" | sed 's/^[^a-z0-9]*//')
if [ -z "$sanitized" ]; then
sanitized="branch"
fi
echo "$sanitized"
}
SANITIZED_BRANCH=$(sanitize_tag "${{ github.ref_name }}" 128)
BRANCH_TAG="${SANITIZED_BRANCH}"
BRANCH_SHA_TAG="${SANITIZED_BRANCH}-$(sanitize_tag "${SHORT_SHA}" 7)"
if [ "${#SANITIZED_BRANCH}" -gt 120 ]; then
SANITIZED_BRANCH=$(sanitize_tag "${{ github.ref_name }}" 120)
BRANCH_SHA_TAG="${SANITIZED_BRANCH}-${SHORT_SHA}"
fi
TAGS=()
TAGS+=("${{ env.GHCR_REGISTRY }}/${{ env.IMAGE_NAME }}:${DEFAULT_TAG}")
TAGS+=("${{ env.DOCKERHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${DEFAULT_TAG}")
if [ "${{ github.event_name }}" != "pull_request" ]; then
TAGS+=("${{ env.GHCR_REGISTRY }}/${{ env.IMAGE_NAME }}:${BRANCH_SHA_TAG}")
TAGS+=("${{ env.DOCKERHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${BRANCH_SHA_TAG}")
if [[ "${{ github.ref_name }}" == feature/* ]]; then
TAGS+=("${{ env.GHCR_REGISTRY }}/${{ env.IMAGE_NAME }}:${BRANCH_TAG}")
TAGS+=("${{ env.DOCKERHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${BRANCH_TAG}")
fi
fi
if [ "${{ github.event_name }}" != "pull_request" ] && \
{ [ "${{ github.ref_name }}" = "main" ] || [ "${{ github.ref_name }}" = "development" ] || [ "${{ github.ref_name }}" = "nightly" ]; }; then
TAGS+=("${{ env.GHCR_REGISTRY }}/${{ env.IMAGE_NAME }}:${SHORT_SHA}")
TAGS+=("${{ env.DOCKERHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:${SHORT_SHA}")
fi
if [ "${{ github.ref_name }}" = "main" ]; then
TAGS+=("${{ env.GHCR_REGISTRY }}/${{ env.IMAGE_NAME }}:latest")
TAGS+=("${{ env.DOCKERHUB_REGISTRY }}/${{ env.IMAGE_NAME }}:latest")
@@ -229,7 +288,7 @@ jobs:
name: Integration - Cerberus
runs-on: ubuntu-latest
needs: build-image
if: inputs.run_integration != false && needs.build-image.outputs.push_image == 'true'
if: needs.build-image.result == 'success' && needs.build-image.outputs.push_image == 'true' && needs.build-image.outputs.image_ref_dockerhub != '' && inputs.run_integration != false
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
@@ -254,7 +313,7 @@ jobs:
name: Integration - CrowdSec
runs-on: ubuntu-latest
needs: build-image
if: inputs.run_integration != false && needs.build-image.outputs.push_image == 'true'
if: needs.build-image.result == 'success' && needs.build-image.outputs.push_image == 'true' && needs.build-image.outputs.image_ref_dockerhub != '' && inputs.run_integration != false
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
@@ -280,7 +339,7 @@ jobs:
name: Integration - WAF
runs-on: ubuntu-latest
needs: build-image
if: inputs.run_integration != false && needs.build-image.outputs.push_image == 'true'
if: needs.build-image.result == 'success' && needs.build-image.outputs.push_image == 'true' && needs.build-image.outputs.image_ref_dockerhub != '' && inputs.run_integration != false
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
@@ -305,7 +364,7 @@ jobs:
name: Integration - Rate Limit
runs-on: ubuntu-latest
needs: build-image
if: inputs.run_integration != false && needs.build-image.outputs.push_image == 'true'
if: needs.build-image.result == 'success' && needs.build-image.outputs.push_image == 'true' && needs.build-image.outputs.image_ref_dockerhub != '' && inputs.run_integration != false
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
@@ -330,6 +389,7 @@ jobs:
name: Integration Gate
runs-on: ubuntu-latest
needs:
- build-image
- integration-cerberus
- integration-crowdsec
- integration-waf
@@ -343,6 +403,11 @@ jobs:
exit 0
fi
if [ "${{ needs.build-image.result }}" != "success" ] || [ "${{ needs.build-image.outputs.push_image }}" != "true" ]; then
echo "Integration stage skipped due to build-image state or push policy."
exit 0
fi
RESULTS=(
"${{ needs.integration-cerberus.result }}"
"${{ needs.integration-crowdsec.result }}"

View File

@@ -137,35 +137,45 @@ jobs:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
# Phase 1: Compute sanitized feature branch tags with SHA suffix
# Implements tag sanitization per spec Section 3.2
# Format: {sanitized-branch-name}-{short-sha} (e.g., feature-dns-provider-abc1234)
- name: Compute feature branch tag
if: steps.skip.outputs.skip_build != 'true' && env.TRIGGER_EVENT != 'pull_request' && startsWith(env.TRIGGER_REF, 'refs/heads/feature/')
id: feature-tag
- name: Compute branch tags
if: steps.skip.outputs.skip_build != 'true' && env.TRIGGER_EVENT != 'pull_request'
id: branch-tags
run: |
BRANCH_NAME="${TRIGGER_REF#refs/heads/}"
SHORT_SHA="$(echo ${{ env.TRIGGER_HEAD_SHA }} | cut -c1-7)"
# Sanitization algorithm per spec Section 3.2:
# 1. Convert to lowercase
# 2. Replace '/' with '-'
# 3. Replace special characters with '-'
# 4. Remove leading/trailing '-'
# 5. Collapse consecutive '-'
# 6. Truncate to 121 chars (leave room for -{sha})
# 7. Append '-{short-sha}' for uniqueness
SANITIZED=$(echo "${BRANCH_NAME}" | \
tr '[:upper:]' '[:lower:]' | \
tr '/' '-' | \
sed 's/[^a-z0-9._-]/-/g' | \
sed 's/^-//; s/-$//' | \
sed 's/--*/-/g' | \
cut -c1-121)
sanitize_tag() {
local raw="$1"
local max_len="$2"
FEATURE_TAG="${SANITIZED}-${SHORT_SHA}"
echo "tag=${FEATURE_TAG}" >> $GITHUB_OUTPUT
echo "📦 Computed feature branch tag: ${FEATURE_TAG}"
local sanitized
sanitized=$(echo "$raw" | tr '[:upper:]' '[:lower:]')
sanitized=$(echo "$sanitized" | sed 's/[^a-z0-9-]/-/g' | sed 's/--*/-/g')
sanitized=$(echo "$sanitized" | sed 's/^[^a-z0-9]*//' | sed 's/[^a-z0-9-]*$//')
if [ -z "$sanitized" ]; then
sanitized="branch"
fi
sanitized=$(echo "$sanitized" | cut -c1-"$max_len")
sanitized=$(echo "$sanitized" | sed 's/^[^a-z0-9]*//')
if [ -z "$sanitized" ]; then
sanitized="branch"
fi
echo "$sanitized"
}
SANITIZED_BRANCH=$(sanitize_tag "${BRANCH_NAME}" 128)
BASE_BRANCH=$(sanitize_tag "${BRANCH_NAME}" 120)
BRANCH_SHA_TAG="${BASE_BRANCH}-${SHORT_SHA}"
echo "branch_sha_tag=${BRANCH_SHA_TAG}" >> $GITHUB_OUTPUT
if [[ "$TRIGGER_REF" == refs/heads/feature/* ]]; then
echo "feature_branch_tag=${SANITIZED_BRANCH}" >> $GITHUB_OUTPUT
echo "feature_branch_sha_tag=${BRANCH_SHA_TAG}" >> $GITHUB_OUTPUT
fi
- name: Generate Docker metadata
id: meta
@@ -178,18 +188,20 @@ jobs:
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{major}}
type=raw,value=latest,enable={{is_default_branch}}
type=raw,value=latest,enable=${{ env.TRIGGER_REF == 'refs/heads/main' }}
type=raw,value=dev,enable=${{ env.TRIGGER_REF == 'refs/heads/development' }}
type=raw,value=${{ steps.feature-tag.outputs.tag }},enable=${{ env.TRIGGER_EVENT != 'pull_request' && startsWith(env.TRIGGER_REF, 'refs/heads/feature/') && steps.feature-tag.outputs.tag != '' }}
type=raw,value=nightly,enable=${{ env.TRIGGER_REF == 'refs/heads/nightly' }}
type=raw,value=${{ steps.branch-tags.outputs.feature_branch_tag }},enable=${{ env.TRIGGER_EVENT != 'pull_request' && startsWith(env.TRIGGER_REF, 'refs/heads/feature/') && steps.branch-tags.outputs.feature_branch_tag != '' }}
type=raw,value=${{ steps.branch-tags.outputs.branch_sha_tag }},enable=${{ env.TRIGGER_EVENT != 'pull_request' && steps.branch-tags.outputs.branch_sha_tag != '' }}
type=raw,value=pr-${{ env.TRIGGER_PR_NUMBER }}-{{sha}},enable=${{ env.TRIGGER_EVENT == 'pull_request' }},prefix=,suffix=
type=sha,format=short,enable=${{ env.TRIGGER_EVENT != 'pull_request' }}
type=sha,format=short,prefix=,suffix=,enable=${{ env.TRIGGER_EVENT != 'pull_request' && (env.TRIGGER_REF == 'refs/heads/main' || env.TRIGGER_REF == 'refs/heads/development' || env.TRIGGER_REF == 'refs/heads/nightly') }}
flavor: |
latest=false
labels: |
org.opencontainers.image.revision=${{ env.TRIGGER_HEAD_SHA }}
io.charon.pr.number=${{ env.TRIGGER_PR_NUMBER }}
io.charon.build.timestamp=${{ github.event.repository.updated_at }}
io.charon.feature.branch=${{ steps.feature-tag.outputs.tag }}
io.charon.feature.branch=${{ steps.branch-tags.outputs.feature_branch_tag }}
# Phase 1 Optimization: Build once, test many
# - For PRs: Single-platform (amd64) + immutable tags (pr-{number}-{short-sha})
# - For feature branches: Single-platform + sanitized tags ({branch}-{short-sha})

View File

@@ -75,10 +75,9 @@ jobs:
- name: Run golangci-lint
uses: golangci/golangci-lint-action@1e7e51e771db61008b38414a730f564565cf7c20 # v9.2.0
with:
version: latest
version: v1.64.5
working-directory: backend
args: --timeout=5m
continue-on-error: true
args: --config=.golangci-fast.yml --timeout=2m
- name: GORM Security Scanner
id: gorm-scan