Skip to content

Commit 6075866

Browse files
authored
Merge pull request #10 from agenixframework/feature/add-docker-compose-artifact-generation
Enhance GitHub workflow: Add docker-compose artifact generation, SBOM…
2 parents 781aadb + 79d5cd9 commit 6075866

File tree

4 files changed

+162
-8
lines changed

4 files changed

+162
-8
lines changed

.github/workflows/publish-nuget-and-containers.yml

Lines changed: 89 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,28 @@ jobs:
309309
cache-from: type=gha,scope=dashboard
310310
cache-to: type=gha,scope=dashboard,mode=max
311311

312+
- name: Generate docker-compose artifact
313+
shell: bash
314+
run: |
315+
set -euo pipefail
316+
echo "Preparing docker-compose artifact from published images..."
317+
mkdir -p ./artifacts/compose
318+
export GHCR_OWNER="${{ github.repository_owner }}"
319+
export GHCR_REPO="${{ github.event.repository.name }}"
320+
export IMAGE_TAG="${{ needs.build.outputs.version }}"
321+
docker compose version || true
322+
docker compose -f docker-compose.yml -f docker-compose.images.yml config > ./artifacts/compose/docker-compose-${{ needs.build.outputs.version }}.yml
323+
cp ./artifacts/compose/docker-compose-${{ needs.build.outputs.version }}.yml ./artifacts/compose/docker-compose.yml
324+
echo "Resolved compose generated at ./artifacts/compose/docker-compose-${{ needs.build.outputs.version }}.yml (and copied as docker-compose.yml)"
325+
head -n 50 ./artifacts/compose/docker-compose-${{ needs.build.outputs.version }}.yml || true
326+
327+
- name: Upload docker-compose artifact
328+
uses: actions/upload-artifact@v4
329+
with:
330+
name: docker-compose-${{ needs.build.outputs.version }}
331+
path: ./artifacts/compose/
332+
retention-days: 30
333+
312334
scan-and-sbom:
313335
runs-on: ubuntu-latest
314336
needs: [publish-containers, build]
@@ -386,15 +408,15 @@ jobs:
386408
- name: Upload Trivy SARIF to code scanning
387409
uses: github/codeql-action/upload-sarif@v3
388410
with:
389-
sarif_file: trivy-${{ matrix.component }}.sarif
390-
category: trivy-${{ matrix.component }}
411+
sarif_file: "trivy-${{ matrix.component }}.sarif"
412+
category: "trivy-${{ matrix.component }}"
391413

392414
- name: Upload Trivy SARIF as artifact
393415
uses: actions/upload-artifact@v4
394416
with:
395-
name: trivy-sarif-${{ matrix.component }}
396-
path: trivy-${{ matrix.component }}.sarif
397-
retention-days: 14
417+
name: "trivy-sarif-${{ matrix.component }}"
418+
path: "trivy-${{ matrix.component }}.sarif"
419+
retention-days: "14"
398420

399421
- name: Generate SBOM (CycloneDX)
400422
uses: anchore/sbom-action@v0
@@ -404,6 +426,68 @@ jobs:
404426
upload-artifact: true
405427
artifact-name: sbom-${{ matrix.component }}
406428

