Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
60 commits
Select commit Hold shift + click to select a range
4b51838
## What
kensternberg-authentik Mar 18, 2026
0037547
Merge branch 'main' into dev
kensternberg-authentik Mar 20, 2026
7c60c42
Merge branch 'main' into dev
kensternberg-authentik Mar 23, 2026
b6d8df0
Merge branch 'main' into dev
kensternberg-authentik Mar 24, 2026
23536f9
Merge branch 'main' into dev
kensternberg-authentik Mar 25, 2026
7aa9920
Merge branch 'main' into dev
kensternberg-authentik Mar 26, 2026
631c3c7
Merge branch 'main' into dev
kensternberg-authentik Mar 26, 2026
7d7e2e9
Merge branch 'main' into dev
kensternberg-authentik Mar 30, 2026
3d40620
Merge branch 'main' into dev
kensternberg-authentik Mar 31, 2026
faf515e
Merge branch 'main' into dev
kensternberg-authentik Apr 1, 2026
380349a
Merge branch 'main' into dev
kensternberg-authentik Apr 2, 2026
ca6fd3d
Merge branch 'main' into dev
kensternberg-authentik Apr 2, 2026
118d34a
Merge branch 'main' into dev
kensternberg-authentik Apr 7, 2026
1a5f7b0
Merge branch 'main' into dev
kensternberg-authentik Apr 8, 2026
639f02a
Merge branch 'main' into dev
kensternberg-authentik Apr 10, 2026
0d0690a
Merge branch 'main' into dev
kensternberg-authentik Apr 28, 2026
2f5ad86
Merge branch 'main' into dev
kensternberg-authentik Apr 30, 2026
41e6a98
Merge branch 'main' into dev
kensternberg-authentik May 1, 2026
1860593
Merge branch 'main' into dev
kensternberg-authentik May 4, 2026
3e966ee
Merge branch 'main' into dev
kensternberg-authentik May 5, 2026
cc9c06d
Merge branch 'main' into dev
kensternberg-authentik May 6, 2026
b5ddfa7
Merge branch 'main' into dev
kensternberg-authentik May 8, 2026
807e3b8
Merge branch 'main' into dev
kensternberg-authentik May 11, 2026
c8229b4
Merge branch 'main' into dev
kensternberg-authentik May 13, 2026
c1d4a5f
Merge branch 'main' into dev
kensternberg-authentik May 13, 2026
8083add
Merge branch 'main' into dev
kensternberg-authentik May 18, 2026
8c0ce54
Merge branch 'main' into dev
kensternberg-authentik May 22, 2026
976bc9a
Merge branch 'main' into dev
kensternberg-authentik Jun 2, 2026
5cd3f0c
Merge branch 'main' into dev
kensternberg-authentik Jun 5, 2026
977cd4d
Merge branch 'main' into dev
kensternberg-authentik Jun 8, 2026
9221a9b
Merge branch 'main' into dev
kensternberg-authentik Jun 10, 2026
6be1be9
Merge branch 'main' into dev
kensternberg-authentik Jun 10, 2026
3149080
Merge branch 'main' into dev
kensternberg-authentik Jun 12, 2026
580a27c
Merge branch 'main' into dev
kensternberg-authentik Jun 24, 2026
5808865
Merge branch 'main' into dev
kensternberg-authentik Jun 25, 2026
f3138a7
Merge branch 'main' into dev
kensternberg-authentik Jun 26, 2026
7d985db
Merge branch 'main' into dev
kensternberg-authentik Jun 29, 2026
9d095db
Merge branch 'main' into dev
kensternberg-authentik Jul 1, 2026
34f3cfb
Merge branch 'main' into dev
kensternberg-authentik Jul 3, 2026
17ab3c5
Merge branch 'main' into dev
kensternberg-authentik Jul 6, 2026
8fb40d8
Merge branch 'main' into dev
kensternberg-authentik Jul 7, 2026
973baba
Merge branch 'main' into dev
kensternberg-authentik Jul 10, 2026
ca9169b
Merge branch 'main' into dev
kensternberg-authentik Jul 13, 2026
78cdfec
Merge branch 'main' into dev
kensternberg-authentik Jul 14, 2026
d65756e
Merge branch 'main' into dev
kensternberg-authentik Jul 15, 2026
9b10128
Merge branch 'main' into dev
kensternberg-authentik Jul 15, 2026
b59545d
Merge branch 'main' into dev
kensternberg-authentik Jul 22, 2026
2123916
Merge branch 'main' into dev
kensternberg-authentik Jul 22, 2026
477cdf4
Merge branch 'main' into dev
kensternberg-authentik Jul 22, 2026
33d06ee
Merge branch 'main' into dev
kensternberg-authentik Jul 23, 2026
06a6051
Merge branch 'main' into dev
kensternberg-authentik Jul 27, 2026
e6daf5d
Merge branch 'main' into dev
kensternberg-authentik Jul 29, 2026
8b1bcca
Merge branch 'main' into dev
kensternberg-authentik Aug 3, 2026
fc081a8
Merge branch 'main' into dev
kensternberg-authentik Aug 4, 2026
8fac6d8
Merge branch 'main' into dev
kensternberg-authentik Aug 6, 2026
5e0879e
Merge branch 'main' into dev
kensternberg-authentik Aug 12, 2026
50b6035
Merge branch 'main' into dev
kensternberg-authentik Aug 12, 2026
1d1c4d1
web/testing/snapshots: enable visual comparisons
kensternberg-authentik Aug 13, 2026
e70ce64
Of course prettier had opinions.
kensternberg-authentik Aug 13, 2026
3fc50fb
Optimised images with calibre/image-actions
authentik-automation[bot] Aug 14, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 30 additions & 13 deletions web/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,41 @@ for awhile, but at least let's get started.

