mirror of
https://github.com/goauthentik/authentik
synced 2026-04-25 17:15:26 +02:00
root: Better version bump (#14905)
Co-authored-by: Marc 'risson' Schmitt <marc.schmitt@risson.space>
This commit is contained in:
@@ -1,36 +0,0 @@
|
|||||||
[bumpversion]
|
|
||||||
current_version = 2025.6.4
|
|
||||||
tag = True
|
|
||||||
commit = True
|
|
||||||
parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)(?:-(?P<rc_t>[a-zA-Z-]+)(?P<rc_n>[1-9]\\d*))?
|
|
||||||
serialize =
|
|
||||||
{major}.{minor}.{patch}-{rc_t}{rc_n}
|
|
||||||
{major}.{minor}.{patch}
|
|
||||||
message = release: {new_version}
|
|
||||||
tag_name = version/{new_version}
|
|
||||||
|
|
||||||
[bumpversion:part:rc_t]
|
|
||||||
values =
|
|
||||||
rc
|
|
||||||
final
|
|
||||||
optional_value = final
|
|
||||||
|
|
||||||
[bumpversion:file:pyproject.toml]
|
|
||||||
|
|
||||||
[bumpversion:file:uv.lock]
|
|
||||||
|
|
||||||
[bumpversion:file:package.json]
|
|
||||||
|
|
||||||
[bumpversion:file:package-lock.json]
|
|
||||||
|
|
||||||
[bumpversion:file:docker-compose.yml]
|
|
||||||
|
|
||||||
[bumpversion:file:schema.yml]
|
|
||||||
|
|
||||||
[bumpversion:file:blueprints/schema.json]
|
|
||||||
|
|
||||||
[bumpversion:file:authentik/__init__.py]
|
|
||||||
|
|
||||||
[bumpversion:file:internal/constants/constants.go]
|
|
||||||
|
|
||||||
[bumpversion:file:lifecycle/aws/template.yaml]
|
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
htmlcov
|
htmlcov
|
||||||
*.env.yml
|
*.env.yml
|
||||||
|
node_modules
|
||||||
**/node_modules
|
**/node_modules
|
||||||
dist/**
|
dist/**
|
||||||
build/**
|
build/**
|
||||||
|
|||||||
@@ -54,6 +54,10 @@ outputs:
|
|||||||
runs:
|
runs:
|
||||||
using: "composite"
|
using: "composite"
|
||||||
steps:
|
steps:
|
||||||
|
- name: Setup authentik env
|
||||||
|
uses: ./.github/actions/setup
|
||||||
|
with:
|
||||||
|
dependencies: "python"
|
||||||
- name: Generate config
|
- name: Generate config
|
||||||
id: ev
|
id: ev
|
||||||
shell: bash
|
shell: bash
|
||||||
@@ -64,4 +68,4 @@ runs:
|
|||||||
PR_HEAD_SHA: ${{ github.event.pull_request.head.sha }}
|
PR_HEAD_SHA: ${{ github.event.pull_request.head.sha }}
|
||||||
REF: ${{ github.ref }}
|
REF: ${{ github.ref }}
|
||||||
run: |
|
run: |
|
||||||
python3 ${{ github.action_path }}/push_vars.py
|
uv run python3 ${{ github.action_path }}/push_vars.py
|
||||||
|
|||||||
@@ -1,13 +1,10 @@
|
|||||||
"""Helper script to get the actual branch name, docker safe"""
|
"""Helper script to get the actual branch name, docker safe"""
|
||||||
|
|
||||||
import configparser
|
|
||||||
import os
|
import os
|
||||||
|
from importlib.metadata import version as package_version
|
||||||
from json import dumps
|
from json import dumps
|
||||||
from time import time
|
from time import time
|
||||||
|
|
||||||
parser = configparser.ConfigParser()
|
|
||||||
parser.read(".bumpversion.cfg")
|
|
||||||
|
|
||||||
# Decide if we should push the image or not
|
# Decide if we should push the image or not
|
||||||
should_push = True
|
should_push = True
|
||||||
if len(os.environ.get("DOCKER_USERNAME", "")) < 1:
|
if len(os.environ.get("DOCKER_USERNAME", "")) < 1:
|
||||||
@@ -31,7 +28,7 @@ is_release = "dev" not in image_names[0]
|
|||||||
sha = os.environ["GITHUB_SHA"] if not is_pull_request else os.getenv("PR_HEAD_SHA")
|
sha = os.environ["GITHUB_SHA"] if not is_pull_request else os.getenv("PR_HEAD_SHA")
|
||||||
|
|
||||||
# 2042.1.0 or 2042.1.0-rc1
|
# 2042.1.0 or 2042.1.0-rc1
|
||||||
version = parser.get("bumpversion", "current_version")
|
version = package_version("authentik")
|
||||||
# 2042.1
|
# 2042.1
|
||||||
version_family = ".".join(version.split("-", 1)[0].split(".")[:-1])
|
version_family = ".".join(version.split("-", 1)[0].split(".")[:-1])
|
||||||
prerelease = "-" in version
|
prerelease = "-" in version
|
||||||
|
|||||||
12
.github/actions/setup/action.yml
vendored
12
.github/actions/setup/action.yml
vendored
@@ -2,6 +2,9 @@ name: "Setup authentik testing environment"
|
|||||||
description: "Setup authentik testing environment"
|
description: "Setup authentik testing environment"
|
||||||
|
|
||||||
inputs:
|
inputs:
|
||||||
|
dependencies:
|
||||||
|
description: "List of dependencies to setup"
|
||||||
|
default: "system,python,node,go,runtime"
|
||||||
postgresql_version:
|
postgresql_version:
|
||||||
description: "Optional postgresql image tag"
|
description: "Optional postgresql image tag"
|
||||||
default: "16"
|
default: "16"
|
||||||
@@ -10,42 +13,51 @@ runs:
|
|||||||
using: "composite"
|
using: "composite"
|
||||||
steps:
|
steps:
|
||||||
- name: Install apt deps
|
- name: Install apt deps
|
||||||
|
if: ${{ contains(inputs.dependencies, 'system') || contains(inputs.dependencies, 'python') }}
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
sudo apt-get update
|
sudo apt-get update
|
||||||
sudo apt-get install --no-install-recommends -y libpq-dev openssl libxmlsec1-dev pkg-config gettext libkrb5-dev krb5-kdc krb5-user krb5-admin-server
|
sudo apt-get install --no-install-recommends -y libpq-dev openssl libxmlsec1-dev pkg-config gettext libkrb5-dev krb5-kdc krb5-user krb5-admin-server
|
||||||
- name: Install uv
|
- name: Install uv
|
||||||
|
if: ${{ contains(inputs.dependencies, 'python') }}
|
||||||
uses: astral-sh/setup-uv@v5
|
uses: astral-sh/setup-uv@v5
|
||||||
with:
|
with:
|
||||||
enable-cache: true
|
enable-cache: true
|
||||||
- name: Setup python
|
- name: Setup python
|
||||||
|
if: ${{ contains(inputs.dependencies, 'python') }}
|
||||||
uses: actions/setup-python@v5
|
uses: actions/setup-python@v5
|
||||||
with:
|
with:
|
||||||
python-version-file: "pyproject.toml"
|
python-version-file: "pyproject.toml"
|
||||||
- name: Install Python deps
|
- name: Install Python deps
|
||||||
|
if: ${{ contains(inputs.dependencies, 'python') }}
|
||||||
shell: bash
|
shell: bash
|
||||||
run: uv sync --all-extras --dev --frozen
|
run: uv sync --all-extras --dev --frozen
|
||||||
- name: Setup node
|
- name: Setup node
|
||||||
|
if: ${{ contains(inputs.dependencies, 'node') }}
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version-file: web/package.json
|
node-version-file: web/package.json
|
||||||
cache: "npm"
|
cache: "npm"
|
||||||
cache-dependency-path: web/package-lock.json
|
cache-dependency-path: web/package-lock.json
|
||||||
- name: Setup go
|
- name: Setup go
|
||||||
|
if: ${{ contains(inputs.dependencies, 'go') }}
|
||||||
uses: actions/setup-go@v5
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version-file: "go.mod"
|
go-version-file: "go.mod"
|
||||||
- name: Setup docker cache
|
- name: Setup docker cache
|
||||||
|
if: ${{ contains(inputs.dependencies, 'runtime') }}
|
||||||
uses: AndreKurait/docker-cache@0fe76702a40db986d9663c24954fc14c6a6031b7
|
uses: AndreKurait/docker-cache@0fe76702a40db986d9663c24954fc14c6a6031b7
|
||||||
with:
|
with:
|
||||||
key: docker-images-${{ runner.os }}-${{ hashFiles('.github/actions/setup/docker-compose.yml', 'Makefile') }}-${{ inputs.postgresql_version }}
|
key: docker-images-${{ runner.os }}-${{ hashFiles('.github/actions/setup/docker-compose.yml', 'Makefile') }}-${{ inputs.postgresql_version }}
|
||||||
- name: Setup dependencies
|
- name: Setup dependencies
|
||||||
|
if: ${{ contains(inputs.dependencies, 'runtime') }}
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
export PSQL_TAG=${{ inputs.postgresql_version }}
|
export PSQL_TAG=${{ inputs.postgresql_version }}
|
||||||
docker compose -f .github/actions/setup/docker-compose.yml up -d
|
docker compose -f .github/actions/setup/docker-compose.yml up -d
|
||||||
cd web && npm ci
|
cd web && npm ci
|
||||||
- name: Generate config
|
- name: Generate config
|
||||||
|
if: ${{ contains(inputs.dependencies, 'python') }}
|
||||||
shell: uv run python {0}
|
shell: uv run python {0}
|
||||||
run: |
|
run: |
|
||||||
from authentik.lib.generators import generate_id
|
from authentik.lib.generators import generate_id
|
||||||
|
|||||||
20
Makefile
20
Makefile
@@ -16,6 +16,7 @@ GEN_API_GO = gen-go-api
|
|||||||
pg_user := $(shell uv run python -m authentik.lib.config postgresql.user 2>/dev/null)
|
pg_user := $(shell uv run python -m authentik.lib.config postgresql.user 2>/dev/null)
|
||||||
pg_host := $(shell uv run python -m authentik.lib.config postgresql.host 2>/dev/null)
|
pg_host := $(shell uv run python -m authentik.lib.config postgresql.host 2>/dev/null)
|
||||||
pg_name := $(shell uv run python -m authentik.lib.config postgresql.name 2>/dev/null)
|
pg_name := $(shell uv run python -m authentik.lib.config postgresql.name 2>/dev/null)
|
||||||
|
redis_db := $(shell uv run python -m authentik.lib.config redis.db 2>/dev/null)
|
||||||
|
|
||||||
all: lint-fix lint test gen web ## Lint, build, and test everything
|
all: lint-fix lint test gen web ## Lint, build, and test everything
|
||||||
|
|
||||||
@@ -57,7 +58,7 @@ migrate: ## Run the Authentik Django server's migrations
|
|||||||
i18n-extract: core-i18n-extract web-i18n-extract ## Extract strings that require translation into files to send to a translation service
|
i18n-extract: core-i18n-extract web-i18n-extract ## Extract strings that require translation into files to send to a translation service
|
||||||
|
|
||||||
aws-cfn:
|
aws-cfn:
|
||||||
cd lifecycle/aws && npm run aws-cfn
|
cd lifecycle/aws && npm i && npm run aws-cfn
|
||||||
|
|
||||||
run-server: ## Run the main authentik server process
|
run-server: ## Run the main authentik server process
|
||||||
uv run ak server
|
uv run ak server
|
||||||
@@ -79,10 +80,10 @@ core-i18n-extract:
|
|||||||
install: node-install docs-install core-install ## Install all requires dependencies for `node`, `docs` and `core`
|
install: node-install docs-install core-install ## Install all requires dependencies for `node`, `docs` and `core`
|
||||||
|
|
||||||
dev-drop-db:
|
dev-drop-db:
|
||||||
dropdb -U ${pg_user} -h ${pg_host} ${pg_name}
|
dropdb -U ${pg_user} -h ${pg_host} ${pg_name} || true
|
||||||
# Also remove the test-db if it exists
|
# Also remove the test-db if it exists
|
||||||
dropdb -U ${pg_user} -h ${pg_host} test_${pg_name} || true
|
dropdb -U ${pg_user} -h ${pg_host} test_${pg_name} || true
|
||||||
redis-cli -n 0 flushall
|
redis-cli -n ${redis_db} flushall
|
||||||
|
|
||||||
dev-create-db:
|
dev-create-db:
|
||||||
createdb -U ${pg_user} -h ${pg_host} ${pg_name}
|
createdb -U ${pg_user} -h ${pg_host} ${pg_name}
|
||||||
@@ -93,6 +94,16 @@ update-test-mmdb: ## Update test GeoIP and ASN Databases
|
|||||||
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-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
|
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
|
||||||
|
uv version $(version)
|
||||||
|
$(MAKE) gen-build gen-compose aws-cfn
|
||||||
|
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
|
||||||
|
|
||||||
#########################
|
#########################
|
||||||
## API Schema
|
## API Schema
|
||||||
#########################
|
#########################
|
||||||
@@ -107,6 +118,9 @@ gen-build: ## Extract the schema from the database
|
|||||||
AUTHENTIK_OUTPOSTS__DISABLE_EMBEDDED_OUTPOST=true \
|
AUTHENTIK_OUTPOSTS__DISABLE_EMBEDDED_OUTPOST=true \
|
||||||
uv run ak spectacular --file schema.yml
|
uv run ak spectacular --file schema.yml
|
||||||
|
|
||||||
|
gen-compose:
|
||||||
|
uv run scripts/generate_docker_compose.py
|
||||||
|
|
||||||
gen-changelog: ## (Release) generate the changelog based from the commits since the last tag
|
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
|
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
|
npx prettier --write changelog.md
|
||||||
|
|||||||
@@ -1,20 +1,28 @@
|
|||||||
"""authentik root module"""
|
"""authentik root module"""
|
||||||
|
|
||||||
|
from functools import lru_cache
|
||||||
|
from importlib.metadata import version
|
||||||
from os import environ
|
from os import environ
|
||||||
|
|
||||||
__version__ = "2025.6.4"
|
|
||||||
ENV_GIT_HASH_KEY = "GIT_BUILD_HASH"
|
ENV_GIT_HASH_KEY = "GIT_BUILD_HASH"
|
||||||
|
|
||||||
|
|
||||||
def get_build_hash(fallback: str | None = None) -> str:
|
@lru_cache
|
||||||
|
def authentik_version() -> str:
|
||||||
|
return version("authentik")
|
||||||
|
|
||||||
|
|
||||||
|
@lru_cache
|
||||||
|
def authentik_build_hash(fallback: str | None = None) -> str:
|
||||||
"""Get build hash"""
|
"""Get build hash"""
|
||||||
build_hash = environ.get(ENV_GIT_HASH_KEY, fallback if fallback else "")
|
build_hash = environ.get(ENV_GIT_HASH_KEY, fallback if fallback else "")
|
||||||
return fallback if build_hash == "" and fallback else build_hash
|
return fallback if build_hash == "" and fallback else build_hash
|
||||||
|
|
||||||
|
|
||||||
def get_full_version() -> str:
|
@lru_cache
|
||||||
|
def authentik_full_version() -> str:
|
||||||
"""Get full version, with build hash appended"""
|
"""Get full version, with build hash appended"""
|
||||||
version = __version__
|
version = authentik_version()
|
||||||
if (build_hash := get_build_hash()) != "":
|
if (build_hash := authentik_build_hash()) != "":
|
||||||
return f"{version}+{build_hash}"
|
return f"{version}+{build_hash}"
|
||||||
return version
|
return version
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ from rest_framework.request import Request
|
|||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
from rest_framework.views import APIView
|
from rest_framework.views import APIView
|
||||||
|
|
||||||
from authentik import get_full_version
|
from authentik import authentik_full_version
|
||||||
from authentik.core.api.utils import PassiveSerializer
|
from authentik.core.api.utils import PassiveSerializer
|
||||||
from authentik.enterprise.license import LicenseKey
|
from authentik.enterprise.license import LicenseKey
|
||||||
from authentik.lib.config import CONFIG
|
from authentik.lib.config import CONFIG
|
||||||
@@ -78,7 +78,7 @@ class SystemInfoSerializer(PassiveSerializer):
|
|||||||
"""Get versions"""
|
"""Get versions"""
|
||||||
return {
|
return {
|
||||||
"architecture": platform.machine(),
|
"architecture": platform.machine(),
|
||||||
"authentik_version": get_full_version(),
|
"authentik_version": authentik_full_version(),
|
||||||
"environment": get_env(),
|
"environment": get_env(),
|
||||||
"openssl_fips_enabled": (
|
"openssl_fips_enabled": (
|
||||||
backend._fips_enabled if LicenseKey.get_total().status().is_valid else None
|
backend._fips_enabled if LicenseKey.get_total().status().is_valid else None
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ from rest_framework.request import Request
|
|||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
from rest_framework.views import APIView
|
from rest_framework.views import APIView
|
||||||
|
|
||||||
from authentik import __version__, get_build_hash
|
from authentik import authentik_build_hash, authentik_version
|
||||||
from authentik.admin.tasks import VERSION_CACHE_KEY, VERSION_NULL, update_latest_version
|
from authentik.admin.tasks import VERSION_CACHE_KEY, VERSION_NULL, update_latest_version
|
||||||
from authentik.core.api.utils import PassiveSerializer
|
from authentik.core.api.utils import PassiveSerializer
|
||||||
from authentik.outposts.models import Outpost
|
from authentik.outposts.models import Outpost
|
||||||
@@ -29,20 +29,20 @@ class VersionSerializer(PassiveSerializer):
|
|||||||
|
|
||||||
def get_build_hash(self, _) -> str:
|
def get_build_hash(self, _) -> str:
|
||||||
"""Get build hash, if version is not latest or released"""
|
"""Get build hash, if version is not latest or released"""
|
||||||
return get_build_hash()
|
return authentik_build_hash()
|
||||||
|
|
||||||
def get_version_current(self, _) -> str:
|
def get_version_current(self, _) -> str:
|
||||||
"""Get current version"""
|
"""Get current version"""
|
||||||
return __version__
|
return authentik_version()
|
||||||
|
|
||||||
def get_version_latest(self, _) -> str:
|
def get_version_latest(self, _) -> str:
|
||||||
"""Get latest version from cache"""
|
"""Get latest version from cache"""
|
||||||
if get_current_tenant().schema_name == get_public_schema_name():
|
if get_current_tenant().schema_name == get_public_schema_name():
|
||||||
return __version__
|
return authentik_version()
|
||||||
version_in_cache = cache.get(VERSION_CACHE_KEY)
|
version_in_cache = cache.get(VERSION_CACHE_KEY)
|
||||||
if not version_in_cache: # pragma: no cover
|
if not version_in_cache: # pragma: no cover
|
||||||
update_latest_version.send()
|
update_latest_version.send()
|
||||||
return __version__
|
return authentik_version()
|
||||||
return version_in_cache
|
return version_in_cache
|
||||||
|
|
||||||
def get_version_latest_valid(self, _) -> bool:
|
def get_version_latest_valid(self, _) -> bool:
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ from packaging.version import parse
|
|||||||
from requests import RequestException
|
from requests import RequestException
|
||||||
from structlog.stdlib import get_logger
|
from structlog.stdlib import get_logger
|
||||||
|
|
||||||
from authentik import __version__, get_build_hash
|
from authentik import authentik_build_hash, authentik_version
|
||||||
from authentik.admin.apps import PROM_INFO
|
from authentik.admin.apps import PROM_INFO
|
||||||
from authentik.events.models import Event, EventAction
|
from authentik.events.models import Event, EventAction
|
||||||
from authentik.lib.config import CONFIG
|
from authentik.lib.config import CONFIG
|
||||||
@@ -19,16 +19,16 @@ LOGGER = get_logger()
|
|||||||
VERSION_NULL = "0.0.0"
|
VERSION_NULL = "0.0.0"
|
||||||
VERSION_CACHE_KEY = "authentik_latest_version"
|
VERSION_CACHE_KEY = "authentik_latest_version"
|
||||||
VERSION_CACHE_TIMEOUT = 8 * 60 * 60 # 8 hours
|
VERSION_CACHE_TIMEOUT = 8 * 60 * 60 # 8 hours
|
||||||
LOCAL_VERSION = parse(__version__)
|
LOCAL_VERSION = parse(authentik_version())
|
||||||
|
|
||||||
|
|
||||||
def _set_prom_info():
|
def _set_prom_info():
|
||||||
"""Set prometheus info for version"""
|
"""Set prometheus info for version"""
|
||||||
PROM_INFO.info(
|
PROM_INFO.info(
|
||||||
{
|
{
|
||||||
"version": __version__,
|
"version": authentik_version(),
|
||||||
"latest": cache.get(VERSION_CACHE_KEY, ""),
|
"latest": cache.get(VERSION_CACHE_KEY, ""),
|
||||||
"build_hash": get_build_hash(),
|
"build_hash": authentik_build_hash(),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ from json import loads
|
|||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
|
|
||||||
from authentik import __version__
|
from authentik import authentik_version
|
||||||
from authentik.blueprints.tests import reconcile_app
|
from authentik.blueprints.tests import reconcile_app
|
||||||
from authentik.core.models import Group, User
|
from authentik.core.models import Group, User
|
||||||
from authentik.lib.generators import generate_id
|
from authentik.lib.generators import generate_id
|
||||||
@@ -27,7 +27,7 @@ class TestAdminAPI(TestCase):
|
|||||||
response = self.client.get(reverse("authentik_api:admin_version"))
|
response = self.client.get(reverse("authentik_api:admin_version"))
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
body = loads(response.content)
|
body = loads(response.content)
|
||||||
self.assertEqual(body["version_current"], __version__)
|
self.assertEqual(body["version_current"], authentik_version())
|
||||||
|
|
||||||
def test_apps(self):
|
def test_apps(self):
|
||||||
"""Test apps API"""
|
"""Test apps API"""
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ from rest_framework.relations import PrimaryKeyRelatedField
|
|||||||
from rest_framework.serializers import Serializer
|
from rest_framework.serializers import Serializer
|
||||||
from structlog.stdlib import get_logger
|
from structlog.stdlib import get_logger
|
||||||
|
|
||||||
from authentik import __version__
|
from authentik import authentik_version
|
||||||
from authentik.blueprints.v1.common import BlueprintEntryDesiredState
|
from authentik.blueprints.v1.common import BlueprintEntryDesiredState
|
||||||
from authentik.blueprints.v1.importer import SERIALIZER_CONTEXT_BLUEPRINT, is_model_allowed
|
from authentik.blueprints.v1.importer import SERIALIZER_CONTEXT_BLUEPRINT, is_model_allowed
|
||||||
from authentik.blueprints.v1.meta.registry import BaseMetaModel, registry
|
from authentik.blueprints.v1.meta.registry import BaseMetaModel, registry
|
||||||
@@ -48,7 +48,7 @@ class Command(BaseCommand):
|
|||||||
"$schema": "http://json-schema.org/draft-07/schema",
|
"$schema": "http://json-schema.org/draft-07/schema",
|
||||||
"$id": "https://goauthentik.io/blueprints/schema.json",
|
"$id": "https://goauthentik.io/blueprints/schema.json",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"title": f"authentik {__version__} Blueprint schema",
|
"title": f"authentik {authentik_version()} Blueprint schema",
|
||||||
"required": ["version", "entries"],
|
"required": ["version", "entries"],
|
||||||
"properties": {
|
"properties": {
|
||||||
"version": {
|
"version": {
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ from django.http.request import HttpRequest
|
|||||||
from django.utils.html import _json_script_escapes
|
from django.utils.html import _json_script_escapes
|
||||||
from django.utils.safestring import mark_safe
|
from django.utils.safestring import mark_safe
|
||||||
|
|
||||||
from authentik import get_full_version
|
from authentik import authentik_full_version
|
||||||
from authentik.brands.models import Brand
|
from authentik.brands.models import Brand
|
||||||
from authentik.lib.sentry import get_http_meta
|
from authentik.lib.sentry import get_http_meta
|
||||||
from authentik.tenants.models import Tenant
|
from authentik.tenants.models import Tenant
|
||||||
@@ -44,5 +44,5 @@ def context_processor(request: HttpRequest) -> dict[str, Any]:
|
|||||||
"brand_css": brand_css,
|
"brand_css": brand_css,
|
||||||
"footer_links": tenant.footer_links,
|
"footer_links": tenant.footer_links,
|
||||||
"html_meta": {**get_http_meta()},
|
"html_meta": {**get_http_meta()},
|
||||||
"version": get_full_version(),
|
"version": authentik_full_version(),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ from django.core.management.base import BaseCommand
|
|||||||
from django.db.models import Model
|
from django.db.models import Model
|
||||||
from django.db.models.signals import post_save, pre_delete
|
from django.db.models.signals import post_save, pre_delete
|
||||||
|
|
||||||
from authentik import get_full_version
|
from authentik import authentik_full_version
|
||||||
from authentik.core.models import User
|
from authentik.core.models import User
|
||||||
from authentik.events.middleware import should_log_model
|
from authentik.events.middleware import should_log_model
|
||||||
from authentik.events.models import Event, EventAction
|
from authentik.events.models import Event, EventAction
|
||||||
@@ -19,7 +19,7 @@ from authentik.events.utils import model_to_dict
|
|||||||
|
|
||||||
|
|
||||||
def get_banner_text(shell_type="shell") -> str:
|
def get_banner_text(shell_type="shell") -> str:
|
||||||
return f"""### authentik {shell_type} ({get_full_version()})
|
return f"""### authentik {shell_type} ({authentik_full_version()})
|
||||||
### Node {platform.node()} | Arch {platform.machine()} | Python {platform.python_version()} """
|
### Node {platform.node()} | Arch {platform.machine()} | Python {platform.python_version()} """
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
from django import template
|
from django import template
|
||||||
from django.templatetags.static import static as static_loader
|
from django.templatetags.static import static as static_loader
|
||||||
|
|
||||||
from authentik import get_full_version
|
from authentik import authentik_full_version
|
||||||
|
|
||||||
register = template.Library()
|
register = template.Library()
|
||||||
|
|
||||||
@@ -11,4 +11,4 @@ register = template.Library()
|
|||||||
@register.simple_tag()
|
@register.simple_tag()
|
||||||
def versioned_script(path: str) -> str:
|
def versioned_script(path: str) -> str:
|
||||||
"""Wrapper around {% static %} tag that supports setting the version"""
|
"""Wrapper around {% static %} tag that supports setting the version"""
|
||||||
return static_loader(path.replace("%v", get_full_version()))
|
return static_loader(path.replace("%v", authentik_full_version()))
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ from django.utils.translation import gettext as _
|
|||||||
from django.views.generic.base import RedirectView, TemplateView
|
from django.views.generic.base import RedirectView, TemplateView
|
||||||
from rest_framework.request import Request
|
from rest_framework.request import Request
|
||||||
|
|
||||||
from authentik import get_build_hash
|
from authentik import authentik_build_hash
|
||||||
from authentik.admin.tasks import LOCAL_VERSION
|
from authentik.admin.tasks import LOCAL_VERSION
|
||||||
from authentik.api.v3.config import ConfigView
|
from authentik.api.v3.config import ConfigView
|
||||||
from authentik.brands.api import CurrentBrandSerializer
|
from authentik.brands.api import CurrentBrandSerializer
|
||||||
@@ -52,7 +52,7 @@ class InterfaceView(TemplateView):
|
|||||||
kwargs["brand_json"] = dumps(brand.data)
|
kwargs["brand_json"] = dumps(brand.data)
|
||||||
kwargs["version_family"] = f"{LOCAL_VERSION.major}.{LOCAL_VERSION.minor}"
|
kwargs["version_family"] = f"{LOCAL_VERSION.major}.{LOCAL_VERSION.minor}"
|
||||||
kwargs["version_subdomain"] = f"version-{LOCAL_VERSION.major}-{LOCAL_VERSION.minor}"
|
kwargs["version_subdomain"] = f"version-{LOCAL_VERSION.major}-{LOCAL_VERSION.minor}"
|
||||||
kwargs["build"] = get_build_hash()
|
kwargs["build"] = authentik_build_hash()
|
||||||
kwargs["url_kwargs"] = self.kwargs
|
kwargs["url_kwargs"] = self.kwargs
|
||||||
kwargs["base_url"] = self.request.build_absolute_uri(CONFIG.get("web.path", "/"))
|
kwargs["base_url"] = self.request.build_absolute_uri(CONFIG.get("web.path", "/"))
|
||||||
kwargs["base_url_rel"] = CONFIG.get("web.path", "/")
|
kwargs["base_url_rel"] = CONFIG.get("web.path", "/")
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ from cryptography.x509.oid import NameOID
|
|||||||
from django.db import models
|
from django.db import models
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
from authentik import __version__
|
from authentik import authentik_version
|
||||||
from authentik.crypto.models import CertificateKeyPair
|
from authentik.crypto.models import CertificateKeyPair
|
||||||
|
|
||||||
|
|
||||||
@@ -85,7 +85,7 @@ class CertificateBuilder:
|
|||||||
.issuer_name(
|
.issuer_name(
|
||||||
x509.Name(
|
x509.Name(
|
||||||
[
|
[
|
||||||
x509.NameAttribute(NameOID.COMMON_NAME, f"authentik {__version__}"),
|
x509.NameAttribute(NameOID.COMMON_NAME, f"authentik {authentik_version()}"),
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ from requests import RequestException
|
|||||||
from rest_framework.serializers import Serializer
|
from rest_framework.serializers import Serializer
|
||||||
from structlog.stdlib import get_logger
|
from structlog.stdlib import get_logger
|
||||||
|
|
||||||
from authentik import get_full_version
|
from authentik import authentik_full_version
|
||||||
from authentik.brands.models import Brand
|
from authentik.brands.models import Brand
|
||||||
from authentik.brands.utils import DEFAULT_BRAND
|
from authentik.brands.utils import DEFAULT_BRAND
|
||||||
from authentik.core.middleware import (
|
from authentik.core.middleware import (
|
||||||
@@ -434,7 +434,7 @@ class NotificationTransport(TasksModel, SerializerModel):
|
|||||||
"title": notification.body,
|
"title": notification.body,
|
||||||
"color": "#fd4b2d",
|
"color": "#fd4b2d",
|
||||||
"fields": fields,
|
"fields": fields,
|
||||||
"footer": f"authentik {get_full_version()}",
|
"footer": f"authentik {authentik_full_version()}",
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ from django.core.mail.backends.locmem import EmailBackend
|
|||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
from requests_mock import Mocker
|
from requests_mock import Mocker
|
||||||
|
|
||||||
from authentik import get_full_version
|
from authentik import authentik_full_version
|
||||||
from authentik.core.tests.utils import create_test_admin_user
|
from authentik.core.tests.utils import create_test_admin_user
|
||||||
from authentik.events.models import (
|
from authentik.events.models import (
|
||||||
Event,
|
Event,
|
||||||
@@ -118,7 +118,7 @@ class TestEventTransports(TestCase):
|
|||||||
{"short": True, "title": "Event user", "value": self.user.username},
|
{"short": True, "title": "Event user", "value": self.user.username},
|
||||||
{"title": "foo", "value": "bar,"},
|
{"title": "foo", "value": "bar,"},
|
||||||
],
|
],
|
||||||
"footer": f"authentik {get_full_version()}",
|
"footer": f"authentik {authentik_full_version()}",
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ from django.core.management.base import BaseCommand
|
|||||||
from django.test import RequestFactory
|
from django.test import RequestFactory
|
||||||
from structlog.stdlib import get_logger
|
from structlog.stdlib import get_logger
|
||||||
|
|
||||||
from authentik import __version__
|
from authentik import authentik_version
|
||||||
from authentik.core.tests.utils import create_test_admin_user
|
from authentik.core.tests.utils import create_test_admin_user
|
||||||
from authentik.flows.models import Flow
|
from authentik.flows.models import Flow
|
||||||
from authentik.flows.planner import PLAN_CONTEXT_PENDING_USER, FlowPlanner
|
from authentik.flows.planner import PLAN_CONTEXT_PENDING_USER, FlowPlanner
|
||||||
@@ -99,7 +99,7 @@ class Command(BaseCommand):
|
|||||||
total_min: int = min(min(inner) for inner in values)
|
total_min: int = min(min(inner) for inner in values)
|
||||||
total_avg = sum(sum(inner) for inner in values) / sum(len(inner) for inner in values)
|
total_avg = sum(sum(inner) for inner in values) / sum(len(inner) for inner in values)
|
||||||
|
|
||||||
print(f"Version: {__version__}")
|
print(f"Version: {authentik_version()}")
|
||||||
print(f"Processes: {len(values)}")
|
print(f"Processes: {len(values)}")
|
||||||
print(f"\tMax: {total_max * 100}ms")
|
print(f"\tMax: {total_max * 100}ms")
|
||||||
print(f"\tMin: {total_min * 100}ms")
|
print(f"\tMin: {total_min * 100}ms")
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ from sentry_sdk.tracing import BAGGAGE_HEADER_NAME, SENTRY_TRACE_HEADER_NAME
|
|||||||
from structlog.stdlib import get_logger
|
from structlog.stdlib import get_logger
|
||||||
from websockets.exceptions import WebSocketException
|
from websockets.exceptions import WebSocketException
|
||||||
|
|
||||||
from authentik import __version__, get_build_hash
|
from authentik import authentik_build_hash, authentik_version
|
||||||
from authentik.lib.config import CONFIG
|
from authentik.lib.config import CONFIG
|
||||||
from authentik.lib.utils.http import authentik_user_agent
|
from authentik.lib.utils.http import authentik_user_agent
|
||||||
from authentik.lib.utils.reflection import get_env
|
from authentik.lib.utils.reflection import get_env
|
||||||
@@ -117,11 +117,11 @@ def sentry_init(**sentry_init_kwargs):
|
|||||||
],
|
],
|
||||||
before_send=before_send,
|
before_send=before_send,
|
||||||
traces_sampler=traces_sampler,
|
traces_sampler=traces_sampler,
|
||||||
release=f"authentik@{__version__}",
|
release=f"authentik@{authentik_version()}",
|
||||||
transport=SentryTransport,
|
transport=SentryTransport,
|
||||||
**kwargs,
|
**kwargs,
|
||||||
)
|
)
|
||||||
set_tag("authentik.build_hash", get_build_hash("tagged"))
|
set_tag("authentik.build_hash", authentik_build_hash("tagged"))
|
||||||
set_tag("authentik.env", get_env())
|
set_tag("authentik.env", get_env())
|
||||||
set_tag("authentik.component", "backend")
|
set_tag("authentik.component", "backend")
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ from uuid import uuid4
|
|||||||
from requests.sessions import PreparedRequest, Session
|
from requests.sessions import PreparedRequest, Session
|
||||||
from structlog.stdlib import get_logger
|
from structlog.stdlib import get_logger
|
||||||
|
|
||||||
from authentik import get_full_version
|
from authentik import authentik_full_version
|
||||||
from authentik.lib.config import CONFIG
|
from authentik.lib.config import CONFIG
|
||||||
|
|
||||||
LOGGER = get_logger()
|
LOGGER = get_logger()
|
||||||
@@ -13,7 +13,7 @@ LOGGER = get_logger()
|
|||||||
|
|
||||||
def authentik_user_agent() -> str:
|
def authentik_user_agent() -> str:
|
||||||
"""Get a common user agent"""
|
"""Get a common user agent"""
|
||||||
return f"authentik@{get_full_version()}"
|
return f"authentik@{authentik_full_version()}"
|
||||||
|
|
||||||
|
|
||||||
class TimeoutSession(Session):
|
class TimeoutSession(Session):
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ from rest_framework.request import Request
|
|||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
from rest_framework.viewsets import ModelViewSet
|
from rest_framework.viewsets import ModelViewSet
|
||||||
|
|
||||||
from authentik import get_build_hash
|
from authentik import authentik_build_hash
|
||||||
from authentik.core.api.providers import ProviderSerializer
|
from authentik.core.api.providers import ProviderSerializer
|
||||||
from authentik.core.api.used_by import UsedByMixin
|
from authentik.core.api.used_by import UsedByMixin
|
||||||
from authentik.core.api.utils import JSONDictField, ModelSerializer, PassiveSerializer
|
from authentik.core.api.utils import JSONDictField, ModelSerializer, PassiveSerializer
|
||||||
@@ -194,7 +194,7 @@ class OutpostViewSet(UsedByMixin, ModelViewSet):
|
|||||||
"openssl_version": state.openssl_version,
|
"openssl_version": state.openssl_version,
|
||||||
"fips_enabled": state.fips_enabled,
|
"fips_enabled": state.fips_enabled,
|
||||||
"hostname": state.hostname,
|
"hostname": state.hostname,
|
||||||
"build_hash_should": get_build_hash(),
|
"build_hash_should": authentik_build_hash(),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
return Response(OutpostHealthSerializer(states, many=True).data)
|
return Response(OutpostHealthSerializer(states, many=True).data)
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ from dataclasses import dataclass
|
|||||||
|
|
||||||
from structlog.stdlib import get_logger
|
from structlog.stdlib import get_logger
|
||||||
|
|
||||||
from authentik import __version__, get_build_hash
|
from authentik import authentik_build_hash, authentik_version
|
||||||
from authentik.events.logs import LogEvent, capture_logs
|
from authentik.events.logs import LogEvent, capture_logs
|
||||||
from authentik.lib.config import CONFIG
|
from authentik.lib.config import CONFIG
|
||||||
from authentik.lib.sentry import SentryIgnoredException
|
from authentik.lib.sentry import SentryIgnoredException
|
||||||
@@ -99,6 +99,6 @@ class BaseController:
|
|||||||
image_name_template: str = CONFIG.get("outposts.container_image_base")
|
image_name_template: str = CONFIG.get("outposts.container_image_base")
|
||||||
return image_name_template % {
|
return image_name_template % {
|
||||||
"type": self.outpost.type,
|
"type": self.outpost.type,
|
||||||
"version": __version__,
|
"version": authentik_version(),
|
||||||
"build_hash": get_build_hash(),
|
"build_hash": authentik_build_hash(),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ from paramiko.ssh_exception import SSHException
|
|||||||
from structlog.stdlib import get_logger
|
from structlog.stdlib import get_logger
|
||||||
from yaml import safe_dump
|
from yaml import safe_dump
|
||||||
|
|
||||||
from authentik import __version__
|
from authentik import authentik_version
|
||||||
from authentik.outposts.apps import MANAGED_OUTPOST
|
from authentik.outposts.apps import MANAGED_OUTPOST
|
||||||
from authentik.outposts.controllers.base import BaseClient, BaseController, ControllerException
|
from authentik.outposts.controllers.base import BaseClient, BaseController, ControllerException
|
||||||
from authentik.outposts.docker_ssh import DockerInlineSSH, SSHManagedExternallyException
|
from authentik.outposts.docker_ssh import DockerInlineSSH, SSHManagedExternallyException
|
||||||
@@ -185,7 +185,7 @@ class DockerController(BaseController):
|
|||||||
try:
|
try:
|
||||||
self.client.images.pull(image)
|
self.client.images.pull(image)
|
||||||
except DockerException: # pragma: no cover
|
except DockerException: # pragma: no cover
|
||||||
image = f"ghcr.io/goauthentik/{self.outpost.type}:{__version__}"
|
image = f"ghcr.io/goauthentik/{self.outpost.type}:{authentik_version()}"
|
||||||
self.client.images.pull(image)
|
self.client.images.pull(image)
|
||||||
return image
|
return image
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ from requests import Response
|
|||||||
from structlog.stdlib import get_logger
|
from structlog.stdlib import get_logger
|
||||||
from urllib3.exceptions import HTTPError
|
from urllib3.exceptions import HTTPError
|
||||||
|
|
||||||
from authentik import __version__
|
from authentik import authentik_version
|
||||||
from authentik.outposts.apps import MANAGED_OUTPOST
|
from authentik.outposts.apps import MANAGED_OUTPOST
|
||||||
from authentik.outposts.controllers.base import ControllerException
|
from authentik.outposts.controllers.base import ControllerException
|
||||||
from authentik.outposts.controllers.k8s.triggers import NeedsRecreate, NeedsUpdate
|
from authentik.outposts.controllers.k8s.triggers import NeedsRecreate, NeedsUpdate
|
||||||
@@ -29,8 +29,8 @@ T = TypeVar("T", V1Pod, V1Deployment)
|
|||||||
|
|
||||||
|
|
||||||
def get_version() -> str:
|
def get_version() -> str:
|
||||||
"""Wrapper for __version__ to make testing easier"""
|
"""Wrapper for authentik_version() to make testing easier"""
|
||||||
return __version__
|
return authentik_version()
|
||||||
|
|
||||||
|
|
||||||
class KubernetesObjectReconciler(Generic[T]):
|
class KubernetesObjectReconciler(Generic[T]):
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ from kubernetes.client import (
|
|||||||
V1SecurityContext,
|
V1SecurityContext,
|
||||||
)
|
)
|
||||||
|
|
||||||
from authentik import get_full_version
|
from authentik import authentik_full_version
|
||||||
from authentik.outposts.controllers.base import FIELD_MANAGER
|
from authentik.outposts.controllers.base import FIELD_MANAGER
|
||||||
from authentik.outposts.controllers.k8s.base import KubernetesObjectReconciler
|
from authentik.outposts.controllers.k8s.base import KubernetesObjectReconciler
|
||||||
from authentik.outposts.controllers.k8s.triggers import NeedsUpdate
|
from authentik.outposts.controllers.k8s.triggers import NeedsUpdate
|
||||||
@@ -94,7 +94,7 @@ class DeploymentReconciler(KubernetesObjectReconciler[V1Deployment]):
|
|||||||
meta = self.get_object_meta(name=self.name)
|
meta = self.get_object_meta(name=self.name)
|
||||||
image_name = self.controller.get_container_image()
|
image_name = self.controller.get_container_image()
|
||||||
image_pull_secrets = self.outpost.config.kubernetes_image_pull_secrets
|
image_pull_secrets = self.outpost.config.kubernetes_image_pull_secrets
|
||||||
version = get_full_version().replace("+", "-")
|
version = authentik_full_version().replace("+", "-")
|
||||||
return V1Deployment(
|
return V1Deployment(
|
||||||
metadata=meta,
|
metadata=meta,
|
||||||
spec=V1DeploymentSpec(
|
spec=V1DeploymentSpec(
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ from packaging.version import Version, parse
|
|||||||
from rest_framework.serializers import Serializer
|
from rest_framework.serializers import Serializer
|
||||||
from structlog.stdlib import get_logger
|
from structlog.stdlib import get_logger
|
||||||
|
|
||||||
from authentik import __version__, get_build_hash
|
from authentik import authentik_build_hash, authentik_version
|
||||||
from authentik.blueprints.models import ManagedModel
|
from authentik.blueprints.models import ManagedModel
|
||||||
from authentik.brands.models import Brand
|
from authentik.brands.models import Brand
|
||||||
from authentik.core.models import (
|
from authentik.core.models import (
|
||||||
@@ -40,7 +40,7 @@ from authentik.outposts.controllers.k8s.utils import get_namespace
|
|||||||
from authentik.tasks.schedules.common import ScheduleSpec
|
from authentik.tasks.schedules.common import ScheduleSpec
|
||||||
from authentik.tasks.schedules.models import ScheduledModel
|
from authentik.tasks.schedules.models import ScheduledModel
|
||||||
|
|
||||||
OUR_VERSION = parse(__version__)
|
OUR_VERSION = parse(authentik_version())
|
||||||
OUTPOST_HELLO_INTERVAL = 10
|
OUTPOST_HELLO_INTERVAL = 10
|
||||||
LOGGER = get_logger()
|
LOGGER = get_logger()
|
||||||
|
|
||||||
@@ -481,7 +481,7 @@ class OutpostState:
|
|||||||
"""Check if outpost version matches our version"""
|
"""Check if outpost version matches our version"""
|
||||||
if not self.version:
|
if not self.version:
|
||||||
return False
|
return False
|
||||||
if self.build_hash != get_build_hash():
|
if self.build_hash != authentik_build_hash():
|
||||||
return False
|
return False
|
||||||
return parse(self.version) != OUR_VERSION
|
return parse(self.version) != OUR_VERSION
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ from channels.routing import URLRouter
|
|||||||
from channels.testing import WebsocketCommunicator
|
from channels.testing import WebsocketCommunicator
|
||||||
from django.test import TransactionTestCase
|
from django.test import TransactionTestCase
|
||||||
|
|
||||||
from authentik import __version__
|
from authentik import authentik_version
|
||||||
from authentik.core.tests.utils import create_test_flow
|
from authentik.core.tests.utils import create_test_flow
|
||||||
from authentik.outposts.consumer import WebsocketMessage, WebsocketMessageInstruction
|
from authentik.outposts.consumer import WebsocketMessage, WebsocketMessageInstruction
|
||||||
from authentik.outposts.models import Outpost, OutpostType
|
from authentik.outposts.models import Outpost, OutpostType
|
||||||
@@ -65,7 +65,7 @@ class TestOutpostWS(TransactionTestCase):
|
|||||||
WebsocketMessage(
|
WebsocketMessage(
|
||||||
instruction=WebsocketMessageInstruction.HELLO,
|
instruction=WebsocketMessageInstruction.HELLO,
|
||||||
args={
|
args={
|
||||||
"version": __version__,
|
"version": authentik_version(),
|
||||||
"buildHash": "foo",
|
"buildHash": "foo",
|
||||||
"uuid": "123",
|
"uuid": "123",
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import orjson
|
|||||||
from sentry_sdk import set_tag
|
from sentry_sdk import set_tag
|
||||||
from xmlsec import enable_debug_trace
|
from xmlsec import enable_debug_trace
|
||||||
|
|
||||||
from authentik import __version__
|
from authentik import authentik_version
|
||||||
from authentik.lib.config import CONFIG, django_db_config, redis_url
|
from authentik.lib.config import CONFIG, django_db_config, redis_url
|
||||||
from authentik.lib.logging import get_logger_config, structlog_configure
|
from authentik.lib.logging import get_logger_config, structlog_configure
|
||||||
from authentik.lib.sentry import sentry_init
|
from authentik.lib.sentry import sentry_init
|
||||||
@@ -144,7 +144,7 @@ GUARDIAN_MONKEY_PATCH_USER = False
|
|||||||
SPECTACULAR_SETTINGS = {
|
SPECTACULAR_SETTINGS = {
|
||||||
"TITLE": "authentik",
|
"TITLE": "authentik",
|
||||||
"DESCRIPTION": "Making authentication simple.",
|
"DESCRIPTION": "Making authentication simple.",
|
||||||
"VERSION": __version__,
|
"VERSION": authentik_version(),
|
||||||
"COMPONENT_SPLIT_REQUEST": True,
|
"COMPONENT_SPLIT_REQUEST": True,
|
||||||
"SCHEMA_PATH_PREFIX": "/api/v([0-9]+(beta)?)",
|
"SCHEMA_PATH_PREFIX": "/api/v([0-9]+(beta)?)",
|
||||||
"SCHEMA_PATH_PREFIX_TRIM": True,
|
"SCHEMA_PATH_PREFIX_TRIM": True,
|
||||||
@@ -567,7 +567,7 @@ if DEBUG:
|
|||||||
enable_debug_trace(True)
|
enable_debug_trace(True)
|
||||||
|
|
||||||
|
|
||||||
CONFIG.log("info", "Booting authentik", version=__version__)
|
CONFIG.log("info", "Booting authentik", version=authentik_version())
|
||||||
|
|
||||||
# Load subapps's settings
|
# Load subapps's settings
|
||||||
_filter_and_update(SHARED_APPS + TENANT_APPS)
|
_filter_and_update(SHARED_APPS + TENANT_APPS)
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ from ssl import OPENSSL_VERSION
|
|||||||
import pytest
|
import pytest
|
||||||
from cryptography.hazmat.backends.openssl.backend import backend
|
from cryptography.hazmat.backends.openssl.backend import backend
|
||||||
|
|
||||||
from authentik import get_full_version
|
from authentik import authentik_full_version
|
||||||
|
|
||||||
IS_CI = "CI" in environ
|
IS_CI = "CI" in environ
|
||||||
|
|
||||||
@@ -22,7 +22,7 @@ def pytest_sessionstart(*_, **__):
|
|||||||
def pytest_report_header(*_, **__):
|
def pytest_report_header(*_, **__):
|
||||||
"""Add authentik version to pytest output"""
|
"""Add authentik version to pytest output"""
|
||||||
return [
|
return [
|
||||||
f"authentik version: {get_full_version()}",
|
f"authentik version: {authentik_full_version()}",
|
||||||
f"OpenSSL version: {OPENSSL_VERSION}, FIPS: {backend._fips_enabled}",
|
f"OpenSSL version: {OPENSSL_VERSION}, FIPS: {backend._fips_enabled}",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ from django.http.response import Http404
|
|||||||
from requests.exceptions import RequestException
|
from requests.exceptions import RequestException
|
||||||
from structlog.stdlib import get_logger
|
from structlog.stdlib import get_logger
|
||||||
|
|
||||||
from authentik import __version__
|
from authentik import authentik_version
|
||||||
from authentik.core.sources.flow_manager import SourceFlowManager
|
from authentik.core.sources.flow_manager import SourceFlowManager
|
||||||
from authentik.lib.utils.http import get_http_session
|
from authentik.lib.utils.http import get_http_session
|
||||||
from authentik.sources.plex.models import (
|
from authentik.sources.plex.models import (
|
||||||
@@ -38,7 +38,7 @@ class PlexAuth:
|
|||||||
"""Get common headers"""
|
"""Get common headers"""
|
||||||
return {
|
return {
|
||||||
"X-Plex-Product": "authentik",
|
"X-Plex-Product": "authentik",
|
||||||
"X-Plex-Version": __version__,
|
"X-Plex-Version": authentik_version(),
|
||||||
"X-Plex-Device-Vendor": "goauthentik.io",
|
"X-Plex-Device-Vendor": "goauthentik.io",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ from rest_framework.request import Request
|
|||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
from rest_framework.views import APIView
|
from rest_framework.views import APIView
|
||||||
|
|
||||||
from authentik import get_full_version
|
from authentik import authentik_full_version
|
||||||
from authentik.rbac.permissions import HasPermission
|
from authentik.rbac.permissions import HasPermission
|
||||||
from authentik.tasks.models import WorkerStatus
|
from authentik.tasks.models import WorkerStatus
|
||||||
|
|
||||||
@@ -30,7 +30,7 @@ class WorkerView(APIView):
|
|||||||
)
|
)
|
||||||
def get(self, request: Request) -> Response:
|
def get(self, request: Request) -> Response:
|
||||||
response = []
|
response = []
|
||||||
our_version = parse(get_full_version())
|
our_version = parse(authentik_full_version())
|
||||||
for status in WorkerStatus.objects.filter(last_seen__gt=now() - timedelta(minutes=2)):
|
for status in WorkerStatus.objects.filter(last_seen__gt=now() - timedelta(minutes=2)):
|
||||||
lock_id = f"goauthentik.io/worker/status/{status.pk}"
|
lock_id = f"goauthentik.io/worker/status/{status.pk}"
|
||||||
with pglock.advisory(lock_id, timeout=0, side_effect=pglock.Return) as acquired:
|
with pglock.advisory(lock_id, timeout=0, side_effect=pglock.Return) as acquired:
|
||||||
|
|||||||
@@ -7,7 +7,9 @@ import pglock
|
|||||||
from django.db import OperationalError, connections
|
from django.db import OperationalError, connections
|
||||||
from django.utils.timezone import now
|
from django.utils.timezone import now
|
||||||
from django_dramatiq_postgres.middleware import HTTPServer
|
from django_dramatiq_postgres.middleware import HTTPServer
|
||||||
from django_dramatiq_postgres.middleware import MetricsMiddleware as BaseMetricsMiddleware
|
from django_dramatiq_postgres.middleware import (
|
||||||
|
MetricsMiddleware as BaseMetricsMiddleware,
|
||||||
|
)
|
||||||
from django_redis import get_redis_connection
|
from django_redis import get_redis_connection
|
||||||
from dramatiq.broker import Broker
|
from dramatiq.broker import Broker
|
||||||
from dramatiq.message import Message
|
from dramatiq.message import Message
|
||||||
@@ -15,7 +17,7 @@ from dramatiq.middleware import Middleware
|
|||||||
from redis.exceptions import RedisError
|
from redis.exceptions import RedisError
|
||||||
from structlog.stdlib import get_logger
|
from structlog.stdlib import get_logger
|
||||||
|
|
||||||
from authentik import get_full_version
|
from authentik import authentik_full_version
|
||||||
from authentik.events.models import Event, EventAction
|
from authentik.events.models import Event, EventAction
|
||||||
from authentik.lib.sentry import should_ignore_exception
|
from authentik.lib.sentry import should_ignore_exception
|
||||||
from authentik.tasks.models import Task, TaskStatus, WorkerStatus
|
from authentik.tasks.models import Task, TaskStatus, WorkerStatus
|
||||||
@@ -208,7 +210,7 @@ class WorkerStatusMiddleware(Middleware):
|
|||||||
def run():
|
def run():
|
||||||
status = WorkerStatus.objects.create(
|
status = WorkerStatus.objects.create(
|
||||||
hostname=socket.gethostname(),
|
hostname=socket.gethostname(),
|
||||||
version=get_full_version(),
|
version=authentik_full_version(),
|
||||||
)
|
)
|
||||||
lock_id = f"goauthentik.io/worker/status/{status.pk}"
|
lock_id = f"goauthentik.io/worker/status/{status.pk}"
|
||||||
with pglock.advisory(lock_id, side_effect=pglock.Raise):
|
with pglock.advisory(lock_id, side_effect=pglock.Raise):
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ from django.utils.timezone import now, timedelta
|
|||||||
from packaging.version import parse
|
from packaging.version import parse
|
||||||
from prometheus_client import Gauge
|
from prometheus_client import Gauge
|
||||||
|
|
||||||
from authentik import get_full_version
|
from authentik import authentik_full_version
|
||||||
from authentik.root.monitoring import monitoring_set
|
from authentik.root.monitoring import monitoring_set
|
||||||
from authentik.tasks.models import WorkerStatus
|
from authentik.tasks.models import WorkerStatus
|
||||||
|
|
||||||
@@ -22,7 +22,7 @@ GAUGE_WORKERS = Gauge(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
_version = parse(get_full_version())
|
_version = parse(authentik_full_version())
|
||||||
|
|
||||||
|
|
||||||
@receiver(monitoring_set)
|
@receiver(monitoring_set)
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ var rootCmd = &cobra.Command{
|
|||||||
AttachStacktrace: true,
|
AttachStacktrace: true,
|
||||||
EnableTracing: true,
|
EnableTracing: true,
|
||||||
TracesSampler: sentryutils.SamplerFunc(config.Get().ErrorReporting.SampleRate),
|
TracesSampler: sentryutils.SamplerFunc(config.Get().ErrorReporting.SampleRate),
|
||||||
Release: fmt.Sprintf("authentik@%s", constants.VERSION),
|
Release: fmt.Sprintf("authentik@%s", constants.VERSION()),
|
||||||
Environment: config.Get().ErrorReporting.Environment,
|
Environment: config.Get().ErrorReporting.Environment,
|
||||||
HTTPTransport: webutils.NewUserAgentTransport(constants.UserAgent(), http.DefaultTransport),
|
HTTPTransport: webutils.NewUserAgentTransport(constants.UserAgent(), http.DefaultTransport),
|
||||||
IgnoreErrors: []string{
|
IgnoreErrors: []string{
|
||||||
|
|||||||
@@ -1,90 +1,85 @@
|
|||||||
---
|
|
||||||
|
|
||||||
services:
|
services:
|
||||||
postgresql:
|
postgresql:
|
||||||
image: docker.io/library/postgres:16-alpine
|
env_file:
|
||||||
restart: unless-stopped
|
- .env
|
||||||
healthcheck:
|
|
||||||
test: ["CMD-SHELL", "pg_isready -d $${POSTGRES_DB} -U $${POSTGRES_USER}"]
|
|
||||||
start_period: 20s
|
|
||||||
interval: 30s
|
|
||||||
retries: 5
|
|
||||||
timeout: 5s
|
|
||||||
volumes:
|
|
||||||
- database:/var/lib/postgresql/data
|
|
||||||
environment:
|
environment:
|
||||||
|
POSTGRES_DB: ${PG_DB:-authentik}
|
||||||
POSTGRES_PASSWORD: ${PG_PASS:?database password required}
|
POSTGRES_PASSWORD: ${PG_PASS:?database password required}
|
||||||
POSTGRES_USER: ${PG_USER:-authentik}
|
POSTGRES_USER: ${PG_USER:-authentik}
|
||||||
POSTGRES_DB: ${PG_DB:-authentik}
|
|
||||||
env_file:
|
|
||||||
- .env
|
|
||||||
redis:
|
|
||||||
image: docker.io/library/redis:alpine
|
|
||||||
command: --save 60 1 --loglevel warning
|
|
||||||
restart: unless-stopped
|
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD-SHELL", "redis-cli ping | grep PONG"]
|
|
||||||
start_period: 20s
|
|
||||||
interval: 30s
|
interval: 30s
|
||||||
retries: 5
|
retries: 5
|
||||||
timeout: 3s
|
start_period: 20s
|
||||||
volumes:
|
test:
|
||||||
- redis:/data
|
- CMD-SHELL
|
||||||
server:
|
- pg_isready -d $${POSTGRES_DB} -U $${POSTGRES_USER}
|
||||||
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2025.6.4}
|
timeout: 5s
|
||||||
|
image: docker.io/library/postgres:16-alpine
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
command: server
|
|
||||||
environment:
|
|
||||||
AUTHENTIK_SECRET_KEY: ${AUTHENTIK_SECRET_KEY:?secret key required}
|
|
||||||
AUTHENTIK_REDIS__HOST: redis
|
|
||||||
AUTHENTIK_POSTGRESQL__HOST: postgresql
|
|
||||||
AUTHENTIK_POSTGRESQL__USER: ${PG_USER:-authentik}
|
|
||||||
AUTHENTIK_POSTGRESQL__NAME: ${PG_DB:-authentik}
|
|
||||||
AUTHENTIK_POSTGRESQL__PASSWORD: ${PG_PASS}
|
|
||||||
volumes:
|
volumes:
|
||||||
- ./media:/media
|
- database:/var/lib/postgresql/data
|
||||||
- ./custom-templates:/templates
|
redis:
|
||||||
env_file:
|
command: --save 60 1 --loglevel warning
|
||||||
- .env
|
healthcheck:
|
||||||
ports:
|
interval: 30s
|
||||||
- "${COMPOSE_PORT_HTTP:-9000}:9000"
|
retries: 5
|
||||||
- "${COMPOSE_PORT_HTTPS:-9443}:9443"
|
start_period: 20s
|
||||||
|
test:
|
||||||
|
- CMD-SHELL
|
||||||
|
- redis-cli ping | grep PONG
|
||||||
|
timeout: 3s
|
||||||
|
image: docker.io/library/redis:alpine
|
||||||
|
restart: unless-stopped
|
||||||
|
volumes:
|
||||||
|
- redis:/data
|
||||||
|
server:
|
||||||
|
command: server
|
||||||
depends_on:
|
depends_on:
|
||||||
postgresql:
|
postgresql:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
redis:
|
redis:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
worker:
|
env_file:
|
||||||
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2025.6.4}
|
- .env
|
||||||
restart: unless-stopped
|
|
||||||
command: worker
|
|
||||||
environment:
|
environment:
|
||||||
AUTHENTIK_SECRET_KEY: ${AUTHENTIK_SECRET_KEY:?secret key required}
|
|
||||||
AUTHENTIK_REDIS__HOST: redis
|
|
||||||
AUTHENTIK_POSTGRESQL__HOST: postgresql
|
AUTHENTIK_POSTGRESQL__HOST: postgresql
|
||||||
AUTHENTIK_POSTGRESQL__USER: ${PG_USER:-authentik}
|
|
||||||
AUTHENTIK_POSTGRESQL__NAME: ${PG_DB:-authentik}
|
AUTHENTIK_POSTGRESQL__NAME: ${PG_DB:-authentik}
|
||||||
AUTHENTIK_POSTGRESQL__PASSWORD: ${PG_PASS}
|
AUTHENTIK_POSTGRESQL__PASSWORD: ${PG_PASS}
|
||||||
# `user: root` and the docker socket volume are optional.
|
AUTHENTIK_POSTGRESQL__USER: ${PG_USER:-authentik}
|
||||||
# See more for the docker socket integration here:
|
AUTHENTIK_REDIS__HOST: redis
|
||||||
# https://goauthentik.io/docs/outposts/integrations/docker
|
AUTHENTIK_SECRET_KEY: ${AUTHENTIK_SECRET_KEY:?secret key required}
|
||||||
# Removing `user: root` also prevents the worker from fixing the permissions
|
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2025.6.4}
|
||||||
# on the mounted folders, so when removing this make sure the folders have the correct UID/GID
|
ports:
|
||||||
# (1000:1000 by default)
|
- ${COMPOSE_PORT_HTTP:-9000}:9000
|
||||||
|
- ${COMPOSE_PORT_HTTPS:-9443}:9443
|
||||||
|
restart: unless-stopped
|
||||||
|
volumes:
|
||||||
|
- ./media:/media
|
||||||
|
- ./custom-templates:/templates
|
||||||
|
worker:
|
||||||
|
command: worker
|
||||||
|
depends_on:
|
||||||
|
postgresql:
|
||||||
|
condition: service_healthy
|
||||||
|
redis:
|
||||||
|
condition: service_healthy
|
||||||
|
env_file:
|
||||||
|
- .env
|
||||||
|
environment:
|
||||||
|
AUTHENTIK_POSTGRESQL__HOST: postgresql
|
||||||
|
AUTHENTIK_POSTGRESQL__NAME: ${PG_DB:-authentik}
|
||||||
|
AUTHENTIK_POSTGRESQL__PASSWORD: ${PG_PASS}
|
||||||
|
AUTHENTIK_POSTGRESQL__USER: ${PG_USER:-authentik}
|
||||||
|
AUTHENTIK_REDIS__HOST: redis
|
||||||
|
AUTHENTIK_SECRET_KEY: ${AUTHENTIK_SECRET_KEY:?secret key required}
|
||||||
|
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2025.6.4}
|
||||||
|
restart: unless-stopped
|
||||||
user: root
|
user: root
|
||||||
volumes:
|
volumes:
|
||||||
- /var/run/docker.sock:/var/run/docker.sock
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
- ./media:/media
|
- ./media:/media
|
||||||
- ./certs:/certs
|
- ./certs:/certs
|
||||||
- ./custom-templates:/templates
|
- ./custom-templates:/templates
|
||||||
env_file:
|
|
||||||
- .env
|
|
||||||
depends_on:
|
|
||||||
postgresql:
|
|
||||||
condition: service_healthy
|
|
||||||
redis:
|
|
||||||
condition: service_healthy
|
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
database:
|
database:
|
||||||
driver: local
|
driver: local
|
||||||
|
|||||||
1
internal/constants/VERSION
Normal file
1
internal/constants/VERSION
Normal file
@@ -0,0 +1 @@
|
|||||||
|
2025.6.4
|
||||||
@@ -1,10 +1,14 @@
|
|||||||
package constants
|
package constants
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
_ "embed"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
//go:embed VERSION
|
||||||
|
var version string
|
||||||
|
|
||||||
func BUILD(def string) string {
|
func BUILD(def string) string {
|
||||||
build := os.Getenv("GIT_BUILD_HASH")
|
build := os.Getenv("GIT_BUILD_HASH")
|
||||||
if build == "" {
|
if build == "" {
|
||||||
@@ -13,12 +17,15 @@ func BUILD(def string) string {
|
|||||||
return build
|
return build
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func VERSION() string {
|
||||||
|
return version
|
||||||
|
}
|
||||||
|
|
||||||
func FullVersion() string {
|
func FullVersion() string {
|
||||||
ver := VERSION
|
|
||||||
if b := BUILD(""); b != "" {
|
if b := BUILD(""); b != "" {
|
||||||
return fmt.Sprintf("%s+%s", ver, b)
|
return fmt.Sprintf("%s+%s", version, b)
|
||||||
}
|
}
|
||||||
return ver
|
return version
|
||||||
}
|
}
|
||||||
|
|
||||||
func UserAgentOutpost() string {
|
func UserAgentOutpost() string {
|
||||||
@@ -32,5 +39,3 @@ func UserAgentIPC() string {
|
|||||||
func UserAgent() string {
|
func UserAgent() string {
|
||||||
return fmt.Sprintf("authentik@%s", FullVersion())
|
return fmt.Sprintf("authentik@%s", FullVersion())
|
||||||
}
|
}
|
||||||
|
|
||||||
const VERSION = "2025.6.4"
|
|
||||||
|
|||||||
@@ -198,7 +198,7 @@ func (a *APIController) OnRefresh() error {
|
|||||||
|
|
||||||
func (a *APIController) getEventPingArgs() map[string]interface{} {
|
func (a *APIController) getEventPingArgs() map[string]interface{} {
|
||||||
args := map[string]interface{}{
|
args := map[string]interface{}{
|
||||||
"version": constants.VERSION,
|
"version": constants.VERSION(),
|
||||||
"buildHash": constants.BUILD(""),
|
"buildHash": constants.BUILD(""),
|
||||||
"uuid": a.instanceUUID.String(),
|
"uuid": a.instanceUUID.String(),
|
||||||
"golangVersion": runtime.Version(),
|
"golangVersion": runtime.Version(),
|
||||||
@@ -218,7 +218,7 @@ func (a *APIController) StartBackgroundTasks() error {
|
|||||||
"outpost_name": a.Outpost.Name,
|
"outpost_name": a.Outpost.Name,
|
||||||
"outpost_type": a.Server.Type(),
|
"outpost_type": a.Server.Type(),
|
||||||
"uuid": a.instanceUUID.String(),
|
"uuid": a.instanceUUID.String(),
|
||||||
"version": constants.VERSION,
|
"version": constants.VERSION(),
|
||||||
"build": constants.BUILD(""),
|
"build": constants.BUILD(""),
|
||||||
}).Set(1)
|
}).Set(1)
|
||||||
go func() {
|
go func() {
|
||||||
|
|||||||
@@ -163,7 +163,7 @@ func (ac *APIController) startEventHandler() {
|
|||||||
"outpost_name": ac.Outpost.Name,
|
"outpost_name": ac.Outpost.Name,
|
||||||
"outpost_type": ac.Server.Type(),
|
"outpost_type": ac.Server.Type(),
|
||||||
"uuid": ac.instanceUUID.String(),
|
"uuid": ac.instanceUUID.String(),
|
||||||
"version": constants.VERSION,
|
"version": constants.VERSION(),
|
||||||
"build": constants.BUILD(""),
|
"build": constants.BUILD(""),
|
||||||
}).SetToCurrentTime()
|
}).SetToCurrentTime()
|
||||||
}
|
}
|
||||||
@@ -228,7 +228,7 @@ func (ac *APIController) startIntervalUpdater() {
|
|||||||
"outpost_name": ac.Outpost.Name,
|
"outpost_name": ac.Outpost.Name,
|
||||||
"outpost_type": ac.Server.Type(),
|
"outpost_type": ac.Server.Type(),
|
||||||
"uuid": ac.instanceUUID.String(),
|
"uuid": ac.instanceUUID.String(),
|
||||||
"version": constants.VERSION,
|
"version": constants.VERSION(),
|
||||||
"build": constants.BUILD(""),
|
"build": constants.BUILD(""),
|
||||||
}).SetToCurrentTime()
|
}).SetToCurrentTime()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ func doGlobalSetup(outpost api.Outpost, globalConfig *api.Config) {
|
|||||||
Environment: globalConfig.ErrorReporting.Environment,
|
Environment: globalConfig.ErrorReporting.Environment,
|
||||||
EnableTracing: true,
|
EnableTracing: true,
|
||||||
TracesSampler: sentryutils.SamplerFunc(float64(globalConfig.ErrorReporting.TracesSampleRate)),
|
TracesSampler: sentryutils.SamplerFunc(float64(globalConfig.ErrorReporting.TracesSampleRate)),
|
||||||
Release: fmt.Sprintf("authentik@%s", constants.VERSION),
|
Release: fmt.Sprintf("authentik@%s", constants.VERSION()),
|
||||||
HTTPTransport: webutils.NewUserAgentTransport(constants.UserAgentOutpost(), http.DefaultTransport),
|
HTTPTransport: webutils.NewUserAgentTransport(constants.UserAgentOutpost(), http.DefaultTransport),
|
||||||
IgnoreErrors: []string{
|
IgnoreErrors: []string{
|
||||||
http.ErrAbortHandler.Error(),
|
http.ErrAbortHandler.Error(),
|
||||||
@@ -66,7 +66,7 @@ func doGlobalSetup(outpost api.Outpost, globalConfig *api.Config) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !initialSetup {
|
if !initialSetup {
|
||||||
l.WithField("hash", constants.BUILD("tagged")).WithField("version", constants.VERSION).Info("Starting authentik outpost")
|
l.WithField("hash", constants.BUILD("tagged")).WithField("version", constants.VERSION()).Info("Starting authentik outpost")
|
||||||
initialSetup = true
|
initialSetup = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -98,7 +98,7 @@ func (ws *WebServer) staticHeaderMiddleware(h http.Handler) http.Handler {
|
|||||||
etagHandler := etag.Handler(h, false)
|
etagHandler := etag.Handler(h, false)
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
w.Header().Set("Cache-Control", "public, no-transform")
|
w.Header().Set("Cache-Control", "public, no-transform")
|
||||||
w.Header().Set("X-authentik-version", constants.VERSION)
|
w.Header().Set("X-authentik-version", constants.VERSION())
|
||||||
w.Header().Set("Vary", "X-authentik-version, Etag")
|
w.Header().Set("Vary", "X-authentik-version, Etag")
|
||||||
etagHandler.ServeHTTP(w, r)
|
etagHandler.ServeHTTP(w, r)
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ from aws_cdk import (
|
|||||||
)
|
)
|
||||||
from constructs import Construct
|
from constructs import Construct
|
||||||
|
|
||||||
from authentik import __version__
|
from authentik import authentik_version as ak_version
|
||||||
|
|
||||||
|
|
||||||
class AuthentikStack(Stack):
|
class AuthentikStack(Stack):
|
||||||
@@ -88,7 +88,7 @@ class AuthentikStack(Stack):
|
|||||||
self,
|
self,
|
||||||
"AuthentikVersion",
|
"AuthentikVersion",
|
||||||
type="String",
|
type="String",
|
||||||
default=__version__,
|
default=ak_version(),
|
||||||
description="authentik Docker image tag",
|
description="authentik Docker image tag",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ from typing import TYPE_CHECKING
|
|||||||
|
|
||||||
from prometheus_client.values import MultiProcessValue
|
from prometheus_client.values import MultiProcessValue
|
||||||
|
|
||||||
from authentik import get_full_version
|
from authentik import authentik_full_version
|
||||||
from authentik.lib.config import CONFIG
|
from authentik.lib.config import CONFIG
|
||||||
from authentik.lib.debug import start_debug_server
|
from authentik.lib.debug import start_debug_server
|
||||||
from authentik.lib.logging import get_logger_config
|
from authentik.lib.logging import get_logger_config
|
||||||
@@ -127,9 +127,9 @@ if not CONFIG.get_bool("disable_startup_analytics", False):
|
|||||||
json={
|
json={
|
||||||
"domain": "authentik",
|
"domain": "authentik",
|
||||||
"name": "pageview",
|
"name": "pageview",
|
||||||
"referrer": get_full_version(),
|
"referrer": authentik_full_version(),
|
||||||
"url": (
|
"url": (
|
||||||
f"http://localhost/{env}?utm_source={get_full_version()}&utm_medium={env}"
|
f"http://localhost/{env}?utm_source={authentik_full_version()}&utm_medium={env}"
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
headers={
|
headers={
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
from lifecycle.migrate import BaseMigration
|
from lifecycle.migrate import BaseMigration
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
from authentik import __version__, get_build_hash
|
from authentik import authentik_version, authentik_build_hash
|
||||||
|
|
||||||
|
|
||||||
class Migration(BaseMigration):
|
class Migration(BaseMigration):
|
||||||
@@ -14,7 +14,7 @@ class Migration(BaseMigration):
|
|||||||
ORDER BY "timestamp" DESC
|
ORDER BY "timestamp" DESC
|
||||||
LIMIT 1
|
LIMIT 1
|
||||||
""",
|
""",
|
||||||
(__version__, get_build_hash()),
|
(authentik_version(), authentik_build_hash()),
|
||||||
)
|
)
|
||||||
return not bool(self.cur.rowcount)
|
return not bool(self.cur.rowcount)
|
||||||
|
|
||||||
@@ -24,7 +24,7 @@ class Migration(BaseMigration):
|
|||||||
INSERT INTO authentik_version_history ("timestamp", version, build)
|
INSERT INTO authentik_version_history ("timestamp", version, build)
|
||||||
VALUES (%s, %s, %s)
|
VALUES (%s, %s, %s)
|
||||||
""",
|
""",
|
||||||
(datetime.now(), __version__, get_build_hash()),
|
(datetime.now(), authentik_version(), authentik_build_hash()),
|
||||||
)
|
)
|
||||||
self.cur.execute(
|
self.cur.execute(
|
||||||
"""
|
"""
|
||||||
|
|||||||
317
pyproject.toml
317
pyproject.toml
@@ -5,112 +5,111 @@ description = ""
|
|||||||
authors = [{ name = "authentik Team", email = "hello@goauthentik.io" }]
|
authors = [{ name = "authentik Team", email = "hello@goauthentik.io" }]
|
||||||
requires-python = "==3.13.*"
|
requires-python = "==3.13.*"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"argon2-cffi==25.1.0",
|
"argon2-cffi==25.1.0",
|
||||||
"channels==4.3.0",
|
"channels==4.3.0",
|
||||||
"channels-redis==4.3.0",
|
"channels-redis==4.3.0",
|
||||||
"cryptography==45.0.5",
|
"cryptography==45.0.5",
|
||||||
"dacite==1.9.2",
|
"dacite==1.9.2",
|
||||||
"deepmerge==2.0",
|
"deepmerge==2.0",
|
||||||
"defusedxml==0.7.1",
|
"defusedxml==0.7.1",
|
||||||
"django==5.1.11",
|
"django==5.1.11",
|
||||||
"django-countries==7.6.1",
|
"django-countries==7.6.1",
|
||||||
"django-cte==2.0.0",
|
"django-cte==2.0.0",
|
||||||
"django-dramatiq-postgres",
|
"django-dramatiq-postgres",
|
||||||
"django-filter==25.1",
|
"django-filter==25.1",
|
||||||
"django-guardian==3.0.3",
|
"django-guardian==3.0.3",
|
||||||
"django-model-utils==5.0.0",
|
"django-model-utils==5.0.0",
|
||||||
"django-pglock==1.7.2",
|
"django-pglock==1.7.2",
|
||||||
"django-pgtrigger==4.15.2",
|
"django-pgtrigger==4.15.2",
|
||||||
"django-prometheus==2.4.1",
|
"django-prometheus==2.4.1",
|
||||||
"django-redis==6.0.0",
|
"django-redis==6.0.0",
|
||||||
"django-storages[s3]==1.14.6",
|
"django-storages[s3]==1.14.6",
|
||||||
"django-tenants==3.8.0",
|
"django-tenants==3.8.0",
|
||||||
"djangoql==0.18.1",
|
"djangoql==0.18.1",
|
||||||
"djangorestframework-guardian==0.4.0",
|
"djangorestframework-guardian==0.4.0",
|
||||||
"djangorestframework==3.16.0",
|
"djangorestframework==3.16.0",
|
||||||
"docker==7.1.0",
|
"docker==7.1.0",
|
||||||
"drf-orjson-renderer==1.7.3",
|
"drf-orjson-renderer==1.7.3",
|
||||||
"drf-spectacular==0.28.0",
|
"drf-spectacular==0.28.0",
|
||||||
"dumb-init==1.2.5.post1",
|
"dumb-init==1.2.5.post1",
|
||||||
"duo-client==5.5.0",
|
"duo-client==5.5.0",
|
||||||
"fido2==2.0.0",
|
"fido2==2.0.0",
|
||||||
"geoip2==5.1.0",
|
"geoip2==5.1.0",
|
||||||
"geopy==2.4.1",
|
"geopy==2.4.1",
|
||||||
"google-api-python-client==2.177.0",
|
"google-api-python-client==2.177.0",
|
||||||
"gssapi==1.9.0",
|
"gssapi==1.9.0",
|
||||||
"gunicorn==23.0.0",
|
"gunicorn==23.0.0",
|
||||||
"jsonpatch==1.33",
|
"jsonpatch==1.33",
|
||||||
"jwcrypto==1.5.6",
|
"jwcrypto==1.5.6",
|
||||||
"kubernetes==33.1.0",
|
"kubernetes==33.1.0",
|
||||||
"ldap3==2.9.1",
|
"ldap3==2.9.1",
|
||||||
"lxml==6.0.0",
|
"lxml==6.0.0",
|
||||||
"msgraph-sdk==1.39.0",
|
"msgraph-sdk==1.39.0",
|
||||||
"opencontainers==0.0.15",
|
"opencontainers==0.0.15",
|
||||||
"packaging==25.0",
|
"packaging==25.0",
|
||||||
"paramiko==3.5.1",
|
"paramiko==3.5.1",
|
||||||
"psycopg[c,pool]==3.2.9",
|
"psycopg[c,pool]==3.2.9",
|
||||||
"pydantic==2.11.7",
|
"pydantic==2.11.7",
|
||||||
"pydantic-scim==0.0.8",
|
"pydantic-scim==0.0.8",
|
||||||
"pyjwt==2.10.1",
|
"pyjwt==2.10.1",
|
||||||
"pyrad==2.4",
|
"pyrad==2.4",
|
||||||
"python-kadmin-rs==0.6.1",
|
"python-kadmin-rs==0.6.1",
|
||||||
"pyyaml==6.0.2",
|
"pyyaml==6.0.2",
|
||||||
"requests-oauthlib==2.0.0",
|
"requests-oauthlib==2.0.0",
|
||||||
"scim2-filter-parser==0.7.0",
|
"scim2-filter-parser==0.7.0",
|
||||||
"sentry-sdk==2.33.2",
|
"sentry-sdk==2.33.2",
|
||||||
"service-identity==24.2.0",
|
"service-identity==24.2.0",
|
||||||
"setproctitle==1.3.6",
|
"setproctitle==1.3.6",
|
||||||
"structlog==25.4.0",
|
"structlog==25.4.0",
|
||||||
"swagger-spec-validator==3.0.4",
|
"swagger-spec-validator==3.0.4",
|
||||||
"twilio==9.7.0",
|
"twilio==9.7.0",
|
||||||
"ua-parser==1.0.1",
|
"ua-parser==1.0.1",
|
||||||
"unidecode==1.4.0",
|
"unidecode==1.4.0",
|
||||||
"urllib3<3",
|
"urllib3<3",
|
||||||
"uvicorn[standard]==0.35.0",
|
"uvicorn[standard]==0.35.0",
|
||||||
"watchdog==6.0.0",
|
"watchdog==6.0.0",
|
||||||
"webauthn==2.6.0",
|
"webauthn==2.6.0",
|
||||||
"wsproto==1.2.0",
|
"wsproto==1.2.0",
|
||||||
"xmlsec==1.3.16",
|
"xmlsec==1.3.16",
|
||||||
"zxcvbn==4.5.0",
|
"zxcvbn==4.5.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[dependency-groups]
|
[dependency-groups]
|
||||||
dev = [
|
dev = [
|
||||||
"aws-cdk-lib==2.188.0",
|
"aws-cdk-lib==2.188.0",
|
||||||
"bandit==1.8.3",
|
"bandit==1.8.3",
|
||||||
"black==25.1.0",
|
"black==25.1.0",
|
||||||
"bump2version==1.0.1",
|
"channels[daphne]==4.3.0",
|
||||||
"channels[daphne]==4.3.0",
|
"codespell==2.4.1",
|
||||||
"codespell==2.4.1",
|
"colorama==0.4.6",
|
||||||
"colorama==0.4.6",
|
"constructs==10.4.2",
|
||||||
"constructs==10.4.2",
|
"coverage[toml]==7.8.0",
|
||||||
"coverage[toml]==7.8.0",
|
"debugpy==1.8.14",
|
||||||
"debugpy==1.8.14",
|
"drf-jsonschema-serializer==3.0.0",
|
||||||
"drf-jsonschema-serializer==3.0.0",
|
"freezegun==1.5.1",
|
||||||
"freezegun==1.5.1",
|
"importlib-metadata==8.6.1",
|
||||||
"importlib-metadata==8.6.1",
|
"k5test==0.10.4",
|
||||||
"k5test==0.10.4",
|
"pdoc==15.0.3",
|
||||||
"pdoc==15.0.3",
|
"pytest==8.3.5",
|
||||||
"pytest==8.3.5",
|
"pytest-django==4.11.1",
|
||||||
"pytest-django==4.11.1",
|
"pytest-github-actions-annotate-failures==0.3.0",
|
||||||
"pytest-github-actions-annotate-failures==0.3.0",
|
"pytest-randomly==3.16.0",
|
||||||
"pytest-randomly==3.16.0",
|
"pytest-timeout==2.4.0",
|
||||||
"pytest-timeout==2.4.0",
|
"requests-mock==1.12.1",
|
||||||
"requests-mock==1.12.1",
|
"ruff==0.11.9",
|
||||||
"ruff==0.11.9",
|
"selenium==4.32.0",
|
||||||
"selenium==4.32.0",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[tool.uv]
|
[tool.uv]
|
||||||
no-binary-package = [
|
no-binary-package = [
|
||||||
# This differs from the no-binary packages in the Dockerfile. This is due to the fact
|
# This differs from the no-binary packages in the Dockerfile. This is due to the fact
|
||||||
# that these packages are built from source for different reasons than cryptography and kadmin.
|
# that these packages are built from source for different reasons than cryptography and kadmin.
|
||||||
# These packages are built from source to link against the libxml2 on the system which is
|
# These packages are built from source to link against the libxml2 on the system which is
|
||||||
# required for functionality and to stay up-to-date on both libraries.
|
# required for functionality and to stay up-to-date on both libraries.
|
||||||
# The other packages specified in the dockerfile are compiled from source to link against the
|
# The other packages specified in the dockerfile are compiled from source to link against the
|
||||||
# correct FIPS OpenSSL libraries
|
# correct FIPS OpenSSL libraries
|
||||||
"lxml",
|
"lxml",
|
||||||
"xmlsec",
|
"xmlsec",
|
||||||
]
|
]
|
||||||
|
|
||||||
[tool.uv.sources]
|
[tool.uv.sources]
|
||||||
@@ -133,29 +132,29 @@ exclude_dirs = ["**/node_modules/**"]
|
|||||||
|
|
||||||
[tool.codespell]
|
[tool.codespell]
|
||||||
skip = [
|
skip = [
|
||||||
"**/node_modules",
|
"**/node_modules",
|
||||||
"**/package-lock.json",
|
"**/package-lock.json",
|
||||||
"schema.yml",
|
"schema.yml",
|
||||||
"unittest.xml",
|
"unittest.xml",
|
||||||
"./blueprints/schema.json",
|
"./blueprints/schema.json",
|
||||||
"go.sum",
|
"go.sum",
|
||||||
"locale",
|
"locale",
|
||||||
"**/web/src/locales",
|
"**/web/src/locales",
|
||||||
"**/dist", # Distributed build output
|
"**/dist", # Distributed build output
|
||||||
"**/storybook-static",
|
"**/storybook-static",
|
||||||
"**/web/xliff",
|
"**/web/xliff",
|
||||||
"**/out", # TypeScript type-checking output
|
"**/out", # TypeScript type-checking output
|
||||||
"./web/custom-elements.json", # TypeScript custom element definitions
|
"./web/custom-elements.json", # TypeScript custom element definitions
|
||||||
"./website/build", # TODO: Remove this after moving website to docs
|
"./website/build", # TODO: Remove this after moving website to docs
|
||||||
"./website/**/build", # TODO: Remove this after moving website to docs
|
"./website/**/build", # TODO: Remove this after moving website to docs
|
||||||
"./docs/build", # Docusaurus Topic docs build output
|
"./docs/build", # Docusaurus Topic docs build output
|
||||||
"./docs/**/build", # Docusaurus workspaces output
|
"./docs/**/build", # Docusaurus workspaces output
|
||||||
"*.api.mdx", # Generated API docs
|
"*.api.mdx", # Generated API docs
|
||||||
"./gen-ts-api",
|
"./gen-ts-api",
|
||||||
"./gen-py-api",
|
"./gen-py-api",
|
||||||
"./gen-go-api",
|
"./gen-go-api",
|
||||||
"./htmlcov",
|
"./htmlcov",
|
||||||
"./media",
|
"./media",
|
||||||
]
|
]
|
||||||
dictionary = ".github/codespell-dictionary.txt,-"
|
dictionary = ".github/codespell-dictionary.txt,-"
|
||||||
ignore-words = ".github/codespell-words.txt"
|
ignore-words = ".github/codespell-words.txt"
|
||||||
@@ -172,23 +171,23 @@ exclude = ["**/migrations/**", "**/node_modules/**"]
|
|||||||
|
|
||||||
[tool.ruff.lint]
|
[tool.ruff.lint]
|
||||||
select = [
|
select = [
|
||||||
# pycodestyle
|
# pycodestyle
|
||||||
"E",
|
"E",
|
||||||
# Pyflakes
|
# Pyflakes
|
||||||
"F",
|
"F",
|
||||||
# isort
|
# isort
|
||||||
"I",
|
"I",
|
||||||
# pyupgrade
|
# pyupgrade
|
||||||
"UP",
|
"UP",
|
||||||
# flake8-bugbear
|
# flake8-bugbear
|
||||||
"B",
|
"B",
|
||||||
# django
|
# django
|
||||||
"DJ",
|
"DJ",
|
||||||
# pylint
|
# pylint
|
||||||
"PL",
|
"PL",
|
||||||
]
|
]
|
||||||
ignore = [
|
ignore = [
|
||||||
"DJ001", # Avoid using `null=True` on string-based fields,
|
"DJ001", # Avoid using `null=True` on string-based fields,
|
||||||
]
|
]
|
||||||
|
|
||||||
[tool.ruff.lint.pylint]
|
[tool.ruff.lint.pylint]
|
||||||
@@ -200,14 +199,14 @@ max-returns = 10
|
|||||||
source = ["authentik"]
|
source = ["authentik"]
|
||||||
relative_files = true
|
relative_files = true
|
||||||
omit = [
|
omit = [
|
||||||
"*/asgi.py",
|
"*/asgi.py",
|
||||||
"manage.py",
|
"manage.py",
|
||||||
"*/migrations/*",
|
"*/migrations/*",
|
||||||
"*/management/commands/*",
|
"*/management/commands/*",
|
||||||
"*/apps.py",
|
"*/apps.py",
|
||||||
# TODO: Remove this after moving website to docs
|
# TODO: Remove this after moving website to docs
|
||||||
"website/",
|
"website/",
|
||||||
"docs/",
|
"docs/",
|
||||||
]
|
]
|
||||||
|
|
||||||
[tool.coverage.report]
|
[tool.coverage.report]
|
||||||
@@ -215,19 +214,19 @@ sort = "Cover"
|
|||||||
skip_covered = true
|
skip_covered = true
|
||||||
precision = 2
|
precision = 2
|
||||||
exclude_lines = [
|
exclude_lines = [
|
||||||
"pragma: no cover",
|
"pragma: no cover",
|
||||||
# Don't complain about missing debug-only code:
|
# Don't complain about missing debug-only code:
|
||||||
"def __unicode__",
|
"def __unicode__",
|
||||||
"def __str__",
|
"def __str__",
|
||||||
"def __repr__",
|
"def __repr__",
|
||||||
"if self.debug",
|
"if self.debug",
|
||||||
"if TYPE_CHECKING",
|
"if TYPE_CHECKING",
|
||||||
# Don't complain if tests don't hit defensive assertion code:
|
# Don't complain if tests don't hit defensive assertion code:
|
||||||
"raise AssertionError",
|
"raise AssertionError",
|
||||||
"raise NotImplementedError",
|
"raise NotImplementedError",
|
||||||
# Don't complain if non-runnable code isn't run:
|
# Don't complain if non-runnable code isn't run:
|
||||||
"if 0:",
|
"if 0:",
|
||||||
"if __name__ == .__main__.:",
|
"if __name__ == .__main__.:",
|
||||||
]
|
]
|
||||||
show_missing = true
|
show_missing = true
|
||||||
|
|
||||||
@@ -237,6 +236,6 @@ python_files = ["tests.py", "test_*.py", "*_tests.py"]
|
|||||||
junit_family = "xunit2"
|
junit_family = "xunit2"
|
||||||
addopts = "-p authentik.root.test_plugin --junitxml=unittest.xml -vv --full-trace --doctest-modules --import-mode=importlib --ignore=authentik/tasks/setup.py"
|
addopts = "-p authentik.root.test_plugin --junitxml=unittest.xml -vv --full-trace --doctest-modules --import-mode=importlib --ignore=authentik/tasks/setup.py"
|
||||||
filterwarnings = [
|
filterwarnings = [
|
||||||
"ignore:defusedxml.lxml is no longer supported and will be removed in a future release.:DeprecationWarning",
|
"ignore:defusedxml.lxml is no longer supported and will be removed in a future release.:DeprecationWarning",
|
||||||
"ignore:SelectableGroups dict interface is deprecated. Use select.:DeprecationWarning",
|
"ignore:SelectableGroups dict interface is deprecated. Use select.:DeprecationWarning",
|
||||||
]
|
]
|
||||||
|
|||||||
92
scripts/generate_docker_compose.py
Normal file
92
scripts/generate_docker_compose.py
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
from yaml import safe_dump
|
||||||
|
|
||||||
|
from authentik import authentik_version
|
||||||
|
|
||||||
|
authentik_image = (
|
||||||
|
f"${{AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}}:${{AUTHENTIK_TAG:-{authentik_version()}}}"
|
||||||
|
)
|
||||||
|
|
||||||
|
base = {
|
||||||
|
"services": {
|
||||||
|
"postgresql": {
|
||||||
|
"env_file": [".env"],
|
||||||
|
"environment": {
|
||||||
|
"POSTGRES_DB": "${PG_DB:-authentik}",
|
||||||
|
"POSTGRES_PASSWORD": "${PG_PASS:?database " "password " "required}",
|
||||||
|
"POSTGRES_USER": "${PG_USER:-authentik}",
|
||||||
|
},
|
||||||
|
"healthcheck": {
|
||||||
|
"interval": "30s",
|
||||||
|
"retries": 5,
|
||||||
|
"start_period": "20s",
|
||||||
|
"test": ["CMD-SHELL", "pg_isready -d " "$${POSTGRES_DB} -U " "$${POSTGRES_USER}"],
|
||||||
|
"timeout": "5s",
|
||||||
|
},
|
||||||
|
"image": "docker.io/library/postgres:16-alpine",
|
||||||
|
"restart": "unless-stopped",
|
||||||
|
"volumes": ["database:/var/lib/postgresql/data"],
|
||||||
|
},
|
||||||
|
"redis": {
|
||||||
|
"command": "--save 60 1 --loglevel warning",
|
||||||
|
"healthcheck": {
|
||||||
|
"interval": "30s",
|
||||||
|
"retries": 5,
|
||||||
|
"start_period": "20s",
|
||||||
|
"test": ["CMD-SHELL", "redis-cli ping | grep PONG"],
|
||||||
|
"timeout": "3s",
|
||||||
|
},
|
||||||
|
"image": "docker.io/library/redis:alpine",
|
||||||
|
"restart": "unless-stopped",
|
||||||
|
"volumes": ["redis:/data"],
|
||||||
|
},
|
||||||
|
"server": {
|
||||||
|
"command": "server",
|
||||||
|
"depends_on": {
|
||||||
|
"postgresql": {"condition": "service_healthy"},
|
||||||
|
"redis": {"condition": "service_healthy"},
|
||||||
|
},
|
||||||
|
"env_file": [".env"],
|
||||||
|
"environment": {
|
||||||
|
"AUTHENTIK_POSTGRESQL__HOST": "postgresql",
|
||||||
|
"AUTHENTIK_POSTGRESQL__NAME": "${PG_DB:-authentik}",
|
||||||
|
"AUTHENTIK_POSTGRESQL__PASSWORD": "${PG_PASS}",
|
||||||
|
"AUTHENTIK_POSTGRESQL__USER": "${PG_USER:-authentik}",
|
||||||
|
"AUTHENTIK_REDIS__HOST": "redis",
|
||||||
|
"AUTHENTIK_SECRET_KEY": "${AUTHENTIK_SECRET_KEY:?secret " "key " "required}",
|
||||||
|
},
|
||||||
|
"image": authentik_image,
|
||||||
|
"ports": ["${COMPOSE_PORT_HTTP:-9000}:9000", "${COMPOSE_PORT_HTTPS:-9443}:9443"],
|
||||||
|
"restart": "unless-stopped",
|
||||||
|
"volumes": ["./media:/media", "./custom-templates:/templates"],
|
||||||
|
},
|
||||||
|
"worker": {
|
||||||
|
"command": "worker",
|
||||||
|
"depends_on": {
|
||||||
|
"postgresql": {"condition": "service_healthy"},
|
||||||
|
"redis": {"condition": "service_healthy"},
|
||||||
|
},
|
||||||
|
"env_file": [".env"],
|
||||||
|
"environment": {
|
||||||
|
"AUTHENTIK_POSTGRESQL__HOST": "postgresql",
|
||||||
|
"AUTHENTIK_POSTGRESQL__NAME": "${PG_DB:-authentik}",
|
||||||
|
"AUTHENTIK_POSTGRESQL__PASSWORD": "${PG_PASS}",
|
||||||
|
"AUTHENTIK_POSTGRESQL__USER": "${PG_USER:-authentik}",
|
||||||
|
"AUTHENTIK_REDIS__HOST": "redis",
|
||||||
|
"AUTHENTIK_SECRET_KEY": "${AUTHENTIK_SECRET_KEY:?secret " "key " "required}",
|
||||||
|
},
|
||||||
|
"image": authentik_image,
|
||||||
|
"restart": "unless-stopped",
|
||||||
|
"user": "root",
|
||||||
|
"volumes": [
|
||||||
|
"/var/run/docker.sock:/var/run/docker.sock",
|
||||||
|
"./media:/media",
|
||||||
|
"./certs:/certs",
|
||||||
|
"./custom-templates:/templates",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"volumes": {"database": {"driver": "local"}, "redis": {"driver": "local"}},
|
||||||
|
}
|
||||||
|
|
||||||
|
with open("docker-compose.yml", "w") as _compose:
|
||||||
|
safe_dump(base, _compose)
|
||||||
@@ -5,11 +5,11 @@ Generates a Semantic Versioning identifier, suffixed with a timestamp.
|
|||||||
|
|
||||||
from time import time
|
from time import time
|
||||||
|
|
||||||
from authentik import __version__ as package_version
|
from authentik import authentik_version
|
||||||
|
|
||||||
"""
|
"""
|
||||||
See: https://semver.org/#spec-item-9 (Pre-release spec)
|
See: https://semver.org/#spec-item-9 (Pre-release spec)
|
||||||
"""
|
"""
|
||||||
pre_release_timestamp = int(time())
|
pre_release_timestamp = int(time())
|
||||||
|
|
||||||
print(f"{package_version}-{pre_release_timestamp}")
|
print(f"{authentik_version()}-{pre_release_timestamp}")
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
"""LDAP and Outpost e2e tests"""
|
"""LDAP and Outpost e2e tests"""
|
||||||
|
|
||||||
from dataclasses import asdict
|
from dataclasses import asdict
|
||||||
from time import sleep
|
|
||||||
|
|
||||||
from guardian.shortcuts import assign_perm
|
from guardian.shortcuts import assign_perm
|
||||||
from ldap3 import ALL, ALL_ATTRIBUTES, ALL_OPERATIONAL_ATTRIBUTES, SUBTREE, Connection, Server
|
from ldap3 import ALL, ALL_ATTRIBUTES, ALL_OPERATIONAL_ATTRIBUTES, SUBTREE, Connection, Server
|
||||||
@@ -56,17 +55,6 @@ class TestProviderLDAP(SeleniumTestCase):
|
|||||||
outpost.providers.add(ldap)
|
outpost.providers.add(ldap)
|
||||||
|
|
||||||
self.start_ldap(outpost)
|
self.start_ldap(outpost)
|
||||||
|
|
||||||
# Wait until outpost healthcheck succeeds
|
|
||||||
healthcheck_retries = 0
|
|
||||||
while healthcheck_retries < 50: # noqa: PLR2004
|
|
||||||
if len(outpost.state) > 0:
|
|
||||||
state = outpost.state[0]
|
|
||||||
if state.last_seen:
|
|
||||||
break
|
|
||||||
healthcheck_retries += 1
|
|
||||||
sleep(0.5)
|
|
||||||
sleep(5)
|
|
||||||
return outpost
|
return outpost
|
||||||
|
|
||||||
@retry()
|
@retry()
|
||||||
|
|||||||
@@ -88,15 +88,6 @@ class TestProviderProxy(SeleniumTestCase):
|
|||||||
|
|
||||||
self.start_proxy(outpost)
|
self.start_proxy(outpost)
|
||||||
|
|
||||||
# Wait until outpost healthcheck succeeds
|
|
||||||
healthcheck_retries = 0
|
|
||||||
while healthcheck_retries < 50: # noqa: PLR2004
|
|
||||||
if len(outpost.state) > 0:
|
|
||||||
state = outpost.state[0]
|
|
||||||
if state.last_seen:
|
|
||||||
break
|
|
||||||
healthcheck_retries += 1
|
|
||||||
sleep(0.5)
|
|
||||||
sleep(5)
|
sleep(5)
|
||||||
|
|
||||||
self.driver.get("http://localhost:9000/api")
|
self.driver.get("http://localhost:9000/api")
|
||||||
@@ -170,15 +161,6 @@ class TestProviderProxy(SeleniumTestCase):
|
|||||||
|
|
||||||
self.start_proxy(outpost)
|
self.start_proxy(outpost)
|
||||||
|
|
||||||
# Wait until outpost healthcheck succeeds
|
|
||||||
healthcheck_retries = 0
|
|
||||||
while healthcheck_retries < 50: # noqa: PLR2004
|
|
||||||
if len(outpost.state) > 0:
|
|
||||||
state = outpost.state[0]
|
|
||||||
if state.last_seen:
|
|
||||||
break
|
|
||||||
healthcheck_retries += 1
|
|
||||||
sleep(0.5)
|
|
||||||
sleep(5)
|
sleep(5)
|
||||||
|
|
||||||
self.driver.get("http://localhost:9000/api")
|
self.driver.get("http://localhost:9000/api")
|
||||||
|
|||||||
@@ -77,17 +77,6 @@ class TestProviderProxyForward(SeleniumTestCase):
|
|||||||
|
|
||||||
self.start_outpost(outpost)
|
self.start_outpost(outpost)
|
||||||
|
|
||||||
# Wait until outpost healthcheck succeeds
|
|
||||||
healthcheck_retries = 0
|
|
||||||
while healthcheck_retries < 50: # noqa: PLR2004
|
|
||||||
if len(outpost.state) > 0:
|
|
||||||
state = outpost.state[0]
|
|
||||||
if state.last_seen:
|
|
||||||
break
|
|
||||||
healthcheck_retries += 1
|
|
||||||
sleep(0.5)
|
|
||||||
sleep(5)
|
|
||||||
|
|
||||||
@retry()
|
@retry()
|
||||||
def test_traefik(self):
|
def test_traefik(self):
|
||||||
"""Test traefik"""
|
"""Test traefik"""
|
||||||
|
|||||||
@@ -51,15 +51,6 @@ class TestProviderRadius(SeleniumTestCase):
|
|||||||
|
|
||||||
self.start_radius(outpost)
|
self.start_radius(outpost)
|
||||||
|
|
||||||
# Wait until outpost healthcheck succeeds
|
|
||||||
healthcheck_retries = 0
|
|
||||||
while healthcheck_retries < 50: # noqa: PLR2004
|
|
||||||
if len(outpost.state) > 0:
|
|
||||||
state = outpost.state[0]
|
|
||||||
if state.last_seen:
|
|
||||||
break
|
|
||||||
healthcheck_retries += 1
|
|
||||||
sleep(0.5)
|
|
||||||
sleep(5)
|
sleep(5)
|
||||||
return outpost
|
return outpost
|
||||||
|
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ def get_local_ip() -> str:
|
|||||||
class DockerTestCase(TestCase):
|
class DockerTestCase(TestCase):
|
||||||
"""Mixin for dealing with containers"""
|
"""Mixin for dealing with containers"""
|
||||||
|
|
||||||
max_healthcheck_attempts = 30
|
max_healthcheck_attempts = 45
|
||||||
|
|
||||||
__client: DockerClient
|
__client: DockerClient
|
||||||
__network: Network
|
__network: Network
|
||||||
@@ -88,7 +88,7 @@ class DockerTestCase(TestCase):
|
|||||||
sleep(1)
|
sleep(1)
|
||||||
attempt += 1
|
attempt += 1
|
||||||
if attempt >= self.max_healthcheck_attempts:
|
if attempt >= self.max_healthcheck_attempts:
|
||||||
self.failureException("Container failed to start")
|
raise self.failureException("Container failed to start")
|
||||||
|
|
||||||
def get_container_image(self, base: str) -> str:
|
def get_container_image(self, base: str) -> str:
|
||||||
"""Try to pull docker image based on git branch, fallback to main if not found."""
|
"""Try to pull docker image based on git branch, fallback to main if not found."""
|
||||||
|
|||||||
11
uv.lock
generated
11
uv.lock
generated
@@ -236,7 +236,6 @@ dev = [
|
|||||||
{ name = "aws-cdk-lib" },
|
{ name = "aws-cdk-lib" },
|
||||||
{ name = "bandit" },
|
{ name = "bandit" },
|
||||||
{ name = "black" },
|
{ name = "black" },
|
||||||
{ name = "bump2version" },
|
|
||||||
{ name = "channels", extra = ["daphne"] },
|
{ name = "channels", extra = ["daphne"] },
|
||||||
{ name = "codespell" },
|
{ name = "codespell" },
|
||||||
{ name = "colorama" },
|
{ name = "colorama" },
|
||||||
@@ -334,7 +333,6 @@ dev = [
|
|||||||
{ name = "aws-cdk-lib", specifier = "==2.188.0" },
|
{ name = "aws-cdk-lib", specifier = "==2.188.0" },
|
||||||
{ name = "bandit", specifier = "==1.8.3" },
|
{ name = "bandit", specifier = "==1.8.3" },
|
||||||
{ name = "black", specifier = "==25.1.0" },
|
{ name = "black", specifier = "==25.1.0" },
|
||||||
{ name = "bump2version", specifier = "==1.0.1" },
|
|
||||||
{ name = "channels", extras = ["daphne"], specifier = "==4.3.0" },
|
{ name = "channels", extras = ["daphne"], specifier = "==4.3.0" },
|
||||||
{ name = "codespell", specifier = "==2.4.1" },
|
{ name = "codespell", specifier = "==2.4.1" },
|
||||||
{ name = "colorama", specifier = "==0.4.6" },
|
{ name = "colorama", specifier = "==0.4.6" },
|
||||||
@@ -583,15 +581,6 @@ wheels = [
|
|||||||
{ url = "https://files.pythonhosted.org/packages/16/56/dd25fb9e47060e8f7e353208678fefb65d1b06704ea30983cad8bdd81370/botocore-1.40.2-py3-none-any.whl", hash = "sha256:a31e6269af05498f8dc1c7f2b3f34448a0f16c79a8601c0389ecddab51b2c2ab", size = 13944886, upload-time = "2025-08-04T19:31:37.027Z" },
|
{ url = "https://files.pythonhosted.org/packages/16/56/dd25fb9e47060e8f7e353208678fefb65d1b06704ea30983cad8bdd81370/botocore-1.40.2-py3-none-any.whl", hash = "sha256:a31e6269af05498f8dc1c7f2b3f34448a0f16c79a8601c0389ecddab51b2c2ab", size = 13944886, upload-time = "2025-08-04T19:31:37.027Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "bump2version"
|
|
||||||
version = "1.0.1"
|
|
||||||
source = { registry = "https://pypi.org/simple" }
|
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/29/2a/688aca6eeebfe8941235be53f4da780c6edee05dbbea5d7abaa3aab6fad2/bump2version-1.0.1.tar.gz", hash = "sha256:762cb2bfad61f4ec8e2bdf452c7c267416f8c70dd9ecb1653fd0bbb01fa936e6", size = 36236, upload-time = "2020-10-07T18:38:40.119Z" }
|
|
||||||
wheels = [
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/1d/e3/fa60c47d7c344533142eb3af0b73234ef8ea3fb2da742ab976b947e717df/bump2version-1.0.1-py2.py3-none-any.whl", hash = "sha256:37f927ea17cde7ae2d7baf832f8e80ce3777624554a653006c9144f8017fe410", size = 22030, upload-time = "2020-10-07T18:38:38.148Z" },
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cachetools"
|
name = "cachetools"
|
||||||
version = "5.5.2"
|
version = "5.5.2"
|
||||||
|
|||||||
4
web/package-lock.json
generated
4
web/package-lock.json
generated
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "@goauthentik/web",
|
"name": "@goauthentik/web",
|
||||||
"version": "0.0.0",
|
"version": "2025.6.4",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "@goauthentik/web",
|
"name": "@goauthentik/web",
|
||||||
"version": "0.0.0",
|
"version": "2025.6.4",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"workspaces": [
|
"workspaces": [
|
||||||
"./packages/*"
|
"./packages/*"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@goauthentik/web",
|
"name": "@goauthentik/web",
|
||||||
"version": "0.0.0",
|
"version": "2025.6.4",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ export function readGitBuildHash() {
|
|||||||
/**
|
/**
|
||||||
* Reads the build identifier for the current environment.
|
* Reads the build identifier for the current environment.
|
||||||
*
|
*
|
||||||
* This must match the behavior defined in authentik's server-side `get_full_version` function.
|
* This must match the behavior defined in authentik's server-side `authentik_full_version` function.
|
||||||
*
|
*
|
||||||
* @runtime node
|
* @runtime node
|
||||||
* @see {@link "authentik\_\_init\_\_.py"}
|
* @see {@link "authentik\_\_init\_\_.py"}
|
||||||
|
|||||||
Reference in New Issue
Block a user