Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
The diff you're trying to view is too large. We only load the first 3000 changed files.
6 changes: 2 additions & 4 deletions .agents/skills/fix-ci/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,12 +79,10 @@ pnpm run check
`check` runs every leg CI runs except those needing Docker or a live credential — `docs:lint`
included. If `check` is green and CI is not, the difference is one of those.

Server tests need `-P'!quick'`. The `quick` profile is activated by the presence of generated GraphQL
sources and sets `maven.test.skip=true`, so a plain `./mvnw test` prints BUILD SUCCESS having run
nothing:
The server reactor builds generated clients before the application. Run the unit tier with:

```bash
cd server && ./mvnw test -P'!quick' -Dsurefire.includedGroups=unit -T 2C --batch-mode -q
cd server && ./mvnw -pl application -am test -Dsurefire.includedGroups=unit -T 2C --batch-mode -q
```

`-Dgroups` is ignored: the POM binds `${surefire.includedGroups}`, and a POM element beats the
Expand Down
12 changes: 6 additions & 6 deletions .agents/skills/land-pr/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,10 @@ pnpm run format
pnpm run check
```

`check` is the whole gate — every leg is listed under `check` in the root `package.json`, and every
one of them also runs in CI. Formatting must never be the reason a remote build fails.
`check` is the complete local quality gate — every leg is listed under `check` in the root
`package.json`, and every one also runs in CI. CI additionally runs service tests, builds, images,
security checks, and workflow-specific gates. Formatting must never be the reason a remote build
fails.

## 4. Regenerate what your change invalidated

Expand All @@ -68,12 +70,10 @@ busy — HTTP, management, or the JMX port it defaults to. Pass free ports; the

```bash
pnpm run test:webapp
cd server && ./mvnw test -P'!quick' -Dsurefire.includedGroups=unit -T 2C --batch-mode -q
cd server && ./mvnw -pl application -am test -Dsurefire.includedGroups=unit -T 2C --batch-mode -q
```

`-P'!quick'` is not optional: the `quick` profile is activated by the presence of generated GraphQL
sources and sets `maven.test.skip=true`, so a plain `./mvnw test` prints BUILD SUCCESS having run
nothing.
`-am` is required so a cold checkout builds the generated-client dependency before the application.

## 6. Re-run format + check

Expand Down
5 changes: 5 additions & 0 deletions .changeset/proud-rooms-move.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"hephaestus": patch
---
Comment thread
coderabbitai[bot] marked this conversation as resolved.

Updates Spring Boot to 4.0.7 for CVE-2026-40992 and the PostgreSQL driver to 42.7.12 for CVE-2026-54291.
6 changes: 2 additions & 4 deletions .claude/skills/fix-ci/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,12 +79,10 @@ pnpm run check
`check` runs every leg CI runs except those needing Docker or a live credential — `docs:lint`
included. If `check` is green and CI is not, the difference is one of those.

Server tests need `-P'!quick'`. The `quick` profile is activated by the presence of generated GraphQL
sources and sets `maven.test.skip=true`, so a plain `./mvnw test` prints BUILD SUCCESS having run
nothing:
The server reactor builds generated clients before the application. Run the unit tier with:

```bash
cd server && ./mvnw test -P'!quick' -Dsurefire.includedGroups=unit -T 2C --batch-mode -q
cd server && ./mvnw -pl application -am test -Dsurefire.includedGroups=unit -T 2C --batch-mode -q
```

`-Dgroups` is ignored: the POM binds `${surefire.includedGroups}`, and a POM element beats the
Expand Down
12 changes: 6 additions & 6 deletions .claude/skills/land-pr/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,10 @@ pnpm run format
pnpm run check
```

`check` is the whole gate — every leg is listed under `check` in the root `package.json`, and every
one of them also runs in CI. Formatting must never be the reason a remote build fails.
`check` is the complete local quality gate — every leg is listed under `check` in the root
`package.json`, and every one also runs in CI. CI additionally runs service tests, builds, images,
security checks, and workflow-specific gates. Formatting must never be the reason a remote build
fails.

## 4. Regenerate what your change invalidated

Expand All @@ -68,12 +70,10 @@ busy — HTTP, management, or the JMX port it defaults to. Pass free ports; the

```bash
pnpm run test:webapp
cd server && ./mvnw test -P'!quick' -Dsurefire.includedGroups=unit -T 2C --batch-mode -q
cd server && ./mvnw -pl application -am test -Dsurefire.includedGroups=unit -T 2C --batch-mode -q
```

`-P'!quick'` is not optional: the `quick` profile is activated by the presence of generated GraphQL
sources and sets `maven.test.skip=true`, so a plain `./mvnw test` prints BUILD SUCCESS having run
nothing.
`-am` is required so a cold checkout builds the generated-client dependency before the application.

