fix: restore golangci-lint in CI pipeline and enforce blocking behavior
This commit is contained in:
81
.github/workflows/ci-pipeline.yml
vendored
81
.github/workflows/ci-pipeline.yml
vendored
@@ -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 }}"
|
||||
|
||||
68
.github/workflows/docker-build.yml
vendored
68
.github/workflows/docker-build.yml
vendored
@@ -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})
|
||||
|
||||
5
.github/workflows/quality-checks.yml
vendored
5
.github/workflows/quality-checks.yml
vendored
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user