Compare commits

...

10 Commits

44 changed files with 44946 additions and 56340 deletions

View File

@ -28,9 +28,9 @@ runs:
- name: Setup node - name: Setup node
uses: actions/setup-node@v4 uses: actions/setup-node@v4
with: with:
node-version-file: web/package.json node-version-file: package.json
cache: "npm" cache: "npm"
cache-dependency-path: web/package-lock.json cache-dependency-path: package-lock.json
- name: Setup go - name: Setup go
uses: actions/setup-go@v5 uses: actions/setup-go@v5
with: with:
@ -44,7 +44,7 @@ runs:
run: | run: |
export PSQL_TAG=${{ inputs.postgresql_version }} export PSQL_TAG=${{ inputs.postgresql_version }}
docker compose -f .github/actions/setup/docker-compose.yml up -d docker compose -f .github/actions/setup/docker-compose.yml up -d
cd web && npm ci npm ci
- name: Generate config - name: Generate config
shell: uv run python {0} shell: uv run python {0}
run: | run: |

View File

@ -20,8 +20,11 @@ jobs:
token: ${{ steps.generate_token.outputs.token }} token: ${{ steps.generate_token.outputs.token }}
- uses: actions/setup-node@v4 - uses: actions/setup-node@v4
with: with:
node-version-file: web/package.json node-version-file: package.json
registry-url: "https://registry.npmjs.org" registry-url: "https://registry.npmjs.org"
- name: Prepare Dependencies
run: |
npm ci
- name: Generate API Client - name: Generate API Client
run: make gen-client-ts run: make gen-client-ts
- name: Publish package - name: Publish package
@ -32,15 +35,13 @@ jobs:
env: env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_PUBLISH_TOKEN }} NODE_AUTH_TOKEN: ${{ secrets.NPM_PUBLISH_TOKEN }}
- name: Upgrade /web - name: Upgrade /web
working-directory: web
run: | run: |
export VERSION=`node -e 'console.log(require("../gen-ts-api/package.json").version)'` export VERSION=`node -e 'console.log(require("./gen-ts-api/package.json").version)'`
npm i @goauthentik/api@$VERSION npm i @goauthentik/api@$VERSION -w @goauthentik/web
- name: Upgrade /web/packages/sfe - name: Upgrade /web/packages/sfe
working-directory: web/packages/sfe
run: | run: |
export VERSION=`node -e 'console.log(require("../gen-ts-api/package.json").version)'` export VERSION=`node -e 'console.log(require("./gen-ts-api/package.json").version)'`
npm i @goauthentik/api@$VERSION npm i @goauthentik/api@$VERSION -w @goauthentik/web-sfe
- uses: peter-evans/create-pull-request@v7 - uses: peter-evans/create-pull-request@v7
id: cpr id: cpr
with: with:

View File

@ -193,23 +193,22 @@ jobs:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Setup authentik env - name: Setup authentik env
uses: ./.github/actions/setup uses: ./.github/actions/setup
- name: Setup e2e env (chrome, etc) - name: Setup E2E environment (Chrome, etc)
run: | run: |
docker compose -f tests/e2e/docker-compose.yml up -d --quiet-pull docker compose -f tests/e2e/docker-compose.yml up -d --quiet-pull
- id: cache-web - id: cache-web
uses: actions/cache@v4 uses: actions/cache@v4
with: with:
path: web/dist path: web/dist
key: ${{ runner.os }}-web-${{ hashFiles('web/package-lock.json', 'web/src/**', 'web/packages/sfe/src/**') }}-b key: ${{ runner.os }}-web-${{ hashFiles('package-lock.json', 'web/src/**', 'web/packages/sfe/src/**') }}-b
- name: prepare web ui - name: Prepare Web UI
if: steps.cache-web.outputs.cache-hit != 'true' if: steps.cache-web.outputs.cache-hit != 'true'
working-directory: web
run: | run: |
npm ci npm ci
make -C .. gen-client-ts make gen-client-ts
npm run build npm run build -w @goauthentik/web
npm run build:sfe npm run build -w @goauthentik/web-sfe
- name: run e2e - name: Run E2E
run: | run: |
uv run coverage run manage.py test ${{ matrix.job.glob }} uv run coverage run manage.py test ${{ matrix.job.glob }}
uv run coverage xml uv run coverage xml

View File

@ -26,7 +26,7 @@ jobs:
mkdir -p web/dist mkdir -p web/dist
mkdir -p website/help mkdir -p website/help
touch web/dist/test website/help/test touch web/dist/test website/help/test
- name: Generate API - name: Generate Golang API Client
run: make gen-client-go run: make gen-client-go
- name: golangci-lint - name: golangci-lint
uses: golangci/golangci-lint-action@v8 uses: golangci/golangci-lint-action@v8
@ -43,7 +43,7 @@ jobs:
go-version-file: "go.mod" go-version-file: "go.mod"
- name: Setup authentik env - name: Setup authentik env
uses: ./.github/actions/setup uses: ./.github/actions/setup
- name: Generate API - name: Generate Golang API Client
run: make gen-client-go run: make gen-client-go
- name: Go unittests - name: Go unittests
run: | run: |
@ -99,7 +99,7 @@ jobs:
registry: ghcr.io registry: ghcr.io
username: ${{ github.repository_owner }} username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }} password: ${{ secrets.GITHUB_TOKEN }}
- name: Generate API - name: Generate Golang API Client
run: make gen-client-go run: make gen-client-go
- name: Build Docker Image - name: Build Docker Image
id: push id: push
@ -145,16 +145,17 @@ jobs:
go-version-file: "go.mod" go-version-file: "go.mod"
- uses: actions/setup-node@v4 - uses: actions/setup-node@v4
with: with:
node-version-file: web/package.json node-version-file: package.json
cache: "npm" cache: "npm"
cache-dependency-path: web/package-lock.json cache-dependency-path: package-lock.json
- name: Generate API - name: Generate Golang API Client
run: make gen-client-go run: make gen-client-go
- name: Build web - name: Prepare Dependencies
working-directory: web/
run: | run: |
npm ci npm ci
npm run build-proxy - name: Run ESBuild
run: |
npm run build-proxy -w @goauthentik/web
- name: Build outpost - name: Build outpost
run: | run: |
set -x set -x

View File

@ -19,47 +19,45 @@ jobs:
matrix: matrix:
command: command:
- lint - lint
- lint:lockfile
- tsc
- prettier-check - prettier-check
project: project:
- web - web
include: include:
- command: tsc
project: web
- command: lit-analyse - command: lit-analyse
project: web project: web
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: actions/setup-node@v4 - uses: actions/setup-node@v4
with: with:
node-version-file: ${{ matrix.project }}/package.json node-version-file: package.json
cache: "npm" cache: "npm"
cache-dependency-path: ${{ matrix.project }}/package-lock.json cache-dependency-path: package-lock.json
- working-directory: ${{ matrix.project }}/ - name: Prepare Dependencies
run: | run: |
npm ci npm ci
- name: Generate API - name: Generate TypeScript API
run: make gen-client-ts run: make gen-client-ts
- name: Lint - name: Lint Project
working-directory: ${{ matrix.project }}/ run: |
run: npm run ${{ matrix.command }} npm run build-locales -w @goauthentik/web
npm run lint:types
- name: Lint Web
run: npm run ${{ matrix.command }} -w @goauthentik/web
build: build:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: actions/setup-node@v4 - uses: actions/setup-node@v4
with: with:
node-version-file: web/package.json node-version-file: package.json
cache: "npm" cache: "npm"
cache-dependency-path: web/package-lock.json cache-dependency-path: package-lock.json
- working-directory: web/ - name: Prepare Dependencies
run: npm ci run: npm ci
- name: Generate API - name: Generate TypeScript API
run: make gen-client-ts run: make gen-client-ts
- name: build - name: build
working-directory: web/ run: npm run build -w @goauthentik/web
run: npm run build
ci-web-mark: ci-web-mark:
if: always() if: always()
needs: needs:
@ -78,13 +76,12 @@ jobs:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: actions/setup-node@v4 - uses: actions/setup-node@v4
with: with:
node-version-file: web/package.json node-version-file: package.json
cache: "npm" cache: "npm"
cache-dependency-path: web/package-lock.json cache-dependency-path: package-lock.json
- working-directory: web/ - name: Prepare Dependencies
run: npm ci run: npm ci
- name: Generate API - name: Generate TypeScript API
run: make gen-client-ts run: make gen-client-ts
- name: test - name: test
working-directory: web/ run: npm run test -w @goauthentik/web || exit 0
run: npm run test || exit 0

View File

@ -14,53 +14,44 @@ on:
jobs: jobs:
lint: lint:
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
command:
- lint:lockfile
- prettier-check
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- working-directory: website/ - uses: actions/setup-node@v4
with:
node-version-file: package.json
cache: "npm"
cache-dependency-path: package-lock.json
- name: Prepare Dependencies
run: npm ci run: npm ci
- name: Lint - name: Lint
working-directory: website/ run: npm run prettier-check -w @goauthentik/docs
run: npm run ${{ matrix.command }}
test: test:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: actions/setup-node@v4 - uses: actions/setup-node@v4
with: with:
node-version-file: website/package.json node-version-file: package.json
cache: "npm" cache: "npm"
cache-dependency-path: website/package-lock.json cache-dependency-path: package-lock.json
- working-directory: website/ - name: Prepare Dependencies
run: npm ci run: npm ci
- name: test - name: test
working-directory: website/ run: npm test -w @goauthentik/docs
run: npm test
build: build:
runs-on: ubuntu-latest runs-on: ubuntu-latest
name: ${{ matrix.job }}
strategy:
fail-fast: false
matrix:
job:
- build
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: actions/setup-node@v4 - uses: actions/setup-node@v4
with: with:
node-version-file: website/package.json node-version-file: package.json
cache: "npm" cache: "npm"
cache-dependency-path: website/package-lock.json cache-dependency-path: package-lock.json
- working-directory: website/ - name: Prepare Dependencies
run: npm ci run: npm ci
- name: build - name: Run Docusaurus
working-directory: website/ run: npm run build -w @goauthentik/docs
run: npm run ${{ matrix.job }}
ci-website-mark: ci-website-mark:
if: always() if: always()
needs: needs:

View File

