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