## 6. Re-run format + check

Expand Down
2 changes: 1 addition & 1 deletion .github/CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ renovate.json @ls1intum/hephaestus-maintainers
server/ @ls1intum/hephaestus-maintainers

# Auth / identity (Account, IdentityLink, JWT issuance, oauth2Login) — see ADR 0017
server/src/main/java/de/tum/cit/aet/hephaestus/core/auth/ @FelixTJDietrich @ls1intum/hephaestus-maintainers
server/application/src/main/java/de/tum/cit/aet/hephaestus/core/auth/ @FelixTJDietrich @ls1intum/hephaestus-maintainers
docs/decisions/0017-replace-keycloak-with-spring-native-auth.md @FelixTJDietrich
docs/auth-glossary.md @FelixTJDietrich
docs/auth-architecture.md @FelixTJDietrich
Expand Down
41 changes: 29 additions & 12 deletions .github/actions/setup-caches/action.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: "Setup CI caches"
description: "Caches Maven repo + generated sources, Playwright browsers, and Storybook builds. Node/pnpm setup happens in the calling workflow via pnpm/action-setup + actions/setup-node (cache: pnpm)."
description: "Caches Maven dependencies, generated-client build outputs, Playwright browsers, and Storybook builds."
inputs:
cache-type:
description: "Type of cache to setup"
Expand All @@ -13,28 +13,45 @@ runs:
using: "composite"
steps:
- name: Set up JDK 21
id: java
if: startsWith(inputs.cache-type, 'application-server-') || contains(fromJSON('["webapp-e2e", "server-contracts"]'), inputs.cache-type)
uses: actions/setup-java@dd06d9cba3e5552c54d9f8ea23572deb30010f7c # v6.0.0
with:
distribution: "temurin"
java-version: "21"

- name: Cache Maven repo
# server/target/generated-sources is deliberately NOT cached. actions/cache's
# restore-keys fallback can restore a stale generated-sources tree from a prior
# build (e.g., from before a Java package rename); the `quick` profile in pom.xml
# then activates on the present directory and skips codegen, causing compile
# failures because the cached classes don't match the current sources. Codegen
# runs in ~5s — much cheaper than that failure mode.
if: startsWith(inputs.cache-type, 'application-server-') || contains(fromJSON('["webapp-e2e", "server-contracts"]'), inputs.cache-type)
- name: Restore Maven dependencies
if: github.event_name == 'pull_request' && (startsWith(inputs.cache-type, 'application-server-') || contains(fromJSON('["webapp-e2e", "server-contracts"]'), inputs.cache-type))
uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: ~/.m2/repository
key: ${{ inputs.os }}-maven-${{ hashFiles('server/**/pom.xml', 'server/.mvn/extensions.xml', 'server/.mvn/wrapper/maven-wrapper.properties') || 'no-pom' }}
restore-keys: |
${{ inputs.os }}-maven-

- name: Cache Maven dependencies
if: github.ref == format('refs/heads/{0}', github.event.repository.default_branch) && contains(fromJSON('["push", "schedule", "workflow_dispatch"]'), github.event_name) && (startsWith(inputs.cache-type, 'application-server-') || contains(fromJSON('["webapp-e2e", "server-contracts"]'), inputs.cache-type))
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: |
~/.m2/repository
key: ${{ inputs.os }}-maven-${{ hashFiles('server/pom.xml') || 'no-pom' }}
path: ~/.m2/repository
key: ${{ inputs.os }}-maven-${{ hashFiles('server/**/pom.xml', 'server/.mvn/extensions.xml', 'server/.mvn/wrapper/maven-wrapper.properties') || 'no-pom' }}
restore-keys: |
${{ inputs.os }}-maven-

- name: Restore generated clients
if: github.event_name == 'pull_request' && (startsWith(inputs.cache-type, 'application-server-') || contains(fromJSON('["webapp-e2e", "server-contracts"]'), inputs.cache-type))
uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: ~/.m2/build-cache
key: ${{ inputs.os }}-${{ steps.java.outputs.distribution }}-${{ steps.java.outputs.version }}-generated-clients-${{ hashFiles('server/pom.xml', 'server/generated-clients/pom.xml', 'server/.mvn/**', 'server/generated-clients/src/**') }}

- name: Cache generated clients
if: github.ref == format('refs/heads/{0}', github.event.repository.default_branch) && contains(fromJSON('["push", "schedule", "workflow_dispatch"]'), github.event_name) && (startsWith(inputs.cache-type, 'application-server-') || contains(fromJSON('["webapp-e2e", "server-contracts"]'), inputs.cache-type))
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: ~/.m2/build-cache
key: ${{ inputs.os }}-${{ steps.java.outputs.distribution }}-${{ steps.java.outputs.version }}-generated-clients-${{ hashFiles('server/pom.xml', 'server/generated-clients/pom.xml', 'server/.mvn/**', 'server/generated-clients/src/**') }}

