2020 responders_matrix : ${{ steps.set-matrix.outputs.responders_matrix }}
2121 steps :
2222 - name : Checkout repository
23- uses : actions/checkout@v4
23+ uses : actions/checkout@v5
2424 with :
2525 fetch-depth : 0
2626
8383 matrix : ${{ fromJson(needs.generate-matrix.outputs.analyzers_matrix) }}
8484 steps :
8585 - name : Checkout repository
86- uses : actions/checkout@v4
86+ uses : actions/checkout@v5
8787 with :
8888 fetch-depth : 0
8989
@@ -149,66 +149,82 @@ jobs:
149149
150150 if [ ! -f "$dockerfile_path" ]; then
151151 echo "Dockerfile not found in $dockerfile_path. Creating one..."
152- #echo "FROM python:3-alpine" > "$dockerfile_path"
153- #echo "RUN apk add --no-cache openssl ca-certificates" >> "$dockerfile_path"
154- echo "FROM python:3-slim" > "$dockerfile_path"
155- # echo "RUN apt-get update && apt-get install -y --no-install-recommends ca-certificates && rm -rf /var/lib/apt/lists/*" >> "$dockerfile_path"
152+
153+ # Multi-stage build - Builder stage
154+ echo "# Builder stage" > "$dockerfile_path"
155+ echo "FROM python:3-slim as builder" >> "$dockerfile_path"
156+ echo "WORKDIR /build" >> "$dockerfile_path"
156157
157- # Check if current worker is among special alpine workers
158+ # Check if current worker is among special alpine workers and install build dependencies
159+ if echo "$special_alpine_workers" | grep -qw "$matrix_directory"; then
160+ echo "RUN apt-get update && apt-get install -y --no-install-recommends libmagic-dev build-essential && rm -rf /var/lib/apt/lists/*" >> "$dockerfile_path"
161+ fi
162+
163+ echo "COPY requirements.txt ." >> "$dockerfile_path"
164+ echo "RUN test ! -e requirements.txt || pip install --user --no-cache-dir -r requirements.txt" >> "$dockerfile_path"
165+ echo "" >> "$dockerfile_path"
166+
167+ # Runtime stage
168+ echo "# Runtime stage" >> "$dockerfile_path"
169+ echo "FROM python:3-slim" >> "$dockerfile_path"
170+
171+ # Check if current worker needs runtime libraries
158172 if echo "$special_alpine_workers" | grep -qw "$matrix_directory"; then
159- # echo "RUN apk add --no-cache file-dev && rm -rf /var/cache/apk/*" >> "$dockerfile_path"
160173 echo "RUN apt-get update && apt-get install -y --no-install-recommends libmagic1 && rm -rf /var/lib/apt/lists/*" >> "$dockerfile_path"
161174 fi
162175
163176 echo "WORKDIR /worker" >> "$dockerfile_path"
164- echo "COPY requirements.txt ${matrix_directory}/" >> "$dockerfile_path"
165- echo "RUN test ! -e ${matrix_directory}/requirements.txt || pip install --no-cache-dir -r ${matrix_directory}/requirements.txt" >> "$dockerfile_path"
177+ echo "COPY --from=builder /root/.local /root/.local" >> "$dockerfile_path"
166178 echo "COPY . ${matrix_directory}/" >> "$dockerfile_path"
179+ echo "ENV PATH=/root/.local/bin:\$PATH" >> "$dockerfile_path"
167180 echo "ENTRYPOINT [\"python\", \"${command_value}\"]" >> "$dockerfile_path"
168181 else
169182 echo "Dockerfile exists: $dockerfile_path"
170183 fi
171184
172185 - name : Check if image needs rebuild
173186 id : check-rebuild
187+ env :
188+ IMAGE_NAME : ghcr.io/${{ env.LOWER_REPO_OWNER }}/${{ env.LOWERCASE_NAME }}:${{ env.VERSION }}
189+ CURRENT_SHA : ${{ github.sha }}
190+ COMPONENT_DIR : analyzers/${{ matrix.directory }}
174191 run : |
175- image="ghcr.io/${{ env.LOWER_REPO_OWNER }}/${{ env.LOWERCASE_NAME }}:${{ env.VERSION }}"
176- current_sha="${{ github.sha }}"
177-
178- token="${{ secrets.GITHUB_TOKEN }}"
179-
180- # Fetch image manifest from GHCR
181- manifest_response=$(curl -sSL \
182- -H "Authorization : Bearer $token" \
183- -H "Accept : application/vnd.docker.distribution.manifest.v2+json" \
184- " https://ghcr.io/v2/${{ env.LOWER_REPO_OWNER }}/${{ env.LOWERCASE_NAME }}/manifests/${{ env.VERSION }}" )
185-
186- # Check if the manifest response contains a valid digest
187- labels=$(echo "$manifest_response" | jq -r '.config.digest // empty')
188-
189- if [[ -z "$labels" ]]; then
190- echo "No existing image or unable to fetch manifest. rebuild needed"
192+ set +x # Disable command echoing for security
193+
194+ # Force rebuild on scheduled runs (cron)
195+ if [ "${{ github.event_name }}" = "schedule" ]; then
196+ echo "Scheduled run detected - forcing rebuild"
191197 echo "rebuild=true" >> $GITHUB_OUTPUT
192198 exit 0
193199 fi
194-
195- # Fetch image config blob to extract labels
196- config_response=$(curl -sSL \
197- -H "Authorization : Bearer $token" \
198- " https://ghcr.io/v2/${{ env.LOWER_REPO_OWNER }}/${{ env.LOWERCASE_NAME }}/blobs/$labels" )
199-
200- # Extract image label safely
201- image_labels=$(echo "$config_response" | jq -r '.config.Labels["org.opencontainers.image.revision"] // empty')
202-
203- # Debugging: print values
204- echo "current_sha : $current_sha"
205- echo "image_labels : $image_labels"
206-
207- if [[ "$image_labels" == "$current_sha" ]]; then
208- echo "No rebuild needed. SHA matches : $current_sha"
209- echo "rebuild=false" >> $GITHUB_OUTPUT
200+
201+ # Try to pull the image to check if it exists
202+ if docker pull --platform linux/amd64 "$IMAGE_NAME" >/dev/null 2>&1; then
203+ # Image exists, check if it has the current SHA
204+ EXISTING_SHA=$(docker inspect "$IMAGE_NAME" --format='{{index .Config.Labels "org.opencontainers.image.revision"}}' 2>/dev/null || echo "")
205+
206+ if [[ "$EXISTING_SHA" == "$CURRENT_SHA" ]]; then
207+ echo "Image is up to date with current commit. No rebuild needed."
208+ echo "rebuild=false" >> $GITHUB_OUTPUT
209+ else
210+ # Check if this specific component folder has changes since the image was built
211+ if [[ -n "$EXISTING_SHA" ]] && git rev-parse --verify "$EXISTING_SHA" >/dev/null 2>&1; then
212+ # Check if there are changes in the component directory since the existing SHA
213+ if git diff --quiet "$EXISTING_SHA" "$CURRENT_SHA" -- "$COMPONENT_DIR"; then
214+ echo "No changes in $COMPONENT_DIR since last build. No rebuild needed."
215+ echo "rebuild=false" >> $GITHUB_OUTPUT
216+ else
217+ echo "Changes detected in $COMPONENT_DIR. Rebuild needed."
218+ echo "rebuild=true" >> $GITHUB_OUTPUT
219+ fi
220+ else
221+ echo "Cannot verify existing SHA. Rebuild needed."
222+ echo "rebuild=true" >> $GITHUB_OUTPUT
223+ fi
224+ fi
210225 else
211- echo "SHA mismatch or missing label. rebuild needed"
226+ # Image doesn't exist or can't be pulled
227+ echo "Image not found or inaccessible. Rebuild needed."
212228 echo "rebuild=true" >> $GITHUB_OUTPUT
213229 fi
214230
@@ -222,8 +238,8 @@ jobs:
222238 # Keep one image tag for import testing
223239 echo "IMAGE_TAG=${{ env.VERSION_SPLIT }}" >> $GITHUB_ENV
224240 # Produce three tags:
225- # 1) :VERSION (e.g. 2.0)
226- # 2) :VERSION_SPLIT (e.g. 2)
241+ # 1) :VERSION (eg 2.0)
242+ # 2) :VERSION_SPLIT (eg 2)
227243 # 3) :latest
228244 echo "IMAGE_TAGS=ghcr.io/${{ env.LOWER_REPO_OWNER }}/${{ env.LOWERCASE_NAME }}:${{ env.VERSION }},ghcr.io/${{ env.LOWER_REPO_OWNER }}/${{ env.LOWERCASE_NAME }}:${{ env.VERSION_SPLIT }}" >> $GITHUB_ENV
229245 else
@@ -258,6 +274,8 @@ jobs:
258274 platforms : ${{ env.PLATFORMS }}
259275 push : true
260276 tags : ${{ env.IMAGE_TAGS }}
277+ cache-from : type=gha
278+ cache-to : type=gha,mode=max,scope=shared
261279 labels : |
262280 org.opencontainers.image.created=${{ steps.build_date.outputs.date }}
263281 org.opencontainers.image.title=${{ env.LOWERCASE_NAME }}
@@ -276,7 +294,7 @@ jobs:
276294 org.opencontainers.image.version=${{ env.VERSION }}
277295
278296 - name : Scan image for vulnerabilities (Trivy)
279- uses : aquasecurity/trivy-action@0.32.0
297+ uses : aquasecurity/trivy-action@0.33.1
280298 with :
281299 image-ref : ghcr.io/${{ env.LOWER_REPO_OWNER }}/${{ env.LOWERCASE_NAME }}:${{ env.IMAGE_TAG }}
282300 format : table
@@ -504,7 +522,7 @@ jobs:
504522 matrix : ${{ fromJson(needs.generate-matrix.outputs.responders_matrix) }}
505523 steps :
506524 - name : Checkout repository
507- uses : actions/checkout@v4
525+ uses : actions/checkout@v5
508526 with :
509527 fetch-depth : 0
510528
@@ -570,68 +588,84 @@ jobs:
570588
571589 if [ ! -f "$dockerfile_path" ]; then
572590 echo "Dockerfile not found in $dockerfile_path. Creating one..."
573- # echo "FROM python:3-alpine" > "$dockerfile_path"
574- # echo "RUN apk add --no-cache openssl ca-certificates bind-tools" >> "$dockerfile_path"
575- echo "FROM python:3-slim" > "$dockerfile_path"
591+
592+ # Multi-stage build - Builder stage
593+ echo "# Builder stage" > "$dockerfile_path"
594+ echo "FROM python:3-slim as builder" >> "$dockerfile_path"
595+ echo "WORKDIR /build" >> "$dockerfile_path"
576596
577- # Check if current worker is among special alpine workers
597+ # Check if current worker is among special alpine workers and install build dependencies
598+ if echo "$special_alpine_workers" | grep -qw "$matrix_directory"; then
599+ echo "RUN apt-get update && apt-get install -y --no-install-recommends libmagic-dev build-essential && rm -rf /var/lib/apt/lists/*" >> "$dockerfile_path"
600+ fi
601+
602+ echo "COPY requirements.txt ." >> "$dockerfile_path"
603+ echo "RUN test ! -e requirements.txt || pip install --user --no-cache-dir -r requirements.txt" >> "$dockerfile_path"
604+ echo "" >> "$dockerfile_path"
605+
606+ # Runtime stage
607+ echo "# Runtime stage" >> "$dockerfile_path"
608+ echo "FROM python:3-slim" >> "$dockerfile_path"
609+
610+ # Check if current worker needs runtime libraries
578611 if echo "$special_alpine_workers" | grep -qw "$matrix_directory"; then
579- # echo "RUN apk add --no-cache file-dev && rm -rf /var/cache/apk/*" >> "$dockerfile_path"
580612 echo "RUN apt-get update && apt-get install -y --no-install-recommends libmagic1 && rm -rf /var/lib/apt/lists/*" >> "$dockerfile_path"
581613 fi
582614
583615 echo "WORKDIR /worker" >> "$dockerfile_path"
584- echo "COPY requirements.txt ${matrix_directory}/" >> "$dockerfile_path"
585- echo "RUN test ! -e ${matrix_directory}/requirements.txt || pip install --no-cache-dir -r ${matrix_directory}/requirements.txt" >> "$dockerfile_path"
616+ echo "COPY --from=builder /root/.local /root/.local" >> "$dockerfile_path"
586617 echo "COPY . ${matrix_directory}/" >> "$dockerfile_path"
618+ echo "ENV PATH=/root/.local/bin:\$PATH" >> "$dockerfile_path"
587619 echo "ENTRYPOINT [\"python\", \"${command_value}\"]" >> "$dockerfile_path"
588620 else
589621 echo "Dockerfile exists: $dockerfile_path"
590622 fi
591623
592624 - name : Check if image needs rebuild
593625 id : check-rebuild
626+ env :
627+ IMAGE_NAME : ghcr.io/${{ env.LOWER_REPO_OWNER }}/${{ env.LOWERCASE_NAME }}:${{ env.VERSION }}
628+ CURRENT_SHA : ${{ github.sha }}
629+ COMPONENT_DIR : responders/${{ matrix.directory }}
594630 run : |
595- image="ghcr.io/${{ env.LOWER_REPO_OWNER }}/${{ env.LOWERCASE_NAME }}:${{ env.VERSION }}"
596- current_sha="${{ github.sha }}"
597-
598- token="${{ secrets.GITHUB_TOKEN }}"
599-
600- # Fetch image manifest from GHCR
601- manifest_response=$(curl -sSL \
602- -H "Authorization : Bearer $token" \
603- -H "Accept : application/vnd.docker.distribution.manifest.v2+json" \
604- " https://ghcr.io/v2/${{ env.LOWER_REPO_OWNER }}/${{ env.LOWERCASE_NAME }}/manifests/${{ env.VERSION }}" )
605-
606- # Check if the manifest response contains a valid digest
607- labels=$(echo "$manifest_response" | jq -r '.config.digest // empty')
608-
609- if [[ -z "$labels" ]]; then
610- echo "No existing image or unable to fetch manifest. rebuild needed"
631+ set +x # Disable command echoing for security
632+
633+ # Force rebuild on scheduled runs (cron)
634+ if [ "${{ github.event_name }}" = "schedule" ]; then
635+ echo "Scheduled run detected - forcing rebuild"
611636 echo "rebuild=true" >> $GITHUB_OUTPUT
612637 exit 0
613638 fi
614-
615- # Fetch image config blob to extract labels
616- config_response=$(curl -sSL \
617- -H "Authorization : Bearer $token" \
618- " https://ghcr.io/v2/${{ env.LOWER_REPO_OWNER }}/${{ env.LOWERCASE_NAME }}/blobs/$labels" )
619-
620- # Extract image label safely
621- image_labels=$(echo "$config_response" | jq -r '.config.Labels["org.opencontainers.image.revision"] // empty')
622-
623- # Debugging: print values
624- echo "current_sha : $current_sha"
625- echo "image_labels : $image_labels"
626-
627- if [[ "$image_labels" == "$current_sha" ]]; then
628- echo "No rebuild needed. SHA matches : $current_sha"
629- echo "rebuild=false" >> $GITHUB_OUTPUT
639+
640+ # Try to pull the image to check if it exists
641+ if docker pull --platform linux/amd64 "$IMAGE_NAME" >/dev/null 2>&1; then
642+ # Image exists, check if it has the current SHA
643+ EXISTING_SHA=$(docker inspect "$IMAGE_NAME" --format='{{index .Config.Labels "org.opencontainers.image.revision"}}' 2>/dev/null || echo "")
644+
645+ if [[ "$EXISTING_SHA" == "$CURRENT_SHA" ]]; then
646+ echo "Image is up to date with current commit. No rebuild needed."
647+ echo "rebuild=false" >> $GITHUB_OUTPUT
648+ else
649+ # Check if this specific component folder has changes since the image was built
650+ if [[ -n "$EXISTING_SHA" ]] && git rev-parse --verify "$EXISTING_SHA" >/dev/null 2>&1; then
651+ # Check if there are changes in the component directory since the existing SHA
652+ if git diff --quiet "$EXISTING_SHA" "$CURRENT_SHA" -- "$COMPONENT_DIR"; then
653+ echo "No changes in $COMPONENT_DIR since last build. No rebuild needed."
654+ echo "rebuild=false" >> $GITHUB_OUTPUT
655+ else
656+ echo "Changes detected in $COMPONENT_DIR. Rebuild needed."
657+ echo "rebuild=true" >> $GITHUB_OUTPUT
658+ fi
659+ else
660+ echo "Cannot verify existing SHA. Rebuild needed."
661+ echo "rebuild=true" >> $GITHUB_OUTPUT
662+ fi
663+ fi
630664 else
631- echo "SHA mismatch or missing label. rebuild needed"
665+ # Image doesn't exist or can't be pulled
666+ echo "Image not found or inaccessible. Rebuild needed."
632667 echo "rebuild=true" >> $GITHUB_OUTPUT
633668 fi
634-
635669
636670 - name : Set build date
637671 id : build_date
@@ -643,8 +677,8 @@ jobs:
643677 # Keep one image tag for import testing
644678 echo "IMAGE_TAG=${{ env.VERSION_SPLIT }}" >> $GITHUB_ENV
645679 # Produce three tags:
646- # 1) :VERSION (e.g. 2.0)
647- # 2) :VERSION_SPLIT (e.g. 2)
680+ # 1) :VERSION (eg 2.0)
681+ # 2) :VERSION_SPLIT (eg 2)
648682 # 3) :latest
649683 echo "IMAGE_TAGS=ghcr.io/${{ env.LOWER_REPO_OWNER }}/${{ env.LOWERCASE_NAME }}:${{ env.VERSION }},ghcr.io/${{ env.LOWER_REPO_OWNER }}/${{ env.LOWERCASE_NAME }}:${{ env.VERSION_SPLIT }}" >> $GITHUB_ENV
650684 else
@@ -679,6 +713,8 @@ jobs:
679713 platforms : ${{ env.PLATFORMS }}
680714 push : true
681715 tags : ${{ env.IMAGE_TAGS }}
716+ cache-from : type=gha
717+ cache-to : type=gha,mode=max,scope=shared
682718 labels : |
683719 org.opencontainers.image.created=${{ steps.build_date.outputs.date }}
684720 org.opencontainers.image.title=${{ env.LOWERCASE_NAME }}
@@ -697,7 +733,7 @@ jobs:
697733 org.opencontainers.image.version=${{ env.VERSION }}
698734
699735 - name : Scan image for vulnerabilities (Trivy)
700- uses : aquasecurity/trivy-action@0.32.0
736+ uses : aquasecurity/trivy-action@0.33.1
701737 with :
702738 image-ref : ghcr.io/${{ env.LOWER_REPO_OWNER }}/${{ env.LOWERCASE_NAME }}:${{ env.IMAGE_TAG }}
703739 format : table
@@ -924,7 +960,7 @@ jobs:
924960 if : always()
925961 steps :
926962 - name : Checkout repository
927- uses : actions/checkout@v4
963+ uses : actions/checkout@v5
928964 - name : Set lowercase repository owner
929965 run : |
930966 owner="${{ github.repository_owner }}"
@@ -982,13 +1018,13 @@ jobs:
9821018 needs : [ build_analyzers, build_responders ]
9831019 if : startsWith(github.ref, 'refs/tags/') && always()
9841020 steps :
985- - uses : actions/checkout@v4
1021+ - uses : actions/checkout@v5
9861022 - name : Prepare documentation files
9871023 uses : docker://thehiveproject/doc-builder
9881024 with :
9891025 args : --type Cortex-Neurons
9901026 - name : Set up Python
991- uses : actions/setup-python@v5
1027+ uses : actions/setup-python@v6
9921028 with :
9931029 python-version : " 3.x"
9941030 architecture : x64
0 commit comments