Skip to content

Commit 0aa1108

Browse files
authored
Merge pull request #412 from labsai/feature/v6-rc2-hardening
Feature/v6 rc2 hardening
2 parents 7926c94 + 4d935b0 commit 0aa1108

307 files changed

Lines changed: 33279 additions & 2365 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.amazonq/rules/project-context.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# EDDI — AI Coding Assistant Instructions
2+
3+
Read and follow all instructions in AGENTS.md in the repository root.

.cursor/rules/project-context.mdc

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
description: EDDI Backend — AI Agent Instructions. Complete project context, architecture, and coding guidelines.
3+
globs:
4+
alwaysApply: true
5+
---
6+
7+
Read and follow all instructions in the repository root file AGENTS.md.

.dockerignore

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22
!target/*-runner
33
!target/*-runner.jar
44
!target/lib/*
5-
!target/quarkus-app/*
6-
!licenses/*
7-
!docs/*
5+
!target/quarkus-app/
6+
!target/quarkus-app/**
7+
!licenses/
8+
!licenses/**
9+
!docs/
10+
!docs/**

.github/workflows/ci.yml

Lines changed: 240 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,17 @@ name: CI/CD
22

33
on:
44
push:
5-
branches: [ main ]
6-
tags: [ '[0-9]*' ]
5+
branches: [main]
6+
tags: ["[0-9]*"]
77
pull_request:
8-
branches: [ main ]
8+
branches: [main]
99

1010
permissions:
1111
contents: read
1212

1313
env:
1414
DOCKER_IMAGE: labsai/eddi
15-
JAVA_VERSION: '25'
15+
JAVA_VERSION: "25"
1616

1717
jobs:
1818
# ─── Job 1: Build & Test ────────────────────────────────────────
@@ -22,10 +22,10 @@ jobs:
2222

2323
steps:
2424
- name: Checkout
25-
uses: actions/checkout@v6
25+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
2626

2727
- name: Set up JDK ${{ env.JAVA_VERSION }}
28-
uses: actions/setup-java@v5
28+
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5
2929
with:
3030
distribution: temurin
3131
java-version: ${{ env.JAVA_VERSION }}
@@ -39,21 +39,60 @@ jobs:
3939

4040
- name: Upload test results
4141
if: always()
42-
uses: actions/upload-artifact@v7
42+
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7
4343
with:
4444
name: test-results
4545
path: target/surefire-reports/
4646
retention-days: 14
4747

4848
- name: Upload coverage report
4949
if: always()
50-
uses: actions/upload-artifact@v7
50+
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7
5151
with:
5252
name: jacoco-report
5353
path: target/site/jacoco/
5454
retention-days: 14
5555

56-
# ─── Job 2: Docker Build & Push ─────────────────────────────────
56+
# ─── Job 2: Integration Tests ─────────────────────────────────
57+
integration-test:
58+
name: Integration Tests
59+
runs-on: ubuntu-latest
60+
needs: build-and-test
61+
62+
steps:
63+
- name: Checkout
64+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
65+
66+
- name: Set up JDK ${{ env.JAVA_VERSION }}
67+
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5
68+
with:
69+
distribution: temurin
70+
java-version: ${{ env.JAVA_VERSION }}
71+
cache: maven
72+
73+
- name: Set execute permission for mvnw
74+
run: chmod +x mvnw
75+
76+
- name: Run integration tests
77+
run: ./mvnw verify -DskipITs=false -B
78+
79+
- name: Upload integration test results
80+
if: always()
81+
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7
82+
with:
83+
name: integration-test-results
84+
path: target/failsafe-reports/
85+
retention-days: 14
86+
87+
- name: Upload integration coverage report
88+
if: always()
89+
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7
90+
with:
91+
name: jacoco-it-report
92+
path: target/site/jacoco-it/
93+
retention-days: 14
94+
95+
# ─── Job 3: Docker Build & Push ─────────────────────────────────
5796
docker:
5897
name: Docker Build & Push
5998
runs-on: ubuntu-latest
@@ -70,10 +109,10 @@ jobs:
70109

71110
steps:
72111
- name: Checkout
73-
uses: actions/checkout@v6
112+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
74113

75114
- name: Set up JDK ${{ env.JAVA_VERSION }}
76-
uses: actions/setup-java@v5
115+
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5
77116
with:
78117
distribution: temurin
79118
java-version: ${{ env.JAVA_VERSION }}
@@ -86,7 +125,7 @@ jobs:
86125
id: meta
87126
run: |
88127
if [[ "$GITHUB_REF" == refs/tags/* ]]; then
89-
# Tag push: 6.0.0-RC1
128+
# Tag push: 6.0.0-RC2
90129
PRIMARY_TAG="${GITHUB_REF#refs/tags/}"
91130
IS_RELEASE="true"
92131
else
@@ -126,7 +165,7 @@ jobs:
126165
.
127166
128167
- name: Login to Docker Hub
129-
uses: docker/login-action@v4
168+
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4
130169
with:
131170
username: ${{ secrets.DOCKER_USERNAME }}
132171
password: ${{ secrets.DOCKER_PASSWORD }}
@@ -143,7 +182,7 @@ jobs:
143182
144183
echo "### ✅ Pushed to Docker Hub" >> $GITHUB_STEP_SUMMARY
145184
146-
# ─── Job 3: Smoke Test ──────────────────────────────────────────
185+
# ─── Job 4: Smoke Test ──────────────────────────────────────────
147186
smoke-test:
148187
name: Smoke Test
149188
runs-on: ubuntu-latest
@@ -211,19 +250,19 @@ jobs:
211250
docker rm -f eddi 2>/dev/null || true
212251
docker rm -f mongodb 2>/dev/null || true
213252
214-
# ─── Job 4: Red Hat Preflight (PRs only) ────────────────────────
253+
# ─── Job 5: Red Hat Preflight — PR Dry-Run ──────────────────────
215254
preflight-check:
216-
name: Preflight Dry-Run (Red Hat Certification)
255+
name: Preflight Dry-Run (PR)
217256
runs-on: ubuntu-latest
218257
needs: build-and-test
219258
if: github.event_name == 'pull_request'
220259

221260
steps:
222261
- name: Checkout
223-
uses: actions/checkout@v6
262+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
224263

225264
- name: Set up JDK ${{ env.JAVA_VERSION }}
226-
uses: actions/setup-java@v5
265+
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5
227266
with:
228267
distribution: temurin
229268
java-version: ${{ env.JAVA_VERSION }}
@@ -295,8 +334,190 @@ jobs:
295334
296335
- name: Upload preflight dry-run results
297336
if: always()
298-
uses: actions/upload-artifact@v7
337+
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7
299338
with:
300339
name: preflight-dryrun
301340
path: preflight-dryrun.txt
302341
retention-days: 14
342+
343+
# ─── Job 6: Red Hat Preflight — Push Verification ───────────────
344+
preflight-push:
345+
name: Preflight Verify (Pushed Image)
346+
runs-on: ubuntu-latest
347+
needs: docker
348+
if: >
349+
github.event_name == 'push' &&
350+
needs.docker.result == 'success'
351+
352+
steps:
353+
- name: Login to Docker Hub
354+
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4
355+
with:
356+
username: ${{ secrets.DOCKER_USERNAME }}
357+
password: ${{ secrets.DOCKER_PASSWORD }}
358+
359+
- name: Pull pushed image
360+
run: |
361+
PRIMARY_TAG="${{ needs.docker.outputs.primary-tag }}"
362+
echo "Pulling ${DOCKER_IMAGE}:${PRIMARY_TAG}..."
363+
docker pull ${DOCKER_IMAGE}:${PRIMARY_TAG}
364+
365+
- name: Verify Red Hat labels present
366+
run: |
367+
PRIMARY_TAG="${{ needs.docker.outputs.primary-tag }}"
368+
echo "=== Checking required Red Hat labels ==="
369+
LABELS=$(docker inspect ${DOCKER_IMAGE}:${PRIMARY_TAG} --format '{{json .Config.Labels}}')
370+
echo "$LABELS" | python3 -m json.tool
371+
MISSING=0
372+
for label in name vendor version release summary description; do
373+
if echo "$LABELS" | python3 -c "import sys,json; d=json.load(sys.stdin); assert '$label' in d" 2>/dev/null; then
374+
echo "✅ Label '$label' present"
375+
else
376+
echo "❌ Label '$label' MISSING"
377+
MISSING=1
378+
fi
379+
done
380+
if [ "$MISSING" -eq 1 ]; then
381+
echo "::error::Required Red Hat labels are missing on pushed image"
382+
exit 1
383+
fi
384+
385+
- name: Verify /licenses in container
386+
run: |
387+
PRIMARY_TAG="${{ needs.docker.outputs.primary-tag }}"
388+
echo "=== /licenses directory ==="
389+
docker run --rm --entrypoint="" ${DOCKER_IMAGE}:${PRIMARY_TAG} ls -la /licenses/
390+
echo ""
391+
echo "=== THIRD-PARTY.txt exists ==="
392+
docker run --rm --entrypoint="" ${DOCKER_IMAGE}:${PRIMARY_TAG} \
393+
test -f /licenses/THIRD-PARTY.txt && echo "✅ THIRD-PARTY.txt found" || { echo "❌ THIRD-PARTY.txt missing"; exit 1; }
394+
395+
- name: Install preflight
396+
run: |
397+
PREFLIGHT_VERSION=$(curl -s https://api.github.com/repos/redhat-openshift-ecosystem/openshift-preflight/releases/latest | jq -r .tag_name)
398+
echo "Installing preflight ${PREFLIGHT_VERSION}..."
399+
curl -sL "https://github.com/redhat-openshift-ecosystem/openshift-preflight/releases/download/${PREFLIGHT_VERSION}/preflight-linux-amd64" \
400+
-o /usr/local/bin/preflight
401+
chmod +x /usr/local/bin/preflight
402+
preflight --version
403+
404+
- name: Preflight check (pushed image, no submit)
405+
run: |
406+
PRIMARY_TAG="${{ needs.docker.outputs.primary-tag }}"
407+
preflight check container \
408+
docker.io/${DOCKER_IMAGE}:${PRIMARY_TAG} \
409+
--docker-config=${HOME}/.docker/config.json \
410+
2>&1 | tee preflight-push-results.txt
411+
echo ""
412+
echo "=== Preflight Summary ==="
413+
if grep -q "FAILED" preflight-push-results.txt; then
414+
echo "::warning::Preflight check has failures on pushed image — review output above."
415+
else
416+
echo "✅ All preflight checks passed on pushed image"
417+
fi
418+
419+
- name: Upload preflight results
420+
if: always()
421+
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7
422+
with:
423+
name: preflight-push-results
424+
path: preflight-push-results.txt
425+
retention-days: 14
426+
427+
# ─── Job 7: Slack Notification ─────────────────────────────────
428+
notify-slack:
429+
name: Slack Notification
430+
runs-on: ubuntu-latest
431+
if: always()
432+
needs:
433+
[build-and-test, integration-test, docker, smoke-test, preflight-check, preflight-push]
434+
435+
steps:
436+
- name: Send build notification
437+
env:
438+
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_URL }}
439+
run: |
440+
# Skip if no webhook configured
441+
if [ -z "$SLACK_WEBHOOK" ]; then
442+
echo "No SLACK_WEBHOOK_URL configured, skipping"
443+
exit 0
444+
fi
445+
446+
# Determine overall status
447+
BUILD="${{ needs.build-and-test.result }}"
448+
IT="${{ needs.integration-test.result }}"
449+
DOCKER="${{ needs.docker.result }}"
450+
SMOKE="${{ needs.smoke-test.result }}"
451+
PREFLIGHT_PR="${{ needs.preflight-check.result }}"
452+
PREFLIGHT_PUSH="${{ needs.preflight-push.result }}"
453+
# Merge: whichever preflight job actually ran wins (the other is "skipped")
454+
if [ "$PREFLIGHT_PUSH" != "skipped" ]; then
455+
PREFLIGHT="$PREFLIGHT_PUSH"
456+
else
457+
PREFLIGHT="$PREFLIGHT_PR"
458+
fi
459+
460+
# Map result to emoji
461+
status_icon() {
462+
case "$1" in
463+
success) echo "✅" ;;
464+
failure) echo "❌" ;;
465+
skipped) echo "⏭️" ;;
466+
cancelled) echo "🚫" ;;
467+
*) echo "❓" ;;
468+
esac
469+
}
470+
471+
# Overall status
472+
if [ "$BUILD" = "success" ] && [ "$IT" != "failure" ] && [ "$DOCKER" != "failure" ] && [ "$SMOKE" != "failure" ]; then
473+
OVERALL_ICON="✅"
474+
OVERALL_TEXT="Build Passed"
475+
COLOR="#36a64f"
476+
else
477+
OVERALL_ICON="❌"
478+
OVERALL_TEXT="Build Failed"
479+
COLOR="#cc0000"
480+
fi
481+
482+
# Branch or tag name
483+
REF="${GITHUB_REF#refs/heads/}"
484+
REF="${REF#refs/tags/}"
485+
REF="${REF#refs/pull/}"
486+
487+
# Sanitize commit message for JSON embedding
488+
RAW_MSG="${{ github.event.head_commit.message || github.event.pull_request.title || 'Manual run' }}"
489+
COMMIT_MSG=$(echo "$RAW_MSG" | head -1 | cut -c1-80 | sed 's/[\"\\]//g' | sed "s/[']//g")
490+
491+
curl -sf -X POST "$SLACK_WEBHOOK" \
492+
-H 'Content-type: application/json' \
493+
-d "{
494+
\"blocks\": [
495+
{
496+
\"type\": \"header\",
497+
\"text\": { \"type\": \"plain_text\", \"text\": \"${OVERALL_ICON} EDDI CI: ${OVERALL_TEXT}\", \"emoji\": true }
498+
},
499+
{
500+
\"type\": \"section\",
501+
\"text\": {
502+
\"type\": \"mrkdwn\",
503+
\"text\": \"*Branch:* \`${REF}\` · *By:* ${{ github.actor }}\n${COMMIT_MSG}\"
504+
}
505+
},
506+
{
507+
\"type\": \"section\",
508+
\"fields\": [
509+
{ \"type\": \"mrkdwn\", \"text\": \"$(status_icon $BUILD) Build & Test\" },
510+
{ \"type\": \"mrkdwn\", \"text\": \"$(status_icon $IT) Integration Tests\" },
511+
{ \"type\": \"mrkdwn\", \"text\": \"$(status_icon $DOCKER) Docker Push\" },
512+
{ \"type\": \"mrkdwn\", \"text\": \"$(status_icon $SMOKE) Smoke Test\" },
513+
{ \"type\": \"mrkdwn\", \"text\": \"$(status_icon $PREFLIGHT) Red Hat Preflight\" }
514+
]
515+
},
516+
{
517+
\"type\": \"context\",
518+
\"elements\": [
519+
{ \"type\": \"mrkdwn\", \"text\": \"<${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|View Run #${{ github.run_number }}>\" }
520+
]
521+
}
522+
]
523+
}"

0 commit comments

Comments
 (0)