11name : CrowdSec Integration Tests
22
33on :
4- push :
5- branches : [ main, development, 'feature/**' ]
6- paths :
7- - ' backend/internal/crowdsec/**'
8- - ' backend/internal/models/crowdsec*.go'
9- - ' configs/crowdsec/**'
10- - ' scripts/crowdsec_integration.sh'
11- - ' scripts/crowdsec_decision_integration.sh'
12- - ' scripts/crowdsec_startup_test.sh'
13- - ' .github/skills/integration-test-crowdsec*/**'
14- - ' Dockerfile'
15- - ' .github/workflows/crowdsec-integration.yml'
16- pull_request :
17- branches : [ main, development ]
18- paths :
19- - ' backend/internal/crowdsec/**'
20- - ' backend/internal/models/crowdsec*.go'
21- - ' configs/crowdsec/**'
22- - ' scripts/crowdsec_integration.sh'
23- - ' scripts/crowdsec_decision_integration.sh'
24- - ' scripts/crowdsec_startup_test.sh'
25- - ' .github/skills/integration-test-crowdsec*/**'
26- - ' Dockerfile'
27- - ' .github/workflows/crowdsec-integration.yml'
28- # Allow manual trigger
4+ workflow_run :
5+ workflows : ["Docker Build, Publish & Test"]
6+ types : [completed]
7+ branches : [main, development, 'feature/**'] # Explicit branch filter prevents unexpected triggers
8+ # Allow manual trigger for debugging
299 workflow_dispatch :
3010
3111concurrency :
@@ -37,19 +17,134 @@ jobs:
3717 name : CrowdSec Bouncer Integration
3818 runs-on : ubuntu-latest
3919 timeout-minutes : 15
20+ # Only run if docker-build.yml succeeded, or if manually triggered
21+ if : ${{ github.event.workflow_run.conclusion == 'success' || github.event_name == 'workflow_dispatch' }}
4022
4123 steps :
4224 - uses : actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6
4325
44- - name : Set up Docker Buildx
45- uses : docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0
26+ # Determine the correct image tag based on trigger context
27+ # For PRs: pr-{number}-{sha}, For branches: {sanitized-branch}-{sha}
28+ - name : Determine image tag
29+ id : image
30+ env :
31+ EVENT : ${{ github.event.workflow_run.event }}
32+ REF : ${{ github.event.workflow_run.head_branch }}
33+ SHA : ${{ github.event.workflow_run.head_sha }}
34+ MANUAL_TAG : ${{ inputs.image_tag }}
35+ run : |
36+ # Manual trigger uses provided tag
37+ if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then
38+ if [[ -n "$MANUAL_TAG" ]]; then
39+ echo "tag=${MANUAL_TAG}" >> $GITHUB_OUTPUT
40+ else
41+ # Default to latest if no tag provided
42+ echo "tag=latest" >> $GITHUB_OUTPUT
43+ fi
44+ echo "source_type=manual" >> $GITHUB_OUTPUT
45+ exit 0
46+ fi
47+
48+ # Extract 7-character short SHA
49+ SHORT_SHA=$(echo "$SHA" | cut -c1-7)
50+
51+ if [[ "$EVENT" == "pull_request" ]]; then
52+ # Use native pull_requests array (no API calls needed)
53+ PR_NUM=$(echo '${{ toJson(github.event.workflow_run.pull_requests) }}' | jq -r '.[0].number')
54+
55+ if [[ -z "$PR_NUM" || "$PR_NUM" == "null" ]]; then
56+ echo "❌ ERROR: Could not determine PR number"
57+ echo "Event: $EVENT"
58+ echo "Ref: $REF"
59+ echo "SHA: $SHA"
60+ echo "Pull Requests JSON: ${{ toJson(github.event.workflow_run.pull_requests) }}"
61+ exit 1
62+ fi
63+
64+ # Immutable tag with SHA suffix prevents race conditions
65+ echo "tag=pr-${PR_NUM}-${SHORT_SHA}" >> $GITHUB_OUTPUT
66+ echo "source_type=pr" >> $GITHUB_OUTPUT
67+ else
68+ # Branch push: sanitize branch name and append SHA
69+ # Sanitization: lowercase, replace / with -, remove special chars
70+ SANITIZED=$(echo "$REF" | \
71+ tr '[:upper:]' '[:lower:]' | \
72+ tr '/' '-' | \
73+ sed 's/[^a-z0-9-._]/-/g' | \
74+ sed 's/^-//; s/-$//' | \
75+ sed 's/--*/-/g' | \
76+ cut -c1-121) # Leave room for -SHORT_SHA (7 chars)
77+
78+ echo "tag=${SANITIZED}-${SHORT_SHA}" >> $GITHUB_OUTPUT
79+ echo "source_type=branch" >> $GITHUB_OUTPUT
80+ fi
81+
82+ echo "sha=${SHORT_SHA}" >> $GITHUB_OUTPUT
83+ echo "Determined image tag: $(cat $GITHUB_OUTPUT | grep tag=)"
84+
85+ # Pull image from registry with retry logic (dual-source strategy)
86+ # Try registry first (fast), fallback to artifact if registry fails
87+ - name : Pull Docker image from registry
88+ id : pull_image
89+ uses : nick-fields/retry@v3
90+ with :
91+ timeout_minutes : 5
92+ max_attempts : 3
93+ retry_wait_seconds : 10
94+ command : |
95+ IMAGE_NAME="ghcr.io/${{ github.repository_owner }}/charon:${{ steps.image.outputs.tag }}"
96+ echo "Pulling image: $IMAGE_NAME"
97+ docker pull "$IMAGE_NAME"
98+ docker tag "$IMAGE_NAME" charon:local
99+ echo "✅ Successfully pulled from registry"
100+ continue-on-error : true
46101
47- - name : Build Docker image
102+ # Fallback: Download artifact if registry pull failed
103+ - name : Fallback to artifact download
104+ if : steps.pull_image.outcome == 'failure'
105+ env :
106+ GH_TOKEN : ${{ secrets.GITHUB_TOKEN }}
107+ SHA : ${{ steps.image.outputs.sha }}
48108 run : |
49- docker build \
50- --no-cache \
51- --build-arg VCS_REF=${{ github.sha }} \
52- -t charon:local .
109+ echo "⚠️ Registry pull failed, falling back to artifact..."
110+
111+ # Determine artifact name based on source type
112+ if [[ "${{ steps.image.outputs.source_type }}" == "pr" ]]; then
113+ PR_NUM=$(echo '${{ toJson(github.event.workflow_run.pull_requests) }}' | jq -r '.[0].number')
114+ ARTIFACT_NAME="pr-image-${PR_NUM}"
115+ else
116+ ARTIFACT_NAME="push-image"
117+ fi
118+
119+ echo "Downloading artifact: $ARTIFACT_NAME"
120+ gh run download ${{ github.event.workflow_run.id }} \
121+ --name "$ARTIFACT_NAME" \
122+ --dir /tmp/docker-image || {
123+ echo "❌ ERROR: Artifact download failed!"
124+ echo "Available artifacts:"
125+ gh run view ${{ github.event.workflow_run.id }} --json artifacts --jq '.artifacts[].name'
126+ exit 1
127+ }
128+
129+ docker load < /tmp/docker-image/charon-image.tar
130+ docker tag $(docker images --format "{{.Repository}}:{{.Tag}}" | head -1) charon:local
131+ echo "✅ Successfully loaded from artifact"
132+
133+ # Validate image freshness by checking SHA label
134+ - name : Validate image SHA
135+ env :
136+ SHA : ${{ steps.image.outputs.sha }}
137+ run : |
138+ LABEL_SHA=$(docker inspect charon:local --format '{{index .Config.Labels "org.opencontainers.image.revision"}}' | cut -c1-7)
139+ echo "Expected SHA: $SHA"
140+ echo "Image SHA: $LABEL_SHA"
141+
142+ if [[ "$LABEL_SHA" != "$SHA" ]]; then
143+ echo "⚠️ WARNING: Image SHA mismatch!"
144+ echo "Image may be stale. Proceeding with caution..."
145+ else
146+ echo "✅ Image SHA matches expected commit"
147+ fi
53148
54149 - name : Run CrowdSec integration tests
55150 id : crowdsec-test
0 commit comments