- name: Cache Playwright browsers
if: inputs.cache-type == 'webapp-storybook'
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/ci-docker-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ jobs:
# Paketo Cloud Native Buildpacks via spring-boot:build-image, with Application CDS.
# See docs/admin/buildpacks-cds-decision.md and pom.xml's <image> block.
use-buildpacks: true
maven-module: "server"
maven-module: "server/application"
registry: "ghcr.io"
# amd64-only on PRs (main/release build both arches). See reusable-docker-build.yml.
single-arch: ${{ github.event_name == 'pull_request' }}
Expand Down
8 changes: 4 additions & 4 deletions .github/workflows/ci-profile.yml
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ jobs:
continue-on-error: true
run: >-
pnpm run summarize:test-results "Server Integration Profile"
server/target/surefire-reports ci-metrics/server-integration-profile.json
server/application/target/surefire-reports ci-metrics/server-integration-profile.json
ci-metrics/server-integration.log ci-metrics/server-integration-resource.txt

- name: Enforce performance budgets
Expand All @@ -65,7 +65,7 @@ jobs:
continue-on-error: true
run: >-
jfr print --events hephaestus.test.DatabaseCleanup
server/target/integration-profile.jfr
server/application/target/integration-profile.jfr
> ci-metrics/database-cleanup.jfr.txt

- name: Upload profile
Expand All @@ -74,8 +74,8 @@ jobs:
with:
name: server-integration-profile-${{ github.run_id }}
path: |
server/target/integration-profile.jfr
server/target/surefire-reports
server/application/target/integration-profile.jfr
server/application/target/surefire-reports
ci-metrics/server-integration-profile.json
ci-metrics/server-integration.log
ci-metrics/server-integration-resource.txt
Expand Down
8 changes: 4 additions & 4 deletions .github/workflows/ci-quality-gates.yml
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ jobs:
pnpm run format:java:check || { FMT_OK=false; ISSUES_FOUND+=("Java formatting failed. Run: pnpm run format:java"); }
pnpm run lint:java || { PMD_OK=false; ISSUES_FOUND+=("PMD found violations. Run: pnpm run lint:java:report"); }
if [ "$PMD_OK" = "true" ] && [ "${{ inputs.pmd_canary }}" = "true" ]; then
PMD_CANARY=server/src/main/java/de/tum/cit/aet/hephaestus/Application.java
PMD_CANARY=server/application/src/main/java/de/tum/cit/aet/hephaestus/Application.java
cp "$PMD_CANARY" "$RUNNER_TEMP/Application.java"
trap 'cp "$RUNNER_TEMP/Application.java" "$PMD_CANARY"' EXIT
sed -i '/public class Application {/a\ private int deliberatelyUnusedPmdCanary;' "$PMD_CANARY"
Expand Down Expand Up @@ -300,7 +300,7 @@ jobs:
export SPRING_DATASOURCE_USERNAME="root"
export SPRING_DATASOURCE_PASSWORD="root"

if ! (cd server && ./mvnw test -P'!quick' -Dsurefire.includedGroups=database -Dmaven.test.skip=false -DskipCoverage=true --quiet); then
if ! (cd server && ./mvnw test -pl application -am -Dsurefire.includedGroups=database -DskipCoverage=true --quiet); then
echo "::error::Maven compilation or database contract tests failed. Fix the reported error before continuing."
echo "### Database Validation" >> $GITHUB_STEP_SUMMARY
echo "| Check | Status | Fix |" >> $GITHUB_STEP_SUMMARY
Expand All @@ -315,9 +315,9 @@ jobs:
# liquibase:update — so this step is ALSO the empty→head migration-chain replay gate (a
# changelog that doesn't apply fails here). Keep that apply intact.
scripts/db-utils.sh draft-changelog || ISSUES_FOUND+=("Schema check / migration-chain apply failed. Run: pnpm run db:draft-changelog")
if [ -f "server/src/main/resources/db/changelog_new.xml" ]; then
if [ -f "server/application/src/main/resources/db/changelog_new.xml" ]; then
echo "::error::Schema drift detected. Run: pnpm run db:draft-changelog"
cat server/src/main/resources/db/changelog_new.xml
cat server/application/src/main/resources/db/changelog_new.xml
ISSUES_FOUND+=("Schema drift detected")
fi

Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/ci-security-scan.yml
Original file line number Diff line number Diff line change
Expand Up @@ -125,8 +125,8 @@ jobs:
RELEASED_REF: ${{ github.event_name == 'pull_request' && github.base_ref || 'main' }}
run: |
set -euo pipefail
CHANGELOG_DIR="server/src/main/resources/db/changelog"
MASTER="server/src/main/resources/db/master.xml"
CHANGELOG_DIR="server/application/src/main/resources/db/changelog"
MASTER="server/application/src/main/resources/db/master.xml"
FAILED=false