# Setup

Install dependencies from the repo root with `make node-install` (or `make install` for the full
Python + web + docs bootstrap). This wraps `npm ci` and explicitly rebuilds the small set of
packages whose install scripts are required for the toolchain to function — currently `esbuild`,
`chromedriver`, `tree-sitter`, and `tree-sitter-json`.
The package manager is **pnpm**, pinned by the `packageManager` field in `package.json`. We
currently require Node.js 24 or newer.

The repo-root `.npmrc` sets `ignore-scripts=true` to neutralize the dominant npm supply-chain
attack vector. As a side effect, running `npm ci` directly in this directory will install
dependencies but skip those rebuilds, leaving `esbuild` and `chromedriver` in a non-functional
state. If you bypass `make`, run the rebuild step yourself:
Install from the project root (not the `./web` folder!):

```bash
npm rebuild --ignore-scripts=false --foreground-scripts \
esbuild chromedriver tree-sitter tree-sitter-json
make web-install # this package only
make install # node + web + the Python core
```

New dependencies that ship install scripts must be audited and added to `TRUSTED_INSTALL_SCRIPTS`
in the repo-root `Makefile`. Each entry is arbitrary code that runs at install time, so the list
is intentionally small.
`web/` is a pnpm workspace root — it has its own `pnpm-workspace.yaml` and `pnpm-lock.yaml`,
independent of the ones at the repository root. `make node-install` installs the _root_ workspace
and does **not** include the `./web` folder (this folder); use `make web-install` (or `make
install`) for web work. Documentation dependencies are also separate; build them with `make
docs-install`.

Running `pnpm install` in this folder will also work. The `make` targets add two things: they pass
`--frozen-lockfile`, and `make node-install` first runs `scripts/node/lint-runtime.mjs` to check
that the local Node or pnpm matches the requirements in `package.json`. (The project root `.npmrc`
also sets `engine-strict=true` and `save-exact=true` to make sure `pnpm add` writes exact versions.)

## Install scripts

pnpm blocks package install scripts by default, since they're the vector for most supply-chain
attacks. Packages can be allowed to run install scripts only by explicitly being included in one of
two fields in `pnpm-workspace.yaml`:

- **`onlyBuiltDependencies`** — the allowlist. Currently `chromedriver`, `esbuild`, `tree-sitter`,
`tree-sitter-json`, and `@tree-sitter-grammars/tree-sitter-yaml`, all of which need to compile or
fetch a binary to function.
- **`allowBuilds`** — pnpm 11's explicit approval map. `true` mirrors the allowlist; `false` records
a deliberate decline, which suppresses the "pending approval" prompt without running anything.

A new dependency that ships an install script must be audited and added to **both** fields. Think
before you add anything to the lists.

# The Theory of the authentik UI

Expand Down
78 changes: 78 additions & 0 deletions web/test/browser/1000-snapshots.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import { expect, test } from "#e2e";

const COLOR_SCHEMES = ["light", "dark"] as const;

for (const scheme of COLOR_SCHEMES) {
test.describe(`Appearance - ${scheme}`, () => {
// locking the viewport size to ensure consistent snapshots
test.use({ colorScheme: scheme, viewport: { width: 1280, height: 800 } });

test("Dashboard renders", async ({ session, page }) => {
await test.step("Authenticate", async () =>
await session.login({ to: "/if/admin/#/administration/overview" }));

await expect(
page.locator("html"),
`Document reports the ${scheme} color scheme`,
).toHaveAttribute("data-theme", scheme, { timeout: 10_000 });

await page.waitForTimeout(1000);

await test.step("Compare the screenshot", async () => {
await expect(page, `${scheme} matches the baseline`).toHaveScreenshot(
`overview-${scheme}.webp`,
// Fairly high, but needed to handle how dates and version numbers
// can change.
{
animations: "disabled",
caret: "hide",
mask: [page.locator("ak-version")],
maxDiffPixelRatio: 0.05,
},
);
});
});

test("Table renders", async ({ session, page }) => {
await test.step("Authenticate", async () =>
await session.login({ to: "/if/admin/#/events/rules" }));

await page.getByRole("button", { name: "Expand row" }).first().click();

await page.waitForTimeout(1000);

await test.step("Compare the screenshot", async () => {
await expect(page, `${scheme} matches the baseline`).toHaveScreenshot(
`notification-table-${scheme}.webp`,
// Tighter, since there are no dates, versions, etc on the page.
{
animations: "disabled",
caret: "hide",
maxDiffPixelRatio: 0.02,
},
);
});
});

test("Form renders", async ({ session, page }) => {
await test.step("Authenticate", async () =>
await session.login({ to: "/if/admin/#/flow/stages/prompts" }));

await page.getByRole("button", { name: "New Prompt" }).click();

await page.waitForTimeout(1000);

await test.step("Compare the screenshot", async () => {
await expect(page, `${scheme} matches the baseline`).toHaveScreenshot(
`new-prompt-form-${scheme}.webp`,
// Tighter, since there are no dates, versions, etc on the page.
{
animations: "disabled",
caret: "hide",
maxDiffPixelRatio: 0.02,
},
);
});
});
});
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading