Merge branch 'main' into copilot/fix-10389

This commit is contained in:
Tim Möhlmann
2025-08-07 15:09:48 +03:00
committed by GitHub
64 changed files with 11183 additions and 1938 deletions

View File

@@ -8,9 +8,13 @@ ENV SHELL=/bin/bash \
PNPM_HOME=/home/node/.local/share/pnpm \
PATH=/home/node/.local/share/pnpm:$PATH
RUN apt-get update && \
apt-get --no-install-recommends install -y \
# Cypress dependencies
libgtk2.0-0 libgtk-3-0 libgbm-dev libnotify-dev libnss3 libxss1 libasound2 libxtst6 xauth xvfb && \
apt-get clean && \
corepack enable && COREPACK_ENABLE_DOWNLOAD_PROMPT=0 corepack prepare pnpm@9.1.2 --activate
corepack enable && COREPACK_ENABLE_DOWNLOAD_PROMPT=0 corepack prepare pnpm@10.13.1 --activate
COPY --chown=node:node commands /commands
USER node

View File

@@ -0,0 +1,2 @@
*
!commands

View File

@@ -0,0 +1,39 @@
#!/bin/bash
if [ "$FAIL_COMMANDS_ON_ERRORS" == "true" ]; then
set -e
fi
echo
echo
echo
echo -e "THANKS FOR CONTRIBUTING TO ZITADEL 🚀"
echo
echo "Your dev container is configured for fixing login integration tests."
echo "The login is running in a separate container with the same configuration."
echo "It calls the mock-zitadel container which provides a mocked Zitadel gRPC API."
echo
echo "Also the test suite is configured correctly."
echo "For example, run a single test file:"
echo "pnpm cypress run --spec integration/integration/login.cy.ts"
echo
echo "You can also run the test interactively."
echo "However, this is only possible from outside the dev container."
echo "On your host machine, run:"
echo "cd apps/login"
echo "pnpm cypress open"
echo
echo "If you want to change the login code, you can replace the login container by a hot reloading dev server."
echo "docker stop login-integration"
echo "pnpm turbo dev"
echo "Navigate to the page you want to fix, for example:"
echo "http://localhost:3001/ui/v2/login/verify?userId=221394658884845598&code=abc"
echo "Change some code and reload the page for instant feedback."
echo
echo "When you are done, make sure all integration tests pass:"
echo "pnpm cypress run"
echo
if [ "$FAIL_COMMANDS_ON_ERRORS" != "true" ]; then
exit 0
fi

View File

@@ -0,0 +1,18 @@
#!/bin/bash
if [ "$FAIL_COMMANDS_ON_ERRORS" == "true" ]; then
echo "Running in fail-on-errors mode"
set -e
fi
pnpm install --frozen-lockfile \
--filter @zitadel/login \
--filter @zitadel/client \
--filter @zitadel/proto \
--filter zitadel-monorepo
pnpm cypress install
pnpm test:integration:login
if [ "$FAIL_COMMANDS_ON_ERRORS" != "true" ]; then
exit 0
fi

View File

@@ -0,0 +1,30 @@
#!/bin/bash
if [ "$FAIL_COMMANDS_ON_ERRORS" == "true" ]; then
set -e
fi
echo
echo
echo
echo -e "THANKS FOR CONTRIBUTING TO ZITADEL 🚀"
echo
echo "Your dev container is configured for fixing linting and unit tests."
echo "No other services are running alongside this container."
echo
echo "To fix all auto-fixable linting errors, run:"
echo "pnpm turbo lint:fix"
echo
echo "To watch console linting errors, run:"
echo "pnpm turbo watch lint --filter console"
echo
echo "To watch @zitadel/client unit test failures, run:"
echo "pnpm turbo watch test:unit --filter @zitadel/client"
echo
echo "To watch @zitadel/login relevant unit tests and linting failures, run:"
echo "pnpm turbo watch lint test:unit --filter @zitadel/login..."
echo
if [ "$FAIL_COMMANDS_ON_ERRORS" != "true" ]; then
exit 0
fi

View File

@@ -0,0 +1,12 @@
#!/bin/bash
if [ "$FAIL_COMMANDS_ON_ERRORS" == "true" ]; then
set -e
fi
pnpm install --frozen-lockfile --recursive
pnpm turbo lint test:unit
if [ "$FAIL_COMMANDS_ON_ERRORS" != "true" ]; then
exit 0
fi

View File