429+
- name: Trivy SBOM (CycloneDX JSON)
430+
uses: aquasecurity/[email protected]
431+
with:
432+
image-ref: ${{ steps.vars.outputs.image }}
433+
format: 'cyclonedx'
434+
output: trivy-sbom-${{ matrix.component }}.cdx.json
435+
exit-code: '0'
436+
env:
437+
TRIVY_USERNAME: ${{ github.actor }}
438+
TRIVY_PASSWORD: ${{ secrets.GITHUB_TOKEN }}
439+
440+
- name: Render Trivy SBOM summary (markdown)
441+
id: sbom-summary
442+
shell: bash
443+
run: |
444+
FILE="trivy-sbom-${{ matrix.component }}.cdx.json"
445+
OUT="sbom-summary-${{ matrix.component }}.md"
446+
447+
echo "# SBOM Summary - ${{ matrix.component }}" > "$OUT"
448+
echo "" >> "$OUT"
449+
echo "- Image: ${{ steps.vars.outputs.image }}" >> "$OUT"
450+
echo "- Components: $(jq -r '(.components // []) | length' "$FILE" 2>/dev/null || echo 0)" >> "$OUT"
451+
452+
echo "" >> "$OUT"
453+
echo "## Counts by type" >> "$OUT"
454+
echo "" >> "$OUT"
455+
echo "| Type | Count |" >> "$OUT"
456+
echo "|------|-------|" >> "$OUT"
457+
jq -r '(.components // []) | sort_by(.type // "unknown") | group_by(.type) | map({k:(.[0].type // "unknown"), c:length}) | .[] | "| \(.k) | \(.c) |"' "$FILE" 2>/dev/null >> "$OUT" || true
458+
459+
echo "" >> "$OUT"
460+
echo "## Sample components (first 20)" >> "$OUT"
461+
echo "" >> "$OUT"
462+
echo "| Name | Version | Type | License |" >> "$OUT"
463+
echo "|------|---------|------|---------|" >> "$OUT"
464+
jq -r '(.components // []) | sort_by(.name) | .[0:20] | .[] | "| \(.name // "-") | \(.version // "-") | \(.type // "-") | \(((.licenses[0].license.id // .licenses[0].license.name) // "-")) |"' "$FILE" 2>/dev/null >> "$OUT" || true
465+
466+
{
467+
echo "## SBOM Summary - ${{ matrix.component }}";
468+
echo "";
469+
cat "$OUT";
470+
} >> "$GITHUB_STEP_SUMMARY"
471+
472+
echo "summary-file=$OUT" >> $GITHUB_OUTPUT
473+
474+
- name: Upload SBOM summary and JSON
475+
uses: actions/upload-artifact@v4
476+
with:
477+
name: trivy-sbom-${{ matrix.component }}
478+
path: |
479+
trivy-sbom-${{ matrix.component }}.cdx.json
480+
sbom-summary-${{ matrix.component }}.md
481+
retention-days: 14
482+
483+
- name: Comment SBOM summary on PR
484+
if: github.event_name == 'pull_request'
485+
uses: peter-evans/create-or-update-comment@v4
486+
with:
487+
issue-number: ${{ github.event.pull_request.number }}
488+
body-file: ${{ steps.sbom-summary.outputs.summary-file }}
489+
edit-mode: replace
490+
407491
# Notification Job
408492
notify:
409493
runs-on: ubuntu-latest

README.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,3 +243,32 @@ PR checklist: include relevant documentation updates when changing endpoints, da
243243
[1]: .assets/logos/agenix-logo-large.png "Agenix"
244244

245245
[2]: .assets/icons/icon-64.png "Agenix"
246+
247+
248+
Run with published images (GHCR)
249+
--------------------------------
250+
If you don't want to build locally, you can run the stack against images published to GitHub Container Registry.
251+
252+
Prereqs
253+
- If images are private: docker login ghcr.io
254+
255+
Environment variables (can also be placed in a .env file at repo root)
256+
- GHCR_OWNER = your GitHub org or username (required)
257+
- GHCR_REPO = agenix-playwright-grid (defaults to this repo name if not set)
258+
- IMAGE_TAG = latest, or a specific version produced by CI (e.g., 1.2.3)
259+
260+
Start the stack using the images override file
261+
262+
export GHCR_OWNER=<your-gh-username-or-org>
263+
# optional overrides
264+
export IMAGE_TAG=latest
265+
# export GHCR_REPO=agenix-playwright-grid
266+
267+
docker compose -f docker-compose.yml -f docker-compose.images.yml pull
268+
docker compose -f docker-compose.yml -f docker-compose.images.yml up -d
269+
270+
Notes
271+
- The override file disables local builds and points hub/worker/dashboard to ghcr.io/${GHCR_OWNER}/${GHCR_REPO}-<service>:${IMAGE_TAG}.
272+
- Available services: -hub, -worker, -dashboard. Redis/Prometheus/Grafana already use public images.
273+
- CI pushes multi-arch images (linux/amd64, linux/arm64) and tags both ${IMAGE_TAG} (e.g., 1.2.3) and latest.
274+
- To scale workers, either duplicate worker sections/ports in docker-compose.yml or use: docker compose up -d --scale worker1=2 (when using a generalized worker service). In this repo workers are declared as worker1/2/3; adjust POOL_CONFIG and ports accordingly.

