diff --git a/.github/README.md b/.github/README.md
new file mode 100644
index 00000000..cf2f9c8a
--- /dev/null
+++ b/.github/README.md
@@ -0,0 +1,77 @@
+# GitHub Actions workflows
+
+CI/CD for this JHipster monolith (Java 21 + Spring Boot, Angular frontend, Maven wrapper, npm).
+
+| Workflow | File | Triggers | What it does |
+| ---------- | ------------------------------------------------------ | ---------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| CI | [`workflows/ci.yml`](workflows/ci.yml) | push to `main`/`master`, pull requests, manual | `build` (fast path: `./mvnw verify -DskipTests -Pprod`, uploads the jar), `backend` (`./mvnw -ntp verify` — surefire + failsafe + JaCoCo, publishes the JUnit report and uploads test results and coverage), `frontend` (`npm run lint`, `npm test` → Vitest with coverage) |
+| Validation | [`workflows/validation.yml`](workflows/validation.yml) | push, pull requests, weekly cron, manual | `format` (`npm run prettier:check`, `./mvnw spotless:check`, `./mvnw checkstyle:check` — the repo's `checkstyle.xml` is the JHipster nohttp ruleset) and `dependency-scan` (`npm audit`, Trivy filesystem scan uploaded as SARIF to code scanning) |
+| CD | [`workflows/cd.yml`](workflows/cd.yml) | `workflow_dispatch` only | Builds a container image with Jib, pushes it to Amazon ECR and deploys to Amazon ECS. **Mocked for the demo — see below.** |
+
+Both CI and Validation use concurrency groups that cancel superseded runs on branches
+(never on `main`/`master`), and least-privilege `permissions:` (`contents: read`, plus
+`security-events: write` only for the SARIF upload and `id-token: write` only for the CD jobs
+that assume an AWS role).
+
+Java and Node versions are set from `pom.xml` (`21`,
+`v24.13.0`) via the `JAVA_VERSION` / `NODE_VERSION` env blocks —
+update both together when the pom changes.
+
+## CD is mocked
+
+Every AWS identifier in `cd.yml` is a placeholder and none of the resources exist:
+
+| Setting | Placeholder value |
+| ---------------------------------- | --------------------------------------------------------------------------- |
+| Account / region | `123456789012` / `us-east-1` |
+| ECR registry | `123456789012.dkr.ecr.us-east-1.amazonaws.com` |
+| ECR repository | `demo-jhipster/jhipster-sample-application` |
+| ECS cluster / service | `demo-cluster` / `demo-jhipster-service` |
+| Kubernetes namespace (EKS variant) | `demo-jhipster` |
+| OIDC role ARNs | `arn:aws:iam::123456789012:role/demo-github-actions-deploy[-]` |
+| Environment URL | `https://.demo-jhipster.example.com` |
+
+Three independent gates keep it away from real infrastructure:
+
+1. it only runs on `workflow_dispatch` — nothing triggers it automatically;
+2. the `dry_run` input defaults to `true`, and while it is true every AWS-mutating step is
+ skipped and replaced by an echo of the command that would have run (the image is still
+ built locally with `jib:dockerBuild`, so the Jib config is genuinely exercised);
+3. even with `dry_run=false`, a real deployment additionally requires the repository variable
+ `ENABLE_REAL_DEPLOY` to be set to `true`.
+
+### Making it real
+
+1. Replace the placeholders above with real values.
+2. Create the GitHub environments `staging` and `production`; configure **required reviewers**
+ on `production` so the `deploy` job pauses for approval.
+3. Create an IAM role trusting GitHub's OIDC provider
+ (`token.actions.githubusercontent.com`) with permission to push to ECR and update the ECS
+ service, and point `role-to-assume` at it.
+4. Set the repository variable `ENABLE_REAL_DEPLOY=true` and run the workflow with
+ `dry_run=false`.
+
+### Secrets and variables
+
+No secrets are required for CI, Validation, or a dry-run CD.
+
+| Name | Kind | Used by | Notes |
+| -------------------- | ---------------------- | -------------------------- | ------------------------------------------------------------------------ |
+| `ENABLE_REAL_DEPLOY` | repository variable | `cd.yml` | Must equal `true` for a non-dry-run deployment. Unset in this demo repo. |
+| `GITHUB_TOKEN` | provided automatically | `ci.yml`, `validation.yml` | Publishing the test report and uploading SARIF. |
+
+Authentication to AWS uses OIDC role assumption, so no long-lived `AWS_ACCESS_KEY_ID` /
+`AWS_SECRET_ACCESS_KEY` secrets are needed.
+
+## Dependabot
+
+[`dependabot.yml`](dependabot.yml) watches the `maven`, `npm` and `github-actions` ecosystems
+weekly, with grouped minor/patch updates (plus dedicated Spring and Angular groups) to keep the
+PR volume low.
+
+## Action pinning
+
+Third-party actions are pinned to their major version tag (`actions/checkout@v4`,
+`aws-actions/configure-aws-credentials@v4`, `mikepenz/action-junit-report@v5`, …). The one
+exception is `aquasecurity/trivy-action`, which publishes no major-version tag and is therefore
+pinned to an exact release (`v0.36.0`); Dependabot's `github-actions` ecosystem keeps it current.
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 00000000..7bfff7af
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,52 @@
+version: 2
+updates:
+ - package-ecosystem: maven
+ directory: /
+ schedule:
+ interval: weekly
+ day: monday
+ time: '05:00'
+ open-pull-requests-limit: 5
+ labels: [dependencies, backend]
+ commit-message:
+ prefix: 'deps(maven)'
+ groups:
+ spring:
+ patterns:
+ - 'org.springframework*:*'
+ - 'io.micrometer:*'
+ maven-minor-and-patch:
+ update-types: [minor, patch]
+
+ - package-ecosystem: npm
+ directory: /
+ schedule:
+ interval: weekly
+ day: monday
+ time: '05:00'
+ open-pull-requests-limit: 5
+ labels: [dependencies, frontend]
+ commit-message:
+ prefix: 'deps(npm)'
+ groups:
+ angular:
+ patterns:
+ - '@angular*'
+ - '@angular-*'
+ - 'angular-eslint'
+ npm-minor-and-patch:
+ update-types: [minor, patch]
+
+ - package-ecosystem: github-actions
+ directory: /
+ schedule:
+ interval: weekly
+ day: monday
+ time: '05:00'
+ open-pull-requests-limit: 5
+ labels: [dependencies, ci]
+ commit-message:
+ prefix: 'deps(actions)'
+ groups:
+ github-actions:
+ patterns: ['*']
diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml
new file mode 100644
index 00000000..ff1b73b9
--- /dev/null
+++ b/.github/workflows/cd.yml
@@ -0,0 +1,261 @@
+# Deployment pipeline: build a container image with Jib, push it to Amazon ECR and
+# roll it out to Amazon ECS.
+#
+# ############################################################################
+# DEMO NOTICE — every AWS identifier below is a MOCKED PLACEHOLDER.
+# The account id (123456789012), region (us-east-1), role ARNs, ECR repository,
+# ECS cluster (demo-cluster) / namespace (demo-jhipster) and service names do not
+# exist. The workflow is additionally gated so it can never reach real
+# infrastructure by accident:
+# * it only runs via workflow_dispatch (no automatic trigger),
+# * DRY_RUN defaults to `true`; every AWS-mutating step is skipped while it is
+# true and replaced by an echo of the command that would have run,
+# * a real run additionally requires the repository variable
+# ENABLE_REAL_DEPLOY to be set to `true` (it is unset in this demo repo).
+# To make this real: set the variables/secrets listed in .github/README.md,
+# replace the placeholders below, and set ENABLE_REAL_DEPLOY=true.
+# ############################################################################
+name: CD
+
+on:
+ workflow_dispatch:
+ inputs:
+ environment:
+ description: Target environment
+ type: choice
+ options: [staging, production]
+ default: staging
+ required: true
+ dry_run:
+ description: Mock the deployment (no AWS calls)
+ type: boolean
+ default: true
+ image_tag:
+ description: Image tag to build and deploy (defaults to the commit SHA)
+ type: string
+ required: false
+
+concurrency:
+ # One deployment at a time per environment; deployments are never cancelled midway.
+ group: cd-${{ inputs.environment }}
+ cancel-in-progress: false
+
+permissions:
+ contents: read
+
+env:
+ JAVA_VERSION: '21'
+ NODE_VERSION: '24.13.0'
+ # MOCK VALUES — replace with real ones for an actual deployment.
+ AWS_REGION: us-east-1
+ AWS_ACCOUNT_ID: '123456789012'
+ ECR_REGISTRY: 123456789012.dkr.ecr.us-east-1.amazonaws.com
+ ECR_REPOSITORY: demo-jhipster/jhipster-sample-application
+ ECS_CLUSTER: demo-cluster
+ ECS_SERVICE: demo-jhipster-service
+ ECS_CONTAINER_NAME: jhipster-sample-application
+ # Kubernetes/EKS equivalent, kept for reference if the target is EKS instead of ECS.
+ K8S_NAMESPACE: demo-jhipster
+
+jobs:
+ build-image:
+ name: Build and push image
+ runs-on: ubuntu-latest
+ timeout-minutes: 45
+ environment: ${{ inputs.environment }}
+ permissions:
+ contents: read
+ id-token: write # required for OIDC role assumption
+ outputs:
+ image: ${{ steps.image.outputs.image }}
+ dry_run: ${{ steps.mode.outputs.dry_run }}
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Resolve run mode
+ id: mode
+ # Real AWS calls need BOTH dry_run=false and the repo variable ENABLE_REAL_DEPLOY=true.
+ run: |
+ if [ "${{ inputs.dry_run }}" = "false" ] && [ "${{ vars.ENABLE_REAL_DEPLOY }}" = "true" ]; then
+ echo "dry_run=false" >> "$GITHUB_OUTPUT"
+ echo "::notice::Running a REAL deployment to ${{ inputs.environment }}"
+ else
+ echo "dry_run=true" >> "$GITHUB_OUTPUT"
+ echo "::notice::DRY RUN — no AWS calls will be made (mocked demo pipeline)"
+ fi
+
+ - name: Set up Java
+ uses: actions/setup-java@v4
+ with:
+ distribution: temurin
+ java-version: ${{ env.JAVA_VERSION }}
+ cache: maven
+
+ - name: Set up Node
+ uses: actions/setup-node@v4
+ with:
+ node-version: ${{ env.NODE_VERSION }}
+ cache: npm
+
+ - name: Install frontend dependencies
+ run: npm ci
+
+ - name: Compute image reference
+ id: image
+ run: |
+ TAG="${{ inputs.image_tag }}"
+ [ -n "$TAG" ] || TAG="${GITHUB_SHA::12}"
+ echo "tag=$TAG" >> "$GITHUB_OUTPUT"
+ echo "image=${ECR_REGISTRY}/${ECR_REPOSITORY}:${TAG}" >> "$GITHUB_OUTPUT"
+
+ # MOCK ROLE ARN — a real setup points this at an IAM role trusting GitHub's OIDC provider.
+ - name: Configure AWS credentials (OIDC)
+ if: steps.mode.outputs.dry_run == 'false'
+ uses: aws-actions/configure-aws-credentials@v4
+ with:
+ role-to-assume: arn:aws:iam::123456789012:role/demo-github-actions-deploy
+ role-session-name: gha-cd-${{ github.run_id }}
+ aws-region: ${{ env.AWS_REGION }}
+
+ - name: Log in to Amazon ECR
+ if: steps.mode.outputs.dry_run == 'false'
+ uses: aws-actions/amazon-ecr-login@v2
+
+ # Dry run: build the image into the local Docker daemon so the Jib
+ # configuration is genuinely exercised without any registry push.
+ - name: Build image locally (dry run)
+ if: steps.mode.outputs.dry_run == 'true'
+ run: |
+ ./mvnw -ntp -B verify -DskipTests -Pprod jib:dockerBuild \
+ -Dimage=${{ steps.image.outputs.image }}
+ echo "::notice::[MOCK] would push ${{ steps.image.outputs.image }} to Amazon ECR"
+
+ - name: Build and push image to ECR
+ if: steps.mode.outputs.dry_run == 'false'
+ run: |
+ ./mvnw -ntp -B verify -DskipTests -Pprod jib:build \
+ -Dimage=${{ steps.image.outputs.image }}
+
+ deploy:
+ name: Deploy to ${{ inputs.environment }}
+ needs: build-image
+ runs-on: ubuntu-latest
+ timeout-minutes: 30
+ # GitHub environment: `production` is configured with required reviewers, so a
+ # production deployment pauses here until it is approved.
+ environment:
+ name: ${{ inputs.environment }}
+ url: https://${{ inputs.environment }}.demo-jhipster.example.com
+ permissions:
+ contents: read
+ id-token: write
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Configure AWS credentials (OIDC)
+ if: needs.build-image.outputs.dry_run == 'false'
+ uses: aws-actions/configure-aws-credentials@v4
+ with:
+ # MOCK ROLE ARN — per-environment deploy roles.
+ role-to-assume: arn:aws:iam::123456789012:role/demo-github-actions-deploy-${{ inputs.environment }}
+ role-session-name: gha-deploy-${{ github.run_id }}
+ aws-region: ${{ env.AWS_REGION }}
+
+ - name: Render ECS task definition
+ run: |
+ # MOCK task definition — a real pipeline would download the live one with
+ # `aws ecs describe-task-definition` instead of templating it here.
+ cat > task-definition.json <<'JSON'
+ {
+ "family": "demo-jhipster",
+ "networkMode": "awsvpc",
+ "requiresCompatibilities": ["FARGATE"],
+ "cpu": "1024",
+ "memory": "2048",
+ "executionRoleArn": "arn:aws:iam::123456789012:role/demo-ecs-task-execution",
+ "taskRoleArn": "arn:aws:iam::123456789012:role/demo-ecs-task",
+ "containerDefinitions": [
+ {
+ "name": "jhipster-sample-application",
+ "image": "PLACEHOLDER_IMAGE",
+ "essential": true,
+ "portMappings": [{ "containerPort": 8080, "protocol": "tcp" }],
+ "environment": [
+ { "name": "SPRING_PROFILES_ACTIVE", "value": "prod,api-docs" },
+ { "name": "JHIPSTER_SLEEP", "value": "0" }
+ ],
+ "secrets": [
+ {
+ "name": "SPRING_DATASOURCE_PASSWORD",
+ "valueFrom": "arn:aws:secretsmanager:us-east-1:123456789012:secret:demo-jhipster/db-password"
+ }
+ ],
+ "healthCheck": {
+ "command": ["CMD-SHELL", "curl -f http://localhost:8080/management/health || exit 1"],
+ "interval": 30,
+ "timeout": 5,
+ "retries": 3,
+ "startPeriod": 90
+ },
+ "logConfiguration": {
+ "logDriver": "awslogs",
+ "options": {
+ "awslogs-group": "/ecs/demo-jhipster",
+ "awslogs-region": "us-east-1",
+ "awslogs-stream-prefix": "ecs"
+ }
+ }
+ }
+ ]
+ }
+ JSON
+
+ - name: Set image in task definition
+ id: task-def
+ uses: aws-actions/amazon-ecs-render-task-definition@v1
+ with:
+ task-definition: task-definition.json
+ container-name: ${{ env.ECS_CONTAINER_NAME }}
+ image: ${{ needs.build-image.outputs.image }}
+
+ - name: Mock deployment (dry run)
+ if: needs.build-image.outputs.dry_run == 'true'
+ run: |
+ echo "::notice::[MOCK] aws ecs update-service --cluster ${ECS_CLUSTER} --service ${ECS_SERVICE} --task-definition demo-jhipster --force-new-deployment"
+ echo "[MOCK] image : ${{ needs.build-image.outputs.image }}"
+ echo "[MOCK] environment : ${{ inputs.environment }}"
+ echo "[MOCK] cluster : ${ECS_CLUSTER} (region ${AWS_REGION})"
+ echo "[MOCK] EKS variant : kubectl -n ${K8S_NAMESPACE} set image deployment/jhipster-sample-application app=${{ needs.build-image.outputs.image }}"
+ echo "--- rendered task definition ---"
+ cat "${{ steps.task-def.outputs.task-definition }}"
+ echo "::notice::[MOCK] would wait for the ECS service to reach a steady state"
+
+ - name: Deploy to Amazon ECS
+ if: needs.build-image.outputs.dry_run == 'false'
+ uses: aws-actions/amazon-ecs-deploy-task-definition@v2
+ with:
+ task-definition: ${{ steps.task-def.outputs.task-definition }}
+ cluster: ${{ env.ECS_CLUSTER }}
+ service: ${{ env.ECS_SERVICE }}
+ wait-for-service-stability: true
+
+ - name: Smoke test
+ run: |
+ URL="https://${{ inputs.environment }}.demo-jhipster.example.com/management/health"
+ if [ "${{ needs.build-image.outputs.dry_run }}" = "true" ]; then
+ echo "::notice::[MOCK] would curl ${URL} and assert {\"status\":\"UP\"}"
+ else
+ curl --fail --retry 10 --retry-delay 15 --retry-connrefused "$URL"
+ fi
+
+ - name: Summary
+ run: |
+ {
+ echo "### CD run"
+ echo ""
+ echo "| field | value |"
+ echo "| --- | --- |"
+ echo "| environment | ${{ inputs.environment }} |"
+ echo "| image | \`${{ needs.build-image.outputs.image }}\` |"
+ echo "| mode | ${{ needs.build-image.outputs.dry_run == 'true' && 'DRY RUN (mocked, no AWS calls)' || 'real deployment' }} |"
+ } >> "$GITHUB_STEP_SUMMARY"
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 00000000..e98b0ec8
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,148 @@
+# Continuous integration for the JHipster monolith (Java 21 + Spring Boot backend, Angular frontend).
+name: CI
+
+on:
+ push:
+ branches: [main, master]
+ pull_request:
+ branches: [main, master]
+ workflow_dispatch:
+
+# Cancel superseded runs on the same ref (but never cancel a run on main/master).
+concurrency:
+ group: ci-${{ github.workflow }}-${{ github.ref }}
+ cancel-in-progress: ${{ github.ref != 'refs/heads/main' && github.ref != 'refs/heads/master' }}
+
+permissions:
+ contents: read
+
+env:
+ # Kept in sync with pom.xml: 21, v24.13.0
+ JAVA_VERSION: '21'
+ NODE_VERSION: '24.13.0'
+
+jobs:
+ # Fast path: compiles backend + frontend without running any test, so obvious
+ # breakage fails within a couple of minutes instead of the full verify cycle.
+ build:
+ name: Build (no tests)
+ runs-on: ubuntu-latest
+ timeout-minutes: 30
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Set up Java
+ uses: actions/setup-java@v4
+ with:
+ distribution: temurin
+ java-version: ${{ env.JAVA_VERSION }}
+ cache: maven
+
+ - name: Set up Node
+ uses: actions/setup-node@v4
+ with:
+ node-version: ${{ env.NODE_VERSION }}
+ cache: npm
+
+ - name: Install frontend dependencies
+ run: npm ci
+
+ - name: Package application (prod profile, tests skipped)
+ run: ./mvnw -ntp -B verify -DskipTests -Pprod
+
+ - name: Upload application jar
+ uses: actions/upload-artifact@v4
+ with:
+ name: application-jar
+ path: target/*.jar
+ if-no-files-found: error
+ retention-days: 7
+
+ backend:
+ name: Backend tests
+ runs-on: ubuntu-latest
+ timeout-minutes: 45
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Set up Java
+ uses: actions/setup-java@v4
+ with:
+ distribution: temurin
+ java-version: ${{ env.JAVA_VERSION }}
+ cache: maven
+
+ - name: Set up Node
+ uses: actions/setup-node@v4
+ with:
+ node-version: ${{ env.NODE_VERSION }}
+ cache: npm
+
+ # `./mvnw verify` triggers the frontend build through frontend-maven-plugin,
+ # so the npm dependencies have to be present.
+ - name: Install frontend dependencies
+ run: npm ci
+
+ # Unit tests (surefire) + integration tests (failsafe) + JaCoCo reports.
+ - name: Backend build and tests
+ run: ./mvnw -ntp -B verify
+
+ - name: Publish test report
+ uses: mikepenz/action-junit-report@v5
+ if: always()
+ with:
+ report_paths: 'target/surefire-reports/TEST-*.xml,target/failsafe-reports/TEST-*.xml'
+ check_name: Backend test report
+ fail_on_failure: false
+
+ - name: Upload backend test results
+ uses: actions/upload-artifact@v4
+ if: always()
+ with:
+ name: backend-test-results
+ path: |
+ target/surefire-reports/
+ target/failsafe-reports/
+ if-no-files-found: warn
+ retention-days: 7
+
+ - name: Upload JaCoCo coverage
+ uses: actions/upload-artifact@v4
+ if: always()
+ with:
+ name: jacoco-coverage
+ path: target/site/jacoco*/
+ if-no-files-found: warn
+ retention-days: 7
+
+ frontend:
+ name: Frontend lint and tests
+ runs-on: ubuntu-latest
+ timeout-minutes: 30
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Set up Node
+ uses: actions/setup-node@v4
+ with:
+ node-version: ${{ env.NODE_VERSION }}
+ cache: npm
+
+ - name: Install frontend dependencies
+ run: npm ci
+
+ - name: Lint
+ run: npm run lint
+
+ # `npm test` runs `ng test --coverage` (Vitest) and lints via the pretest hook.
+ - name: Unit tests with coverage
+ run: npm test
+
+ - name: Upload frontend coverage
+ uses: actions/upload-artifact@v4
+ if: always()
+ with:
+ name: frontend-coverage
+ path: target/test-results/
+ if-no-files-found: warn
+ retention-days: 7
diff --git a/.github/workflows/validation.yml b/.github/workflows/validation.yml
new file mode 100644
index 00000000..1a1b3bf9
--- /dev/null
+++ b/.github/workflows/validation.yml
@@ -0,0 +1,119 @@
+# Static validation: formatting, code style and dependency vulnerability scanning.
+name: Validation
+
+on:
+ push:
+ branches: [main, master]
+ pull_request:
+ branches: [main, master]
+ schedule:
+ # Weekly re-scan so newly published CVEs are surfaced without a code change.
+ - cron: '17 4 * * 1'
+ workflow_dispatch:
+
+concurrency:
+ group: validation-${{ github.workflow }}-${{ github.ref }}
+ cancel-in-progress: ${{ github.ref != 'refs/heads/main' && github.ref != 'refs/heads/master' }}
+
+permissions:
+ contents: read
+
+env:
+ JAVA_VERSION: '21'
+ NODE_VERSION: '24.13.0'
+
+jobs:
+ format:
+ name: Formatting and code style
+ runs-on: ubuntu-latest
+ timeout-minutes: 20
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Set up Java
+ uses: actions/setup-java@v4
+ with:
+ distribution: temurin
+ java-version: ${{ env.JAVA_VERSION }}
+ cache: maven
+
+ - name: Set up Node
+ uses: actions/setup-node@v4
+ with:
+ node-version: ${{ env.NODE_VERSION }}
+ cache: npm
+
+ - name: Install frontend dependencies
+ run: npm ci
+
+ # Prettier owns formatting for both the TypeScript sources and (via
+ # prettier-plugin-java) the Java sources; spotless applies the same rules
+ # from Maven, so `spotless:check` catches anything committed unformatted.
+ - name: Prettier check
+ run: npm run prettier:check
+
+ - name: Spotless check
+ run: ./mvnw -ntp -B spotless:check
+
+ # checkstyle.xml in this repo is the JHipster nohttp ruleset.
+ - name: Checkstyle (nohttp)
+ run: ./mvnw -ntp -B checkstyle:check
+
+ dependency-scan:
+ name: Dependency vulnerability scan
+ runs-on: ubuntu-latest
+ timeout-minutes: 30
+ permissions:
+ contents: read
+ security-events: write
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Set up Java
+ uses: actions/setup-java@v4
+ with:
+ distribution: temurin
+ java-version: ${{ env.JAVA_VERSION }}
+ cache: maven
+
+ - name: Set up Node
+ uses: actions/setup-node@v4
+ with:
+ node-version: ${{ env.NODE_VERSION }}
+ cache: npm
+
+ - name: Install frontend dependencies
+ run: npm ci
+
+ # Reports only: a transitive CVE in a dependency should not block a PR that
+ # does not touch dependencies. Dependabot (see .github/dependabot.yml) opens
+ # the corresponding upgrade PRs.
+ - name: npm audit (high and above)
+ run: npm audit --audit-level=high || true
+
+ - name: Trivy filesystem scan (SARIF)
+ uses: aquasecurity/trivy-action@v0.36.0
+ with:
+ scan-type: fs
+ scan-ref: .
+ scanners: vuln
+ severity: HIGH,CRITICAL
+ ignore-unfixed: true
+ format: sarif
+ output: trivy-results.sarif
+
+ - name: Upload SARIF to code scanning
+ uses: github/codeql-action/upload-sarif@v3
+ if: always()
+ continue-on-error: true
+ with:
+ sarif_file: trivy-results.sarif
+
+ - name: Upload scan artifact
+ uses: actions/upload-artifact@v4
+ if: always()
+ with:
+ name: trivy-results
+ path: trivy-results.sarif
+ if-no-files-found: warn
+ retention-days: 7
diff --git a/README.md b/README.md
index 2b0b28e8..f7170a2e 100644
--- a/README.md
+++ b/README.md
@@ -275,9 +275,19 @@ docker compose -f src/main/docker/app.yml up -d
For more information refer to [Docker and Docker-Compose](https://www.jhipster.tech/documentation-archive/v9.0.0-beta.3/docker-compose/), this page also contains information on the Docker Compose sub-generator (`jhipster docker-compose`), which is able to generate Docker configurations for one or several JHipster applications.
-## Continuous Integration (optional)
+## Continuous Integration / Continuous Deployment
-To configure CI for your project, run the ci-cd sub-generator (`jhipster ci-cd`), this will let you generate configuration files for a number of Continuous Integration systems. Consult the [Setting up Continuous Integration](https://www.jhipster.tech/documentation-archive/v9.0.0-beta.3/setting-up-ci/) page for more information.
+GitHub Actions workflows live in [`.github/workflows`](.github/workflows):
+
+- **CI** (`ci.yml`) — on push to `main`/`master` and on pull requests: a build-only fast path, backend build and tests (`./mvnw -ntp verify`, JUnit report + JaCoCo coverage artifacts) and frontend lint + Vitest tests.
+- **Validation** (`validation.yml`) — Prettier / Spotless / Checkstyle (nohttp) checks and a dependency vulnerability scan (`npm audit` + Trivy SARIF).
+- **CD** (`cd.yml`) — Jib image build, push to Amazon ECR and deploy to Amazon ECS via OIDC, targeting the `staging` and `production` GitHub environments. **All AWS values are mocked placeholders and the workflow is dry-run gated**, so it never touches real infrastructure.
+
+Dependency updates are handled by [`.github/dependabot.yml`](.github/dependabot.yml) (maven, npm, github-actions).
+
+See [`.github/README.md`](.github/README.md) for the full description, the mocked-value table and the required secrets/variables.
+
+To generate configuration for other CI systems, run the ci-cd sub-generator (`jhipster ci-cd`), this will let you generate configuration files for a number of Continuous Integration systems. Consult the [Setting up Continuous Integration](https://www.jhipster.tech/documentation-archive/v9.0.0-beta.3/setting-up-ci/) page for more information.
## References