VIOLATIONS=$(git diff --name-only --diff-filter=MDR "$BASE" HEAD -- "$CHANGELOG_DIR")
Expand Down Expand Up @@ -177,7 +177,7 @@ jobs:
if grep -rEnI "$NEEDLE" \
--exclude-dir=node_modules --exclude-dir=target --exclude-dir=.git \
. \
| grep -vE '^\./(MIGRATION\.md|docs/admin/agent-image-digests\.md|docs/decisions/0031-.*\.md|server/src/test/java/de/tum/cit/aet/hephaestus/agent/sandbox/AgentImageReferenceGuardTest\.java):' ; then
| grep -vE '^\./(MIGRATION\.md|docs/admin/agent-image-digests\.md|docs/decisions/0031-.*\.md|server/application/src/test/java/de/tum/cit/aet/hephaestus/agent/sandbox/AgentImageReferenceGuardTest\.java):' ; then
echo "::error::A release-channel agent image tag resolves to another release's image (ADR 0031). Leave the reference unset so it follows this deployment's image tag, or pin a digest."
exit 1
fi
Expand Down
87 changes: 87 additions & 0 deletions .github/workflows/ci-server-clean-reference.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
name: Server Phase Reference

on:
workflow_dispatch:
schedule:
- cron: "23 3 * * 2"

permissions:
contents: read

concurrency:
group: server-clean-reference
cancel-in-progress: false

jobs:
verify:
name: Profile clean server phases
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false

- uses: actions/setup-java@dd06d9cba3e5552c54d9f8ea23572deb30010f7c # v6.0.0
with:
distribution: temurin
java-version: "21"
cache: maven
cache-dependency-path: "server/**/pom.xml"

- name: Profile generated clients
working-directory: server
run: |
mkdir -p ../ci-metrics/generated
./mvnw clean install -pl generated-clients -am -DskipTests \
-Dmaven.build.cache.enabled=false -Dprofile=generated-clients -DprofileFormat=JSON \
-Dmaven-profiler-report-directory=../ci-metrics/generated --batch-mode
cp generated-clients/target/hephaestus-generated-clients-*.jar ../ci-metrics/generated-clients-first.jar

- name: Verify generated artifact reproducibility
working-directory: server
run: |
mkdir -p ../ci-metrics/reproducibility
./mvnw clean package -pl generated-clients -am -DskipTests \
-Dmaven.build.cache.enabled=false -Dprofile=reproducibility -DprofileFormat=JSON \
-Dmaven-profiler-report-directory=../ci-metrics/reproducibility --batch-mode
cmp ../ci-metrics/generated-clients-first.jar generated-clients/target/hephaestus-generated-clients-*.jar
sha256sum ../ci-metrics/generated-clients-first.jar \
generated-clients/target/hephaestus-generated-clients-*.jar \
> ../ci-metrics/generated-clients-sha256.txt

- name: Profile application and test compilation
working-directory: server
run: |
mkdir -p ../ci-metrics/compilation
./mvnw -f application/pom.xml test-compile -DskipTests \
-Dmaven.build.cache.enabled=false -Dprofile=compilation -DprofileFormat=JSON \
-Dmaven-profiler-report-directory=../ci-metrics/compilation --batch-mode

- name: Profile unit and architecture execution
working-directory: server
run: |
mkdir -p ../ci-metrics/unit-architecture
./mvnw -f application/pom.xml test -Parchitecture-tests \
-Dsurefire.includedGroups=unit,architecture -DskipCoverage=false \
-Dmaven.build.cache.enabled=false -Dprofile=unit-architecture -DprofileFormat=JSON \
-Dmaven-profiler-report-directory=../ci-metrics/unit-architecture --batch-mode

- name: Profile integration execution
working-directory: server
run: |
mkdir -p ../ci-metrics/integration
./mvnw -f application/pom.xml test -Dsurefire.includedGroups=integration -Dparallel=none \
-Dmaven.build.cache.enabled=false -Dprofile=integration -DprofileFormat=JSON \
-Dmaven-profiler-report-directory=../ci-metrics/integration --batch-mode

- name: Upload phase profiles
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0 # v7.0.1
with:
name: server-phase-reference-${{ github.run_id }}
path: |
ci-metrics
server/application/target/surefire-reports
if-no-files-found: error
retention-days: 30
Loading
Loading