@ -17,27 +17,28 @@ jobs:
fail-fast: false fail-fast: false
matrix: matrix:
package: package:
- docusaurus-config - packages/docusaurus-config
- eslint-config - packages/eslint-config
- prettier-config - packages/prettier-config
- tsconfig - packages/tsconfig
- packages/web/esbuild-plugin-live-reload
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with: with:
fetch-depth: 2 fetch-depth: 2
- uses: actions/setup-node@v4 - uses: actions/setup-node@v4
with: with:
node-version-file: packages/${{ matrix.package }}/package.json node-version-file: ${{ matrix.package }}/package.json
registry-url: "https://registry.npmjs.org" registry-url: "https://registry.npmjs.org"
- name: Get changed files - name: Get changed files
id: changed-files id: changed-files
uses: tj-actions/changed-files@ed68ef82c095e0d48ec87eccea555d944a631a4c uses: tj-actions/changed-files@ed68ef82c095e0d48ec87eccea555d944a631a4c
with: with:
files: | files: |
packages/${{ matrix.package }}/package.json ${{ matrix.package }}/package.json
- name: Publish package - name: Publish package
if: steps.changed-files.outputs.any_changed == 'true' if: steps.changed-files.outputs.any_changed == 'true'
working-directory: packages/${{ matrix.package}} working-directory: ${{ matrix.package }}
run: | run: |
npm ci npm ci
npm run build npm run build

View File

@ -106,14 +106,14 @@ jobs:
go-version-file: "go.mod" go-version-file: "go.mod"
- uses: actions/setup-node@v4 - uses: actions/setup-node@v4
with: with:
node-version-file: web/package.json node-version-file: package.json
cache: "npm" cache: "npm"
cache-dependency-path: web/package-lock.json cache-dependency-path: package-lock.json
- name: Build web - name: Prepare Dependencies
working-directory: web/ run: npm ci
- name: Run ESBuild (Proxy)
run: | run: |
npm ci npm run build-proxy -w @goauthentik/web
npm run build-proxy
- name: Build outpost - name: Build outpost
run: | run: |
set -x set -x

View File

@ -32,15 +32,25 @@ jobs:
if: ${{ github.event_name == 'pull_request' }} if: ${{ github.event_name == 'pull_request' }}
- name: Setup authentik env - name: Setup authentik env
uses: ./.github/actions/setup uses: ./.github/actions/setup
- name: Generate API - uses: actions/setup-node@v4
with:
node-version-file: package.json
cache: "npm"
cache-dependency-path: package-lock.json
- name: Prepare Dependencies
run: npm ci
- name: Generate TypeScript API
run: make gen-client-ts run: make gen-client-ts
- name: run extract - name: Run extract
run: | run: |
uv run make i18n-extract uv run make i18n-extract
- name: run compile - name: Run UV compile
run: | run: |
uv run ak compilemessages uv run ak compilemessages
make web-check-compile - name: Lint Project
run: |
npm run build-locales -w @goauthentik/web
npm run lint:types
- name: Create Pull Request - name: Create Pull Request
if: ${{ github.event_name != 'pull_request' }} if: ${{ github.event_name != 'pull_request' }}
uses: peter-evans/create-pull-request@v7 uses: peter-evans/create-pull-request@v7

View File

@ -36,12 +36,19 @@ coverage
*.mdx *.mdx
*.md *.md
## Import order matters
poly.ts
src/locale-codes.ts
src/locales/
# Storybook # Storybook
storybook-static/ storybook-static/
.storybook/css-import-maps* .storybook/css-import-maps*
# JSON Schemas
schemas/**/*.json
blueprints/**/*.json
authentik/**/*.json
lifecycle/**/*.json
# Locales
web/src/locale-codes.ts
web/src/locales/
# Wireit's cache
.wireit

View File

@ -17,6 +17,6 @@
"ms-python.vscode-pylance", "ms-python.vscode-pylance",
"redhat.vscode-yaml", "redhat.vscode-yaml",
"Tobermory.es6-string-html", "Tobermory.es6-string-html",
"unifiedjs.vscode-mdx", "unifiedjs.vscode-mdx"
] ]
} }

40
.vscode/tasks.json vendored
View File

