134 lines
6.5 KiB
Bash
Executable File
134 lines
6.5 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Exercises the allow/deny list helpers and the google-auth:allow / :unallow /
|
|
# :deny / :undeny subcommands against a fake dokku layout, and checks that the
|
|
# lists reach the env file the auth service reads.
|
|
set -eo pipefail
|
|
|
|
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
WORK="$(mktemp -d)"
|
|
trap 'rm -rf "$WORK"' EXIT
|
|
|
|
# Fake dokku host layout.
|
|
export DOKKU_ROOT="$WORK/dokku-root"
|
|
export DOKKU_LIB_ROOT="$WORK/dokku-lib"
|
|
export PLUGIN_CORE_AVAILABLE_PATH="$WORK/nonexistent" # force built-in fallbacks
|
|
GLOBAL="$DOKKU_LIB_ROOT/data/google-auth/global"
|
|
mkdir -p "$GLOBAL"
|
|
|
|
# Stub docker so the subcommands see the service as not running and never touch
|
|
# a real container. This test is about list handling, not container management.
|
|
mkdir -p "$WORK/bin"
|
|
printf '#!/bin/sh\nexit 1\n' >"$WORK/bin/docker"
|
|
chmod +x "$WORK/bin/docker"
|
|
export PATH="$WORK/bin:$PATH"
|
|
|
|
# shellcheck disable=SC1091
|
|
source "$ROOT/functions"
|
|
|
|
fail() {
|
|
echo "FAIL: $*" 1>&2
|
|
exit 1
|
|
}
|
|
|
|
ga() {
|
|
local sub="$1"
|
|
shift
|
|
"$ROOT/subcommands/$sub" "google-auth:$sub" "$@"
|
|
}
|
|
|
|
# expect_output <needle> <subcommand> [args...] — asserts the subcommand's
|
|
# output (stdout + stderr) contains <needle>. Collects the output first rather
|
|
# than piping into grep, which would SIGPIPE the writer under pipefail.
|
|
expect_output() {
|
|
local needle="$1" out
|
|
shift
|
|
out="$(ga "$@" 2>&1 || true)"
|
|
grep -qF "$needle" <<<"$out" || fail "expected '$needle' in google-auth:$1 output, got: $out"
|
|
}
|
|
|
|
# --- entry validation and classification ---
|
|
fn-ga-validate-list-entry "guest@partner.com" || fail "address should be a valid entry"
|
|
fn-ga-validate-list-entry "signal.org" || fail "domain should be a valid entry"
|
|
fn-ga-validate-list-entry "a@b.com,c@d.com" && fail "comma should be rejected (it splits the env var)"
|
|
fn-ga-validate-list-entry "not a domain" && fail "whitespace should be rejected"
|
|
fn-ga-validate-list-entry "" && fail "empty entry should be rejected"
|
|
[[ "$(fn-ga-allow-entry-kind "signal.org")" == "domain" ]] || fail "bare domain misclassified"
|
|
[[ "$(fn-ga-allow-entry-kind "@signal.org")" == "domain" ]] || fail "@domain misclassified"
|
|
[[ "$(fn-ga-allow-entry-kind "guest@partner.com")" == "email" ]] || fail "address misclassified"
|
|
echo "ok: entry validation and classification"
|
|
|
|
# --- list helpers ---
|
|
fn-ga-global-list-add allowed-emails "a@x.com"
|
|
fn-ga-global-list-add allowed-emails "a@x.com" # idempotent
|
|
[[ "$(fn-ga-global-list-count allowed-emails)" -eq 1 ]] || fail "duplicate add should be a no-op"
|
|
fn-ga-global-list-contains allowed-emails "a@x.com" || fail "contains should find the entry"
|
|
fn-ga-global-list-contains allowed-emails "a@x.co" && fail "contains should match whole lines only"
|
|
fn-ga-global-list-remove allowed-emails "a@x.com"
|
|
[[ "$(fn-ga-global-list-count allowed-emails)" -eq 0 ]] || fail "remove should empty the list"
|
|
fn-ga-global-list-remove allowed-emails "nope@x.com" # missing entry is not an error
|
|
echo "ok: list helpers"
|
|
|
|
# --- allow ---
|
|
ga allow >/dev/null || fail "listing an empty allow list should succeed"
|
|
ga allow Signal.org @Example.com Guest@Partner.com >/dev/null
|
|
grep -qx "signal.org" "$GLOBAL/allowed-domains" || fail "bare domain should be stored lowercased"
|
|
grep -qx "example.com" "$GLOBAL/allowed-domains" || fail "@domain should be stored without the @"
|
|
grep -qx "guest@partner.com" "$GLOBAL/allowed-emails" || fail "address should be stored lowercased"
|
|
ga allow "a@b.com,c@d.com" 2>/dev/null && fail "allow should reject an entry with a comma"
|
|
ga allow "localhost" 2>/dev/null && fail "allow should reject a domain with no dot"
|
|
[[ "$(fn-ga-global-list-count allowed-domains)" -eq 2 ]] || fail "rejected entries should not be stored"
|
|
echo "ok: allow"
|
|
|
|
# --- deny wins, and contradictions are surfaced ---
|
|
ga deny Former@Signal.org >/dev/null
|
|
grep -qx "former@signal.org" "$GLOBAL/denied-emails" || fail "deny should store the address lowercased"
|
|
ga deny signal.org 2>/dev/null && fail "deny should reject a bare domain"
|
|
ga deny guest@partner.com >/dev/null
|
|
# guest@partner.com is on both lists now; allow must say deny wins.
|
|
expect_output "deny list" allow guest@partner.com
|
|
echo "ok: deny"
|
|
|
|
# --- undeny ---
|
|
ga undeny Guest@Partner.com >/dev/null
|
|
fn-ga-global-list-contains denied-emails "guest@partner.com" && fail "undeny should remove the address"
|
|
expect_output "was not on the deny list" undeny never@denied.com
|
|
ga deny stranger@elsewhere.com >/dev/null
|
|
expect_output "still cannot sign in" undeny stranger@elsewhere.com
|
|
echo "ok: undeny"
|
|
|
|
# --- unallow, including the lockout guardrail ---
|
|
ga unallow @Example.com >/dev/null
|
|
fn-ga-global-list-contains allowed-domains "example.com" && fail "unallow should remove the domain"
|
|
expect_output "was not on the allow list" unallow absent@nowhere.com
|
|
|
|
# signal.org + guest@partner.com remain; removing both (with a duplicate to
|
|
# check de-duplication) must be refused, and must not change anything.
|
|
before="$(cat "$GLOBAL/allowed-domains" "$GLOBAL/allowed-emails")"
|
|
ga unallow signal.org guest@partner.com SIGNAL.ORG 2>/dev/null &&
|
|
fail "unallow should refuse to empty the allow list"
|
|
[[ "$(cat "$GLOBAL/allowed-domains" "$GLOBAL/allowed-emails")" == "$before" ]] ||
|
|
fail "a refused unallow must leave the lists untouched"
|
|
ga unallow guest@partner.com >/dev/null || fail "unallow should still remove a non-final entry"
|
|
[[ "$(fn-ga-global-list-count allowed-domains)" -eq 1 ]] || fail "signal.org should remain allowed"
|
|
echo "ok: unallow and lockout guardrail"
|
|
|
|
# --- configure's replace-the-list flags stay consistent with the above ---
|
|
"$ROOT/subcommands/configure" google-auth:configure \
|
|
--allow-domain signal.org --deny-email one@signal.org --deny-email two@signal.org >/dev/null 2>&1 || true
|
|
[[ "$(fn-ga-global-list-count denied-emails)" -eq 2 ]] || fail "--deny-email should replace the deny list"
|
|
"$ROOT/subcommands/configure" google-auth:configure --clear-deny-emails >/dev/null 2>&1 || true
|
|
[[ "$(fn-ga-global-list-count denied-emails)" -eq 0 ]] || fail "--clear-deny-emails should empty the deny list"
|
|
echo "ok: configure flags"
|
|
|
|
# --- the lists reach the service env file ---
|
|
ga deny former@signal.org >/dev/null
|
|
ga allow guest@partner.com >/dev/null
|
|
fn-ga-write-env-file
|
|
ENV_FILE="$DOKKU_LIB_ROOT/data/google-auth/service.env"
|
|
grep -qx "GOOGLE_AUTH_ALLOWED_DOMAINS=signal.org" "$ENV_FILE" || fail "env file missing allowed domains"
|
|
grep -qx "GOOGLE_AUTH_ALLOWED_EMAILS=guest@partner.com" "$ENV_FILE" || fail "env file missing allowed emails"
|
|
grep -qx "GOOGLE_AUTH_DENIED_EMAILS=former@signal.org" "$ENV_FILE" || fail "env file missing denied emails"
|
|
echo "ok: service env file"
|
|
|
|
echo "ALL ACCESS LIST TESTS PASSED"
|