Skip to content

Commit

Permalink
Merge branch 'main' into dev
Browse files Browse the repository at this point in the history
* main:
  root: fix missing imports after #9081 (#9106)
  root: move database calls from ready() to dedicated startup signal (#9081)
  web: fix console log leftover (#9096)
  web: bump the eslint group in /web with 2 updates (#9098)
  core: bump twilio from 9.0.2 to 9.0.3 (#9103)
  web: bump the eslint group in /tests/wdio with 2 updates (#9099)
  core: bump drf-spectacular from 0.27.1 to 0.27.2 (#9100)
  core: bump django-model-utils from 4.4.0 to 4.5.0 (#9101)
  core: bump ruff from 0.3.4 to 0.3.5 (#9102)
  website/docs:  update notes on SECRET_KEY (#9091)
  web: fix broken locale compile (#9095)
  website/integrations: add outline knowledge base (#8786)
  website/docs: fix typo (#9082)
  website/docs: email stage: fix example translation error (#9048)
  • Loading branch information
kensternberg-authentik committed Apr 2, 2024
2 parents 5d4c380 + 70462c4 commit 66cefcc
Show file tree
Hide file tree
Showing 57 changed files with 1,148 additions and 298 deletions.
8 changes: 4 additions & 4 deletions .github/actions/setup/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,25 +16,25 @@ runs:
sudo apt-get update
sudo apt-get install --no-install-recommends -y libpq-dev openssl libxmlsec1-dev pkg-config gettext
- name: Setup python and restore poetry
uses: actions/setup-python@v4
uses: actions/setup-python@v5
with:
python-version-file: "pyproject.toml"
cache: "poetry"
- name: Setup node
uses: actions/setup-node@v3
uses: actions/setup-node@v4
with:
node-version-file: web/package.json
cache: "npm"
cache-dependency-path: web/package-lock.json
- name: Setup go
uses: actions/setup-go@v4
uses: actions/setup-go@v5
with:
go-version-file: "go.mod"
- name: Setup dependencies
shell: bash
run: |
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
poetry install
cd web && npm ci
- name: Generate config
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/ci-main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ jobs:
uses: ./.github/actions/setup
- name: Setup e2e env (chrome, etc)
run: |
docker-compose -f tests/e2e/docker-compose.yml up -d
docker compose -f tests/e2e/docker-compose.yml up -d
- id: cache-web
uses: actions/cache@v4
with:
Expand Down
8 changes: 4 additions & 4 deletions .github/workflows/release-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -157,10 +157,10 @@ jobs:
run: |
echo "PG_PASS=$(openssl rand -base64 32)" >> .env
echo "AUTHENTIK_SECRET_KEY=$(openssl rand -base64 32)" >> .env
docker-compose pull -q
docker-compose up --no-start
docker-compose start postgresql redis
docker-compose run -u root server test-all
docker compose pull -q
docker compose up --no-start
docker compose start postgresql redis
docker compose run -u root server test-all
sentry-release:
needs:
- build-server
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/release-tag.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ jobs:
docker build -t testing:latest .
echo "AUTHENTIK_IMAGE=testing" >> .env
echo "AUTHENTIK_TAG=latest" >> .env
docker-compose up --no-start
docker-compose start postgresql redis
docker-compose run -u root server test-all
docker compose up --no-start
docker compose start postgresql redis
docker compose run -u root server test-all
- id: generate_token
uses: tibdex/github-app-token@v2
with:
Expand Down
8 changes: 4 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,10 @@ test-go:
test-docker: ## Run all tests in a docker-compose
echo "PG_PASS=$(openssl rand -base64 32)" >> .env
echo "AUTHENTIK_SECRET_KEY=$(openssl rand -base64 32)" >> .env
docker-compose pull -q
docker-compose up --no-start
docker-compose start postgresql redis
docker-compose run -u root server test-all
docker compose pull -q
docker compose up --no-start
docker compose start postgresql redis
docker compose run -u root server test-all
rm -f .env

test: ## Run the server tests and produce a coverage report (locally)
Expand Down
7 changes: 6 additions & 1 deletion authentik/blueprints/apps.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
from django.db import DatabaseError, InternalError, ProgrammingError
from structlog.stdlib import BoundLogger, get_logger

from authentik.root.signals import startup


class ManagedAppConfig(AppConfig):
"""Basic reconciliation logic for apps"""
Expand All @@ -23,9 +25,12 @@ def __init__(self, app_name: str, *args, **kwargs) -> None:

def ready(self) -> None:
self.import_related()
startup.connect(self._on_startup_callback, dispatch_uid=self.label)
return super().ready()

def _on_startup_callback(self, sender, **_):
self._reconcile_global()
self._reconcile_tenant()
return super().ready()

def import_related(self):
"""Automatically import related modules which rely on just being imported
Expand Down
2 changes: 1 addition & 1 deletion authentik/blueprints/tests/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ def wrapper_outer(func: Callable):
def wrapper(*args, **kwargs):
config = apps.get_app_config(app_name)
if isinstance(config, ManagedAppConfig):
config.ready()
config._on_startup_callback(None)
return func(*args, **kwargs)

return wrapper
Expand Down
28 changes: 26 additions & 2 deletions authentik/core/management/commands/dev_server.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,34 @@
"""custom runserver command"""

from typing import TextIO

from daphne.management.commands.runserver import Command as RunServer
from daphne.server import Server

from authentik.root.signals import post_startup, pre_startup, startup


class SignalServer(Server):
"""Server which signals back to authentik when it finished starting up"""

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)

def ready_callable():
pre_startup.send(sender=self)
startup.send(sender=self)
post_startup.send(sender=self)

self.ready_callable = ready_callable


class Command(RunServer):
"""custom runserver command, which doesn't show the misleading django startup message"""

def on_bind(self, server_port):
pass
server_cls = SignalServer

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# Redirect standard stdout banner from Daphne into the void
# as there are a couple more steps that happen before startup is fully done
self.stdout = TextIO()
5 changes: 2 additions & 3 deletions authentik/flows/apps.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,9 @@ class AuthentikFlowsConfig(ManagedAppConfig):
verbose_name = "authentik Flows"
default = True

@ManagedAppConfig.reconcile_global
def load_stages(self):
"""Ensure all stages are loaded"""
def import_related(self):
from authentik.flows.models import Stage

for stage in all_subclasses(Stage):
_ = stage().view
return super().import_related()
6 changes: 4 additions & 2 deletions authentik/lib/utils/reflection.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@
import os
from importlib import import_module
from pathlib import Path
from tempfile import gettempdir

from django.conf import settings
from kubernetes.config.incluster_config import SERVICE_HOST_ENV_NAME

from authentik.lib.config import CONFIG

SERVICE_HOST_ENV_NAME = "KUBERNETES_SERVICE_HOST"


def all_subclasses(cls, sort=True):
"""Recursively return all subclassess of cls"""
Expand Down Expand Up @@ -55,7 +57,7 @@ def get_env() -> str:
return "dev"
if SERVICE_HOST_ENV_NAME in os.environ:
return "kubernetes"
if Path("/tmp/authentik-mode").exists(): # nosec
if (Path(gettempdir()) / "authentik-mode").exists():
return "compose"
if "AK_APPLIANCE" in os.environ:
return os.environ["AK_APPLIANCE"]
Expand Down
4 changes: 2 additions & 2 deletions authentik/outposts/apps.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,14 @@ def embedded_outpost(self):
outpost.managed = MANAGED_OUTPOST
outpost.save()
return
outpost, updated = Outpost.objects.update_or_create(
outpost, created = Outpost.objects.update_or_create(
defaults={
"type": OutpostType.PROXY,
"name": MANAGED_OUTPOST_NAME,
},
managed=MANAGED_OUTPOST,
)
if updated:
if created:
if KubernetesServiceConnection.objects.exists():
outpost.service_connection = KubernetesServiceConnection.objects.first()
elif DockerServiceConnection.objects.exists():
Expand Down
2 changes: 1 addition & 1 deletion authentik/providers/oauth2/views/device_init.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ def validate_code(self, code: int) -> HttpResponse | None:
"""Validate code and save the returned http response"""
response = validate_code(code, self.stage.request)
if not response:
raise ValidationError("Invalid code", "invalid")
raise ValidationError(_("Invalid code"), "invalid")
return response


Expand Down
13 changes: 12 additions & 1 deletion authentik/root/asgi.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,18 @@ async def __call__(self, scope, receive, send):
raise exc


application = SentryAsgiMiddleware(
class AuthentikAsgi(SentryAsgiMiddleware):
"""Root ASGI App wrapper"""

def call_startup(self):
from authentik.root.signals import post_startup, pre_startup, startup

pre_startup.send(sender=self)
startup.send(sender=self)
post_startup.send(sender=self)


application = AuthentikAsgi(
ProtocolTypeRouter(
{
"http": get_asgi_application(),
Expand Down
26 changes: 26 additions & 0 deletions authentik/root/signals.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
from datetime import timedelta

from django.core.signals import Signal
from django.dispatch import receiver
from django.utils.timezone import now
from structlog.stdlib import get_logger

# Signal dispatched before actual startup trigger
pre_startup = Signal()
# Signal dispatched which should trigger all startup logic
startup = Signal()
# Signal dispatched after the startup logic
post_startup = Signal()

LOGGER = get_logger()


@receiver(pre_startup)
def pre_startup_log(sender, **_):
sender._start_time = now()


@receiver(post_startup)
def post_startup_log(sender, **_):
took: timedelta = now() - sender._start_time
LOGGER.info("authentik Core Worker finished starting", took_s=took.total_seconds())
5 changes: 5 additions & 0 deletions authentik/root/test_runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

from authentik.lib.config import CONFIG
from authentik.lib.sentry import sentry_init
from authentik.root.signals import post_startup, pre_startup, startup
from tests.e2e.utils import get_docker_tag

# globally set maxDiff to none to show full assert error
Expand Down Expand Up @@ -46,6 +47,10 @@ def __init__(self, **kwargs):
CONFIG.set("error_reporting.send_pii", True)
sentry_init()

pre_startup.send(sender=self, mode="test")
startup.send(sender=self, mode="test")
post_startup.send(sender=self, mode="test")

@classmethod
def add_arguments(cls, parser: ArgumentParser):
"""Add more pytest-specific arguments"""
Expand Down
5 changes: 2 additions & 3 deletions authentik/sources/oauth/apps.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,10 @@ class AuthentikSourceOAuthConfig(ManagedAppConfig):
mountpoint = "source/oauth/"
default = True

@ManagedAppConfig.reconcile_global
def load_source_types(self):
"""Load source_types from config file"""
def import_related(self):
for source_type in AUTHENTIK_SOURCES_OAUTH_TYPES:
try:
self.import_module(source_type)
except ImportError as exc:
LOGGER.warning("Failed to load OAuth Source", exc=exc)
return super().import_related()
7 changes: 2 additions & 5 deletions internal/gounicorn/gounicorn.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,18 +96,15 @@ func (g *GoUnicorn) healthcheck() {
g.log.Debug("starting healthcheck")
// Default healthcheck is every 1 second on startup
// once we've been healthy once, increase to 30 seconds
for range time.Tick(time.Second) {
for range time.NewTicker(time.Second).C {
if g.Healthcheck() {
g.alive = true
g.log.Info("backend is alive, backing off with healthchecks")
g.log.Debug("backend is alive, backing off with healthchecks")
g.HealthyCallback()
break
}
g.log.Debug("backend not alive yet")
}
for range time.Tick(30 * time.Second) {
g.Healthcheck()
}
}

func (g *GoUnicorn) Reload() {
Expand Down
3 changes: 0 additions & 3 deletions internal/web/proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,6 @@ func (ws *WebServer) configureProxy() {
}
rp.ErrorHandler = ws.proxyErrorHandler
rp.ModifyResponse = ws.proxyModifyResponse
ws.m.Path("/-/health/live/").HandlerFunc(sentry.SentryNoSample(func(rw http.ResponseWriter, r *http.Request) {
rw.WriteHeader(204)
}))
ws.m.PathPrefix("/").HandlerFunc(sentry.SentryNoSample(func(rw http.ResponseWriter, r *http.Request) {
if !ws.g.IsRunning() {
ws.proxyErrorHandler(rw, r, errors.New("authentik starting"))
Expand Down
3 changes: 0 additions & 3 deletions lifecycle/ak
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ function log {

function wait_for_db {
python -m lifecycle.wait_for_db
python -m lifecycle.migrate
log "Bootstrap completed"
}

Expand Down Expand Up @@ -65,7 +64,6 @@ if [[ "${AUTHENTIK_REMOTE_DEBUG}" == "true" ]]; then
fi

if [[ "$1" == "server" ]]; then
wait_for_db
set_mode "server"
# If we have bootstrap credentials set, run bootstrap tasks outside of main server
# sync, so that we can sure the first start actually has working bootstrap
Expand All @@ -75,7 +73,6 @@ if [[ "$1" == "server" ]]; then
fi
run_authentik
elif [[ "$1" == "worker" ]]; then
wait_for_db
set_mode "worker"
check_if_root "python -m manage worker"
elif [[ "$1" == "worker-status" ]]; then
Expand Down
Loading

0 comments on commit 66cefcc

Please sign in to comment.