diff --git a/.devcontainer/base/docker-compose.yml b/.devcontainer/base/docker-compose.yml index 3ffa0384ef..0775d9592d 100644 --- a/.devcontainer/base/docker-compose.yml +++ b/.devcontainer/base/docker-compose.yml @@ -42,7 +42,7 @@ services: login-integration: container_name: login-integration - image: "${LOGIN_TAG:-ghcr.io/zitadel/zitadel-login:v4.0.0-rc.2}" + image: "${LOGIN_TAG:-zitadel-login:local}" env_file: ../../apps/login/apps/login/.env.test network_mode: service:devcontainer environment: diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index fe88f7cea9..12dd1359a3 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -110,7 +110,6 @@ jobs: login-container: uses: ./.github/workflows/login-container.yml - if: ${{ github.event_name == 'workflow_dispatch' }} permissions: packages: write id-token: write diff --git a/.github/workflows/login-container.yml b/.github/workflows/login-container.yml index 958e0a8f5b..25f338fb50 100644 --- a/.github/workflows/login-container.yml +++ b/.github/workflows/login-container.yml @@ -62,10 +62,10 @@ jobs: provenance: true sbom: true targets: login-standalone - set: login-*.context=./login/ + set: login-*.context=./apps/login/ project: w47wkxzdtw files: | - ./login/docker-bake.hcl - ./login/docker-bake-release.hcl + ./apps/login/docker-bake.hcl + ./apps/login/docker-bake-release.hcl ./docker-bake.hcl cwd://${{ steps.login-meta.outputs.bake-file }} diff --git a/apps/login/Makefile b/apps/login/Makefile deleted file mode 100644 index 05cf704c3f..0000000000 --- a/apps/login/Makefile +++ /dev/null @@ -1,137 +0,0 @@ -XDG_CACHE_HOME ?= $(HOME)/.cache -export CACHE_DIR ?= $(XDG_CACHE_HOME)/zitadel-make - -LOGIN_DIR ?= ./ -LOGIN_BAKE_CLI ?= docker buildx bake -LOGIN_BAKE_CLI_WITH_ARGS := $(LOGIN_BAKE_CLI) --file $(LOGIN_DIR)docker-bake.hcl --file $(LOGIN_DIR)apps/login-test-acceptance/docker-compose.yaml -LOGIN_BAKE_CLI_ADDITIONAL_ARGS ?= -LOGIN_BAKE_CLI_WITH_ARGS += $(LOGIN_BAKE_CLI_ADDITIONAL_ARGS) - -export COMPOSE_BAKE=true -export UID := $(id -u) -export GID := $(id -g) - -export LOGIN_TEST_ACCEPTANCE_BUILD_CONTEXT := $(LOGIN_DIR)apps/login-test-acceptance - -export DOCKER_METADATA_OUTPUT_VERSION ?= local -export LOGIN_TAG ?= zitadel-login:${DOCKER_METADATA_OUTPUT_VERSION} -export LOGIN_TEST_UNIT_TAG := login-test-unit:${DOCKER_METADATA_OUTPUT_VERSION} -export LOGIN_TEST_INTEGRATION_TAG := login-test-integration:${DOCKER_METADATA_OUTPUT_VERSION} -export LOGIN_TEST_ACCEPTANCE_TAG := login-test-acceptance:${DOCKER_METADATA_OUTPUT_VERSION} -export LOGIN_TEST_ACCEPTANCE_SETUP_TAG := login-test-acceptance-setup:${DOCKER_METADATA_OUTPUT_VERSION} -export LOGIN_TEST_ACCEPTANCE_SINK_TAG := login-test-acceptance-sink:${DOCKER_METADATA_OUTPUT_VERSION} -export LOGIN_TEST_ACCEPTANCE_OIDCRP_TAG := login-test-acceptance-oidcrp:${DOCKER_METADATA_OUTPUT_VERSION} -export LOGIN_TEST_ACCEPTANCE_OIDCOP_TAG := login-test-acceptance-oidcop:${DOCKER_METADATA_OUTPUT_VERSION} -export LOGIN_TEST_ACCEPTANCE_SAMLSP_TAG := login-test-acceptance-samlsp:${DOCKER_METADATA_OUTPUT_VERSION} -export LOGIN_TEST_ACCEPTANCE_SAMLIDP_TAG := login-test-acceptance-samlidp:${DOCKER_METADATA_OUTPUT_VERSION} -export POSTGRES_TAG := postgres:17.0-alpine3.19 -export GOLANG_TAG := golang:1.24-alpine -export ZITADEL_TAG ?= ghcr.io/zitadel/zitadel:latest -export LOGIN_CORE_MOCK_TAG := login-core-mock:${DOCKER_METADATA_OUTPUT_VERSION} - -login_help: - @echo "Makefile for the login service" - @echo "Available targets:" - @echo " login_help - Show this help message." - @echo " login_quality - Run all quality checks (login_lint, login_test_unit, login_test_integration, login_test_acceptance)." - @echo " login_standalone_build - Build the docker image for production login containers." - @echo " login_lint - Run linting and formatting checks. IGNORE_RUN_CACHE=true prevents skipping." - @echo " login_test_unit - Run unit tests. Tests without any dependencies. IGNORE_RUN_CACHE=true prevents skipping." - @echo " login-test_integration - Run integration tests. Tests a login production build against a mocked Zitadel core API. IGNORE_RUN_CACHE=true prevents skipping." - @echo " login_test_acceptance - Run acceptance tests. Tests a login production build with a local Zitadel instance behind a reverse proxy. IGNORE_RUN_CACHE=true prevents skipping." - @echo " typescript_generate - Generate TypeScript client code from Protobuf definitions." - @echo " show_run_caches - Show all run caches with image ids and exit codes." - @echo " clean_run_caches - Remove all run caches." - - -login_lint: - @echo "Running login linting and formatting checks" - $(LOGIN_BAKE_CLI_WITH_ARGS) login-lint - -login_test_unit: - @echo "Running login unit tests" - $(LOGIN_BAKE_CLI_WITH_ARGS) login-test-unit - -login_test_integration_build: - @echo "Building login integration test environment with the local core mock image" - $(LOGIN_BAKE_CLI_WITH_ARGS) core-mock login-test-integration login-standalone --load - -login_test_integration_dev: login_test_integration_cleanup - @echo "Starting login integration test environment with the local core mock image" - $(LOGIN_BAKE_CLI_WITH_ARGS) core-mock && docker compose --file $(LOGIN_DIR)apps/login-test-integration/docker-compose.yaml run --service-ports --rm core-mock - -login_test_integration_run: login_test_integration_cleanup - @echo "Running login integration tests" - docker compose --file $(LOGIN_DIR)apps/login-test-integration/docker-compose.yaml run --rm integration - -login_test_integration_cleanup: - @echo "Cleaning up login integration test environment" - docker compose --file $(LOGIN_DIR)apps/login-test-integration/docker-compose.yaml down --volumes - -login_test_integration: login_test_integration_build - $(LOGIN_DIR)scripts/run_or_skip.sh login_test_integration_run \ - "$(LOGIN_TAG) \ - $(LOGIN_CORE_MOCK_TAG) \ - $(LOGIN_TEST_INTEGRATION_TAG)" - -login_test_acceptance_build_bake: - @echo "Building login test acceptance images as defined in the docker-bake.hcl" - $(LOGIN_BAKE_CLI_WITH_ARGS) login-test-acceptance login-standalone --load - -login_test_acceptance_build_compose: - @echo "Building login test acceptance images as defined in the docker-compose.yaml" - $(LOGIN_BAKE_CLI_WITH_ARGS) --load setup sink - -# login_test_acceptance_build is overwritten by the login_dev target in zitadel/zitadel/Makefile -login_test_acceptance_build: login_test_acceptance_build_compose login_test_acceptance_build_bake - -login_test_acceptance_run: login_test_acceptance_cleanup - @echo "Running login test acceptance tests" - docker compose --file $(LOGIN_DIR)apps/login-test-acceptance/docker-compose.yaml --file $(LOGIN_DIR)apps/login-test-acceptance/docker-compose-ci.yaml run --rm --service-ports acceptance - -login_test_acceptance_cleanup: - @echo "Cleaning up login test acceptance environment" - docker compose --file $(LOGIN_DIR)apps/login-test-acceptance/docker-compose.yaml --file $(LOGIN_DIR)apps/login-test-acceptance/docker-compose-ci.yaml down --volumes - -login_test_acceptance: login_test_acceptance_build - $(LOGIN_DIR)scripts/run_or_skip.sh login_test_acceptance_run \ - "$(LOGIN_TAG) \ - $(ZITADEL_TAG) \ - $(POSTGRES_TAG) \ - $(GOLANG_TAG) \ - $(LOGIN_TEST_ACCEPTANCE_TAG) \ - $(LOGIN_TEST_ACCEPTANCE_SETUP_TAG) \ - $(LOGIN_TEST_ACCEPTANCE_SINK_TAG)" - -login_test_acceptance_setup_env: login_test_acceptance_build_compose login_test_acceptance_cleanup - @echo "Setting up the login test acceptance environment and writing the env.test.local file" - docker compose --file $(LOGIN_DIR)apps/login-test-acceptance/docker-compose.yaml run setup - -login_test_acceptance_setup_dev: - @echo "Starting the login test acceptance environment with the local zitadel image" - docker compose --file $(LOGIN_DIR)apps/login-test-acceptance/docker-compose.yaml up --no-recreate zitadel traefik sink - -login_quality: login_lint login_test_unit login_test_integration - @echo "Running login quality checks: lint, unit tests, integration tests" - -login_standalone_build: - @echo "Building the login standalone docker image with tag: $(LOGIN_TAG)" - $(LOGIN_BAKE_CLI_WITH_ARGS) login-standalone --load - -login_standalone_out: - $(LOGIN_BAKE_CLI_WITH_ARGS) login-standalone-out - -typescript_generate: - @echo "Generating TypeScript client and writing to local $(LOGIN_DIR)packages/zitadel-proto" - $(LOGIN_BAKE_CLI_WITH_ARGS) login-typescript-proto-client-out - -clean_run_caches: - @echo "Removing cache directory: $(CACHE_DIR)" - rm -rf "$(CACHE_DIR)" - -show_run_caches: - @echo "Showing run caches with docker image ids and exit codes in $(CACHE_DIR):" - @find "$(CACHE_DIR)" -type f 2>/dev/null | while read file; do \ - echo "$$file: $$(cat $$file)"; \ - done - diff --git a/apps/login/apps/login/.dockerignore b/apps/login/apps/login/.dockerignore new file mode 100644 index 0000000000..4e64fd495f --- /dev/null +++ b/apps/login/apps/login/.dockerignore @@ -0,0 +1,21 @@ +* + +!constants +!scripts +!src +!public +!locales +!next.config.mjs +!next-env-vars.d.ts +!next-env.d.ts +!tailwind.config.js +!tsconfig.json +!package.json +!pnpm-lock.yaml + +**/*.md +**/*.png +**/node_modules +**/.turbo +**/*.test.ts +**/*.test.tsx \ No newline at end of file diff --git a/apps/login/apps/login/Dockerfile b/apps/login/apps/login/Dockerfile new file mode 100644 index 0000000000..7e3d8668d2 --- /dev/null +++ b/apps/login/apps/login/Dockerfile @@ -0,0 +1,36 @@ +FROM node:20-alpine AS base + +FROM base AS build +ENV PNPM_HOME="/pnpm" +ENV PATH="$PNPM_HOME:$PATH" +RUN corepack enable && COREPACK_ENABLE_DOWNLOAD_PROMPT=0 corepack prepare pnpm@9.1.2 --activate && \ + apk update && apk add --no-cache && \ + rm -rf /var/cache/apk/* +WORKDIR /app +COPY pnpm-lock.yaml ./ +RUN --mount=type=cache,id=pnpm,target=/root/.local/share/pnpm/store pnpm fetch --frozen-lockfile +COPY package.json ./ +RUN --mount=type=cache,id=pnpm,target=/root/.local/share/pnpm/store pnpm install --frozen-lockfile --prod +COPY . . +RUN pnpm build:login:standalone + +FROM scratch AS build-out +COPY --from=build /app/.next/standalone / +COPY --from=build /app/.next/static /.next/static +COPY --from=build /app/public /public + +FROM base AS login-standalone +WORKDIR /runtime +RUN addgroup --system --gid 1001 nodejs && \ + adduser --system --uid 1001 nextjs +# If /.env-file/.env is mounted into the container, its variables are made available to the server before it starts up. +RUN mkdir -p /.env-file && touch /.env-file/.env && chown -R nextjs:nodejs /.env-file +COPY ./scripts/ ./ +COPY --chown=nextjs:nodejs --from=build-out / ./ +USER nextjs +ENV HOSTNAME="0.0.0.0" +ENV PORT=3000 +# TODO: Check healthy, not ready +HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \ +CMD ["/bin/sh", "-c", "node ./healthcheck.js http://localhost:${PORT}/ui/v2/login/healthy"] +ENTRYPOINT ["./entrypoint.sh"] diff --git a/apps/login/apps/login/package.json b/apps/login/apps/login/package.json index 6e986d4ba3..eaa3a396b4 100644 --- a/apps/login/apps/login/package.json +++ b/apps/login/apps/login/package.json @@ -6,7 +6,7 @@ "scripts": { "dev": "next dev", "build": "next build", - "build:standalone": "NEXT_PUBLIC_BASE_PATH=/ui/v2/login NEXT_OUTPUT_MODE=standalone next build", + "build:login:standalone": "NEXT_PUBLIC_BASE_PATH=/ui/v2/login NEXT_OUTPUT_MODE=standalone next build", "start": "next start", "lint": "pnpm run '/^lint:check:.*$/'", "lint:check:next": "next lint", diff --git a/apps/login/apps/login/scripts/entrypoint.sh b/apps/login/apps/login/scripts/entrypoint.sh index c537e8b8fb..c64bd675ce 100755 --- a/apps/login/apps/login/scripts/entrypoint.sh +++ b/apps/login/apps/login/scripts/entrypoint.sh @@ -8,4 +8,4 @@ if [ -n "${ZITADEL_SERVICE_USER_TOKEN_FILE}" ] && [ -f "${ZITADEL_SERVICE_USER_T export ZITADEL_SERVICE_USER_TOKEN=$(cat "${ZITADEL_SERVICE_USER_TOKEN_FILE}") fi -exec node apps/login/server.js +exec node server.js diff --git a/apps/login/apps/login/scripts/run_or_skip.sh b/apps/login/apps/login/scripts/run_or_skip.sh deleted file mode 100755 index 4516eb01b1..0000000000 --- a/apps/login/apps/login/scripts/run_or_skip.sh +++ /dev/null @@ -1,67 +0,0 @@ -#!/usr/bin/env bash - -# Usage: ./run_or_skip.sh -# Example: ./run_or_skip.sh lint-force "img1;img2" - -set -euo pipefail - -if [ -z "$CACHE_DIR" ]; then - echo "CACHE_DIR is not set. Please set it to a valid directory." - exit 1 -fi - -MAKE_TARGET=$1 -IMAGES=$2 -IGNORE_RUN_CACHE=${IGNORE_RUN_CACHE:-false} - -CACHE_FILE="$CACHE_DIR/$MAKE_TARGET.digests" -mkdir -p "$CACHE_DIR" - -get_image_creation_dates() { - local values="" - for img in $(echo "$IMAGES"); do - local value=$(docker image inspect "$img" --format='{{.Created}}' 2>/dev/null || true) - if [[ -z $value ]]; then - docker pull "$img" >/dev/null 2>&1 || true - value=$(docker image inspect "$img" --format='{{.Created}}' 2>/dev/null || true) - fi - if [[ -z $value ]]; then - value=$(docker image inspect "$img" --format='{{.Created}}' 2>/dev/null || true) - fi - value=${value:-new-and-not-pullable-or-failed-to-build} - value="${img}@${value}" - values="${values}${value};" - done - values=${values%;} # Remove trailing semicolon - echo "$values" -} - -CACHE_FILE_CONTENT=$(cat "$CACHE_FILE" 2>/dev/null || echo "") -CACHED_STATUS=$(echo "$CACHE_FILE_CONTENT" | cut -d ';' -f1) -CACHED_IMAGE_CREATED_VALUES=$(echo "$CACHE_FILE_CONTENT" | cut -d ';' -f2-99) -CURRENT_IMAGE_CREATED_VALUES="$(get_image_creation_dates)" - if [[ "$CACHED_IMAGE_CREATED_VALUES" == "$CURRENT_IMAGE_CREATED_VALUES" ]]; then - if [[ "$IGNORE_RUN_CACHE" == "true" ]]; then - echo "\$IGNORE_RUN_CACHE=$IGNORE_RUN_CACHE - Running $MAKE_TARGET despite unchanged images." - else - echo "Skipping $MAKE_TARGET – all images unchanged, returning cached status $CACHED_STATUS" - exit $CACHED_STATUS - fi -fi -echo "Images have changed" -echo -echo "CACHED_IMAGE_CREATED_VALUES does not match CURRENT_IMAGE_CREATED_VALUES" -echo -echo "$CACHED_IMAGE_CREATED_VALUES" -echo -echo "$CURRENT_IMAGE_CREATED_VALUES" -echo -docker images -echo -echo "Running $MAKE_TARGET..." -set +e -make -j $MAKE_TARGET -STATUS=$? -set -e -echo "${STATUS};$(get_image_creation_dates)" > $CACHE_FILE -exit $STATUS diff --git a/apps/login/apps/login/turbo.json b/apps/login/apps/login/turbo.json index d6edba036c..b7b4e5fd27 100644 --- a/apps/login/apps/login/turbo.json +++ b/apps/login/apps/login/turbo.json @@ -5,8 +5,9 @@ "outputs": ["dist/**", ".next/**", "!.next/cache/**"], "dependsOn": ["@zitadel/client#build"] }, - "build:standalone": { - "outputs": ["dist/**", ".next/**", "!.next/cache/**"] + "build:login:standalone": { + "outputs": ["dist/**", ".next/**", "!.next/cache/**"], + "dependsOn": ["@zitadel/client#build"] }, "dev": { "dependsOn": ["@zitadel/client#build"] diff --git a/apps/login/pnpm-lock.yaml b/apps/login/pnpm-lock.yaml index e6e6a7bf0c..05b08193da 100644 --- a/apps/login/pnpm-lock.yaml +++ b/apps/login/pnpm-lock.yaml @@ -143,6 +143,9 @@ importers: make-dir-cli: specifier: 4.0.0 version: 4.0.0 + package-json-merge: + specifier: ^0.0.1 + version: 0.0.1 postcss: specifier: 8.5.3 version: 8.5.3 @@ -1898,6 +1901,10 @@ packages: resolution: {integrity: sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==} engines: {node: '>=18'} + commander@2.9.0: + resolution: {integrity: sha512-bmkUukX8wAOjHdN26xj5c4ctEV22TQ7dQYhSmuckKhToXrkUn0iIaolHdIxYYqD55nhpSPA9zPQ1yP57GdXP2A==} + engines: {node: '>= 0.6.x'} + commander@4.1.1: resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} engines: {node: '>= 6'} @@ -2568,6 +2575,9 @@ packages: graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + graceful-readlink@1.0.1: + resolution: {integrity: sha512-8tLu60LgxF6XpdbK8OW3FA+IfTNBn1ZHGHKF4KQbEeSkajYw5PlYJcKluntgegDPTg8UkHjpet1T82vk6TQ68w==} + graphemer@1.4.0: resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} @@ -3322,6 +3332,10 @@ packages: package-json-from-dist@1.0.1: resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} + package-json-merge@0.0.1: + resolution: {integrity: sha512-ygVyCxYFAb4wAWuonxtdDXxC/jGM6o5ka2fR7DGy1HCFUZdVOXHcxpINHHCMFI9s3qqbnEQEbOVdz1a6rwr6OA==} + hasBin: true + parent-module@1.0.1: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} engines: {node: '>=6'} @@ -5949,6 +5963,10 @@ snapshots: commander@13.1.0: {} + commander@2.9.0: + dependencies: + graceful-readlink: 1.0.1 + commander@4.1.1: {} commander@6.2.1: {} @@ -6080,6 +6098,10 @@ snapshots: optionalDependencies: supports-color: 8.1.1 + debug@4.4.1: + dependencies: + ms: 2.1.3 + debug@4.4.1(supports-color@5.5.0): dependencies: ms: 2.1.3 @@ -6682,7 +6704,7 @@ snapshots: follow-redirects@1.15.9(debug@4.4.1): optionalDependencies: - debug: 4.4.1(supports-color@5.5.0) + debug: 4.4.1 for-each@0.3.5: dependencies: @@ -6867,6 +6889,8 @@ snapshots: graceful-fs@4.2.11: {} + graceful-readlink@1.0.1: {} + graphemer@1.4.0: {} grpc-tools@1.13.0: @@ -6934,7 +6958,7 @@ snapshots: https-proxy-agent@7.0.6: dependencies: agent-base: 7.1.4 - debug: 4.4.1(supports-color@5.5.0) + debug: 4.4.1 transitivePeerDependencies: - supports-color @@ -7632,6 +7656,10 @@ snapshots: package-json-from-dist@1.0.1: {} + package-json-merge@0.0.1: + dependencies: + commander: 2.9.0 + parent-module@1.0.1: dependencies: callsites: 3.1.0 @@ -8138,7 +8166,7 @@ snapshots: arg: 5.0.2 bluebird: 3.7.2 check-more-types: 2.24.0 - debug: 4.4.1(supports-color@5.5.0) + debug: 4.4.1 execa: 5.1.1 lazy-ass: 1.6.0 ps-tree: 1.2.0 diff --git a/apps/login/pnpm-workspace.yaml b/apps/login/pnpm-workspace.yaml deleted file mode 100644 index 3ff5faaaf5..0000000000 --- a/apps/login/pnpm-workspace.yaml +++ /dev/null @@ -1,3 +0,0 @@ -packages: - - "apps/*" - - "packages/*" diff --git a/dockerfiles/login.Dockerfile b/dockerfiles/login.Dockerfile new file mode 100644 index 0000000000..03990894a3 --- /dev/null +++ b/dockerfiles/login.Dockerfile @@ -0,0 +1,45 @@ +FROM node:20-alpine AS base + +FROM base AS build +ENV PNPM_HOME="/pnpm" +ENV PATH="$PNPM_HOME:$PATH" +RUN corepack enable && COREPACK_ENABLE_DOWNLOAD_PROMPT=0 corepack prepare pnpm@9.1.2 --activate && \ + apk update && apk add --no-cache && \ + rm -rf /var/cache/apk/* +WORKDIR /app +COPY pnpm-lock.yaml pnpm-workspace.yaml ./ +RUN --mount=type=cache,id=pnpm,target=/root/.local/share/pnpm/store pnpm fetch --frozen-lockfile \ + --filter @zitadel/login \ + --filter @zitadel/client \ + --filter @zitadel/proto +COPY package.json ./ +COPY apps/login/apps/login/package.json ./apps/login/apps/login/package.json +COPY packages/zitadel-proto/package.json ./packages/zitadel-proto/package.json +COPY packages/zitadel-client/package.json ./packages/zitadel-client/package.json +RUN --mount=type=cache,id=pnpm,target=/root/.local/share/pnpm/store pnpm install --frozen-lockfile \ + --filter @zitadel/login \ + --filter @zitadel/client \ + --filter @zitadel/proto +COPY . . +RUN pnpm turbo build:login:standalone + +FROM scratch AS build-out +COPY --from=build /app/apps/login/apps/login/.next/standalone / +COPY --from=build /app/apps/login/apps/login/.next/static /.next/static +COPY --from=build /app/apps/login/apps/login/public /public + +FROM base AS login-standalone +WORKDIR /runtime +RUN addgroup --system --gid 1001 nodejs && \ + adduser --system --uid 1001 nextjs +# If /.env-file/.env is mounted into the container, its variables are made available to the server before it starts up. +RUN mkdir -p /.env-file && touch /.env-file/.env && chown -R nextjs:nodejs /.env-file +COPY apps/login/apps/login/scripts ./ +COPY --chown=nextjs:nodejs --from=build-out . . +USER nextjs +ENV HOSTNAME="0.0.0.0" +ENV PORT=3000 +# TODO: Check healthy, not ready +HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \ +CMD ["/bin/sh", "-c", "node ./healthcheck.js http://localhost:${PORT}/ui/v2/login/healthy"] +ENTRYPOINT ["./entrypoint.sh"] diff --git a/dockerfiles/login.Dockerfile.dockerignore b/dockerfiles/login.Dockerfile.dockerignore new file mode 100644 index 0000000000..08d014d47e --- /dev/null +++ b/dockerfiles/login.Dockerfile.dockerignore @@ -0,0 +1,37 @@ +* + +!apps/login/apps/login/constants +!apps/login/apps/login/scripts +!apps/login/apps/login/src +!apps/login/apps/login/public +!apps/login/apps/login/locales +!apps/login/apps/login/next.config.mjs +!apps/login/apps/login/next-env-vars.d.ts +!apps/login/apps/login/next-env.d.ts +!apps/login/apps/login/tailwind.config.js +!apps/login/apps/login/tsconfig.json +!apps/login/apps/login/package.json +!apps/login/apps/login/turbo.json + +!package.json +!pnpm-lock.yaml +!pnpm-workspace.yaml +!turbo.json + +!packages/zitadel-proto/package.json +!packages/zitadel-proto/buf.gen.yaml +!packages/zitadel-proto/turbo.json + +!packages/zitadel-client/package.json +!packages/zitadel-client/src +!packages/zitadel-client/tsconfig.json +!packages/zitadel-client/tsup.config.ts +!packages/zitadel-client/turbo.json + +!proto + +*.md +*.png +node_modules +*.test.ts +*.test.tsx diff --git a/package.json b/package.json index 97a0943116..5eb30a69c7 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,9 @@ "changeset": "changeset", "devcontainer": "devcontainer", "devcontainer:lint-unit": "pnpm devcontainer up --config .devcontainer/turbo-lint-unit/devcontainer.json --workspace-folder . --remove-existing-container", - "devcontainer:integration:login": "pnpm devcontainer up --config .devcontainer/login-integration/devcontainer.json --workspace-folder . --remove-existing-container" + "devcontainer:integration:login": "pnpm devcontainer up --config .devcontainer/login-integration/devcontainer.json --workspace-folder . --remove-existing-container", + "devcontainer:integration:login:build": "pnpm docker:build:login && devcontainer:integration:login", + "docker:build:login": "docker build --tag zitadel-login:local --file dockerfiles/login.Dockerfile ." }, "pnpm": { "overrides": { diff --git a/turbo.json b/turbo.json index a45ed9361e..2dad100d23 100644 --- a/turbo.json +++ b/turbo.json @@ -24,6 +24,7 @@ "cache": true }, "build": {}, + "build:login:standalone": {}, "quality": { "with": [ "lint",