Compare commits

..

117 Commits

Author SHA1 Message Date
Teffen Ellis
c8d5832018 web: Flesh out module driven tag names. 2026-02-06 07:23:00 +01:00
Ken Sternberg
52eef39e7e web/flow: refactor FlowExecutor so that client-side stage selection is separate from stage execution
# What

Extracts and normalizes the *massive* switch/case statement into a table, eliminating as much repetition as possible. Where the server-side stage token and the client-side component have the same tag, only one is required. There were three different patterns for prop definitions, and those have been regularized into an expression with a compile-time type check, and the most common one can be omitted from the stage definition table.

# Why

1.  Because it’s hella cleaner. Stages are clear and easy to spot in the table (especially when it’s alphabetically ordered, OMG). Stages that disagree in name with their components, stages that take props different from the “standard” set, and stages that need `import` statements, are all easy to identify.
2.  Because identifying what we *do* with our web components is critical to their success, and to the success of the styling system the authentik web team envisions. FlowExecutor provides selection and execution of stages, but it also provides the inspector, the locale selector, headers, footers, customizations, and branding. Clearing away clutter to make that easier to see makes future refactoring for compatibility mode and dark theme handling much easier.
2026-02-03 17:22:07 -08:00
Ken Sternberg
a2f5ad00a9 Merge branch 'main' into dev
* main: (26 commits)
  providers/saml: auto pull signature algorithm options (#17614)
  core, web: bump @isaacs/brace-expansion from 5.0.0 to 5.0.1 in /packages/prettier-config (#19990)
  web: bump @isaacs/brace-expansion from 5.0.0 to 5.0.1 in /web (#19989)
  stages/authenticator_webauthn: fix double JSON encoding of webauthn options (#19952)
  core: bump django from 5.2.10 to 5.2.11 (#19988)
  ci: allow setting assignee to fail (#19985)
  root: revert enterprise loading behaviour (#19485)
  web/flows: update flow background (#19974)
  providers/oauth2: use compare_digest for client_secret comparison (#19979)
  recovery: consume token in transaction (#19967)
  core: ask for token duration on recovery link/email by admin (#19875)
  core: bump aws-cdk-lib from 2.236.0 to 2.237.0 (#19958)
  web: bump the storybook group across 1 directory with 5 updates (#19960)
  core: bump library/nginx from `c881927` to `7fe5dda` in /website (#19961)
  core: bump gunicorn from 25.0.0 to 25.0.1 (#19959)
  core: bump goauthentik.io/api/v3 to 3.2026.2.0-rc1-1770129730 (#19973)
  lifecycle: bump shm size (#19369)
  crypto: Add ED25519 and ED448 support to the certificate builder (#19465)
  web/admin: Register stage elements. Fix linter warnings (#19948)
  web: bump knip from 5.82.1 to 5.83.0 in /web (#19962)
  ...
2026-02-03 13:56:03 -08:00
Ken Sternberg
86a689ae05 Merge branch 'main' into dev
* main: (30 commits)
  web/admin: fix default binding order (#19943)
  ci: fix test_docker.sh (#19944)
  lib: Add ssh/sftp schemas in to DomainlessFormattedURLValidator (#19881)
  core: fix non-expiring service accounts and app passwords (#19913)
  lifecycle/ak: make sure /data has the correct permissions (#19935)
  lifecycle/aws: add /data volume (#19936)
  website/docs: Update location of media storage and outdated references (#19885)
  web: bump @types/node from 25.1.0 to 25.2.0 in /web (#19923)
  web: bump @playwright/test from 1.58.0 to 1.58.1 in /web (#19926)
  web: bump the rollup group across 1 directory with 4 updates (#19922)
  ci: always generate API clients (#19906)
  providers/scim: add configuration warning for migration (#19859)
  core, web: update translations (#19868)
  core: bump gunicorn from 24.1.1 to 25.0.0 (#19916)
  core: bump pyjwt from 2.10.1 to 2.11.0 (#19920)
  core: bump cachetools from 6.2.6 to 7.0.0 (#19919)
  web: bump @formatjs/intl-listformat from 8.2.0 to 8.2.1 in /web (#19924)
  web: bump the storybook group across 1 directory with 5 updates (#19921)
  core: bump axllent/mailpit from v1.28.4 to v1.29.0 in /tests/e2e (#19918)
  core: bump goauthentik/selenium from 144.0-ak-0.35.9 to 144.0-ak-0.40.0 in /tests/e2e (#19917)
  ...
2026-02-02 09:26:54 -08:00
Ken Sternberg
50092fef98 Merge branch 'main' into dev
* main: (52 commits)
  website: QL Search keyboard interactions docs, examples. (#16259)
  website/integrations: immich: add signing algorithm (#19187)
  website/docs: endpoint devices: add version command (#19767)
  common: introduce common (#19852)
  web: bump @sentry/browser from 10.37.0 to 10.38.0 in /web in the sentry group across 1 directory (#19871)
  core: bump debugpy from 1.8.19 to 1.8.20 (#19872)
  ci: bump actions/cache from 5.0.2 to 5.0.3 (#19873)
  web: bump chromedriver from 144.0.1 to 145.0.0 in /web (#19874)
  web: Captcha Refinements, Part 2  (#19757)
  root: assign cherry-pick PRs to original author (#19858)
  web: Lit Development Mode, performance fixes. (#19825)
  web: Fix development theme overrides (#19826)
  website/docs: add tip for recovering from accidental main branch work (#19865)
  web: bump API Client version (#19857)
  rbac: clean up roles and permissions (#19588)
  web: bump API Client version (#19851)
  website/docs: add more info to entra id scim doc (#19849)
  sources/oauth: Fix an issue where wechat may crash duing login. (#18973)
  providers/scim: fix email validation mismatch (#19848)
  providers/scim: modify user- and group syncing behavior (#13947)
  ...
2026-01-30 09:17:50 -08:00
Ken Sternberg
ea188eeac3 Merge branch 'main' into dev
* main: (45 commits)
  sources/saml: Add testcases for PR #19593 (#19647)
  revert: website/integrations: wazuh: Change exchange key generation to 64 bytes (#19759)
  web: bump API Client version (#19760)
  core: bump djangoql from 0.18.2 to 0.19.1 (#19780)
  web: Vendor SFE Bootstrap (#19766)
  core, web: update translations (#19717)
  web: bump the eslint group across 1 directory with 3 updates (#19782)
  web: bump the react group across 1 directory with 2 updates (#19784)
  web: bump country-flag-icons from 1.6.8 to 1.6.9 in /web (#19785)
  providers/oauth2: Support login_hint (#19498)
  admin/files: add centralized theme variable support for file URLs (#19657)
  core: bump github.com/pires/go-proxyproto from 0.9.1 to 0.9.2 (#19778)
  core: bump openapitools/openapi-diff from 2.1.6 to 2.1.7 in /scripts/api (#19779)
  core: bump gssapi from 1.10.1 to 1.11.1 (#19781)
  ci: bump actions/attest-build-provenance from 3.1.0 to 3.2.0 (#19783)
  website/docs: endpoint devices: fix local device login (#19698)
  web: Enforce `challenge` nullish types. (#19768)
  web/elements: stabilize dual-select status height (#19734)
  web/a11y: CAPTCHA Stage Form (#19670)
  web/table: align row action icons and tooltip color (#19736)
  ...
2026-01-27 10:45:44 -08:00
Ken Sternberg
50bb59b84c Merge branch 'main' into dev
* main:
  endpoints: FleetDM connector (#18589)
  web/admin: fix impersonation form requesting data without being opened (#19673)
  core: return bad request when user is authenticated and not active (#19706)
2026-01-23 13:53:00 -08:00
Ken Sternberg
e6ca150a21 Merge branch 'main' into dev
* main: (115 commits)
  internal: fix incorrect metric calculation (#19701)
  core, web: update translations (#19684)
  core: bump goauthentik.io/api/v3 from 3.2026020.12 to 3.2026020.14 (#19686)
  lifecycle/aws: bump aws-cdk from 2.1101.0 to 2.1102.0 in /lifecycle/aws (#19687)
  core: bump goauthentik/selenium from 143.0-ak-0.35.3 to 144.0-ak-0.35.7 in /tests/e2e (#19688)
  core: bump msgraph-sdk from 1.52.0 to 1.53.0 (#19689)
  core: bump ruff from 0.14.13 to 0.14.14 (#19690)
  core: bump twilio from 9.9.1 to 9.10.0 (#19691)
  core: bump gunicorn from 23.0.0 to 24.0.0 (#19692)
  web: bump the bundler group across 1 directory with 3 updates (#19693)
  web: bump unist-util-visit from 5.0.0 to 5.1.0 in /web (#19694)
  web: bump globals from 17.0.0 to 17.1.0 in /web (#19695)
  ci: bump actions/checkout from 6.0.1 to 6.0.2 (#19696)
  web: Form Modal Independence: Part 1 (#19395)
  web/common: add dev middleware to show warnings for consecutive identical requests (#19671)
  web/admin: fix file upload not preserving extension for custom names with dots (#19548)
  web/admin: fix brand form sending "undefined" string for blank default application (#19658)
  providers/proxy: Fix incorrect comparison of redirect URL and CookieDomain (#15686)
  core: add bulk session revocation (#18564)
  website/docs: endpoint devices: add serial number note (#19677)
  ...
2026-01-23 08:13:07 -08:00
Ken Sternberg
3cd4afb06a Merge branch 'main' into dev
* main: (47 commits)
  endpoints/connectors/agent: add tests for IA endpoint stage (#19487)
  website/docs: limiting permissions of AD service account (#19483)
  endpoints/connectors/agent: Skip Endpoint stage on device IA & fix confusing identification subtext (#19482)
  root: adjust makefile for non-brew macos (#19479)
  providers/oauth2: allow property mappings to override scope claim in access tokens (#19226)
  revert: lib: use orjson for structlog json (#19478)
  stages/authenticator_webauthn: Update FIDO MDS3 & Passkey aaguid blobs (#19464)
  core: bump library/nginx from `e3a22a7` to `c881927` in /website (#19469)
  core: bump library/node from 25.2.1-trixie to 25.3.0-trixie in /website (#19468)
  web: bump prettier from 3.7.4 to 3.8.0 in /web (#19471)
  website/integrations: add MinIO AIStor configuration via environment variables (#19337)
  root: upgrade ruff lint for 3.14 (#19461)
  lib: use orjson for structlog json (#19462)
  ci: fix checkout stable (for 2025.12) (#19448)
  root: Python 3.14 (#17313)
  core: bump channels from 4.3.1 to 4.3.2 (#19458)
  core: bump mypy from 1.18.2 to 1.19.1 (#19457)
  core: bump google-api-python-client from 2.177.0 to 2.188.0 (#19443)
  core: bump selenium from 4.32.0 to 4.39.0 (#19455)
  core: bump msgraph-sdk from 1.39.0 to 1.52.0 (#19454)
  ...
2026-01-15 10:24:07 -08:00
Ken Sternberg
42ad526636 Merge branch 'main' into dev
* main: (87 commits)
  core: bump importlib-metadata from 8.6.1 to 8.7.1 (#19430)
  core: bump geoip2 from 5.1.0 to 5.2.0 (#19429)
  core: bump debugpy from 1.8.14 to 1.8.19 (#19414)
  core: remove session migration (#14568)
  website/docs: add 2026.2 release notes draft page (#19418)
  core: bump wsproto from 1.2.0 to 1.3.2 (#19417)
  core: bump bpython from 0.25 to 0.26 (#19408)
  core: bump pdoc from 15.0.3 to 16.0.0 (#19413)
  core: bump ruff from 0.11.9 to 0.14.11 (#19410)
  core: bump python-kadmin-rs from 0.6.1 to 0.6.3 (#19416)
  core: bump drf-orjson-renderer from 1.7.3 to 1.8.0 (#19415)
  core: bump black from 25.1.0 to 25.12.0 (#19412)
  core: bump lxml from 6.0.0 to 6.0.2 (#19409)
  core: bump xmlsec from 1.3.16 to 1.3.17 (#19411)
  core: bump library/nginx from `06eb0c8` to `e3a22a7` in /website (#19394)
  core: bump library/node from `03729a7` to `6222695` in /website (#19393)
  website/docs: remove "beta" tag from 2025.12 (#19404)
  website/docs: add import to discord policy (#19397)
  web: bump @types/node from 25.0.7 to 25.0.8 in /web (#19392)
  website/docs: mention dynamic overrides in redirect stage documentation (#19368)
  ...
2026-01-14 08:24:16 -08:00
Ken Sternberg
f921eefdde Merge branch 'main' into dev
* main:
  website/docs: update unique email policy (#19305)
  core: bump library/nginx from `ca871a8` to `7272239` in /website (#19334)
  web: bump @types/node from 25.0.3 to 25.0.6 in /web (#19331)
  core: bump axllent/mailpit from v1.28.1 to v1.28.2 in /tests/e2e (#19329)
  web: bump knip from 5.80.1 to 5.80.2 in /web (#19332)
  web: bump pino from 10.1.0 to 10.1.1 in /web (#19333)
  website/docs: add flow import warnings (#19307)
  website/docs: Fix documentation example for `app_entitlements_attributes`. (#19316)
  website/docs: update m2m doc (#18963)
  website/docs: Fix typo in GitHub OAuth Source instructions (#18936)
  website/docs: deprecate GCDT auth stage (#19306)
  core, web: update translations (#19237)
2026-01-12 08:20:33 -08:00
Ken Sternberg
dd9eb4274d Merge branch 'main' into dev
* main: (44 commits)
  web: Fix flow inspector advancement event. (#19309)
  web: bump knip from 5.80.0 to 5.80.1 in /web (#19301)
  core: bump urllib3 from 2.5.0 to v2.6.3 (#19287)
  endpoints: show agent version (#19239)
  core: bump django from v5.2.9 to 5.2.10 (#19290)
  web/admin: add banner to flow import form (#19288)
  web: bump chromedriver from 143.0.3 to 143.0.4 in /web (#19244)
  stages/password: replace session-based retries with reputation (#18643)
  website/integations: fix aws spelling (#19253)
  website/docs: update entra id provider docs (#18366)
  stages/prompt: optimize API endpoints (#19251)
  web: bump the rollup group across 1 directory with 4 updates (#19206)
  web: bump vite from 7.3.0 to 7.3.1 in /web (#19245)
  website/docs: update github social login script example (#19246)
  website/integrations: update AWS (#17861)
  core: bump goauthentik.io/api/v3 from 3.2026020.8 to 3.2026020.10 (#19242)
  website: Fix typos. (#19243)
  core: fix read replica routing during transactions (#19086)
  website/glossary: improve (#18969)
  stages/authenticator_static: set max token length to 100 chars (#19162)
  ...
2026-01-09 09:34:48 -08:00
Ken Sternberg
ac0c1c9df3 Merge branch 'main' into dev
* main: (24 commits)
  web/maintenance: no missing element type definitions (#18950)
  core: add prettier failure on duplicate group names (#18941)
  website/integrations: make grafana terraform section expand (#19192)
  lib: update error logging (#18628)
  core, web: update translations (#19179)
  web: bump @formatjs/intl-listformat from 8.1.0 to 8.1.1 in /web (#19182)
  ci: bump getsentry/action-release from 3.4.0 to 3.5.0 (#19183)
  web: bump knip from 5.78.0 to 5.79.0 in /web (#19181)
  lifecycle: fix migration conn_options for psycopg connection (#19134)
  website/docs: remove duplicates in slo docs (#19170)
  web/admin: adjust sync threshold, add tooltip (#19131)
  web: Fix user library colors, modal z-indexes, table progress bars (#19152)
  web: fix slug auto-updating when editing existing applications (#19169)
  core: handle deserialization errors from FileField migration (#19067)
  stages/authenticator_webauthn: Update FIDO MDS3 & Passkey aaguid blobs (#19137)
  website/integrations: vaultwarden: add custom email scope (#19160)
  ci: bump int128/docker-manifest-create-action from 2.10.0 to 2.12.0 (#19138)
  core, web: update translations (#19135)
  web: bump globals from 16.5.0 to 17.0.0 in /web (#19154)
  web/user: fix consent delete form missing details (#19147)
  ...
2026-01-06 10:27:49 -08:00
Ken Sternberg
634f1f754d Merge branch 'main' into dev
* main: (48 commits)
  website/integrations: karakeep: don't hardcode wellknown's slug (#19127)
  core, web: bump qs from 6.14.0 to 6.14.1 in /packages/docusaurus-config (#19130)
  core: bump library/node from `ccfd9da` to `03729a7` in /website (#19125)
  core: bump github.com/jackc/pgx/v5 from 5.7.6 to 5.8.0 (#19088)
  web: bump the swc group across 1 directory with 11 updates (#19124)
  core: bump library/nginx from `ad85427` to `ca871a8` in /website (#19126)
  web: Capitalize language display names, code owner fix (#19119)
  web: Fix Impersonation, Lit Reactive Controller Contexts (#19114)
  web: bump the eslint group across 1 directory with 3 updates (#19110)
  core: bump library/nginx from `fb01117` to `ad85427` in /website (#19112)
  web: bump the storybook group across 1 directory with 5 updates (#19111)
  website/docs: release notes: Add more integrations (#19109)
  website/integrations: Add Audiobookshelf (#19104)
  website/integrations: Add Pulse (#19105)
  web/maintenance/no unknown attributes (part 1) (#18970)
  Update Vaultwarden documentation by removing warning (#19102)
  web: Fix stale flow background (#19015)
  web: fix promoted source button hover losing blue color (#19048)
  web: bump knip from 5.77.1 to 5.78.0 in /web (#19090)
  website/docs: endpoint devices: add path to macos setup (#19093)
  ...
2025-12-31 10:23:08 -08:00
Ken Sternberg
1620155f32 Merge branch 'main' into dev
* main:
  website/docs: Prioritize "Release Candidate" over "Current Release" (#18975)
  core: bump goauthentik.io/api/v3 from 3.2026020.4 to 3.2026020.5 (#19017)
  web: bump the eslint group across 1 directory with 3 updates (#19019)
  web/admin: prevent file upload attempt when backend not managed (#18646)
  api: rework schema generation (#18977)
  web: bump globby from 16.0.0 to 16.1.0 in /web (#18995)
  core: bump openapitools/openapi-generator-cli from v7.16.0 to v7.18.0 in /scripts/api (#19018)
  web: bump the rollup group across 1 directory with 4 updates (#18994)
2025-12-23 08:10:24 -08:00
Ken Sternberg
8d29ae4dd8 Merge branch 'main' into dev
* main:
  website/docs: improve endpoint devices docs (#19007)
  enterprise/search: add static autocomplete structure (#19008)
  enterprise/reports: improve export list, confirmation (#18981)
  providers/oauth2: Automated OpenID Conformance tests (#14785)
  ci: bump docker/setup-buildx-action from 3.11.1 to 3.12.0 (#18999)
  blueprints: fix flaky tests (#19002)
  web: fix Open button selecting row instead of navigating (#18992)
  events: notifications live update (#18980)
  web/admin: Fix haveibeenpwned link in PasswordPolicyForm (#18984)
  web/admin: fix dark theme on map (#18985)
  blueprints: add InternallyManagedMixin instead of large list (#18983)
  website/integrations: Fix path for Cloudflare Access (#18979)
2025-12-22 13:43:32 -08:00
Ken Sternberg
1521ade889 Merge branch 'main' into dev
* main: (60 commits)
  web/maintenance: no unknown tag names (#18944)
  web/maintenance: fix missing custom web component imports (#18942)
  website/docs: add note to active directory source doc (#18787)
  ci: bump actions/attest-build-provenance from 3.0.0 to 3.1.0 (#18960)
  web: bump @sentry/browser from 10.31.0 to 10.32.0 in /web in the sentry group across 1 directory (#18957)
  web: bump the swc group across 1 directory with 11 updates (#18958)
  web: bump chromedriver from 143.0.2 to 143.0.3 in /web (#18959)
  core: bump goauthentik.io/api/v3 from 3.2026020.3 to 3.2026020.4 (#18956)
  root: move docker files to lifecycle/containers and change docker-compose to compose (#16624)
  flows/executor: fix KeyError when session has no existing plan (#18951)
  web/admin: fix endpoints user binding (#18935)
  website/docs: Fix version parsing. (#18948)
  website/docs: release notes: add endpoint device links to 2025.12 notes (#18940)
  website/docs: Fix labels, Pre-Release detection (#18945)
  website/docs: endpoint devices (#18634)
  stages/identification: replace sleep with make_password (#18883)
  web/elements: progress-bar and table loading header (#18934)
  crypto: fix extra cert data in db migration (#18937)
  website/integrations: Add launch URL for Immich (#18921)
  web/flow: Fix spurious double submit  on ak-stage-autosubmit (#18727)
  ...
2025-12-19 08:55:37 -08:00
Ken Sternberg
9a4c56e6b2 Merge branch 'main' into dev
* main: (54 commits)
  website/docs: 2025.10.3 release notes (#18868)
  website/docs: Add docs for passkey autofill (WebauthN Conditional UI) (#18805)
  website/docs: adjust RBAC-related details in 2025.12 release notes (#18863)
  outposts: fix permission errors for related certificates (#18861)
  web/admin/rbac: misc object permission fixes (#18859)
  core: bump library/golang from `5d35fb8` to `8e8f9c8` (#18855)
  rbac: alter migrated direct permission roles (#18860)
  core: add skip s3_test_server_available to TestResolveFileUrlS3Backend (#18858)
  ci: replace codecov test-results action (#18862)
  core: bump goauthentik/fips-debian from `c10cd2c` to `2f19fc1` (#18856)
  admin/files: fix get_objects_for_user queryset argument in FileUsedByView (#18845)
  core: skip s3 tests if endpoint isn't available (#18841)
  crypto: Store details parsed from includeDetails in database instead (#18013)
  website/docs: add jellyseer integration doc (#18812)
  admin/files: revert add check for /media existence (#18636) (#18829)
  core: bump goauthentik.io/api/v3 from 3.2025120.26 to 3.2026020.1 (#18815)
  packages/django-dramatiq-postgres: broker: close django connections on consumer close (#18833)
  core: remove superuser check from `Token` list (#18684)
  website/docs: add icon info to style guide (#18832)
  core: list applications fix (#18798)
  ...
2025-12-16 08:05:51 -08:00
Ken Sternberg
4f1126ea99 Merge branch 'main' into dev
* main: (69 commits)
  website/docs: fix incorrect menu reference in data exports doc (#18752)
  translate: Updates for project authentik and language zh-Hans (#18756)
  translate: Updates for project authentik and language tr_TR (#18758)
  translate: Updates for project authentik and language fi_FI (#18759)
  translate: Updates for project authentik and language pl_PL (#18754)
  translate: Updates for project authentik and language ru_RU (#18745)
  translate: Updates for project authentik and language ko_KR (#18760)
  translate: Updates for project authentik and language ja_JP (#18755)
  translate: Updates for project authentik and language de_DE (#18749)
  translate: Updates for project authentik and language nl_NL (#18751)
  translate: Updates for project authentik and language pt_BR (#18746)
  translate: Updates for project authentik and language es_ES (#18748)
  translate: Updates for project authentik and language it_IT (#18750)
  translate: Updates for project authentik and language cs_CZ (#18753)
  translate: Updates for project authentik and language fr_FR (#18747)
  stages/identification: Add WebAuthn conditional UI (passkey autofill) support (#18377)
  api: allow configuring default page_size and max_page_size (#18165)
  root: do not require backend approval for npm workspace dependencies (#18738)
  outpost/proxyv2: more tests, fix pg password with spaces, and existing session on restart (#18211)
  web: bump @types/guacamole-common-js from 1.5.4 to 1.5.5 in /web (#18717)
  ...
2025-12-11 13:08:08 -08:00
Ken Sternberg
d15e360a74 Merge branch 'main' into dev
* main: (23 commits)
  *: Auto compress images (#18673)
  website/integrations: update kimai doc (#18629)
  root: skip current tab when refreshing others (#18674)
  core: add digraph group hierarchy (#17050)
  core: bump astral-sh/uv from 0.9.15 to 0.9.16 (#18668)
  core: bump goauthentik.io/api/v3 from 3.2025120.16 to 3.2025120.18 (#18661)
  web: bump type-fest from 5.3.0 to 5.3.1 in /web (#18663)
  ci: bump peter-evans/create-pull-request from 7.0.9 to 7.0.11 (#18666)
  web: bump vite from 7.2.6 to 7.2.7 in /web (#18662)
  core: bump goauthentik/fips-debian from `a80dbbd` to `10c8086` (#18665)
  ci: bump actions/create-github-app-token from 2.2.0 to 2.2.1 (#18664)
  ci: bump astral-sh/setup-uv from 7.1.4 to 7.1.5 in /.github/actions/setup (#18667)
  website/docs: background tasks: add more detail about "next run" (#18660)
  website/docs: install-config: fix dump_config command (#18659)
  website/integrations: wordpress: fix redirect uri (#18658)
  stages/mtls: always include cert in flow plan (#18657)
  endpoints: fix UI bugs, add user binding, etc (#18609)
  sources/ldap: make server info optional (#18648)
  web/admin: fix event volume chart not updating with query (#18649)
  web: Bump types, fix ESLint errors (#17546)
  ...
2025-12-08 08:35:20 -08:00
Ken Sternberg
2cd358d5e1 Merge branch 'main' into dev
* main: (40 commits)
  enterprise/stages/mtls: fix traefik certificate parsing (#18607)
  wed/admin: change s to S in "Stage" (#18632)
  flows: refresh unauthenticated tabs (#18621)
  flows: keep ?next url when using cancel (#18619)
  core, web: update translations (#18620)
  ci: bump actions/setup-node from 6.0.0 to 6.1.0 (#18552)
  core: bump goauthentik/fips-debian from `cf233be` to `a80dbbd` (#18594)
  web: bump @sentry/browser from 10.28.0 to 10.29.0 in /web in the sentry group across 1 directory (#18623)
  website/docs: adds note about ak_create_jwt function (#18614)
  api: fix IPC auth (#18612)
  web: bump mermaid from 11.12.1 to 11.12.2 in /web (#18602)
  web: Codemirror fixes (#18610)
  web: bump packages in /web (#18604)
  website/docs: expressions: fix markdown (#18613)
  website/docs: add missing API sidebar entry (#18586)
  web: bump yaml from 2.8.1 to 2.8.2 in /web (#18605)
  web/elements: update AppIcon story with files change (#18608)
  api: test action decorator (#18583)
  crypto: separate permissions for certificate and private keydownload (#18588)
  core: bump github.com/spf13/cobra from 1.10.1 to 1.10.2 (#18592)
  ...
2025-12-05 15:58:42 -08:00
Ken Sternberg
9fbc76098a Merge branch 'main' into dev
* main: (44 commits)
  build(deps): bump django from 5.2.8 to 5.2.9 (#18566)
  web: Adjust colors (#18427)
  admin/files: delete applications cache on migration (#18565)
  core: bump astral-sh/uv from 0.9.14 to 0.9.15 (#18555)
  core: bump goauthentik.io/api/v3 from 3.2025120.11 to 3.2025120.15 (#18551)
  core: bump goauthentik/fips-debian from `c718f60` to `cf233be` (#18553)
  ci: bump actions/checkout from 6.0.0 to 6.0.1 (#18554)
  ci: bump actions/stale from 10.1.0 to 10.1.1 (#18556)
  ci: bump golangci/golangci-lint-action from 9.1.0 to 9.2.0 (#18557)
  ci: bump actions/setup-node from 6.0.0 to 6.1.0 in /.github/actions/setup (#18559)
  core: bump library/golang from 1.25.4-trixie to 1.25.5-trixie (#18558)
  providers/scim: cache ServiceProviderConfig (#18047)
  web/i18n: Locale Context Merge Branch (#18426)
  website: Glossary (#16007)
  endpoints/stage: v2, better error handling, more settings (#18545)
  website: Docusaurus 3.9.2 (#18506)
  website/integrations: add hoop.dev (#17868)
  web/flows: update default background image (#18540)
  endpoints: implement endpoint stage (#18468)
  website/integrations: add salesforce (#18516)
  ...
2025-12-03 10:42:52 -08:00
Ken Sternberg
be3f35c58f Merge branch 'main' into dev
* main: (53 commits)
  core, web: update translations (#18380)
  web: re-add en.xlf locale (#18469)
  stages/user_write: Fix user attributes are not sanitized under certains conditions (#17890)
  providers/scim: compare users/groups before sending update request (#18456)
  enterprise/endpoints/connectors/agent: fix Apple JWE encryption when FIPS is enabled (#18464)
  website: bump @types/react from 19.2.6 to 19.2.7 in /website (#18357)
  core: bump goauthentik/fips-debian from `ac4c80b` to `de70579` (#18419)
  core: bump github.com/getsentry/sentry-go from 0.39.0 to 0.40.0 (#18416)
  website: bump prettier-plugin-packagejson from 2.5.19 to 2.5.20 in /website (#18460)
  core: bump goauthentik.io/api/v3 from 3.2025120.7 to 3.2025120.11 (#18461)
  website/integrations: add GLPI (#17937)
  website/integrations: small fixes (#18423)
  enterprise: Apple Platform SSO (#15318)
  crypto: only generate managed keypair if non-existent (#18457)
  ci: remove translation-rename (#18444)
  translate: Updates for project authentik and language tr (#18438)
  translate: Updates for project authentik and language fr (#18431)
  translate: Updates for project authentik and language ru (#18442)
  translate: Updates for project authentik and language cs_CZ (#18443)
  translate: Updates for project authentik and language pt (#18437)
  ...
2025-12-01 08:31:12 -08:00
Ken Sternberg
ac31137c97 Merge branch 'main' into dev
* main: (58 commits)
  core: bump goauthentik.io/api/v3 from 3.2025120.5 to 3.2025120.7 (#18381)
  web/admin: add entitlement search (#18291)
  core: bump goauthentik/fips-debian from `8b7e8d0` to `8c4ec98` (#18361)
  website: bump the build group in /website with 3 updates (#18382)
  core: bump astral-sh/uv from 0.9.11 to 0.9.12 (#18383)
  root: improve testing helpers (#18379)
  website: bump the goauthentik group across 1 directory with 4 updates (#18378)
  website: bump the eslint group in /website with 3 updates (#18356)
  policies: use flow planner directly in PolicyAccessView to directly set flow context (#18372)
  providers/scim: fix PATCH for AWS (#18230)
  enterprise/providers/scim: fix OAuth (#18358)
  web: Fix stale table rows (#17940)
  web: Bump packages. (#18371)
  *: convert slugfields to textfields (#17411)
  outposts: set container healthcheck inline (#18298)
  web:  ESLint Typing Fixes  (#18362)
  core: bump golang.org/x/crypto from 0.43.0 to 0.45.0 (#18275)
  lifecycle/aws: bump aws-cdk from 2.1032.0 to 2.1033.0 in /lifecycle/aws (#18278)
  core: bump github.com/getsentry/sentry-go from 0.38.0 to 0.39.0 (#18353)
  ci: bump actions/setup-python from 6.0.0 to 6.1.0 in /.github/actions/setup (#18360)
  ...
2025-11-26 07:47:43 -08:00
Ken Sternberg
8509056e21 Merge branch 'main' into dev
* main: (55 commits)
  Makefile: Fix kerberos tests for brew users (#17223)
  website/docs: add 2025.8.5 and 2025.10.2 release notes (#18268)
  internal: Automated internal backport: 5000-sidebar.sec.patch to authentik-main (#18266)
  internal: Automated internal backport: 1498-oauth2-cc-user-active.sec.patch to authentik-main (#18265)
  internal: Automated internal backport: 1487-invitation-expiry.sec.patch to authentik-main (#18264)
  core, web: update translations (#18241)
  web: bump ts-pattern from 5.8.0 to 5.9.0 in /web (#18247)
  web: bump the react group across 2 directories with 1 update (#18244)
  web: bump knip from 5.66.2 to 5.70.0 in /web (#18245)
  core: bump library/nginx from `b5b9e01` to `553f64a` in /website (#18253)
  core: bump library/golang from `27e1c92` to `728cbef` (#18252)
  core: bump goauthentik/fips-debian from `65a9f1f` to `55c1514` (#18251)
  web: Bump Vitest, TypeScript config (#18238)
  web: bump js-yaml from 4.1.0 to 4.1.1 in /packages/esbuild-plugin-live-reload (#18237)
  web/i18n: Remove English Locale (#18164)
  web: bump js-yaml from 3.14.1 to 3.14.2 in /packages/docusaurus-config (#18239)
  web/i18n: Clean up locale scripts (#18163)
  stages/prompt: fix choices with labels causing error on submit (#18183)
  web: Patternfly 5 Prep: Part 2 (#18085)
  lifecycle/aws: bump aws-cdk from 2.1031.2 to 2.1032.0 in /lifecycle/aws (#18218)
  ...
2025-11-20 09:18:17 -08:00
Ken Sternberg
63e188773f Merge branch 'main' into dev
* main:
  website/integrations: FortiMail (#17900)
  web/sfe: downgrade bootstrap that was accidentally upgraded (#18157)
  web: Fix ESBuild hanging process (#18162)
  website/integrations: macmon NAC (#17898)
2025-11-17 08:51:59 -08:00
Ken Sternberg
8585c646a2 Merge branch 'main' into dev
* main: (74 commits)
  packages/django-channels-postgres/layer: fix query when subscribed to multiple channels (#18152)
  core: deduplicate user attribute constant definitions (#18138)
  web: bump @trivago/prettier-plugin-sort-imports from 5.2.2 to 6.0.0 in /web (#18146)
  crypto: update certificates on fs event (#18129)
  github: converts issue templates to forms (#18133)
  core: bump github.com/getsentry/sentry-go from 0.36.2 to 0.37.0 (#18140)
  web: bump type-fest from 5.1.0 to 5.2.0 in /web (#18144)
  web: bump vite from 7.1.12 to 7.2.2 in /web (#18143)
  website: bump the build group in /website with 3 updates (#18141)
  web: bump globals from 16.4.0 to 16.5.0 in /web (#18145)
  core: bump astral-sh/uv from 0.9.8 to 0.9.9 (#18148)
  core: bump goauthentik/fips-debian from `5017d65` to `40a1f32` (#18149)
  website/integrations: Add ezBookkeeping integration (#18040)
  website/integrations: Add Joplin (#18042)
  web: Disable library `<datalist>` on Firefox. (#18103)
  web/admin: link to user on invitation list page (#18132)
  web/admin: update stage descriptions (#18118)
  website/integrations: add SeaTable (#18115)
  website/integrations: stripe: fix markdown (#18126)
  web/flows: improvements for hCaptcha (#16882)
  ...
2025-11-14 08:06:43 -08:00
Ken Sternberg
5c66e50205 website: fix bad escaping of URLs in release notes
## What

Fixes bad escaping of URLs in the release notes that resulted in mangled output.

v2024.6.4 had entries that looked like this:

```
##### `GET` /providers/google_workspace/{#123;id}#125;/
```

v2025.4.md had entries that looked like this:

```
##### `GET` /policies/unique_password/{#125;#123;policy_uuid}/
```

A couple of straightforward search-and-replaces has fixed the issue.

## Notes

Two of the release notes had bad escaping of URLs. I'm not sure how the error was made or got past,
but it was obvious when visiting the page.

@Beryju suggested that the bug is due to our using `{...}` to symbolize parameters in a URL while
Docusaurus wants to interpret `{...}` as an internal template instruction, resulting in odd
behavior. In either case, docusarus interpreted the hashtagged entries as links to unrelated issues
in Github (the same two issues, which were "bump version of pylint" and "bump version of sentry"),
which could be very confusing.

The inconsistencies between the two releases, and the working releases, suggests that the error was
introduced manually.
2025-11-10 09:20:22 -08:00
Ken Sternberg
2c658e2ee6 Merge branch 'main' into dev
* main: (42 commits)
  core, web: update translations (#17943)
  web: bump @types/node from 24.9.1 to 24.10.0 in /packages/prettier-config (#17949)
  core: bump library/nginx from `f547e3d` to `1beed3c` in /website (#17955)
  core: bump goauthentik.io/api/v3 from 3.2025120.2 to 3.2025120.3 (#17945)
  web: bump @types/node from 22.15.19 to 24.10.0 in /web (#17950)
  ci: bump docker/setup-qemu-action from 3.6.0 to 3.7.0 (#17999)
  lifecycle/aws: bump aws-cdk from 2.1031.1 to 2.1031.2 in /lifecycle/aws (#18014)
  core: bump golang.org/x/sync from 0.17.0 to 0.18.0 (#18033)
  core: bump astral-sh/uv from 0.9.7 to 0.9.8 (#18037)
  core: bump golang.org/x/oauth2 from 0.32.0 to 0.33.0 (#18034)
  core: bump axllent/mailpit from v1.27.10 to v1.27.11 in /tests/e2e (#18035)
  ci: bump golangci/golangci-lint-action from 8.0.0 to 9.0.0 (#18036)
  core: bump library/golang from `a13297b` to `27e1c92` (#18038)
  ci: fix migrate-from-stable for old versions (#18019)
  core: bump library/golang from 1.25.3-trixie to 1.25.4-trixie (#18000)
  website/docs: updates img-src csp (#18010)
  providers/saml: move sp binding location and default value (#17609)
  core: Add example invitation blueprint (#17661)
  root: settings.py: fix comment (#18006)
  core: bump google-auth-httplib2 from 0.2.0 to v0.2.1 (#17978)
  ...
2025-11-10 08:42:07 -08:00
Ken Sternberg
2c52a19a44 Merge branch 'main' into dev
* main:
  webiste/docs: remove broken info box and fix sentence (#17963)
  web/admin: fixes capitalization in application wizard title (#17959)
  website/docs: added Note about email_verified scope mapping is set to false by default (#17942)
  crypto: update certificate api and component (#17921)
  core: bump openapitools/openapi-diff from 2.1.4 to 2.1.5 in /scripts/api (#17929)
  ci: bump getsentry/action-release from 3.3.0 to 3.4.0 (#17931)
  ci: bump helm/kind-action from 1.12.0 to 1.13.0 (#17930)
  tasks/schedules: fix rel obj not being associated or updated (#17934)
  core, web: update translations (#17807)
  brands: sort matched brand by match length (#17920)
  web: bump the storybook group across 1 directory with 5 updates (#17787)
  brands: add more matching tests (#16185)
2025-11-05 08:42:36 -08:00
Ken Sternberg
bc2a07156b Merge branch 'main' into dev
* main: (32 commits)
  website/docs: 2025.10.1 release notes (#17918)
  providers/oauth2: fix kid always required for federation (#17914)
  providers/radius: revert fix inverted message authenticator validation (#17855) (#17915)
  website: bump @types/node from 24.9.1 to 24.9.2 in /website (#17786)
  web: bump @rollup/plugin-commonjs from 28.0.8 to 28.0.9 in /web in the rollup group across 1 directory (#17788)
  web: bump validator from 13.15.15 to 13.15.20 in /packages/docusaurus-config (#17866)
  internal: add default go http server timeouts (#17858)
  providers/radius: fix inverted message authenticator validation (#17855)
  stages/authenticator_webauthn: Update FIDO MDS3 & Passkey aaguid blobs (#17871)
  web: fix package-lock.json (#17809)
  website/integrations: oracle cloud: cleanup (#17808)
  website/integrations: Add Keycloak integration (#17813)
  website: bump the build group across 1 directory with 9 updates (#17849)
  lifecycle/aws: bump aws-cdk from 2.1031.0 to 2.1031.1 in /lifecycle/aws (#17850)
  core: bump astral-sh/uv from 0.9.6 to 0.9.7 (#17851)
  internal: full openssl path (#17856)
  outpost: revert breaking signals change (#17847)
  web/a11y: Isolated Outpost Error Page (#17683)
  provider/saml: make signing kp singleton (#17703)
  tasks: sanitize log attributes (#17833)
  ...
2025-11-03 08:23:26 -08:00
Ken Sternberg
0845cc400c Merge branch 'main' into dev
* main: (28 commits)
  ci: use hashes for actions everywhere (#17803)
  website/integrations: fixed paperless-ngx yml syntax issue and added additional info (#17739)
  core, web: update translations (#17782)
  ci: rework internal repo (#17797)
  root: use hashes for dockerfile FROM (#17795)
  web: bump validator from 13.15.15 to 13.15.20 in /packages/prettier-config (#17776)
  tasks: delay startup signals (#17769)
  website: bump the build group in /website with 6 updates (#17712)
  core, web: update translations (#17660)
  web: bump vite from 7.1.11 to 7.1.12 in /web (#17689)
  website: bump validator from 13.15.15 to 13.15.20 in /website (#17741)
  web: bump eslint-plugin-react-hooks from 7.0.0 to 7.0.1 in /packages/eslint-config in the eslint group across 1 directory (#17714)
  web: bump validator from 13.15.15 to 13.15.20 in /packages/eslint-config (#17742)
  packages/django-postgres-cache: use upsert instead of select/update in a transaction (#17760)
  providers/radius: fix panic when no cert is configured (#17762)
  sources/oauth: Make PKCE verifier 128 characters (#17763)
  providers/proxy: fix missing JWT/claims header (#17759)
  providers/proxy: add gorm logging (#17758)
  web: bump the sentry group across 1 directory with 2 updates (#17743)
  root: Add Dockerfile label org.opencontainers.image.source (#17756)
  ...
2025-10-29 10:07:10 -07:00
Ken Sternberg
91bbf0e449 Merge branch 'main' into dev
* main: (25 commits)
  ci: bump astral-sh/setup-uv from 7.1.1 to 7.1.2 in /.github/actions/setup (#17718)
  web: bump the storybook group across 1 directory with 5 updates (#17715)
  ci: bump actions/upload-artifact from 4.6.2 to 5.0.0 (#17720)
  ci: bump actions/download-artifact from 5.0.0 to 6.0.0 (#17719)
  website/integrations: grafana: replace deprecated redirect_uris usage by allowed_redirect_uris (#17710)
  web: bump @types/codemirror from 5.60.16 to 5.60.17 in /web (#17685)
  web: bump @types/node from 22.15.19 to 24.9.1 in /web (#17687)
  web: bump hono from 4.10.2 to 4.10.3 in /web (#17698)
  website/docs: blueprints: add a bit more info (#17704)
  website/docs: release notes: Add Zot integration (#17700)
  website/integrations: zot oci registry integration (#17682)
  website/integrations: sonarr: clarify reverse proxy setup (#17485)
  website/docs: eap add info about custom validation (#17642)
  web: Fix table row click handler. (#17697)
  root: Fix transifex link (#17696)
  translate: add cs_CZ (#17632)
  web: bump @goauthentik/prettier-config from 1.0.5 to 3.1.0 in /web in the goauthentik group across 1 directory (#17684)
  web: Make action field search case insensitive in Event Matcher Policy Form (#17680)
  website/docs: add note about invite link not bound (#17657)
  web:  Abstract Wizard Lifecycle (#17658)
  ...
2025-10-27 10:33:33 -07:00
Ken Sternberg
11f500c670 Merge branch 'main' into dev
* main:
  website: bump the eslint group in /website with 3 updates (#17601)
  web: bump hono from 4.9.12 to 4.10.2 in /web (#17653)
  web: bump @types/node from 24.9.0 to 24.9.1 in /packages/esbuild-plugin-live-reload (#17616)
  core: bump goauthentik.io/api/v3 from 3.2025100.25 to 3.2025120.1 (#17613)
  website: bump @types/node from 24.9.0 to 24.9.1 in /website (#17612)
  web: bump vite from 7.1.10 to 7.1.11 in /web (#17604)
  lib/sync/outgoing: store sync settings in database (#17630)
2025-10-22 10:00:52 -07:00
Ken Sternberg
eaf9185e73 Merge branch 'main' into dev
* main: (213 commits)
  web: bump @types/node from 24.9.0 to 24.9.1 in /packages/prettier-config (#17617)
  web: bump @types/node from 22.15.19 to 24.9.1 in /web (#17618)
  web: bump knip from 5.66.1 to 5.66.2 in /web (#17619)
  translate: Updates for file web/xliff/en.xlf in pt_BR (#17639)
  core, web: update translations (#17643)
  website/docs: rel notes 2025.10: add 3 more integration guides (#17641)
  providers/proxy: drop headers with underscores (#17650)
  core: bump astral-sh/uv from 0.9.4 to 0.9.5 (#17645)
  web: bump style-mod from 4.1.2 to 4.1.3 in /web (#17647)
  core: bump github.com/getsentry/sentry-go from 0.36.0 to 0.36.1 (#17646)
  website/integrations: add terraform cloud (#17610)
  website/integrations: add zendesk (#17541)
  core: bump djangorestframework from 3.16.0 (our fork) to v3.16.1 (official package) (#16594)
  enterprise: add prometheus metrics for license usage and expiry (#17606)
  ci: link to next. for pre-release docs (#17634)
  web: sync web/package-lock.json (#17611)
  website/integrations: random fixes (#17631)
  website/docs: add short-lived certificate recommendation (#17628)
  core, web: update translations (#17605)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in pt_BR (#17622)
  ...
2025-10-22 08:11:04 -07:00
Ken Sternberg
47ed22b57d Merge branch 'main' into dev
* main: (56 commits)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in fr (#17361)
  website/docs: add entra id scim source (#17357)
  outpost: proxyv2: Use Postgres for the Embedded Outpost (#16628)
  tasks: set uid early (#17356)
  tasks: only set tenant on task creation (#17358)
  core: bump golang.org/x/oauth2 from 0.31.0 to 0.32.0 (#17346)
  web: bump eslint-plugin-react-hooks from 6.1.1 to 7.0.0 in /packages/eslint-config in the eslint group across 1 directory (#17347)
  web: bump chromedriver from 141.0.0 to 141.0.1 in /web (#17348)
  web: bump knip from 5.64.1 to 5.64.2 in /web (#17349)
  web: bump @formatjs/intl-listformat from 7.7.11 to 7.7.12 in /web (#17350)
  web: bump pino from 9.13.0 to 10.0.0 in /web (#17351)
  core: bump axllent/mailpit from v1.27.9 to v1.27.10 in /tests/e2e (#17352)
  enterprise/providers/gws+entra: fix group integrity error during discovery (#17355)
  core, web: update translations (#17342)
  ci: bump snok/container-retention-policy from 2.2.1 to 3.0.1 (#17344)
  core: bump goauthentik.io/api/v3 from 3.2025100.18 to 3.2025100.20 (#17345)
  packages/django-dramatiq-postgres: broker: task retrieval fixes and improvements (#17335)
  enterprise/providers/gws+entra: fix integrity error during discovery (#17341)
  web: bump API Client version (#17340)
  api: Clean schema up more (#17055)
  ...
2025-10-09 10:50:39 -07:00
Ken Sternberg
542a605f9a Merge branch 'main' into dev
* main: (118 commits)
  tasks: add preprocess, running and postprocess statuses (#17297)
  web: Fix behavior for modals configured with closeAfterSuccessfulSubmit (#17277)
  web: Responsive toolbar flow (#17278)
  website/integrations: update dokuwiki (#17292)
  core, web: update translations (#17275)
  core: bump astral-sh/uv from 0.8.23 to 0.8.24 (#17281)
  website: bump @types/node from 24.6.2 to 24.7.0 in /website (#17283)
  web: bump the eslint group across 2 directories with 3 updates (#17285)
  web: bump @types/node from 24.6.2 to 24.7.0 in /packages/esbuild-plugin-live-reload (#17287)
  web: bump @types/node from 24.6.2 to 24.7.0 in /packages/prettier-config (#17288)
  web: bump @types/node from 22.15.19 to 24.7.0 in /web (#17289)
  website/integrations: sssd: Updating config template to include default shell (#17274)
  web/a11y: Flow Stages (#17273)
  web/a11y: Flow inspector. (#17271)
  packages/django-channels-postgres/layer: fix connection deadlock (#17270)
  core: bump django to 5.2.7 (#16324)
  core: fix absolute and relative path file uploads (#17269)
  web/a11y: Accessible scrollbars. (#17253)
  web: Fix table column updates, template parsing (#17254)
  website/integrations: add launch url info to dokuwiki (#17268)
  ...
2025-10-07 07:41:29 -07:00
Ken Sternberg
5b4a921b1a Merge branch 'main' into dev
* main: (29 commits)
  web/a11y: Notifications drawer (#17031)
  web: Clean up render interfaces. (#16031)
  web/a11y: Status label (#17148)
  web: Additional text field properties, ARIA fixes (#17115)
  web/e2e: User creation (#17149)
  web/a11y: Tree view (#17147)
  web/a11y: Fix dark theme color contrast (#17144)
  web: Table refresh timestamp. (#17145)
  providers/oauth2: add ui_locales support for OIDC (#17140)
  website/integrations: convert all note boxes to info boxes (#17139)
  website/docs: replaces all note boxes with info boxes (#17138)
  website/docs: developer docs: adjust sentence for writing docs (#17137)
  core: Add input validation for service account creation (#16964)
  website: bump @types/node from 24.5.2 to 24.6.0 in /website (#17126)
  ci: bump actions/setup-node from 4 to 5 (#17123)
  website: bump the build group in /website with 6 updates (#17124)
  website: bump the eslint group in /website with 3 updates (#17125)
  web: bump @sentry/browser from 10.15.0 to 10.16.0 in /web in the sentry group across 1 directory (#17127)
  web: bump the eslint group across 2 directories with 3 updates (#17128)
  lifecycle/aws: bump cross-env from 10.0.0 to 10.1.0 in /lifecycle/aws (#17130)
  ...
2025-09-30 14:26:21 -07:00
Ken Sternberg
08218dcd1a Merge branch 'main' into dev
* main: (38 commits)
  web: Apply consistent background color when input is disabled or readonly. (#17105)
  website/docs: 2025.8.4 release notes (#17119)
  web: revert bump the swc group across 1 directory with 11 updates (#17113)
  ci: fix node version in docker image build (#17110)
  translate: Updates for file web/xliff/en.xlf in pt_BR (#17111)
  tasks: reduce default number of retries and max backoff (#17107)
  packages/django-dramatiq-postgres: broker: fix new messages not being picked up when too many messages are waiting (#17106)
  website/docs: additional documentation for ak_user_by (#17098)
  stages/identification: fix mismatched error messages (#17090)
  providers/oauth2: fix authentication error with identical app passwords (#17100)
  translate: Updates for file web/xliff/en.xlf in de (#17099)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in de (#17096)
  core: bump goauthentik.io/api/v3 from 3.2025100.11 to 3.2025100.14 (#17071)
  website: bump @types/react from 19.1.13 to 19.1.15 in /website (#17075)
  website/integrations: add cloudflare access redirect (#17094)
  cmd/server/healthcheck: info log success instead of debug (#17093)
  website/integrations: cloudflare (#17039)
  rbac: optimize rbac assigned by users query (#17015)
  web: Fix layout class for 'row' in LibraryPage (#16752)
  *: Auto compress images (#16733)
  ...
2025-09-29 15:33:06 -07:00
Ken Sternberg
2c1fd70808 Merge branch 'main' into dev
* main: (70 commits)
  core, web: update translations (#17036)
  web: bump API Client version (#17048)
  tests/e2e: less hardcoded names (#17047)
  core/api: Better naming for partial user/group serializer, optimise bindings (#17022)
  core: bump goauthentik.io/api/v3 from 3.2025100.10 to 3.2025100.11 (#17040)
  website: bump the build group in /website with 6 updates (#17042)
  web: bump the swc group across 1 directory with 11 updates (#17043)
  website/integrations: Move Cloudflare Access Documentation. (#17038)
  web: Fix skip-to-content element target, order. (#17030)
  web: Add disabled radio styles. (#17026)
  web: Report unregistered elements. (#17025)
  website/docs: Update Github expression to handle non-OAuth sources gracefully (#17014)
  tests/e2e: fix ldap tests following #17010 (#17021)
  web: bump @sentry/browser from 10.13.0 to 10.14.0 in /web in the sentry group across 1 directory (#16966)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in pt_BR (#17001)
  lib/config: fix listen settings (#17005)
  core: bump goauthentik.io/api/v3 from 3.2025100.8 to 3.2025100.10 (#17019)
  core: add index on Group.is_superuser (#17011)
  lib: match exception_to_dict locals behaviour (#17006)
  outposts/ldap: add pwdChangeTime attribute (#17010)
  ...
2025-09-26 08:24:17 -07:00
Ken Sternberg
5603fe193e Merge branch 'main' into dev
* main: (24 commits)
  root: add mypy (#16904)
  website: Remove duplicate sidebar entries. (#16922)
  web: Remove CSS constructor polyfill. (#16920)
  web: Replace Github Slugger package with change-case. (#16921)
  website: Fix broken schema links v2 (#16919)
  website: bump the build group in /website with 3 updates (#16908)
  core: bump astral-sh/uv from 0.8.18 to 0.8.19 (#16906)
  core: bump goauthentik.io/api/v3 from 3.2025100.6 to 3.2025100.8 (#16907)
  website: bump the eslint group in /website with 2 updates (#16909)
  web: bump the eslint group across 2 directories with 2 updates (#16911)
  web: bump the rollup group across 1 directory with 4 updates (#16912)
  web: bump typedoc-plugin-markdown from 4.8.1 to 4.9.0 in /packages/esbuild-plugin-live-reload (#16913)
  web: bump pino from 9.10.0 to 9.11.0 in /packages/esbuild-plugin-live-reload (#16914)
  web: bump pino from 9.10.0 to 9.11.0 in /web (#16915)
  website: add hierarchy line to sidebar (#16565)
  events: remove deprecated models (#15823)
  core: update_attributes: only update the model if attributes changed (#16322)
  Revert "website: Fix broken schema links, non-relative paths, unapplied redirect aliases" (#16902)
  website: Fix broken schema links, non-relative paths, unapplied redirect aliases (#16900)
  website/integrations: adds termix (#16889)
  ...
2025-09-22 11:15:33 -07:00
Ken Sternberg
6a882f22fa Merge branch 'main' into dev
* main:
  core, web: update translations (#16885)
  web: bump the storybook group across 1 directory with 5 updates (#16886)
  api: optimise schemas' common query parameters (#16884)
2025-09-19 08:19:10 -07:00
Ken Sternberg
442d42f850 Merge branch 'main' into dev
* main: (58 commits)
  web: bump the esbuild group across 2 directories with 4 updates (#16868)
  core, web: update translations (#16864)
  core: bump astral-sh/uv from 0.8.17 to 0.8.18 (#16866)
  website: bump @types/node from 24.5.1 to 24.5.2 in /website (#16867)
  web: bump @types/node from 24.5.1 to 24.5.2 in /packages/esbuild-plugin-live-reload (#16869)
  web: bump pino from 9.9.5 to 9.10.0 in /packages/esbuild-plugin-live-reload (#16870)
  web: bump @types/node from 24.5.1 to 24.5.2 in /packages/prettier-config (#16871)
  web: bump @types/node from 22.15.19 to 24.5.2 in /web (#16872)
  web: bump dompurify from 3.2.6 to 3.2.7 in /web (#16873)
  web: bump pino from 9.9.5 to 9.10.0 in /web (#16874)
  web: bump vite from 7.1.5 to 7.1.6 in /web (#16875)
  web: bump chromedriver from 140.0.2 to 140.0.3 in /web (#16876)
  lifecycle/aws: bump aws-cdk from 2.1029.1 to 2.1029.2 in /lifecycle/aws (#16877)
  web: Fix docs links, a11y input descriptors (#16671)
  website: bump the eslint group in /website with 3 updates (#16788)
  website: bump the build group in /website with 3 updates (#16787)
  web: bump the eslint group across 2 directories with 3 updates (#16790)
  website/docs: extends the example to include `jwt_config` for matrix/synapse (#16860)
  web/a11y: Flow Search (#15876)
  web: bump API Client version, remove Webdriver dependencies (#16836)
  ...
2025-09-18 16:39:55 -07:00
Ken Sternberg
d0daec4aa1 Merge branch 'main' into dev
* main: (81 commits)
  translate: Updates for file web/xliff/en.xlf in de (#16808)
  stages: update friendly_name model from null to blank (#16672)
  sources/saml: add default error messages to exceptions (#15562)
  website/docs: 2025.8.3 release notes (#16809)
  core, web: update translations (#16783)
  stages/email_authenticator: Fix email mfa loop (#16579)
  website/docs: updated Frontend development environment contributor docs (#16731)
  webiste/integrations: update roundcube doc (#16753)
  website/docs: update create oauth provider page (#16617)
  website: bump @types/node from 24.4.0 to 24.5.0 in /website (#16789)
  web: bump the rollup group across 1 directory with 4 updates (#16792)
  core: bump github.com/getsentry/sentry-go from 0.35.2 to 0.35.3 (#16786)
  web: bump the storybook group across 1 directory with 5 updates (#16791)
  web: bump @types/node from 24.4.0 to 24.5.0 in /packages/esbuild-plugin-live-reload (#16794)
  web: bump @goauthentik/prettier-config from 1.0.5 to 3.1.0 in /web in the goauthentik group across 1 directory (#16793)
  web: bump @types/node from 24.4.0 to 24.5.0 in /packages/prettier-config (#16795)
  web: bump @types/node from 22.15.19 to 24.5.0 in /web (#16796)
  web: Use curated dictionary for e2e fixtures. (#16750)
  website/integrations: fix wekan redirect URL (#16801)
  website/docs: fix docker tabs not rendering properly (#16799)
  ...
2025-09-16 12:10:58 -07:00
Ken Sternberg
951da48f81 Merge branch 'main' into dev
* main: (121 commits)
  website: bump the eslint group in /website with 3 updates (#16674)
  web: bump the eslint group across 2 directories with 3 updates (#16675)
  web: bump vite from 7.1.4 to 7.1.5 in /web (#16676)
  website/docs: fix typo (#16681)
  core: Include region comments in VSCode Minimap. (#16667)
  tasks: fix status and healthcheck breaking with connection issues (#16504)
  website/docs: add period on very last sentence. (#16669)
  core: bump golang.org/x/sync from 0.16.0 to 0.17.0 (#16657)
  web: bump the eslint group across 3 directories with 2 updates (#16661)
  web: bump the storybook group across 1 directory with 5 updates (#16662)
  core: bump golang.org/x/oauth2 from 0.30.0 to 0.31.0 (#16658)
  core: bump github.com/prometheus/client_golang from 1.23.1 to 1.23.2 (#16659)
  website: bump the eslint group in /website with 2 updates (#16660)
  web: bump the rollup group across 1 directory with 4 updates (#16663)
  web: bump pino from 9.9.2 to 9.9.4 in /web (#16664)
  lifecycle/aws: bump aws-cdk from 2.1028.0 to 2.1029.0 in /lifecycle/aws (#16665)
  core: bump selenium/standalone-chrome from 139.0 to 140.0 in /tests/e2e (#16666)
  website/integrations: fix missing space after comma (#16650)
  website/integrations: add missing comma paperless-ngx (#16651)
  root: bump to debian trixie (#16626)
  ...
2025-09-09 08:12:24 -07:00
Ken Sternberg
7f353ac1b8 Merge branch 'main' into dev
* main: (71 commits)
  website: Redirect Azure to Entra. Add tags for search indexing. (#16474)
  website: Page redirect guide, documentation (#16466)
  root: bump openapi-generator-cli to v7.15.0 (#16440)
  ci: bump actions/attest-build-provenance from 2 to 3 (#16462)
  core: bump astral-sh/uv from 0.8.13 to 0.8.14 (#16461)
  ci: remove Python client API publication (#16468)
  website: Unify Netlify redirects with Docusaurus's client-side router. (#16430)
  core: fix client-side only validation allowing admin to set blank user password (#16467)
  website/integrations: Update Issuer URL for Immich (#16460)
  providers/oauth2: include scope in JWT (#16454)
  lib/sync/outgoing: fix single object sync timeout (#16447)
  website/docs: capitalized proper name of stages, removed old version references. (#16414)
  web: bump pino-pretty from 13.0.0 to 13.1.1 in /web (#16411)
  core: bump h2 from 4.2.0 to 4.3.0 (#16446)
  web: bump @playwright/test from 1.54.1 to 1.55.0 in /web (#16413)
  web: bump the react group across 2 directories with 1 update (#16448)
  web: bump bootstrap from 5.3.7 to 5.3.8 in /web (#16416)
  web: bump @sentry/browser from 10.6.0 to 10.7.0 in /web in the sentry group across 1 directory (#16433)
  root: check for brew install of libxml2 before updating path (#16422)
  core: bump github.com/stretchr/testify from 1.11.0 to 1.11.1 (#16434)
  ...
2025-08-29 08:38:11 -07:00
Ken Sternberg
7080053510 Merge branch 'main' into dev
* main:
  web: Automatic reload during server start up. (#16030)
  website/docs: Add steps for fixing xml python errors, clean up (#16223)
2025-08-26 08:21:54 -07:00
Ken Sternberg
f55207b6ef Merge branch 'main' into dev
* main:
  providers/oauth2: avoid deadlock during session migration (#16361)
  lifecycle/aws: bump aws-cdk from 2.1025.0 to 2.1026.0 in /lifecycle/aws (#16352)
  core: bump github.com/stretchr/testify from 1.10.0 to 1.11.0 (#16357)
  core: bump axllent/mailpit from v1.27.5 to v1.27.6 in /tests/e2e (#16358)
  website/docs: fix missing trailing slash in vaultwarden documentation (#16348)
  root: fix security.md (#16345)
  root: update security.md with github reporting link (#16332)
  website/docs: 2025.8.1 release notes (#16343)
  packages/django-dramatiq-postgres: broker: fix various timing issues (#16340)
  website/docs: adds details to certificates doc (#16335)
  outposts: allow ingress path type configuration (#16339)
  core, web: update translations (#16321)
  outposts: fix service connection update task arguments (#16312)
  core: use email backend for test_email management command (#16311)
  core: bump astral-sh/uv from 0.8.12 to 0.8.13 (#16325)
  website: Move docs netlify.toml (#16320)
  website/docs: add link in 2025.8 rel notes to back-channel logout docs (#16306)
  packages/django-dramatiq-postgres: middleware: fix listening on hosts where ipv6 is not supported (#16308)
  website: Fix version origin detection, build-time URLs  (#15774)
  web/a11y: Associating labels with inputs (#16119)
2025-08-25 14:09:52 -07:00
Ken Sternberg
7347577436 Merge branch 'main' into dev
* main: (210 commits)
  web: Username truncation, field alignment. (#16283)
  website/docs: adds a webhook header mapping example (#16301)
  web: Fix issue where form group uses unknown slot. (#16276)
  lifecycle: set PROMETHEUS_MULTIPROC_DIR as early as possible (#16298)
  providers/oauth2: fix logout token missing sid, fix wrong sub mode used (#16295)
  web: bump core-js from 3.45.0 to 3.45.1 in /web (#16290)
  root: Remove CODEOWNERS entries from docs/ directory (#16287)
  *: Fix dead doc link (#16288)
  web: saml provider view: fix state refresh issues (#14474)
  web: fix "Explore integrations" link in Quick actions (#16274)
  website/integrations: fix dead links to external docs (#16273)
  tasks: add rel_obj to system task exception event (#16270)
  website/docs: update 2025.8 release notes (#16269)
  web: bump @patternfly/elements from 4.1.0 to 4.2.0 in /web (#16265)
  web: bump mermaid from 11.9.0 to 11.10.0 in /web (#16263)
  web: bump @types/guacamole-common-js from 1.5.3 to 1.5.4 in /web (#16262)
  security: Bump supported versions (#16261)
  core: bump channels from 4.3.0 to v4.3.1 (#16260)
  translate: Updates for file web/xliff/en.xlf in cs_CZ (#16264)
  website: bump the eslint group in /website with 3 updates (#16248)
  ...
2025-08-21 09:50:14 -07:00
Ken Sternberg
4963dde699 Merge branch 'main' into dev
* main: (32 commits)
  core: bump goauthentik.io/api/v3 from 3.2025064.6 to 3.2025064.7 (#16024)
  core, web: update translations (#16021)
  ci: move images from beryju/* to authentik/* (#15321)
  core, web: update translations (#15985)
  core: bump cattrs from 24.1.3 to v25.1.1 (#15981)
  web: bump API Client version (#16002)
  ci: bump actions/download-artifact from 4 to 5 (#15995)
  core: bump certifi from 2025.7.14 to v2025.8.3 (#15982)
  core: bump anyio from 4.9.0 to v4.10.0 (#15979)
  core: bump boto3 from 1.40.1 to v1.40.2 (#15980)
  core: bump astral-sh/uv from 0.8.4 to 0.8.5 (#15998)
  core: bump goauthentik.io/api/v3 from 3.2025064.5 to 3.2025064.6 (#15997)
  stages/email: implement rate limiting for account verification (#15531)
  web: Fix stale application slug, missing error state. (#15941)
  website/docs: change azure ad to entra id (#15691)
  website/docs: add tips for image optimization (#15978)
  web: bump API Client version (#15976)
  providers/oauth2: backchannel logout (#15401)
  web: bump API Client version (#15953)
  translate: Updates for file web/xliff/en.xlf in fr (#15974)
  ...
2025-08-07 08:31:56 -07:00
Ken Sternberg
b60bfadaaf Merge branch 'main' into dev
* main: (77 commits)
  website/integrations: add hass-openid instructions (#14672)
  core: add updated_at field to user (#15571)
  root: Add more opencontainer labels to Dockerfiles (#15923)
  core: bump goauthentik.io/api/v3 from 3.2025064.2 to 3.2025064.3 (#15949)
  core, providers/ldap: add parent/child groups to api and ldap results (#14974)
  web: Make Webdriver optional during install. (#15952)
  core, web: update translations (#15945)
  packages/django-dramatiq-postgres: fix typo (#15932)
  web: bump API Client version (#15942)
  core: fix flow planner checking against wrong user when creating recovery link (#15390)
  providers/saml: configuration for default NameID Policy (#15109)
  core: bump boto3 from 1.39.15 to v1.40.1 (#15926)
  core: bump jsii from 1.112.0 to v1.113.0 (#15927)
  core: bump argon2-cffi-bindings from 21.2.0 to v25.1.0 (#15925)
  core: bump aiohttp from 3.12.14 to v3.12.15 (#15924)
  core: bump opentelemetry-api from 1.35.0 to v1.36.0 (#15928)
  web/admin: fix variable name (#15934)
  policies: fix typo (#15933)
  web: bump @sentry/browser from 9.43.0 to 10.0.0 in /web in the sentry group across 1 directory (#15911)
  core: bump github.com/prometheus/client_golang from 1.22.0 to 1.23.0 (#15908)
  ...
2025-08-04 10:42:32 -07:00
Ken Sternberg
0fc0783e7e Merge branch 'main' into dev
* main: (91 commits)
  *: replace Celery with Dramatiq (#13492)
  website/docs: stages/mtls: Clean up stage configuration section (#15753)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in es (#15818)
  website: bump the eslint group in /website with 2 updates (#15805)
  web: bump typedoc from 0.28.7 to 0.28.8 in /packages/esbuild-plugin-live-reload (#15809)
  core: bump axllent/mailpit from v1.27.1 to v1.27.2 in /tests/e2e (#15813)
  web: bump the rollup group across 1 directory with 4 updates (#15806)
  web: bump the eslint group across 3 directories with 2 updates (#15808)
  lifecycle/aws: bump cross-env from 7.0.3 to 10.0.0 in /lifecycle/aws (#15807)
  web: bump ts-pattern from 5.7.1 to 5.8.0 in /web (#15810)
  web: bump @sentry/browser from 9.41.0 to 9.42.0 in /web in the sentry group across 1 directory (#15811)
  web: Add support for placeholder in <ak-text-input> (#15795)
  providers/rac: fix incorrect caching (#15779)
  root: support for custom postgresql connection options (#15577)
  website: bump the build group in /website with 3 updates (#15784)
  web: bump @sentry/browser from 9.40.0 to 9.41.0 in /web in the sentry group across 1 directory (#15785)
  core: bump astral-sh/uv from 0.8.2 to 0.8.3 (#15786)
  lifecycle/aws: bump aws-cdk from 2.1021.0 to 2.1022.0 in /lifecycle/aws (#15787)
  core: bump twilio from 9.6.5 to 9.7.0 (#15788)
  revert: web: Font fixes (#15581) (#15789)
  ...
2025-07-28 08:06:15 -07:00
Ken Sternberg
aa73014f6a Merge branch 'main' into dev
* main: (131 commits)
  website/docs: add notification rule expression policy examples (#15333)
  website/docs: add force password reset guide (#15654)
  website: bump prettier-plugin-packagejson from 2.5.18 to 2.5.19 in /website (#15672)
  website: Flesh out Makefile commands, usage. (#15576)
  website/integrations: fix duplicate guacamole section (#15684)
  core: bump goauthentik.io/api/v3 from 3.2025063.5 to 3.2025063.6 (#15671)
  web: bump typedoc-plugin-markdown from 4.7.0 to 4.7.1 in /packages/esbuild-plugin-live-reload (#15681)
  web: bump the esbuild group across 2 directories with 4 updates (#15674)
  web: bump @types/node from 24.0.14 to 24.0.15 in /packages/prettier-config (#15676)
  website: bump @types/node from 24.0.14 to 24.0.15 in /website (#15675)
  web: bump @types/node from 24.0.14 to 24.0.15 in /packages/esbuild-plugin-live-reload (#15677)
  web: bump prettier-plugin-packagejson from 2.5.18 to 2.5.19 in /packages/prettier-config (#15678)
  web: bump chart.js and @types/chart.js in /web (#15679)
  web: bump the swc group across 1 directory with 11 updates (#15680)
  web: bump prettier-plugin-packagejson from 2.5.18 to 2.5.19 in /packages/esbuild-plugin-live-reload (#15682)
  web: bump @types/node from 22.15.19 to 24.0.15 in /web (#15683)
  website/dev docs: FDE e2e: fix useless markdown lini (#15658)
  providers/radius: set message authenticator (#15635)
  web: bump @eslint/plugin-kit from 0.3.1 to 0.3.3 in /packages/eslint-config (#15661)
  website/docs: add e2e testing steps (#15656)
  ...
2025-07-21 09:29:57 -07:00
Ken Sternberg
a95d3abe83 Merge branch 'main' into dev
* main: (280 commits)
  providers/proxy: fix ingress-nginx proxy buffer size annotations (#15506)
  website/docs: troubleshooting: Fix variable for postgres database in k8s (#15503)
  web: bump @sentry/browser from 9.35.0 to 9.36.0 in /web in the sentry group across 1 directory (#15492)
  core: bump golang.org/x/sync from 0.15.0 to 0.16.0 (#15493)
  core: bump maxmind/geoipupdate from v7.1.0 to v7.1.1 (#15495)
  core: bump astral-sh/uv from 0.7.19 to 0.7.20 (#15496)
  Docusaurus 3.8 prep integrations (#15483)
  web: Fix dangling div. (#15478)
  core: bump google-api-python-client from 2.175.0 to 2.176.0 (#15471)
  core, web: update translations (#15468)
  website: bump the build group in /website with 3 updates (#15469)
  website: bump @types/node from 24.0.10 to 24.0.12 in /website (#15470)
  core: bump msgraph-sdk from 1.36.0 to 1.37.0 (#15472)
  web/flows: more padding fixes (#15467)
  events: fix ak_client_ip not set in notification rule policy context (#15464)
  website/docs: edits to latest Events docs (#15457)
  website: bump the eslint group in /website with 3 updates (#15452)
  website/docs: fix small typos (#15403)
  root: monitoring: force db connection reload before healthcheck (#9970)
  core: bump microsoft-kiota-serialization-form from 1.9.3 to v1.9.4 (#15441)
  ...
2025-07-10 10:59:25 -07:00
Ken Sternberg
6948146faa Merge branch 'main' into dev
* main: (39 commits)
  website/docs: Add steps to troubleshoot /initial-setup/ (#15011)
  core, web: update translations (#15084)
  website: bump the eslint group in /website with 3 updates (#15085)
  website: bump @types/node from 24.0.1 to 24.0.3 in /website (#15086)
  website: bump postcss from 8.5.5 to 8.5.6 in /website (#15087)
  core: bump webauthn from 2.5.2 to 2.6.0 (#15089)
  core: bump goauthentik.io/api/v3 from 3.2025061.2 to 3.2025062.1 (#15090)
  web: bump the eslint group across 2 directories with 3 updates (#15091)
  translate: Updates for file web/xliff/en.xlf in zh_CN (#15074)
  translate: Updates for file web/xliff/en.xlf in zh-Hans (#15075)
  ci: fix post-release e2e builds failing (#15082)
  web: bump API Client version (#15079)
  web/common: fix uiConfig not merged correctly (#15080)
  root: backport version bump `2025.6.2` (#15078)
  website/integrations: add note to nextcloud OIDC config (#15073)
  web/admin: remove all special cases of slug handling, replace with a "smart slug" component (#14983)
  Web/cleanup/empty state better slot handling (#14289)
  website/docs: release notes for `2025.6.2` (#15065)
  website/docs: remove commented out config options (#15064)
  website/docs: postgres troubleshooting: get PGPASSWORD from POSTGRES_PASSWORD_FILE (#15039)
  ...
2025-06-17 08:00:48 -07:00
Ken Sternberg
0ea5f10e5a Merge branch 'main' into dev
* main:
  website/docs: also hide the postgres pool_options setting (#15023)
  blueprints: sort schema items (#15022)
  website: bump the build group in /website with 6 updates (#15027)
  core: bump astral-sh/uv from 0.7.12 to 0.7.13 (#15028)
  core: bump twilio from 9.6.2 to 9.6.3 (#15029)
  core: bump sentry-sdk from 2.29.1 to 2.30.0 (#15030)
  core: bump kubernetes from 32.0.1 to 33.1.0 (#15031)
  core, web: update translations (#15026)
  web: bump the sentry group across 1 directory with 2 updates (#15025)
  translate: Updates for file web/xliff/en.xlf in zh_CN (#15018)
  lifecycle/aws: bump aws-cdk from 2.1018.0 to 2.1018.1 in /lifecycle/aws (#15016)
  website: bump postcss from 8.5.4 to 8.5.5 in /website (#15013)
  website: bump @types/node from 24.0.0 to 24.0.1 in /website (#15014)
  core: fix transaction test case (#15021)
  translate: Updates for file web/xliff/en.xlf in zh-Hans (#15019)
  website/docs: correct minor version in release notes (#15012)
  root: test label handling and error reporting in PytestTestRunner (#14000)
  outposts/ldap: Handle comma-separated attributes in LDAP search requests (#15000)
  website/integrations: standardize application slug placeholder in docs (#15007)
  core: bump django from 5.1.10 to 5.1.11 (#14997)
2025-06-13 08:33:02 -07:00
Ken Sternberg
d78e459dcb Merge branch 'main' into dev
* main: (30 commits)
  web/elements: Add light mode custom css handling (#14944)
  website/docs: add host header dynamic property mapping (#15006)
  core, web: update translations (#14999)
  website/docs: fixes misplaced sentence (#14998)
  website/docs: note usage of `is_restored` by source stage (#13422)
  website: bump the build group in /website with 6 updates (#15001)
  web: bump @sentry/browser from 9.27.0 to 9.28.0 in /web in the sentry group across 1 directory (#15002)
  core: bump msgraph-sdk from 1.32.0 to 1.33.0 (#15003)
  core: bump google-api-python-client from 2.171.0 to 2.172.0 (#15004)
  web/admin: fix language in certificate import  (#14953)
  website/integrations: add new categories and update sidebar info (#14995)
  brands: fix custom_css being escaped (#14994)
  web/admin: show selected policy engine mode on bindings pages, allow setting it on sources (#12963)
  website/integrations: add bitwarden (#14922)
  core: bump goauthentik.io/api/v3 from 3.2025061.1 to 3.2025061.2 (#14986)
  website: bump @types/node from 22.15.30 to 24.0.0 in /website (#14988)
  website: bump the eslint group in /website with 3 updates (#14987)
  web: bump the eslint group across 2 directories with 3 updates (#14991)
  website/integrations: fix typos, update language and styling (#14978)
  website/integrations: add 1password (#14815)
  ...
2025-06-11 08:14:02 -07:00
Ken Sternberg
f4393b7b3c Merge branch 'main' into dev
* main: (38 commits)
  website/docs: added a link in our Upgrade docs to the Outpost upgrade docs, slight reformatting  (#14931)
  website: fix search across multiple subdomains (#14976)
  core: bump goauthentik.io/api/v3 from 3.2025060.1 to 3.2025061.1 (#14972)
  web: bump API Client version (#14971)
  root: backport 2025.6.1 bump (#14970)
  stages/email: Only attach logo to email if used (#14835)
  web: bump @codemirror/lang-python from 6.1.6 to 6.2.1 in /web (#14713)
  website: bump prettier-plugin-packagejson from 2.5.14 to 2.5.15 in /website (#14829)
  core: bump selenium/standalone-chrome from 136.0 to 137.0 in /tests/e2e (#14963)
  core: bump axllent/mailpit from v1.25.1 to v1.26.0 in /tests/e2e (#14964)
  core: bump astral-sh/uv from 0.7.11 to 0.7.12 (#14965)
  core: bump github.com/redis/go-redis/v9 from 9.9.0 to 9.10.0 (#14966)
  web: bump @types/mocha from 10.0.8 to 10.0.10 in /web (#14684)
  web: bump ts-pattern from 5.4.0 to 5.7.1 in /web (#14686)
  website: bump @types/node from 22.15.29 to 22.15.30 in /website (#14968)
  web: bump mermaid from 11.4.1 to 11.6.0 in /web (#14688)
  web: bump @fortawesome/fontawesome-free from 6.6.0 to 6.7.2 in /web (#14716)
  web: bump the eslint group across 2 directories with 3 updates (#14833)
  website: bump the eslint group in /website with 4 updates (#14967)
  website: bump @typescript-eslint/parser from 8.32.1 to 8.33.1 in /website (#14828)
  ...
2025-06-09 08:51:20 -07:00
Ken Sternberg
0457b59792 Merge branch 'main' into dev
* main: (54 commits)
  web/user: fix user settings flow not loading (#14911)
  website/docs: fix outdated and incorrect example kubernetes deployment (#14928)
  docusaurus-config: Update deps, colors. (#14796)
  admin: only run update checks in the default tenant (#14874)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in fr (#14923)
  core: bump astral-sh/uv from 0.7.10 to 0.7.11 (#14918)
  providers/proxy: set_oauth_defaults in reconcile instead of task (#14875)
  *: use ManagedAppConfig everywhere (#14839)
  tenants: fix tenant aware celery scheduler (#14921)
  core, web: update translations (#14910)
  core: bump goauthentik.io/api/v3 from 3.2025041.4 to 3.2025060.1 (#14919)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in zh_CN (#14915)
  translate: Updates for file web/xliff/en.xlf in zh_CN (#14916)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in zh-Hans (#14914)
  website/integrations: improve komodo config verification (#14849)
  website/integrations: fix komodo provider url (#14912)
  website/docs: fix note at end of rac credentials prompt (#14909)
  website/docs: add credentials prompt for rac doc (#14840)
  core: bump redis from 6.0.0 to v6.2.0 (#14895)
  core: bump protobuf from 6.30.2 to v6.31.1 (#14894)
  ...
2025-06-05 15:20:24 -07:00
Ken Sternberg
79d5bc02e9 Merge branch 'main' into dev
* main: (97 commits)
  website/docs: update style guide (#14373)
  website/docs: finalize release notes for `2025.6` (#14854)
  providers/rac: apply ConnectionToken scoped-settings last (#14838)
  lib/sync: fix static incorrect label of pages (#14851)
  website/docs: Add FIDO2 references to the documentation (#14826)
  website/docs: add LDAP docs for forward deletion and `memberUid` (#14814)
  stages/authenticator_webauthn: Update FIDO MDS3 & Passkey aaguid blobs (#14801)
  core: bump structlog from 25.3.0 to 25.4.0 (#14834)
  web: bump tar-fs from 3.0.8 to 3.0.9 in /web (#14836)
  website/integrations: Update Zammad SAML Instructions (#14774)
  website/integrations: remove trailing slash from budibase redirect (#14823)
  remove fluff from release notes 2025.6 (#14819)
  web: bump @sentry/browser from 9.22.0 to 9.23.0 in /web in the sentry group across 1 directory (#14776)
  website: bump postcss from 8.5.3 to 8.5.4 in /website (#14787)
  web: bump the esbuild group across 2 directories with 4 updates (#14711)
  core: bump github.com/redis/go-redis/v9 from 9.8.0 to 9.9.0 (#14733)
  core: bump twilio from 9.6.1 to 9.6.2 (#14789)
  website: bump @types/node from 22.15.21 to 22.15.29 in /website (#14808)
  core: bump astral-sh/uv from 0.7.8 to 0.7.9 (#14806)
  core: bump uvicorn[standard] from 0.34.2 to 0.34.3 (#14811)
  ...
2025-06-03 13:46:57 -07:00
Ken Sternberg
f0e742c3ae Merge branch 'main' into dev
* main: (27 commits)
  lib/sync/outgoing: sync in parallel (#14697)
  core, web: update translations (#14707)
  tests/e2e: fix flaky SAML Source test (#14708)
  web: fix lock (#14705)
  Update packages-npm-publish.yml (#14702)
  website/integrations: coder: fix typo (#14514)
  ci: Update packages-npm-publish.yml (#14701)
  web: bump the swc group across 2 directories with 12 updates (#14623)
  web: Use engine available on Github Actions. (#14699)
  web: bump the rollup group across 1 directory with 4 updates (#14682)
  ci: test with postgres 17 (#13967)
  web: bump knip from 5.33.0 to 5.58.0 in /web (#14685)
  web: bump fuse.js from 7.0.0 to 7.1.0 in /web (#14687)
  web: bump @formatjs/intl-listformat from 7.5.7 to 7.7.11 in /web (#14689)
  root: do not use /bin/bash directly (#14698)
  website/integrations: minio: notice about sso deprecation on CE (#14679)
  core: bump cryptography from 44.0.3 to 45.0.3 (#14690)
  core: bump django-tenants from 3.7.0 to 3.8.0 (#14691)
  core: bump astral-sh/uv from 0.7.7 to 0.7.8 (#14681)
  core: bump axllent/mailpit from v1.25.0 to v1.25.1 in /tests/e2e (#14693)
  ...
2025-05-27 08:33:10 -07:00
Ken Sternberg
8a389b4b46 Merge branch 'main' into dev
* main: (24 commits)
  web: Type Tidy (#14647)
  core: bump pydantic from 2.11.4 to 2.11.5 (#14652)
  core: bump google-api-python-client from 2.169.0 to 2.170.0 (#14653)
  sources/scim: fix all users being added to group when no members are given (#14645)
  web: bump @codemirror/lang-javascript from 6.2.2 to 6.2.4 in /web (#14657)
  web: bump @types/node from 22.15.19 to 22.15.21 in /web (#14660)
  core: bump astral-sh/uv from 0.7.6 to 0.7.7 (#14651)
  web: bump wireit from 0.14.9 to 0.14.12 in /web (#14656)
  web: bump country-flag-icons from 1.5.13 to 1.5.19 in /web (#14659)
  web: bump @trivago/prettier-plugin-sort-imports from 4.3.0 to 5.2.2 in /web (#14661)
  web: bump chart.js from 4.4.4 to 4.4.9 in /web (#14655)
  website: bump the goauthentik group in /website with 3 updates (#14654)
  web: bump dompurify from 3.2.4 to 3.2.6 in /web (#14658)
  web: fix lint (#14665)
  website/docs: improve-rac-documents (#14414)
  web: bump the rollup group across 2 directories with 3 updates (#14622)
  web: bump the sentry group across 1 directory with 2 updates (#14587)
  lifecycle/aws: bump aws-cdk from 2.1016.0 to 2.1016.1 in /lifecycle/aws (#14631)
  web: bump @patternfly/elements from 4.0.2 to 4.1.0 in /web (#14634)
  web: bump @lit/task from 1.0.1 to 1.0.2 in /web (#14635)
  ...
2025-05-23 14:46:54 -07:00
Ken Sternberg
e3402682e6 Merge branch 'main' into dev
* main: (55 commits)
  web: Fix missing Enterprise sidebar entries. (#14615)
  core, web: update translations (#14626)
  esbuild-plugin-live-reload: Publish. (#14624)
  web/NPM Workspaces: Prep ESBuild plugin for publish. (#14552)
  lifecycle: fix arguments not being passed to worker command (#14574)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in fr (#14611)
  providers/proxy: kubernetes outpost: fix reconcile when ingress class name changed (#14612)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in zh-Hans (#14608)
  translate: Updates for file web/xliff/en.xlf in zh_CN (#14607)
  translate: Updates for file web/xliff/en.xlf in zh-Hans (#14609)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in zh_CN (#14606)
  root: move forked dependencies to goauthentik org (#14590)
  core: bump library/node from 22 to 24 (#14410)
  core: bump django-guardian from 2.4.0 to v3.0.0 (#14453)
  enterprise/stages/mtls: improve certificate validation (#14582)
  translate: Updates for file web/xliff/en.xlf in it (#14575)
  core, web: update translations (#14578)
  core: bump sentry-sdk from 2.28.0 to 2.29.1 (#14579)
  core: bump astral-sh/uv from 0.7.5 to 0.7.6 (#14580)
  web/NPM Workspaces: ESbuild version cleanup (#14541)
  ...
2025-05-22 08:15:00 -07:00
Ken Sternberg
38c4701e63 Merge branch 'main' into dev
* main: (60 commits)
  website: bump the build group in /website with 6 updates (#14502)
  core: remove `OldAuthenticatedSession` content type (#14507)
  core: bump msgraph-sdk from 1.29.0 to 1.30.0 (#14503)
  core: bump twilio from 9.6.0 to 9.6.1 (#14505)
  core: bump psycopg[c,pool] from 3.2.8 to 3.2.9 (#14504)
  enterprise: fix expired license's users being counted (#14451)
  website/integrations: fix missing closing brace for semaphore (#14467)
  tests/e2e: Add E2E tests for Flow SFE (#14484)
  website: bump semver from 7.7.1 to 7.7.2 in /website (#14491)
  core: bump django from 5.1.8 to 5.1.9 (#14483)
  core: bump psycopg[c,pool] from 3.2.7 to 3.2.8 (#14481)
  core: bump sentry-sdk from 2.27.0 to 2.28.0 (#14482)
  root: pin package version in pyproject for dependabot (#14469)
  core: fix session migration when old session can't be loaded (#14466)
  root: temporarily deactivate database pool option (#14443)
  website: bump the build group in /website with 3 updates (#14475)
  website/docs: stages: fix-typo (#14477)
  website/docs: Update Kubernetes Bootstrap Instructions (#14471)
  root: improve sentry distributed tracing (#14468)
  Revert "web/admin: fix enterprise menu display" (#14458)
  ...
2025-05-14 08:17:09 -07:00
Ken Sternberg
cddc13fcf7 Merge branch 'main' into dev
* main: (45 commits)
  web, website: update browserslist (#14386)
  core, web: update translations (#14383)
  website/integrations: add atlassian (#14209)
  core: bump github.com/pires/go-proxyproto from 0.8.0 to 0.8.1 (#14388)
  ci: bump golangci/golangci-lint-action from 7 to 8 (#14389)
  core: bump axllent/mailpit from v1.24.1 to v1.24.2 in /tests/e2e (#14390)
  translate: Updates for file web/xliff/en.xlf in it (#14372)
  translate: Updates for file web/xliff/en.xlf in zh_CN (#14374)
  translate: Updates for file web/xliff/en.xlf in zh-Hans (#14375)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in pt (#14379)
  website/integrations: Fix outpost link for Home Assistant configuration (#14382)
  website/docs: fix leftover placeholder in release notes (#14377)
  website/integrations: minio: fix typo (#14376)
  core: bump goauthentik/fips-python from 3.12.10-slim-bookworm-fips to 3.13.3-slim-bookworm-fips (#12763)
  core: bump axllent/mailpit from v1.6.5 to v1.24.1 in /tests/e2e (#14341)
  core: bump selenium/standalone-chrome from 122.0 to 135.0 in /tests/e2e (#14342)
  core: bump lxml from 5.3.2 to v5.4.0 (#14355)
  core: bump azure-core from 1.33.0 to v1.34.0 (#14345)
  core: bump boto3 from 1.37.35 to v1.38.7 (#14346)
  core: bump celery from 5.5.1 to v5.5.2 (#14347)
  ...
2025-05-05 08:42:37 -07:00
Ken Sternberg
136e59cfba Merge branch 'main' into dev
* main: (54 commits)
  ci: use dependabot for compose correctly? (#14340)
  website/docs: use Universal Device Trust for GDTC instead of Okta (#14335)
  ci: use dependabot for docker-compose files (#14336)
  website/docs: fix dry-run release highlight (#14337)
  rbac: fix RoleObjectPermissionTable not showing `add_user_to_group` (#14312)
  core, web: update translations (#14326)
  core: bump github.com/sethvargo/go-envconfig from 1.2.0 to 1.3.0 (#14327)
  web: bump vite from 5.4.16 to 5.4.19 in /web (#14324)
  core: bump setuptools from 78.1.0 to v79.0.0 (#14173)
  core: bump ruff from 0.11.5 to v0.11.6 (#14171)
  core: bump s3transfer from 0.11.4 to v0.11.5 (#14172)
  core: bump packaging from 24.2 to v25.0 (#14169)
  core: bump aiohttp from 3.11.16 to v3.11.18 (#14166)
  core: bump boto3 from 1.37.35 to v1.37.38 (#14167)
  core: bump frozenlist from 1.5.0 to v1.6.0 (#14168)
  core: bump pdoc from 15.0.1 to v15.0.3 (#14170)
  core: bump trio from 0.29.0 to v0.30.0 (#14174)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in it (#14271)
  website: bump the build group across 1 directory with 9 updates (#14293)
  core, web: update translations (#14309)
  ...
2025-05-02 10:42:07 -07:00
Ken Sternberg
5da349342f Merge branch 'main' into dev
* main: (33 commits)
  website/integrations: adds missing trailing slash in homarr doc (#14249)
  lifecycle: fix test-all in docker (#14244)
  core, web: update translations (#14243)
  web/admin: prevent default logo flashing in admin interface (#13960)
  website/docs: Update release notes for 2025.4 (#14158)
  core, web: update translations (#14241)
  Updates for file web/xliff/en.xlf in zh_TW [Manual Sync] (#14225)
  translate: Updates for file web/xliff/en.xlf in nl [Manual Sync] (#14217)
  translate: Updates for file web/xliff/en.xlf in fi [Manual Sync] (#14219)
  translate: Updates for file web/xliff/en.xlf in de [Manual Sync] (#14220)
  translate: Updates for file web/xliff/en.xlf in fr [Manual Sync] (#14221)
  translate: Updates for file web/xliff/en.xlf in pl [Manual Sync] (#14222)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in es [Manual Sync] (#14223)
  translate: Updates for file web/xliff/en.xlf in zh-Hans [Manual Sync] (#14224)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in de [Manual Sync] (#14226)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in fi [Manual Sync] (#14227)
  translate: Updates for file web/xliff/en.xlf in tr [Manual Sync] (#14228)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in pl [Manual Sync] (#14229)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in ko [Manual Sync] (#14230)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in it [Manual Sync] (#14231)
  ...
2025-04-25 10:46:52 -07:00
Ken Sternberg
518e9e1554 Merge branch 'main' into dev
* main:
  web: Safari fixes merge branch (#14181)
  website: bump the build group in /website with 9 updates (#14204)
  website: bump typescript from 5.8.2 to 5.8.3 in /website (#13786)
  lifecycle/migrate: fix migration failing if killed during first startup (#14207)
  core, web: update translations (#14203)
  lifecycle/aws: bump aws-cdk from 2.1010.0 to 2.1012.0 in /lifecycle/aws (#14205)
  website/integrations: improves netbird documentation (#14191)
  website/docs: updated user count info (#14186)
  website/docs: rearranged brands docs (#14116)
  website: integrations: apache guacamole: remove redirect URI comments (#14113)
2025-04-24 10:01:18 -07:00
Ken Sternberg
baa64bc1b0 Merge branch 'main' into dev
* main:
  packages/docusaurus-theme: Fix header alignment, overscroll, vertical padding. (#14120)
  outposts: add support for gateway API (#13272)
  translate: Updates for file web/xliff/en.xlf in fr (#14200)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in fr (#14199)
  website/docs: adds code examples for getting user objects from a group object (#14101)
  translate: Updates for file web/xliff/en.xlf in zh-Hans (#14198)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in zh_CN (#14195)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in zh-Hans (#14197)
  translate: Updates for file web/xliff/en.xlf in zh_CN (#14196)
  website/integrations: mealie add integration (#14188)
  core, web: update translations (#14187)
  core: bump goauthentik.io/api/v3 from 3.2025024.8 to 3.2025024.9 (#14189)
  website/docs: update user object doc (#14132)
  website/docs: dev-docs: style guide: no longer using italic for vars (#14185)
  website/docs: dev docs: style guide: update style conventions for urls (#14184)
  website/integrations: paperless: use <slug>. instead of hardcoded slug value (#14183)
  website/docs: updates style guide code block section (#14088)
  website: components: delete multilinecodeblock src (#14094)
  Revert "policies: buffered policy access view for concurrent authorization attempts when unauthenticated (#13629)" (#14180)
2025-04-23 10:59:38 -07:00
Ken Sternberg
8b958408c2 Merge branch 'main' into dev
* main: (49 commits)
  core: bump uvicorn from 0.34.1 to v0.34.2 (#14175)
  website/integrations: add xcreds (#14163)
  core, web: update translations (#14179)
  web: update default flow background (#14115)
  web: bump API Client version (#14176)
  enterprise/policies: Add Password Uniqueness History Policy (#13453)
  web/xliff: fix duplicated translations (#14164)
  website/docs: fix postgres pool recommended settings (#14149)
  core: bump astral-sh/uv from 0.6.14 to 0.6.16 (#14161)
  web: fix scrollbar styling (#12600)
  website: integrations: gravity: fix issuer URL (#14155)
  web: Packagify live reload plugin. (#14134)
  web: bump API Client version (#14062)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in zh-Hans (#14146)
  translate: Updates for file web/xliff/en.xlf in zh_CN (#14145)
  core: bump goauthentik.io/api/v3 from 3.2025024.7 to 3.2025024.8 (#14143)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in zh_CN (#14144)
  translate: Updates for file web/xliff/en.xlf in zh-Hans (#14139)
  core, web: update translations (#14142)
  core: bump yarl from 1.19.0 to v1.20.0 (#14128)
  ...
2025-04-22 09:25:10 -07:00
Ken Sternberg
9a6ca4fba2 Merge branch 'main' into dev
* main: (93 commits)
  core: bump google-auth from 2.38.0 to v2.39.0 (#14076)
  core: bump sentry-sdk from 2.25.1 to v2.26.1 (#14079)
  core: bump prompt-toolkit from 3.0.50 to v3.0.51 (#14078)
  core: bump boto3 from 1.37.33 to v1.37.34 (#14074)
  core: bump msgraph-sdk from 1.27.0 to v1.28.0 (#14077)
  website/docs: fix minor typo in working_with_policies.md (#14071)
  core, web: update translations (#14064)
  stages/authenticator_webauthn: Update FIDO MDS3 & Passkey aaguid blobs (#14065)
  core: bump goauthentik.io/api/v3 from 3.2025024.4 to 3.2025024.6 (#14069)
  Small fix for Actual-Budget wiki guide (#14066)
  root: support db pool (#13534)
  rbac: add `InitialPermissions` (#13795)
  web: bump API Client version (#14058)
  core: Bump django from 5.0.14 to 5.1.8 (#14059)
  core: bump django-rest-framework from 3.14.0 to 3.16.0 (#14057)
  policies/reputation: limit reputation score (#14008)
  ci: fix api-py-publish by disabling poetry cache (#14010)
  core: bump goauthentik/fips-python from 3.12.9-slim-bookworm-fips to 3.12.10-slim-bookworm-fips (#14044)
  ci: add NPM packages publish (#13974)
  root: add packages/ to codeowners (#13975)
  ...
2025-04-15 08:23:44 -07:00
Ken Sternberg
9cf551b1d6 Merge branch 'main' into dev
* main: (204 commits)
  core: bump protobuf from 5.29.4 to v6.30.2 (#13950)
  core: bump pyasn1-modules from 0.4.1 to v0.4.2 (#13951)
  core: bump microsoft-kiota-authentication-azure from 1.9.2 to v1.9.3 (#13948)
  core: bump microsoft-kiota-http from 1.9.2 to v1.9.3 (#13949)
  core: bump trio-websocket from 0.11.1 to v0.12.2 (#13934)
  core: bump msgraph-core from 1.3.1 to v1.3.3 (#13900)
  core: bump jsii from 1.109.0 to v1.111.0 (#13886)
  core: bump setuptools from 72.1.0 to v78.1.0 (#13928)
  core: bump kombu from 5.3.7 to v5.5.2 (#13888)
  core: bump msgpack from 1.0.8 to v1.1.0 (#13899)
  core: bump msgraph-sdk from 1.24.0 to v1.26.0 (#13901)
  core: bump proto-plus from 1.24.0 to v1.26.1 (#13910)
  core: bump protobuf from 5.27.2 to v5.29.4 (#13911)
  core: bump pydantic from 2.10.6 to v2.11.3 (#13914)
  core: bump rich from 13.7.1 to v14.0.0 (#13922)
  core: bump twisted from 24.7.0 to v24.11.0 (#13936)
  core: bump watchfiles from 0.22.0 to v1.0.5 (#13941)
  core: bump typing-extensions from 4.12.2 to v4.13.1 (#13937)
  core: bump multidict from 6.0.5 to v6.2.0 (#13902)
  core: bump sentry-sdk from 2.22.0 to v2.25.1 (#13927)
  ...
2025-04-09 11:13:44 -07:00
Ken Sternberg
f63b3c2bbb Merge branch 'main' into dev
* main:
  ci: stop publishing latest tag (#13245)
  root: fix dependency install due to description-file (#13655)
2025-03-24 13:30:39 -07:00
Ken Sternberg
61dbc932da Merge branch 'main' into dev
* main: (76 commits)
  admin: fix system API when using bearer token (#13651)
  website: bump the build group in /website with 6 updates (#13645)
  core: bump goauthentik.io/api/v3 from 3.2025022.5 to 3.2025022.6 (#13646)
  translate: Updates for file web/xliff/en.xlf in fr (#13653)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in fr (#13652)
  website/integrations: add tandoor (#13560)
  core, web: update translations (#13642)
  providers/scim: fix group membership check failing (#13644)
  ci: add semgrep (#13643)
  flows: fix API not returning configured background (#13641)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in zh_CN (#13631)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in zh-Hans (#13633)
  translate: Updates for file web/xliff/en.xlf in zh_CN (#13632)
  translate: Updates for file web/xliff/en.xlf in zh-Hans (#13634)
  brands: fix migration 0008 by removing incorrect context manager usage (#13635)
  web: Fix prop. (#13630)
  core, web: update translations (#13628)
  web/admin: reworked sync status card (#13625)
  core: bump github.com/golang-jwt/jwt/v5 from 5.2.1 to 5.2.2 (#13626)
  translate: Updates for file web/xliff/en.xlf in zh-Hans (#13622)
  ...
2025-03-24 09:15:11 -07:00
Ken Sternberg
fa994ae318 Merge branch 'main' into dev
* main:
  website/docs: dev docs: bump node/postgres requirements  (#13516)
  sources: prevent deletion of built-in source (#12914)
  core: bump django-tenants (#13536)
  website/docs: dev docs: full: remove note on installing shell plugin (#13515)
  sources/oauth: fix duplicate authentication (#13322)
  web/admin: fix comment being rendered (#13530)
  core: Bump aws-cdk-lib from 2.183.0 to 2.184.0 (#13522)
  core, web: update translations (#13520)
  lifecycle/aws: Bump aws-cdk from 2.1003.0 to 2.1004.0 in /lifecycle/aws (#13524)
  core: Bump github.com/coreos/go-oidc/v3 from 3.12.0 to 3.13.0 (#13525)
2025-03-17 07:21:18 -07:00
Ken Sternberg
cd78fc01f2 Merge branch 'main' into dev
* main: (44 commits)
  providers/rac: fix signals and Endpoint caching (#13529)
  web/flows: fix missing padding on authenticator_validate card (#13420)
  web/user: show admin interface button on mobile (#13421)
  website: Bump the build group in /website with 6 updates (#13501)
  core: Bump goauthentik.io/api/v3 from 3.2025021.3 to 3.2025021.4 (#13495)
  core: Bump importlib-metadata from 8.5.0 to 8.6.1 (#13499)
  core: Bump msgraph-sdk from 1.23.0 to 1.24.0 (#13500)
  core: Bump google-api-python-client from 2.163.0 to 2.164.0 (#13498)
  core: Bump aws-cdk-lib from 2.182.0 to 2.183.0 (#13496)
  core: Bump psycopg from 3.2.5 to 3.2.6 (#13497)
  translate: Updates for file web/xliff/en.xlf in fr (#13514)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in fr (#13513)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in zh-Hans (#13510)
  translate: Updates for file web/xliff/en.xlf in zh-Hans (#13511)
  translate: Updates for file web/xliff/en.xlf in zh_CN (#13509)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in zh_CN (#13508)
  core, web: update translations (#13494)
  website: remove the last updated option from footer (#13493)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in fr (#13487)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in zh_CN (#13488)
  ...
2025-03-14 07:11:45 -07:00
Ken Sternberg
9251e608fa Merge branch 'main' into dev
* main:
  stages/email: token_expiry format (#13394)
  core, web: update translations (#13438)
  website/docs: in developer docs replace deprecated poetry shell command (#13460)
2025-03-11 14:58:45 -07:00
Ken Sternberg
0055882212 Merge branch 'main' into dev
* main:
  web: Ignore Storybook when running codespell. (#13454)
  core: bump ruff from 0.9.9 to 0.9.10 (#13448)
  core: bump webauthn from 2.5.1 to 2.5.2 (#13449)
  website/docs: backup and restore: remove extra period (#13440)
  website: bump prismjs from 1.29.0 to 1.30.0 in /website (#13456)
  web: bump prismjs from 1.29.0 to 1.30.0 in /web (#13455)
2025-03-11 07:01:31 -07:00
Ken Sternberg
68387362c2 Merge branch 'main' into dev
* main:
  web: admin interface: faster card load (#13331)
  web/admin: fix display bug for assigned users in application bindings in the wizard (#13435)
  website: bump the build group across 1 directory with 9 updates (#13442)
  core: bump django from 5.0.12 to 5.0.13 (#13425)
  providers/SCIM: fix object exists error for users, attempt to look up user ID in remote system (#13437)
  website/docs: sys mgmt: document authentik backups/restoration (#12943)
  website: fix build in docker (#13430)
  website/integrations: zipline: add (#13257)
2025-03-11 07:01:23 -07:00
Ken Sternberg
5fe344fb12 Merge branch 'main' into dev
* main:
  translate: Updates for file web/xliff/en.xlf in fr (#13431)
  lifecycle/aws: bump aws-cdk from 2.1002.0 to 2.1003.0 in /lifecycle/aws (#13426)
  translate: Updates for file web/xliff/en.xlf in zh_CN (#13428)
  translate: Updates for file web/xliff/en.xlf in zh-Hans (#13429)
  core, web: update translations (#13423)
2025-03-07 08:14:04 -08:00
Ken Sternberg
aa20df5cca Merge branch 'main' into dev
* main:
  website: add a better edit this page element (#13391)
  web/admin: allow user lists to show active only (#13403)
  core: Tidy contributor onboarding, fix typos. (#12700)
  translate: Updates for file web/xliff/en.xlf in zh-Hans (#13418)
  translate: Updates for file web/xliff/en.xlf in zh_CN (#13417)
  lib/config: fix conn_max_age parsing (#13370)
  core: bump golang.org/x/sync from 0.11.0 to 0.12.0 (#13407)
  stages/authenticator_email: Fix Enroll dropdown in the MFA Devices page (#13404)
  core: bump golang.org/x/oauth2 from 0.27.0 to 0.28.0 (#13408)
  core: bump aws-cdk-lib from 2.181.1 to 2.182.0 (#13409)
  core: bump google-api-python-client from 2.162.0 to 2.163.0 (#13410)
  core: bump msgraph-sdk from 1.22.0 to 1.23.0 (#13411)
  core: bump jinja2 from 3.1.5 to 3.1.6 (#13412)
  web/user: ensure modal container on user-settings page is min-height: 100% (#13402)
  core, web: update translations (#13405)
  web/admin: add button to clear application cache (#13399)
  blueprints: Adjust title for MFA set up (#13400)
2025-03-06 14:56:10 -08:00
Ken Sternberg
75c61afd18 Merge branch 'main' into dev
* main:
  web/admin: fix markdown being completely whited out in dark mode on proxy provider pages (#13387)
  web/admin: decorative display in user’s page breaks in other locales (#13393)
  website: bump the build group in /website with 6 updates (#13396)
  core: bump github.com/prometheus/client_golang from 1.21.0 to 1.21.1 (#13397)
  core: bump debugpy from 1.8.12 to 1.8.13 (#13395)
  website/docs: Update Open Web UI integration  (#13392)
  website/integrations: gravity: add (#13258)
  website/integrations: Pocketbase (#12906)
  ci: cache helper docker images (#13390)
2025-03-05 10:18:55 -08:00
Ken Sternberg
811e7946f7 Merge branch 'main' into dev
* main: (135 commits)
  providers/proxy: kubernetes outpost: fix reconcile when only annotations changed (#13372)
  website: bump the build group in /website with 3 updates (#13381)
  core, web: update translations (#13378)
  web/admin: prefer using datefns over moment.js (#13143)
  website/docs: fix typo (#13377)
  stages/authenticator_email: remove flaky assertions (#13371)
  translate: Updates for file web/xliff/en.xlf in fr (#13374)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in fr (#13373)
  website: bump typescript from 5.7.3 to 5.8.2 in /website (#13368)
  lifecycle/aws: bump aws-cdk from 2.1001.0 to 2.1002.0 in /lifecycle/aws (#13365)
  website: bump the build group in /website with 11 updates (#13367)
  ci: bump getsentry/action-release from 1 to 3 (#13366)
  website: bump @rspack/binding-darwin-arm64 from 1.1.6 to 1.2.6 in /website (#13354)
  core, web: update translations (#13346)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in zh-Hans (#13348)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in zh_CN (#13347)
  translate: Updates for file web/xliff/en.xlf in zh-Hans (#13349)
  translate: Updates for file web/xliff/en.xlf in zh_CN (#13350)
  ci: update versions for daily full testing (#13303)
  website: bump prettier from 3.5.2 to 3.5.3 in /website (#13355)
  ...
2025-03-04 08:29:59 -08:00
Ken Sternberg
19f25d5aa7 Merge branch 'main' into dev
* main:
  web/user: fix opening application with Enter not respecting new tab setting (#13115)
  web: bump API Client version (#13113)
  providers/rac: move to open source (#13015)
  website/docs: add 2025.2 release notes (#13002)
  core: clear expired database sessions (#13105)
  core: bump sentry-sdk from 2.21.0 to 2.22.0 (#13098)
  core: bump bandit from 1.8.2 to 1.8.3 (#13097)
  core: bump aws-cdk-lib from 2.178.2 to 2.179.0 (#13099)
  core: bump goauthentik.io/api/v3 from 3.2024123.4 to 3.2024123.6 (#13100)
  lifecycle/aws: bump aws-cdk from 2.178.2 to 2.179.0 in /lifecycle/aws (#13101)
  website/docs: Add AdventureLog Community Integration Documentation (#12928)
  website/docs: minor fixes (#13095)
  website/integrations: Update to Wizard and Styling Guide (#12919)
  web: bump API Client version (#13093)
  policies/geoip: distance + impossible travel (#12541)
  root: fix generated API docs not being excluded from codespell (#13091)
2025-02-19 08:32:55 -08:00
Ken Sternberg
ffbe8fb598 Merge branch 'main' into dev
* main: (24 commits)
  core: add additional RBAC permission to restrict setting the superuser status on groups (#12900)
  web: bump API Client version (#13089)
  core: bump github.com/spf13/cobra from 1.8.1 to 1.9.1 (#13085)
  stages/authenticator_email: Email OTP (#12630)
  website: bump dompurify and mermaid in /website (#13077)
  web: bump dompurify and mermaid in /web (#13078)
  core: bump django-filter from 24.3 to 25.1 (#13086)
  enterprise/audit: fix diff being created when not enabled (#13084)
  core, web: update translations (#13088)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in zh_CN (#13080)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in zh-Hans (#13081)
  translate: Updates for file web/xliff/en.xlf in zh-Hans (#13082)
  translate: Updates for file web/xliff/en.xlf in zh_CN (#13083)
  core: bump django-storages from 1.14.4 to 1.14.5 (#13087)
  web/user: fix redirects back to user settings (#13076)
  ci: parallelize unit tests (#13036)
  core, web: update translations (#13072)
  stages/authenticator_webauthn: Update FIDO MDS3 & Passkey aaguid blobs (#13073)
  root: Improve debugging experience (#12961)
  core, web: update translations (#13071)
  ...
2025-02-17 08:48:25 -08:00
Ken Sternberg
2279768e6f Merge branch 'main' into dev
* main: (35 commits)
  translate: Updates for file web/xliff/en.xlf in ko [Manual Sync] (#13045)
  translate: Updates for file web/xliff/en.xlf in pl [Manual Sync] (#13043)
  translate: Updates for file web/xliff/en.xlf in ru [Manual Sync] (#13055)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in pl [Manual Sync] (#13062)
  translate: Updates for file web/xliff/en.xlf in zh_TW [Manual Sync] (#13056)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in nl [Manual Sync] (#13058)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in ru [Manual Sync] (#13063)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in zh_TW [Manual Sync] (#13064)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in ko [Manual Sync] (#13060)
  translate: Updates for file web/xliff/en.xlf in nl [Manual Sync] (#13044)
  web: Silence ESBuild warning. (#13025)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in zh-Hans [Manual Sync] (#13066)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in tr [Manual Sync] (#13061)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in zh_CN [Manual Sync] (#13065)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in it [Manual Sync] (#13057)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in pt_BR [Manual Sync] (#13059)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in de [Manual Sync] (#13051)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in fi [Manual Sync] (#13052)
  translate: Updates for file web/xliff/en.xlf in zh-Hans [Manual Sync] (#13050)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in es [Manual Sync] (#13054)
  ...
2025-02-14 09:36:35 -08:00
Ken Sternberg
675e60b816 Merge branch 'main' into dev
* main:
  core: revert bump oss/go/microsoft/golang from 1.23-fips-bookworm to 1.24-fips-bookworm (#13012) (#13022)
2025-02-13 10:00:23 -08:00
Ken Sternberg
e338bef104 Merge branch 'main' into dev
* main: (111 commits)
  root: correctly use correct schema for install_id (#13018)
  website: bump docusaurus-plugin-openapi-docs from 4.3.3 to 4.3.4 in /website (#13011)
  web: bump API Client version (#13017)
  core: bump aws-cdk-lib from 2.178.1 to 2.178.2 (#13013)
  core: bump oss/go/microsoft/golang from 1.23-fips-bookworm to 1.24-fips-bookworm (#13012)
  website: bump docusaurus-theme-openapi-docs from 4.3.3 to 4.3.4 in /website (#13010)
  lifecycle/aws: bump aws-cdk from 2.178.1 to 2.178.2 in /lifecycle/aws (#13009)
  core: bump github.com/sethvargo/go-envconfig from 1.1.0 to 1.1.1 (#13008)
  web/admin: fix source selection for identification stage (#13007)
  core: bump sentry-sdk from 2.20.0 to 2.21.0 (#13014)
  website/integrations: Open WebUI (#12939)
  root: use correct default schema for install_id (#13006)
  website/docs: fix a minor typo (#13004)
  enterprise/providers/ssf: fixes v2 (#13003)
  root: make default postgres schema configurable (#12949)
  providers/oauth2: cleanup tokens when user is deactivated (#12859)
  website/docs: fix Nginx redirection example (#12920)
  core: bump twilio from 9.4.4 to 9.4.5 (#12993)
  core: bump coverage from 7.6.11 to 7.6.12 (#12994)
  core: bump cryptography from 44.0.0 to 44.0.1 (#12992)
  ...
2025-02-13 08:06:21 -08:00
Ken Sternberg
457b61c5b4 Merge branch 'main' into dev
* main:
  web: update gen-client-ts to OpenAPI 7.11.0 (#12756)
  website/integrations: rustdesk-server-pro (#12706)
  core: bump codespell from 2.3.0 to 2.4.0 (#12762)
  root: docker: ensure apt packages are up-to-date (#12683)
  ci: fix missing build args for dev and release (#12760)
  web: bump vite from 5.4.11 to 5.4.14 in /web (#12757)
  web: bump undici from 6.21.0 to 6.21.1 in /web (#12755)
  lifecycle: fix cryptography's OpenSSL path (#12753)
2025-01-22 10:09:24 -08:00
Ken Sternberg
25eefb7d55 Merge branch 'main' into dev
* main: (65 commits)
  stages/redirect: fix query parameter when redirecting to flow (#12750)
  website/integrations: cloudflare-access: refactor (#12663)
  sources/kerberos: handle principal expire time (#12748)
  lifecycle: build binary dependencies which link against SSL directly (#12724)
  website/docs: style guide: document styling preferences for URLs (#12715)
  website/integrations: nextcloud: fix broken link (#12744)
  core: bump selenium from 4.27.1 to 4.28.0 (#12745)
  lifecycle: move AWS CFN generation to lifecycle and fix CI (#12743)
  core: search users' attributes (#12740)
  web/components: ak-number-input: add support for min (#12703)
  website/integrations: nextcloud: fix url for "disable username changes" (#12725)
  core: bump pytest-github-actions-annotate-failures from 0.2.0 to 0.3.0 (#12735)
  website: bump katex from 0.16.11 to 0.16.21 in /website (#12731)
  web: bump katex from 0.16.11 to 0.16.21 in /web (#12730)
  website/integrations: Fix URL for authentik installation instead of mobilizon installation (#12729)
  core: bump debugpy from 1.8.11 to 1.8.12 (#12718)
  core: bump ruff from 0.9.1 to 0.9.2 (#12717)
  core: bump webauthn from 2.4.0 to 2.5.0 (#12719)
  core: bump structlog from 24.4.0 to 25.1.0 (#12720)
  website/integrations: all: install -> installation (#12676)
  ...
2025-01-21 09:56:23 -08:00
Ken Sternberg
50d2f69332 Merge branch 'main' into dev
* main:
  website: revise full development environment instructions (#12638)
  website: bump typescript from 5.7.2 to 5.7.3 in /website (#12620)
  website: bump aws-cdk from 2.174.1 to 2.175.0 in /website (#12621)
  ci: bump docker/setup-qemu-action from 3.2.0 to 3.3.0 (#12622)
  core: bump twilio from 9.4.1 to 9.4.2 (#12623)
  core: bump python-kadmin-rs from 0.5.2 to 0.5.3 (#12624)
  core: bump ruff from 0.8.6 to 0.9.0 (#12625)
  core: bump pydantic from 2.10.4 to 2.10.5 (#12626)
  core: bump google-api-python-client from 2.157.0 to 2.158.0 (#12628)
  core: bump goauthentik.io/api/v3 from 3.2024121.3 to 3.2024122.1 (#12629)
  web: bump API Client version (#12617)
  release: 2024.12.2 (#12615)
  website/docs: prepare 2024.12.2 release notes (#12614)
  providers/saml: fix invalid SAML Response when assertion and response are signed (#12611)
  core: fix error when creating new user with default path (#12609)
  rbac: permissions endpoint: allow authenticated users (#12608)
  website/docs: update customer portal (#12603)
  website/docs: policy for email whitelist: modernize (#12558)
2025-01-10 16:26:36 -08:00
Ken Sternberg
7d972ec711 Merge branch 'main' into dev
* main:
  lib: add expression helper ak_create_jwt to create JWTs (#12599)
  api: cleanup owner permissions (#12598)
  website: bump aws-cdk from 2.174.0 to 2.174.1 in /website (#12593)
  core: bump aws-cdk-lib from 2.174.0 to 2.174.1 (#12594)
  website/integrations: portainer: group config steps (#12548)
  translate: Updates for file web/xliff/en.xlf in fi (#12586)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in fi (#12584)
  website/docs: fix Nginx redirection example (#12561)
2025-01-08 10:13:59 -08:00
Ken Sternberg
854427e463 Merge branch 'main' into dev
* main:
  core: bump golang.org/x/oauth2 from 0.24.0 to 0.25.0 (#12571)
  website: bump the docusaurus group in /website with 9 updates (#12569)
  core: bump github.com/coreos/go-oidc/v3 from 3.11.0 to 3.12.0 (#12572)
  core: bump ruff from 0.8.5 to 0.8.6 (#12573)
  ci: release: fix AWS cfn template permissions (#12576)
  translate: Updates for file web/xliff/en.xlf in fr (#12578)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in fr (#12577)
  sources/kerberos: authenticate with the user's username instead of the first username in authentik (#12497)
  website/integrations: Fix deprecated terraform ressource authentik_scope_mapping in docs (#12554)
  website/user-sources Fix Free IPA docs page (#12549)
  core: bump aws-cdk-lib from 2.173.4 to 2.174.0 (#12574)
  website/integrations: semaphore: fix formatting (#12567)
  website: bump aws-cdk from 2.173.4 to 2.174.0 in /website (#12570)
  website/integrations: Update Frappe Application index.md (#12527)
  website: add api reference docs to redirect file (#12551)
2025-01-06 08:32:50 -08:00
Ken Sternberg
be349e2e14 Merge branch 'main' into dev
* main:
  core: bump github.com/getsentry/sentry-go from 0.30.0 to 0.31.1 (#12543)
  core: bump google-api-python-client from 2.156.0 to 2.157.0 (#12544)
  core: bump ruff from 0.8.4 to 0.8.5 (#12545)
  core: bump msgraph-sdk from 1.15.0 to 1.16.0 (#12546)
  Update index.mdx (#12542)
  web: fix source selection and outpost integration health (#12530)
  Ading a step to paperless guide (#12539)
  website/integrations: Semaphore (#12515)
  website/integrations: komga: document (#12476)
  website/integrations: fix missing quote in paperless-ngx (#12537)
  website/integrations: cloudflare access: upd placeholder for saas (#12536)
  website/integrations: veeam-enterprise-manager: don't hardcode helpcenter doc version (#12538)
2025-01-03 08:09:25 -08:00
Ken Sternberg
bd0e81b8ad Merge branch 'main' into dev
* main:
  website/integrations: meshcentral: document (#12509)
  stages/authenticator_webauthn: Update FIDO MDS3 & Passkey aaguid blobs (#12524)
  core: bump goauthentik.io/api/v3 from 3.2024121.2 to 3.2024121.3 (#12522)
  web: bump API Client version (#12520)
  website/integrations: chronograf: document (#12474)
  website/integrations: update preparation placeholder (#12507)
  providers/saml: fix handle Accept: application/xml for SAML Metadata endpoint (#12483) (#12518)
  core: bump aws-cdk-lib from 2.173.3 to 2.173.4 (#12513)
  website: bump aws-cdk from 2.173.3 to 2.173.4 in /website (#12514)
  core: bump coverage from 7.6.9 to 7.6.10 (#12499)
  core: bump aws-cdk-lib from 2.173.2 to 2.173.3 (#12500)
  website: bump aws-cdk from 2.173.2 to 2.173.3 in /website (#12501)
  core: bump github.com/go-ldap/ldap/v3 from 3.4.9 to 3.4.10 (#12502)
  website/docs: New "Whats Up Docker" URL (#12488)
2025-01-02 10:01:26 -08:00
Ken Sternberg
f6afb59515 Revert "This (temporary) change is needed to prevent the unit tests from failing."
This reverts commit dddde09be5.
2024-12-26 13:59:53 -08:00
Ken Sternberg
dddde09be5 This (temporary) change is needed to prevent the unit tests from failing.
\# What

\# Why

\# How

\# Designs

\# Test Steps

\# Other Notes
2024-12-26 13:59:00 -08:00
Ken Sternberg
6d7fc94698 Merge branch 'main' into dev
* main: (118 commits)
  outposts: fix version label (#12486)
  web: only load version context when authenticated (#12482)
  core: bump goauthentik.io/api/v3 from 3.2024120.2 to 3.2024121.2 (#12478)
  ci: bump helm/kind-action from 1.11.0 to 1.12.0 (#12479)
  web: fix build dev build (#12473)
  root: fix dev build version being invalid semver (#12472)
  internal: fix missing trailing slash in outpost websocket (#12470)
  web: bump API Client version (#12469)
  admin: monitor worker version (#12463)
  core: bump jinja2 from 3.1.4 to 3.1.5 (#12467)
  web: bump API Client version (#12468)
  release: 2024.12.1 (#12466)
  web: misc fixes for admin and flow inspector (#12461)
  website/docs: 2024.12.1 release notes (#12462)
  core: bump goauthentik.io/api/v3 from 3.2024120.1 to 3.2024120.2 (#12456)
  core: bump urllib3 from 2.2.3 to 2.3.0 (#12457)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in zh-Hans (#12454)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in zh_CN (#12453)
  translate: Updates for file web/xliff/en.xlf in zh-Hans (#12455)
  translate: Updates for file web/xliff/en.xlf in zh_CN (#12458)
  ...
2024-12-26 08:49:23 -08:00
Ken Sternberg
1dcf9108ad Merge branch 'main' into dev
* main:
  flows: better test stage's challenge responses (#12316)
  enterprise/stages/authenticator_endpoint_gdtc: don't set frame options globally (#12311)
  stages/identification: fix invalid challenge warning when no captcha stage is set (#12312)
  website/docs: prepare 2024.10.5 release notes (#12309)
  website: bump nanoid from 3.3.7 to 3.3.8 in /website (#12307)
  flows: silent authz flow (#12213)
  root:  use healthcheck in depends_on for postgres and redis (#12301)
  ci: ensure mark jobs always run and reflect correct status (#12288)
  enterprise: allow deletion/modification of users when in read-only mode (#12289)
  web/flows: resize captcha iframes (#12260)
2024-12-10 09:07:45 -08:00
Ken Sternberg
7bb6a3dfe6 Merge branch 'main' into dev
* main:
  website/docs: add page about the Cobalt pentest (#12249)
  core: bump aws-cdk-lib from 2.171.1 to 2.172.0 (#12296)
  website: bump aws-cdk from 2.171.1 to 2.172.0 in /website (#12295)
  core: bump sentry-sdk from 2.19.1 to 2.19.2 (#12297)
  core: bump coverage from 7.6.8 to 7.6.9 (#12299)
  core, web: update translations (#12290)
  root: fix override locale only if it is not empty (#12283)
  translate: Updates for file web/xliff/en.xlf in fr (#12276)
  core: bump twilio from 9.3.7 to 9.3.8 (#12282)
  website: bump path-to-regexp and express in /website (#12279)
  core: bump sentry-sdk from 2.19.0 to 2.19.1 (#12280)
  core: bump ruff from 0.8.1 to 0.8.2 (#12281)
  website/docs: fix lint (#12287)
  website/integrations: netbird: fix redirect URI regex (#12284)
2024-12-09 08:28:52 -08:00
Ken Sternberg
9cc440eee1 Merge branch 'main' into dev
* main:
  web: simplify `?inline` handler for Storybook (#12246)
  website/docs: Update Traefik middleware example to reflect latest version of Traefik (#12267)
  website/docs: add . in https://netbird.company* (#12166)
  core: bump goauthentik.io/api/v3 from 3.2024104.1 to 3.2024104.2 (#12263)
  core: bump pydantic from 2.10.2 to 2.10.3 (#12262)
  core: bump github.com/getsentry/sentry-go from 0.29.1 to 0.30.0 (#12264)
  core, web: update translations (#12268)
  website: bump @types/react from 18.3.12 to 18.3.13 in /website (#12269)
  website: bump prettier from 3.4.1 to 3.4.2 in /website (#12270)
  ci: bump actions/attest-build-provenance from 1 to 2 (#12271)
  core: bump golang.org/x/sync from 0.9.0 to 0.10.0 (#12272)
  core: bump django from 5.0.9 to 5.0.10 (#12273)
  core: bump webauthn from 2.3.0 to 2.4.0 (#12274)
  website/integrations: add The Lounge (#11971)
  core: bump python-kadmin-rs from 0.3.0 to 0.4.0 (#12257)
  root: fix health status code (#12255)
  ci: fix should_push always being false (#12252)
  web: bump API Client version (#12251)
  providers/oauth2: Add provider federation between OAuth2 Providers (#12083)
  website/integrations: mastodon: set correct uid field (#11945)
2024-12-05 10:47:00 -08:00
Ken Sternberg
fe9e4526ac Merge branch 'main' into dev
* main: (31 commits)
  web/admin: bugfix: dual select initialization revision (#12051)
  web: update tests for Chromedriver 131 (#12199)
  website/integrations: add Aruba Orchestrator (#12220)
  core: bump aws-cdk-lib from 2.167.1 to 2.171.1 (#12237)
  website: bump aws-cdk from 2.167.1 to 2.171.1 in /website (#12241)
  core, web: update translations (#12236)
  core: bump python-kadmin-rs from 0.2.0 to 0.3.0 (#12238)
  core: bump pytest from 8.3.3 to 8.3.4 (#12239)
  core: bump drf-spectacular from 0.27.2 to 0.28.0 (#12240)
  core, web: update translations (#12222)
  core: Bump ruff from 0.8.0 to 0.8.1 (#12224)
  core: Bump ua-parser from 0.18.0 to 1.0.0 (#12225)
  core: Bump msgraph-sdk from 1.13.0 to 1.14.0 (#12226)
  stages/authenticator_webauthn: Update FIDO MDS3 & Passkey aaguid blobs (#12234)
  website/docs: install: add aws (#12082)
  core: Bump pyjwt from 2.10.0 to 2.10.1 (#12217)
  core: Bump fido2 from 1.1.3 to 1.2.0 (#12218)
  core: Bump cryptography from 43.0.3 to 44.0.0 (#12219)
  providers/oauth2: allow m2m for JWKS without alg in keys (#12196)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in fr (#12210)
  ...
2024-12-02 09:10:36 -08:00
Ken Sternberg
20b66f850c Merge branch 'main' into dev
* main:
  website/docs: Add note about single group per role (#12169)
  website/docs: Fix documentation about attribute merging for indirect membership (#12168)
  root: support running authentik in subpath (#8675)
  docs: fix contribution link (#12189)
  core, web: update translations (#12190)
  core: Bump msgraph-sdk from 1.12.0 to 1.13.0 (#12191)
  core: Bump selenium from 4.26.1 to 4.27.0 (#12192)
2024-11-26 09:27:51 -08:00
Ken Sternberg
67b327414b Merge branch 'main' into dev
* main:
  website/docs: Fix CSP syntax (#12124)
2024-11-25 13:11:45 -08:00
Ken Sternberg
5b8d86b5a9 Merge branch 'main' into dev
* main:
  ci: only mirror if secret is available (#12181)
  root: fix database ssl options not set correctly (#12180)
  core, web: update translations (#12145)
  core: bump tornado from 6.4.1 to 6.4.2 (#12165)
  website: bump the docusaurus group in /website with 9 updates (#12172)
  website: bump typescript from 5.6.3 to 5.7.2 in /website (#12173)
  ci: bump actions/checkout from 3 to 4 (#12174)
  core: bump github.com/stretchr/testify from 1.9.0 to 1.10.0 (#12175)
  core: bump coverage from 7.6.7 to 7.6.8 (#12176)
  core: bump ruff from 0.7.4 to 0.8.0 (#12177)
2024-11-25 09:21:19 -08:00
Ken Sternberg
67aed3e318 Merge branch 'main' into dev
* main: (33 commits)
  ci: mirror repo to internal repo (#12160)
  core: bump goauthentik.io/api/v3 from 3.2024102.2 to 3.2024104.1 (#12149)
  core: bump debugpy from 1.8.8 to 1.8.9 (#12150)
  core: bump webauthn from 2.2.0 to 2.3.0 (#12151)
  core: bump pydantic from 2.10.0 to 2.10.1 (#12152)
  translate: Updates for file web/xliff/en.xlf in zh_CN (#12156)
  translate: Updates for file web/xliff/en.xlf in zh-Hans (#12157)
  core: bump sentry-sdk from 2.18.0 to 2.19.0 (#12153)
  web: bump API Client version (#12147)
  root: Backport version change (#12146)
  website/docs: update info about footer links to match new UI (#12120)
  website/docs: prepare release notes (#12142)
  providers/oauth2: fix migration (#12138)
  providers/oauth2: fix migration dependencies (#12123)
  web: bump API Client version (#12129)
  providers/oauth2: fix redirect uri input (#12122)
  providers/proxy: fix redirect_uri (#12121)
  website/docs: prepare release notes (#12119)
  web: bump API Client version (#12118)
  security: fix CVE 2024 52289 (#12113)
  ...
2024-11-22 13:56:13 -08:00
Ken Sternberg
9809b94030 Merge branch 'main' into dev
* main: (28 commits)
  providers/scim: accept string and int for SCIM IDs (#12093)
  website: bump the docusaurus group in /website with 9 updates (#12086)
  core: fix source_flow_manager throwing error when authenticated user attempts to re-authenticate with existing link (#12080)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in de (#12079)
  scripts: remove read_replicas from generated dev config (#12078)
  core: bump geoip2 from 4.8.0 to 4.8.1 (#12071)
  core: bump goauthentik.io/api/v3 from 3.2024100.2 to 3.2024102.2 (#12072)
  core: bump maxmind/geoipupdate from v7.0.1 to v7.1.0 (#12073)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in zh_CN (#12074)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in zh-Hans (#12075)
  translate: Updates for file web/xliff/en.xlf in zh-Hans (#12076)
  translate: Updates for file web/xliff/en.xlf in zh_CN (#12077)
  web/admin: auto-prefill user path for new users based on selected path (#12070)
  core: bump aiohttp from 3.10.2 to 3.10.11 (#12069)
  web/admin: fix brand title not respected in application list (#12068)
  core: bump pyjwt from 2.9.0 to 2.10.0 (#12063)
  web: add italian locale (#11958)
  web/admin: better footer links (#12004)
  core, web: update translations (#12052)
  core: bump twilio from 9.3.6 to 9.3.7 (#12061)
  ...
2024-11-20 10:23:54 -08:00
Ken Sternberg
e7527c551b Merge branch 'main' into dev
* main:
  translate: Updates for file locale/en/LC_MESSAGES/django.po in zh-Hans (#12045)
  translate: Updates for file web/xliff/en.xlf in zh_CN (#12047)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in zh_CN (#12044)
  translate: Updates for file web/xliff/en.xlf in zh-Hans (#12046)
  web/flows: fix invisible captcha call (#12048)
  rbac: fix incorrect object_description for object-level permissions (#12029)
  stages/authenticator_webauthn: Update FIDO MDS3 & Passkey aaguid blobs (#12036)
  core: bump coverage from 7.6.4 to 7.6.5 (#12037)
  ci: bump codecov/codecov-action from 4 to 5 (#12038)
  release: 2024.10.2 (#12031)
2024-11-15 12:47:17 -08:00
Ken Sternberg
36b10b434a :wqge branch 'main' into dev
* main:
  providers/ldap: fix global search_full_directory permission not being sufficient (#12028)
  website/docs: 2024.10.2 release notes (#12025)
  lifecycle: fix ak exit status not being passed (#12024)
  core: use versioned_script for path only (#12003)
  core, web: update translations (#12020)
  core: bump google-api-python-client from 2.152.0 to 2.153.0 (#12021)
  providers/oauth2: fix manual device code entry (#12017)
  crypto: validate that generated certificate's name is unique (#12015)
  core, web: update translations (#12006)
  core: bump google-api-python-client from 2.151.0 to 2.152.0 (#12007)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in zh-Hans (#12011)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in zh_CN (#12010)
  translate: Updates for file web/xliff/en.xlf in zh-Hans (#12012)
  translate: Updates for file web/xliff/en.xlf in zh_CN (#12013)
  providers/proxy: fix Issuer when AUTHENTIK_HOST_BROWSER is set (#11968)
  website/docs: move S3 ad GeoIP to System Management/Operations (#11998)
  website/integrations: nextcloud: add SSE warning (#11976)
2024-11-14 11:29:13 -08:00
Ken Sternberg
831797b871 Merge branch 'main' into dev
* main: (21 commits)
  web: bump API Client version (#11997)
  sources/kerberos: use new python-kadmin implementation (#11932)
  core: add ability to provide reason for impersonation (#11951)
  website/integrations:  update vcenter integration docs (#11768)
  core, web: update translations (#11995)
  website: bump postcss from 8.4.48 to 8.4.49 in /website (#11996)
  web: bump API Client version (#11992)
  blueprints: add default Password policy (#11793)
  stages/captcha: Run interactive captcha in Frame (#11857)
  core, web: update translations (#11979)
  core: bump packaging from 24.1 to 24.2 (#11985)
  core: bump ruff from 0.7.2 to 0.7.3 (#11986)
  core: bump msgraph-sdk from 1.11.0 to 1.12.0 (#11987)
  website: bump the docusaurus group in /website with 9 updates (#11988)
  website: bump postcss from 8.4.47 to 8.4.48 in /website (#11989)
  stages/password: use recovery flow from brand (#11953)
  core: bump golang.org/x/sync from 0.8.0 to 0.9.0 (#11962)
  web: bump cookie, swagger-client and express in /web (#11966)
  core, web: update translations (#11959)
  core: bump debugpy from 1.8.7 to 1.8.8 (#11961)
  ...
2024-11-12 10:08:48 -08:00
Ken Sternberg
5cc2c0f45f Merge branch 'main' into dev
* main:
  ci: fix dockerfile warning (#11956)
2024-11-07 12:58:15 -08:00
Ken Sternberg
32442766f4 Merge branch 'main' into dev
* main:
  website/docs: fix slug matching redirect URI causing broken refresh (#11950)
  website/integrations: jellyfin: update plugin catalog location (#11948)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in de (#11942)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in zh_CN (#11946)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in zh-Hans (#11947)
  website/docs: clarify traefik ingress setup (#11938)
  core: bump importlib-metadata from 8.4.0 to 8.5.0 (#11934)
  web: bump API Client version (#11930)
  root: backport version bump `2024.10.1` (#11929)
  website/docs: `2024.10.1` Release Notes (#11926)
  website: bump path-to-regexp from 1.8.0 to 1.9.0 in /website (#11924)
  core: bump sentry-sdk from 2.17.0 to 2.18.0 (#11918)
  website: bump the docusaurus group in /website with 9 updates (#11917)
  core: bump goauthentik.io/api/v3 from 3.2024100.1 to 3.2024100.2 (#11915)
  core, web: update translations (#11914)
2024-11-07 08:08:46 -08:00
Ken Sternberg
75790909a8 Merge branch 'main' into dev
* main:
  web: bump API Client version (#11909)
  enterprise/rac: fix API Schema for invalidation_flow (#11907)
2024-11-04 13:20:15 -08:00
Ken Sternberg
e0d5df89ca Merge branch 'main' into dev
* main:
  core: add `None` check to a device's `extra_description` (#11904)
  providers/oauth2: fix size limited index for tokens (#11879)
  web: fix missing status code on failed build (#11903)
  website: bump docusaurus-theme-openapi-docs from 4.1.0 to 4.2.0 in /website (#11897)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in de (#11891)
  stages/authenticator_webauthn: Update FIDO MDS3 & Passkey aaguid blobs (#11884)
  translate: Updates for file web/xliff/en.xlf in tr (#11878)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in tr (#11866)
  core: bump google-api-python-client from 2.149.0 to 2.151.0 (#11885)
  core: bump selenium from 4.26.0 to 4.26.1 (#11886)
  core, web: update translations (#11896)
  website: bump docusaurus-plugin-openapi-docs from 4.1.0 to 4.2.0 in /website (#11898)
  core: bump watchdog from 5.0.3 to 6.0.0 (#11899)
  core: bump ruff from 0.7.1 to 0.7.2 (#11900)
  core: bump django-pglock from 1.6.2 to 1.7.0 (#11901)
  website/docs: fix release notes to say Federation (#11889)
2024-11-04 10:25:52 -08:00
Ken Sternberg
f25a9c624e Merge branch 'main' into dev
* main:
  website: bump elliptic from 6.5.7 to 6.6.0 in /website (#11869)
  core: bump selenium from 4.25.0 to 4.26.0 (#11875)
  core: bump goauthentik.io/api/v3 from 3.2024083.14 to 3.2024100.1 (#11876)
  website/docs: add info about invalidation flow, default flows in general (#11800)
  website: fix docs redirect (#11873)
  website: remove RC disclaimer for version 2024.10 (#11871)
  website: update supported versions (#11841)
  web: bump API Client version (#11870)
  root: backport version bump 2024.10.0 (#11868)
  website/docs: 2024.8.4 release notes (#11862)
  web/admin: provide default invalidation flows for LDAP and Radius (#11861)
2024-11-04 10:25:45 -08:00
Ken Sternberg
914993a788 Merge branch 'main' into dev
* main: (43 commits)
  core, web: update translations (#11858)
  web/admin: fix code-based MFA toggle not working in wizard (#11854)
  sources/kerberos: add kiprop to ignored system principals (#11852)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in zh_CN (#11846)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in it (#11845)
  translate: Updates for file web/xliff/en.xlf in zh_CN (#11847)
  translate: Updates for file web/xliff/en.xlf in zh-Hans (#11848)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in zh-Hans (#11849)
  translate: Updates for file web/xliff/en.xlf in it (#11850)
  website: 2024.10 Release Notes (#11839)
  translate: Updates for file web/xliff/en.xlf in zh-Hans (#11814)
  core, web: update translations (#11821)
  core: bump goauthentik.io/api/v3 from 3.2024083.13 to 3.2024083.14 (#11830)
  core: bump service-identity from 24.1.0 to 24.2.0 (#11831)
  core: bump twilio from 9.3.5 to 9.3.6 (#11832)
  core: bump pytest-randomly from 3.15.0 to 3.16.0 (#11833)
  website/docs: Update social-logins github (#11822)
  website/docs: remove � (#11823)
  lifecycle: fix kdc5-config missing (#11826)
  website/docs: update preview status of different features (#11817)
  ...
2024-10-30 10:04:59 -07:00
Ken Sternberg
89dad07a66 web: Add InvalidationFlow to Radius Provider dialogues
## What

- Bugfix: adds the InvalidationFlow to the Radius Provider dialogues
  - Repairs: `{"invalidation_flow":["This field is required."]}` message, which was *not* propagated
    to the Notification.
- Nitpick: Pretties `?foo=${true}` expressions: `s/\?([^=]+)=\$\{true\}/\1/`

## Note

Yes, I know I'm going to have to do more magic when we harmonize the forms, and no, I didn't add the
Property Mappings to the wizard, and yes, I know I'm going to have pain with the *new* version of
the wizard. But this is a serious bug; you can't make Radius servers with *either* of the current
dialogues at the moment.
2024-10-23 14:17:30 -07:00
3214 changed files with 51049 additions and 564267 deletions

View File

@@ -1,5 +0,0 @@
[alias]
t = ["nextest", "run", "--workspace"]
[build]
rustflags = ["--cfg", "tokio_unstable"]

View File

@@ -1,47 +0,0 @@
[licenses]
allow = [
"Apache-2.0 WITH LLVM-exception",
"Apache-2.0",
"BSD-3-Clause",
"CC0-1.0",
"CDLA-Permissive-2.0",
"ISC",
"MIT",
"MPL-2.0",
"OpenSSL",
"Unicode-3.0",
"Zlib",
]
[licenses.private]
ignore = true
[bans]
multiple-versions = "allow"
wildcards = "deny"
[bans.workspace-dependencies]
duplicates = "deny"
include-path-dependencies = true
unused = "deny"
# No non-FIPS compliant dependencies
[[bans.deny]]
name = "native-tls"
[[bans.deny]]
name = "openssl"
[[bans.deny]]
name = "openssl-sys"
[[bans.deny]]
name = "ring"
[[bans.features]]
allow = [
"alloc",
"aws-lc-sys",
"default",
"fips",
"prebuilt-nasm",
"ring-io",
"ring-sig-verify",
]
name = "aws-lc-rs"
exact = true

View File

@@ -1,15 +0,0 @@
comment_width = 100
format_code_in_doc_comments = true
format_strings = true
group_imports = "StdExternalCrate"
hex_literal_case = "Lower"
imports_granularity = "Crate"
max_width = 100
newline_style = "Unix"
normalize_comments = true
normalize_doc_attributes = true
reorder_impl_items = true
style_edition = "2024"
use_field_init_shorthand = true
use_try_shorthand = true
wrap_comments = true

View File

@@ -9,5 +9,7 @@ build_docs/**
**/*Dockerfile
blueprints/local
.git
!gen-ts-api/node_modules
!gen-ts-api/dist/**
!gen-go-api/
.venv
target

9
.gitattributes vendored
View File

@@ -1,9 +0,0 @@
packages/client-*/** linguist-generated
web/packages/lex/* linguist-vendored
web/packages/node-domexception/* linguist-vendored
web/packages/formdata-polyfill/* linguist-vendored
web/packages/sfe/vendored/* linguist-vendored
website/vendored/* linguist-vendored
website/docs/** linguist-documentation
website/integrations/** linguist-documentation
website/api/** linguist-documentation

View File

@@ -115,13 +115,20 @@ runs:
shell: bash
env:
GITHUB_TOKEN: ${{ inputs.token }}
PR_NUMBER: ${{ steps.should_run.outputs.pr_number }}
REASON: ${{ steps.should_run.outputs.reason }}
run: |
set -e -o pipefail
PR_NUMBER="${{ steps.should_run.outputs.pr_number }}"
# Get PR details
PR_DATA=$(gh api repos/${{ github.repository }}/pulls/$PR_NUMBER)
PR_TITLE=$(echo "$PR_DATA" | jq -r '.title')
PR_AUTHOR=$(echo "$PR_DATA" | jq -r '.user.login')
echo "pr_title=$PR_TITLE" >> $GITHUB_OUTPUT
echo "pr_author=$PR_AUTHOR" >> $GITHUB_OUTPUT
# Determine which labels to process
if [ "${REASON}" = "label_added_to_merged_pr" ]; then
if [ "${{ steps.should_run.outputs.reason }}" = "label_added_to_merged_pr" ]; then
# Only process the specific label that was just added
if [ "${{ github.event_name }}" = "issues" ]; then
LABEL_NAME="${{ github.event.label.name }}"
@@ -145,13 +152,13 @@ runs:
shell: bash
env:
GITHUB_TOKEN: ${{ inputs.token }}
PR_NUMBER: '${{ steps.should_run.outputs.pr_number }}'
COMMIT_SHA: '${{ steps.should_run.outputs.merge_commit_sha }}'
PR_TITLE: ${{ github.event.pull_request.title }}
PR_AUTHOR: ${{ github.event.pull_request.user.login }}
LABELS: '${{ steps.pr_details.outputs.labels }}'
run: |
set -e -o pipefail
PR_NUMBER='${{ steps.should_run.outputs.pr_number }}'
COMMIT_SHA='${{ steps.should_run.outputs.merge_commit_sha }}'
PR_TITLE='${{ steps.pr_details.outputs.pr_title }}'
PR_AUTHOR='${{ steps.pr_details.outputs.pr_author }}'
LABELS='${{ steps.pr_details.outputs.labels }}'
echo "Processing PR #$PR_NUMBER (reason: ${{ steps.should_run.outputs.reason }})"
echo "Found backport labels: $LABELS"

View File

@@ -54,6 +54,10 @@ outputs:
runs:
using: "composite"
steps:
- name: Setup authentik env
uses: ./.github/actions/setup
with:
dependencies: "python"
- name: Generate config
id: ev
shell: bash
@@ -64,4 +68,4 @@ runs:
PR_HEAD_SHA: ${{ github.event.pull_request.head.sha }}
REF: ${{ github.ref }}
run: |
python3 ${{ github.action_path }}/push_vars.py
uv run python3 ${{ github.action_path }}/push_vars.py

View File

@@ -2,19 +2,10 @@
import os
from json import dumps
from pathlib import Path
from sys import exit as sysexit
from time import time
from typing import Any
def authentik_version() -> str:
init = Path(__file__).parent.parent.parent.parent / "authentik" / "__init__.py"
with open(init) as f:
content = f.read()
locals: dict[str, Any] = {}
exec(content, None, locals) # nosec
return str(locals["VERSION"])
from authentik import authentik_version
def must_or_fail(input: str | None, error: str) -> str:
@@ -106,7 +97,6 @@ if os.getenv("RELEASE", "false").lower() == "true":
image_build_args = [f"VERSION={os.getenv('REF')}"]
else:
image_build_args = [f"GIT_BUILD_HASH={sha}"]
image_build_args_str = "\n".join(image_build_args)
with open(os.environ["GITHUB_OUTPUT"], "a+", encoding="utf-8") as _output:
print(f"shouldPush={str(should_push).lower()}", file=_output)
@@ -119,4 +109,4 @@ with open(os.environ["GITHUB_OUTPUT"], "a+", encoding="utf-8") as _output:
print(f"imageMainTag={image_main_tag}", file=_output)
print(f"imageMainName={image_tags[0]}", file=_output)
print(f"cacheTo={cache_to}", file=_output)
print(f"imageBuildArgs={image_build_args_str}", file=_output)
print(f"imageBuildArgs={"\n".join(image_build_args)}", file=_output)

View File

@@ -4,95 +4,49 @@ description: "Setup authentik testing environment"
inputs:
dependencies:
description: "List of dependencies to setup"
default: "system,python,rust,node,go,runtime"
default: "system,python,node,go,runtime"
postgresql_version:
description: "Optional postgresql image tag"
default: "16"
working-directory:
description: |
Optional working directory if this repo isn't in the root of the actions workspace.
When set, needs to contain a trailing slash
default: ""
runs:
using: "composite"
steps:
- name: Cleanup apt
if: ${{ contains(inputs.dependencies, 'system') || contains(inputs.dependencies, 'python') }}
shell: bash
run: sudo apt-get remove --purge man-db
- name: Install apt deps
if: ${{ contains(inputs.dependencies, 'system') || contains(inputs.dependencies, 'python') }}
uses: gerlero/apt-install@f4fa5265092af9e750549565d28c99aec7189639
with:
packages: libpq-dev openssl libxmlsec1-dev pkg-config gettext krb5-multidev libkrb5-dev heimdal-multidev libclang-dev krb5-kdc krb5-user krb5-admin-server
update: true
upgrade: false
install-recommends: false
- name: Make space on disk
- name: Install apt deps & cleanup
if: ${{ contains(inputs.dependencies, 'system') || contains(inputs.dependencies, 'python') }}
shell: bash
run: |
sudo mkdir -p /tmp/empty/
sudo rsync -a --delete /tmp/empty/ /usr/local/lib/android/
sudo apt-get remove --purge man-db
sudo apt-get update
sudo apt-get install --no-install-recommends -y libpq-dev openssl libxmlsec1-dev pkg-config gettext krb5-multidev libkrb5-dev heimdal-multidev libclang-dev krb5-kdc krb5-user krb5-admin-server
sudo rm -rf /usr/local/lib/android
- name: Install uv
if: ${{ contains(inputs.dependencies, 'python') }}
uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v5
uses: astral-sh/setup-uv@803947b9bd8e9f986429fa0c5a41c367cd732b41 # v5
with:
enable-cache: true
- name: Setup python
if: ${{ contains(inputs.dependencies, 'python') }}
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v5
with:
python-version-file: "${{ inputs.working-directory }}pyproject.toml"
python-version-file: "pyproject.toml"
- name: Install Python deps
if: ${{ contains(inputs.dependencies, 'python') }}
shell: bash
working-directory: ${{ inputs.working-directory }}
run: uv sync --all-extras --dev --locked
- name: Setup rust (stable)
if: ${{ contains(inputs.dependencies, 'rust') && !contains(inputs.dependencies, 'rust-nightly') }}
uses: actions-rust-lang/setup-rust-toolchain@2b1f5e9b395427c92ee4e3331786ca3c37afe2d7 # v1
with:
rustflags: ""
- name: Setup rust (nightly)
if: ${{ contains(inputs.dependencies, 'rust-nightly') }}
uses: actions-rust-lang/setup-rust-toolchain@2b1f5e9b395427c92ee4e3331786ca3c37afe2d7 # v1
with:
toolchain: nightly
components: rustfmt
rustflags: ""
- name: Setup rust dependencies
if: ${{ contains(inputs.dependencies, 'rust') }}
uses: taiki-e/install-action@711e1c3275189d76dcc4d34ddea63bf96ac49090 # v2
with:
tool: cargo-deny cargo-machete cargo-llvm-cov nextest
- name: Setup node (web)
run: uv sync --all-extras --dev --frozen
- name: Setup node
if: ${{ contains(inputs.dependencies, 'node') }}
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v4
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v4
with:
node-version-file: "${{ inputs.working-directory }}web/package.json"
node-version-file: web/package.json
cache: "npm"
cache-dependency-path: "${{ inputs.working-directory }}web/package-lock.json"
registry-url: "https://registry.npmjs.org"
- name: Setup node (root)
if: ${{ contains(inputs.dependencies, 'node') }}
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v4
with:
node-version-file: "${{ inputs.working-directory }}package.json"
cache: "npm"
cache-dependency-path: "${{ inputs.working-directory }}package-lock.json"
registry-url: "https://registry.npmjs.org"
- name: Install Node deps
if: ${{ contains(inputs.dependencies, 'node') }}
shell: bash
working-directory: ${{ inputs.working-directory }}
run: npm ci
cache-dependency-path: web/package-lock.json
registry-url: 'https://registry.npmjs.org'
- name: Setup go
if: ${{ contains(inputs.dependencies, 'go') }}
uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v5
uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v5
with:
go-version-file: "${{ inputs.working-directory }}go.mod"
go-version-file: "go.mod"
- name: Setup docker cache
if: ${{ contains(inputs.dependencies, 'runtime') }}
uses: AndreKurait/docker-cache@0fe76702a40db986d9663c24954fc14c6a6031b7
@@ -101,15 +55,13 @@ runs:
- name: Setup dependencies
if: ${{ contains(inputs.dependencies, 'runtime') }}
shell: bash
working-directory: ${{ inputs.working-directory }}
run: |
export PSQL_TAG=${{ inputs.postgresql_version }}
docker compose -f .github/actions/setup/compose.yml up -d --wait
cd web && npm ci
docker compose -f .github/actions/setup/compose.yml up -d
cd web && npm i
- name: Generate config
if: ${{ contains(inputs.dependencies, 'python') }}
shell: uv run python {0}
working-directory: ${{ inputs.working-directory }}
run: |
from authentik.lib.generators import generate_id
from yaml import safe_dump

View File

@@ -2,20 +2,14 @@ services:
postgresql:
image: docker.io/library/postgres:${PSQL_TAG:-16}
volumes:
- db-data:/var/lib/postgresql
- db-data:/var/lib/postgresql/data
command: "-c log_statement=all"
environment:
POSTGRES_USER: authentik
POSTGRES_PASSWORD: "EK-5jnKfjrGRm<77"
POSTGRES_DB: authentik
PGDATA: /var/lib/postgresql/data/pgdata
ports:
- 5432:5432
healthcheck:
test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB} -h 127.0.0.1"]
interval: 1s
timeout: 5s
retries: 60
restart: always
s3:
container_name: s3

View File

@@ -2,22 +2,18 @@ name: "Process test results"
description: Convert test results to JUnit, add them to GitHub Actions and codecov
inputs:
files:
description: Comma-separated explicit list of files to upload
flags:
description: Codecov flags
runs:
using: "composite"
steps:
- uses: codecov/codecov-action@57e3a136b779b570ffcdbf80b3bdc90e7fab3de2 # v5
- uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de # v5
with:
files: ${{ inputs.files }}
flags: ${{ inputs.flags }}
use_oidc: true
- uses: codecov/codecov-action@57e3a136b779b570ffcdbf80b3bdc90e7fab3de2 # v5
- uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de # v5
with:
files: ${{ inputs.files }}
flags: ${{ inputs.flags }}
use_oidc: true
report_type: test_results

3
.github/codecov.yml vendored
View File

@@ -8,6 +8,3 @@ coverage:
threshold: 1%
comment:
after_n_builds: 3
ignore:
- packages/client-rust
- packages/client-ts

1
.github/codespell-dictionary.txt vendored Normal file
View File

@@ -0,0 +1 @@
authentic->authentik

32
.github/codespell-words.txt vendored Normal file
View File

@@ -0,0 +1,32 @@
akadmin
asgi
assertIn
authentik
authn
crate
docstrings
entra
goauthentik
gunicorn
hass
jwe
jwks
keypair
keypairs
kubernetes
oidc
ontext
openid
passwordless
plex
saml
scim
singed
slo
sso
totp
traefik
# https://github.com/codespell-project/codespell/issues/1224
upToDate
warmup
webauthn

View File

@@ -20,8 +20,6 @@ updates:
prefix: "ci:"
labels:
- dependencies
cooldown:
default-days: 3
#endregion
@@ -37,56 +35,6 @@ updates:
prefix: "core:"
labels:
- dependencies
cooldown:
default-days: 7
semver-major-days: 14
semver-patch-days: 3
exclude:
- "golang.org/x/crypto"
- "golang.org/x/net"
- "github.com/golang-jwt/jwt/*"
- "github.com/coreos/go-oidc/*"
- "github.com/go-ldap/ldap/*"
#endregion
#region Rust
- package-ecosystem: cargo
directory: "/"
schedule:
interval: daily
time: "04:00"
open-pull-requests-limit: 10
commit-message:
prefix: "core:"
labels:
- dependencies
cooldown:
default-days: 7
semver-major-days: 14
semver-patch-days: 3
exclude:
- aws-lc-fips-sys
- aws-lc-rs
- aws-lc-sys
- rustls
- rustls-pki-types
- rustls-platform-verifier
- rustls-webpki
- package-ecosystem: rust-toolchain
directory: "/"
schedule:
interval: daily
time: "04:00"
open-pull-requests-limit: 10
commit-message:
prefix: "core:"
labels:
- dependencies
cooldown:
default-days: 3
#endregion
@@ -105,10 +53,6 @@ updates:
open-pull-requests-limit: 10
commit-message:
prefix: "web:"
cooldown:
default-days: 7
semver-major-days: 14
semver-patch-days: 3
groups:
sentry:
patterns:
@@ -172,10 +116,6 @@ updates:
open-pull-requests-limit: 10
commit-message:
prefix: "core, web:"
cooldown:
default-days: 7
semver-major-days: 14
semver-patch-days: 3
groups:
sentry:
patterns:
@@ -234,10 +174,6 @@ updates:
prefix: "website:"
labels:
- dependencies
cooldown:
default-days: 7
semver-major-days: 14
semver-patch-days: 3
groups:
docusaurus:
patterns:
@@ -276,10 +212,6 @@ updates:
prefix: "lifecycle/aws:"
labels:
- dependencies
cooldown:
default-days: 7
semver-major-days: 14
semver-patch-days: 3
#endregion
@@ -295,18 +227,6 @@ updates:
prefix: "core:"
labels:
- dependencies
cooldown:
default-days: 7
semver-major-days: 14
semver-patch-days: 3
exclude:
- "django"
- "cryptography"
- "pyjwt"
- "xmlsec"
- "lxml"
- "psycopg"
- "pyopenssl"
#endregion
@@ -314,7 +234,7 @@ updates:
- package-ecosystem: docker
directories:
- /lifecycle/container
- /
- /website
schedule:
interval: daily
@@ -324,14 +244,10 @@ updates:
prefix: "core:"
labels:
- dependencies
cooldown:
default-days: 3
- package-ecosystem: docker-compose
directories:
- /packages/client-go
- /packages/client-rust
- /packages/client-ts
# - /scripts # Maybe
- /scripts/api
- /tests/e2e
schedule:
interval: daily
@@ -341,7 +257,5 @@ updates:
prefix: "core:"
labels:
- dependencies
cooldown:
default-days: 3
#endregion

View File

@@ -26,7 +26,7 @@ REPLACE ME
If an API change has been made
- [ ] The API schema and clients have been updated (`make gen`)
- [ ] The API schema has been updated (`make gen-build`)
If changes to the frontend have been made

View File

@@ -43,8 +43,8 @@ jobs:
contents: read
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
- uses: docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a # v4.0.0
- uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
- uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # v3.7.0
- uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3
- name: prepare variables
uses: ./.github/actions/docker-push-variables
id: ev
@@ -56,19 +56,31 @@ jobs:
release: ${{ inputs.release }}
- name: Login to Docker Hub
if: ${{ inputs.registry_dockerhub }}
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3
with:
username: ${{ secrets.DOCKER_CORP_USERNAME }}
password: ${{ secrets.DOCKER_CORP_PASSWORD }}
- name: Login to GitHub Container Registry
if: ${{ inputs.registry_ghcr }}
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v5
with:
node-version-file: web/package.json
cache: "npm"
cache-dependency-path: web/package-lock.json
- uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6
with:
go-version-file: "go.mod"
- name: Generate API Clients
run: |
make gen-client-ts
make gen-client-go
- name: Build Docker Image
uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6
id: push
with:
context: .
@@ -83,7 +95,7 @@ jobs:
platforms: linux/${{ inputs.image_arch }}
cache-from: type=registry,ref=${{ steps.ev.outputs.attestImageNames }}:buildcache-${{ inputs.image_arch }}
cache-to: ${{ steps.ev.outputs.cacheTo }}
- uses: actions/attest-build-provenance@a2bbfa25375fe432b6a289bc6b6cd05ecd0c4c32 # v3
- uses: actions/attest-build-provenance@96278af6caaf10aea03fd8d33a09a777ca52d62f # v3
id: attest
if: ${{ steps.ev.outputs.shouldPush == 'true' }}
with:

View File

@@ -79,25 +79,25 @@ jobs:
image-name: ${{ inputs.image_name }}
- name: Login to Docker Hub
if: ${{ inputs.registry_dockerhub }}
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3
with:
username: ${{ secrets.DOCKER_CORP_USERNAME }}
password: ${{ secrets.DOCKER_CORP_PASSWORD }}
- name: Login to GitHub Container Registry
if: ${{ inputs.registry_ghcr }}
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- uses: int128/docker-manifest-create-action@fa55f72001a6c74b0f4997dca65c70d334905180 # v2
- uses: int128/docker-manifest-create-action@a39573caa37b6a8a03302d43b57c3f48635096e2 # v2
id: build
with:
tags: ${{ matrix.tag }}
sources: |
${{ steps.ev.outputs.attestImageNames }}@${{ needs.build-server-amd64.outputs.image-digest }}
${{ steps.ev.outputs.attestImageNames }}@${{ needs.build-server-arm64.outputs.image-digest }}
- uses: actions/attest-build-provenance@a2bbfa25375fe432b6a289bc6b6cd05ecd0c4c32 # v3
- uses: actions/attest-build-provenance@96278af6caaf10aea03fd8d33a09a777ca52d62f # v3
id: attest
with:
subject-name: ${{ steps.ev.outputs.attestImageNames }}

66
.github/workflows/api-ts-publish.yml vendored Normal file
View File

@@ -0,0 +1,66 @@
---
name: API - Publish Typescript client
on:
push:
branches: [main]
paths:
- "schema.yml"
workflow_dispatch:
permissions:
# Required for NPM OIDC trusted publisher
id-token: write
contents: read
jobs:
build:
runs-on: ubuntu-latest
steps:
- id: generate_token
uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf # v2
with:
app-id: ${{ secrets.GH_APP_ID }}
private-key: ${{ secrets.GH_APP_PRIVATE_KEY }}
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
with:
token: ${{ steps.generate_token.outputs.token }}
- uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v5
with:
node-version-file: web/package.json
registry-url: "https://registry.npmjs.org"
- name: Generate API Client
run: make gen-client-ts
- name: Publish package
working-directory: gen-ts-api/
run: |
npm i
npm publish --tag generated
- name: Upgrade /web
working-directory: web
run: |
export VERSION=`node -e 'console.log(require("../gen-ts-api/package.json").version)'`
npm i @goauthentik/api@$VERSION
- name: Upgrade /web/packages/sfe
working-directory: web/packages/sfe
run: |
export VERSION=`node -e 'console.log(require("../gen-ts-api/package.json").version)'`
npm i @goauthentik/api@$VERSION
- uses: peter-evans/create-pull-request@c0f553fe549906ede9cf27b5156039d195d2ece0 # v7
id: cpr
with:
token: ${{ steps.generate_token.outputs.token }}
branch: update-web-api-client
commit-message: "web: bump API Client version"
title: "web: bump API Client version"
body: "web: bump API Client version"
delete-branch: true
signoff: true
# ID from https://api.github.com/users/authentik-automation[bot]
author: authentik-automation[bot] <135050075+authentik-automation[bot]@users.noreply.github.com>
labels: dependencies
- uses: peter-evans/enable-pull-request-automerge@a660677d5469627102a1c1e11409dd063606628d # v3
with:
token: ${{ steps.generate_token.outputs.token }}
pull-request-number: ${{ steps.cpr.outputs.pull-request-number }}
merge-method: squash

View File

@@ -33,7 +33,7 @@ jobs:
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v5
- uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v5
with:
node-version-file: website/package.json
cache: "npm"
@@ -41,7 +41,7 @@ jobs:
- working-directory: website/
name: Install Dependencies
run: npm ci
- uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v4
- uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v4
with:
path: |
${{ github.workspace }}/website/api/.docusaurus
@@ -55,7 +55,7 @@ jobs:
env:
NODE_ENV: production
run: npm run build -w api
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v4
- uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v4
with:
name: api-docs
path: website/api/build
@@ -67,11 +67,11 @@ jobs:
- build
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v5
- uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v5
with:
name: api-docs
path: website/api/build
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v5
- uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v5
with:
node-version-file: website/package.json
cache: "npm"

View File

@@ -24,7 +24,7 @@ jobs:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
- name: Setup authentik env
uses: ./.github/actions/setup
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v5
- uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v5
with:
node-version-file: lifecycle/aws/package.json
cache: "npm"

View File

@@ -36,7 +36,7 @@ jobs:
NODE_ENV: production
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v5
- uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v5
with:
node-version-file: website/package.json
cache: "npm"
@@ -53,7 +53,7 @@ jobs:
NODE_ENV: production
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v5
- uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v5
with:
node-version-file: website/package.json
cache: "npm"
@@ -77,9 +77,9 @@ jobs:
with:
ref: ${{ github.event.pull_request.head.sha }}
- name: Set up QEMU
uses: docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a # v4.0.0
uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # v3.7.0
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3
- name: prepare variables
uses: ./.github/actions/docker-push-variables
id: ev
@@ -89,14 +89,14 @@ jobs:
image-name: ghcr.io/goauthentik/dev-docs
- name: Login to Container Registry
if: ${{ steps.ev.outputs.shouldPush == 'true' }}
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build Docker Image
id: push
uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6
with:
tags: ${{ steps.ev.outputs.imageTags }}
file: website/Dockerfile
@@ -105,7 +105,7 @@ jobs:
context: .
cache-from: type=registry,ref=ghcr.io/goauthentik/dev-docs:buildcache
cache-to: ${{ steps.ev.outputs.shouldPush == 'true' && 'type=registry,ref=ghcr.io/goauthentik/dev-docs:buildcache,mode=max' || '' }}
- uses: actions/attest-build-provenance@a2bbfa25375fe432b6a289bc6b6cd05ecd0c4c32 # v3
- uses: actions/attest-build-provenance@96278af6caaf10aea03fd8d33a09a777ca52d62f # v3
id: attest
if: ${{ steps.ev.outputs.shouldPush == 'true' }}
with:

View File

@@ -6,10 +6,6 @@ on:
schedule:
# Every night at 3am
- cron: "0 3 * * *"
pull_request:
paths:
# Needs to refer to itself
- .github/workflows/ci-main-daily.yml
jobs:
test-container:
@@ -19,20 +15,14 @@ jobs:
matrix:
version:
- docs
- version-2025-12
- version-2026-2
- version-2025-4
- version-2025-2
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
- run: |
set -euo pipefail
current="$(pwd)"
dir="/tmp/authentik/${{ matrix.version }}"
# 2025.12 still serves the legacy docker-compose filename; newer sites use compose.yml.
compose_path="compose.yml"
if [ "${{ matrix.version }}" = "version-2025-12" ]; then
compose_path="docker-compose.yml"
fi
mkdir -p "${dir}/lifecycle/container"
cd "${dir}"
wget "https://${{ matrix.version }}.goauthentik.io/${compose_path}" -O "${dir}/lifecycle/container/compose.yml"
"${current}/scripts/test_docker.sh"
mkdir -p $dir
cd $dir
wget https://${{ matrix.version }}.goauthentik.io/compose.yml
${current}/scripts/test_docker.sh

View File

@@ -28,52 +28,20 @@ jobs:
strategy:
fail-fast: false
matrix:
include:
- job: bandit
deps: python
- job: black
deps: python
- job: spellcheck
deps: node
- job: pending-migrations
deps: python,runtime
- job: ruff
deps: python
- job: mypy
deps: python
- job: cargo-deny
deps: rust
- job: cargo-machete
deps: rust
- job: clippy
deps: rust
- job: rustfmt
deps: rust-nightly
job:
- bandit
- black
- codespell
- pending-migrations
- ruff
- mypy
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
- name: Setup authentik env
uses: ./.github/actions/setup
with:
dependencies: ${{ matrix.deps }}
- name: run job
run: make ci-lint-${{ matrix.job }}
test-gen:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
with:
ref: ${{ github.event.pull_request.head.sha }}
- name: Setup authentik env
uses: ./.github/actions/setup
with:
dependencies: "system,python,go,node,runtime,rust-nightly"
- name: generate schema
run: make migrate gen-build
- name: generate API clients
run: make gen-clients
- name: ensure schema is up-to-date
run: git diff --exit-code -- schema.yml blueprints/schema.json packages/client-go packages/client-rust packages/client-ts
run: uv run make ci-${{ matrix.job }}
test-migrations:
runs-on: ubuntu-latest
steps:
@@ -127,10 +95,7 @@ jobs:
with:
postgresql_version: ${{ matrix.psql }}
- name: run migrations to stable
run: |
docker ps
docker logs setup-postgresql-1
uv run python -m lifecycle.migrate
run: uv run python -m lifecycle.migrate
- name: checkout current code
run: |
set -x
@@ -195,11 +160,10 @@ jobs:
- name: Setup authentik env
uses: ./.github/actions/setup
- name: Create k8s Kind Cluster
uses: helm/kind-action@ef37e7f390d99f746eb8b610417061a60e82a6cc # v1.14.0
uses: helm/kind-action@92086f6be054225fa813e0a4b13787fc9088faab # v1.13.0
- name: run integration
run: |
uv run coverage run manage.py test tests/integration
uv run coverage combine
uv run coverage xml
- uses: ./.github/actions/test-results
if: ${{ always() }}
@@ -215,60 +179,47 @@ jobs:
job:
- name: proxy
glob: tests/e2e/test_provider_proxy*
profiles: selenium
- name: oauth
glob: tests/e2e/test_provider_oauth2* tests/e2e/test_source_oauth*
profiles: selenium
- name: oauth-oidc
glob: tests/e2e/test_provider_oidc*
profiles: selenium
- name: saml
glob: tests/e2e/test_provider_saml* tests/e2e/test_source_saml*
profiles: selenium
- name: ldap
glob: tests/e2e/test_provider_ldap* tests/e2e/test_source_ldap*
- name: rac
glob: tests/e2e/test_provider_rac*
profiles: selenium
- name: ws-fed
glob: tests/e2e/test_provider_ws_fed*
profiles: selenium
- name: radius
glob: tests/e2e/test_provider_radius*
- name: scim
glob: tests/e2e/test_source_scim*
- name: flows
glob: tests/e2e/test_flows*
profiles: selenium
- name: endpoints
glob: tests/e2e/test_endpoints_*
profiles: selenium
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
- name: Setup authentik env
uses: ./.github/actions/setup
- name: Setup e2e env
env:
COMPOSE_PROFILES: ${{ matrix.job.profiles }}
- name: Setup e2e env (chrome, etc)
run: |
docker compose -f tests/e2e/compose.yml up -d --quiet-pull
- id: cache-web
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v4
if: contains(matrix.job.profiles, 'selenium')
uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v4
with:
path: web/dist
key: ${{ runner.os }}-web-${{ hashFiles('web/package-lock.json', 'package-lock.json', 'web/src/**', 'web/packages/sfe/src/**') }}-b
- name: prepare web ui
if: steps.cache-web.outputs.cache-hit != 'true' && contains(matrix.job.profiles, 'selenium')
if: steps.cache-web.outputs.cache-hit != 'true'
working-directory: web
run: |
npm ci
make -C .. gen-client-ts
npm run build
npm run build:sfe
- name: run e2e
run: |
uv run coverage run manage.py test ${{ matrix.job.glob }}
uv run coverage combine
uv run coverage xml
- uses: ./.github/actions/test-results
if: ${{ always() }}
@@ -282,32 +233,22 @@ jobs:
fail-fast: false
matrix:
job:
- name: oidc_basic
glob: tests/openid_conformance/test_oidc_basic.py
- name: oidc_implicit
glob: tests/openid_conformance/test_oidc_implicit.py
- name: oidc_rp-initiated
glob: tests/openid_conformance/test_oidc_rp_initiated.py
- name: oidc_frontchannel
glob: tests/openid_conformance/test_oidc_frontchannel.py
- name: oidc_backchannel
glob: tests/openid_conformance/test_oidc_backchannel.py
- name: ssf_transmitter
glob: tests/openid_conformance/test_ssf_transmitter.py
- name: basic
glob: tests/openid_conformance/test_basic.py
- name: implicit
glob: tests/openid_conformance/test_implicit.py
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
- name: Setup authentik env
uses: ./.github/actions/setup
- name: Setup e2e env (chrome, etc)
env:
COMPOSE_PROFILES: selenium
run: |
docker compose -f tests/e2e/compose.yml up -d --quiet-pull
- name: Setup conformance suite
run: |
docker compose -f tests/openid_conformance/compose.yml up -d --quiet-pull
- id: cache-web
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v4
uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v4
with:
path: web/dist
key: ${{ runner.os }}-web-${{ hashFiles('web/package-lock.json', 'web/src/**', 'web/packages/sfe/src/**') }}-b
@@ -316,50 +257,26 @@ jobs:
working-directory: web
run: |
npm ci
make -C .. gen-client-ts
npm run build
npm run build:sfe
- name: run conformance
run: |
uv run coverage run manage.py test ${{ matrix.job.glob }}
uv run coverage combine
uv run coverage xml
- uses: ./.github/actions/test-results
if: ${{ always() }}
with:
flags: conformance
- if: ${{ !cancelled() }}
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
with:
name: conformance-certification-${{ matrix.job.name }}
path: tests/openid_conformance/exports/
test-rust:
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
- name: Setup authentik env
uses: ./.github/actions/setup
with:
dependencies: rust,runtime
- name: run tests
run: |
cargo llvm-cov --no-report nextest --workspace
cargo llvm-cov report --codecov --output-path target/llvm-cov-target/rust.json
- uses: ./.github/actions/test-results
if: ${{ always() }}
with:
files: target/llvm-cov-target/rust.json
flags: rust
- if: ${{ !cancelled() }}
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: test-rust
path: target/llvm-cov-target/rust.json
ci-core-mark:
if: always()
needs:
- lint
- test-gen
- test-migrations
- test-migrations-from-stable
- test-unittest

View File

@@ -22,7 +22,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6
- uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6
with:
go-version-file: "go.mod"
- name: Prepare and generate API
@@ -31,6 +31,8 @@ jobs:
mkdir -p web/dist
mkdir -p website/help
touch web/dist/test website/help/test
- name: Generate API
run: make gen-client-go
- name: golangci-lint
uses: golangci/golangci-lint-action@1e7e51e771db61008b38414a730f564565cf7c20 # v8
with:
@@ -41,11 +43,13 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6
- uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6
with:
go-version-file: "go.mod"
- name: Setup authentik env
uses: ./.github/actions/setup
- name: Generate API
run: make gen-client-go
- name: prepare database
run: |
uv run make migrate
@@ -86,9 +90,9 @@ jobs:
with:
ref: ${{ github.event.pull_request.head.sha }}
- name: Set up QEMU
uses: docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a # v4.0.0
uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # v3.7.0
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3
- name: prepare variables
uses: ./.github/actions/docker-push-variables
id: ev
@@ -98,14 +102,16 @@ jobs:
image-name: ghcr.io/goauthentik/dev-${{ matrix.type }}
- name: Login to Container Registry
if: ${{ steps.ev.outputs.shouldPush == 'true' }}
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Generate API
run: make gen-client-go
- name: Build Docker Image
id: push
uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6
with:
tags: ${{ steps.ev.outputs.imageTags }}
file: lifecycle/container/${{ matrix.type }}.Dockerfile
@@ -116,7 +122,7 @@ jobs:
context: .
cache-from: type=registry,ref=ghcr.io/goauthentik/dev-${{ matrix.type }}:buildcache
cache-to: ${{ steps.ev.outputs.shouldPush == 'true' && format('type=registry,ref=ghcr.io/goauthentik/dev-{0}:buildcache,mode=max', matrix.type) || '' }}
- uses: actions/attest-build-provenance@a2bbfa25375fe432b6a289bc6b6cd05ecd0c4c32 # v3
- uses: actions/attest-build-provenance@96278af6caaf10aea03fd8d33a09a777ca52d62f # v3
id: attest
if: ${{ steps.ev.outputs.shouldPush == 'true' }}
with:
@@ -142,14 +148,16 @@ jobs:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
with:
ref: ${{ github.event.pull_request.head.sha }}
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6
- uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6
with:
go-version-file: "go.mod"
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v5
- uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v5
with:
node-version-file: web/package.json
cache: "npm"
cache-dependency-path: web/package-lock.json
- name: Generate API
run: make gen-client-go
- name: Build web
working-directory: web/
run: |

View File

@@ -32,7 +32,7 @@ jobs:
project: web
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v5
- uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v5
with:
node-version-file: ${{ matrix.project }}/package.json
cache: "npm"
@@ -40,6 +40,8 @@ jobs:
- working-directory: ${{ matrix.project }}/
run: |
npm ci
- name: Generate API
run: make gen-client-ts
- name: Lint
working-directory: ${{ matrix.project }}/
run: npm run ${{ matrix.command }}
@@ -47,13 +49,15 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v5
- uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v5
with:
node-version-file: web/package.json
cache: "npm"
cache-dependency-path: web/package-lock.json
- working-directory: web/
run: npm ci
- name: Generate API
run: make gen-client-ts
- name: build
working-directory: web/
run: npm run build
@@ -73,13 +77,15 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v5
- uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v5
with:
node-version-file: web/package.json
cache: "npm"
cache-dependency-path: web/package-lock.json
- working-directory: web/
run: npm ci
- name: Generate API
run: make gen-client-ts
- name: test
working-directory: web/
run: npm run test || exit 0

View File

@@ -29,20 +29,20 @@ jobs:
github.event.pull_request.head.repo.full_name == github.repository)
steps:
- id: generate_token
uses: actions/create-github-app-token@1b10c78c7865c340bc4f6099eb2f838309f1e8c3 # v2
uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf # v2
with:
app-id: ${{ secrets.GH_APP_ID }}
private-key: ${{ secrets.GH_APP_PRIV_KEY }}
private-key: ${{ secrets.GH_APP_PRIVATE_KEY }}
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
with:
token: ${{ steps.generate_token.outputs.token }}
- name: Compress images
id: compress
uses: calibreapp/image-actions@e2cc8db5d49c849e00844dfebf01438318e96fa2 # main
uses: calibreapp/image-actions@420075c115b26f8785e293c5bd5bef0911c506e5 # main
with:
GITHUB_TOKEN: ${{ steps.generate_token.outputs.token }}
compressOnly: ${{ github.event_name != 'pull_request' }}
- uses: peter-evans/create-pull-request@5f6978faf089d4d20b00c7766989d076bb2fc7f1 # v7
- uses: peter-evans/create-pull-request@c0f553fe549906ede9cf27b5156039d195d2ece0 # v7
if: "${{ github.event_name != 'pull_request' && steps.compress.outputs.markdown != '' }}"
id: cpr
with:

View File

@@ -16,17 +16,17 @@ jobs:
runs-on: ubuntu-latest
steps:
- id: generate_token
uses: actions/create-github-app-token@1b10c78c7865c340bc4f6099eb2f838309f1e8c3 # v2
uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf # v2
with:
app-id: ${{ secrets.GH_APP_ID }}
private-key: ${{ secrets.GH_APP_PRIV_KEY }}
private-key: ${{ secrets.GH_APP_PRIVATE_KEY }}
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
with:
token: ${{ steps.generate_token.outputs.token }}
- name: Setup authentik env
uses: ./.github/actions/setup
- run: uv run ak update_webauthn_mds
- uses: peter-evans/create-pull-request@5f6978faf089d4d20b00c7766989d076bb2fc7f1 # v7
- uses: peter-evans/create-pull-request@c0f553fe549906ede9cf27b5156039d195d2ece0 # v7
id: cpr
with:
token: ${{ steps.generate_token.outputs.token }}

View File

@@ -10,11 +10,11 @@ jobs:
steps:
- id: app-token
name: Generate app token
uses: actions/create-github-app-token@1b10c78c7865c340bc4f6099eb2f838309f1e8c3 # v2
uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf # v2
if: ${{ env.GH_APP_ID != '' }}
with:
app-id: ${{ secrets.GH_APP_ID }}
private-key: ${{ secrets.GH_APP_PRIV_KEY }}
private-key: ${{ secrets.GH_APP_PRIVATE_KEY }}
env:
GH_APP_ID: ${{ secrets.GH_APP_ID }}
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5

View File

@@ -16,10 +16,10 @@ jobs:
runs-on: ubuntu-latest
steps:
- id: generate_token
uses: actions/create-github-app-token@1b10c78c7865c340bc4f6099eb2f838309f1e8c3 # v2
uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf # v2
with:
app-id: ${{ secrets.GH_APP_ID }}
private-key: ${{ secrets.GH_APP_PRIV_KEY }}
private-key: ${{ secrets.GH_APP_PRIVATE_KEY }}
- name: Delete 'dev' containers older than a week
uses: snok/container-retention-policy@3b0972b2276b171b212f8c4efbca59ebba26eceb # v3.0.1
with:

View File

@@ -29,19 +29,18 @@ jobs:
- packages/eslint-config
- packages/prettier-config
- packages/docusaurus-config
- packages/logger-js
- packages/esbuild-plugin-live-reload
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
with:
fetch-depth: 2
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v5
- uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v5
with:
node-version-file: ${{ matrix.package }}/package.json
registry-url: "https://registry.npmjs.org"
- name: Get changed files
id: changed-files
uses: tj-actions/changed-files@9426d40962ed5378910ee2e21d5f8c6fcbf2dd96 # 24d32ffd492484c1d75e0c0b894501ddb9d30d62
uses: tj-actions/changed-files@e0021407031f5be11a464abee9a0776171c79891 # 24d32ffd492484c1d75e0c0b894501ddb9d30d62
with:
files: |
${{ matrix.package }}/package.json

View File

@@ -29,10 +29,10 @@ jobs:
steps:
- id: app-token
name: Generate app token
uses: actions/create-github-app-token@1b10c78c7865c340bc4f6099eb2f838309f1e8c3 # v2
uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf # v2
with:
app-id: ${{ secrets.GH_APP_ID }}
private-key: ${{ secrets.GH_APP_PRIV_KEY }}
private-key: ${{ secrets.GH_APP_PRIVATE_KEY }}
- name: Checkout main
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
with:
@@ -57,10 +57,10 @@ jobs:
runs-on: ubuntu-latest
steps:
- id: generate_token
uses: actions/create-github-app-token@1b10c78c7865c340bc4f6099eb2f838309f1e8c3 # v2
uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf # v2
with:
app-id: ${{ secrets.GH_APP_ID }}
private-key: ${{ secrets.GH_APP_PRIV_KEY }}
private-key: ${{ secrets.GH_APP_PRIVATE_KEY }}
- name: Checkout main
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
with:
@@ -73,7 +73,7 @@ jobs:
- name: Bump version
run: "make bump version=${{ inputs.next_version }}.0-rc1"
- name: Create pull request
uses: peter-evans/create-pull-request@5f6978faf089d4d20b00c7766989d076bb2fc7f1 # v7
uses: peter-evans/create-pull-request@c0f553fe549906ede9cf27b5156039d195d2ece0 # v7
with:
token: ${{ steps.generate_token.outputs.token }}
branch: release-bump-${{ inputs.next_version }}

View File

@@ -33,9 +33,9 @@ jobs:
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
- name: Set up QEMU
uses: docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a # v4.0.0
uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # v3.7.0
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3
- name: prepare variables
uses: ./.github/actions/docker-push-variables
id: ev
@@ -44,21 +44,21 @@ jobs:
with:
image-name: ghcr.io/goauthentik/docs
- name: Login to GitHub Container Registry
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build Docker Image
id: push
uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6
with:
tags: ${{ steps.ev.outputs.imageTags }}
file: website/Dockerfile
push: true
platforms: linux/amd64,linux/arm64
context: .
- uses: actions/attest-build-provenance@a2bbfa25375fe432b6a289bc6b6cd05ecd0c4c32 # v3
- uses: actions/attest-build-provenance@96278af6caaf10aea03fd8d33a09a777ca52d62f # v3
id: attest
if: true
with:
@@ -84,18 +84,18 @@ jobs:
- rac
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6
- uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6
with:
go-version-file: "go.mod"
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v5
- uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v5
with:
node-version-file: web/package.json
cache: "npm"
cache-dependency-path: web/package-lock.json
- name: Set up QEMU
uses: docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a # v4.0.0
uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # v3.7.0
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3
- name: prepare variables
uses: ./.github/actions/docker-push-variables
id: ev
@@ -103,19 +103,23 @@ jobs:
DOCKER_USERNAME: ${{ secrets.DOCKER_CORP_USERNAME }}
with:
image-name: ghcr.io/goauthentik/${{ matrix.type }},authentik/${{ matrix.type }}
- name: Generate API Clients
run: |
make gen-client-ts
make gen-client-go
- name: Docker Login Registry
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3
with:
username: ${{ secrets.DOCKER_CORP_USERNAME }}
password: ${{ secrets.DOCKER_CORP_PASSWORD }}
- name: Login to GitHub Container Registry
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build Docker Image
uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6
id: push
with:
push: true
@@ -125,7 +129,7 @@ jobs:
file: lifecycle/container/${{ matrix.type }}.Dockerfile
platforms: linux/amd64,linux/arm64
context: .
- uses: actions/attest-build-provenance@a2bbfa25375fe432b6a289bc6b6cd05ecd0c4c32 # v3
- uses: actions/attest-build-provenance@96278af6caaf10aea03fd8d33a09a777ca52d62f # v3
id: attest
with:
subject-name: ${{ steps.ev.outputs.attestImageNames }}
@@ -148,21 +152,18 @@ jobs:
goarch: [amd64, arm64]
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6
- uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6
with:
go-version-file: "go.mod"
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v5
- uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v5
with:
node-version-file: web/package.json
cache: "npm"
cache-dependency-path: web/package-lock.json
- name: Install web dependencies
working-directory: web/
run: |
npm ci
- name: Build web
working-directory: web/
run: |
npm ci
npm run build-proxy
- name: Build outpost
run: |
@@ -172,7 +173,7 @@ jobs:
export CGO_ENABLED=0
go build -tags=outpost_static_embed -v -o ./authentik-outpost-${{ matrix.type }}_${{ matrix.goos }}_${{ matrix.goarch }} ./cmd/${{ matrix.type }}
- name: Upload binaries to release
uses: svenstaro/upload-release-action@29e53e917877a24fad85510ded594ab3c9ca12de # v2
uses: svenstaro/upload-release-action@6b7fa9f267e90b50a19fef07b3596790bb941741 # v2
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
file: ./authentik-outpost-${{ matrix.type }}_${{ matrix.goos }}_${{ matrix.goarch }}
@@ -191,7 +192,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
- uses: aws-actions/configure-aws-credentials@ec61189d14ec14c8efccab744f656cffd0e33f37 # v6.1.0
- uses: aws-actions/configure-aws-credentials@61815dcd50bd041e203e49132bacad1fd04d2708 # v5
with:
role-to-assume: "arn:aws:iam::016170277896:role/github_goauthentik_authentik"
aws-region: ${{ env.AWS_REGION }}
@@ -209,12 +210,12 @@ jobs:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
- name: Run test suite in final docker images
run: |
echo "PG_PASS=$(openssl rand 32 | base64 -w 0)" >> lifecycle/container/.env
echo "AUTHENTIK_SECRET_KEY=$(openssl rand 32 | base64 -w 0)" >> lifecycle/container/.env
docker compose -f lifecycle/container/compose.yml pull -q
docker compose -f lifecycle/container/compose.yml up --no-start
docker compose -f lifecycle/container/compose.yml start postgresql
docker compose -f lifecycle/container/compose.yml run -u root server test-all
echo "PG_PASS=$(openssl rand 32 | base64 -w 0)" >> .env
echo "AUTHENTIK_SECRET_KEY=$(openssl rand 32 | base64 -w 0)" >> .env
docker compose pull -q
docker compose up --no-start
docker compose start postgresql
docker compose run -u root server test-all
sentry-release:
needs:
- build-server
@@ -236,7 +237,7 @@ jobs:
container=$(docker container create ${{ steps.ev.outputs.imageMainName }})
docker cp ${container}:web/ .
- name: Create a Sentry.io release
uses: getsentry/action-release@5657c9e888b4e2cc85f4d29143ea4131fde4a73a # v3
uses: getsentry/action-release@dab6548b3c03c4717878099e43782cf5be654289 # v3
continue-on-error: true
env:
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}

View File

@@ -67,10 +67,10 @@ jobs:
steps:
- id: app-token
name: Generate app token
uses: actions/create-github-app-token@1b10c78c7865c340bc4f6099eb2f838309f1e8c3 # v2
uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf # v2
with:
app-id: ${{ secrets.GH_APP_ID }}
private-key: ${{ secrets.GH_APP_PRIV_KEY }}
private-key: ${{ secrets.GH_APP_PRIVATE_KEY }}
- id: get-user-id
name: Get GitHub app user ID
run: echo "user-id=$(gh api "/users/${{ steps.app-token.outputs.app-slug }}[bot]" --jq .id)" >> "$GITHUB_OUTPUT"
@@ -91,12 +91,11 @@ jobs:
# ID from https://api.github.com/users/authentik-automation[bot]
git config --global user.name '${{ steps.app-token.outputs.app-slug }}[bot]'
git config --global user.email '${{ steps.get-user-id.outputs.user-id }}+${{ steps.app-token.outputs.app-slug }}[bot]@users.noreply.github.com'
git pull
git commit -a -m "release: ${{ inputs.version }}" --allow-empty
git tag "version/${{ inputs.version }}" HEAD -m "version/${{ inputs.version }}"
git push --follow-tags
- name: Create Release
uses: softprops/action-gh-release@b4309332981a82ec1c5618f44dd2e27cc8bfbfda # v3.0.0
uses: softprops/action-gh-release@a06a81a03ee405af7f2048a818ed3f03bbf83c7b # v2.5.0
with:
token: "${{ steps.app-token.outputs.token }}"
tag_name: "version/${{ inputs.version }}"
@@ -115,10 +114,10 @@ jobs:
steps:
- id: app-token
name: Generate app token
uses: actions/create-github-app-token@1b10c78c7865c340bc4f6099eb2f838309f1e8c3 # v2
uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf # v2
with:
app-id: ${{ secrets.GH_APP_ID }}
private-key: ${{ secrets.GH_APP_PRIV_KEY }}
private-key: ${{ secrets.GH_APP_PRIVATE_KEY }}
repositories: helm
- id: get-user-id
name: Get GitHub app user ID
@@ -137,7 +136,7 @@ jobs:
sed -E -i 's/[0-9]{4}\.[0-9]{1,2}\.[0-9]+$/${{ inputs.version }}/' charts/authentik/Chart.yaml
./scripts/helm-docs.sh
- name: Create pull request
uses: peter-evans/create-pull-request@5f6978faf089d4d20b00c7766989d076bb2fc7f1 # v7
uses: peter-evans/create-pull-request@c0f553fe549906ede9cf27b5156039d195d2ece0 # v7
with:
token: "${{ steps.app-token.outputs.token }}"
branch: bump-${{ inputs.version }}
@@ -157,10 +156,10 @@ jobs:
steps:
- id: app-token
name: Generate app token
uses: actions/create-github-app-token@1b10c78c7865c340bc4f6099eb2f838309f1e8c3 # v2
uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf # v2
with:
app-id: ${{ secrets.GH_APP_ID }}
private-key: ${{ secrets.GH_APP_PRIV_KEY }}
private-key: ${{ secrets.GH_APP_PRIVATE_KEY }}
repositories: version
- id: get-user-id
name: Get GitHub app user ID
@@ -175,28 +174,24 @@ jobs:
if: "${{ inputs.release_reason == 'feature' }}"
run: |
changelog_url="https://docs.goauthentik.io/docs/releases/${{ needs.check-inputs.outputs.major_version }}"
reason="${{ inputs.release_reason }}"
jq \
--arg version "${{ inputs.version }}" \
--arg changelog "See ${changelog_url}" \
--arg changelog_url "${changelog_url}" \
--arg reason "${reason}" \
'.stable.version = $version | .stable.changelog = $changelog | .stable.changelog_url = $changelog_url | .stable.reason = $reason' version.json > version.new.json
'.stable.version = $version | .stable.changelog = $changelog | .stable.changelog_url = $changelog_url' version.json > version.new.json
mv version.new.json version.json
- name: Bump version
if: "${{ inputs.release_reason != 'feature' }}"
run: |
changelog_url="https://docs.goauthentik.io/docs/releases/${{ needs.check-inputs.outputs.major_version }}#fixed-in-$(echo -n ${{ inputs.version}} | sed 's/\.//g')"
reason="${{ inputs.release_reason }}"
jq \
--arg version "${{ inputs.version }}" \
--arg changelog "See ${changelog_url}" \
--arg changelog_url "${changelog_url}" \
--arg reason "${reason}" \
'.stable.version = $version | .stable.changelog = $changelog | .stable.changelog_url = $changelog_url | .stable.reason = $reason' version.json > version.new.json
'.stable.version = $version | .stable.changelog = $changelog | .stable.changelog_url = $changelog_url' version.json > version.new.json
mv version.new.json version.json
- name: Create pull request
uses: peter-evans/create-pull-request@5f6978faf089d4d20b00c7766989d076bb2fc7f1 # v7
uses: peter-evans/create-pull-request@c0f553fe549906ede9cf27b5156039d195d2ece0 # v7
with:
token: "${{ steps.app-token.outputs.token }}"
branch: bump-${{ inputs.version }}

View File

@@ -15,11 +15,11 @@ jobs:
runs-on: ubuntu-latest
steps:
- id: generate_token
uses: actions/create-github-app-token@1b10c78c7865c340bc4f6099eb2f838309f1e8c3 # v2
uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf # v2
with:
app-id: ${{ secrets.GH_APP_ID }}
private-key: ${{ secrets.GH_APP_PRIV_KEY }}
- uses: actions/stale@b5d41d4e1d5dceea10e7104786b73624c18a190f # v10
private-key: ${{ secrets.GH_APP_PRIVATE_KEY }}
- uses: actions/stale@997185467fa4f803885201cee163a9f38240193d # v10
with:
repo-token: ${{ steps.generate_token.outputs.token }}
days-before-stale: 60

View File

@@ -21,10 +21,10 @@ jobs:
steps:
- id: generate_token
if: ${{ github.event_name != 'pull_request' }}
uses: actions/create-github-app-token@1b10c78c7865c340bc4f6099eb2f838309f1e8c3 # v2
uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf # v2
with:
app-id: ${{ secrets.GH_APP_ID }}
private-key: ${{ secrets.GH_APP_PRIV_KEY }}
private-key: ${{ secrets.GH_APP_PRIVATE_KEY }}
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
if: ${{ github.event_name != 'pull_request' }}
with:
@@ -33,6 +33,8 @@ jobs:
if: ${{ github.event_name == 'pull_request' }}
- name: Setup authentik env
uses: ./.github/actions/setup
- name: Generate API
run: make gen-client-ts
- name: run extract
run: |
uv run make i18n-extract
@@ -42,7 +44,7 @@ jobs:
make web-check-compile
- name: Create Pull Request
if: ${{ github.event_name != 'pull_request' }}
uses: peter-evans/create-pull-request@5f6978faf089d4d20b00c7766989d076bb2fc7f1 # v7
uses: peter-evans/create-pull-request@c0f553fe549906ede9cf27b5156039d195d2ece0 # v7
with:
token: ${{ steps.generate_token.outputs.token }}
branch: extract-compile-backend-translation

27
.gitignore vendored
View File

@@ -15,9 +15,6 @@ media
node_modules
.cspellcache
cspell-report.*
# If your build process includes running collectstatic, then you probably don't need or want to include staticfiles/
# in your Git repository. Update and uncomment the following line accordingly.
# <django-project-name>/staticfiles/
@@ -195,24 +192,6 @@ pyvenv.cfg
pip-selfcheck.json
# End of https://www.gitignore.io/api/python,django
# Created by https://www.toptal.com/developers/gitignore/api/rust
# Edit at https://www.toptal.com/developers/gitignore?templates=rust
### Rust ###
# Generated by Cargo
# will have compiled files and executables
debug/
target/
# These are backup files generated by rustfmt
**/*.rs.bk
# MSVC Windows builds of rustc generate these, which store debugging information
*.pdb
# End of https://www.toptal.com/developers/gitignore/api/rust
/static/
local.env.yml
@@ -220,6 +199,7 @@ media/
*mmdb
.idea/
/gen-*/
data/
# Local Netlify folder
@@ -229,11 +209,6 @@ source_docs/
### Golang ###
/vendor/
server
proxy
ldap
rac
radius
### Docker ###
tests/openid_conformance/exports/*.zip

View File

@@ -1,7 +1,6 @@
# Prettier Ignorefile
## Static Files
CODEOWNERS
**/LICENSE
authentik/stages/**/*

View File

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

28
.vscode/settings.json vendored
View File

@@ -14,10 +14,6 @@
"[xml]": {
"editor.minimap.markSectionHeaderRegex": "<!--\\s*#\\bregion\\s*(?<separator>-?)\\s*(?<label>.*)\\s*-->"
},
"files.associations": {
// The built-in "ignore" language gives us enough syntax highlighting to make these files readable.
"**/dictionaries/*.txt": "ignore"
},
"todo-tree.tree.showCountsInTree": true,
"todo-tree.tree.showBadges": true,
"yaml.customTags": [
@@ -38,10 +34,10 @@
"!AtIndex scalar",
"!ParseJSON scalar"
],
"js/ts.preferences.importModuleSpecifier": "non-relative",
"js/ts.preferences.importModuleSpecifierEnding": "index",
"js/ts.tsdk.path": "./node_modules/typescript/lib",
"js/ts.tsdk.promptToUseWorkspaceVersion": true,
"typescript.preferences.importModuleSpecifier": "non-relative",
"typescript.preferences.importModuleSpecifierEnding": "index",
"typescript.tsdk": "./node_modules/typescript/lib",
"typescript.enablePromptUseWorkspaceTsdk": true,
"yaml.schemas": {
"./blueprints/schema.json": "blueprints/**/*.yaml"
},
@@ -53,17 +49,13 @@
"ignoreCase": false
}
],
"go.testFlags": ["-count=1"],
"go.testFlags": [
"-count=1"
],
"go.testEnvVars": {
"WORKSPACE_DIR": "${workspaceFolder}"
},
"github-actions.workflows.pinned.workflows": [".github/workflows/ci-main.yml"],
"search.exclude": {
"**/*.code-search": true,
"**/bower_components": true,
"**/node_modules": true,
"**/playwright-report/**": true,
"**/website/**/build": true,
"**/client-*": true
}
"github-actions.workflows.pinned.workflows": [
".github/workflows/ci-main.yml"
]
}

View File

@@ -3,7 +3,6 @@
# Backend
authentik/ @goauthentik/backend
blueprints/ @goauthentik/backend
src/ @goauthentik/backend
cmd/ @goauthentik/backend
internal/ @goauthentik/backend
lifecycle/ @goauthentik/backend
@@ -12,13 +11,8 @@ scripts/ @goauthentik/backend
tests/ @goauthentik/backend
pyproject.toml @goauthentik/backend
uv.lock @goauthentik/backend
Cargo.toml @goauthentik/backend
Cargo.lock @goauthentik/backend
build.rs @goauthentik/backend
go.mod @goauthentik/backend
go.sum @goauthentik/backend
.cargo/ @goauthentik/backend
rust-toolchain.toml @goauthentik/backend
# Infrastructure
.github/ @goauthentik/infrastructure
lifecycle/aws/ @goauthentik/infrastructure
@@ -28,23 +22,18 @@ Makefile @goauthentik/infrastructure
.editorconfig @goauthentik/infrastructure
CODEOWNERS @goauthentik/infrastructure
# Backend packages
packages/ak-* @goauthentik/backend
packages/client-rust @goauthentik/backend
packages/django-channels-postgres @goauthentik/backend
packages/django-postgres-cache @goauthentik/backend
packages/django-dramatiq-postgres @goauthentik/backend
# Web packages
tsconfig.json @goauthentik/frontend
package.json @goauthentik/frontend
package-lock.json @goauthentik/frontend
packages/package.json @goauthentik/frontend
packages/package-lock.json @goauthentik/frontend
packages/client-ts @goauthentik/frontend
packages/docusaurus-config @goauthentik/frontend
packages/esbuild-plugin-live-reload @goauthentik/frontend
packages/eslint-config @goauthentik/frontend
packages/prettier-config @goauthentik/frontend
packages/logger-js @goauthentik/frontend
packages/tsconfig @goauthentik/frontend
# Web
web/ @goauthentik/frontend

5208
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,289 +0,0 @@
[workspace]
members = [
"packages/ak-axum",
"packages/ak-common",
"packages/client-rust",
"website/scripts/docsmg",
]
resolver = "3"
[workspace.package]
version = "2026.8.0-rc1"
authors = ["authentik Team <hello@goauthentik.io>"]
description = "Making authentication simple."
edition = "2024"
readme = "README.md"
homepage = "https://goauthentik.io"
repository = "https://github.com/goauthentik/authentik.git"
license-file = "LICENSE"
publish = false
[workspace.dependencies]
arc-swap = "= 1.9.1"
argh = "= 0.1.19"
axum-server = { version = "= 0.8.0", features = ["tls-rustls-no-provider"] }
aws-lc-rs = { version = "= 1.16.3", features = ["fips"] }
axum = { version = "= 0.8.9", features = ["http2", "macros", "ws"] }
clap = { version = "= 4.6.1", features = ["derive", "env"] }
client-ip = { version = "0.2.1", features = ["forwarded-header"] }
color-eyre = "= 0.6.5"
colored = "= 3.1.1"
config-rs = { package = "config", version = "= 0.15.22", default-features = false, features = [
"json",
"yaml",
] }
console-subscriber = "= 0.5.0"
dotenvy = "= 0.15.7"
durstr = "= 0.5.1"
eyre = "= 0.6.12"
forwarded-header-value = "= 0.1.1"
futures = "= 0.3.32"
glob = "= 0.3.3"
hyper-unix-socket = "= 0.6.1"
hyper-util = "= 0.1.20"
ipnet = { version = "= 2.12.0", features = ["serde"] }
json-subscriber = "= 0.2.8"
metrics = "= 0.24.5"
metrics-exporter-prometheus = { version = "= 0.18.3", default-features = false }
nix = { version = "= 0.31.2", features = ["hostname", "signal"] }
notify = "= 8.2.0"
pin-project-lite = "= 0.2.17"
pyo3 = "= 0.28.3"
pyo3-build-config = "= 0.28.3"
regex = "= 1.12.3"
reqwest = { version = "= 0.13.3", features = [
"form",
"json",
"multipart",
"query",
"rustls",
"stream",
] }
reqwest-middleware = { version = "= 0.5.1", features = [
"form",
"json",
"multipart",
"query",
"rustls",
] }
rustls = { version = "= 0.23.40", features = ["fips"] }
sentry = { version = "= 0.48.0", default-features = false, features = [
"backtrace",
"contexts",
"debug-images",
"panic",
"rustls",
"reqwest",
"tower",
"tracing",
] }
serde = { version = "= 1.0.228", features = ["derive"] }
serde_json = "= 1.0.149"
serde_repr = "= 0.1.20"
serde_with = { version = "= 3.18.0", default-features = false, features = [
"base64",
] }
sqlx = { version = "= 0.8.6", default-features = false, features = [
"runtime-tokio",
"tls-rustls-aws-lc-rs",
"postgres",
"derive",
"macros",
"uuid",
"chrono",
"ipnet",
"json",
] }
tempfile = "= 3.27.0"
thiserror = "= 2.0.18"
time = { version = "= 0.3.47", features = ["macros"] }
tokio = { version = "= 1.52.1", features = ["full", "tracing"] }
tokio-retry2 = "= 0.9.1"
tokio-rustls = "= 0.26.4"
tokio-util = { version = "= 0.7.18", features = ["full"] }
tower = "= 0.5.3"
tower-http = { version = "= 0.6.8", features = ["timeout"] }
tracing = "= 0.1.44"
tracing-error = "= 0.2.1"
tracing-subscriber = { version = "= 0.3.23", features = [
"env-filter",
"json",
"local-time",
"tracing-log",
] }
url = "= 2.5.8"
uuid = { version = "= 1.23.1", features = ["serde", "v4"] }
which = "= 8.0.2"
ak-axum = { package = "authentik-axum", version = "2026.8.0-rc1", path = "./packages/ak-axum" }
ak-client = { package = "authentik-client", version = "2026.8.0-rc1", path = "./packages/client-rust" }
ak-common = { package = "authentik-common", version = "2026.8.0-rc1", path = "./packages/ak-common", default-features = false }
[workspace.lints.rust]
ambiguous_negative_literals = "warn"
closure_returning_async_block = "warn"
macro_use_extern_crate = "deny"
# must_not_suspend = "deny", unstable see https://github.com/rust-lang/rust/issues/83310
non_ascii_idents = "deny"
redundant_imports = "warn"
semicolon_in_expressions_from_macros = "warn"
trivial_casts = "warn"
trivial_numeric_casts = "warn"
unit_bindings = "warn"
unreachable_pub = "warn"
unsafe_code = "deny"
unused_extern_crates = "warn"
unused_import_braces = "warn"
unused_lifetimes = "warn"
unused_macro_rules = "warn"
unused_qualifications = "warn"
[workspace.lints.rustdoc]
unescaped_backticks = "warn"
[workspace.lints.clippy]
### enable all lints
cargo = { priority = -1, level = "warn" }
complexity = { priority = -1, level = "warn" }
correctness = { priority = -1, level = "warn" }
nursery = { priority = -1, level = "warn" }
pedantic = { priority = -1, level = "warn" }
perf = { priority = -1, level = "warn" }
# Those are too restrictive and disabled by default, however we enable some below
# restriction = { priority = -1, level = "warn" }
style = { priority = -1, level = "warn" }
suspicious = { priority = -1, level = "warn" }
### and disable the ones we don't want
### cargo group
multiple_crate_versions = "allow"
### pedantic group
missing_errors_doc = "allow"
missing_panics_doc = "allow"
must_use_candidate = "allow"
redundant_closure_for_method_calls = "allow"
struct_field_names = "allow"
too_many_lines = "allow"
### nursery
missing_const_for_fn = "allow"
option_if_let_else = "allow"
redundant_pub_crate = "allow"
significant_drop_tightening = "allow"
### restriction group
allow_attributes = "warn"
allow_attributes_without_reason = "warn"
as_conversions = "warn"
as_pointer_underscore = "warn"
as_underscore = "warn"
assertions_on_result_states = "warn"
clone_on_ref_ptr = "warn"
create_dir = "warn"
dbg_macro = "warn"
default_numeric_fallback = "warn"
disallowed_script_idents = "warn"
empty_drop = "warn"
empty_enum_variants_with_brackets = "warn"
empty_structs_with_brackets = "warn"
error_impl_error = "warn"
exit = "warn"
filetype_is_file = "warn"
float_cmp_const = "warn"
fn_to_numeric_cast_any = "warn"
get_unwrap = "warn"
if_then_some_else_none = "warn"
impl_trait_in_params = "warn"
infinite_loop = "warn"
lossy_float_literal = "warn"
map_with_unused_argument_over_ranges = "warn"
mem_forget = "warn"
missing_asserts_for_indexing = "warn"
missing_trait_methods = "warn"
mixed_read_write_in_expression = "warn"
mutex_atomic = "warn"
mutex_integer = "warn"
needless_raw_strings = "warn"
non_zero_suggestions = "warn"
panic_in_result_fn = "warn"
pathbuf_init_then_push = "warn"
print_stdout = "warn"
rc_buffer = "warn"
redundant_test_prefix = "warn"
redundant_type_annotations = "warn"
ref_patterns = "warn"
renamed_function_params = "warn"
rest_pat_in_fully_bound_structs = "warn"
return_and_then = "warn"
same_name_method = "warn"
semicolon_inside_block = "warn"
str_to_string = "warn"
string_add = "warn"
suspicious_xor_used_as_pow = "warn"
tests_outside_test_module = "warn"
todo = "warn"
try_err = "warn"
undocumented_unsafe_blocks = "warn"
unimplemented = "warn"
unnecessary_safety_comment = "warn"
unnecessary_safety_doc = "warn"
unnecessary_self_imports = "warn"
unneeded_field_pattern = "warn"
unseparated_literal_suffix = "warn"
unused_result_ok = "warn"
unused_trait_names = "warn"
unwrap_in_result = "warn"
unwrap_used = "warn"
verbose_file_reads = "warn"
[profile.dev.package.backtrace]
opt-level = 3
[profile.dev]
panic = "abort"
[profile.release]
debug = 2
lto = "fat"
# Because of the async runtime, we want to die straightaway if we panic.
panic = "abort"
strip = true
[package]
name = "authentik"
version.workspace = true
authors.workspace = true
edition.workspace = true
readme.workspace = true
homepage.workspace = true
repository.workspace = true
license-file.workspace = true
publish.workspace = true
[features]
default = ["core", "proxy"]
core = ["ak-common/core", "dep:pyo3", "dep:sqlx"]
proxy = ["ak-common/proxy"]
[build-dependencies]
pyo3-build-config.workspace = true
[dependencies]
ak-axum.workspace = true
ak-common.workspace = true
arc-swap.workspace = true
argh.workspace = true
axum.workspace = true
color-eyre.workspace = true
eyre.workspace = true
hyper-unix-socket.workspace = true
hyper-util.workspace = true
metrics.workspace = true
metrics-exporter-prometheus.workspace = true
nix.workspace = true
pyo3 = { workspace = true, optional = true }
sqlx = { workspace = true, optional = true }
tokio.workspace = true
tracing.workspace = true
uuid.workspace = true
which.workspace = true
[lints]
workspace = true

160
Makefile
View File

@@ -15,11 +15,14 @@ else
SED_INPLACE = sed -i
endif
GEN_API_TS = gen-ts-api
GEN_API_PY = gen-py-api
GEN_API_GO = gen-go-api
BREW_LDFLAGS :=
BREW_CPPFLAGS :=
BREW_PKG_CONFIG_PATH :=
CARGO := cargo
UV := uv
# For macOS users, add the libxml2 installed from brew libxmlsec1 to the build path
@@ -66,29 +69,22 @@ help: ## Show this help
sort
@echo ""
go-test: ## Run the golang tests
go-test:
go test -timeout 0 -v -race -cover ./...
rust-test: ## Run the Rust tests
$(CARGO) nextest run --workspace
test: ## Run the server tests and produce a coverage report (locally)
$(UV) run coverage run manage.py test --keepdb $(or $(filter-out $@,$(MAKECMDGOALS)),authentik)
$(UV) run coverage combine
$(UV) run coverage html
$(UV) run coverage report
lint-fix-rust:
$(CARGO) +nightly fmt --all -- --config-path "${PWD}/.cargo/rustfmt.toml"
lint-fix: lint-fix-rust ## Lint and automatically fix errors in the python source code. Reports spelling errors.
lint-fix: lint-codespell ## Lint and automatically fix errors in the python source code. Reports spelling errors.
$(UV) run black $(PY_SOURCES)
$(UV) run ruff check --fix $(PY_SOURCES)
lint-spellcheck: ## Reports spelling errors.
npm run lint:spellcheck
lint-codespell: ## Reports spelling errors.
$(UV) run codespell -w
lint: ci-lint-bandit ci-lint-mypy ci-lint-cargo-deny ci-lint-cargo-machete ## Lint the python and golang sources
lint: ci-bandit ci-mypy ## Lint the python and golang sources
golangci-lint run -v
core-install:
@@ -109,11 +105,11 @@ i18n-extract: core-i18n-extract web-i18n-extract ## Extract strings that requir
aws-cfn:
cd lifecycle/aws && npm i && $(UV) run npm run aws-cfn
run: ## Run the main authentik server and worker processes
$(UV) run ak allinone
run-server: ## Run the main authentik server process
$(UV) run ak server
run-watch: ## Run the authentik server and worker, with auto reloading
watchexec --on-busy-update=restart --stop-signal=SIGINT --exts py,rs,go --no-meta --notify -- $(UV) run ak allinone
run-worker: ## Run the main authentik worker process
$(UV) run ak worker
core-i18n-extract:
$(UV) run ak makemessages \
@@ -121,7 +117,8 @@ core-i18n-extract:
--no-obsolete \
--ignore web \
--ignore internal \
--ignore packages/client-ts \
--ignore ${GEN_API_TS} \
--ignore ${GEN_API_GO} \
--ignore website \
-l en
@@ -144,25 +141,18 @@ dev-create-db:
dev-reset: dev-drop-db dev-create-db migrate ## Drop and restore the Authentik PostgreSQL instance to a "fresh install" state.
update-test-mmdb: ## Update test GeoIP and ASN Databases
curl \
-L \
-o ${PWD}/tests/geoip/GeoLite2-ASN-Test.mmdb \
https://raw.githubusercontent.com/maxmind/MaxMind-DB/refs/heads/main/test-data/GeoLite2-ASN-Test.mmdb
curl \
-L \
-o ${PWD}/tests/geoip/GeoLite2-City-Test.mmdb \
https://raw.githubusercontent.com/maxmind/MaxMind-DB/refs/heads/main/test-data/GeoLite2-City-Test.mmdb
curl -L https://raw.githubusercontent.com/maxmind/MaxMind-DB/refs/heads/main/test-data/GeoLite2-ASN-Test.mmdb -o ${PWD}/tests/GeoLite2-ASN-Test.mmdb
curl -L https://raw.githubusercontent.com/maxmind/MaxMind-DB/refs/heads/main/test-data/GeoLite2-City-Test.mmdb -o ${PWD}/tests/GeoLite2-City-Test.mmdb
bump: ## Bump authentik version. Usage: make bump version=20xx.xx.xx
ifndef version
$(error Usage: make bump version=20xx.xx.xx )
endif
$(eval current_version := $(shell cat ${PWD}/internal/constants/VERSION))
$(SED_INPLACE) 's/^version = ".*"/version = "$(version)"/' ${PWD}/pyproject.toml
$(SED_INPLACE) 's/^VERSION = ".*"/VERSION = "$(version)"/' ${PWD}/authentik/__init__.py
$(SED_INPLACE) "s/version = \"${current_version}\"/version = \"$(version)\"/" ${PWD}/Cargo.toml ${PWD}/Cargo.lock
$(SED_INPLACE) 's/^version = ".*"/version = "$(version)"/' pyproject.toml
$(SED_INPLACE) 's/^VERSION = ".*"/VERSION = "$(version)"/' authentik/__init__.py
$(MAKE) gen-build gen-compose aws-cfn
$(SED_INPLACE) "s/\"${current_version}\"/\"$(version)\"/" ${PWD}/package.json ${PWD}/package-lock.json ${PWD}/web/package.json ${PWD}/web/package-lock.json
npm version --no-git-tag-version --allow-same-version $(version)
cd ${PWD}/web && npm version --no-git-tag-version --allow-same-version $(version)
echo -n $(version) > ${PWD}/internal/constants/VERSION
#########################
@@ -178,23 +168,13 @@ gen-build: ## Extract the schema from the database
gen-compose:
$(UV) run scripts/generate_compose.py
gen-changelog: ## (Release) generate the changelog based from the commits since the last version
# These are best-effort guesses based on commit messages
$(eval last_version := $(shell git tag --list 'version/*' --sort 'version:refname' | grep -vE 'rc\d+$$' | tail -1))
$(eval current_commit := $(shell git rev-parse HEAD))
git log --pretty=format:"- %s" $(shell git merge-base ${last_version} ${current_commit})...${current_commit} > merged_to_current
git log --pretty=format:"- %s" $(shell git merge-base ${last_version} ${current_commit})...${last_version} > merged_to_last
grep -Eo 'cherry-pick (#\d+)' merged_to_last | cut -d ' ' -f 2 | sed 's/.*/(&)$$/' > cherry_picked_to_last
grep -vf cherry_picked_to_last merged_to_current | sort > changelog.md
rm merged_to_current
rm merged_to_last
rm cherry_picked_to_last
gen-changelog: ## (Release) generate the changelog based from the commits since the last tag
git log --pretty=format:" - %s" $(shell git describe --tags $(shell git rev-list --tags --max-count=1))...$(shell git branch --show-current) | sort > changelog.md
npx prettier --write changelog.md
gen-diff: ## (Release) generate the changelog diff between the current schema and the last version
$(eval last_version := $(shell git tag --list 'version/*' --sort 'version:refname' | grep -vE 'rc\d+$$' | tail -1))
git show ${last_version}:schema.yml > schema-old.yml
docker compose -f scripts/compose.yml run --rm --user "${UID}:${GID}" diff \
gen-diff: ## (Release) generate the changelog diff between the current schema and the last tag
git show $(shell git describe --tags $(shell git rev-list --tags --max-count=1)):schema.yml > schema-old.yml
docker compose -f scripts/api/compose.yml run --rm --user "${UID}:${GID}" diff \
--markdown \
/local/diff.md \
/local/schema-old.yml \
@@ -204,26 +184,51 @@ gen-diff: ## (Release) generate the changelog diff between the current schema a
$(SED_INPLACE) 's/}/&#125;/g' diff.md
npx prettier --write diff.md
gen-client-go: ## Build and install the authentik API for Golang
$(UV) run make -C "${PWD}/packages/client-go" build
gen-clean-ts: ## Remove generated API client for TypeScript
rm -rf ${PWD}/${GEN_API_TS}/
rm -rf ${PWD}/web/node_modules/@goauthentik/api/
gen-client-rust: ## Build and install the authentik API for Rust
$(UV) run make -C "${PWD}/packages/client-rust" build version=${NPM_VERSION}
make lint-fix-rust
gen-clean-py: ## Remove generated API client for Python
rm -rf ${PWD}/${GEN_API_PY}
gen-client-ts: ## Build and install the authentik API for Typescript into the authentik UI Application
make -C "${PWD}/packages/client-ts" build
npm --prefix web install
gen-clean-go: ## Remove generated API client for Go
rm -rf ${PWD}/${GEN_API_GO}
_gen-clients: gen-client-go gen-client-rust gen-client-ts
gen-clients: ## Build and install API clients used by authentik
$(MAKE) _gen-clients -j
gen-clean: gen-clean-ts gen-clean-go gen-clean-py ## Remove generated API clients
gen: gen-build gen-clients ## Build and install API schema and clients used by authentik
gen-client-ts: gen-clean-ts ## Build and install the authentik API for Typescript into the authentik UI Application
docker compose -f scripts/api/compose.yml run --rm --user "${UID}:${GID}" gen \
generate \
-i /local/schema.yml \
-g typescript-fetch \
-o /local/${GEN_API_TS} \
-c /local/scripts/api/ts-config.yaml \
--additional-properties=npmVersion=${NPM_VERSION} \
--git-repo-id authentik \
--git-user-id goauthentik
cd ${PWD}/${GEN_API_TS} && npm i
cd ${PWD}/${GEN_API_TS} && npm link
cd ${PWD}/web && npm link @goauthentik/api
gen-client-py: gen-clean-py ## Build and install the authentik API for Python
mkdir -p ${PWD}/${GEN_API_PY}
git clone --depth 1 https://github.com/goauthentik/client-python.git ${PWD}/${GEN_API_PY}
cp ${PWD}/schema.yml ${PWD}/${GEN_API_PY}
make -C ${PWD}/${GEN_API_PY} build version=${NPM_VERSION}
gen-client-go: gen-clean-go ## Build and install the authentik API for Golang
mkdir -p ${PWD}/${GEN_API_GO}
git clone --depth 1 https://github.com/goauthentik/client-go.git ${PWD}/${GEN_API_GO}
cp ${PWD}/schema.yml ${PWD}/${GEN_API_GO}
make -C ${PWD}/${GEN_API_GO} build version=${NPM_VERSION}
go mod edit -replace goauthentik.io/api/v3=./${GEN_API_GO}
gen-dev-config: ## Generate a local development config file
$(UV) run scripts/generate_config.py
gen: gen-build gen-client-ts
#########################
## Node.js
#########################
@@ -271,7 +276,7 @@ docs: docs-lint-fix docs-build ## Automatically fix formatting issues in the Au
docs-install:
npm ci --prefix website
docs-lint-fix: lint-spellcheck
docs-lint-fix: lint-codespell
npm run --prefix website prettier
docs-build:
@@ -292,7 +297,7 @@ docs-api-build:
npm run --prefix website -w api build
docs-api-watch: ## Build and watch the API documentation
npm run --prefix website -w api generate
npm run --prefix website -w api build:api
npm run --prefix website -w api start
docs-api-clean: ## Clean generated API documentation
@@ -303,6 +308,7 @@ docs-api-clean: ## Clean generated API documentation
#########################
docker: ## Build a docker image of the current source tree
mkdir -p ${GEN_API_TS}
DOCKER_BUILDKIT=1 docker build . -f lifecycle/container/Dockerfile --progress plain --tag ${DOCKER_IMAGE}
test-docker:
@@ -315,42 +321,28 @@ test-docker:
# which makes the YAML File a lot smaller
ci--meta-debug:
$(UV) run python -V || echo "No python installed"
$(CARGO) --version || echo "No rust installed"
node --version || echo "No node installed"
$(UV) run python -V
node --version
ci-lint-mypy: ci--meta-debug
ci-mypy: ci--meta-debug
$(UV) run mypy --strict $(PY_SOURCES)
ci-lint-black: ci--meta-debug
ci-black: ci--meta-debug
$(UV) run black --check $(PY_SOURCES)
ci-lint-ruff: ci--meta-debug
ci-ruff: ci--meta-debug
$(UV) run ruff check $(PY_SOURCES)
ci-lint-spellcheck: ci--meta-debug
npm run lint:spellcheck
ci-codespell: ci--meta-debug
$(UV) run codespell -s
ci-lint-bandit: ci--meta-debug
ci-bandit: ci--meta-debug
$(UV) run bandit -c pyproject.toml -r $(PY_SOURCES) -iii
ci-lint-pending-migrations: ci--meta-debug
ci-pending-migrations: ci--meta-debug
$(UV) run ak makemigrations --check
ci-lint-cargo-deny: ci--meta-debug
$(CARGO) deny --locked --workspace check --config "${PWD}/.cargo/deny.toml"
ci-lint-cargo-machete: ci--meta-debug
$(CARGO) machete
ci-lint-rustfmt: ci--meta-debug
$(CARGO) +nightly fmt --all --check -- --config-path "${PWD}/.cargo/rustfmt.toml"
ci-lint-clippy: ci--meta-debug
$(CARGO) clippy --workspace -- -D warnings
ci-test: ci--meta-debug
$(UV) run coverage run manage.py test --keepdb --parallel auto authentik
$(UV) run coverage combine
$(UV) run coverage run manage.py test --keepdb authentik
$(UV) run coverage report
$(UV) run coverage xml

View File

@@ -18,10 +18,10 @@ Even if the issue is not a CVE, we still greatly appreciate your help in hardeni
(.x being the latest patch release for each version)
| Version | Supported |
| --------- | --------- |
| 2025.12.x | ✅ |
| 2026.2.x | ✅ |
| Version | Supported |
| ---------- | ---------- |
| 2025.10.x | ✅ |
| 2025.12.x | ✅ |
## Reporting a Vulnerability
@@ -60,40 +60,6 @@ authentik reserves the right to reclassify CVSS as necessary. To determine sever
| 7.0 8.9 | High |
| 9.0 10.0 | Critical |
## Intended functionality
The following capabilities are part of intentional system design and should not be reported as security vulnerabilities:
- Expressions (property mappings/policies/prompts) can execute arbitrary Python code without safeguards.
This is expected behavior. Any user with permission to create or modify objects containing expression fields can write code that is executed within authentik. If a vulnerability allows a user without the required permissions to write or modify code and have it executed, that would be a valid security report.
However, the fact that expressions are executed as part of normal operations is not considered a privilege escalation or security vulnerability.
- Blueprints can access all files on the filesystem.
This access is intentional to allow legitimate configuration and deployment tasks. It does not represent a security problem by itself.
- Importing blueprints allows arbitrary modification of application objects.
This is intended functionality. This behavior reflects the privileged design of blueprint imports. It is "exploitable" when importing blueprints from untrusted sources without reviewing the blueprint beforehand. However, any method to create, modify or execute blueprints without the required permissions would be a valid security report.
- Flow imports may contain objects other than flows (such as policies, users, groups, etc.)
This is expected behavior as flow imports are blueprint files.
- Prompt HTML is not escaped.
Prompts intentionally allow raw HTML, including script tags, so they can be used to create interactive or customized user interface elements. Because of this, scripts within prompts may affect or interact with the surrounding page as designed.
- Open redirects that do not include tokens or other sensitive information are not considered a security vulnerability.
Redirects that only change navigation flow and do not expose session tokens, API keys, or other confidential data are considered acceptable and do not require reporting.
- Outgoing network requests are not filtered.
The destinations of outgoing network requests (HTTP, TCP, etc.) made by authentik to configurable endpoints through objects such as OAuth Sources, SSO Providers, and others are not validated. Depending on your threat model, these requests should be restricted at the network level using appropriate firewall or network policies.
## Disclosure process
1. Report from Github or Issue is reported via Email as listed above.

View File

@@ -3,7 +3,7 @@
from functools import lru_cache
from os import environ
VERSION = "2026.8.0-rc1"
VERSION = "2026.2.0-rc1"
ENV_GIT_HASH_KEY = "GIT_BUILD_HASH"

View File

@@ -8,8 +8,8 @@ from rest_framework.response import Response
from rest_framework.viewsets import ViewSet
from authentik.core.api.utils import PassiveSerializer
from authentik.lib.api import Models
from authentik.lib.utils.reflection import get_apps
from authentik.policies.event_matcher.models import model_choices
class AppSerializer(PassiveSerializer):
@@ -42,6 +42,6 @@ class ModelViewSet(ViewSet):
def list(self, request: Request) -> Response:
"""Read-only view list all installed models"""
data = []
for name, label in Models.choices:
for name, label in model_choices():
data.append({"name": name, "label": label})
return Response(AppSerializer(data, many=True).data)

View File

@@ -94,7 +94,7 @@ class Backend:
Args:
file_path: Relative file path
request: Optional Django HttpRequest for fully qualified URL building
request: Optional Django HttpRequest for fully qualifed URL building
use_cache: whether to retrieve the URL from cache
Returns:
@@ -106,7 +106,6 @@ class Backend:
self,
name: str,
request: HttpRequest | None = None,
use_cache: bool = True,
) -> dict[str, str] | None:
"""
Get URLs for each theme variant when filename contains %(theme)s.
@@ -122,7 +121,7 @@ class Backend:
return None
return {
theme: self.file_url(substitute_theme(name, theme), request, use_cache=use_cache)
theme: self.file_url(substitute_theme(name, theme), request, use_cache=True)
for theme in get_valid_themes()
}

View File

@@ -51,7 +51,6 @@ class PassthroughBackend(Backend):
self,
name: str,
request: HttpRequest | None = None,
use_cache: bool = True,
) -> dict[str, str] | None:
"""Support themed URLs for external URLs with %(theme)s placeholder.

View File

@@ -1,7 +1,7 @@
from collections.abc import Generator, Iterator
from contextlib import contextmanager
from tempfile import SpooledTemporaryFile
from urllib.parse import urlsplit, urlunsplit
from urllib.parse import urlsplit
import boto3
from botocore.config import Config
@@ -100,25 +100,13 @@ class S3Backend(ManageableBackend):
f"storage.{self.usage.value}.{self.name}.addressing_style",
CONFIG.get(f"storage.{self.name}.addressing_style", "auto"),
)
signature_version = CONFIG.get(
f"storage.{self.usage.value}.{self.name}.signature_version",
CONFIG.get(f"storage.{self.name}.signature_version", "s3v4"),
)
# Keep signature_version pass-through and let boto3/botocore handle it.
# In boto3's S3 configuration docs, `s3v4` (default) and deprecated `s3`
# are the documented values:
# https://github.com/boto/boto3/blob/791a3e8f36d83664a47b4281a0586b3546cef3ec/docs/source/guide/configuration.rst?plain=1#L398-L407
# Botocore also supports additional signer names, so we intentionally do
# not enforce a restricted allowlist here.
return self.session.client(
"s3",
endpoint_url=endpoint_url,
use_ssl=use_ssl,
region_name=region_name,
config=Config(
signature_version=signature_version, s3={"addressing_style": addressing_style}
),
config=Config(signature_version="s3v4", s3={"addressing_style": addressing_style}),
)
@property
@@ -164,19 +152,16 @@ class S3Backend(ManageableBackend):
)
def _file_url(name: str, request: HttpRequest | None) -> str:
client = self.client
params = {
"Bucket": self.bucket_name,
"Key": f"{self.base_path}/{name}",
}
operation_name = "GetObject"
operation_model = client.meta.service_model.operation_model(operation_name)
request_dict = client._convert_to_request_dict(
params,
operation_model,
endpoint_url=client.meta.endpoint_url,
context={"is_presign_request": True},
url = self.client.generate_presigned_url(
"get_object",
Params=params,
ExpiresIn=expires_in,
HttpMethod="GET",
)
# Support custom domain for S3-compatible storage (so not AWS)
@@ -186,8 +171,9 @@ class S3Backend(ManageableBackend):
CONFIG.get(f"storage.{self.name}.custom_domain", None),
)
if custom_domain:
parsed = urlsplit(url)
scheme = "https" if use_https else "http"
path = request_dict["url_path"]
path = parsed.path
# When using path-style addressing, the presigned URL contains the bucket
# name in the path (e.g., /bucket-name/key). Since custom_domain must
@@ -202,22 +188,9 @@ class S3Backend(ManageableBackend):
if not path.startswith("/"):
path = f"/{path}"
custom_base = urlsplit(f"{scheme}://{custom_domain}")
url = f"{scheme}://{custom_domain}{path}?{parsed.query}"
# Sign the final public URL instead of signing the internal S3 endpoint and
# rewriting it afterwards. Presigned SigV4 URLs include the host header in the
# canonical request, so post-sign host changes break strict backends like RustFS.
public_path = f"{custom_base.path.rstrip('/')}{path}" if custom_base.path else path
request_dict["url_path"] = public_path
request_dict["url"] = urlunsplit(
(custom_base.scheme, custom_base.netloc, public_path, "", "")
)
return client._request_signer.generate_presigned_url(
request_dict,
operation_name,
expires_in=expires_in,
)
return url
if use_cache:
return self._cache_get_or_set(name, request, _file_url, expires_in)

View File

@@ -1,7 +1,5 @@
from unittest import skipUnless
from urllib.parse import parse_qs, urlsplit
from botocore.exceptions import UnsupportedSignatureVersionError
from django.test import TestCase
from authentik.admin.files.tests.utils import FileTestS3BackendMixin, s3_test_server_available
@@ -83,27 +81,6 @@ class TestS3Backend(FileTestS3BackendMixin, TestCase):
self.assertIn("X-Amz-Signature=", url)
self.assertIn("test.png", url)
def test_client_signature_version_default_v4(self):
"""Test S3 client defaults to v4 signature when not configured."""
self.assertEqual(self.media_s3_backend.client.meta.config.signature_version, "s3v4")
@CONFIG.patch("storage.s3.signature_version", "s3")
def test_client_signature_version_global_override(self):
"""Test S3 client respects globally configured signature version."""
self.assertEqual(self.media_s3_backend.client.meta.config.signature_version, "s3")
@CONFIG.patch("storage.s3.signature_version", "s3v4")
@CONFIG.patch("storage.media.s3.signature_version", "s3")
def test_client_signature_version_media_override(self):
"""Test usage-specific signature version takes precedence over global."""
self.assertEqual(self.media_s3_backend.client.meta.config.signature_version, "s3")
@CONFIG.patch("storage.media.s3.signature_version", "not-a-real-signature")
def test_client_signature_version_unsupported(self):
"""Test unsupported signature version raises botocore error."""
with self.assertRaises(UnsupportedSignatureVersionError):
self.media_s3_backend.file_url("test.png", use_cache=False)
@CONFIG.patch("storage.s3.bucket_name", "test-bucket")
def test_file_exists_true(self):
"""Test file_exists returns True for existing file"""
@@ -169,44 +146,6 @@ class TestS3Backend(FileTestS3BackendMixin, TestCase):
f"URL: {url}",
)
@CONFIG.patch("storage.s3.secure_urls", False)
@CONFIG.patch("storage.s3.addressing_style", "path")
def test_file_url_custom_domain_resigns_for_custom_host(self):
"""Test presigned URLs are signed for the custom domain host.
Host-changing custom domains must produce a signature query string for
the public host, not reuse the internal endpoint signature.
"""
bucket_name = self.media_s3_bucket_name
key_name = "application-icons/test.svg"
custom_domain = f"files.example.test:8020/{bucket_name}"
endpoint_signed_url = self.media_s3_backend.client.generate_presigned_url(
"get_object",
Params={
"Bucket": bucket_name,
"Key": f"{self.media_s3_backend.base_path}/{key_name}",
},
ExpiresIn=900,
HttpMethod="GET",
)
with CONFIG.patch("storage.media.s3.custom_domain", custom_domain):
custom_url = self.media_s3_backend.file_url(key_name, use_cache=False)
endpoint_parts = urlsplit(endpoint_signed_url)
custom_parts = urlsplit(custom_url)
self.assertEqual(custom_parts.scheme, "http")
self.assertEqual(custom_parts.netloc, "files.example.test:8020")
self.assertEqual(parse_qs(custom_parts.query)["X-Amz-SignedHeaders"], ["host"])
self.assertNotEqual(
custom_parts.query,
endpoint_parts.query,
"Custom-domain URLs must be signed for the public host, not reuse the endpoint "
"signature query string.",
)
def test_themed_urls_without_theme_variable(self):
"""Test themed_urls returns None when filename has no %(theme)s"""
result = self.media_s3_backend.themed_urls("logo.png")

View File

@@ -74,10 +74,6 @@ class FileManager:
) -> str:
"""
Get URL for accessing the file.
Set ``use_cache=False`` when the caller needs a fresh signed URL instead
of a cached one, for example when serializing flow/login payloads that
may be refreshed after the previous JWT has expired.
"""
if not name:
return ""
@@ -87,7 +83,7 @@ class FileManager:
for backend in self.backends:
if backend.supports_file(name):
return backend.file_url(name, request, use_cache=use_cache)
return backend.file_url(name, request)
LOGGER.warning(f"Could not find file backend for file: {name}")
return ""
@@ -96,14 +92,10 @@ class FileManager:
self,
name: str | None,
request: HttpRequest | Request | None = None,
use_cache: bool = True,
) -> dict[str, str] | None:
"""
Get URLs for each theme variant when filename contains %(theme)s.
``use_cache`` has the same semantics as ``file_url()`` and allows
callers to force regeneration of expiring signed URLs.
Returns dict mapping theme to URL if %(theme)s present, None otherwise.
"""
if not name:
@@ -114,7 +106,7 @@ class FileManager:
for backend in self.backends:
if backend.supports_file(name):
return backend.themed_urls(name, request, use_cache=use_cache)
return backend.themed_urls(name, request)
return None

View File

@@ -1,7 +1,6 @@
"""Test file service layer"""
from unittest import skipUnless
from unittest.mock import Mock
from urllib.parse import urlparse
from django.http import HttpRequest
@@ -54,19 +53,6 @@ class TestResolveFileUrlBasic(TestCase):
result = manager.file_url("/static/authentik/sources/icon.svg")
self.assertEqual(result, "/static/authentik/sources/icon.svg")
def test_file_url_forwards_use_cache(self):
"""Test file_url forwards use_cache to backend."""
manager = FileManager(FileUsage.MEDIA)
backend = Mock()
backend.supports_file.return_value = True
backend.file_url.return_value = "/files/media/public/test.png?token=fresh"
manager.backends = [backend]
result = manager.file_url("test.png", use_cache=False)
self.assertEqual(result, "/files/media/public/test.png?token=fresh")
backend.file_url.assert_called_once_with("test.png", None, use_cache=False)
class TestResolveFileUrlFileBackend(FileTestFileBackendMixin, TestCase):
def test_resolve_storage_file(self):

View File

@@ -106,14 +106,14 @@ class TokenAuthentication(BaseAuthentication):
if not auth_credentials:
return None
# first, check traditional tokens
key_token = Token.objects.filter(
key_token = Token.filter_not_expired(
key=auth_credentials, intent=TokenIntents.INTENT_API
).first()
if key_token:
CTX_AUTH_VIA.set("api_token")
return key_token.user, key_token
# then try to auth via JWT
jwt_token = AccessToken.objects.filter(
jwt_token = AccessToken.filter_not_expired(
token=auth_credentials, _scope__icontains=SCOPE_AUTHENTIK_API
).first()
if jwt_token:

View File

@@ -1,36 +0,0 @@
from django.db.models import F, QuerySet
from rest_framework.filters import OrderingFilter
from rest_framework.request import Request
from rest_framework.views import APIView
class NullsAwareOrderingFilter(OrderingFilter):
"""OrderingFilter that sorts NULL values consistently.
For any nullable field, NULLs are treated as the smallest possible value:
- ascending → NULLs appear first (nulls_first=True)
- descending → NULLs appear last (nulls_last=True)
"""
def _nullable_field_names(self, queryset: QuerySet) -> set[str]:
return {f.name for f in queryset.model._meta.get_fields() if hasattr(f, "null") and f.null}
def filter_queryset(self, request: Request, queryset: QuerySet, view: APIView):
queryset = super().filter_queryset(request, queryset, view)
ordering = queryset.query.order_by
if not ordering:
return queryset
nullable = self._nullable_field_names(queryset)
new_ordering = []
changed = False
for term in ordering:
name = term.lstrip("-")
if name in nullable:
changed = True
if term.startswith("-"):
new_ordering.append(F(name).desc(nulls_last=True))
else:
new_ordering.append(F(name).asc(nulls_first=True))
else:
new_ordering.append(term)
return queryset.order_by(*new_ordering) if changed else queryset

View File

@@ -1,18 +1,10 @@
"""Pagination which includes total pages and current page"""
from typing import TYPE_CHECKING
from drf_spectacular.plumbing import build_object_type
from rest_framework import pagination
from rest_framework.response import Response
from authentik.api.search.ql import QLSearch
from authentik.api.v3.schema.pagination import PAGINATION
from authentik.api.v3.schema.search import AUTOCOMPLETE_SCHEMA
if TYPE_CHECKING:
from django.db.models import QuerySet
from rest_framework.request import Request
from authentik.api.v3.schema.response import PAGINATION
class Pagination(pagination.PageNumberPagination):
@@ -21,14 +13,14 @@ class Pagination(pagination.PageNumberPagination):
page_query_param = "page"
page_size_query_param = "page_size"
def get_page_size(self, request: Request) -> int:
def get_page_size(self, request):
if self.page_size_query_param in request.query_params:
page_size = super().get_page_size(request)
if page_size is not None:
return min(super().get_page_size(request), request.tenant.pagination_max_page_size)
return request.tenant.pagination_default_page_size
def get_paginated_response(self, data) -> Response:
def get_paginated_response(self, data):
previous_page_number = 0
if self.page.has_previous():
previous_page_number = self.page.previous_page_number()
@@ -47,33 +39,16 @@ class Pagination(pagination.PageNumberPagination):
"end_index": self.page.end_index(),
},
"results": data,
"autocomplete": self.get_autocomplete(),
}
)
def paginate_queryset(self, queryset: QuerySet, request: Request, view=None):
self.view = view
return super().paginate_queryset(queryset, request, view)
def get_autocomplete(self):
schema = QLSearch().get_schema(self.request, self.view)
introspections = {}
if hasattr(self.view, "get_ql_fields"):
from authentik.api.search.schema import AKQLSchemaSerializer
introspections = AKQLSchemaSerializer().serialize(
schema(self.page.paginator.object_list.model)
)
return introspections
def get_paginated_response_schema(self, schema):
return build_object_type(
properties={
"pagination": PAGINATION.ref,
"results": schema,
"autocomplete": AUTOCOMPLETE_SCHEMA.ref,
},
required=["pagination", "results", "autocomplete"],
required=["pagination", "results"],
)

103
authentik/api/schema.py Normal file
View File

@@ -0,0 +1,103 @@
"""Error Response schema, from https://github.com/axnsan12/drf-yasg/issues/224"""
from collections.abc import Callable
from typing import Any
from drf_spectacular.generators import SchemaGenerator
from drf_spectacular.plumbing import ResolvedComponent
from drf_spectacular.renderers import OpenApiJsonRenderer
from drf_spectacular.settings import spectacular_settings
from structlog.stdlib import get_logger
from authentik.api.apps import AuthentikAPIConfig
from authentik.api.v3.schema.query import QUERY_PARAMS
from authentik.api.v3.schema.response import (
GENERIC_ERROR,
GENERIC_ERROR_RESPONSE,
PAGINATION,
VALIDATION_ERROR,
VALIDATION_ERROR_RESPONSE,
)
LOGGER = get_logger()
def preprocess_schema_exclude_non_api(endpoints: list[tuple[str, Any, Any, Callable]], **kwargs):
"""Filter out all API Views which are not mounted under /api"""
return [
(path, path_regex, method, callback)
for path, path_regex, method, callback in endpoints
if path.startswith("/" + AuthentikAPIConfig.mountpoint)
]
def postprocess_schema_register(
result: dict[str, Any], generator: SchemaGenerator, **kwargs
) -> dict[str, Any]:
"""Register custom schema components"""
LOGGER.debug("Registering custom schemas")
generator.registry.register_on_missing(PAGINATION)
generator.registry.register_on_missing(GENERIC_ERROR)
generator.registry.register_on_missing(GENERIC_ERROR_RESPONSE)
generator.registry.register_on_missing(VALIDATION_ERROR)
generator.registry.register_on_missing(VALIDATION_ERROR_RESPONSE)
for query in QUERY_PARAMS.values():
generator.registry.register_on_missing(query)
return result
def postprocess_schema_responses(
result: dict[str, Any], generator: SchemaGenerator, **kwargs
) -> dict[str, Any]:
"""Default error responses"""
LOGGER.debug("Adding default error responses")
for path in result["paths"].values():
for method in path.values():
method["responses"].setdefault("400", VALIDATION_ERROR_RESPONSE.ref)
method["responses"].setdefault("403", GENERIC_ERROR_RESPONSE.ref)
result["components"] = generator.registry.build(spectacular_settings.APPEND_COMPONENTS)
# This is a workaround for authentik/stages/prompt/stage.py
# since the serializer PromptChallengeResponse
# accepts dynamic keys
for component in result["components"]["schemas"]:
if component == "PromptChallengeResponseRequest":
comp = result["components"]["schemas"][component]
comp["additionalProperties"] = {}
return result
def postprocess_schema_query_params(
result: dict[str, Any], generator: SchemaGenerator, **kwargs
) -> dict[str, Any]:
"""Optimise pagination parameters, instead of redeclaring parameters for each endpoint
declare them globally and refer to them"""
LOGGER.debug("Deduplicating query parameters")
for path in result["paths"].values():
for method in path.values():
for idx, param in enumerate(method.get("parameters", [])):
if param["name"] not in QUERY_PARAMS:
continue
method["parameters"][idx] = QUERY_PARAMS[param["name"]].ref
return result
def postprocess_schema_remove_unused(
result: dict[str, Any], generator: SchemaGenerator, **kwargs
) -> dict[str, Any]:
"""Remove unused components"""
# To check if the schema is used, render it to JSON and then substring check that
# less efficient than walking through the tree but a lot simpler and no
# possibility that we miss something
raw = OpenApiJsonRenderer().render(result, renderer_context={}).decode()
count = 0
for key in result["components"][ResolvedComponent.SCHEMA].keys():
schema_usages = raw.count(f"#/components/{ResolvedComponent.SCHEMA}/{key}")
if schema_usages >= 1:
continue
del generator.registry[(key, ResolvedComponent.SCHEMA)]
count += 1
LOGGER.debug("Removing unused components", count=count)
result["components"] = generator.registry.build(spectacular_settings.APPEND_COMPONENTS)
return result

View File

@@ -1,59 +0,0 @@
from django.db.models import OrderBy
from django.test import TestCase
from rest_framework.request import Request
from rest_framework.test import APIRequestFactory
from authentik.api.ordering import NullsAwareOrderingFilter
from authentik.core.models import Token, User
class MockView:
ordering_fields = "__all__"
ordering = None
class TestNullsAwareOrderingFilter(TestCase):
def setUp(self):
self.filter = NullsAwareOrderingFilter()
self.view = MockView()
factory = APIRequestFactory()
self._req = lambda ordering: Request(factory.get("/", {"ordering": ordering}))
def _order_by(self, model, ordering):
qs = model.objects.all()
return self.filter.filter_queryset(self._req(ordering), qs, self.view).query.order_by
def test_nullable_asc_nulls_first(self):
"""Ascending sort on a nullable field rewrites to nulls_first=True."""
(expr,) = self._order_by(User, "last_login")
self.assertIsInstance(expr, OrderBy)
self.assertFalse(expr.descending)
self.assertTrue(expr.nulls_first)
def test_nullable_desc_nulls_last(self):
"""Descending sort on a nullable field rewrites to nulls_last=True."""
(expr,) = self._order_by(User, "-last_login")
self.assertIsInstance(expr, OrderBy)
self.assertTrue(expr.descending)
self.assertTrue(expr.nulls_last)
def test_non_nullable_passes_through(self):
"""Non-nullable fields are left as plain string terms."""
(expr,) = self._order_by(User, "username")
self.assertEqual(expr, "username")
def test_mixed_ordering(self):
"""Only nullable terms are rewritten; non-nullable terms pass through unchanged."""
first, second = self._order_by(User, "username,-last_login")
self.assertEqual(first, "username")
self.assertIsInstance(second, OrderBy)
self.assertTrue(second.descending)
self.assertTrue(second.nulls_last)
def test_expires_nullable(self):
"""expires on ExpiringModel is nullable and is rewritten correctly."""
(expr,) = self._order_by(Token, "-expires")
self.assertIsInstance(expr, OrderBy)
self.assertTrue(expr.descending)
self.assertTrue(expr.nulls_last)

View File

@@ -1,8 +1,6 @@
"""Schema generation tests"""
from pathlib import Path
from tempfile import gettempdir
from uuid import uuid4
from django.core.management import call_command
from django.urls import reverse
@@ -31,14 +29,15 @@ class TestSchemaGeneration(APITestCase):
def test_build_schema(self):
"""Test schema build command"""
tmp = Path(gettempdir())
blueprint_file = tmp / f"{str(uuid4())}.json"
api_file = tmp / f"{str(uuid4())}.yml"
blueprint_file = Path("blueprints/schema.json")
api_file = Path("schema.yml")
blueprint_file.unlink()
api_file.unlink()
with (
CONFIG.patch("debug", True),
CONFIG.patch("tenants.enabled", True),
CONFIG.patch("outposts.disable_embedded_outpost", True),
):
call_command("build_schema", blueprint_file=blueprint_file, api_file=api_file)
call_command("build_schema")
self.assertTrue(blueprint_file.exists())
self.assertTrue(api_file.exists())

View File

@@ -1,73 +1,31 @@
"""authentik API Modelviewset tests"""
from collections.abc import Callable
from urllib.parse import urlencode
from django.test import TestCase
from rest_framework.viewsets import ModelViewSet, ReadOnlyModelViewSet
from authentik.admin.api.version_history import VersionHistoryViewSet
from authentik.api.v3.urls import router
from authentik.core.tests.utils import RequestFactory, create_test_admin_user
from authentik.lib.generators import generate_id
from authentik.tenants.api.domains import DomainViewSet
from authentik.tenants.api.tenants import TenantViewSet
from authentik.tenants.utils import get_current_tenant
class TestModelViewSets(TestCase):
"""Test Viewset"""
def setUp(self):
self.user = create_test_admin_user()
self.factory = RequestFactory()
def viewset_tester_factory(test_viewset: type[ModelViewSet], full=True) -> dict[str, Callable]:
def viewset_tester_factory(test_viewset: type[ModelViewSet]) -> Callable:
"""Test Viewset"""
def test_attrs(self: TestModelViewSets) -> None:
"""Test attributes we require on all viewsets"""
self.assertIsNotNone(getattr(test_viewset, "ordering", None))
def tester(self: TestModelViewSets):
self.assertIsNotNone(getattr(test_viewset, "search_fields", None))
self.assertIsNotNone(getattr(test_viewset, "ordering", None))
filterset_class = getattr(test_viewset, "filterset_class", None)
if not filterset_class:
self.assertIsNotNone(getattr(test_viewset, "filterset_fields", None))
def test_ordering(self: TestModelViewSets) -> None:
"""Test that all ordering fields are correct"""
view = test_viewset.as_view({"get": "list"})
for ordering_field in test_viewset.ordering:
with self.subTest(ordering_field):
req = self.factory.get(
f"/?{urlencode({'ordering': ordering_field}, doseq=True)}", user=self.user
)
req.tenant = get_current_tenant()
res = view(req)
self.assertEqual(res.status_code, 200)
def test_search(self: TestModelViewSets) -> None:
"""Test that search fields are correct"""
view = test_viewset.as_view({"get": "list"})
req = self.factory.get(
f"/?{urlencode({'search': generate_id()}, doseq=True)}", user=self.user
)
req.tenant = get_current_tenant()
res = view(req)
self.assertEqual(res.status_code, 200)
cases = {
"attrs": test_attrs,
}
if full:
cases["ordering"] = test_ordering
cases["search"] = test_search
return cases
return tester
for _, viewset, _ in router.registry:
if not issubclass(viewset, ModelViewSet | ReadOnlyModelViewSet):
continue
full = viewset not in [VersionHistoryViewSet, DomainViewSet, TenantViewSet]
for test, case in viewset_tester_factory(viewset, full=full).items():
setattr(TestModelViewSets, f"test_viewset_{viewset.__name__}_{test}", case)
setattr(TestModelViewSets, f"test_viewset_{viewset.__name__}", viewset_tester_factory(viewset))

View File

@@ -1,75 +0,0 @@
"""Error Response schema, from https://github.com/axnsan12/drf-yasg/issues/224"""
from collections.abc import Callable
from typing import Any
from drf_spectacular.contrib.django_filters import (
DjangoFilterExtension as BaseDjangoFilterExtension,
)
from drf_spectacular.generators import SchemaGenerator
from drf_spectacular.plumbing import (
ResolvedComponent,
follow_field_source,
)
from drf_spectacular.renderers import OpenApiJsonRenderer
from drf_spectacular.settings import spectacular_settings
from structlog.stdlib import get_logger
from authentik.api.apps import AuthentikAPIConfig
LOGGER = get_logger()
def preprocess_schema_exclude_non_api(endpoints: list[tuple[str, Any, Any, Callable]], **kwargs):
"""Filter out all API Views which are not mounted under /api"""
return [
(path, path_regex, method, callback)
for path, path_regex, method, callback in endpoints
if path.startswith("/" + AuthentikAPIConfig.mountpoint)
]
def postprocess_schema_remove_unused(
result: dict[str, Any], generator: SchemaGenerator, **kwargs
) -> dict[str, Any]:
"""Remove unused components"""
# To check if the schema is used, render it to JSON and then substring check that
# less efficient than walking through the tree but a lot simpler and no
# possibility that we miss something
raw = OpenApiJsonRenderer().render(result, renderer_context={}).decode()
count = 0
for key in result["components"][ResolvedComponent.SCHEMA].keys():
schema_usages = raw.count(f"#/components/{ResolvedComponent.SCHEMA}/{key}")
if schema_usages >= 1:
continue
del generator.registry[(key, ResolvedComponent.SCHEMA)]
count += 1
LOGGER.debug("Removing unused components", count=count)
result["components"] = generator.registry.build(spectacular_settings.APPEND_COMPONENTS)
return result
class DjangoFilterExtension(BaseDjangoFilterExtension):
"""
From https://github.com/netbox-community/netbox/pull/21521:
Overrides drf-spectacular's DjangoFilterExtension to fix a regression in v0.29.0 where
_get_model_field() incorrectly double-appends to_field_name when field_name already ends
with that value (e.g. field_name='tags__slug', to_field_name='slug' produces the invalid
path ['tags', 'slug', 'slug']). This caused hundreds of spurious warnings during schema
generation for filters such as TagFilter, TenancyFilterSet.tenant, and OwnerFilterMixin.owner.
See: https://github.com/netbox-community/netbox/issues/20787
https://github.com/tfranzel/drf-spectacular/issues/1475
"""
priority = 1
def _get_model_field(self, filter_field, model):
if not filter_field.field_name:
return None
path = filter_field.field_name.split("__")
to_field_name = filter_field.extra.get("to_field_name")
if to_field_name is not None and path[-1] != to_field_name:
path.append(to_field_name)
return follow_field_source(model, path, emit_warnings=False)

View File

@@ -1,287 +0,0 @@
"""Error Response schema, from https://github.com/axnsan12/drf-yasg/issues/224"""
import functools
import inspect
import re
from collections import defaultdict
from enum import Enum
from django.db.models import Choices
from django.utils.translation import get_language
from drf_spectacular.drainage import error, warn
from drf_spectacular.hooks import postprocess_schema_enum_id_removal
from drf_spectacular.plumbing import (
ResolvedComponent,
deep_import_string,
list_hash,
safe_ref,
)
from drf_spectacular.settings import spectacular_settings
from inflection import camelize
from structlog.stdlib import get_logger
LOGGER = get_logger()
# See https://github.com/tfranzel/drf-spectacular/blob/master/drf_spectacular/hooks.py
# and https://github.com/tfranzel/drf-spectacular/issues/520
def postprocess_schema_enums(result, generator, **kwargs): # noqa: PLR0912, PLR0915
"""
simple replacement of Enum/Choices that globally share the same name and have
the same choices. Aids client generation to not generate a separate enum for
every occurrence. only takes effect when replacement is guaranteed to be correct.
"""
def is_enum_prop(prop_schema):
return (
"enum" in prop_schema
or prop_schema.get("type") == "array"
and "enum" in prop_schema.get("items", {})
)
def iter_field_schemas():
def iter_prop_containers(schema, component_name=None):
if not component_name:
for _component_name, _schema in schema.items():
if spectacular_settings.COMPONENT_SPLIT_PATCH:
_component_name = re.sub("^Patched(.+)", r"\1", _component_name)
if spectacular_settings.COMPONENT_SPLIT_REQUEST:
_component_name = re.sub("(.+)Request$", r"\1", _component_name)
yield from iter_prop_containers(_schema, _component_name)
elif isinstance(schema, list):
for item in schema:
yield from iter_prop_containers(item, component_name)
elif isinstance(schema, dict):
if schema.get("properties"):
yield component_name, schema["properties"]
yield from iter_prop_containers(schema.get("oneOf", []), component_name)
yield from iter_prop_containers(schema.get("allOf", []), component_name)
yield from iter_prop_containers(schema.get("anyOf", []), component_name)
def iter_path_parameters():
for path in result.get("paths", {}).values():
for operation in path.values():
for parameter in operation.get("parameters", []):
parameter_schema = parameter.get("schema", {})
if is_enum_prop(parameter_schema):
# Move description into enum schema
if "description" in parameter:
parameter_schema["description"] = parameter.pop("description")
if "name" not in parameter:
continue
yield "", {parameter["name"]: parameter_schema}
component_schemas = result.get("components", {}).get("schemas", {})
yield from iter_prop_containers(component_schemas)
yield from iter_path_parameters()
def create_enum_component(name, schema):
component = ResolvedComponent(
name=name,
type=ResolvedComponent.SCHEMA,
schema=schema,
object=name,
)
generator.registry.register_on_missing(component)
return component
def extract_hash(schema):
if "x-spec-enum-id" in schema:
# try to use the injected enum hash first as it generated from (name, value) tuples,
# which prevents collisions on choice sets only differing in labels not values.
return schema["x-spec-enum-id"]
else:
# fall back to actual list hashing when we encounter enums not generated by us.
# remove blank/null entry for hashing. will be reconstructed in the last step
return list_hash([(i, i) for i in schema["enum"] if i not in ("", None)])
overrides = load_enum_name_overrides()
prop_hash_mapping = defaultdict(set)
hash_name_mapping = defaultdict(set)
# collect all enums, their names and choice sets
for component_name, props in iter_field_schemas():
for prop_name, prop_schema in props.items():
_prop_schema = prop_schema
if prop_schema.get("type") == "array":
_prop_schema = prop_schema.get("items", {})
if "enum" not in _prop_schema:
continue
prop_enum_cleaned_hash = extract_hash(_prop_schema)
prop_hash_mapping[prop_name].add(prop_enum_cleaned_hash)
hash_name_mapping[prop_enum_cleaned_hash].add((component_name, prop_name))
# get the suffix to be used for enums from settings
enum_suffix = spectacular_settings.ENUM_SUFFIX
# traverse all enum properties and generate a name for the choice set. naming collisions
# are resolved and a warning is emitted. giving a choice set multiple names is technically
# correct but potentially unwanted. also emit a warning there to make the user aware.
enum_name_mapping = {}
for prop_name, prop_hash_set in prop_hash_mapping.items():
for prop_hash in prop_hash_set:
if prop_hash in overrides:
enum_name = overrides[prop_hash]
elif len(prop_hash_set) == 1:
# prop_name has been used exclusively for one choice set (best case)
enum_name = f"{camelize(prop_name)}{enum_suffix}"
elif len(hash_name_mapping[prop_hash]) == 1:
# prop_name has multiple choice sets, but each one limited to one component only
component_name, _ = next(iter(hash_name_mapping[prop_hash]))
enum_name = f"{camelize(component_name)}{camelize(prop_name)}{enum_suffix}"
else:
enum_name = f"{camelize(prop_name)}{prop_hash[:3].capitalize()}{enum_suffix}"
warn(
f"enum naming encountered a non-optimally resolvable collision for fields "
f'named "{prop_name}". The same name has been used for multiple choice sets '
f'in multiple components. The collision was resolved with "{enum_name}". '
f"add an entry to ENUM_NAME_OVERRIDES to fix the naming."
)
if enum_name_mapping.get(prop_hash, enum_name) != enum_name:
warn(
f"encountered multiple names for the same choice set ({enum_name}). This "
f"may be unwanted even though the generated schema is technically correct. "
f"Add an entry to ENUM_NAME_OVERRIDES to fix the naming."
)
del enum_name_mapping[prop_hash]
else:
enum_name_mapping[prop_hash] = enum_name
enum_name_mapping[(prop_hash, prop_name)] = enum_name
# replace all enum occurrences with a enum schema component. cut out the
# enum, replace it with a reference and add a corresponding component.
for _, props in iter_field_schemas():
for prop_name, _prop_schema in props.items():
prop_schema = _prop_schema
is_array = prop_schema.get("type") == "array"
if is_array:
prop_schema = prop_schema.get("items", {})
if "enum" not in prop_schema:
continue
prop_enum_original_list = prop_schema["enum"]
prop_schema["enum"] = [i for i in prop_schema["enum"] if i not in ["", None]]
prop_hash = extract_hash(prop_schema)
# when choice sets are reused under multiple names, the generated name cannot be
# resolved from the hash alone. fall back to prop_name and hash for resolution.
enum_name = enum_name_mapping.get(prop_hash) or enum_name_mapping[prop_hash, prop_name]
# split property into remaining property and enum component parts
enum_schema = {k: v for k, v in prop_schema.items() if k in ["type", "enum"]}
prop_schema = {
k: v for k, v in prop_schema.items() if k not in ["type", "enum", "x-spec-enum-id"]
}
# separate actual description from name-value tuples
if spectacular_settings.ENUM_GENERATE_CHOICE_DESCRIPTION:
if prop_schema.get("description", "").startswith("*"):
enum_schema["description"] = prop_schema.pop("description")
elif "\n\n*" in prop_schema.get("description", ""):
_, _, post = prop_schema["description"].partition("\n\n*")
enum_schema["description"] = "*" + post
components = [create_enum_component(enum_name, schema=enum_schema)]
if spectacular_settings.ENUM_ADD_EXPLICIT_BLANK_NULL_CHOICE:
if "" in prop_enum_original_list:
components.append(
create_enum_component(f"Blank{enum_suffix}", schema={"enum": [""]})
)
if None in prop_enum_original_list:
if spectacular_settings.OAS_VERSION.startswith("3.1"):
components.append(
create_enum_component(f"Null{enum_suffix}", schema={"type": "null"})
)
else:
components.append(
create_enum_component(f"Null{enum_suffix}", schema={"enum": [None]})
)
# undo OAS 3.1 type list NULL construction as we cover
# this in a separate component already
if spectacular_settings.OAS_VERSION.startswith("3.1") and isinstance(
enum_schema["type"], list
):
enum_schema["type"] = [t for t in enum_schema["type"] if t != "null"][0]
if len(components) == 1:
prop_schema.update(components[0].ref)
else:
prop_schema.update({"oneOf": [c.ref for c in components]})
patch_target = props[prop_name] # noqa: PLR1733
if is_array:
patch_target = patch_target["items"]
# Replace existing schema information with reference
patch_target.clear()
patch_target.update(safe_ref(prop_schema))
# sort again with additional components
result["components"] = generator.registry.build(spectacular_settings.APPEND_COMPONENTS)
# remove remaining ids that were not part of this hook (operation parameters mainly)
postprocess_schema_enum_id_removal(result, generator)
return result
# Fixed version of `load_enum_name_overrides()` with a LRU cache based on language
# *and* enum overrides.
# Without this, API generation breaks if there is more than 1 API present (such as in split APIs)
# Original source: drf-spectacular/drf_spectacular/plumbing.py
def load_enum_name_overrides():
cache_key = get_language() or ""
for k, v in sorted(spectacular_settings.ENUM_NAME_OVERRIDES.items()):
cache_key += f";{k}:{v}"
return _load_enum_name_overrides(cache_key)
# Original source: drf-spectacular/drf_spectacular/plumbing.py
# Only change: cache_key argument instead of language.
@functools.lru_cache
def _load_enum_name_overrides(cache_key):
overrides = {}
for name, _choices in spectacular_settings.ENUM_NAME_OVERRIDES.items():
choices = _choices
if isinstance(choices, str):
choices = deep_import_string(choices)
if not choices:
warn(
f"unable to load choice override for {name} from ENUM_NAME_OVERRIDES. "
f"please check module path string."
)
continue
if inspect.isclass(choices) and issubclass(choices, Choices):
choices = choices.choices
if inspect.isclass(choices) and issubclass(choices, Enum):
choices = [(c.value, c.name) for c in choices]
normalized_choices = []
for choice in choices:
# Allow None values in the simple values list case
if isinstance(choice, str) or choice is None:
# TODO warning
normalized_choices.append((choice, choice)) # simple choice list
elif isinstance(choice[1], (list, tuple)):
normalized_choices.extend(choice[1]) # categorized nested choices
else:
normalized_choices.append(choice) # normal 2-tuple form
# Get all of choice values that should be used in the hash, blank and
# None values get excluded in the post-processing hook for enum overrides,
# so we do the same here to ensure the hashes match
hashable_values = [
(value, label) for value, label in normalized_choices if value not in ["", None]
]
overrides[list_hash(hashable_values)] = name
if len(spectacular_settings.ENUM_NAME_OVERRIDES) != len(overrides):
error(
"ENUM_NAME_OVERRIDES has duplication issues. Encountered multiple names "
"for the same choice set. Enum naming might be unexpected."
)
return overrides

View File

@@ -1,32 +0,0 @@
from drf_spectacular.plumbing import (
ResolvedComponent,
build_basic_type,
build_object_type,
)
from drf_spectacular.types import OpenApiTypes
PAGINATION = ResolvedComponent(
name="Pagination",
type=ResolvedComponent.SCHEMA,
object="Pagination",
schema=build_object_type(
properties={
"next": build_basic_type(OpenApiTypes.NUMBER),
"previous": build_basic_type(OpenApiTypes.NUMBER),
"count": build_basic_type(OpenApiTypes.NUMBER),
"current": build_basic_type(OpenApiTypes.NUMBER),
"total_pages": build_basic_type(OpenApiTypes.NUMBER),
"start_index": build_basic_type(OpenApiTypes.NUMBER),
"end_index": build_basic_type(OpenApiTypes.NUMBER),
},
required=[
"next",
"previous",
"count",
"current",
"total_pages",
"start_index",
"end_index",
],
),
)

View File

@@ -1,17 +1,10 @@
from typing import Any
from django.utils.translation import gettext_lazy as _
from drf_spectacular.generators import SchemaGenerator
from drf_spectacular.plumbing import (
ResolvedComponent,
build_basic_type,
build_parameter_type,
)
from drf_spectacular.types import OpenApiTypes
from structlog.stdlib import get_logger
LOGGER = get_logger()
QUERY_PARAMS = {
"ordering": ResolvedComponent(
@@ -70,18 +63,3 @@ QUERY_PARAMS = {
),
),
}
def postprocess_schema_query_params(
result: dict[str, Any], generator: SchemaGenerator, **kwargs
) -> dict[str, Any]:
"""Optimize pagination parameters, instead of redeclaring parameters for each endpoint
declare them globally and refer to them"""
LOGGER.debug("Deduplicating query parameters")
for path in result["paths"].values():
for method in path.values():
for idx, param in enumerate(method.get("parameters", [])):
if param["name"] not in QUERY_PARAMS:
continue
method["parameters"][idx] = QUERY_PARAMS[param["name"]].ref
return result

View File

@@ -1,22 +1,12 @@
from typing import Any
from django.utils.translation import gettext_lazy as _
from drf_spectacular.generators import SchemaGenerator
from drf_spectacular.plumbing import (
ResolvedComponent,
build_array_type,
build_basic_type,
build_object_type,
)
from drf_spectacular.settings import spectacular_settings
from drf_spectacular.types import OpenApiTypes
from rest_framework.settings import api_settings
from structlog.stdlib import get_logger
from authentik.api.v3.schema.pagination import PAGINATION
from authentik.api.v3.schema.query import QUERY_PARAMS
LOGGER = get_logger()
GENERIC_ERROR = ResolvedComponent(
name="GenericError",
@@ -67,40 +57,28 @@ VALIDATION_ERROR_RESPONSE = ResolvedComponent(
"description": "",
},
)
def postprocess_schema_register(
result: dict[str, Any], generator: SchemaGenerator, **kwargs
) -> dict[str, Any]:
"""Register custom schema components"""
LOGGER.debug("Registering custom schemas")
generator.registry.register_on_missing(PAGINATION)
generator.registry.register_on_missing(GENERIC_ERROR)
generator.registry.register_on_missing(GENERIC_ERROR_RESPONSE)
generator.registry.register_on_missing(VALIDATION_ERROR)
generator.registry.register_on_missing(VALIDATION_ERROR_RESPONSE)
for query in QUERY_PARAMS.values():
generator.registry.register_on_missing(query)
return result
def postprocess_schema_responses(
result: dict[str, Any], generator: SchemaGenerator, **kwargs
) -> dict[str, Any]:
"""Default error responses"""
LOGGER.debug("Adding default error responses")
for path in result["paths"].values():
for method in path.values():
method["responses"].setdefault("400", VALIDATION_ERROR_RESPONSE.ref)
method["responses"].setdefault("403", GENERIC_ERROR_RESPONSE.ref)
result["components"] = generator.registry.build(spectacular_settings.APPEND_COMPONENTS)
# This is a workaround for authentik/stages/prompt/stage.py
# since the serializer PromptChallengeResponse
# accepts dynamic keys
for component in result["components"]["schemas"]:
if component == "PromptChallengeResponseRequest":
comp = result["components"]["schemas"][component]
comp["additionalProperties"] = {}
return result
PAGINATION = ResolvedComponent(
name="Pagination",
type=ResolvedComponent.SCHEMA,
object="Pagination",
schema=build_object_type(
properties={
"next": build_basic_type(OpenApiTypes.NUMBER),
"previous": build_basic_type(OpenApiTypes.NUMBER),
"count": build_basic_type(OpenApiTypes.NUMBER),
"current": build_basic_type(OpenApiTypes.NUMBER),
"total_pages": build_basic_type(OpenApiTypes.NUMBER),
"start_index": build_basic_type(OpenApiTypes.NUMBER),
"end_index": build_basic_type(OpenApiTypes.NUMBER),
},
required=[
"next",
"previous",
"count",
"current",
"total_pages",
"start_index",
"end_index",
],
),
)

View File

@@ -1,20 +0,0 @@
from typing import TYPE_CHECKING
from drf_spectacular.plumbing import ResolvedComponent, build_object_type
if TYPE_CHECKING:
from drf_spectacular.generators import SchemaGenerator
AUTOCOMPLETE_SCHEMA = ResolvedComponent(
name="Autocomplete",
object="Autocomplete",
type=ResolvedComponent.SCHEMA,
schema=build_object_type(additionalProperties={}),
)
def postprocess_schema_search_autocomplete(result, generator: SchemaGenerator, **kwargs):
generator.registry.register_on_missing(AUTOCOMPLETE_SCHEMA)
return result

View File

@@ -1,74 +1,24 @@
"""Serializer mixin for managed models"""
from json import JSONDecodeError, loads
from typing import cast
from django.conf import settings
from django.core.files.uploadedfile import InMemoryUploadedFile
from django.utils.translation import gettext_lazy as _
from drf_spectacular.utils import extend_schema, inline_serializer
from rest_framework.decorators import action
from rest_framework.exceptions import PermissionDenied, ValidationError
from rest_framework.fields import (
BooleanField,
CharField,
DateTimeField,
FileField,
)
from rest_framework.parsers import MultiPartParser
from rest_framework.exceptions import ValidationError
from rest_framework.fields import CharField, DateTimeField
from rest_framework.request import Request
from rest_framework.response import Response
from rest_framework.serializers import ListSerializer
from rest_framework.viewsets import ModelViewSet
from authentik.api.validation import validate
from authentik.blueprints.models import BlueprintInstance
from authentik.blueprints.v1.common import Blueprint
from authentik.blueprints.v1.importer import Importer
from authentik.blueprints.v1.oci import OCI_PREFIX
from authentik.blueprints.v1.tasks import apply_blueprint, blueprints_find_dict
from authentik.core.api.used_by import UsedByMixin
from authentik.core.api.utils import JSONDictField, ModelSerializer, PassiveSerializer
from authentik.core.models import User
from authentik.events.logs import LogEventSerializer
from authentik.rbac.decorators import permission_required
def get_blueprints():
if settings.DEBUG:
return blueprints_find_dict()
return blueprints_find_dict.send().get_result(block=True)
class BlueprintUploadSerializer(PassiveSerializer):
"""Serializer to upload file"""
file = FileField(required=False)
path = CharField(required=False)
context = CharField(required=False, allow_blank=True)
def validate_path(self, path: str) -> str:
"""Ensure the path (if set) specified is retrievable"""
if path == "":
return path
files: list[dict] = get_blueprints()
if path not in [file["path"] for file in files]:
raise ValidationError(_("Blueprint file does not exist"))
return path
def validate_context(self, context: str) -> dict:
"""Parse context as a JSON object"""
if not context:
return {}
try:
parsed = loads(context)
except JSONDecodeError as exc:
raise ValidationError(_("Context must be valid JSON")) from exc
if not isinstance(parsed, dict):
raise ValidationError(_("Context must be a JSON object"))
return parsed
class ManagedSerializer:
"""Managed Serializer"""
@@ -89,7 +39,7 @@ class BlueprintInstanceSerializer(ModelSerializer):
"""Ensure the path (if set) specified is retrievable"""
if path == "" or path.startswith(OCI_PREFIX):
return path
files: list[dict] = get_blueprints()
files: list[dict] = blueprints_find_dict.send().get_result(block=True)
if path not in [file["path"] for file in files]:
raise ValidationError(_("Blueprint file does not exist"))
return path
@@ -138,33 +88,6 @@ class BlueprintInstanceSerializer(ModelSerializer):
}
def check_blueprint_perms(blueprint: Blueprint, user: User, explicit_action: str | None = None):
"""Check for individual permissions for each model in a blueprint"""
for entry in blueprint.iter_entries():
full_model = entry.get_model(blueprint)
app, __, model = full_model.partition(".")
perms = [
f"{app}.add_{model}",
f"{app}.change_{model}",
f"{app}.delete_{model}",
]
if explicit_action:
perms = [f"{app}.{explicit_action}_{model}"]
for perm in perms:
if not user.has_perm(perm):
raise PermissionDenied(
{
entry.id: _(
"User lacks permission to create {model}".format_map(
{
"model": full_model,
}
)
)
}
)
class BlueprintInstanceViewSet(UsedByMixin, ModelViewSet):
"""Blueprint instances"""
@@ -174,12 +97,6 @@ class BlueprintInstanceViewSet(UsedByMixin, ModelViewSet):
filterset_fields = ["name", "path"]
ordering = ["name"]
class BlueprintImportResultSerializer(PassiveSerializer):
"""Logs of an attempted blueprint import"""
logs = LogEventSerializer(many=True, read_only=True)
success = BooleanField(read_only=True)
@extend_schema(
responses={
200: ListSerializer(
@@ -198,7 +115,7 @@ class BlueprintInstanceViewSet(UsedByMixin, ModelViewSet):
@action(detail=False, pagination_class=None, filter_backends=[])
def available(self, request: Request) -> Response:
"""Get blueprints"""
files: list[dict] = get_blueprints()
files: list[dict] = blueprints_find_dict.send().get_result(block=True)
return Response(files)
@permission_required("authentik_blueprints.view_blueprintinstance")
@@ -214,43 +131,3 @@ class BlueprintInstanceViewSet(UsedByMixin, ModelViewSet):
blueprint = self.get_object()
apply_blueprint.send_with_options(args=(blueprint.pk,), rel_obj=blueprint)
return self.retrieve(request, *args, **kwargs)
@extend_schema(
request={"multipart/form-data": BlueprintUploadSerializer},
responses={200: BlueprintImportResultSerializer},
)
@action(url_path="import", detail=False, methods=["POST"], parser_classes=(MultiPartParser,))
@validate(
BlueprintUploadSerializer,
)
def import_(self, request: Request, body: BlueprintUploadSerializer) -> Response:
"""Import blueprint from .yaml file and apply it once, without creating an instance"""
string_contents = ""
if body.validated_data.get("file"):
file = cast(InMemoryUploadedFile, body.validated_data["file"])
string_contents = file.read().decode()
elif body.validated_data.get("path"):
string_contents = BlueprintInstance(
path=body.validated_data.get("path")
).retrieve_file()
else:
raise ValidationError("Either path or file must be set")
context = body.validated_data.get("context") or {}
importer = Importer.from_string(string_contents, context)
check_blueprint_perms(importer.blueprint, request.user)
valid, logs = importer.validate()
import_response = self.BlueprintImportResultSerializer(
data={
"logs": [LogEventSerializer(log).data for log in logs],
"success": valid,
}
)
import_response.is_valid(raise_exception=True)
if valid:
import_response.initial_data["success"] = importer.apply()
import_response.is_valid()
return Response(data=import_response.initial_data, status=200)

View File

@@ -3,6 +3,7 @@
import traceback
from collections.abc import Callable
from importlib import import_module
from inspect import ismethod
from django.apps import AppConfig
from django.conf import settings
@@ -71,19 +72,12 @@ class ManagedAppConfig(AppConfig):
def _reconcile(self, prefix: str) -> None:
for meth_name in dir(self):
# Check the attribute on the class to avoid evaluating @property descriptors.
# Using getattr(self, ...) on a @property would evaluate it, which can trigger
# expensive side effects (e.g. tenant_schedule_specs iterating all providers
# and running PolicyEngine queries for every user).
class_attr = getattr(type(self), meth_name, None)
if class_attr is None or isinstance(class_attr, property):
meth = getattr(self, meth_name)
if not ismethod(meth):
continue
if not callable(class_attr):
continue
category = getattr(class_attr, "_authentik_managed_reconcile", None)
category = getattr(meth, "_authentik_managed_reconcile", None)
if category != prefix:
continue
meth = getattr(self, meth_name)
name = meth_name.replace(prefix, "")
try:
self.logger.debug("Starting reconciler", name=name)

View File

@@ -1,6 +1,5 @@
"""Apply blueprint from commandline"""
from argparse import ArgumentParser
from sys import exit as sys_exit
from django.core.management.base import BaseCommand, no_translations
@@ -32,5 +31,5 @@ class Command(BaseCommand):
sys_exit(1)
importer.apply()
def add_arguments(self, parser: ArgumentParser):
def add_arguments(self, parser):
parser.add_argument("blueprints", nargs="+", type=str)

View File

@@ -1,19 +1,14 @@
"""Test blueprints v1 api"""
from json import dumps, loads
from json import loads
from tempfile import NamedTemporaryFile, mkdtemp
from django.core.files.uploadedfile import SimpleUploadedFile
from django.urls import reverse
from rest_framework.test import APITestCase
from yaml import dump
from authentik.core.tests.utils import create_test_admin_user
from authentik.flows.models import Flow
from authentik.lib.config import CONFIG
from authentik.lib.generators import generate_id
from authentik.stages.invitation.models import InvitationStage
from authentik.stages.user_write.models import UserWriteStage
TMP = mkdtemp("authentik-blueprints")
@@ -85,121 +80,3 @@ class TestBlueprintsV1API(APITestCase):
res.content.decode(),
{"content": ["Failed to validate blueprint", "- Invalid blueprint version"]},
)
def test_api_import_with_context(self):
"""Test that the import endpoint applies the supplied context to the real blueprint"""
slug = f"invitation-enrollment-{generate_id()}"
flow_name = f"Invitation Enrollment {generate_id()}"
stage_name = f"invitation-stage-{generate_id()}"
user_type = "internal"
continue_without_invitation = True
res = self.client.post(
reverse("authentik_api:blueprintinstance-import-"),
data={
"path": "example/flows-invitation-enrollment-minimal.yaml",
"context": dumps(
{
"flow_slug": slug,
"flow_name": flow_name,
"stage_name": stage_name,
"continue_flow_without_invitation": continue_without_invitation,
"user_type": user_type,
}
),
},
format="multipart",
)
self.assertEqual(res.status_code, 200)
self.assertTrue(res.json()["success"])
flow = Flow.objects.get(slug=slug)
self.assertEqual(flow.name, flow_name)
self.assertEqual(flow.title, flow_name)
invitation_stage = InvitationStage.objects.get(name=stage_name)
self.assertEqual(
invitation_stage.continue_flow_without_invitation,
continue_without_invitation,
)
user_write_stage = UserWriteStage.objects.get(
name=f"invitation-enrollment-user-write-{slug}"
)
self.assertEqual(user_write_stage.user_type, user_type)
self.assertEqual(user_write_stage.user_path_template, f"users/{user_type}")
def test_api_import_blank_path(self):
"""Validator returns empty path unchanged (covers api.py:53)."""
with NamedTemporaryFile(mode="w+", suffix=".yaml") as file:
file.write(dump({"version": 1, "entries": []}))
file.flush()
file.seek(0)
res = self.client.post(
reverse("authentik_api:blueprintinstance-import-"),
data={"path": "", "file": file},
format="multipart",
)
self.assertEqual(res.status_code, 200)
def test_api_import_invalid_blueprint_returns_result_payload(self):
"""Invalid blueprint content returns a result payload instead of a 400 response."""
file = SimpleUploadedFile("invalid-blueprint.yaml", b'{"version": 3}')
res = self.client.post(
reverse("authentik_api:blueprintinstance-import-"),
data={"file": file},
format="multipart",
)
self.assertEqual(res.status_code, 200)
self.assertFalse(res.json()["success"])
self.assertGreater(len(res.json()["logs"]), 0)
def test_api_import_unknown_path(self):
"""Path not in available blueprints is rejected (covers api.py:56)."""
res = self.client.post(
reverse("authentik_api:blueprintinstance-import-"),
data={"path": "does/not/exist.yaml"},
format="multipart",
)
self.assertEqual(res.status_code, 400)
self.assertIn("Blueprint file does not exist", res.content.decode())
def test_api_import_blank_context(self):
"""Blank context is normalized to empty dict (covers api.py:62)."""
res = self.client.post(
reverse("authentik_api:blueprintinstance-import-"),
data={
"path": "example/flows-invitation-enrollment-minimal.yaml",
"context": "",
},
format="multipart",
)
self.assertEqual(res.status_code, 200)
def test_api_import_invalid_json_context(self):
"""Malformed JSON context raises ValidationError (covers api.py:65-66)."""
res = self.client.post(
reverse("authentik_api:blueprintinstance-import-"),
data={
"path": "example/flows-invitation-enrollment-minimal.yaml",
"context": "{not json",
},
format="multipart",
)
self.assertEqual(res.status_code, 400)
self.assertIn("Context must be valid JSON", res.content.decode())
def test_api_import_non_object_context(self):
"""JSON context that isn't an object is rejected (covers api.py:68)."""
res = self.client.post(
reverse("authentik_api:blueprintinstance-import-"),
data={
"path": "example/flows-invitation-enrollment-minimal.yaml",
"context": "[1, 2, 3]",
},
format="multipart",
)
self.assertEqual(res.status_code, 400)
self.assertIn("Context must be a JSON object", res.content.decode())

View File

@@ -1,11 +1,8 @@
"""Test blueprints v1"""
from unittest.mock import patch
from django.test import TransactionTestCase
from authentik.blueprints.v1.importer import Importer
from authentik.enterprise.license import LicenseKey
from authentik.flows.models import Flow
from authentik.lib.generators import generate_id
from authentik.lib.tests.utils import load_fixture
@@ -45,45 +42,3 @@ class TestBlueprintsV1Conditions(TransactionTestCase):
# Ensure objects do not exist
self.assertFalse(Flow.objects.filter(slug=flow_slug1))
self.assertFalse(Flow.objects.filter(slug=flow_slug2))
def test_enterprise_license_context_unlicensed(self):
"""Test enterprise license context defaults to a false boolean when unlicensed."""
license_key = LicenseKey("test", 0, "Test license", 0, 0)
with patch("authentik.enterprise.license.LicenseKey.get_total", return_value=license_key):
importer = Importer.from_string("""
version: 1
entries:
- identifiers:
name: enterprise-test
slug: enterprise-test
model: authentik_flows.flow
conditions:
- !Context goauthentik.io/enterprise/licensed
attrs:
designation: stage_configuration
title: foo
""")
self.assertIs(importer.blueprint.context["goauthentik.io/enterprise/licensed"], False)
def test_enterprise_license_context_licensed(self):
"""Test enterprise license context defaults to a true boolean when licensed."""
license_key = LicenseKey("test", 253402300799, "Test license", 1000, 1000)
with patch("authentik.enterprise.license.LicenseKey.get_total", return_value=license_key):
importer = Importer.from_string("""
version: 1
entries:
- identifiers:
name: enterprise-test
slug: enterprise-test
model: authentik_flows.flow
conditions:
- !Context goauthentik.io/enterprise/licensed
attrs:
designation: stage_configuration
title: foo
""")
self.assertIs(importer.blueprint.context["goauthentik.io/enterprise/licensed"], True)

View File

@@ -43,6 +43,8 @@ def get_attrs(obj: SerializerModel) -> dict[str, Any]:
continue
if _field.read_only:
data.pop(field_name, None)
if _field.get_initial() == data.get(field_name, None):
data.pop(field_name, None)
if field_name.endswith("_set"):
data.pop(field_name, None)
return data

View File

@@ -146,7 +146,9 @@ class Importer:
try:
from authentik.enterprise.license import LicenseKey
context["goauthentik.io/enterprise/licensed"] = LicenseKey.get_total().status().is_valid
context["goauthentik.io/enterprise/licensed"] = (
LicenseKey.get_total().status().is_valid,
)
except ModuleNotFoundError:
pass
return context
@@ -270,7 +272,7 @@ class Importer:
and entry.state != BlueprintEntryDesiredState.MUST_CREATED
):
self.logger.debug(
"Initialize serializer with instance",
"Initialise serializer with instance",
model=model,
instance=model_instance,
pk=model_instance.pk,
@@ -288,7 +290,7 @@ class Importer:
)
else:
self.logger.debug(
"Initialized new serializer instance",
"Initialised new serializer instance",
model=model,
**cleanse_dict(updated_identifiers),
)

View File

@@ -64,7 +64,6 @@ class BrandSerializer(ModelSerializer):
"flow_unenrollment",
"flow_user_settings",
"flow_device_code",
"flow_lockdown",
"default_application",
"web_certificate",
"client_certificates",
@@ -118,7 +117,6 @@ class CurrentBrandSerializer(PassiveSerializer):
flow_unenrollment = CharField(source="flow_unenrollment.slug", required=False)
flow_user_settings = CharField(source="flow_user_settings.slug", required=False)
flow_device_code = CharField(source="flow_device_code.slug", required=False)
flow_lockdown = CharField(source="flow_lockdown.slug", required=False)
default_locale = CharField(read_only=True)
flags = SerializerMethodField()
@@ -156,7 +154,6 @@ class BrandViewSet(UsedByMixin, ModelViewSet):
"flow_unenrollment",
"flow_user_settings",
"flow_device_code",
"flow_lockdown",
"web_certificate",
"client_certificates",
]

View File

@@ -1,25 +0,0 @@
# Generated by Django 5.2.12 on 2026-03-14 02:58
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("authentik_brands", "0011_alter_brand_branding_default_flow_background_and_more"),
("authentik_flows", "0031_alter_flow_layout"),
]
operations = [
migrations.AddField(
model_name="brand",
name="flow_lockdown",
field=models.ForeignKey(
null=True,
on_delete=django.db.models.deletion.SET_NULL,
related_name="brand_lockdown",
to="authentik_flows.flow",
),
),
]

View File

@@ -58,9 +58,6 @@ class Brand(SerializerModel):
flow_device_code = models.ForeignKey(
Flow, null=True, on_delete=models.SET_NULL, related_name="brand_device_code"
)
flow_lockdown = models.ForeignKey(
Flow, null=True, on_delete=models.SET_NULL, related_name="brand_lockdown"
)
default_application = models.ForeignKey(
"authentik_core.Application",
@@ -104,23 +101,13 @@ class Brand(SerializerModel):
"""Get themed URLs for branding_favicon if it contains %(theme)s"""
return get_file_manager(FileUsage.MEDIA).themed_urls(self.branding_favicon)
def branding_default_flow_background_url(self, request=None, use_cache: bool = True) -> str:
def branding_default_flow_background_url(self) -> str:
"""Get branding_default_flow_background URL"""
return get_file_manager(FileUsage.MEDIA).file_url(
self.branding_default_flow_background,
request,
use_cache=use_cache,
)
return get_file_manager(FileUsage.MEDIA).file_url(self.branding_default_flow_background)
def branding_default_flow_background_themed_urls(
self, request=None, use_cache: bool = True
) -> dict[str, str] | None:
def branding_default_flow_background_themed_urls(self) -> dict[str, str] | None:
"""Get themed URLs for branding_default_flow_background if it contains %(theme)s"""
return get_file_manager(FileUsage.MEDIA).themed_urls(
self.branding_default_flow_background,
request,
use_cache=use_cache,
)
return get_file_manager(FileUsage.MEDIA).themed_urls(self.branding_default_flow_background)
@property
def serializer(self) -> type[Serializer]:

View File

@@ -20,16 +20,11 @@ class TestBrands(APITestCase):
def setUp(self):
super().setUp()
self.default_flags = {}
for flag in Flag.available(visibility="public"):
self.default_flags[flag().key] = flag.get()
Brand.objects.all().delete()
@property
def default_flags(self) -> dict[str, object]:
"""Get current public flags.
Some tests define temporary Flag subclasses, so this can't be cached in setUp.
"""
return {flag().key: flag.get() for flag in Flag.available(visibility="public")}
def test_current_brand(self):
"""Test Current brand API"""
brand = create_test_brand()

View File

@@ -3,7 +3,7 @@
from typing import Any
from django.db.models import Case, F, IntegerField, Q, Value, When
from django.db.models.functions import Concat, Length
from django.db.models.functions import Length
from django.http.request import HttpRequest
from django.utils.html import _json_script_escapes
from django.utils.safestring import mark_safe
@@ -26,8 +26,7 @@ def get_brand_for_request(request: HttpRequest) -> Brand:
domain_length=Length("domain"),
match_priority=Case(
When(
condition=Q(host_domain__iexact=F("domain"))
| Q(host_domain__iendswith=Concat(Value("."), F("domain"))),
condition=Q(host_domain__iendswith=F("domain")),
then=F("domain_length"),
),
default=Value(-1),

View File

@@ -5,7 +5,6 @@ from django.utils.translation import gettext_lazy as _
GRANT_TYPE_AUTHORIZATION_CODE = "authorization_code"
GRANT_TYPE_IMPLICIT = "implicit"
GRANT_TYPE_HYBRID = "hybrid"
GRANT_TYPE_REFRESH_TOKEN = "refresh_token" # nosec
GRANT_TYPE_CLIENT_CREDENTIALS = "client_credentials"
GRANT_TYPE_PASSWORD = "password" # nosec
@@ -22,9 +21,6 @@ PROMPT_CONSENT = "consent"
PROMPT_LOGIN = "login"
PLAN_CONTEXT_OIDC_LOGOUT_IFRAME_SESSIONS = "goauthentik.io/providers/oauth2/iframe_sessions"
PLAN_CONTEXT_POST_LOGOUT_REDIRECT_URI = "goauthentik.io/providers/oauth2/post_logout_redirect_uri"
OAUTH2_BINDING = "redirect"
SCOPE_OPENID = "openid"
SCOPE_OPENID_PROFILE = "profile"
@@ -41,9 +37,6 @@ TOKEN_TYPE = "Bearer" # nosec
SCOPE_AUTHENTIK_API = "goauthentik.io/api"
# URI schemes that are forbidden for redirect URIs
FORBIDDEN_URI_SCHEMES = {"javascript", "data", "vbscript"}
# Read/write full user (including email)
SCOPE_GITHUB_USER = "user"
# Read user (without email)

View File

@@ -28,10 +28,6 @@ SAML_ATTRIBUTES_GROUP = "http://schemas.xmlsoap.org/claims/Group"
SAML_BINDING_POST = "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
SAML_BINDING_REDIRECT = "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
SAML_STATUS_SUCCESS = "urn:oasis:names:tc:SAML:2.0:status:Success"
DEFAULT_ISSUER = "authentik"
DSA_SHA1 = "http://www.w3.org/2000/09/xmldsig#dsa-sha1"
RSA_SHA1 = "http://www.w3.org/2000/09/xmldsig#rsa-sha1"
# https://datatracker.ietf.org/doc/html/rfc4051#section-2.3.2

View File

@@ -47,8 +47,7 @@ class ApplicationEntitlementViewSet(UsedByMixin, ModelViewSet):
search_fields = [
"pbm_uuid",
"name",
"app__name",
"app__slug",
"app",
"attributes",
]
filterset_fields = [

View File

@@ -25,7 +25,6 @@ from authentik.core.api.providers import ProviderSerializer
from authentik.core.api.used_by import UsedByMixin
from authentik.core.api.users import UserSerializer
from authentik.core.api.utils import ModelSerializer, ThemedUrlsSerializer
from authentik.core.apps import AppAccessWithoutBindings
from authentik.core.models import Application, User
from authentik.events.logs import LogEventSerializer, capture_logs
from authentik.policies.api.exec import PolicyTestResultSerializer
@@ -36,13 +35,9 @@ from authentik.rbac.filters import ObjectFilter
LOGGER = get_logger()
def user_app_cache_key(
user_pk: str, page_number: int | None = None, only_with_launch_url: bool = False
) -> str:
def user_app_cache_key(user_pk: str, page_number: int | None = None) -> str:
"""Cache key where application list for user is saved"""
key = f"{CACHE_PREFIX}app_access/{user_pk}"
if only_with_launch_url:
key += "/launch"
if page_number:
key += f"/{page_number}"
return key
@@ -52,12 +47,7 @@ class ApplicationSerializer(ModelSerializer):
"""Application Serializer"""
launch_url = SerializerMethodField()
provider_obj = ProviderSerializer(
source="get_provider",
required=False,
read_only=True,
allow_null=True,
)
provider_obj = ProviderSerializer(source="get_provider", required=False, read_only=True)
backchannel_providers_obj = ProviderSerializer(
source="backchannel_providers", required=False, read_only=True, many=True
)
@@ -120,7 +110,6 @@ class ApplicationSerializer(ModelSerializer):
"meta_publisher",
"policy_engine_mode",
"group",
"meta_hide",
]
extra_kwargs = {
"backchannel_providers": {"required": False},
@@ -165,16 +154,15 @@ class ApplicationViewSet(UsedByMixin, ModelViewSet):
return queryset
def _get_allowed_applications(
self, paginated_apps: Iterator[Application], user: User | None = None
self, pagined_apps: Iterator[Application], user: User | None = None
) -> list[Application]:
applications = []
request = self.request._request
if user:
request = copy(request)
request.user = user
for application in paginated_apps:
for application in pagined_apps:
engine = PolicyEngine(application, request.user, request)
engine.empty_result = AppAccessWithoutBindings.get()
engine.build()
if engine.passing:
applications.append(application)
@@ -232,7 +220,6 @@ class ApplicationViewSet(UsedByMixin, ModelViewSet):
if not for_user:
raise ValidationError({"for_user": "User not found"})
engine = PolicyEngine(application, for_user, request)
engine.empty_result = AppAccessWithoutBindings.get()
engine.use_cache = False
with capture_logs() as logs:
engine.build()
@@ -279,17 +266,11 @@ class ApplicationViewSet(UsedByMixin, ModelViewSet):
if superuser_full_list and request.user.is_superuser:
return super().list(request)
only_with_launch_url = (
str(request.query_params.get("only_with_launch_url", "false")).lower()
) == "true"
only_with_launch_url = str(
request.query_params.get("only_with_launch_url", "false")
).lower()
queryset = self._filter_queryset_for_list(self.get_queryset())
queryset = queryset.exclude(meta_hide=True)
if only_with_launch_url:
# Pre-filter at DB level to skip expensive per-app policy evaluation
# for apps that can never appear in the launcher (no meta_launch_url
# and no provider, so no possible launch URL).
queryset = queryset.exclude(meta_launch_url="", provider__isnull=True)
paginator: Pagination = self.paginator
paginated_apps = paginator.paginate_queryset(queryset, request)
@@ -306,6 +287,7 @@ class ApplicationViewSet(UsedByMixin, ModelViewSet):
except ValueError as exc:
raise ValidationError from exc
allowed_applications = self._get_allowed_applications(paginated_apps, user=for_user)
allowed_applications = self._expand_applications(allowed_applications)
serializer = self.get_serializer(allowed_applications, many=True)
return self.get_paginated_response(serializer.data)
@@ -315,26 +297,19 @@ class ApplicationViewSet(UsedByMixin, ModelViewSet):
allowed_applications = self._get_allowed_applications(paginated_apps)
if should_cache:
allowed_applications = cache.get(
user_app_cache_key(
self.request.user.pk, paginator.page.number, only_with_launch_url
)
user_app_cache_key(self.request.user.pk, paginator.page.number)
)
if allowed_applications:
# Re-fetch cached applications since pickled instances lose prefetched
# relationships, causing N+1 queries during serialization
allowed_applications = self._expand_applications(allowed_applications)
else:
if not allowed_applications:
LOGGER.debug("Caching allowed application list", page=paginator.page.number)
allowed_applications = self._get_allowed_applications(paginated_apps)
cache.set(
user_app_cache_key(
self.request.user.pk, paginator.page.number, only_with_launch_url
),
user_app_cache_key(self.request.user.pk, paginator.page.number),
allowed_applications,
timeout=86400,
)
allowed_applications = self._expand_applications(allowed_applications)
if only_with_launch_url:
if only_with_launch_url == "true":
allowed_applications = self._filter_applications_with_launch_url(allowed_applications)
serializer = self.get_serializer(allowed_applications, many=True)

View File

@@ -32,19 +32,19 @@ from authentik.rbac.decorators import permission_required
class UserAgentDeviceDict(TypedDict):
"""User agent device"""
brand: str | None = None
brand: str
family: str
model: str | None = None
model: str
class UserAgentOSDict(TypedDict):
"""User agent os"""
family: str
major: str | None = None
minor: str | None = None
patch: str | None = None
patch_minor: str | None = None
major: str
minor: str
patch: str
patch_minor: str
class UserAgentBrowserDict(TypedDict):

View File

@@ -7,7 +7,6 @@ from django.http import Http404
from django.utils.translation import gettext as _
from django_filters.filters import CharFilter, ModelMultipleChoiceFilter
from django_filters.filterset import FilterSet
from djangoql.schema import BoolField, StrField
from drf_spectacular.utils import (
OpenApiParameter,
OpenApiResponse,
@@ -19,16 +18,13 @@ from rest_framework.authentication import SessionAuthentication
from rest_framework.decorators import action
from rest_framework.fields import CharField, IntegerField, SerializerMethodField
from rest_framework.permissions import IsAuthenticated
from rest_framework.relations import ManyRelatedField, PrimaryKeyRelatedField
from rest_framework.relations import PrimaryKeyRelatedField
from rest_framework.request import Request
from rest_framework.response import Response
from rest_framework.serializers import ListSerializer, ValidationError
from rest_framework.viewsets import ModelViewSet
from authentik.api.authentication import TokenAuthentication
from authentik.api.search.fields import (
JSONSearchField,
)
from authentik.api.validation import validate
from authentik.core.api.used_by import UsedByMixin
from authentik.core.api.utils import JSONDictField, ModelSerializer, PassiveSerializer
@@ -37,77 +33,6 @@ from authentik.endpoints.connectors.agent.auth import AgentAuth
from authentik.rbac.api.roles import RoleSerializer
from authentik.rbac.decorators import permission_required
class BulkManyRelatedField(ManyRelatedField):
"""ManyRelatedField that validates all PKs in a single query instead of one per PK."""
def to_internal_value(self, data):
if isinstance(data, str) or not hasattr(data, "__iter__"):
self.fail("not_a_list", input_type=type(data).__name__)
if not self.allow_empty and len(data) == 0:
self.fail("empty")
child = self.child_relation
pk_field = child.pk_field
# Coerce PKs through pk_field if defined
pk_map = {}
for item in data:
if isinstance(item, bool):
self.fail("incorrect_type", data_type=type(item).__name__)
pk = pk_field.to_internal_value(item) if pk_field else item
pk_map[pk] = item # map coerced PK -> original value for error reporting
queryset = child.get_queryset()
# Use count to validate all PKs exist in a single query
found_count = queryset.filter(pk__in=pk_map.keys()).count()
if found_count < len(pk_map):
# Some PKs not found — fall back to per-PK checks for error reporting.
# This only runs when there's an actual validation error (rare path).
for pk, original in pk_map.items():
if not queryset.filter(pk=pk).exists():
child.fail("does_not_exist", pk_value=original)
# Return raw PKs — Django's M2M set() accepts both objects and PKs,
# using get_prep_value() for type coercion. This avoids loading all
# objects into memory and avoids triggering post_init signals.
return list(pk_map.keys())
def to_representation(self, iterable):
# For non-prefetched querysets, get PKs directly without loading model instances.
# When prefetched, _result_cache is a list (possibly empty); when not, it's None.
if hasattr(iterable, "values_list") and getattr(iterable, "_result_cache", None) is None:
return list(iterable.values_list("pk", flat=True))
return super().to_representation(iterable)
class BulkPrimaryKeyRelatedField(PrimaryKeyRelatedField):
"""PrimaryKeyRelatedField that uses bulk validation when many=True."""
@classmethod
def many_init(cls, *args, **kwargs):
allow_empty = kwargs.pop("allow_empty", None)
max_length = kwargs.pop("max_length", None)
min_length = kwargs.pop("min_length", None)
child_relation = cls(*args, **kwargs)
list_kwargs = {
"child_relation": child_relation,
}
if allow_empty is not None:
list_kwargs["allow_empty"] = allow_empty
if max_length is not None:
list_kwargs["max_length"] = max_length
if min_length is not None:
list_kwargs["min_length"] = min_length
list_kwargs.update(
{
key: value
for key, value in kwargs.items()
if key in ("required", "default", "source")
}
)
return BulkManyRelatedField(**list_kwargs)
PARTIAL_USER_SERIALIZER_MODEL_FIELDS = [
"pk",
"username",
@@ -150,7 +75,6 @@ class GroupSerializer(ModelSerializer):
"""Group Serializer"""
attributes = JSONDictField(required=False)
users = BulkPrimaryKeyRelatedField(queryset=User.objects.all(), many=True, default=list)
parents = PrimaryKeyRelatedField(queryset=Group.objects.all(), many=True, required=False)
parents_obj = SerializerMethodField(allow_null=True)
children_obj = SerializerMethodField(allow_null=True)
@@ -265,6 +189,9 @@ class GroupSerializer(ModelSerializer):
"children_obj",
]
extra_kwargs = {
"users": {
"default": list,
},
"children": {
"required": False,
"default": list,
@@ -294,7 +221,6 @@ class GroupFilter(FilterSet):
members_by_pk = ModelMultipleChoiceFilter(
field_name="users",
queryset=User.objects.all(),
distinct=False,
)
def filter_attributes(self, queryset, name, value):
@@ -339,6 +265,12 @@ class GroupViewSet(UsedByMixin, ModelViewSet):
]
def get_ql_fields(self):
from djangoql.schema import BoolField, StrField
from authentik.enterprise.search.fields import (
JSONSearchField,
)
return [
StrField(Group, "name"),
BoolField(Group, "is_superuser", nullable=True),
@@ -346,8 +278,7 @@ class GroupViewSet(UsedByMixin, ModelViewSet):
]
def get_queryset(self):
# Always prefetch parents and children since their PKs are always serialized
base_qs = Group.objects.all().prefetch_related("roles", "parents", "children")
base_qs = Group.objects.all().prefetch_related("roles")
if self.serializer_class(context={"request": self.request})._should_include_users:
# Only fetch fields needed by PartialUserSerializer to reduce DB load and instantiation
@@ -358,9 +289,16 @@ class GroupViewSet(UsedByMixin, ModelViewSet):
queryset=User.objects.all().only(*PARTIAL_USER_SERIALIZER_MODEL_FIELDS),
)
)
# When include_users=false, skip users prefetch entirely.
# BulkManyRelatedField.to_representation will use values_list to get PKs
# directly without loading User instances into memory.
else:
base_qs = base_qs.prefetch_related(
Prefetch("users", queryset=User.objects.all().only("id"))
)
if self.serializer_class(context={"request": self.request})._should_include_children:
base_qs = base_qs.prefetch_related("children")
if self.serializer_class(context={"request": self.request})._should_include_parents:
base_qs = base_qs.prefetch_related("parents")
return base_qs

View File

@@ -124,7 +124,7 @@ class TokenViewSet(UsedByMixin, ModelViewSet):
"""Token Viewset"""
lookup_field = "identifier"
queryset = Token.objects.including_expired().all()
queryset = Token.objects.all()
serializer_class = TokenSerializer
search_fields = [
"identifier",

View File

@@ -2,8 +2,9 @@
from django.apps import apps
from django.db.models import Model
from django.utils.translation import gettext as _
from drf_spectacular.utils import PolymorphicProxySerializer, extend_schema, extend_schema_field
from rest_framework.exceptions import ValidationError
from rest_framework.exceptions import PermissionDenied, ValidationError
from rest_framework.fields import BooleanField, CharField, ChoiceField, DictField, ListField
from rest_framework.permissions import IsAuthenticated
from rest_framework.request import Request
@@ -12,7 +13,6 @@ from rest_framework.views import APIView
from yaml import ScalarNode
from authentik.api.validation import validate
from authentik.blueprints.api import check_blueprint_perms
from authentik.blueprints.v1.common import (
Blueprint,
BlueprintEntry,
@@ -165,7 +165,21 @@ class TransactionalApplicationView(APIView):
def put(self, request: Request, body: TransactionApplicationSerializer) -> Response:
"""Convert data into a blueprint, validate it and apply it"""
blueprint: Blueprint = body.validated_data
check_blueprint_perms(blueprint, request.user, explicit_action="add")
for entry in blueprint.entries:
full_model = entry.get_model(blueprint)
app, __, model = full_model.partition(".")
if not request.user.has_perm(f"{app}.add_{model}"):
raise PermissionDenied(
{
entry.id: _(
"User lacks permission to create {model}".format_map(
{
"model": full_model,
}
)
)
}
)
importer = Importer(blueprint, {})
applied = importer.apply()
response = {"applied": False, "logs": []}

View File

@@ -6,7 +6,6 @@ from typing import Any
from django.contrib.auth import update_session_auth_hash
from django.contrib.auth.models import AnonymousUser, Permission
from django.db.models import Exists, OuterRef, Prefetch, Q
from django.db.transaction import atomic
from django.db.utils import IntegrityError
from django.urls import reverse_lazy
@@ -14,7 +13,6 @@ from django.utils.http import urlencode
from django.utils.text import slugify
from django.utils.timezone import now
from django.utils.translation import gettext as _
from django.utils.translation import gettext_lazy
from django_filters.filters import (
BooleanFilter,
CharFilter,
@@ -24,7 +22,6 @@ from django_filters.filters import (
UUIDFilter,
)
from django_filters.filterset import FilterSet
from djangoql.schema import BoolField, StrField
from drf_spectacular.types import OpenApiTypes
from drf_spectacular.utils import (
OpenApiParameter,
@@ -58,10 +55,6 @@ from rest_framework.viewsets import ModelViewSet
from structlog.stdlib import get_logger
from authentik.api.authentication import TokenAuthentication
from authentik.api.search.fields import (
ChoiceSearchField,
JSONSearchField,
)
from authentik.api.validation import validate
from authentik.blueprints.v1.importer import SERIALIZER_CONTEXT_BLUEPRINT
from authentik.brands.models import Brand
@@ -79,7 +72,6 @@ from authentik.core.middleware import (
from authentik.core.models import (
USER_ATTRIBUTE_TOKEN_EXPIRING,
USER_PATH_SERVICE_ACCOUNT,
USERNAME_MAX_LENGTH,
Group,
Session,
Token,
@@ -107,10 +99,6 @@ from authentik.stages.email.utils import TemplateEmailMessage
LOGGER = get_logger()
INVALID_PASSWORD_HASH_MESSAGE = gettext_lazy(
"Invalid password hash format. Must be a valid Django password hash."
)
class ParamUserSerializer(PassiveSerializer):
"""Partial serializer for query parameters to select a user"""
@@ -137,7 +125,7 @@ class PartialGroupSerializer(ModelSerializer):
class UserSerializer(ModelSerializer):
"""User Serializer"""
is_superuser = SerializerMethodField()
is_superuser = BooleanField(read_only=True)
avatar = SerializerMethodField()
attributes = JSONDictField(required=False)
groups = PrimaryKeyRelatedField(
@@ -156,7 +144,7 @@ class UserSerializer(ModelSerializer):
roles_obj = SerializerMethodField(allow_null=True)
uid = CharField(read_only=True)
username = CharField(
max_length=USERNAME_MAX_LENGTH,
max_length=150,
validators=[UniqueValidator(queryset=User.objects.all().order_by("username"))],
)
@@ -174,14 +162,6 @@ class UserSerializer(ModelSerializer):
return True
return str(request.query_params.get("include_roles", "true")).lower() == "true"
@extend_schema_field(BooleanField)
def get_is_superuser(self, instance: User) -> bool:
"""Use annotation if available to avoid N+1 query"""
ann = getattr(instance, "_annotated_is_superuser", None)
if ann is not None:
return ann
return instance.is_superuser
@extend_schema_field(PartialGroupSerializer(many=True))
def get_groups_obj(self, instance: User) -> list[PartialGroupSerializer] | None:
if not self._should_include_groups:
@@ -195,79 +175,47 @@ class UserSerializer(ModelSerializer):
return RoleSerializer(instance.roles, many=True).data
def __init__(self, *args, **kwargs):
"""Setting password and permissions directly is allowed only in blueprints."""
super().__init__(*args, **kwargs)
if SERIALIZER_CONTEXT_BLUEPRINT in self.context:
self.fields["password"] = CharField(required=False, allow_null=True)
self.fields["password_hash"] = CharField(required=False, allow_null=True)
self.fields["permissions"] = ListField(
required=False,
child=ChoiceField(choices=get_permission_choices()),
)
def create(self, validated_data: dict) -> User:
"""Create a user, with blueprint-only password and permission writes."""
is_blueprint = SERIALIZER_CONTEXT_BLUEPRINT in self.context
if is_blueprint:
password = validated_data.pop("password", None)
password_hash = validated_data.pop("password_hash", None)
permissions = validated_data.pop("permissions", [])
self._validate_password_inputs(password, password_hash)
"""If this serializer is used in the blueprint context, we allow for
directly setting a password. However should be done via the `set_password`
method instead of directly setting it like rest_framework."""
password = validated_data.pop("password", None)
perms_qs = Permission.objects.filter(
codename__in=[x.split(".")[1] for x in validated_data.pop("permissions", [])]
).values_list("content_type__app_label", "codename")
perms_list = [f"{ct}.{name}" for ct, name in list(perms_qs)]
instance: User = super().create(validated_data)
if is_blueprint:
self._set_password(instance, password, password_hash)
perms_qs = Permission.objects.filter(
codename__in=[permission.split(".")[1] for permission in permissions]
).values_list("content_type__app_label", "codename")
perms_list = [f"{ct}.{name}" for ct, name in perms_qs]
instance.assign_perms_to_managed_role(perms_list)
self._ensure_password_not_empty(instance)
self._set_password(instance, password)
instance.assign_perms_to_managed_role(perms_list)
return instance
def update(self, instance: User, validated_data: dict) -> User:
"""Update a user, with blueprint-only password and permission writes."""
is_blueprint = SERIALIZER_CONTEXT_BLUEPRINT in self.context
if is_blueprint:
password = validated_data.pop("password", None)
password_hash = validated_data.pop("password_hash", None)
permissions = validated_data.pop("permissions", [])
self._validate_password_inputs(password, password_hash)
"""Same as `create` above, set the password directly if we're in a blueprint
context"""
password = validated_data.pop("password", None)
perms_qs = Permission.objects.filter(
codename__in=[x.split(".")[1] for x in validated_data.pop("permissions", [])]
).values_list("content_type__app_label", "codename")
perms_list = [f"{ct}.{name}" for ct, name in list(perms_qs)]
instance = super().update(instance, validated_data)
if is_blueprint:
self._set_password(instance, password, password_hash)
perms_qs = Permission.objects.filter(
codename__in=[permission.split(".")[1] for permission in permissions]
).values_list("content_type__app_label", "codename")
perms_list = [f"{ct}.{name}" for ct, name in perms_qs]
instance.assign_perms_to_managed_role(perms_list)
self._ensure_password_not_empty(instance)
self._set_password(instance, password)
instance.assign_perms_to_managed_role(perms_list)
return instance
def _validate_password_inputs(self, password: str | None, password_hash: str | None):
"""Validate mutually-exclusive password inputs before any model mutation."""
if password is not None and password_hash is not None:
raise ValidationError(_("Cannot set both password and password_hash. Use only one."))
if password_hash is None:
return
try:
User.validate_password_hash(password_hash)
except ValueError as exc:
LOGGER.warning("Failed to identify password hash format", exc_info=exc)
raise ValidationError(INVALID_PASSWORD_HASH_MESSAGE) from exc
def _set_password(self, instance: User, password: str | None, password_hash: str | None = None):
"""Set password from plain text or hash."""
if password_hash is not None:
instance.set_password_from_hash(password_hash)
instance.save()
elif password:
def _set_password(self, instance: User, password: str | None):
"""Set password of user if we're in a blueprint context, and if it's an empty
string then use an unusable password"""
if SERIALIZER_CONTEXT_BLUEPRINT in self.context and password:
instance.set_password(password)
instance.save()
def _ensure_password_not_empty(self, instance: User):
"""Store an explicit unusable password instead of an empty password field."""
if len(instance.password) == 0:
instance.set_unusable_password()
instance.save()
@@ -436,12 +384,6 @@ class UserPasswordSetSerializer(PassiveSerializer):
password = CharField(required=True)
class UserPasswordHashSetSerializer(PassiveSerializer):
"""Payload to set a users' password hash directly"""
password = CharField(required=True)
class UserServiceAccountSerializer(PassiveSerializer):
"""Payload to create a service account"""
@@ -563,9 +505,6 @@ class UsersFilter(FilterSet):
class UserViewSet(
ConditionalInheritance(
"authentik.enterprise.stages.account_lockdown.api.UserAccountLockdownMixin"
),
ConditionalInheritance("authentik.enterprise.reports.api.reports.ExportMixin"),
UsedByMixin,
ModelViewSet,
@@ -584,6 +523,13 @@ class UserViewSet(
]
def get_ql_fields(self):
from djangoql.schema import BoolField, StrField
from authentik.enterprise.search.fields import (
ChoiceSearchField,
JSONSearchField,
)
return [
StrField(User, "username"),
StrField(User, "name"),
@@ -596,30 +542,10 @@ class UserViewSet(
def get_queryset(self):
base_qs = User.objects.all().exclude_anonymous()
# Always prefetch groups since group PKs are always serialized.
# Use full prefetch when include_groups=true (for groups_obj), ID-only otherwise.
if self.serializer_class(context={"request": self.request})._should_include_groups:
base_qs = base_qs.prefetch_related("groups")
else:
base_qs = base_qs.prefetch_related(
Prefetch("groups", queryset=Group.objects.all().only("group_uuid"))
)
if self.serializer_class(context={"request": self.request})._should_include_roles:
base_qs = base_qs.prefetch_related("roles")
else:
base_qs = base_qs.prefetch_related(
Prefetch("roles", queryset=Role.objects.all().only("uuid"))
)
# Annotate is_superuser to avoid N+1 query per user
base_qs = base_qs.annotate(
_annotated_is_superuser=Exists(
Group.objects.filter(
is_superuser=True,
).filter(
Q(users=OuterRef("pk")) | Q(descendant_nodes__descendant__users=OuterRef("pk"))
)
)
)
return base_qs
@extend_schema(
@@ -788,11 +714,6 @@ class UserViewSet(
self.request.session.modified = True
return Response(serializer.initial_data)
def _update_session_hash_after_password_change(self, request: Request, user: User):
if user.pk == request.user.pk and SESSION_KEY_IMPERSONATE_USER not in self.request.session:
LOGGER.debug("Updating session hash after password change")
update_session_auth_hash(self.request, user)
@permission_required("authentik_core.reset_user_password")
@extend_schema(
request=UserPasswordSetSerializer,
@@ -816,45 +737,9 @@ class UserViewSet(
except (ValidationError, IntegrityError) as exc:
LOGGER.debug("Failed to set password", exc=exc)
return Response(status=400)
self._update_session_hash_after_password_change(request, user)
return Response(status=204)
@permission_required("authentik_core.reset_user_password")
@extend_schema(
request=UserPasswordHashSetSerializer,
responses={
204: OpenApiResponse(description="Successfully changed password"),
400: OpenApiResponse(description="Bad request"),
},
)
@action(
detail=True,
methods=["POST"],
permission_classes=[IsAuthenticated],
)
@validate(UserPasswordHashSetSerializer)
def set_password_hash(
self, request: Request, pk: int, body: UserPasswordHashSetSerializer
) -> Response:
"""Set a user's password from a pre-hashed Django password value.
Submit the Django password hash in the shared ``password`` request field.
This updates authentik's local password verifier only. It does not attempt
to propagate the password change to LDAP or Kerberos because no raw password
is available from the request payload.
"""
user: User = self.get_object()
try:
user.set_password_from_hash(body.validated_data["password"], request=request)
user.save()
except ValueError as exc:
LOGGER.debug("Failed to set password hash", exc=exc)
return Response(data={"password": [INVALID_PASSWORD_HASH_MESSAGE]}, status=400)
except (ValidationError, IntegrityError) as exc:
LOGGER.debug("Failed to set password hash", exc=exc)
return Response(status=400)
self._update_session_hash_after_password_change(request, user)
if user.pk == request.user.pk and SESSION_KEY_IMPERSONATE_USER not in self.request.session:
LOGGER.debug("Updating session hash after password change")
update_session_auth_hash(self.request, user)
return Response(status=204)
@permission_required("authentik_core.reset_user_password")

View File

@@ -1,26 +1,7 @@
"""authentik core app config"""
from django.utils.translation import gettext_lazy as _
from authentik.blueprints.apps import ManagedAppConfig
from authentik.tasks.schedules.common import ScheduleSpec
from authentik.tenants.flags import Flag
class Setup(Flag[bool], key="setup"):
default = False
visibility = "system"
class AppAccessWithoutBindings(Flag[bool], key="core_default_app_access"):
default = True
visibility = "none"
description = _(
"Configure if applications without any policy/group/user bindings "
"should be accessible to any user."
)
class AuthentikCoreConfig(ManagedAppConfig):
@@ -32,10 +13,6 @@ class AuthentikCoreConfig(ManagedAppConfig):
mountpoint = ""
default = True
def import_related(self):
super().import_related()
self.import_module("authentik.core.setup.signals")
@ManagedAppConfig.reconcile_tenant
def source_inbuilt(self):
"""Reconcile inbuilt source"""

View File

@@ -81,7 +81,7 @@ class TokenBackend(InbuiltBackend):
User().set_password(password, request=request)
return None
tokens = Token.objects.filter(
tokens = Token.filter_not_expired(
user=user, key=password, intent=TokenIntents.INTENT_APP_PASSWORD
)
if not tokens.exists():

View File

@@ -1,28 +0,0 @@
"""Hash password using Django's password hashers"""
from django.contrib.auth.hashers import make_password
from django.core.management.base import BaseCommand, CommandError
class Command(BaseCommand):
"""Hash a password using Django's password hashers"""
help = "Hash a password for use with AUTHENTIK_BOOTSTRAP_PASSWORD_HASH"
def add_arguments(self, parser):
parser.add_argument(
"password",
type=str,
help="Password to hash",
)
def handle(self, *args, **options):
password = options["password"]
if not password:
raise CommandError("Password cannot be empty")
try:
hashed = make_password(password)
self.stdout.write(hashed)
except ValueError as exc:
raise CommandError(f"Error hashing password: {exc}") from exc

View File

@@ -1,61 +0,0 @@
# Generated by Django 5.2.13 on 2026-04-21 18:49
from django.apps.registry import Apps
from django.db.backends.base.schema import BaseDatabaseSchemaEditor
from django.db import migrations
def check_is_already_setup(apps: Apps, schema_editor: BaseDatabaseSchemaEditor):
from django.conf import settings
from authentik.flows.models import FlowAuthenticationRequirement
VersionHistory = apps.get_model("authentik_admin", "VersionHistory")
Flow = apps.get_model("authentik_flows", "Flow")
User = apps.get_model("authentik_core", "User")
db_alias = schema_editor.connection.alias
# Upgrading from a previous version
if not settings.TEST and VersionHistory.objects.using(db_alias).count() > 1:
return True
# OOBE flow sets itself to this authentication requirement once finished
if (
Flow.objects.using(db_alias)
.filter(
slug="initial-setup", authentication=FlowAuthenticationRequirement.REQUIRE_SUPERUSER
)
.exists()
):
return True
# non-akadmin and non-guardian anonymous user exist
if (
User.objects.using(db_alias)
.exclude(username="akadmin")
.exclude(username="AnonymousUser")
.exists()
):
return True
return False
def update_setup_flag(apps: Apps, schema_editor: BaseDatabaseSchemaEditor):
from authentik.core.apps import Setup
from authentik.tenants.utils import get_current_tenant
is_already_setup = check_is_already_setup(apps, schema_editor)
if is_already_setup:
tenant = get_current_tenant()
tenant.flags[Setup().key] = True
tenant.save()
class Migration(migrations.Migration):
dependencies = [
("authentik_core", "0057_remove_user_groups_remove_user_user_permissions_and_more"),
# 0024_flow_authentication adds the `authentication` field.
("authentik_flows", "0024_flow_authentication"),
]
operations = [migrations.RunPython(update_setup_flag, migrations.RunPython.noop)]

View File

@@ -1,33 +0,0 @@
# Generated by Django 5.2.12 on 2026-04-09 18:04
from django.apps.registry import Apps
from django.db import migrations, models
from django.db.backends.base.schema import BaseDatabaseSchemaEditor
def migrate_blank_launch_url(apps: Apps, schema_editor: BaseDatabaseSchemaEditor):
db_alias = schema_editor.connection.alias
Application = apps.get_model("authentik_core", "Application")
Application.objects.using(db_alias).filter(meta_launch_url="blank://blank").update(
meta_hide=True, meta_launch_url=""
)
class Migration(migrations.Migration):
dependencies = [
("authentik_core", "0058_setup"),
]
operations = [
migrations.AddField(
model_name="application",
name="meta_hide",
field=models.BooleanField(
default=False,
help_text="Hide this application from the user's My applications page.",
),
),
migrations.RunPython(migrate_blank_launch_url, migrations.RunPython.noop),
]

View File

@@ -1,8 +1,6 @@
"""authentik core models"""
import re
import traceback
from datetime import datetime
from datetime import datetime, timedelta
from enum import StrEnum
from hashlib import sha256
from typing import Any, Self
@@ -10,13 +8,14 @@ from uuid import uuid4
import pgtrigger
from deepmerge import always_merger
from django.contrib.auth.hashers import check_password, identify_hasher
from django.contrib.auth.hashers import check_password
from django.contrib.auth.models import AbstractUser, Permission
from django.contrib.auth.models import UserManager as DjangoUserManager
from django.contrib.sessions.base_session import AbstractBaseSession
from django.core.validators import validate_slug
from django.db import models
from django.db.models import Manager, Q, QuerySet, options
from django.db.models import Q, QuerySet, options
from django.db.models.constants import LOOKUP_SEP
from django.http import HttpRequest
from django.utils.functional import cached_property
from django.utils.timezone import now
@@ -44,8 +43,6 @@ from authentik.lib.models import (
DomainlessFormattedURLValidator,
SerializerModel,
)
from authentik.lib.utils.inheritance import get_deepest_child
from authentik.lib.utils.reflection import class_to_path
from authentik.lib.utils.time import timedelta_from_string
from authentik.policies.models import PolicyBindingModel
from authentik.rbac.models import Role
@@ -53,7 +50,6 @@ from authentik.tenants.models import DEFAULT_TOKEN_DURATION, DEFAULT_TOKEN_LENGT
from authentik.tenants.utils import get_current_tenant, get_unique_identifier
LOGGER = get_logger()
USERNAME_MAX_LENGTH = 150
USER_PATH_SYSTEM_PREFIX = "goauthentik.io"
_USER_ATTR_PREFIX = f"{USER_PATH_SYSTEM_PREFIX}/user"
USER_ATTRIBUTE_DEBUG = f"{_USER_ATTR_PREFIX}/debug"
@@ -518,7 +514,7 @@ class User(SerializerModel, AttributesMixin, AbstractUser):
@property
def ak_groups(self):
"""This is a proxy for a renamed, deprecated field."""
from authentik.events.models import Event
from authentik.events.models import Event, EventAction
deprecation = "authentik.core.models.User.ak_groups"
replacement = "authentik.core.models.User.groups"
@@ -531,23 +527,23 @@ class User(SerializerModel, AttributesMixin, AbstractUser):
"default: in 30 days). See authentik logs for every will invocation of this "
"deprecation."
)
stacktrace = traceback.format_stack()
# The last line is this function, the next-to-last line is its caller
cause = stacktrace[-2] if len(stacktrace) > 1 else "Unknown, see stacktrace in logs"
if search := re.search(r'"(.*?)"', cause):
cause = f"Property mapping or Expression policy named {search.group(1)}"
LOGGER.warning(
"deprecation used",
message=message_logger,
deprecation=deprecation,
replacement=replacement,
cause=cause,
stacktrace=stacktrace,
)
Event.log_deprecation(
deprecation, message=message_event, cause=cause, replacement=replacement
)
if not Event.filter_not_expired(
action=EventAction.CONFIGURATION_WARNING, context__deprecation=deprecation
).exists():
event = Event.new(
EventAction.CONFIGURATION_WARNING,
deprecation=deprecation,
replacement=replacement,
message=message_event,
)
event.expires = datetime.now() + timedelta(days=30)
event.save()
return self.groups
def set_password(self, raw_password, signal=True, sender=None, request=None):
@@ -560,33 +556,6 @@ class User(SerializerModel, AttributesMixin, AbstractUser):
self.password_change_date = now()
return super().set_password(raw_password)
@staticmethod
def validate_password_hash(password_hash: str):
"""Validate that the value is a recognized Django password hash."""
identify_hasher(password_hash) # Raises ValueError if invalid
def set_password_from_hash(self, password_hash: str, signal=True, sender=None, request=None):
"""Set password directly from a pre-hashed value.
Unlike set_password(), this does not hash the input again. The provided value
must already be a valid Django password hash, and it is stored directly on the
user after validation.
Because no raw password is available, downstream password sync integrations
such as LDAP and Kerberos cannot be updated from this code path.
Raises ValueError if the hash format is not recognized.
"""
self.validate_password_hash(password_hash)
if self.pk and signal:
from authentik.core.signals import password_hash_changed
if not sender:
sender = self
password_hash_changed.send(sender=sender, user=self, request=request)
self.password = password_hash
self.password_change_date = now()
def check_password(self, raw_password: str) -> bool:
"""
Return a boolean of whether the raw_password was correct. Handles
@@ -762,9 +731,6 @@ class Application(SerializerModel, PolicyBindingModel):
meta_icon = FileField(default="", blank=True)
meta_description = models.TextField(default="", blank=True)
meta_publisher = models.TextField(default="", blank=True)
meta_hide = models.BooleanField(
default=False, help_text=_("Hide this application from the user's My applications page.")
)
objects = ApplicationQuerySet.as_manager()
@@ -820,21 +786,35 @@ class Application(SerializerModel, PolicyBindingModel):
def get_provider(self) -> Provider | None:
"""Get casted provider instance. Needs Application queryset with_provider"""
if hasattr(self, "_cached_provider"):
return self._cached_provider
if not self.provider:
self._cached_provider = None
return None
self._cached_provider = get_deepest_child(self.provider)
return self._cached_provider
candidates = []
base_class = Provider
for subclass in base_class.objects.get_queryset()._get_subclasses_recurse(base_class):
parent = self.provider
for level in subclass.split(LOOKUP_SEP):
try:
parent = getattr(parent, level)
except AttributeError:
break
if parent in candidates:
continue
idx = subclass.count(LOOKUP_SEP)
if type(parent) is not base_class:
idx += 1
candidates.insert(idx, parent)
if not candidates:
return None
return candidates[-1]
def backchannel_provider_for[T: Provider](self, provider_type: type[T], **kwargs) -> T | None:
"""Get Backchannel provider for a specific type"""
provider: BackchannelProvider | None = self.backchannel_providers.filter(
providers = self.backchannel_providers.filter(
**{f"{provider_type._meta.model_name}__isnull": False},
**kwargs,
).first()
return getattr(provider, provider_type._meta.model_name) if provider else None
)
return getattr(providers.first(), provider_type._meta.model_name)
def __str__(self):
return str(self.name)
@@ -985,34 +965,21 @@ class Source(ManagedModel, SerializerModel, PolicyBindingModel):
objects = InheritanceManager()
def get_icon_url(self, request=None, use_cache: bool = True) -> str | None:
"""Get the URL to the source icon."""
if not self.icon:
return None
return get_file_manager(FileUsage.MEDIA).file_url(self.icon, request, use_cache=use_cache)
@property
def icon_url(self) -> str | None:
"""Get the URL to the source icon"""
return self.get_icon_url()
def get_icon_themed_urls(
self,
request=None,
use_cache: bool = True,
) -> dict[str, str] | None:
"""Get themed URLs for icon if it contains %(theme)s."""
if not self.icon:
return None
return get_file_manager(FileUsage.MEDIA).themed_urls(
self.icon,
request,
use_cache=use_cache,
)
return get_file_manager(FileUsage.MEDIA).file_url(self.icon)
@property
def icon_themed_urls(self) -> dict[str, str] | None:
return self.get_icon_themed_urls()
"""Get themed URLs for icon if it contains %(theme)s"""
if not self.icon:
return None
return get_file_manager(FileUsage.MEDIA).themed_urls(self.icon)
def get_user_path(self) -> str:
"""Get user path, fallback to default for formatting errors"""
@@ -1132,24 +1099,12 @@ class GroupSourceConnection(SerializerModel, CreatedUpdatedModel):
unique_together = (("group", "source"),)
class ExpiringManager(Manager):
"""Manager for expiring objects which filters out expired objects by default"""
def get_queryset(self):
return QuerySet(self.model, using=self._db).exclude(expires__lt=now(), expiring=True)
def including_expired(self):
return QuerySet(self.model, using=self._db)
class ExpiringModel(models.Model):
"""Base Model which can expire, and is automatically cleaned up."""
expires = models.DateTimeField(default=None, null=True)
expiring = models.BooleanField(default=True)
objects = ExpiringManager()
class Meta:
abstract = True
indexes = [
@@ -1163,33 +1118,13 @@ class ExpiringModel(models.Model):
default the object is deleted. This is less efficient compared
to bulk deleting objects, but classes like Token() need to change
values instead of being deleted."""
try:
return self.delete(*args, **kwargs)
except self.DoesNotExist:
# Object has already been deleted, so this should be fine
return None
return self.delete(*args, **kwargs)
@classmethod
def filter_not_expired(cls, **kwargs) -> QuerySet[Self]:
"""Filer for tokens which are not expired yet or are not expiring,
and match filters in `kwargs`"""
from authentik.events.models import Event
deprecation_id = f"{class_to_path(cls)}.filter_not_expired"
Event.log_deprecation(
deprecation_id,
message=(
".filter_not_expired() is deprecated as the default lookup now excludes "
"expired objects."
),
)
for obj in (
cls.objects.including_expired()
.filter(**kwargs)
.filter(Q(expires__lt=now(), expiring=True))
):
for obj in cls.objects.filter(**kwargs).filter(Q(expires__lt=now(), expiring=True)):
obj.delete()
return cls.objects.filter(**kwargs)

View File

@@ -72,7 +72,6 @@ class SessionStore(SessionBase):
# and their descriptors fail to initialize (e.g., missing storage)
# TypeError - can happen with incompatible pickled objects
# If any of these happen, just return an empty dictionary (an empty session)
LOGGER.warning("Failed to decode session data", exc_info=True)
pass
return {}

View File

@@ -1,42 +0,0 @@
from os import getenv
from django.dispatch import receiver
from structlog.stdlib import get_logger
from authentik.blueprints.models import BlueprintInstance
from authentik.blueprints.v1.importer import Importer
from authentik.core.apps import Setup
from authentik.root.signals import post_startup
from authentik.tenants.models import Tenant
BOOTSTRAP_BLUEPRINT = "system/bootstrap.yaml"
LOGGER = get_logger()
@receiver(post_startup)
def post_startup_setup_bootstrap(sender, **_):
if (
not getenv("AUTHENTIK_BOOTSTRAP_PASSWORD")
and not getenv("AUTHENTIK_BOOTSTRAP_PASSWORD_HASH")
and not getenv("AUTHENTIK_BOOTSTRAP_TOKEN")
):
return
LOGGER.info("Configuring authentik through bootstrap environment variables")
content = BlueprintInstance(path=BOOTSTRAP_BLUEPRINT).retrieve()
# If we have bootstrap credentials set, run bootstrap tasks outside of main server
# sync, so that we can sure the first start actually has working bootstrap
# credentials
for tenant in Tenant.objects.filter(ready=True):
if Setup.get(tenant=tenant):
LOGGER.info("Tenant is already setup, skipping", tenant=tenant.schema_name)
continue
with tenant:
importer = Importer.from_string(content)
valid, logs = importer.validate()
if not valid:
LOGGER.warning("Blueprint invalid", tenant=tenant.schema_name)
for log in logs:
log.log()
importer.apply()
Setup.set(True, tenant=tenant)

View File

@@ -1,80 +0,0 @@
from functools import lru_cache
from http import HTTPMethod, HTTPStatus
from django.contrib.staticfiles import finders
from django.db import transaction
from django.http import HttpRequest, HttpResponse
from django.shortcuts import redirect
from django.urls import reverse
from django.views import View
from structlog.stdlib import get_logger
from authentik.blueprints.models import BlueprintInstance
from authentik.core.apps import Setup
from authentik.flows.models import Flow, FlowAuthenticationRequirement, in_memory_stage
from authentik.flows.planner import FlowPlanner
from authentik.flows.stage import StageView
LOGGER = get_logger()
FLOW_CONTEXT_START_BY = "goauthentik.io/core/setup/started-by"
@lru_cache
def read_static(path: str) -> str | None:
result = finders.find(path)
if not result:
return None
with open(result, encoding="utf8") as _file:
return _file.read()
class SetupView(View):
setup_flow_slug = "initial-setup"
def dispatch(self, request: HttpRequest, *args, **kwargs):
if request.method != HTTPMethod.HEAD and Setup.get():
return redirect(reverse("authentik_core:root-redirect"))
return super().dispatch(request, *args, **kwargs)
def head(self, request: HttpRequest, *args, **kwargs):
if Setup.get():
return HttpResponse(status=HTTPStatus.SERVICE_UNAVAILABLE)
if not Flow.objects.filter(slug=self.setup_flow_slug).exists():
return HttpResponse(status=HTTPStatus.SERVICE_UNAVAILABLE)
return HttpResponse(status=HTTPStatus.OK)
def get(self, request: HttpRequest):
flow = Flow.objects.filter(slug=self.setup_flow_slug).first()
if not flow:
LOGGER.info("Setup flow does not exist yet, waiting for worker to finish")
return HttpResponse(
read_static("dist/standalone/loading/startup.html"),
status=HTTPStatus.SERVICE_UNAVAILABLE,
)
planner = FlowPlanner(flow)
plan = planner.plan(request, {FLOW_CONTEXT_START_BY: "setup"})
plan.append_stage(in_memory_stage(PostSetupStageView))
return plan.to_redirect(request, flow)
class PostSetupStageView(StageView):
"""Run post-setup tasks"""
def post(self, request: HttpRequest, *args, **kwargs) -> HttpResponse:
"""Wrapper when this stage gets hit with a post request"""
return self.get(request, *args, **kwargs)
def get(self, requeset: HttpRequest, *args, **kwargs):
with transaction.atomic():
# Remember we're setup
Setup.set(True)
# Disable OOBE Blueprints
BlueprintInstance.objects.filter(
**{"metadata__labels__blueprints.goauthentik.io/system-oobe": "true"}
).update(enabled=False)
# Make flow inaccessible
Flow.objects.filter(slug="initial-setup").update(
authentication=FlowAuthenticationRequirement.REQUIRE_SUPERUSER
)
return self.executor.stage_ok()

View File

@@ -1,5 +1,6 @@
"""authentik core signals"""
from asgiref.sync import async_to_sync
from channels.layers import get_channel_layer
from django.contrib.auth.signals import user_logged_in
from django.core.cache import cache
@@ -23,10 +24,7 @@ from authentik.root.ws.consumer import build_device_group
# Arguments: user: User, password: str
password_changed = Signal()
# Arguments: user: User, request: HttpRequest | None
password_hash_changed = Signal()
# Arguments: credentials: dict[str, any], request: HttpRequest,
# stage: Stage, context: dict[str, any]
# Arguments: credentials: dict[str, any], request: HttpRequest, stage: Stage
login_failed = Signal()
LOGGER = get_logger()
@@ -58,7 +56,7 @@ def user_logged_in_session(sender, request: HttpRequest, user: User, **_):
layer = get_channel_layer()
device_cookie = request.COOKIES.get("authentik_device")
if device_cookie:
layer.group_send_blocking(
async_to_sync(layer.group_send)(
build_device_group(device_cookie),
{"type": "event.session.authenticated"},
)

View File

@@ -27,10 +27,7 @@ def clean_expired_models():
for cls in ExpiringModel.__subclasses__():
cls: ExpiringModel
objects = (
cls.objects.including_expired()
.all()
.exclude(expiring=False)
.exclude(expiring=True, expires__gt=now())
cls.objects.all().exclude(expiring=False).exclude(expiring=True, expires__gt=now())
)
amount = objects.count()
for obj in chunked_queryset(objects):

View File

@@ -21,10 +21,6 @@
{% block head_before %}
{% endblock %}
{% block interface_stylesheet %}
<link rel="stylesheet" type="text/css" href="{% versioned_script 'dist/styles/interface-%v.css' %}" />
{% endblock %}
{% include "base/theme.html" %}
<style data-id="brand-css">{{ brand_css }}</style>

View File

@@ -1,6 +1,8 @@
{% load static %}
{% load authentik_core %}
<link rel="stylesheet" type="text/css" href="{% versioned_script 'dist/styles/interface-%v.css' %}" />
{% if ui_theme == "dark" %}
<meta name="color-scheme" content="dark" />
<meta name="theme-color" content="#18191a">

Some files were not shown because too many files have changed in this diff Show More