docker-compose.images.yml

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
version: "3.8"
2+
3+
# Override file to run the stack using published images on GHCR instead of local builds.
4+
# Usage:
5+
# export GHCR_OWNER=<your-gh-org-or-username>
6+
# # optional overrides
7+
# export GHCR_REPO=agenix-playwright-grid # defaults to repo name
8+
# export IMAGE_TAG=latest # or a specific version like v1.2.3
9+
# docker compose -f docker-compose.yml -f docker-compose.images.yml up -d
10+
#
11+
# Notes:
12+
# - This file nullifies `build:` on services that normally build locally and replaces them with `image:`.
13+
# - pull_policy: always ensures the latest tag is pulled when using :latest or mutable tags.
14+
# - Required env: GHCR_OWNER. You can also set via .env file in the project root.
15+
16+
services:
17+
hub:
18+
# Remove local build and use published image
19+
build: null
20+
image: ghcr.io/${GHCR_OWNER:?GHCR_OWNER not set}/${GHCR_REPO:-agenix-playwright-grid}-hub:${IMAGE_TAG:-latest}
21+
pull_policy: always
22+
23+
worker1:
24+
build: null
25+
image: ghcr.io/${GHCR_OWNER:?GHCR_OWNER not set}/${GHCR_REPO:-agenix-playwright-grid}-worker:${IMAGE_TAG:-latest}
26+
pull_policy: always
27+
28+
worker2:
29+
build: null
30+
image: ghcr.io/${GHCR_OWNER:?GHCR_OWNER not set}/${GHCR_REPO:-agenix-playwright-grid}-worker:${IMAGE_TAG:-latest}
31+
pull_policy: always
32+
33+
worker3:
34+
build: null
35+
image: ghcr.io/${GHCR_OWNER:?GHCR_OWNER not set}/${GHCR_REPO:-agenix-playwright-grid}-worker:${IMAGE_TAG:-latest}
36+
pull_policy: always
37+
38+
dashboard:
39+
build: null
40+
image: ghcr.io/${GHCR_OWNER:?GHCR_OWNER not set}/${GHCR_REPO:-agenix-playwright-grid}-dashboard:${IMAGE_TAG:-latest}
41+
pull_policy: always

docs/tasks.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,10 @@ The following is an ordered, actionable checklist covering architectural and cod
4545
39. [ ] Provide Helm chart/Kubernetes manifests with sensible defaults, probes, and resource limits.
4646
40. [ ] Harden Docker images: run as non-root user, drop capabilities, read-only filesystem with writable temp for Playwright.
4747
41. [ ] Slim Docker images further: prune caches (npm, dotnet), multi-stage for Node assets, consolidate OS packages, consider distroless base.
48-
42. [ ] Add multi-arch builds (linux/amd64, linux/arm64) for Hub/Worker via buildx.
48+
42. [X] Add multi-arch builds (linux/amd64, linux/arm64) for Hub/Worker via buildx.
4949
43. [X] Add image vulnerability scanning (Trivy/GHCR) and SBOM generation during CI.
50-
44. [ ] Introduce GitHub Actions CI: build, unit tests, integration tests (with Testcontainers), publish artifacts, and optional Docker image publish.
51-
45. [ ] Add workflow caching for dotnet restore, npm playwright installs, and docker layers to speed up CI.
50+
44. [X] Introduce GitHub Actions CI: build, unit tests, integration tests (with Testcontainers), publish artifacts, and optional Docker image publish.
51+
45. [X] Add workflow caching for dotnet restore, npm playwright installs, and docker layers to speed up CI.
5252
46. [ ] Expand unit tests for label matching, options parsing (POOL_CONFIG), and secret handling edge cases.
5353
47. [ ] Add integration tests for: secret mismatch (401), capacity exhaustion (503), borrow queue timeout, and node eviction scenarios.
5454
48. [ ] Add flaky-test mitigations: deterministic time helpers, extended health timeouts via env, and richer test diagnostics.

0 commit comments

Comments
 (0)