Fix letsencrypt auto-renew.

This commit is contained in:
Greyson Parrelli committed 2026-10-13 15:03:24 -04:00
1 parent 3406c622c5
commit 54b640aef0
7 files changed
+102 -18

No files matched your search

+14 -7
View File
@@ -284,7 +284,8 @@ dokku google-auth:allow my-app alice@signal.org # …or just on one app
dokku google-auth:deny --global former@signal.org # cut someone off
dokku google-auth:disable my-app # turn SSO off for an app
dokku google-auth:logs -t # follow auth service logs (sign-ins, denials)
dokku google-auth:restart # restart the auth service
dokku google-auth:restart # restart the auth service (rebuilds if the source moved)
dokku google-auth:rebuild # force a rebuild when the source looks unchanged
```
Users can check who they're signed in as at `https://<any-app>/_google-auth/`
@@ -315,12 +316,18 @@ and sign out at `https://<any-app>/_google-auth/logout`.
- **Plugin updates:** `sudo dokku plugin:update google-auth` rebuilds the
service image and recreates the container with freshly written settings.
Editing the plugin directory in place works too: the image is tagged with a
fingerprint of its source, so `google-auth:restart` (and anything else that
starts the service) rebuilds when the Go code has moved rather than reusing
the binary that happens to be tagged. This matters because the shell half of
the plugin takes effect the moment the files change while the binary does
not, and a container running an older build accepts the mount, accepts
`GOOGLE_AUTH_APP_CONFIG_DIR`, and ignores both.
fingerprint of `Dockerfile`, `go.mod`, `cmd/`, and `internal/`, so
`google-auth:restart` (and anything else that starts the service) rebuilds
when the Go code has moved rather than reusing the binary that happens to be
tagged. This matters because the shell half of the plugin takes effect the
moment the files change while the binary does not, and a container running an
older build accepts the mount, accepts `GOOGLE_AUTH_APP_CONFIG_DIR`, and
ignores both.
That fingerprint covers this plugin's own source and nothing else, so when
the inputs it cannot see change — a patched `golang:1.24-alpine`, a build that
died halfway — force the rebuild: `dokku google-auth:rebuild`, or
`dokku google-auth:rebuild --no-cache` to also discard the layer cache and
re-pull the base images.
`dokku google-auth:report` names the running service's state — it asks the
service itself rather than trusting Docker's metadata — and if it ever says
it is ignoring per-app lists, `dokku google-auth:restart` recreates it.
+2 -1
View File
@@ -18,7 +18,8 @@ case "$1" in
google-auth:report [app], Show global and per-app google-auth status
google-auth:start, Start the shared auth service container
google-auth:stop, Stop the shared auth service container
google-auth:restart, Restart the shared auth service container (picks up config changes)
google-auth:restart, Restart the shared auth service container (rebuilds the image if the plugin source changed)
google-auth:rebuild [--no-cache], Force a rebuild of the service image even if the source looks unchanged
google-auth:logs [--tail|-t], Show logs from the shared auth service container
help_content
}
+12 -4
View File
@@ -637,11 +637,19 @@ fn-ga-image-current() {
}
fn-ga-build-image() {
declare NO_CACHE="${1:-false}"
command -v docker >/dev/null 2>&1 || dokku_log_fail "docker is required to build the google-auth service image"
local args=(image build)
if [[ "$NO_CACHE" == "true" ]]; then
# --pull too: the source hash cannot see the base images, so a rebuild that
# keeps a cached golang:1.24-alpine is not actually a fresh build.
args+=(--no-cache --pull)
dokku_log_info1 "Building $GOOGLE_AUTH_IMAGE from scratch (ignoring the layer cache, re-pulling base images)"
else
dokku_log_info1 "Building $GOOGLE_AUTH_IMAGE (first build downloads the Go toolchain image; this can take a few minutes)"
docker image build \
--label "google-auth.source-hash=$(fn-ga-source-hash)" \
-t "$GOOGLE_AUTH_IMAGE" "$GOOGLE_AUTH_PLUGIN_DIR"
fi
args+=(--label "google-auth.source-hash=$(fn-ga-source-hash)" -t "$GOOGLE_AUTH_IMAGE" "$GOOGLE_AUTH_PLUGIN_DIR")
docker "${args[@]}"
}
fn-ga-service-running() {
@@ -739,7 +747,7 @@ fn-ga-service-start() {
# Starting the service is how an operator expects to pick up an upgraded
# plugin, and reusing the old binary there is what makes a new feature look
# broken rather than absent.
fn-ga-image-current || fn-ga-build-image
fn-ga-image-current || fn-ga-build-image false
fn-ga-write-env-file
local port
port="$(fn-ga-global-get port "$GOOGLE_AUTH_DEFAULT_PORT")"
+8 -4
View File
@@ -9,9 +9,15 @@ DATA_ROOT="$DOKKU_LIB_ROOT/data/google-auth"
mkdir -p "$DATA_ROOT/global" "$DATA_ROOT/apps"
# shellcheck disable=SC1091
source "$PLUGIN_DIR/functions"
if command -v docker >/dev/null 2>&1; then
echo "-----> Building dokku-google-auth service image (first build can take a few minutes)"
docker image build -t dokku-google-auth:latest "$PLUGIN_DIR"
# Build through fn-ga-build-image rather than calling docker directly, so the
# image carries the source-hash label. An unlabelled image reads as stale
# forever: every service start would rebuild it, and the report would claim
# the binary is older than the plugin right after an upgrade installed it.
fn-ga-build-image false
# Pick up the new image if the service is already running. This goes through
# fn-ga-service-start rather than its own `docker run` so an upgrade always
# rewrites service.env first: recreating the container from the file an older
@@ -20,8 +26,6 @@ if command -v docker >/dev/null 2>&1; then
# access list and fall back to the global one.
if [[ "$(docker container inspect -f '{{.State.Running}}' dokku-google-auth 2>/dev/null)" == "true" ]]; then
echo "-----> Restarting google-auth service with the new image"
# shellcheck disable=SC1091
source "$PLUGIN_DIR/functions"
if fn-ga-configured; then
fn-ga-service-start
else
+4 -2
View File
@@ -39,8 +39,10 @@ description = "Check the help output shapes and that every subcommand is documen
run = "test/help-test.sh"
[tasks.docker-build]
description = "Build the auth service docker image"
run = "docker build -t dokku-google-auth:latest ."
description = "Build the auth service docker image, labelled the way the plugin does"
# Via fn-ga-build-image so the image carries its source-hash label. A build
# without it reads as permanently stale to the plugin.
run = "bash -c 'source ./functions && fn-ga-build-image'"
[tasks.check]
description = "Run everything CI would run"
+34
View File
@@ -0,0 +1,34 @@
#!/usr/bin/env bash
set -eo pipefail
[[ $DOKKU_TRACE ]] && set -x
source "$(dirname "$(dirname "${BASH_SOURCE[0]}")")/functions"
cmd-google-auth-rebuild() {
declare desc="rebuild the auth service image from the plugin source and restart"
local cmd="google-auth:rebuild"
[[ "$1" == "$cmd" ]] && shift 1
# Starting the service already rebuilds when the Go source has moved, so this
# exists for the case that check cannot see: the source is unchanged but the
# build inputs are not — a patched base image, a half-written image, a build
# that failed partway.
local no_cache=false
while [[ $# -gt 0 ]]; do
case "$1" in
--no-cache) no_cache=true ;;
*) dokku_log_fail "usage: dokku $cmd [--no-cache]" ;;
esac
shift
done
fn-ga-build-image "$no_cache"
if fn-ga-service-running; then
# The image is current now, so this recreates the container without
# building a second time.
fn-ga-service-start
else
dokku_log_verbose "auth service is not running; the new image is used when it starts"
fi
}
cmd-google-auth-rebuild "$@"
+28
View File
@@ -238,6 +238,7 @@ cat >"$WORK/bin-docker/docker" <<'EOF'
case "$1 $2" in
"container inspect") cat "$DOCKER_INSPECT_FIXTURE" ;;
"image inspect") printf '%s\n' "$DOCKER_IMAGE_FIXTURE" ;;
"image build") printf '%s\n' "$*" >"$DOCKER_ARGS_FIXTURE" ;;
esac
exit 0
EOF
@@ -308,6 +309,33 @@ image_current "$SOURCE_HASH" || fail "an image labelled with the current source
image_current "0000000000000000" && fail "an image built from other source is not current"
image_current "<no value>" && fail "an unlabelled image (built before this check) is not current"
image_current "" && fail "an image with no label value is not current"
# Every build must apply the label, or the image it produces is stale on
# arrival — the plugin would rebuild on every start and the report would call a
# freshly installed binary out of date.
# shellcheck disable=SC2030,SC2031 # the subshell is what keeps the stubs local
build_args() (
export DOCKER_ARGS_FIXTURE="$WORK/build-args"
PATH="$WORK/bin-docker:$PATH"
fn-ga-build-image "$1" >/dev/null
cat "$DOCKER_ARGS_FIXTURE"
)
DEFAULT_BUILD="$(build_args false)"
grep -q -- "--label google-auth.source-hash=$SOURCE_HASH" <<<"$DEFAULT_BUILD" ||
fail "a build must label the image with the source hash, got: $DEFAULT_BUILD"
grep -q -- "-t dokku-google-auth:latest" <<<"$DEFAULT_BUILD" ||
fail "a build must tag the service image, got: $DEFAULT_BUILD"
grep -q -- "--no-cache" <<<"$DEFAULT_BUILD" &&
fail "an ordinary build should use the layer cache"
FORCED_BUILD="$(build_args true)"
grep -q -- "--no-cache" <<<"$FORCED_BUILD" || fail "a forced build should ignore the layer cache"
# The source hash covers this plugin's files, not the images the Dockerfile
# pulls, so a forced build that reuses a cached base image is not a fresh one.
grep -q -- "--pull" <<<"$FORCED_BUILD" || fail "a forced build should re-pull the base images"
grep -q -- "--label google-auth.source-hash=$SOURCE_HASH" <<<"$FORCED_BUILD" ||
fail "a forced build must still label the image, got: $FORCED_BUILD"
echo "ok: service image tracks the plugin source"
# --- lifecycle triggers carry per-app lists ---