@ -4,12 +4,7 @@
{ {
"label": "authentik/core: make", "label": "authentik/core: make",
"command": "uv", "command": "uv",
"args": [ "args": ["run", "make", "lint-fix", "lint"],
"run",
"make",
"lint-fix",
"lint"
],
"presentation": { "presentation": {
"panel": "new" "panel": "new"
}, },
@ -18,11 +13,7 @@
{ {
"label": "authentik/core: run", "label": "authentik/core: run",
"command": "uv", "command": "uv",
"args": [ "args": ["run", "ak", "server"],
"run",
"ak",
"server"
],
"group": "build", "group": "build",
"presentation": { "presentation": {
"panel": "dedicated", "panel": "dedicated",
@ -32,17 +23,13 @@
{ {
"label": "authentik/web: make", "label": "authentik/web: make",
"command": "make", "command": "make",
"args": [ "args": ["web"],
"web"
],
"group": "build" "group": "build"
}, },
{ {
"label": "authentik/web: watch", "label": "authentik/web: watch",
"command": "make", "command": "make",
"args": [ "args": ["web-watch"],
"web-watch"
],
"group": "build", "group": "build",
"presentation": { "presentation": {
"panel": "dedicated", "panel": "dedicated",
@ -52,26 +39,19 @@
{ {
"label": "authentik: install", "label": "authentik: install",
"command": "make", "command": "make",
"args": [ "args": ["install", "-j4"],
"install",
"-j4"
],
"group": "build" "group": "build"
}, },
{ {
"label": "authentik/website: make", "label": "authentik/website: make",
"command": "make", "command": "make",
"args": [ "args": ["website"],
"website"
],
"group": "build" "group": "build"
}, },
{ {
"label": "authentik/website: watch", "label": "authentik/website: watch",
"command": "make", "command": "make",
"args": [ "args": ["website-watch"],
"website-watch"
],
"group": "build", "group": "build",
"presentation": { "presentation": {
"panel": "dedicated", "panel": "dedicated",
@ -81,11 +61,7 @@
{ {
"label": "authentik/api: generate", "label": "authentik/api: generate",
"command": "uv", "command": "uv",
"args": [ "args": ["run", "make", "gen"],
"run",
"make",
"gen"
],
"group": "build" "group": "build"
} }
] ]

View File

@ -1,49 +1,41 @@
# syntax=docker/dockerfile:1 # syntax=docker/dockerfile:1
# Stage 1: Build website # Stage 1: Build Node packages
FROM --platform=${BUILDPLATFORM} docker.io/library/node:24 AS website-builder FROM --platform=${BUILDPLATFORM} docker.io/library/node:24-slim AS node-packages
ENV NODE_ENV=production
WORKDIR /work/website
RUN --mount=type=bind,target=/work/website/package.json,src=./website/package.json \
--mount=type=bind,target=/work/website/package-lock.json,src=./website/package-lock.json \
--mount=type=cache,id=npm-website,sharing=shared,target=/root/.npm \
npm ci --include=dev
COPY ./website /work/website/
COPY ./blueprints /work/blueprints/
COPY ./schema.yml /work/
COPY ./SECURITY.md /work/
RUN npm run build-bundled
# Stage 2: Build webui
FROM --platform=${BUILDPLATFORM} docker.io/library/node:24 AS web-builder
ARG GIT_BUILD_HASH ARG GIT_BUILD_HASH
ENV GIT_BUILD_HASH=$GIT_BUILD_HASH ENV GIT_BUILD_HASH=$GIT_BUILD_HASH
ENV NODE_ENV=production
WORKDIR /work/web WORKDIR /work
RUN --mount=type=bind,target=/work/web/package.json,src=./web/package.json \
--mount=type=bind,target=/work/web/package-lock.json,src=./web/package-lock.json \
--mount=type=bind,target=/work/web/packages/sfe/package.json,src=./web/packages/sfe/package.json \
--mount=type=bind,target=/work/web/scripts,src=./web/scripts \
--mount=type=cache,id=npm-web,sharing=shared,target=/root/.npm \
npm ci --include=dev
COPY ./SECURITY.md /work
COPY ./schema.yml /work
COPY ./docker-compose.yml /work
COPY ./blueprints /work/blueprints/
COPY ./package.json /work COPY ./package.json /work
COPY ./package-lock.json /work
COPY ./tsconfig.json /work
COPY ./packages/ /work/packages/
COPY ./web /work/web/ COPY ./web /work/web/
COPY ./website /work/website/ COPY ./website /work/website/
COPY ./gen-ts-api /work/web/node_modules/@goauthentik/api COPY ./gen-ts-api /work/gen-ts-api/
RUN npm run build && \ RUN --mount=type=cache,id=npm-node,sharing=shared,target=/root/.npm \
npm run build:sfe npm ci
# Stage 3: Build go proxy RUN cd ./gen-ts-api && npm link
RUN npm link @goauthentik/api -w @goauthentik/web
ENV NODE_ENV=production
RUN npm run build -w @goauthentik/web
RUN npm run build -w @goauthentik/web-sfe
RUN npm run build:api -w @goauthentik/docs
RUN npm run build:docusaurus -w @goauthentik/docs
# Stage 2: Build go proxy
FROM --platform=${BUILDPLATFORM} docker.io/library/golang:1.24-bookworm AS go-builder FROM --platform=${BUILDPLATFORM} docker.io/library/golang:1.24-bookworm AS go-builder
ARG TARGETOS ARG TARGETOS
@ -68,8 +60,8 @@ RUN --mount=type=bind,target=/go/src/goauthentik.io/go.mod,src=./go.mod \
COPY ./cmd /go/src/goauthentik.io/cmd COPY ./cmd /go/src/goauthentik.io/cmd
COPY ./authentik/lib /go/src/goauthentik.io/authentik/lib COPY ./authentik/lib /go/src/goauthentik.io/authentik/lib
COPY ./web/static.go /go/src/goauthentik.io/web/static.go COPY ./web/static.go /go/src/goauthentik.io/web/static.go
COPY --from=web-builder /work/web/robots.txt /go/src/goauthentik.io/web/robots.txt COPY --from=node-packages /work/web/robots.txt /go/src/goauthentik.io/web/robots.txt
COPY --from=web-builder /work/web/security.txt /go/src/goauthentik.io/web/security.txt COPY --from=node-packages /work/web/security.txt /go/src/goauthentik.io/web/security.txt
COPY ./internal /go/src/goauthentik.io/internal COPY ./internal /go/src/goauthentik.io/internal
COPY ./go.mod /go/src/goauthentik.io/go.mod COPY ./go.mod /go/src/goauthentik.io/go.mod
COPY ./go.sum /go/src/goauthentik.io/go.sum COPY ./go.sum /go/src/goauthentik.io/go.sum
@ -80,7 +72,7 @@ RUN --mount=type=cache,sharing=locked,target=/go/pkg/mod \
CGO_ENABLED=1 GOFIPS140=latest GOARM="${TARGETVARIANT#v}" \ CGO_ENABLED=1 GOFIPS140=latest GOARM="${TARGETVARIANT#v}" \
go build -o /go/authentik ./cmd/server go build -o /go/authentik ./cmd/server
# Stage 4: MaxMind GeoIP # Stage 3: MaxMind GeoIP
FROM --platform=${BUILDPLATFORM} ghcr.io/maxmind/geoipupdate:v7.1.0 AS geoip FROM --platform=${BUILDPLATFORM} ghcr.io/maxmind/geoipupdate:v7.1.0 AS geoip
ENV GEOIPUPDATE_EDITION_IDS="GeoLite2-City GeoLite2-ASN" ENV GEOIPUPDATE_EDITION_IDS="GeoLite2-City GeoLite2-ASN"
@ -93,9 +85,9 @@ RUN --mount=type=secret,id=GEOIPUPDATE_ACCOUNT_ID \
mkdir -p /usr/share/GeoIP && \ mkdir -p /usr/share/GeoIP && \
/bin/sh -c "GEOIPUPDATE_LICENSE_KEY_FILE=/run/secrets/GEOIPUPDATE_LICENSE_KEY /usr/bin/entry.sh || echo 'Failed to get GeoIP database, disabling'; exit 0" /bin/sh -c "GEOIPUPDATE_LICENSE_KEY_FILE=/run/secrets/GEOIPUPDATE_LICENSE_KEY /usr/bin/entry.sh || echo 'Failed to get GeoIP database, disabling'; exit 0"
# Stage 5: Download uv # Stage 4: Download uv
FROM ghcr.io/astral-sh/uv:0.7.6 AS uv FROM ghcr.io/astral-sh/uv:0.7.6 AS uv
# Stage 6: Base python image # Stage 5: Base python image
FROM ghcr.io/goauthentik/fips-python:3.13.3-slim-bookworm-fips AS python-base FROM ghcr.io/goauthentik/fips-python:3.13.3-slim-bookworm-fips AS python-base
ENV VENV_PATH="/ak-root/.venv" \ ENV VENV_PATH="/ak-root/.venv" \
@ -109,7 +101,7 @@ WORKDIR /ak-root/
COPY --from=uv /uv /uvx /bin/ COPY --from=uv /uv /uvx /bin/
# Stage 7: Python dependencies # Stage 6: Python dependencies
FROM python-base AS python-deps FROM python-base AS python-deps
ARG TARGETARCH ARG TARGETARCH
@ -144,7 +136,7 @@ RUN --mount=type=bind,target=pyproject.toml,src=pyproject.toml \
--mount=type=cache,target=/root/.cache/uv \ --mount=type=cache,target=/root/.cache/uv \
uv sync --frozen --no-install-project --no-dev uv sync --frozen --no-install-project --no-dev
# Stage 8: Run # Stage 7: Run
FROM python-base AS final-image FROM python-base AS final-image
ARG VERSION ARG VERSION
@ -187,9 +179,9 @@ COPY ./lifecycle/ /lifecycle
COPY ./authentik/sources/kerberos/krb5.conf /etc/krb5.conf COPY ./authentik/sources/kerberos/krb5.conf /etc/krb5.conf
COPY --from=go-builder /go/authentik /bin/authentik COPY --from=go-builder /go/authentik /bin/authentik
COPY --from=python-deps /ak-root/.venv /ak-root/.venv COPY --from=python-deps /ak-root/.venv /ak-root/.venv
COPY --from=web-builder /work/web/dist/ /web/dist/ COPY --from=node-packages /work/web/dist/ /web/dist/
COPY --from=web-builder /work/web/authentik/ /web/authentik/ COPY --from=node-packages /work/web/authentik/ /web/authentik/
COPY --from=website-builder /work/website/build/ /website/help/ COPY --from=node-packages /work/website/build/ /website/help/
COPY --from=geoip /usr/share/GeoIP /geoip COPY --from=geoip /usr/share/GeoIP /geoip
USER 1000 USER 1000

View File

@ -73,7 +73,7 @@ core-i18n-extract:
--ignore website \ --ignore website \
-l en -l en
install: web-install website-install core-install ## Install all requires dependencies for `web`, `website` and `core` install: npm-install core-install ## Install all requires dependencies for `web`, `website` and `core`
dev-drop-db: dev-drop-db:
dropdb -U ${pg_user} -h ${pg_host} ${pg_name} dropdb -U ${pg_user} -h ${pg_host} ${pg_name}
@ -146,9 +146,8 @@ gen-client-ts: gen-clean-ts ## Build and install the authentik API for Typescri
--additional-properties=npmVersion=${NPM_VERSION} \ --additional-properties=npmVersion=${NPM_VERSION} \
--git-repo-id authentik \ --git-repo-id authentik \
--git-user-id goauthentik --git-user-id goauthentik
mkdir -p web/node_modules/@goauthentik/api cd ./${GEN_API_TS} && npm link
cd ${PWD}/${GEN_API_TS} && npm i npm link @goauthentik/api -w @goauthentik/web
\cp -rf ${PWD}/${GEN_API_TS}/* web/node_modules/@goauthentik/api
gen-client-py: gen-clean-py ## Build and install the authentik API for Python gen-client-py: gen-clean-py ## Build and install the authentik API for Python
docker run \ docker run \
@ -183,38 +182,34 @@ gen: gen-build gen-client-ts
## Web ## Web
######################### #########################
web-build: web-install ## Build the Authentik UI web-build: npm-install ## Build the Authentik UI
cd web && npm run build npm run build -w @goauthentik/web
web: web-lint-fix web-lint web-check-compile ## Automatically fix formatting issues in the Authentik UI source code, lint the code, and compile it web: web-lint-fix web-lint web-check-compile ## Automatically fix formatting issues in the Authentik UI source code, lint the code, and compile it
web-install: ## Install the necessary libraries to build the Authentik UI npm-install: ## Install the necessary libraries to build the Authentik UI
cd web && npm ci npm ci
web-test: ## Run tests for the Authentik UI web-test: ## Run tests for the Authentik UI
cd web && npm run test npm run test -w @goauthentik/web
web-watch: ## Build and watch the Authentik UI for changes, updating automatically web-watch: ## Build and watch the Authentik UI for changes, updating automatically
rm -rf web/dist/ npm run watch -w @goauthentik/web
mkdir web/dist/
touch web/dist/.gitkeep
cd web && npm run watch
web-storybook-watch: ## Build and run the storybook documentation server web-storybook-watch: ## Build and run the storybook documentation server
cd web && npm run storybook npm run storybook -w @goauthentik/web
web-lint-fix: web-lint-fix:
cd web && npm run prettier npm run prettier -w @goauthentik/web
web-lint: web-lint:
cd web && npm run lint npm run lint -w @goauthentik/web
cd web && npm run lit-analyse
web-check-compile: web-check-compile:
cd web && npm run tsc npm run lint:types
web-i18n-extract: web-i18n-extract:
cd web && npm run extract-locales npm run extract-locales -w @goauthentik/web
######################### #########################
## Website ## Website
@ -222,17 +217,14 @@ web-i18n-extract:
website: website-lint-fix website-build ## Automatically fix formatting issues in the Authentik website/docs source code, lint the code, and compile it website: website-lint-fix website-build ## Automatically fix formatting issues in the Authentik website/docs source code, lint the code, and compile it
website-install:
cd website && npm ci
website-lint-fix: lint-codespell website-lint-fix: lint-codespell
cd website && npm run prettier npm run prettier --prefix website
website-build: website-build:
cd website && npm run build npm run build --prefix website
website-watch: ## Build and watch the documentation website, updating automatically website-watch: ## Build and watch the documentation website, updating automatically
cd website && npm run watch npm run watch --prefix website
######################### #########################
## Docker ## Docker

10
eslint.config.mjs Normal file
View File

@ -0,0 +1,10 @@
import { createESLintPackageConfig } from "@goauthentik/eslint-config";
// @ts-check
/**
* ESLint configuration for authentik's monorepo.
*/
const ESLintConfig = createESLintPackageConfig();
export default ESLintConfig;

44361
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -2,14 +2,33 @@
"name": "@goauthentik/authentik", "name": "@goauthentik/authentik",
"version": "2025.4.1", "version": "2025.4.1",
"private": true, "private": true,
"scripts": {
"lint": "eslint --fix .",
"lint-check": "eslint --max-warnings 0 .",
"lint:types": "NODE_OPTIONS=\"--max-old-space-size=3000\" tsc -b .",
"prettier": "prettier --cache --write -u .",
"prettier-check": "prettier --cache --check -u ."
},
"type": "module", "type": "module",
"devDependencies": { "devDependencies": {
"@eslint/js": "^9.11.1",
"@trivago/prettier-plugin-sort-imports": "^5.2.2", "@trivago/prettier-plugin-sort-imports": "^5.2.2",
"prettier": "^3.3.3", "@typescript-eslint/eslint-plugin": "^8.28.0",
"prettier-plugin-organize-imports": "^4.1.0", "@typescript-eslint/parser": "^8.28.0",
"prettier-plugin-packagejson": "^2.5.10", "eslint": "^9.23.0",
"typescript": "^5.6.2" "eslint-plugin-lit": "^2.0.0",
"eslint-plugin-wc": "^3.0.0",
"npm-run-all": "^4.1.5",
"prettier": "^3.5.3",
"prettier-plugin-packagejson": "^2.5.13",
"typescript": "^5.8.3",
"typescript-eslint": "^8.29.0"
}, },
"workspaces": [], "workspaces": [
"./packages/*",
"./web/packages/*",
"./web",
"./website"
],
"prettier": "./packages/prettier-config/index.js" "prettier": "./packages/prettier-config/index.js"
} }

View File

@ -23,6 +23,7 @@ export const DefaultIgnorePatterns = [
"**/out", "**/out",
"**/dist", "**/dist",
"**/.wireit", "**/.wireit",
"**/.venv",
"website/build/**", "website/build/**",
"website/.docusaurus/**", "website/.docusaurus/**",
"**/node_modules", "**/node_modules",
@ -58,16 +59,44 @@ export function createESLintPackageConfig({ ignorePatterns = DefaultIgnorePatter
...reactConfig, ...reactConfig,
//#region TODO Incomplete Rules
{ {
// The following rules are disabled because the changes needed to satisfy them are
// are large enough to warrant several follow-up PRs.
rules: { rules: {
"no-console": "off", // TODO: High priority, common and easy to fix.
"eqeqeq": "off",
// TODO: High priority, common and easy to fix.
"no-sparse-arrays": "off",
// TODO: High priority, common and easy to fix.
"no-lonely-if": "off",
// TODO: Reconsider this rule.
"dot-notation": "off",
// TODO: Reconsider this rule.
"no-implicit-coercion": "off",
// TODO: Reconsider this rule.
"prefer-template": "off",
"@typescript-eslint/ban-ts-comment": "off",
"@typescript-eslint/no-unused-vars": "off",
"@typescript-eslint/no-use-before-define": "off",
"array-callback-return": "off",
"block-scoped-var": "off",
"consistent-return": "off",
"func-names": "off",
"guard-for-in": "off",
"no-bitwise": "off",
"no-div-regex": "off",
"no-else-return": "off",
"no-empty-function": "off",
"no-param-reassign": "off",
"no-throw-literal": "off",
"no-var": "error",
"prefer-arrow-callback": "off",
"react/jsx-no-leaked-render": "off",
"vars-on-top": "off",
}, },
files: [
// ---
"**/scripts/**/*",
"**/test/**/*",
"**/tests/**/*",
],
}, },
//#endregion
); );
} }

View File

@ -116,7 +116,6 @@ export const javaScriptConfig = tseslint.config({
"no-useless-call": "error", "no-useless-call": "error",
"no-dupe-class-members": "error", "no-dupe-class-members": "error",
"no-var": "error", "no-var": "error",
"no-void": "error",
"no-with": "error", "no-with": "error",
"prefer-arrow-callback": "error", "prefer-arrow-callback": "error",
"prefer-const": "error", "prefer-const": "error",
@ -131,7 +130,6 @@ export const javaScriptConfig = tseslint.config({
"vars-on-top": "error", "vars-on-top": "error",
"yoda": ["error", "never"], "yoda": ["error", "never"],
"no-console": ["error", { allow: ["debug", "warn", "error"] }],
// SonarJS is not yet compatible with ESLint 9. Commenting these out // SonarJS is not yet compatible with ESLint 9. Commenting these out
// until it is. // until it is.
// "sonarjs/cognitive-complexity": ["off", MAX_COGNITIVE_COMPLEXITY], // "sonarjs/cognitive-complexity": ["off", MAX_COGNITIVE_COMPLEXITY],

View File

@ -2,19 +2,19 @@
"name": "@goauthentik/tsconfig", "name": "@goauthentik/tsconfig",
"version": "1.0.4", "version": "1.0.4",
"description": "authentik's base TypeScript configuration.", "description": "authentik's base TypeScript configuration.",
"keywords": [
"tsconfig",
"typescript"
],
"license": "MIT", "license": "MIT",
"scripts": { "scripts": {
"build": "" "build": ""
}, },
"type": "module",
"main": "tsconfig.json", "main": "tsconfig.json",
"type": "module",
"engines": { "engines": {
"node": ">=20.11" "node": ">=20.11"
}, },
"keywords": [
"tsconfig",
"typescript"
],
"publishConfig": { "publishConfig": {
"access": "public" "access": "public"
} }

View File

@ -1,20 +1,22 @@
# syntax=docker/dockerfile:1 # syntax=docker/dockerfile:1
# Stage 1: Build web # Stage 1: Build web
FROM --platform=${BUILDPLATFORM} docker.io/library/node:24 AS web-builder FROM --platform=${BUILDPLATFORM} docker.io/library/node:24-slim AS web-builder
WORKDIR /work
COPY ./package.json /work
COPY ./package-lock.json /work
COPY ./tsconfig.json /work
COPY ./packages/ /work/packages/
COPY ./web /work/web/
RUN --mount=type=cache,id=npm-node,sharing=shared,target=/root/.npm \
npm ci
ENV NODE_ENV=production ENV NODE_ENV=production
WORKDIR /static
COPY package.json / RUN npm run build-proxy -w @goauthentik/web
RUN --mount=type=bind,target=/static/package.json,src=./web/package.json \
--mount=type=bind,target=/static/package-lock.json,src=./web/package-lock.json \
--mount=type=bind,target=/static/scripts,src=./web/scripts \
--mount=type=cache,target=/root/.npm \
npm ci --include=dev
COPY web .
RUN npm run build-proxy
# Stage 2: Build # Stage 2: Build
FROM --platform=${BUILDPLATFORM} docker.io/library/golang:1.24-bookworm AS builder FROM --platform=${BUILDPLATFORM} docker.io/library/golang:1.24-bookworm AS builder
@ -65,10 +67,10 @@ RUN apt-get update && \
rm -rf /tmp/* /var/lib/apt/lists/* rm -rf /tmp/* /var/lib/apt/lists/*
COPY --from=builder /go/proxy / COPY --from=builder /go/proxy /
COPY --from=web-builder /static/robots.txt /web/robots.txt COPY --from=web-builder /work/web/robots.txt /web/robots.txt
COPY --from=web-builder /static/security.txt /web/security.txt COPY --from=web-builder /work/web/security.txt /web/security.txt
COPY --from=web-builder /static/dist/ /web/dist/ COPY --from=web-builder /work/web/dist/ /web/dist/
COPY --from=web-builder /static/authentik/ /web/authentik/ COPY --from=web-builder /work/web/authentik/ /web/authentik/
HEALTHCHECK --interval=5s --retries=20 --start-period=3s CMD [ "/proxy", "healthcheck" ] HEALTHCHECK --interval=5s --retries=20 --start-period=3s CMD [ "/proxy", "healthcheck" ]

View File

@ -0,0 +1,7 @@
{
"$schema": "https://json.schemastore.org/tsconfig",
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "dist/esm",
},
}

View File

@ -0,0 +1,23 @@
{
"$schema": "https://json.schemastore.org/tsconfig",
"compilerOptions": {
"composite": true,
"isolatedModules": true,
"incremental": true,
"baseUrl": ".",
"rootDir": "src",
"strict": true,
"newLine": "lf",
"target": "ESNext",
"module": "ESNext",
"moduleResolution": "bundler",
"outDir": "dist",
"skipDefaultLibCheck": true,
"skipLibCheck": true,
"sourceMap": true,
"declaration": true,
"declarationMap": true,
"lib": ["DOM", "DOM.Iterable", "ESNext"],
},
"exclude": ["node_modules", "./out/**/*", "./dist/**/*"],
}

View File

@ -23,6 +23,8 @@
"files": [], "files": [],
"references": [ "references": [
// Note that references are in the order we want them to be built. // Note that references are in the order we want them to be built.
// TODO: Left blank until TypeScript workspaces are complete. {
"path": "./web"
}
] ]
} }

38
web/commands.mjs Normal file
View File

@ -0,0 +1,38 @@
/// <reference types="@wdio/globals/types" />
/// <reference types="./types/webdriver.js" />
/**
*
* @param {WebdriverIO.Browser} browser
*/
export function addCommands(browser) {
/**
* @file Custom WDIO browser commands
*/
browser.addCommand(
"focus",
/**
* @this {HTMLElement}
*/
function () {
this.focus();
return this;
},
/* attachToElement */ true,
);
browser.addCommand(
"blur",
/**
* @this {HTMLElement}
*/
function () {
this.blur();
return this;
},
/* attachToElement */ true,
);
}

View File

@ -24,13 +24,12 @@ export default tseslint.config(
...ESLintConfig, ...ESLintConfig,
{ {
rules: { rules: {
"no-console": "off", "no-console": ["error", { allow: ["debug", "warn", "error"] }],
}, },
files: ["packages/**/*"], files: ["src/**/*"],
}, },
{ {
rules: { rules: {
"no-void": "off",
"no-implicit-coercion": "off", "no-implicit-coercion": "off",
"prefer-template": "off", "prefer-template": "off",
"@typescript-eslint/ban-ts-comment": "off", "@typescript-eslint/ban-ts-comment": "off",
@ -47,7 +46,6 @@ export default tseslint.config(
"no-empty-function": "off", "no-empty-function": "off",
"no-param-reassign": "off", "no-param-reassign": "off",
"no-throw-literal": "off", "no-throw-literal": "off",
// "no-var": "off",
"prefer-arrow-callback": "off", "prefer-arrow-callback": "off",
"react/jsx-no-leaked-render": "off", "react/jsx-no-leaked-render": "off",
"vars-on-top": "off", "vars-on-top": "off",

27188
web/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -14,13 +14,13 @@
"format": "wireit", "format": "wireit",
"lint": "eslint --fix .", "lint": "eslint --fix .",
"lint-check": "eslint --max-warnings 0 .", "lint-check": "eslint --max-warnings 0 .",
"prettier": "prettier --cache --write -u .",
"prettier-check": "prettier --cache --check -u .",
"lint:imports": "knip --config scripts/knip.config.ts", "lint:imports": "knip --config scripts/knip.config.ts",
"lint:lockfile": "wireit", "lint:lockfile": "wireit",
"lint:types": "wireit", "lint:types": "wireit",
"lit-analyse": "wireit", "lit-analyse": "wireit",
"precommit": "wireit", "precommit": "wireit",
"prettier": "prettier --cache --write -u .",
"prettier-check": "prettier --cache --check -u .",
"pseudolocalize": "node ./scripts/pseudolocalize.mjs", "pseudolocalize": "node ./scripts/pseudolocalize.mjs",
"storybook": "storybook dev -p 6006", "storybook": "storybook dev -p 6006",
"storybook:build": "wireit", "storybook:build": "wireit",
@ -143,8 +143,8 @@
"@eslint/js": "^9.27.0", "@eslint/js": "^9.27.0",
"@goauthentik/core": "^1.0.0", "@goauthentik/core": "^1.0.0",
"@goauthentik/esbuild-plugin-live-reload": "^1.0.4", "@goauthentik/esbuild-plugin-live-reload": "^1.0.4",
"@goauthentik/eslint-config": "^1.0.4", "@goauthentik/eslint-config": "^1.0.5",
"@goauthentik/prettier-config": "^1.0.4", "@goauthentik/prettier-config": "^1.0.5",
"@goauthentik/tsconfig": "^1.0.4", "@goauthentik/tsconfig": "^1.0.4",
"@hcaptcha/types": "^1.0.4", "@hcaptcha/types": "^1.0.4",
"@lit/localize-tools": "^0.8.0", "@lit/localize-tools": "^0.8.0",
@ -168,9 +168,10 @@
"@types/react-dom": "^19.1.5", "@types/react-dom": "^19.1.5",
"@typescript-eslint/eslint-plugin": "^8.8.0", "@typescript-eslint/eslint-plugin": "^8.8.0",
"@typescript-eslint/parser": "^8.8.0", "@typescript-eslint/parser": "^8.8.0",
"@wdio/browser-runner": "9.4", "@wdio/browser-runner": "^9.14.0",
"@wdio/cli": "9.4", "@wdio/cli": "^9.14.0",
"@wdio/spec-reporter": "^9.1.2", "@wdio/spec-reporter": "^9.14.0",
"@web/test-runner": "^0.20.2",
"chromedriver": "^136.0.3", "chromedriver": "^136.0.3",
"esbuild": "^0.25.4", "esbuild": "^0.25.4",
"esbuild-plugin-copy": "^2.1.1", "esbuild-plugin-copy": "^2.1.1",
@ -184,7 +185,7 @@
"knip": "^5.30.6", "knip": "^5.30.6",
"lit-analyzer": "^2.0.3", "lit-analyzer": "^2.0.3",
"npm-run-all": "^4.1.5", "npm-run-all": "^4.1.5",
"prettier": "^3.3.3", "prettier": "^3.5.3",
"pseudolocale": "^2.1.0", "pseudolocale": "^2.1.0",
"rollup-plugin-postcss-lit": "^2.2.0", "rollup-plugin-postcss-lit": "^2.2.0",
"storybook": "^8.6.14", "storybook": "^8.6.14",
@ -301,8 +302,7 @@
"lint", "lint",
"lint:types", "lint:types",
"lint:components", "lint:components",
"lint:lockfile", "lint:lockfile"
"lint:lockfiles"
] ]
}, },
"storybook:build": { "storybook:build": {
@ -371,12 +371,12 @@
"chromedriver": { "chromedriver": {
"axios": "^1.8.4" "axios": "^1.8.4"
}, },
"rapidoc": {
"@apitools/openapi-parser@": "0.0.37"
},
"storybook-addon-mock": { "storybook-addon-mock": {
"react": "^19.1.0", "react": "^19.1.0",
"react-dom": "^19.1.0" "react-dom": "^19.1.0"
},
"rapidoc": {
"@apitools/openapi-parser@": "0.0.37"
} }
} }
} }

View File

@ -48,8 +48,8 @@
"@goauthentik/prettier-config": "^1.0.4", "@goauthentik/prettier-config": "^1.0.4",
"@goauthentik/tsconfig": "^1.0.4", "@goauthentik/tsconfig": "^1.0.4",
"@types/node": "^22.15.21", "@types/node": "^22.15.21",
"prettier": "^3.3.3", "prettier": "^3.5.3",
"typescript": "^5.6.3" "typescript": "^5.8.3"
}, },
"engines": { "engines": {
"node": ">=20.11" "node": ">=20.11"

View File

@ -10,8 +10,11 @@ const DOCS_DOMAIN = "https://goauthentik.io";
* - Resolves relative links to the public directory in the public docs domain. * - Resolves relative links to the public directory in the public docs domain.
* - Intercepts local links and scrolls to the target element. * - Intercepts local links and scrolls to the target element.
*/ */
export const MDXAnchor = memo<React.AnchorHTMLAttributes<HTMLAnchorElement>>( export const MDXAnchor = ({
({ href, children, ...props }) => { href,
children,
...props
}: React.AnchorHTMLAttributes<HTMLAnchorElement>) => {
const { publicDirectory } = useMDXModule(); const { publicDirectory } = useMDXModule();
if (href?.startsWith(".") && publicDirectory) { if (href?.startsWith(".") && publicDirectory) {
@ -55,7 +58,4 @@ export const MDXAnchor = memo<React.AnchorHTMLAttributes<HTMLAnchorElement>>(
{children} {children}
</a> </a>
); );
}, };
);
MDXAnchor.displayName = "MDXAnchor";

View File

@ -8,7 +8,7 @@ export interface MDXWrapperProps {
/** /**
* A wrapper component for MDX content that adds a title if one is provided in the frontmatter. * A wrapper component for MDX content that adds a title if one is provided in the frontmatter.
*/ */
export const MDXWrapper: React.FC<MDXWrapperProps> = ({ children, frontmatter }) => { export const MDXWrapper = ({ children, frontmatter }: MDXWrapperProps) => {
const { title } = frontmatter; const { title } = frontmatter;
const nextChildren = React.Children.toArray(children); const nextChildren = React.Children.toArray(children);

View File

@ -4,12 +4,13 @@ import { Route } from "@goauthentik/elements/router/Route";
import { RouteMatch } from "@goauthentik/elements/router/RouteMatch"; import { RouteMatch } from "@goauthentik/elements/router/RouteMatch";
import "@goauthentik/elements/router/Router404"; import "@goauthentik/elements/router/Router404";
import { import {
BrowserClient,
SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, SEMANTIC_ATTRIBUTE_SENTRY_SOURCE,
Span,
getClient, getClient,
startBrowserTracingNavigationSpan, startBrowserTracingNavigationSpan,
startBrowserTracingPageLoadSpan, startBrowserTracingPageLoadSpan,
} from "@sentry/browser"; } from "@sentry/browser";
import { Client, Span } from "@sentry/types";
import { CSSResult, PropertyValues, TemplateResult, css, html } from "lit"; import { CSSResult, PropertyValues, TemplateResult, css, html } from "lit";
import { customElement, property } from "lit/decorators.js"; import { customElement, property } from "lit/decorators.js";
@ -60,7 +61,7 @@ export class RouterOutlet extends AKElement {
@property({ attribute: false }) @property({ attribute: false })
routes: Route[] = []; routes: Route[] = [];
private sentryClient?: Client; private sentryClient?: BrowserClient;
private pageLoadSpan?: Span; private pageLoadSpan?: Span;
static get styles(): CSSResult[] { static get styles(): CSSResult[] {

View File

@ -1,6 +1,5 @@
{ {
"compilerOptions": { "compilerOptions": {
"strict": true,
"baseUrl": ".", "baseUrl": ".",
"moduleResolution": "node", "moduleResolution": "node",
"module": "ESNext", "module": "ESNext",

123
web/tests/wdio.conf.mjs Normal file
View File

@ -0,0 +1,123 @@
/**
* @file WebdriverIO configuration file for **component unit tests**.
*
* @see https://webdriver.io/docs/configurationfile.html
*/
import { cwd } from "process";
import litCSS from "vite-plugin-lit-css";
import tsconfigPaths from "vite-tsconfig-paths";
import { addCommands } from "../commands.mjs";
const NODE_ENV = process.env.NODE_ENV || "development";
const headless = !!process.env.HEADLESS || !!process.env.CI;
const lemmeSee = !!process.env.WDIO_LEMME_SEE;
/**
* @type {WebdriverIO.Capabilities[]}
*/
const capabilities = [];
const DEFAULT_MAX_INSTANCES = 10;
let maxInstances = 1;
if (headless) {
maxInstances = process.env.MAX_INSTANCES
? parseInt(process.env.MAX_INSTANCES, 10)
: DEFAULT_MAX_INSTANCES;
}
if (!process.env.WDIO_SKIP_CHROME) {
/**
* @satisfies {WebdriverIO.Capabilities}
*/
const chromeBrowserConfig = {
"browserName": "chrome",
"goog:chromeOptions": {
args: ["disable-search-engine-choice-screen"],
},
};
if (headless) {
chromeBrowserConfig["goog:chromeOptions"].args.push(
"headless",
"disable-gpu",
"no-sandbox",
"window-size=1280,672",
"browser-test",
);
}
capabilities.push(chromeBrowserConfig);
}
if (process.env.WDIO_TEST_SAFARI) {
capabilities.push({
browserName: "safari",
});
}
if (process.env.WDIO_TEST_FIREFOX) {
capabilities.push({
browserName: "firefox",
});
}
/**
* @type {WebdriverIO.BrowserRunnerOptions}
*/
const browserRunnerOptions = {
viteConfig: {
define: {
"process.env.NODE_ENV": JSON.stringify(NODE_ENV),
"process.env.CWD": JSON.stringify(cwd()),
"process.env.AK_API_BASE_PATH": JSON.stringify(process.env.AK_API_BASE_PATH || ""),
},
plugins: [
// ---
// @ts-ignore WDIO's Vite is out of date.
litCSS(),
// @ts-ignore WDIO's Vite is out of date.
tsconfigPaths(),
],
},
};
/**
* @satisfies {WebdriverIO.Config}
*/
export const config = {
runner: ["browser", browserRunnerOptions],
tsConfigPath: "./tsconfig.test.json",
specs: ["./src/**/*.test.ts"],
exclude: [],
maxInstances,
capabilities,
logLevel: "warn",
bail: 0,
waitforTimeout: 12000,
connectionRetryTimeout: 12000,
connectionRetryCount: 3,
framework: "mocha",
reporters: ["spec"],
mochaOpts: {
ui: "bdd",
timeout: 60000,
},
/**
* @param {WebdriverIO.Browser} browser
*/
before(_capabilities, _specs, browser) {
addCommands(browser);
},
afterTest() {
if (lemmeSee) return browser.pause(500);
},
};

View File

@ -1,320 +0,0 @@
import { browser } from "@wdio/globals";
const lemmeSee = process.env.WDIO_LEMME_SEE !== undefined;
const testSafari = process.env.WDIO_TEST_SAFARI !== undefined;
const testFirefox = process.env.WDIO_TEST_FIREFOX !== undefined;
const skipChrome = process.env.WDIO_SKIP_CHROME !== undefined;
const runHeadless = process.env.CI !== undefined;
const capabilities = [];
if (!skipChrome) {
capabilities.push({
"browserName": "chrome",
"wdio:chromedriverOptions": {
binary: "./node_modules/.bin/chromedriver",
},
"goog:chromeOptions": {
args: ["disable-infobars", "window-size=1280,800"].concat(
(function () {
return runHeadless
? [
"headless",
"no-sandbox",
"disable-gpu",
"disable-setuid-sandbox",
"disable-dev-shm-usage",
]
: [];
})(),
),
},
});
}
if (testSafari) {
capabilities.push({
browserName: "safari", // or "firefox", "microsoftedge", "safari"
});
}
if (testFirefox) {
capabilities.push({
browserName: "firefox", // or "firefox", "microsoftedge", "safari"
});
}
export const config: WebdriverIO.Config = {
//
// ====================
// Runner Configuration
// ====================
// WebdriverIO supports running e2e tests as well as unit and component tests.
runner: "local",
tsConfigPath: "./tsconfig.json",
//
// ==================
// Specify Test Files
// ==================
// Define which test specs should run. The pattern is relative to the directory
// of the configuration file being run.
//
// The specs are defined as an array of spec files (optionally using wildcards
// that will be expanded). The test for each spec file will be run in a separate
// worker process. In order to have a group of spec files run in the same worker
// process simply enclose them in an array within the specs array.
//
// If you are calling `wdio` from an NPM script (see https://docs.npmjs.com/cli/run-script),
// then the current working directory is where your `package.json` resides, so `wdio`
// will be called from there.
//
specs: ["./specs/**/*.ts"],
// Patterns to exclude.
exclude: [
// 'path/to/excluded/files'
],
//
// ============
// Capabilities
// ============
// Define your capabilities here. WebdriverIO can run multiple capabilities at the same
// time. Depending on the number of capabilities, WebdriverIO launches several test
// sessions. Within your capabilities you can overwrite the spec and exclude options in
// order to group specific specs to a specific capability.
//
// First, you can define how many instances should be started at the same time. Let's
// say you have 3 different capabilities (Chrome, Firefox, and Safari) and you have
// set maxInstances to 1; wdio will spawn 3 processes. Therefore, if you have 10 spec
// files and you set maxInstances to 10, all spec files will get tested at the same time
// and 30 processes will get spawned. The property handles how many capabilities
// from the same test should run tests.
//
maxInstances: 1,
//
// If you have trouble getting all important capabilities together, check out the
// Sauce Labs platform configurator - a great tool to configure your capabilities:
// https://saucelabs.com/platform/platform-configurator
//
capabilities,
//
// ===================
// Test Configurations
// ===================
// Define all options that are relevant for the WebdriverIO instance here
//
// Level of logging verbosity: trace | debug | info | warn | error | silent
logLevel: "warn",
//
// Set specific log levels per logger
// loggers:
// - webdriver, webdriverio
// - @wdio/browserstack-service, @wdio/devtools-service, @wdio/sauce-service
// - @wdio/mocha-framework, @wdio/jasmine-framework
// - @wdio/local-runner
// - @wdio/sumologic-reporter
// - @wdio/cli, @wdio/config, @wdio/utils
// Level of logging verbosity: trace | debug | info | warn | error | silent
// logLevels: {
// webdriver: 'info',
// '@wdio/appium-service': 'info'
// },
//
// If you only want to run your tests until a specific amount of tests have failed use
// bail (default is 0 - don't bail, run all tests).
bail: 0,
//
// Set a base URL in order to shorten url command calls. If your `url` parameter starts
// with `/`, the base url gets prepended, not including the path portion of your baseUrl.
// If your `url` parameter starts without a scheme or `/` (like `some/path`), the base url
// gets prepended directly.
baseUrl: "http://localhost",
//
// Default timeout for all waitFor* commands.
waitforTimeout: 10000,
//
// Default timeout in milliseconds for request
// if browser driver or grid doesn't send response
connectionRetryTimeout: 120000,
//
// Default request retries count
connectionRetryCount: 3,
//
// Test runner services
// Services take over a specific job you don't want to take care of. They enhance
// your test setup with almost no effort. Unlike plugins, they don't add new
// commands. Instead, they hook themselves up into the test process.
// services: [],
//
// Framework you want to run your specs with.
// The following are supported: Mocha, Jasmine, and Cucumber
// see also: https://webdriver.io/docs/frameworks
//
// Make sure you have the wdio adapter package for the specific framework installed
// before running any tests.
framework: "mocha",
//
// The number of times to retry the entire specfile when it fails as a whole
// specFileRetries: 1,
//
// Delay in seconds between the spec file retry attempts
// specFileRetriesDelay: 0,
//
// Whether or not retried spec files should be retried immediately or deferred to the end of the queue
// specFileRetriesDeferred: false,
//
// Test reporter for stdout.
// The only one supported by default is 'dot'
// see also: https://webdriver.io/docs/dot-reporter
reporters: ["spec"],
//
// Options to be passed to Mocha.
// See the full list at http://mochajs.org/
mochaOpts: {
ui: "bdd",
timeout: 60000,
},
//
// =====
// Hooks
// =====
// WebdriverIO provides several hooks you can use to interfere with the test process in order to enhance
// it and to build services around it. You can either apply a single function or an array of
// methods to it. If one of them returns with a promise, WebdriverIO will wait until that promise got
// resolved to continue.
/**
* Gets executed once before all workers get launched.
* @param {object} config wdio configuration object
* @param {Array.<Object>} capabilities list of capabilities details
*/
// onPrepare: function (config, capabilities) {
// },
/**
* Gets executed before a worker process is spawned and can be used to initialise specific service
* for that worker as well as modify runtime environments in an async fashion.
* @param {string} cid capability id (e.g 0-0)
* @param {object} caps object containing capabilities for session that will be spawn in the worker
* @param {object} specs specs to be run in the worker process
* @param {object} args object that will be merged with the main configuration once worker is initialized
* @param {object} execArgv list of string arguments passed to the worker process
*/
// onWorkerStart: function (cid, caps, specs, args, execArgv) {
// },
/**
* Gets executed just after a worker process has exited.
* @param {string} cid capability id (e.g 0-0)
* @param {number} exitCode 0 - success, 1 - fail
* @param {object} specs specs to be run in the worker process
* @param {number} retries number of retries used
*/
// onWorkerEnd: function (cid, exitCode, specs, retries) {
// },
/**
* Gets executed just before initialising the webdriver session and test framework. It allows you
* to manipulate configurations depending on the capability or spec.
* @param {object} config wdio configuration object
* @param {Array.<Object>} capabilities list of capabilities details
* @param {Array.<String>} specs List of spec file paths that are to be run
* @param {string} cid worker id (e.g. 0-0)
*/
// beforeSession: function (config, capabilities, specs, cid) {
// },
/**
* Runs before a WebdriverIO command gets executed.
* @param {string} commandName hook command name
* @param {Array} args arguments that command would receive
*/
// beforeCommand: function (commandName, args) {
// },
/**
* Hook that gets executed before the suite starts
* @param {object} suite suite details
*/
// beforeSuite: function (suite) {
// },
/**
* Function to be executed before a test (in Mocha/Jasmine) starts.
*/
// beforeTest: function (test, context) {
// },
/**
* Hook that gets executed _before_ a hook within the suite starts (e.g. runs before calling
* beforeEach in Mocha)
*/
// beforeHook: function (test, context) {
// },
/**
* Hook that gets executed _after_ a hook within the suite starts (e.g. runs after calling
* afterEach in Mocha)
*/
// afterHook: function (test, context, { error, result, duration, passed, retries }) {
// },
/**
* Function to be executed after a test (in Mocha/Jasmine only)
* @param {object} test test object
* @param {object} context scope object the test was executed with
* @param {Error} result.error error object in case the test fails, otherwise `undefined`
* @param {*} result.result return object of test function
* @param {number} result.duration duration of test
* @param {boolean} result.passed true if test has passed, otherwise false
* @param {object} result.retries information about spec related retries, e.g. `{ attempts: 0, limit: 0 }`
*/
// Below is the full signature; we're not using any of them.
// afterTest: async function (test, context, { error, result, duration, passed, retries }) {
afterTest: async function () {
if (lemmeSee) {
await browser.pause(500);
}
},
/**
* Hook that gets executed after the suite has ended
* @param {object} suite suite details
*/
// afterSuite: function (suite) {
// },
/**
* Runs after a WebdriverIO command gets executed
* @param {string} commandName hook command name
* @param {Array} args arguments that command would receive
* @param {number} result 0 - command success, 1 - command error
* @param {object} error error object if any
*/
// afterCommand: function (commandName, args, result, error) {
// },
/**
* Gets executed after all tests are done. You still have access to all global variables from
* the test.
* @param {number} result 0 - test pass, 1 - test fail
* @param {Array.<Object>} capabilities list of capabilities details
* @param {Array.<String>} specs List of spec file paths that ran
*/
// after: function (result, capabilities, specs) {
// },
/**
* Gets executed right after terminating the webdriver session.
* @param {object} config wdio configuration object
* @param {Array.<Object>} capabilities list of capabilities details
* @param {Array.<String>} specs List of spec file paths that ran
*/
// afterSession: function (config, capabilities, specs) {
// },
/**
* Gets executed after all workers got shut down and the process is about to exit. An error
* thrown in the onComplete hook will result in the test run failing.
* @param {object} exitCode 0 - success, 1 - fail
* @param {object} config wdio configuration object
* @param {Array.<Object>} capabilities list of capabilities details
* @param {<Object>} results object containing test results
*/
// onComplete: function(exitCode, config, capabilities, results) {
// },
/**
* Gets executed when a refresh happens.
* @param {string} oldSessionId session ID of the old session
* @param {string} newSessionId session ID of the new session
*/
// onReload: function(oldSessionId, newSessionId) {
// }
};

View File

@ -3,34 +3,7 @@
"compilerOptions": { "compilerOptions": {
"baseUrl": ".", "baseUrl": ".",
"types": ["node", "webdriverio/async", "@wdio/cucumber-framework", "expect-webdriverio"], "types": ["node", "webdriverio/async", "@wdio/cucumber-framework", "expect-webdriverio"],
"target": "esnext", "extends": "./tsconfig.json",
"module": "esnext", "include": ["src", "./tests"]
"forceConsistentCasingInFileNames": true,
"experimentalDecorators": true,
"lib": [
"ES5",
"ES2015",
"ES2016",
"ES2017",
"ES2018",
"ES2019",
"ES2020",
"ESNext",
"DOM",
"DOM.Iterable",
"WebWorker"
],
"paths": {
"@goauthentik/admin/*": ["./src/admin/*"],
"@goauthentik/common/*": ["./src/common/*"],
"@goauthentik/components/*": ["./src/components/*"],
"@goauthentik/docs/*": ["../website/docs/*"],
"@goauthentik/elements/*": ["./src/elements/*"],
"@goauthentik/flow/*": ["./src/flow/*"],
"@goauthentik/locales/*": ["./src/locales/*"],
"@goauthentik/polyfill/*": ["./src/polyfill/*"],
"@goauthentik/standalone/*": ["./src/standalone/*"],
"@goauthentik/user/*": ["./src/user/*"]
}
} }
} }

14
web/types/webdriver.d.ts vendored Normal file
View File

@ -0,0 +1,14 @@
declare namespace WebdriverIO {
interface Element {
/**
* Focus on the element.
* @monkeypatch
*/
focus(): Promise<void>;
/**
* Blur the element.
* @monkeypatch
*/
blur(): Promise<void>;
}
}

100
web/wdio.conf.mjs Normal file
View File

@ -0,0 +1,100 @@
/**
* @file WebdriverIO configuration file for **integration tests**.
*
* @see https://webdriver.io/docs/configurationfile.html
*/
import { browser } from "@wdio/globals";
import { addCommands } from "./commands.mjs";
/// <reference types="@wdio/globals/types" />
/// <reference types="./types/webdriver.js" />
const headless = !!process.env.CI;
const lemmeSee = !!process.env.WDIO_LEMME_SEE;
/**
* @type {WebdriverIO.Capabilities[]}
*/
const capabilities = [];
if (!process.env.WDIO_SKIP_CHROME) {
/**
* @satisfies {WebdriverIO.Capabilities}
*/
const chromeBrowserConfig = {
"browserName": "chrome",
// "wdio:chromedriverOptions": {
// binary: "./node_modules/.bin/chromedriver",
// },
"goog:chromeOptions": {
args: ["disable-infobars", "window-size=1280,800"],
},
};
if (headless) {
chromeBrowserConfig["goog:chromeOptions"].args.push(
"headless",
"no-sandbox",
"disable-gpu",
"disable-setuid-sandbox",
"disable-dev-shm-usage",
);
}
capabilities.push(chromeBrowserConfig);
}
if (process.env.WDIO_TEST_SAFARI) {
capabilities.push({
browserName: "safari",
});
}
if (process.env.WDIO_TEST_FIREFOX) {
capabilities.push({
browserName: "firefox",
});
}
/**
* @satisfies {WebdriverIO.Config}
*/
export const config = {
runner: "local",
tsConfigPath: "./tsconfig.json",
specs: [
// "./tests/specs/**/*.ts"
"./tests/specs/new-application-by-wizard.ts",
],
exclude: [],
maxInstances: 1,
capabilities,
logLevel: "warn",
baseUrl: "http://localhost",
waitforTimeout: 10000,
connectionRetryTimeout: 120000,
connectionRetryCount: 3,
framework: "mocha",
reporters: ["spec"],
mochaOpts: {
ui: "bdd",
timeout: 60000,
},
/**
* @param {WebdriverIO.Capabilities} capabilities
* @param {string[]} specs
* @param {WebdriverIO.Browser} browser
* @returns {void}
*/
before(capabilities, specs, browser) {
addCommands(browser);
},
afterTest() {
if (lemmeSee) return browser.pause(500);
},
};

View File

@ -1,391 +0,0 @@
/// <reference types="@wdio/browser-runner" />
import { createBundleDefinitions } from "#bundler/utils/node";
import { browser } from "@wdio/globals";
import type { Options } from "@wdio/types";
import path from "node:path";
import { fileURLToPath } from "node:url";
import type { InlineConfig } from "vite";
import litCSS from "vite-plugin-lit-css";
import tsconfigPaths from "vite-tsconfig-paths";
const __dirname = fileURLToPath(new URL(".", import.meta.url));
const runHeadless = process.env.CI !== undefined;
const testSafari = process.env.WDIO_TEST_SAFARI !== undefined;
const testFirefox = process.env.WDIO_TEST_FIREFOX !== undefined;
const skipChrome = process.env.WDIO_SKIP_CHROME !== undefined;
const lemmeSee = process.env.WDIO_LEMME_SEE !== undefined;
const capabilities = [];
const DEFAULT_MAX_INSTANCES = 10;
if (!skipChrome) {
capabilities.push({
// capabilities for local browser web tests
"browserName": "chrome", // or "firefox", "microsoftedge", "safari"
"goog:chromeOptions": {
args: [
"disable-search-engine-choice-screen",
...(runHeadless
? [
"headless",
"disable-gpu",
"no-sandbox",
"window-size=1280,672",
"browser-test",
]
: []),
],
},
});
}
if (testSafari) {
capabilities.push({
browserName: "safari", // or "firefox", "microsoftedge", "safari"
});
}
if (testFirefox) {
capabilities.push({
browserName: "firefox", // or "firefox", "microsoftedge", "safari"
});
}
const maxInstances =
process.env.MAX_INSTANCES !== undefined
? parseInt(process.env.MAX_INSTANCES, DEFAULT_MAX_INSTANCES)
: runHeadless
? 1
: 1;
export const config: Options.Testrunner = {
//
// ====================
// Runner Configuration
// ====================
// WebdriverIO supports running e2e tests as well as unit and component tests.
runner: [
"browser",
{
viteConfig: {
define: createBundleDefinitions(),
plugins: [litCSS(), tsconfigPaths()],
resolve: {
alias: {
"@goauthentik/admin": path.resolve(__dirname, "src/admin"),
"@goauthentik/common": path.resolve(__dirname, "src/common"),
"@goauthentik/components": path.resolve(__dirname, "src/components"),
"@goauthentik/docs": path.resolve(__dirname, "../website/docs"),
"@goauthentik/elements": path.resolve(__dirname, "src/elements"),
"@goauthentik/flow": path.resolve(__dirname, "src/flow"),
"@goauthentik/locales": path.resolve(__dirname, "src/locales"),
"@goauthentik/polyfill": path.resolve(__dirname, "src/polyfill"),
"@goauthentik/standalone": path.resolve(__dirname, "src/standalone"),
"@goauthentik/user": path.resolve(__dirname, "src/user"),
},
},
} satisfies InlineConfig,
},
],
// @ts-expect-error TS2353: The types are not up-to-date with Wdio9.
autoCompileOpts: {
autoCompile: true,
tsNodeOpts: {
project: "./tsconfig.json",
transpileOnly: true,
},
},
//
// ==================
// Specify Test Files
// ==================
// Define which test specs should run. The pattern is relative to the directory
// of the configuration file being run.
//
// The specs are defined as an array of spec files (optionally using wildcards
// that will be expanded). The test for each spec file will be run in a separate
// worker process. In order to have a group of spec files run in the same worker
// process simply enclose them in an array within the specs array.
//
// The path of the spec files will be resolved relative from the directory of
// of the config file unless it's absolute.
//
specs: ["./src/**/*.test.ts"],
// Patterns to exclude.
exclude: [
// 'path/to/excluded/files'
],
//
// ============
// Capabilities
// ============
// Define your capabilities here. WebdriverIO can run multiple capabilities at the same
// time. Depending on the number of capabilities, WebdriverIO launches several test
// sessions. Within your capabilities you can overwrite the spec and exclude options in
// order to group specific specs to a specific capability.
//
// First, you can define how many instances should be started at the same time. Let's
// say you have 3 different capabilities (Chrome, Firefox, and Safari) and you have
// set maxInstances to 1; wdio will spawn 3 processes. Therefore, if you have 10 spec
// files and you set maxInstances to 10, all spec files will get tested at the same time
// and 30 processes will get spawned. The property handles how many capabilities
// from the same test should run tests.
//
maxInstances,
//
// If you have trouble getting all important capabilities together, check out the
// Sauce Labs platform configurator - a great tool to configure your capabilities:
// https://saucelabs.com/platform/platform-configurator
//
capabilities,
//
// ===================
// Test Configurations
// ===================
// Define all options that are relevant for the WebdriverIO instance here
//
// Level of logging verbosity: trace | debug | info | warn | error | silent
logLevel: "warn",
//
// Set specific log levels per logger
// loggers:
// - webdriver, webdriverio
// - @wdio/browserstack-service, @wdio/devtools-service, @wdio/sauce-service
// - @wdio/mocha-framework, @wdio/jasmine-framework
// - @wdio/local-runner
// - @wdio/sumologic-reporter
// - @wdio/cli, @wdio/config, @wdio/utils
// Level of logging verbosity: trace | debug | info | warn | error | silent
// logLevels: {
// webdriver: 'info',
// '@wdio/appium-service': 'info'
// },
//
// If you only want to run your tests until a specific amount of tests have failed use
// bail (default is 0 - don't bail, run all tests).
bail: 0,
//
// Set a base URL in order to shorten url command calls. If your `url` parameter starts
// with `/`, the base url gets prepended, not including the path portion of your baseUrl.
// If your `url` parameter starts without a scheme or `/` (like `some/path`), the base url
// gets prepended directly.
// baseUrl: 'http://localhost:8080',
//
// Default timeout for all waitFor* commands.
waitforTimeout: 12000,
//
// Default timeout in milliseconds for request
// if browser driver or grid doesn't send response
connectionRetryTimeout: 12000,
//
// Default request retries count
connectionRetryCount: 3,
//
// Test runner services
// Services take over a specific job you don't want to take care of. They enhance
// your test setup with almost no effort. Unlike plugins, they don't add new
// commands. Instead, they hook themselves up into the test process.
// services: [],
//
// Framework you want to run your specs with.
// The following are supported: Mocha, Jasmine, and Cucumber
// see also: https://webdriver.io/docs/frameworks
//
// Make sure you have the wdio adapter package for the specific framework installed
// before running any tests.
framework: "mocha",
//
// The number of times to retry the entire specfile when it fails as a whole
// specFileRetries: 1,
//
// Delay in seconds between the spec file retry attempts
// specFileRetriesDelay: 0,
//
// Whether or not retried spec files should be retried immediately or deferred to the end of the queue
// specFileRetriesDeferred: false,
//
// Test reporter for stdout.
// The only one supported by default is 'dot'
// see also: https://webdriver.io/docs/dot-reporter
reporters: ["spec"],
// Options to be passed to Mocha.
// See the full list at http://mochajs.org/
mochaOpts: {
ui: "bdd",
timeout: 60000,
},
//
// =====
// Hooks
// =====
// WebdriverIO provides several hooks you can use to interfere with the test process in order to enhance
// it and to build services around it. You can either apply a single function or an array of
// methods to it. If one of them returns with a promise, WebdriverIO will wait until that promise got
// resolved to continue.
/**
* Gets executed once before all workers get launched.
* @param {object} config wdio configuration object
* @param {Array.<Object>} capabilities list of capabilities details
*/
// onPrepare: function (config, capabilities) {
// },
/**
* Gets executed before a worker process is spawned and can be used to initialize specific service
* for that worker as well as modify runtime environments in an async fashion.
* @param {string} cid capability id (e.g 0-0)
* @param {object} caps object containing capabilities for session that will be spawn in the worker
* @param {object} specs specs to be run in the worker process
* @param {object} args object that will be merged with the main configuration once worker is initialized
* @param {object} execArgv list of string arguments passed to the worker process
*/
// onWorkerStart: function (cid, caps, specs, args, execArgv) {
// },
/**
* Gets executed just after a worker process has exited.
* @param {string} cid capability id (e.g 0-0)
* @param {number} exitCode 0 - success, 1 - fail
* @param {object} specs specs to be run in the worker process
* @param {number} retries number of retries used
*/
// onWorkerEnd: function (cid, exitCode, specs, retries) {
// },
/**
* Gets executed just before initialising the webdriver session and test framework. It allows you
* to manipulate configurations depending on the capability or spec.
* @param {object} config wdio configuration object
* @param {Array.<Object>} capabilities list of capabilities details
* @param {Array.<String>} specs List of spec file paths that are to be run
* @param {string} cid worker id (e.g. 0-0)
*/
// beforeSession: function (config, capabilities, specs, cid) {
// },
/**
* Gets executed before test execution begins. At this point you can access to all global
* variables like `browser`. It is the perfect place to define custom commands.
* @param {Array.<Object>} capabilities list of capabilities details
* @param {Array.<String>} specs List of spec file paths that are to be run
* @param {object} browser instance of created browser/device session
*/
// before: function (capabilities, specs) {
// },
/**
* Runs before a WebdriverIO command gets executed.
* @param {string} commandName hook command name
* @param {Array} args arguments that command would receive
*/
// beforeCommand: function (commandName, args) {
// },
/**
* Hook that gets executed before the suite starts
* @param {object} suite suite details
*/
// beforeSuite: function (suite) {
// },
/**
* Function to be executed before a test (in Mocha/Jasmine) starts.
*/
// beforeTest: function (test, context) {
// },
/**
* Hook that gets executed _before_ a hook within the suite starts (e.g. runs before calling
* beforeEach in Mocha)
*/
// beforeHook: function (test, context, hookName) {
// },
/**
* Hook that gets executed _after_ a hook within the suite starts (e.g. runs after calling
* afterEach in Mocha)
*/
// afterHook: function (test, context, { error, result, duration, passed, retries }, hookName) {
// },
/**
* Function to be executed after a test (in Mocha/Jasmine only)
* @param {object} test test object
* @param {object} context scope object the test was executed with
* @param {Error} result.error error object in case the test fails, otherwise `undefined`
* @param {*} result.result return object of test function
* @param {number} result.duration duration of test
* @param {boolean} result.passed true if test has passed, otherwise false
* @param {object} result.retries information about spec related retries, e.g. `{ attempts: 0, limit: 0 }`
*/
afterTest: async function (
_test,
_context,
{ error: _error, result: _result, duration: _duration, passed: _passed, retries: _retries },
) {
if (lemmeSee) {
// @ts-expect-error TODO
await browser.pause(500);
}
},
/**
* Hook that gets executed after the suite has ended
* @param {object} suite suite details
*/
// afterSuite: function (suite) {
// },
/**
* Runs after a WebdriverIO command gets executed
* @param {string} commandName hook command name
* @param {Array} args arguments that command would receive
* @param {number} result 0 - command success, 1 - command error
* @param {object} error error object if any
*/
// afterCommand: function (commandName, args, result, error) {
// },
/**
* Gets executed after all tests are done. You still have access to all global variables from
* the test.
* @param {number} result 0 - test pass, 1 - test fail
* @param {Array.<Object>} capabilities list of capabilities details
* @param {Array.<String>} specs List of spec file paths that ran
*/
// after: function (result, capabilities, specs) {
// },
/**
* Gets executed right after terminating the webdriver session.
* @param {object} config wdio configuration object
* @param {Array.<Object>} capabilities list of capabilities details
* @param {Array.<String>} specs List of spec file paths that ran
*/
// afterSession: function (config, capabilities, specs) {
// },
/**
* Gets executed after all workers got shut down and the process is about to exit. An error
* thrown in the onComplete hook will result in the test run failing.
* @param {object} exitCode 0 - success, 1 - fail
* @param {object} config wdio configuration object
* @param {Array.<Object>} capabilities list of capabilities details
* @param {<Object>} results object containing test results
*/
// onComplete: function(exitCode, config, capabilities, results) {
// },
/**
* Gets executed when a refresh happens.
* @param {string} oldSessionId session ID of the old session
* @param {string} newSessionId session ID of the new session
*/
// onReload: function(oldSessionId, newSessionId) {
// }
/**
* Hook that gets executed before a WebdriverIO assertion happens.
* @param {object} params information about the assertion to be executed
*/
// beforeAssertion: function(params) {
// }
/**
* Hook that gets executed after a WebdriverIO assertion happened.
* @param {object} params information about the assertion that was executed, including its results
*/
// afterAssertion: function(params) {
// }
};

View File

@ -1,6 +1,16 @@
export default { /**
* @file Web Test Runner configuration.
* @see https://modern-web.dev/docs/test-runner/cli-and-configuration/
*/
/**
* @type {import('@web/test-runner').TestRunnerConfig}
*/
const config = {
files: ["dist/**/*.spec.js"], files: ["dist/**/*.spec.js"],
nodeResolve: { nodeResolve: {
exportConditions: ["browser", "production"], exportConditions: ["browser", "production"],
}, },
}; };
export default config;

View File

@ -62,7 +62,6 @@ Depending on platform, some native dependencies might be required. On macOS, run
4. From the cloned repository root, install the front-end dependencies using NPM. 4. From the cloned repository root, install the front-end dependencies using NPM.
```shell ```shell
cd web
npm ci npm ci
``` ```

View File

@ -5,8 +5,12 @@
* @import * as OpenApiPlugin from "docusaurus-plugin-openapi-docs"; * @import * as OpenApiPlugin from "docusaurus-plugin-openapi-docs";
* @import { BuildUrlValues } from "remark-github"; * @import { BuildUrlValues } from "remark-github";
*/ */
import { MonoRepoRoot } from "@goauthentik/core/paths/node";
import { createDocusaurusConfig } from "@goauthentik/docusaurus-config"; import { createDocusaurusConfig } from "@goauthentik/docusaurus-config";
import { cp } from "node:fs/promises";
import { createRequire } from "node:module"; import { createRequire } from "node:module";
import { resolve } from "node:path";
import { fileURLToPath } from "node:url";
import remarkDirective from "remark-directive"; import remarkDirective from "remark-directive";
import remarkGithub, { defaultBuildUrl } from "remark-github"; import remarkGithub, { defaultBuildUrl } from "remark-github";
@ -16,7 +20,30 @@ import remarkSupportDirective from "./remark/support-directive.mjs";
import remarkVersionDirective from "./remark/version-directive.mjs"; import remarkVersionDirective from "./remark/version-directive.mjs";
const require = createRequire(import.meta.url); const require = createRequire(import.meta.url);
const __dirname = fileURLToPath(new URL(".", import.meta.url));
const staticDirectory = resolve(__dirname, "static");
/**
* @param {string} fileName
*/
function copyStaticFile(fileName) {
const source = resolve(MonoRepoRoot, fileName);
const destination = resolve(staticDirectory, fileName);
return cp(source, destination).catch((error) => {
const wrapper = new Error(`Failed to copy file "${source}" to "${destination}"`);
wrapper.cause = error;
throw wrapper;
});
}
await Promise.all([
// ---
copyStaticFile("docker-compose.yml"),
copyStaticFile("schema.yml"),
]);
/** /**
* Documentation site configuration for Docusaurus. * Documentation site configuration for Docusaurus.
*/ */

28003
website/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -4,24 +4,20 @@
"license": "MIT", "license": "MIT",
"private": true, "private": true,
"scripts": { "scripts": {
"build": "run-s build:docker build:schema build:api build:docusaurus", "build": "run-s build:api build:docusaurus",
"build-bundled": "run-s build:schema build:api build:docusaurus",
"build:api": "docusaurus gen-api-docs all", "build:api": "docusaurus gen-api-docs all",
"build:docker": "cp ../docker-compose.yml ./static/docker-compose.yml",
"build:docusaurus": "cross-env NODE_OPTIONS='--max_old_space_size=65536' docusaurus build", "build:docusaurus": "cross-env NODE_OPTIONS='--max_old_space_size=65536' docusaurus build",
"build:schema": "cp -f ../schema.yml ./static/schema.yml",
"deploy": "docusaurus deploy", "deploy": "docusaurus deploy",
"docusaurus": "docusaurus", "docusaurus": "docusaurus",
"lint": "eslint --fix .", "lint": "eslint --fix .",
"lint-check": "eslint --max-warnings 0 .", "lint-check": "eslint --max-warnings 0 .",
"lint:lockfile": "echo 'Skipping lockfile linting'",
"prettier": "prettier --write .", "prettier": "prettier --write .",
"prettier-check": "prettier --check .", "prettier-check": "prettier --check .",
"serve": "docusaurus serve", "serve": "docusaurus serve",
"start": "docusaurus start", "start": "docusaurus start",
"swizzle": "docusaurus swizzle", "swizzle": "docusaurus swizzle",
"test": "node --test", "test": "node --test",
"watch": "run-s build:schema build:api start" "watch": "run-s build:api start"
}, },
"dependencies": { "dependencies": {
"@docusaurus/core": "^3.7.0", "@docusaurus/core": "^3.7.0",
@ -44,15 +40,17 @@
"react-dom": "^18.3.1", "react-dom": "^18.3.1",
"remark-directive": "^4.0.0", "remark-directive": "^4.0.0",
"remark-github": "^12.0.0", "remark-github": "^12.0.0",
"semver": "^7.7.2" "semver": "^7.7.2",
"vscode-languageserver-types": "3.17.5"
}, },
"devDependencies": { "devDependencies": {
"@docusaurus/module-type-aliases": "^3.7.0", "@docusaurus/module-type-aliases": "^3.7.0",
"@docusaurus/tsconfig": "^3.7.0", "@docusaurus/tsconfig": "^3.7.0",
"@docusaurus/types": "^3.7.0", "@docusaurus/types": "^3.7.0",
"@eslint/js": "^9.27.0", "@eslint/js": "^9.27.0",
"@goauthentik/eslint-config": "^1.0.4", "@goauthentik/core": "^1.0.0",
"@goauthentik/prettier-config": "^1.0.4", "@goauthentik/eslint-config": "^1.0.5",
"@goauthentik/prettier-config": "^1.0.5",
"@goauthentik/tsconfig": "^1.0.4", "@goauthentik/tsconfig": "^1.0.4",
"@trivago/prettier-plugin-sort-imports": "^5.2.2", "@trivago/prettier-plugin-sort-imports": "^5.2.2",
"@types/lodash": "^4.17.17", "@types/lodash": "^4.17.17",
@ -86,7 +84,7 @@
"lightningcss-linux-x64-gnu": "1.30.1" "lightningcss-linux-x64-gnu": "1.30.1"
}, },
"engines": { "engines": {
"node": ">=22.14.0" "node": ">=22.15.1"
}, },
"browserslist": { "browserslist": {
"production": [ "production": [