@@ -1,15 +1,15 @@
{
"$schema": "https://raw.githubusercontent.com/devcontainers/spec/refs/heads/main/schemas/devContainer.schema.json",
"name": "devcontainer",
"dockerComposeFile": "docker-compose.yml",
"name": "Base: Build and Run the Components you need",
"dockerComposeFile": "docker-compose.yaml",
"service": "devcontainer",
"runServices": [
"devContainer",
"db"
],
"workspaceFolder": "/workspaces",
"features": {
"ghcr.io/devcontainers/features/go:1": {
"version": "1.24"
},
"ghcr.io/guiyomh/features/golangci-lint:0": {},
"ghcr.io/jungaretti/features/make:1": {}
"remoteEnv": {
"DISPLAY": ""
},
"forwardPorts": [
3000,
@@ -17,12 +17,13 @@
4200,
8080
],
"onCreateCommand": "pnpm install -g sass@1.64.1",
"customizations": {
"jetbrains": {
"settings": {
"com.intellij:app:HttpConfigurable.use_proxy_pac": true
}
}
"onCreateCommand": "pnpm install --frozen-lockfile --recursive --prefer-offline",
"features": {
"ghcr.io/devcontainers/features/go:1": {
"version": "1.24"
},
"ghcr.io/guiyomh/features/golangci-lint:0": {},
"ghcr.io/jungaretti/features/make:1": {},
"ghcr.io/devcontainers/features/docker-outside-of-docker": {}
}
}

View File

@@ -1,20 +1,11 @@
x-build-cache: &build-cache
cache_from:
- type=gha
cache_to:
- type=gha,mode=max
services:
devcontainer:
container_name: devcontainer
build:
context: .
<<: *build-cache
context: ../base
volumes:
- ../../:/workspaces:cached
- /tmp/.X11-unix:/tmp/.X11-unix:cached
- home-dir:/home/node:delegated
command: sleep infinity
working_dir: /workspaces
environment:
@@ -39,34 +30,9 @@ services:
ports:
- "5432:5432"
mock-zitadel:
container_name: mock-zitadel
build:
context: ../../apps/login/integration/core-mock
<<: *build-cache
ports:
- 22220:22220
- 22222:22222
login-integration:
container_name: login-integration
build:
context: ../..
dockerfile: build/login/Dockerfile
<<: *build-cache
image: "${LOGIN_TAG:-zitadel-login:local}"
env_file: ../../apps/login/.env.test
network_mode: service:devcontainer
environment:
NODE_ENV: test
PORT: 3001
depends_on:
mock-zitadel:
condition: service_started
zitadel:
image: "${ZITADEL_TAG:-ghcr.io/zitadel/zitadel:v4.0.0-rc.2}"
container_name: zitadel
image: "${ZITADEL_TAG:-ghcr.io/zitadel/zitadel:latest}"
command: 'start-from-init --masterkey "MasterkeyNeedsToHave32Characters" --config /zitadel.yaml --steps /zitadel.yaml'
volumes:
- ../../apps/login/acceptance/pat:/pat:delegated
@@ -89,7 +55,6 @@ services:
build:
context: ../../apps/login/acceptance/setup
dockerfile: ../go-command.Dockerfile
<<: *build-cache
entrypoint: "./setup.sh"
network_mode: service:devcontainer
environment:
@@ -111,7 +76,7 @@ services:
login-acceptance:
container_name: login
image: "${LOGIN_TAG:-ghcr.io/zitadel/zitadel-login:v4.0.0-rc.2}"
image: "${LOGIN_TAG:-ghcr.io/zitadel/zitadel-login:latest}"
network_mode: service:devcontainer
volumes:
- ../../apps/login/.env.test.local:/env-files/.env:cached
@@ -126,7 +91,6 @@ services:
dockerfile: ../go-command.Dockerfile
args:
- LOGIN_TEST_ACCEPTANCE_GOLANG_TAG=${LOGIN_TEST_ACCEPTANCE_GOLANG_TAG:-golang:1.24-alpine}
<<: *build-cache
environment:
PORT: '3333'
command:
@@ -151,7 +115,6 @@ services:
dockerfile: ../go-command.Dockerfile
args:
- LOGIN_TEST_ACCEPTANCE_GOLANG_TAG=${LOGIN_TEST_ACCEPTANCE_GOLANG_TAG:-golang:1.24-alpine}
<<: *build-cache
network_mode: service:devcontainer
environment:
API_URL: 'http://localhost:8080'
@@ -175,7 +138,6 @@ services:
# dockerfile: ../../go-command.Dockerfile
# args:
# - LOGIN_TEST_ACCEPTANCE_GOLANG_TAG=${LOGIN_TEST_ACCEPTANCE_GOLANG_TAG:-golang:1.24-alpine}
# <<: *build-cache
# network_mode: service:devcontainer
# environment:
# API_URL: 'http://localhost:8080'
@@ -197,7 +159,6 @@ services:
dockerfile: ../go-command.Dockerfile
args:
- LOGIN_TEST_ACCEPTANCE_GOLANG_TAG=${LOGIN_TEST_ACCEPTANCE_GOLANG_TAG:-golang:1.24-alpine}
<<: *build-cache
network_mode: service:devcontainer
environment:
API_URL: 'http://localhost:8080'
@@ -219,7 +180,6 @@ services:
# dockerfile: ../../go-command.Dockerfile
# args:
# - LOGIN_TEST_ACCEPTANCE_GOLANG_TAG=${LOGIN_TEST_ACCEPTANCE_GOLANG_TAG:-golang:1.24-alpine}
# <<: *build-cache
# network_mode: service:devcontainer
# environment:
# API_URL: 'http://localhost:8080'
@@ -236,4 +196,3 @@ services:
volumes:
postgres-data:
home-dir:

View File

@@ -1,21 +0,0 @@
{
"$schema": "https://raw.githubusercontent.com/devcontainers/spec/refs/heads/main/schemas/devContainer.schema.json",
"name": "login-integration-debug",
"dockerComposeFile": [
"../base/docker-compose.yml",
"docker-compose.yml"
],
"service": "login-integration-debug",
"runServices": ["login-integration-debug"],
"workspaceFolder": "/workspaces",
"forwardPorts": [3001],
"onCreateCommand": "pnpm install --recursive",
"postAttachCommand": "pnpm turbo daemon clean; pnpm turbo @zitadel/login#dev test:integration:login:debug",
"customizations": {
"jetbrains": {
"settings": {
"com.intellij:app:HttpConfigurable.use_proxy_pac": true
}
}
}
}

View File

@@ -1,9 +0,0 @@
services:
login-integration-debug:
extends:
file: ../base/docker-compose.yml
service: devcontainer
container_name: login-integration-debug
depends_on:
mock-zitadel:
condition: service_started

View File

@@ -1,19 +1,26 @@
{
"$schema": "https://raw.githubusercontent.com/devcontainers/spec/refs/heads/main/schemas/devContainer.schema.json",
"name": "login-integration",
"name": "Login Integration",
"dockerComposeFile": [
"../base/docker-compose.yml"
"./docker-compose.yaml"
],
"service": "devcontainer",
"runServices": ["login-integration"],
"workspaceFolder": "/workspaces",
"forwardPorts": [3001],
"onCreateCommand": "pnpm install --frozen-lockfile --recursive && cd apps/login/packages/integration && pnpm cypress install && pnpm test:integration:login",
"customizations": {
"jetbrains": {
"settings": {
"com.intellij:app:HttpConfigurable.use_proxy_pac": true
}
}
"service": "login-integration-dev",
"runServices": [
"login-integration"
],
"workspaceFolder": "/workspaces/apps/login",
"forwardPorts": [
22220,
22222,
3001
],
"remoteEnv": {
"FAIL_COMMANDS_ON_ERRORS": "${localEnv:FAIL_COMMANDS_ON_ERRORS}",
"DISPLAY": ""
},
"updateContentCommand": "/commands/login-integration.update-content.sh",
"postAttachCommand": "/commands/login-integration.post-attach.sh",
"features": {
"ghcr.io/devcontainers/features/docker-outside-of-docker": {}
}
}

View File

@@ -0,0 +1,35 @@
services:
login-integration-dev:
extends:
file: ../base/docker-compose.yaml
service: devcontainer
container_name: login-integration-dev
env_file: ../../apps/login/.env.test
environment:
CORE_MOCK_STUBS_URL: http://localhost:22220/v1/stubs
LOGIN_BASE_URL: http://localhost:3001/ui/v2/login
CYPRESS_CACHE_FOLDER: /workspaces/.artifacts/cypress
network_mode: service:mock-zitadel
depends_on:
login-integration:
condition: service_healthy
login-integration:
container_name: login-integration
image: "${LOGIN_TAG:-ghcr.io/zitadel/zitadel-login:latest}"
build:
context: ../..
dockerfile: build/login/Dockerfile
env_file: ../../apps/login/.env.test
network_mode: service:mock-zitadel
mock-zitadel:
container_name: mock-zitadel
build:
context: ../../apps/login/integration/core-mock
additional_contexts:
- zitadel-protos=../../proto
ports:
- 22220:22220
- 22222:22222
- 3001:3001

View File

@@ -0,0 +1,22 @@
{
"$schema": "https://raw.githubusercontent.com/devcontainers/spec/refs/heads/main/schemas/devContainer.base.schema.json",
"image": "mcr.microsoft.com/devcontainers/typescript-node:20-bookworm",
"name": "Login Subtree Container - Use the Login As If You Would Have Forked the Mirror Repo",
"workspaceFolder": "/login",
"workspaceMount": "source=${localWorkspaceFolder}/apps/login,target=/login,type=bind,consistency=cached",
"mounts": [],
"forwardPorts": [
22220,
22222,
3000,
3001
],
"features": {
"ghcr.io/devcontainers/features/go:1": {
"version": "1.24"
},
"ghcr.io/guiyomh/features/golangci-lint:0": {},
"ghcr.io/jungaretti/features/make:1": {},
"ghcr.io/devcontainers/features/docker-outside-of-docker": {}
}
}

View File

@@ -1,21 +0,0 @@
{
"$schema": "https://raw.githubusercontent.com/devcontainers/spec/refs/heads/main/schemas/devContainer.schema.json",
"name": "turbo-lint-unit-debug",
"dockerComposeFile": [
"../base/docker-compose.yml",
"docker-compose.yml"
],
"service": "turbo-lint-unit-debug",
"runServices": ["turbo-lint-unit-debug"],
"workspaceFolder": "/workspaces",
"forwardPorts": [3001],
"onCreateCommand": "pnpm install --recursive",
"postAttachCommand": "pnpm turbo daemon clean; pnpm turbo watch lint test:unit",
"customizations": {
"jetbrains": {
"settings": {
"com.intellij:app:HttpConfigurable.use_proxy_pac": true
}
}
}
}

View File

@@ -1,6 +0,0 @@
services:
turbo-lint-unit-debug:
extends:
file: ../base/docker-compose.yml
service: devcontainer
container_name: turbo-lint-unit-debug

View File

@@ -1,18 +1,20 @@
{
"$schema": "https://raw.githubusercontent.com/devcontainers/spec/refs/heads/main/schemas/devContainer.schema.json",
"name": "turbo-lint-unit",
"name": "Turbo Lint and Unit Tests",
"dockerComposeFile": [
"../base/docker-compose.yml"
"../base/docker-compose.yaml"
],
"service": "devcontainer",
"runServices": ["devcontainer"],
"runServices": [
"devcontainer"
],
"workspaceFolder": "/workspaces",
"postStartCommand": "pnpm install --frozen-lockfile --recursive && pnpm turbo lint test:unit",
"customizations": {
"jetbrains": {
"settings": {
"com.intellij:app:HttpConfigurable.use_proxy_pac": true
}
}
}
"forwardPorts": [
3001
],
"remoteEnv": {
"FAIL_COMMANDS_ON_ERRORS": "${localEnv:FAIL_COMMANDS_ON_ERRORS}"
},
"updateContentCommand": "/commands/turbo-lint-unit.update-content.sh",
"postAttachCommand": "/commands/turbo-lint-unit.post-attach.sh"
}

View File

@@ -1,11 +1,14 @@
# .git
.codecov
.github
.gitignore
.dockerignore
**/Dockerfile
/k8s/
/node_modules/
**/node_modules
**/.pnpm-store
**/.turbo
**/.next
/console/src/app/proto/generated/
/console/.angular
/console/tmp/
@@ -24,5 +27,5 @@ console/.angular
console/node_modules
console/src/app/proto/generated/
console/tmp/
.vscode
build/*.Dockerfile

View File

@@ -102,6 +102,12 @@ jobs:
login_build_image_name: "ghcr.io/zitadel/zitadel-login-build"
node_version: "20"
login-integration-test:
uses: ./.github/workflows/login-integration-test.yml
needs: [login-container]
with:
login_build_image: ${{ needs.login-container.outputs.login_build_image }}
e2e:
uses: ./.github/workflows/e2e.yml
needs: [compile]
@@ -121,6 +127,7 @@ jobs:
lint,
container,
login-container,
login-integration-test,
e2e,
]
if: ${{ github.event_name == 'workflow_dispatch' }}

View File

@@ -53,14 +53,21 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install Dev Container CLI
run: npm install -g @devcontainers/cli@0.80.0
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Run lint and unit tests in dev container
uses: devcontainers/ci@v0.3
with:
push: never
configFile: .devcontainer/turbo-lint-unit/devcontainer.json
runCmd: echo "Successfully ran lint and unit tests in dev container postStartCommand"
- name: Lint and Unit Test All JavaScript Code
run: npm run devcontainer:lint-unit
- name: Fix Failures
if: failure()
run: |
echo "Reproduce this check locally:"
echo "npm run devcontainer:lint-unit"
echo "If you have pnpm installed, most linting errors can be fixed automatically:"
echo "pnpm turbo lint:fix"
echo "In other cases, you can open the dev container called \"Turbo Lint and Unit Tests\"."
echo "You will have the same environment as the pipeline check as well as some guidance on how to fix the errors."
core:
name: core

View File

@@ -13,7 +13,7 @@ on:
outputs:
login_build_image:
description: 'The full image tag of the standalone login image'
value: '${{ inputs.login_build_image_name }}:${{ github.sha }}'
value: ${{ inputs.login_build_image_name }}:${{ github.sha }}
permissions:
packages: write
@@ -30,6 +30,8 @@ jobs:
runs-on: ubuntu-latest
permissions:
packages: write
outputs:
login_build_image: ${{ steps.short-sha.outputs.login_build_image }}
steps:
- uses: actions/checkout@v4
- name: Login meta
@@ -41,7 +43,7 @@ jobs:
annotations: |
manifest:org.opencontainers.image.licenses=MIT
tags: |
type=sha,prefix=,suffix=,format=long
type=sha,prefix=,format=long
- name: Login to Docker registry
uses: docker/login-action@v3
with:
@@ -49,6 +51,7 @@ jobs:
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Set up Docker Buildx
id: setup-buildx
uses: docker/setup-buildx-action@v3
- name: Bake login multi-arch
uses: docker/bake-action@v6
@@ -58,13 +61,9 @@ jobs:
source: .
push: true
provenance: true
sbom: true
targets: login-standalone
set: |
*.cache-from=type=gha
*.cache-to=type=gha,mode=max
files: |
./apps/login/docker-bake.hcl
./apps/login/docker-bake-release.hcl
${{ github.event_name == 'workflow_dispatch' && './apps/login/docker-bake-release.hcl' || '' }}
./docker-bake.hcl
cwd://${{ steps.login-meta.outputs.bake-file }}

View File

@@ -0,0 +1,58 @@
name: Integration test core
on:
workflow_call:
inputs:
login_build_image:
required: true
type: string
permissions:
packages: write
jobs:
login-integration-test:
name: login-integration-test
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install Dev Container CLI
run: npm install -g @devcontainers/cli@0.80.0
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Pull Login Build Image
run: docker compose --file .devcontainer/login-integration/docker-compose.yaml pull
env:
LOGIN_TAG: ${{ inputs.login_build_image }}
- name: Run Integration Tests against the Login and a Mocked Zitadel API
run: npm run devcontainer:integration:login
env:
LOGIN_TAG: ${{ inputs.login_build_image }}
DOCKER_BUILDKIT: 1
- name: Fix Failures
if: failure()
run: |
echo "Reproduce this check locally:"
echo "LOGIN_TAG=${{ inputs.login_build_image }} npm run devcontainer:integration:login"
echo "To fix the failures, open the dev container called \"Login Integration Tests\"."
echo "You will have the same environment as the pipeline check as well as some guidance on how to fix the errors."
- name: Show Compose Status
if: failure()
run: docker compose --file .devcontainer/base/docker-compose.yaml --file .devcontainer/login-integration-ci/docker-compose.yaml ps
- name: Print Config
if: failure()
run: COMPOSE_BAKE=1 docker compose --file .devcontainer/base/docker-compose.yaml --file .devcontainer/login-integration-ci/docker-compose.yaml config login-integration
env:
LOGIN_TAG: ${{ inputs.login_build_image }}
- name: Show Container Logs
if: failure()
run: docker compose --file .devcontainer/base/docker-compose.yaml --file .devcontainer/login-integration-ci/docker-compose.yaml logs --timestamps --no-color --tail 100 login-integration
- name: Inspect All Failed Containers
if: failure()
run: |
docker ps -a --filter "status=exited" --filter "status=created" --format "table {{.ID}}\t{{.Names}}\t{{.Status}}\t{{.Image}}"
for container in $(docker ps -a --filter "status=exited" --filter "status=created" -q); do
echo "Inspecting container $container"
docker inspect $container || true
done

View File

@@ -1,6 +1,5 @@
# Contributing to Zitadel
## Introduction
Thank you for your interest about how to contribute! As you might know there is more than code to contribute. You can find all information needed to start contributing here.
@@ -150,51 +149,19 @@ The API is designed to be used by different clients, such as web applications, m
Therefore, the API is designed to be easy to use, consistent, and reliable.
Please check out the dedicated [API guidelines](./API_DESIGN.md) page when contributing to the API.
#### <a name="dev-containers"></>Developing Zitadel with Dev Containers
You can use dev containers if you'd like to make sure you have the same development environment like the corresponding GitHub PR checks use.
The following dev containers are available:
- **.devcontainer/base/devcontainer.json**: Contains everything you need to run whatever you want.
- **.devcontainer/turbo-lint-unit/devcontainer.json**: Runs a dev container that executes frontent linting and unit tests and then exits. This is useful to reproduce the corresponding GitHub PR check.
- **.devcontainer/turbo-lint-unit-debug/devcontainer.json**: Runs a dev container that executes frontent linting and unit tests in watch mode. You can fix the errors right away and have immediate feedback.
- **.devcontainer/login-integration/devcontainer.json**: Runs a dev container that executes login integration tests and then exits. This is useful to reproduce the corresponding GitHub PR check.
- **.devcontainer/login-integration-debug/devcontainer.json**: Runs a dev container that spins up the login in a hot-reloading dev server and executes login integration tests interactively. You can fix the errors right away and have immediate feedback.
You can also run the GitHub PR checks locally in dev containers without having to connect to a dev container.
The following pnpm commands use the [devcontainer CLI](https://github.com/devcontainers/cli/) and exit when the checks are done.
The minimal system requirements are having Docker and the devcontainers CLI installed.
If you don't have the node_modules installed already, you need to install the devcontainers CLI manually. Run `npm i -g @devcontainers/cli`. Alternatively, the [official Microsoft VS Code extension for Dev Containers](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers) offers a command `Dev Containers: Install devcontainer CLI`
```bash
npm run devcontainer:lint-unit
npm run devcontainer:integration:login
```
If you don't have NPM installed, copy and execute the scripts from the package.json directly.
To connect to a dev container to have full IDE support, follow the instructions provided by your code editor/IDE to initiate the dev container.
This typically involves opening the "Command Palette" or similar functionality and searching for commands related to "Dev Containers" or "Remote Containers".
The quick start guide for VS Code can found [here](https://code.visualstudio.com/docs/devcontainers/containers#_quick-start-open-an-existing-folder-in-a-container)
For example, to build and run the Zitadel binary in a dev container, connect your IDE to the dev container described in .devcontainer/base/devcontainer.json.
Run the following commands inside the container to start Zitadel.
```bash
make compile && ./zitadel start-from-init --masterkey MasterkeyNeedsToHave32Characters --tlsMode disabled
```
Zitadel serves traffic as soon as you can see the following log line:
`INFO[0001] server is listening on [::]:8080`
## <a name="backend"></a>Contribute Backend Code
### <a name="backend-requirements"></a> Backend Requirements
By executing the commands from this section, you run everything you need to develop the Zitadel backend locally.
> [!INFO]
> Some [dev containers are available](dev-containers) for remote development with docker and pipeline debugging in isolated environments.
> If you don't want to use one of the dev containers, you can develop the backend components directly on your local machine.
> To do so, proceed with installing the necessary dependencies.
Using [Docker Compose](https://docs.docker.com/compose/), you run a [PostgreSQL](https://www.postgresql.org/download/) on your local machine.
With [make](https://www.gnu.org/software/make/), you build a debuggable Zitadel binary and run it using [delve](https://github.com/go-delve/delve).
Then, you test your changes via the console your binary is serving at http://<span because="breaks the link"></span>localhost:8080 and by verifying the database.
@@ -208,6 +175,8 @@ The commands in this section are tested against the following software versions:
- [Go version 1.22](https://go.dev/doc/install)
- [Delve 1.9.1](https://github.com/go-delve/delve/tree/v1.9.1/Documentation/installation)
### <a name="build-and-run-zitadel"></a>Build and Run Zitadel
Make some changes to the source code, then run the database locally.
```bash
@@ -588,6 +557,48 @@ For the turbo commands, check your options with `pnpm turbo --help`
| `pnpm turbo down` | Remove containers and volumes | Shut down containers from the integration test setup `pnpm turbo down` |
| `pnpm turbo clean` | Remove downloaded dependencies and other generated files | Remove generated docs `pnpm turbo clean --filter zitadel-docs` |
## <a name="dev-containers"></>Developing Zitadel with Dev Containers
You can use dev containers if you'd like to make sure you have the same development environment like the corresponding GitHub PR checks use.
The following dev containers are available:
- **.devcontainer/base/devcontainer.json**: Contains everything you need to run whatever you want.
- **.devcontainer/turbo-lint-unit/devcontainer.json**: Runs a dev container that executes frontent linting and unit tests and then exits. This is useful to reproduce the corresponding GitHub PR check.
- **.devcontainer/turbo-lint-unit-debug/devcontainer.json**: Runs a dev container that executes frontent linting and unit tests in watch mode. You can fix the errors right away and have immediate feedback.
- **.devcontainer/login-integration/devcontainer.json**: Runs a dev container that executes login integration tests and then exits. This is useful to reproduce the corresponding GitHub PR check.
- **.devcontainer/login-integration-debug/devcontainer.json**: Runs a dev container that spins up the login in a hot-reloading dev server and executes login integration tests interactively. You can fix the errors right away and have immediate feedback.
You can also run the GitHub PR checks locally in dev containers without having to connect to a dev container.
The following pnpm commands use the [devcontainer CLI](https://github.com/devcontainers/cli/) and exit when the checks are done.
The minimal system requirements are having Docker and the devcontainers CLI installed.
If you don't have the node_modules installed already, you need to install the devcontainers CLI manually. Run `npm i -g @devcontainers/cli@0.80.0`. Alternatively, the [official Microsoft VS Code extension for Dev Containers](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers) offers a command `Dev Containers: Install devcontainer CLI`
```bash
npm run devcontainer:lint-unit
npm run devcontainer:integration:login
```
If you don't have NPM installed, copy and execute the scripts from the package.json directly.
To connect to a dev container to have full IDE support, follow the instructions provided by your code editor/IDE to initiate the dev container.
This typically involves opening the "Command Palette" or similar functionality and searching for commands related to "Dev Containers" or "Remote Containers".
The quick start guide for VS Code can found [here](https://code.visualstudio.com/docs/devcontainers/containers#_quick-start-open-an-existing-folder-in-a-container)
For example, to build and run the Zitadel binary in a dev container, connect your IDE to the dev container described in .devcontainer/base/devcontainer.json.
Run the following commands inside the container to start Zitadel.
```bash
make compile && ./zitadel start-from-init --masterkey MasterkeyNeedsToHave32Characters --tlsMode disabled
```
Zitadel serves traffic as soon as you can see the following log line:
`INFO[0001] server is listening on [::]:8080`
## <a name="contribute-translations"></a>Contribute Translations
Zitadel loads translations from four files:
@@ -608,11 +619,6 @@ You also have to add some changes to the following files:
- [Customized Text Docs](./docs/docs/guides/manage/customize/texts.md)
- [Add language option](./internal/api/ui/login/static/templates/external_not_found_option.html)
## Want to start Zitadel?
You can find an installation guide for all the different environments here:
[https://zitadel.com/docs/self-hosting/deploy/overview](https://zitadel.com/docs/self-hosting/deploy/overview)
## **Did you find a security flaw?**
- Please read [Security Policy](./SECURITY.md).

View File

@@ -1,5 +1,6 @@
NEXT_PUBLIC_BASE_PATH="/ui/v2/login"
ZITADEL_API_URL=http://mock-zitadel:22222
ZITADEL_API_URL=http://localhost:22222
ZITADEL_SERVICE_USER_TOKEN="yolo"
EMAIL_VERIFICATION=true
DEBUG=true
PORT=3001
NEXT_PUBLIC_BASE_PATH=/ui/v2/login

View File

@@ -2,6 +2,7 @@ custom-config.js
.env*.local
standalone
tsconfig.tsbuildinfo
cypress
.DS_Store
node_modules
@@ -11,6 +12,5 @@ node_modules
dist
dist-ssr
*.local
.env
.vscode
/blob-report/

View File

@@ -3,21 +3,21 @@ 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 && \
RUN corepack enable && COREPACK_ENABLE_DOWNLOAD_PROMPT=0 corepack prepare pnpm@10.13.1 --activate && \
apk update && \
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
RUN --mount=type=cache,id=pnpm,target=/root/.local/share/pnpm/store pnpm install --frozen-lockfile
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
COPY public public
FROM base AS login-standalone
WORKDIR /runtime
@@ -25,12 +25,13 @@ 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 ./scripts/ ./
COPY --chown=nextjs:nodejs --from=build-out / ./
USER nextjs
ENV HOSTNAME="0.0.0.0"
ENV PORT=3000
ENV HOSTNAME="0.0.0.0" \
NEXT_PUBLIC_BASE_PATH="/ui/v2/login" \
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"]
CMD ["/bin/sh", "-c", "node /runtime/healthcheck.js http://localhost:${PORT}/ui/v2/login/healthy"]
ENTRYPOINT ["/runtime/entrypoint.sh"]

View File

@@ -8,7 +8,8 @@
!next.config.mjs
!next-env-vars.d.ts
!next-env.d.ts
!tailwind.config.js
!tailwind.config.mjs
!postcss.config.cjs
!tsconfig.json
!package.json
!pnpm-lock.yaml

View File

@@ -1,20 +0,0 @@
{
"name": "login-test-acceptance",
"private": true,
"scripts": {
"test:acceptance": "dotenv -e ../login/.env.test.local playwright",
"test:acceptance:setup": "cd ../.. && make login_test_acceptance_setup_env && NODE_ENV=test turbo run test:acceptance:setup:dev",
"test:acceptance:setup:dev": "cd ../.. && make login_test_acceptance_setup_dev",
"clean": "rm -rf .turbo node_modules"
},
"devDependencies": {
"@faker-js/faker": "^9.7.0",
"@otplib/core": "^12.0.0",
"@otplib/plugin-crypto": "^12.0.0",
"@otplib/plugin-thirty-two": "^12.0.0",
"@playwright/test": "^1.52.0",
"dotenv-cli": "^8.0.0",
"gaxios": "^7.1.0",
"typescript": "^5.8.3"
}
}

View File

@@ -2,11 +2,11 @@ import { defineConfig } from "cypress";
export default defineConfig({
reporter: "list",
video: true,
e2e: {
baseUrl: process.env.LOGIN_BASE_URL || "http://localhost:3001/ui/v2/login",
specPattern: "integration/**/*.cy.{js,jsx,ts,tsx}",
supportFile: "support/e2e.{js,jsx,ts,tsx}",
specPattern: "integration/integration/**/*.cy.{js,jsx,ts,tsx}",
supportFile: "integration/support/e2e.{js,jsx,ts,tsx}",
setupNodeEvents(on, config) {
// implement node event listeners here
},

View File

@@ -1,8 +1,10 @@
FROM bufbuild/buf:1.54.0 AS proto-files
RUN buf export https://github.com/envoyproxy/protoc-gen-validate.git --path validate --output /proto-files && \
buf export https://github.com/grpc-ecosystem/grpc-gateway.git --path protoc-gen-openapiv2 --output /proto-files && \
buf export https://github.com/googleapis/googleapis.git --path protos/zitadelgoogle/api/annotations.proto --path google/api/http.proto --path google/api/field_behavior.proto --output /proto-files && \
buf export https://github.com/zitadel/zitadel.git --path ./proto/zitadel --output /proto-files
FROM bufbuild/buf:1.54.0 AS dependencies
RUN buf export https://github.com/envoyproxy/protoc-gen-validate.git --path validate --output /proto && \
buf export https://github.com/grpc-ecosystem/grpc-gateway.git --path protoc-gen-openapiv2 --output /proto && \
buf export https://github.com/googleapis/googleapis.git --path google/api/annotations.proto --path google/api/http.proto --path google/api/field_behavior.proto --output /proto
FROM bufbuild/buf:1.54.0 AS zitadel-protos
RUN buf export https://github.com/zitadel/zitadel.git --path ./proto/zitadel --output /zitadel
FROM golang:1.20.5-alpine3.18 AS mock-zitadel
@@ -10,6 +12,7 @@ RUN go install github.com/eliobischof/grpc-mock/cmd/grpc-mock@01b09f60db1b501178
COPY mocked-services.cfg .
COPY initial-stubs initial-stubs
COPY --from=proto-files /proto-files/ ./
COPY --from=dependencies /proto/ ./
COPY --from=zitadel-protos /zitadel/ ./zitadel/
ENTRYPOINT [ "sh", "-c", "grpc-mock -v 1 -proto $(tr '\n' ',' < ./mocked-services.cfg) -stub-dir ./initial-stubs -mock-addr :22222" ]

View File

@@ -1,5 +0,0 @@
{
"name": "Using fixtures to represent data",
"email": "hello@cypress.io",
"body": "Fixtures are a great way to mock data for responses to routes"
}

View File

@@ -22,22 +22,22 @@ describe("verify invite", () => {
user: {
userId: "221394658884845598",
state: 1,
username: "john@zitadel.com",
loginNames: ["john@zitadel.com"],
preferredLoginName: "john@zitadel.com",
username: "john@example.com",
loginNames: ["john@example.com"],
preferredLoginName: "john@example.com",
human: {
userId: "221394658884845598",
state: 1,
username: "john@zitadel.com",
loginNames: ["john@zitadel.com"],
preferredLoginName: "john@zitadel.com",
username: "john@example.com",
loginNames: ["john@example.com"],
preferredLoginName: "john@example.com",
profile: {
givenName: "John",
familyName: "Doe",
avatarUrl: "https://zitadel.com/avatar.jpg",
avatarUrl: "https://example.com/avatar.jpg",
},
email: {
email: "john@zitadel.com",
email: "john@example.com",
isVerified: false,
},
},
@@ -68,7 +68,7 @@ describe("verify invite", () => {
factors: {
user: {
id: "221394658884845598",
loginName: "john@zitadel.com",
loginName: "john@example.com",
},
password: undefined,
webAuthN: undefined,
@@ -93,7 +93,7 @@ describe("verify invite", () => {
stub("zitadel.user.v2.UserService", "VerifyInviteCode");
cy.visit("/verify?userId=221394658884845598&code=abc&invite=true");
cy.url({ timeout: 10_000 }).should("include", Cypress.config().baseUrl + "/authenticator/set");
cy.url().should("include", Cypress.config().baseUrl + "/authenticator/set");
});
it("shows an error if invite code validation failed", () => {

View File

@@ -33,7 +33,7 @@ describe("login", () => {
factors: {
user: {
id: "221394658884845598",
loginName: "john@zitadel.com",
loginName: "john@example.com",
},
password: undefined,
webAuthN: undefined,
@@ -64,22 +64,22 @@ describe("login", () => {
{
userId: "221394658884845598",
state: 1,
username: "john@zitadel.com",
loginNames: ["john@zitadel.com"],
preferredLoginName: "john@zitadel.com",
username: "john@example.com",
loginNames: ["john@example.com"],
preferredLoginName: "john@example.com",
human: {
userId: "221394658884845598",
state: 1,
username: "john@zitadel.com",
loginNames: ["john@zitadel.com"],
preferredLoginName: "john@zitadel.com",
username: "john@example.com",
loginNames: ["john@example.com"],
preferredLoginName: "john@example.com",
profile: {
givenName: "John",
familyName: "Doe",
avatarUrl: "https://zitadel.com/avatar.jpg",
avatarUrl: "https://example.com/avatar.jpg",
},
email: {
email: "john@zitadel.com",
email: "john@example.com",
isVerified: true,
},
},
@@ -94,8 +94,8 @@ describe("login", () => {
});
});
it("should redirect a user with password authentication to /password", () => {
cy.visit("/loginname?loginName=john%40zitadel.com&submit=true");
cy.url({ timeout: 10_000 }).should("include", Cypress.config().baseUrl + "/password");
cy.visit("/loginname?loginName=john%40example.com&submit=true");
cy.url({ timeout: 5 * 60_000 }).should("include", Cypress.config().baseUrl + "/password");
});
describe("with passkey prompt", () => {
beforeEach(() => {
@@ -112,8 +112,8 @@ describe("login", () => {
});
});
// it("should prompt a user to setup passwordless authentication if passkey is allowed in the login settings", () => {
// cy.visit("/loginname?loginName=john%40zitadel.com&submit=true");
// cy.location("pathname", { timeout: 10_000 }).should("eq", "/password");
// cy.visit("/loginname?loginName=john%40example.com&submit=true");
// cy.location("pathname", { timeout: 5 * 60_000 }).should("eq", "/password");
// cy.get('input[type="password"]').focus().type("MyStrongPassword!1");
// cy.get('button[type="submit"]').click();
// cy.location("pathname", { timeout: 10_000 }).should(
@@ -134,22 +134,22 @@ describe("login", () => {
{
userId: "221394658884845598",
state: 1,
username: "john@zitadel.com",
loginNames: ["john@zitadel.com"],
preferredLoginName: "john@zitadel.com",
username: "john@example.com",
loginNames: ["john@example.com"],
preferredLoginName: "john@example.com",
human: {
userId: "221394658884845598",
state: 1,
username: "john@zitadel.com",
loginNames: ["john@zitadel.com"],
preferredLoginName: "john@zitadel.com",
username: "john@example.com",
loginNames: ["john@example.com"],
preferredLoginName: "john@example.com",
profile: {
givenName: "John",
familyName: "Doe",
avatarUrl: "https://zitadel.com/avatar.jpg",
avatarUrl: "https://example.com/avatar.jpg",
},
email: {
email: "john@zitadel.com",
email: "john@example.com",
isVerified: true,
},
},
@@ -165,8 +165,8 @@ describe("login", () => {
});
it("should redirect a user with passwordless authentication to /passkey", () => {
cy.visit("/loginname?loginName=john%40zitadel.com&submit=true");
cy.url({ timeout: 10_000 }).should("include", Cypress.config().baseUrl + "/passkey");
cy.visit("/loginname?loginName=john%40example.com&submit=true");
cy.url().should("include", Cypress.config().baseUrl + "/passkey");
});
});
});

View File

@@ -15,7 +15,7 @@ describe("register idps", () => {
cy.visit("/idp");
cy.get('button[e2e="google"]').click();
cy.origin(IDP_URL, { args: IDP_URL }, (url) => {
cy.location("href", { timeout: 10_000 }).should("eq", url);
cy.location("href").should("eq", url);
});
});
});

View File

@@ -48,7 +48,7 @@ describe("register", () => {
factors: {
user: {
id: "221394658884845598",
loginName: "john@zitadel.com",
loginName: "john@example.com",
},
password: undefined,
webAuthN: undefined,
@@ -64,10 +64,10 @@ describe("register", () => {
cy.visit("/register");
cy.get('input[data-testid="firstname-text-input"]').focus().type("John");
cy.get('input[data-testid="lastname-text-input"]').focus().type("Doe");
cy.get('input[data-testid="email-text-input"]').focus().type("john@zitadel.com");
cy.get('input[data-testid="email-text-input"]').focus().type("john@example.com");
cy.get('input[type="checkbox"][value="privacypolicy"]').check();
cy.get('input[type="checkbox"][value="tos"]').check();
cy.get('button[type="submit"]').click();
cy.url({ timeout: 10_000 }).should("include", Cypress.config().baseUrl + "/passkey/set");
cy.url().should("include", Cypress.config().baseUrl + "/passkey/set");
});
});

View File

@@ -24,22 +24,22 @@ describe("verify email", () => {
user: {
userId: "221394658884845598",
state: 1,
username: "john@zitadel.com",
loginNames: ["john@zitadel.com"],
preferredLoginName: "john@zitadel.com",
username: "john@example.com",
loginNames: ["john@example.com"],
preferredLoginName: "john@example.com",
human: {
userId: "221394658884845598",
state: 1,
username: "john@zitadel.com",
loginNames: ["john@zitadel.com"],
preferredLoginName: "john@zitadel.com",
username: "john@example.com",
loginNames: ["john@example.com"],
preferredLoginName: "john@example.com",
profile: {
givenName: "John",
familyName: "Doe",
avatarUrl: "https://zitadel.com/avatar.jpg",
avatarUrl: "https://example.com/avatar.jpg",
},
email: {
email: "john@zitadel.com",
email: "john@example.com",
isVerified: false, // email is not verified yet
},
},
@@ -70,7 +70,7 @@ describe("verify email", () => {
factors: {
user: {
id: "221394658884845598",
loginName: "john@zitadel.com",
loginName: "john@example.com",
},
password: undefined,
webAuthN: undefined,
@@ -90,6 +90,6 @@ describe("verify email", () => {
// TODO: Avoid uncaught exception in application
cy.once("uncaught:exception", () => false);
cy.visit("/verify?userId=221394658884845598&code=abc");
cy.contains("Could not verify email", { timeout: 10_000 });
cy.contains("Could not verify email");
});
});

View File

@@ -1,4 +1,4 @@
const url = Cypress.env("CORE_MOCK_STUBS_URL") || "http://mock-zitadel:22220/v1/stubs";
const url = Cypress.env("CORE_MOCK_STUBS_URL") || "http://localhost:22220/v1/stubs";
function removeStub(service: string, method: string) {
return cy.request({

View File

@@ -4,5 +4,5 @@
"lib": ["es5", "dom"],
"types": ["cypress", "node"]
},
"include": ["**/*.ts"]
"include": ["**/*.ts", "../cypress.config.ts"]
}

View File

@@ -27,6 +27,8 @@ declare namespace NodeJS {
/**
* Optional: custom request headers to be added to every request
* Split by comma, key value pairs separated by colon
* For example: to call the Zitadel API at an internal address, you can set:
* `CUSTOM_REQUEST_HEADERS=Host:http://zitadel-internal:8080`
*/
CUSTOM_REQUEST_HEADERS?: string;
}

View File

@@ -1,5 +1,5 @@
{
"packageManager": "pnpm@9.1.2+sha256.19c17528f9ca20bd442e4ca42f00f1b9808a9cb419383cd04ba32ef19322aba7",
"packageManager": "pnpm@10.13.1",
"name": "@zitadel/login",
"private": true,
"type": "module",
@@ -15,8 +15,7 @@
"test:unit": "vitest --run",
"lint-staged": "lint-staged",
"clean": "rm -rf .turbo && rm -rf node_modules && rm -rf .next",
"test:integration:login": "cypress run",
"test:integration:login:debug": "cypress open",
"test:integration:login": "wait-on --simultaneous 1 http://localhost:3001/ui/v2/login/verify?userId=221394658884845598&code=abc && cypress run",
"test:acceptance": "dotenv -e ../login/.env.test.local playwright",
"test:acceptance:setup": "cd ../.. && make login_test_acceptance_setup_env && NODE_ENV=test turbo run test:acceptance:setup:dev",
"test:acceptance:setup:dev": "cd ../.. && make login_test_acceptance_setup_dev"
@@ -54,6 +53,11 @@
"devDependencies": {
"@babel/eslint-parser": "^7.23.0",
"@bufbuild/buf": "^1.53.0",
"@faker-js/faker": "^9.7.0",
"@otplib/core": "^12.0.0",
"@otplib/plugin-crypto": "^12.0.0",
"@otplib/plugin-thirty-two": "^12.0.0",
"@playwright/test": "^1.52.0",
"@testing-library/jest-dom": "^6.6.3",
"@testing-library/react": "^16.3.0",
"@types/ms": "2.1.0",
@@ -67,34 +71,30 @@
"@vercel/git-hooks": "1.0.0",
"@vitejs/plugin-react": "^4.4.1",
"autoprefixer": "10.4.21",
"concurrently": "^9.1.2",
"cypress": "^14.5.2",
"dotenv-cli": "^8.0.0",
"env-cmd": "^10.0.0",
"eslint": "^8.57.0",
"eslint-config-next": "15.4.0-canary.86",
"eslint-config-prettier": "^9.1.0",
"gaxios": "^7.1.0",
"grpc-tools": "1.13.0",
"jsdom": "^26.1.0",
"lint-staged": "15.5.1",
"make-dir-cli": "4.0.0",
"nodemon": "^3.1.9",
"postcss": "8.5.3",
"prettier": "^3.2.5",
"prettier-plugin-organize-imports": "^3.2.0",
"prettier-plugin-tailwindcss": "0.6.11",
"sass": "^1.87.0",
"start-server-and-test": "^2.0.11",
"tailwindcss": "3.4.14",
"ts-proto": "^2.7.0",
"typescript": "^5.8.3",
"vite-tsconfig-paths": "^5.1.4",
"vitest": "^2.0.0",
"concurrently": "^9.1.2",
"cypress": "^14.5.2",
"dotenv-cli": "^8.0.0",
"env-cmd": "^10.0.0",
"nodemon": "^3.1.9",
"start-server-and-test": "^2.0.11",
"@faker-js/faker": "^9.7.0",
"@otplib/core": "^12.0.0",
"@otplib/plugin-crypto": "^12.0.0",
"@otplib/plugin-thirty-two": "^12.0.0",
"@playwright/test": "^1.52.0",
"gaxios": "^7.1.0"
"wait-on": "^7.2.0"
}
}

9151
apps/login/pnpm-lock.yaml generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,22 +1,57 @@
{
"extends": ["//"],
"extends": [
"//"
],
"tasks": {
"build": {
"outputs": ["dist/**", ".next/**", "!.next/cache/**"],
"dependsOn": ["@zitadel/client#build"]
"outputs": [
"dist/**",
".next/**",
"!.next/cache/**"
],
"dependsOn": [
"@zitadel/client#build"
]
},
"build:login:standalone": {
"outputs": ["dist/**", ".next/**", "!.next/cache/**"],
"dependsOn": ["@zitadel/client#build"]
"outputs": [
"dist/**",
".next/**",
"!.next/cache/**"
],
"dependsOn": [
"@zitadel/client#build"
]
},
"dev": {
"dependsOn": ["@zitadel/client#build"]
"persistent": true,
"cache": false,
"dependsOn": [
"@zitadel/client#build"
]
},
"test": {
"dependsOn": ["@zitadel/client#build"]
"dependsOn": [
"@zitadel/client#build"
]
},
"test:unit": {
"dependsOn": ["@zitadel/client#build"]
"dependsOn": [
"@zitadel/client#build"
]
},
"test:integration:login": {
"inputs": [
".next/**",
"!.next/cache/**",
"integration/integration/**",
"integration/support/**",
"cypress.config.ts"
],
"outputs": [
"cypress/videos/**",
"cypress/screenshots/**"
]
}
}
}

View File

@@ -1,34 +1,43 @@
FROM node:20-alpine AS base
FROM node:20-alpine AS runtime
FROM base AS build
FROM runtime AS pnpm-base
RUN apk add --no-cache libc6-compat
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/package.json ./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
RUN corepack enable && corepack prepare pnpm@10.13.1 --activate
RUN --mount=type=cache,id=pnpm,target=/pnpm/store \
pnpm add -g turbo@2.5.5
FROM pnpm-base AS pruner
WORKDIR /prune
COPY . .
RUN pnpm turbo build:login:standalone
RUN pnpm turbo prune @zitadel/login @zitadel/client @zitadel/proto --docker
FROM pnpm-base AS installer
WORKDIR /install
COPY --from=pruner /prune/out/pnpm-lock.yaml ./
RUN --mount=type=cache,id=pnpm,target=/pnpm/store \
pnpm fetch --frozen-lockfile
COPY --from=pruner /prune/out/json/ .
RUN --mount=type=cache,id=pnpm,target=/pnpm/store \
pnpm install --frozen-lockfile --ignore-scripts
FROM pnpm-base AS builder
WORKDIR /build
COPY --from=installer /install/ .
COPY --from=pruner /prune/out/full/ .
COPY proto ./proto
ENV CI=true
RUN --mount=type=cache,id=turbo,target=/build/.turbo/cache \
--mount=type=cache,id=next,target=/build/apps/login/.next/cache \
pnpm turbo build:login:standalone --cache-dir=/build/.turbo/cache
FROM scratch AS build-out
COPY /apps/login/public ./apps/login/public
COPY --from=build /app/apps/login/.next/standalone ./
COPY --from=build /app/apps/login/.next/static ./apps/login/.next/static
COPY --from=builder /build/apps/login/.next/standalone ./
COPY --from=builder /build/apps/login/.next/static ./apps/login/.next/static
FROM base AS login-standalone
FROM runtime AS login-standalone
WORKDIR /runtime
RUN addgroup --system --gid 1001 nodejs && \
adduser --system --uid 1001 nextjs
@@ -36,10 +45,11 @@ RUN addgroup --system --gid 1001 nodejs && \
RUN mkdir -p /.env-file && touch /.env-file/.env && chown -R nextjs:nodejs /.env-file
COPY --chown=nextjs:nodejs apps/login/scripts ./
COPY --chown=nextjs:nodejs --from=build-out . .
# Debug the final structure
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"]
CMD ["/bin/sh", "-c", "node /runtime/healthcheck.js http://localhost:${PORT}/ui/v2/login/healthy"]
ENTRYPOINT ["/runtime/entrypoint.sh"]

View File

@@ -524,7 +524,7 @@ OIDC:
PollInterval: 5s # ZITADEL_OIDC_DEVICEAUTH_POLLINTERVAL
UserCode:
CharSet: "BCDFGHJKLMNPQRSTVWXZ" # ZITADEL_OIDC_DEVICEAUTH_USERCODE_CHARSET
CharAmount: 8 # ZITADEL_OIDC_DEVICEAUTH_USERCODE_CHARARMOUNT
CharAmount: 8 # ZITADEL_OIDC_DEVICEAUTH_USERCODE_CHARAMOUNT
DashInterval: 4 # ZITADEL_OIDC_DEVICEAUTH_USERCODE_DASHINTERVAL
DefaultLoginURLV2: "/ui/v2/login/login?authRequest=" # ZITADEL_OIDC_DEFAULTLOGINURLV2
DefaultLogoutURLV2: "/ui/v2/login/logout?post_logout_redirect=" # ZITADEL_OIDC_DEFAULTLOGOUTURLV2

View File

@@ -66,18 +66,24 @@
.type-icon {
color: $primary-color;
}
.type-button-icon,
.type-icon,
span {
margin-right: 1rem;
}
.type-icon,
.type-button-icon {
position: relative;
}
> span {
margin-right: 1rem;
}
button[mat-icon-button] {
margin-right: 0;
.type-button-icon {
margin-right: 0;
}
}
}
.trigger-wrapper {

View File

@@ -6,8 +6,6 @@ target "login-standalone" {
target "login-standalone-out" {
inherits = ["login-standalone"]
target = "build-out"
output = [
"type=local,dest=.artifacts/login"
]
output = ["type=local,dest=.artifacts/login"]
}

View File

@@ -184,7 +184,7 @@ https://github.com/zitadel/actions/blob/main/examples/add_metadata.js
## Use provided fields of identity providers
If you want to ensure that the data of a user are always update you can automatically update user fields during authentication and safe time of your customers and your team. 🤯
If you want to ensure that the data of a user are always up-to-date, you can automatically update user fields during authentication and save time of your customers and your team.
### Trigger

View File

@@ -1 +1 @@
login-client-pat
*.pat

View File

@@ -1,8 +1,6 @@
Open your favorite internet browser and navigate to [http://localhost:8080/ui/console](http://localhost:8080/ui/console).
This is the default IAM admin users login:
- **username**: *zitadel-admin@<span></span>zitadel.localhost*
- **password**: *Password1!*
Open your favorite internet browser and navigate to http://localhost:8080/ui/console?login_hint=zitadel-admin@zitadel.localhost.
Enther the password *Password1!* to log in.
:::info
In the above username, replace localhost with your configured external domain, if any. e.g. with *zitadel-admin@<span></span>zitadel.sso.my.domain.tld*
In the above login hint in the URL, replace localhost with your configured external domain, if any. e.g. with *zitadel-admin@<span></span>zitadel.sso.my.domain.tld*
:::

View File

@@ -5,61 +5,45 @@ sidebar_label: Docker Compose
import CodeBlock from '@theme/CodeBlock';
import DockerComposeSource from '!!raw-loader!./docker-compose.yaml'
import ExampleZitadelConfigSource from '!!raw-loader!./example-zitadel-config.yaml'
import ExampleZitadelSecretsSource from '!!raw-loader!./example-zitadel-secrets.yaml'
import ExampleZitadelInitStepsSource from '!!raw-loader!./example-zitadel-init-steps.yaml'
import Disclaimer from './_disclaimer.mdx'
import DefaultUser from './_defaultuser.mdx'
import Next from './_next.mdx'
import NoteInstanceNotFound from './troubleshooting/_note_instance_not_found.mdx';
The stack consists of four long-running containers and a couple of short-lived containers:
- A [Traefik](https://doc.traefik.io/traefik/) reverse proxy container with upstream HTTP/2 enabled, issuing a self-signed TLS certificate.
- A Login container that is accessible via Traefik at `/ui/v2/login`
- A Zitadel container that is accessible via Traefik at all other paths than `/ui/v2/login`.
- An insecure [PostgreSQL](https://www.postgresql.org/docs/current/index.html).
The Traefik container and the login container call the Zitadel container via the internal Docker network at `h2c://zitadel:8080`
The setup is tested against Docker version 28.3.2 and Docker Compose version v2.38.2
By executing the commands below, you will download the following files:
## Docker compose
By executing the commands below, you will download the following file:
<details>
<summary>docker-compose.yaml</summary>
<CodeBlock language="yaml">{DockerComposeSource}</CodeBlock>
</details>
<details>
<summary>example-zitadel-config.yaml</summary>
<CodeBlock language="yaml">{ExampleZitadelConfigSource}</CodeBlock>
</details>
<details>
<summary>example-zitadel-secrets.yaml</summary>
<CodeBlock language="yaml">{ExampleZitadelSecretsSource}</CodeBlock>
</details>
<details>
<summary>example-zitadel-init-steps.yaml</summary>
<CodeBlock language="yaml">{ExampleZitadelInitStepsSource}</CodeBlock>
</details>
```bash
# Download the docker compose example configuration.
wget https://raw.githubusercontent.com/zitadel/zitadel/main/docs/docs/self-hosting/deploy/docker-compose.yaml
# Download and adjust the example configuration file containing standard configuration.
wget https://raw.githubusercontent.com/zitadel/zitadel/main/docs/docs/self-hosting/deploy/example-zitadel-config.yaml
# Download and adjust the example configuration file containing secret configuration.
wget https://raw.githubusercontent.com/zitadel/zitadel/main/docs/docs/self-hosting/deploy/example-zitadel-secrets.yaml
# Download and adjust the example configuration file containing database initialization configuration.
wget https://raw.githubusercontent.com/zitadel/zitadel/main/docs/docs/self-hosting/deploy/example-zitadel-init-steps.yaml
# Make sure you have the latest version of the images
# Make sure you have the latest image versions
docker compose pull
# Run the containers
# Run the PostgreSQL database, the Zitadel API and the Zitadel login.
docker compose up
```
Open your favorite internet browser at https://localhost/ui/console?login_hint=zitadel-admin@zitadel.localhost.
Your browser warns you about the insecure self-signed TLS certificate. As localhost resolves to your local machine, you can safely proceed.
Use the password *Password1!* to log in.
<DefaultUser components={props.components} />
Read more about [the login process](/guides/integrate/login/oidc/login-users).
:::info
If you ran these commands for an existing instance that still uses the login v1, [create a login client for it to the now running v2 login](/self-hosting/manage/login-client#create-login-client).
Move the login client PAT to `./login-client.pat` and restart the login container.
```bash
docker compose restart login
```
Now, [enable the Login UI for all users](/self-hosting/manage/login-client#require-login-v2)
:::
<NoteInstanceNotFound/>
<Next components={props.components} />
<Disclaimer components={props.components} />

View File

@@ -1,117 +1,98 @@
services:
db:
image: postgres:17-alpine
restart: unless-stopped
environment:
- POSTGRES_USER=root
- POSTGRES_PASSWORD=postgres
networks:
- 'storage'
healthcheck:
test: [ "CMD-SHELL", "pg_isready", "-d", "db_prod" ]
interval: 10s
timeout: 60s
retries: 5
start_period: 10s
volumes:
- 'data:/var/lib/postgresql/data:rw'
zitadel-init:
restart: 'no'
networks:
- 'storage'
image: 'ghcr.io/zitadel/zitadel:v4.0.0-rc.2'
command: [ init, --config, /example-zitadel-config.yaml, --config, /example-zitadel-secrets.yaml ]
depends_on:
db:
condition: 'service_healthy'
volumes:
- './example-zitadel-config.yaml:/example-zitadel-config.yaml:ro'
- './example-zitadel-secrets.yaml:/example-zitadel-secrets.yaml:ro'
zitadel-setup:
restart: 'no'
networks:
- 'storage'
image: 'ghcr.io/zitadel/zitadel:v4.0.0-rc.2'
command: [ setup, --config, /current-dir/example-zitadel-config.yaml, --config, /current-dir/example-zitadel-secrets.yaml, --steps, /current-dir/example-zitadel-init-steps.yaml, --masterkey, MasterkeyNeedsToHave32Characters ]
depends_on:
zitadel-init:
condition: 'service_completed_successfully'
restart: false
volumes:
- '.:/current-dir:rw'
zitadel:
restart: 'unless-stopped'
networks:
- 'backend'
- 'storage'
labels:
- "traefik.http.routers.zitadel.rule=!PathPrefix(`/ui/v2/login`)"
- "traefik.http.routers.zitadel.tls=true" # Traefik uses a self-signed certificate
- "traefik.http.services.zitadel.loadbalancer.passhostheader=true"
- "traefik.http.services.zitadel.loadbalancer.server.scheme=h2c"
- "traefik.http.services.zitadel.loadbalancer.server.port=8080"
image: 'ghcr.io/zitadel/zitadel:v4.0.0-rc.2'
command: [ start, --config, /example-zitadel-config.yaml, --config, /example-zitadel-secrets.yaml, --masterkey, MasterkeyNeedsToHave32Characters ]
depends_on:
zitadel-setup:
condition: 'service_completed_successfully'
restart: true
volumes:
- './example-zitadel-config.yaml:/example-zitadel-config.yaml:ro'
- './example-zitadel-secrets.yaml:/example-zitadel-secrets.yaml:ro'
restart: unless-stopped
image: ghcr.io/zitadel/zitadel:latest
command: start-from-init --masterkey "MasterkeyNeedsToHave32Characters" --tlsMode disabled
environment:
ZITADEL_EXTERNALSECURE: false
ZITADEL_TLS_ENABLED: false
ZITADEL_DATABASE_POSTGRES_HOST: db
ZITADEL_DATABASE_POSTGRES_PORT: 5432
ZITADEL_DATABASE_POSTGRES_DATABASE: zitadel
ZITADEL_DATABASE_POSTGRES_USER_USERNAME: zitadel
ZITADEL_DATABASE_POSTGRES_USER_PASSWORD: zitadel
ZITADEL_DATABASE_POSTGRES_USER_SSL_MODE: disable
ZITADEL_DATABASE_POSTGRES_ADMIN_USERNAME: postgres
ZITADEL_DATABASE_POSTGRES_ADMIN_PASSWORD: postgres
ZITADEL_DATABASE_POSTGRES_ADMIN_SSL_MODE: disable
# By configuring a login client, the setup job creates a user of type machine with the role IAM_LOGIN_CLIENT.
# It writes a PAT to the path specified in ZITADEL_FIRSTINSTANCE_LOGINCLIENTPATPATH.
# The PAT is passed to the login container via the environment variable ZITADEL_SERVICE_USER_TOKEN_FILE.
ZITADEL_FIRSTINSTANCE_LOGINCLIENTPATPATH: /current-dir/login-client.pat
ZITADEL_FIRSTINSTANCE_ORG_HUMAN_PASSWORDCHANGEREQUIRED: false
ZITADEL_FIRSTINSTANCE_ORG_LOGINCLIENT_MACHINE_USERNAME: login-client
ZITADEL_FIRSTINSTANCE_ORG_LOGINCLIENT_MACHINE_NAME: Automatically Initialized IAM_LOGIN_CLIENT
ZITADEL_FIRSTINSTANCE_ORG_LOGINCLIENT_PAT_EXPIRATIONDATE: '2029-01-01T00:00:00Z'
ZITADEL_DEFAULTINSTANCE_FEATURES_LOGINV2_REQUIRED: true
ZITADEL_DEFAULTINSTANCE_FEATURES_LOGINV2_BASEURI: http://localhost:3000/ui/v2/login
ZITADEL_OIDC_DEFAULTLOGINURLV2: http://localhost:3000/ui/v2/login/login?authRequest=
ZITADEL_OIDC_DEFAULTLOGOUTURLV2: http://localhost:3000/ui/v2/login/logout?post_logout_redirect=
ZITADEL_SAML_DEFAULTLOGINURLV2: http://localhost:3000/ui/v2/login/login?samlRequest=
# By configuring a machine, the setup job creates a user of type machine with the role IAM_OWNER.
# It writes a personal access token (PAT) to the path specified in ZITADEL_FIRSTINSTANCE_PATPATH.
# The PAT can be used to provision resources with [Terraform](/docs/guides/manage/terraform-provider), for example.
ZITADEL_FIRSTINSTANCE_PATPATH: /current-dir/admin.pat
ZITADEL_FIRSTINSTANCE_ORG_MACHINE_MACHINE_USERNAME: admin
ZITADEL_FIRSTINSTANCE_ORG_MACHINE_MACHINE_NAME: Automatically Initialized IAM_OWNER
ZITADEL_FIRSTINSTANCE_ORG_MACHINE_MACHINEKEY_TYPE: 1
healthcheck:
test: [ "CMD", "/app/zitadel", "ready", "--config", "/example-zitadel-config.yaml", "--config", "/example-zitadel-secrets.yaml" ]
test:
- CMD
- /app/zitadel
- ready
interval: 10s
timeout: 60s
retries: 5
start_period: 10s
volumes:
- .:/current-dir:delegated
ports:
- 8080:8080
- 3000:3000
networks:
- zitadel
depends_on:
db:
condition: service_healthy
login:
restart: 'unless-stopped'
labels:
- "traefik.http.routers.login.rule=PathPrefix(`/ui/v2/login`)"
- "traefik.http.routers.login.tls=true" # Traefik uses a self-signed certificate
- "traefik.http.services.login.loadbalancer.passhostheader=true"
- "traefik.http.services.login.loadbalancer.server.port=3000"
image: 'ghcr.io/zitadel/zitadel-login:v4.0.0-rc.2'
restart: unless-stopped
image: ghcr.io/zitadel/zitadel-login:latest
# If you can't use the network_mode service:zitadel, you can pass the environment variable CUSTOM_REQUEST_HEADERS=Host:localhost instead.
network_mode: service:zitadel
environment:
- ZITADEL_API_URL=http://localhost:8080
- NEXT_PUBLIC_BASE_PATH=/ui/v2/login
- ZITADEL_SERVICE_USER_TOKEN_FILE=/current-dir/login-client-pat
- ZITADEL_SERVICE_USER_TOKEN_FILE=/current-dir/login-client.pat
user: "${UID:-1000}"
network_mode: service:zitadel
volumes:
- '.:/current-dir:ro'
depends_on:
zitadel-setup:
condition: 'service_completed_successfully'
restart: false
traefik:
image: traefik:latest
command: --providers.docker --api.insecure=true --entrypoints.websecure.address=:443 --log.level=DEBUG --accesslog
networks:
- 'backend'
ports:
- "443:443"
- "8080:8080"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- .:/current-dir:ro
depends_on:
zitadel:
condition: 'service_healthy'
login:
condition: 'service_started'
condition: service_healthy
restart: false
db:
restart: unless-stopped
image: postgres:17-alpine
environment:
PGUSER: postgres
POSTGRES_PASSWORD: postgres
healthcheck:
test:
- CMD-SHELL
- pg_isready
- -d
- zitadel
- -U
- postgres
interval: 10s
timeout: 30s
retries: 5
start_period: 20s
networks:
- zitadel
networks:
storage:
backend:
volumes:
data:
zitadel:

View File

@@ -1,22 +0,0 @@
# All possible options and their defaults: https://github.com/zitadel/zitadel/blob/main/cmd/defaults.yaml
ExternalSecure: true
ExternalPort: 443
# Traefik terminates TLS. Inside the Docker network, we use plain text.
TLS.Enabled: false
# If not using the docker compose example, adjust these values for connecting ZITADEL to your PostgreSQL
Database:
postgres:
Host: 'db'
Port: 5432
Database: zitadel
User.SSL.Mode: 'disable'
Admin.SSL.Mode: 'disable'
# Access logs allow us to debug Network issues
LogStore.Access.Stdout.Enabled: true
# Skipping the MFA init step allows us to immediately authenticate at the console
DefaultInstance.LoginPolicy.MfaInitSkipLifetime: "0s"

View File

@@ -1,11 +0,0 @@
# All possible options and their defaults: https://github.com/zitadel/zitadel/blob/main/cmd/setup/steps.yaml
FirstInstance:
LoginClientPatPath: '/current-dir/login-client-pat'
Org:
# We want to authenticate immediately at the console without changing the password
Human.PasswordChangeRequired: false
LoginClient:
Machine:
Username: 'login-client'
Name: 'Automatically Initialized IAM Login Client'
Pat.ExpirationDate: '2029-01-01T00:00:00Z'

View File

@@ -1,12 +0,0 @@
# All possible options and their defaults: https://github.com/zitadel/zitadel/blob/main/cmd/defaults.yaml
# If not using the docker compose example, adjust these values for connecting ZITADEL to your PostgreSQL
Database:
postgres:
User:
# If the user doesn't exist already, it is created
Username: 'zitadel_user'
Password: 'zitadel'
Admin:
Username: 'root'
Password: 'postgres'

View File

@@ -0,0 +1,47 @@
---
title: Connect your Self-Hosted Login UI to Zitadel
sidebar_label: Create a Login Client
---
To enable your self-hosted Login UI to connect to the Zitadel API, it needs a token for a user with the IAM_LOGIN_CLIENT role.
On new installations, the Zitadel setup job can be configured to automatically write a Personal Access Token (PAT) for the login client.
Check out [one of the deployment examples](https://zitadel.com/docs/self-hosting/deploy/overview) to learn how to do this.
However, if you want to replace the v1 login of an existing installation by a self-hosted v2 login, the setup job won't execute these steps.
In that case, you can create a new PAT for the login client manually.
## Create a Login Client User{#create-login-client}
In the following URLs, replace the base URL and the user ID according to your environment.
1. Create a new machine user, for example at http://localhost:8080/ui/console/users/create-machine
2. Create a PAT, for example at http://localhost:8080/ui/console/users/332169800719532035?new=true&id=pat
3. Save the PAT to a file, for example `/path/on/your/host/login-client.pat`
4. Make sure the user has the `Iam Login Client` role (internally called `IAM_LOGIN_CLIENT`), for example at http://localhost:8080/ui/console/instance/members
# Configure the Login UI
Make sure your Login UI has the environment variable `ZITADEL_SERVICE_USER_TOKEN` set with your PAT.
If you run the Login UI with Docker, you can also mount the file into the container and reference it by passing the environment variable `ZITADEL_SERVICE_USER_TOKEN_FILE`.
For example:
```bash
docker run -p 3000:3000 -v /path/on/your/host/login-client.pat:/path/in/container/login-client.pat:ro -e ZITADEL_SERVICE_USER_TOKEN_FILE=/path/in/container/login-client.pat ghcr.io/zitadel/zitadel-login:latest
```
# Enable the Login UI for all users{#require-login-v2}
:::caution
Before doing this, make sure you have a working PAT for an Iam Owner user.
In case something goes wrong and you lock yourself out from the login screen, you can revert the changes.
Create a machine user PAT like you created the [login client PAT above](#create-login-client), but give the user the Iam Owner role (internally called `IAM_OWNER`).
:::
Enable the `Login V2` feature flag, for example at the bottom of http://localhost:8080/ui/console/instance?id=features.
Enter the base URI of your Login UI, for example `http://localhost:3000/ui/v2/login`.
# Test
That's it!
Click your users avatar in the top right corner of the console and select `Log in With Another Account`.
You should see the new Login UI.

View File

@@ -67,6 +67,5 @@
"@docusaurus/module-type-aliases": "^3.8.1",
"@docusaurus/types": "^3.8.1",
"tailwindcss": "^3.2.4"
},
"packageManager": "pnpm@9.1.2+sha256.19c17528f9ca20bd442e4ca42f00f1b9808a9cb419383cd04ba32ef19322aba7"
}
}

View File

@@ -1094,6 +1094,7 @@ module.exports = {
items: [
"self-hosting/manage/production",
"self-hosting/manage/productionchecklist",
"self-hosting/manage/login-client",
"self-hosting/manage/configure/configure",
{
type: "category",

View File

@@ -17,7 +17,7 @@
"clean": "rm -rf .turbo node_modules"
},
"private": true,
"dependencies": {
"devDependencies": {
"@types/pg": "^8.11.6",
"cypress-wait-until": "^3.0.2",
"jsonwebtoken": "^9.0.2",
@@ -26,9 +26,7 @@
"prettier": "^3.3.3",
"typescript": "^5.5.4",
"uuid": "^10.0.0",
"wait-on": "^7.2.0"
},
"devDependencies": {
"wait-on": "^7.2.0",
"@types/node": "^22.3.0",
"cypress": "^14.5.3"
}

View File

@@ -1,15 +1,14 @@
{
"packageManager": "pnpm@9.1.2+sha256.19c17528f9ca20bd442e4ca42f00f1b9808a9cb419383cd04ba32ef19322aba7",
"packageManager": "pnpm@10.13.1",
"private": true,
"name": "zitadel-monorepo",
"scripts": {
"generate": "turbo run generate",
"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:lint-unit": "FAIL_COMMANDS_ON_ERRORS=true devcontainer up --prebuild --config .devcontainer/turbo-lint-unit/devcontainer.json --workspace-folder .",
"devcontainer:integration:login": "FAIL_COMMANDS_ON_ERRORS=true devcontainer up --prebuild --config .devcontainer/login-integration/devcontainer.json --workspace-folder .",
"clean": "turbo run clean",
"clean:all": "pnpm run clean && rm -rf .turbo node_modules",
"generate": "turbo run generate"
"clean:all": "pnpm run clean && rm -rf .turbo node_modules"
},
"pnpm": {
"overrides": {
@@ -21,6 +20,7 @@
"devDependencies": {
"@changesets/cli": "^2.29.5",
"@devcontainers/cli": "^0.80.0",
"sass": "^1.64.1",
"turbo": "2.5.5"
}
}

View File

@@ -1,4 +1,5 @@
{
"packageManager": "pnpm@10.13.1",
"name": "@zitadel/client",
"version": "1.3.1",
"license": "MIT",

View File

@@ -1,4 +1,5 @@
{
"packageManager": "pnpm@10.13.1",
"name": "@zitadel/proto",
"version": "1.3.1",
"license": "MIT",
@@ -77,7 +78,7 @@
},
"sideEffects": false,
"scripts": {
"generate": "pnpm exec buf generate ../../proto",
"generate": "buf generate ../../proto",
"clean": "rm -rf zitadel .turbo node_modules google protoc-gen-openapiv2 validate cjs types es"
},
"dependencies": {

2672
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,9 @@
{
"$schema": "https://turbo.build/schema.json",
"ui": "tui",
"globalDependencies": ["**/.env.*local"],
"globalDependencies": [
"**/.env.*local"
],
"globalEnv": [
"DEBUG",
"VERCEL_URL",
@@ -36,6 +38,7 @@
},
"start": {},
"test:unit": {},
"test:integration:login": {},
"test:acceptance": {},
"test:e2e": {},
"lint": {},