name: CI Pipeline on: push: branches: - main tags: - 'v*' pull_request: branches: - main env: REGISTRY: ${{ vars.REGISTRY_URL }} IMAGE_NAME: enterprise-openldap jobs: # Stage 1: Lint Dockerfile lint: runs-on: docker steps: - name: Checkout repository uses: actions/checkout@v4 - name: Lint Dockerfile with hadolint run: | docker run --rm -i hadolint/hadolint < Dockerfile || { echo "::warning::Dockerfile linting found issues (non-blocking)" } # Stage 2: Build image build: runs-on: docker needs: lint outputs: image_tag: ${{ steps.version.outputs.VERSION }} steps: - name: Checkout repository uses: actions/checkout@v4 - name: Determine version tag id: version run: | if [[ "$GITHUB_REF" == refs/tags/v* ]]; then VERSION="${GITHUB_REF#refs/tags/v}" else VERSION="$(echo "$GITHUB_SHA" | cut -c1-7)" fi echo "VERSION=$VERSION" >> $GITHUB_OUTPUT echo "Building version: $VERSION" - name: Build Docker image run: | docker build -t ${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }} . docker tag ${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }} ${{ env.IMAGE_NAME }}:test - name: Save image for subsequent jobs run: | mkdir -p /tmp/images docker save ${{ env.IMAGE_NAME }}:test -o /tmp/images/image.tar - name: Upload image artifact uses: actions/upload-artifact@v4 with: name: docker-image path: /tmp/images/image.tar retention-days: 1 # Stage 3: Integration tests test: runs-on: docker needs: build steps: - name: Checkout repository uses: actions/checkout@v4 - name: Download image artifact uses: actions/download-artifact@v4 with: name: docker-image path: /tmp/images - name: Load Docker image run: | docker load -i /tmp/images/image.tar - name: Run integration tests run: | chmod +x tests/test-container.sh ./tests/test-container.sh env: IMAGE_NAME: ${{ env.IMAGE_NAME }}:test CONTAINER_NAME: openldap-ci-test # Stage 4: Security scan security-scan: runs-on: docker needs: build steps: - name: Download image artifact uses: actions/download-artifact@v4 with: name: docker-image path: /tmp/images - name: Load Docker image run: | docker load -i /tmp/images/image.tar - name: Scan image with Trivy run: | docker run --rm \ -v /var/run/docker.sock:/var/run/docker.sock \ aquasec/trivy:latest image \ --severity HIGH,CRITICAL \ --exit-code 0 \ --no-progress \ ${{ env.IMAGE_NAME }}:test - name: Scan for critical vulnerabilities (blocking) run: | docker run --rm \ -v /var/run/docker.sock:/var/run/docker.sock \ aquasec/trivy:latest image \ --severity CRITICAL \ --exit-code 1 \ --no-progress \ --ignore-unfixed \ ${{ env.IMAGE_NAME }}:test || { echo "::error::Critical vulnerabilities found!" exit 1 } # Stage 5: Push to registry push: runs-on: docker needs: [test, security-scan] if: github.event_name != 'pull_request' outputs: version: ${{ steps.version.outputs.VERSION }} full_image: ${{ steps.version.outputs.FULL_IMAGE }} steps: - name: Download image artifact uses: actions/download-artifact@v4 with: name: docker-image path: /tmp/images - name: Load Docker image run: | docker load -i /tmp/images/image.tar - name: Determine version and tags id: version run: | if [[ "$GITHUB_REF" == refs/tags/v* ]]; then VERSION="${GITHUB_REF#refs/tags/v}" # For releases, tag with version, major.minor, and latest MAJOR=$(echo $VERSION | cut -d. -f1) MINOR=$(echo $VERSION | cut -d. -f2) TAGS="${VERSION},${MAJOR}.${MINOR},latest" else VERSION="$(echo "$GITHUB_SHA" | cut -c1-7)" TAGS="${VERSION},latest" fi echo "VERSION=$VERSION" >> $GITHUB_OUTPUT echo "TAGS=$TAGS" >> $GITHUB_OUTPUT echo "FULL_IMAGE=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${VERSION}" >> $GITHUB_OUTPUT - name: Log in to Docker Registry run: | echo "${{ secrets.REGISTRY_PASSWORD }}" | docker login ${{ env.REGISTRY }} -u "${{ secrets.REGISTRY_USERNAME }}" --password-stdin - name: Tag and push images run: | IFS=',' read -ra TAGS <<< "${{ steps.version.outputs.TAGS }}" for TAG in "${TAGS[@]}"; do docker tag ${{ env.IMAGE_NAME }}:test ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:$TAG docker push ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:$TAG echo "Pushed: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:$TAG" done - name: Logout from registry if: always() run: docker logout ${{ env.REGISTRY }} || true # Stage 6: Update CD pipeline (trigger deployment) update-cd: runs-on: docker needs: push if: github.event_name != 'pull_request' && startsWith(github.ref, 'refs/tags/v') steps: - name: Trigger CD pipeline run: | echo "==============================================" echo " Ready to update CD pipeline" echo "==============================================" echo "New version: ${{ needs.push.outputs.version }}" echo "Full image: ${{ needs.push.outputs.full_image }}" echo "" echo "TODO: Add step to update version in CD repository" echo "This could be:" echo " - Update docker-compose.yml in infra repo" echo " - Update Helm values" echo " - Trigger ArgoCD sync" echo "=============================================="