Add explict allow deny commands.
This commit is contained in:
Executable
+133
@@ -0,0 +1,133 @@
|
||||
#!/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"
|
||||
Reference in New Issue
Block a user