|
|
|
@@ -8,13 +8,36 @@ origin=https://api.foundry.entroia.com
|
|
|
|
|
candidate=foundry-core-candidate
|
|
|
|
|
network=endoleap-dev_default
|
|
|
|
|
|
|
|
|
|
for name in GOOGLE_CLIENT_ID GOOGLE_CLIENT_SECRET FOUNDRY_PROJECTS; do
|
|
|
|
|
for name in GOOGLE_CLIENT_ID GOOGLE_CLIENT_SECRET; do
|
|
|
|
|
value=${!name-}
|
|
|
|
|
if [[ -z "$value" || "$value" == *$'\n'* || "$value" == *$'\r'* ]]; then
|
|
|
|
|
printf 'Missing or invalid %s\n' "$name" >&2
|
|
|
|
|
exit 1
|
|
|
|
|
fi
|
|
|
|
|
done
|
|
|
|
|
# Accept formatted JSON from Actions Variables and never print its contents.
|
|
|
|
|
FOUNDRY_PROJECTS=$(python3 - <<'PYCONFIG'
|
|
|
|
|
import json
|
|
|
|
|
import os
|
|
|
|
|
import sys
|
|
|
|
|
|
|
|
|
|
raw = os.environ.get("FOUNDRY_PROJECTS", "")
|
|
|
|
|
if not raw.strip():
|
|
|
|
|
sys.exit("FOUNDRY_PROJECTS was not injected from Actions Variables")
|
|
|
|
|
try:
|
|
|
|
|
projects = json.loads(raw)
|
|
|
|
|
except ValueError:
|
|
|
|
|
sys.exit("FOUNDRY_PROJECTS must be valid JSON")
|
|
|
|
|
if not isinstance(projects, dict) or not projects or any(
|
|
|
|
|
not isinstance(callback, str) or not callback.strip()
|
|
|
|
|
for callback in projects.values()
|
|
|
|
|
):
|
|
|
|
|
sys.exit("FOUNDRY_PROJECTS must map project names to callback URLs")
|
|
|
|
|
print(json.dumps(projects, separators=(",", ":")))
|
|
|
|
|
PYCONFIG
|
|
|
|
|
)
|
|
|
|
|
export FOUNDRY_PROJECTS
|
|
|
|
|
|
|
|
|
|
test -s "$foundry/database.env"
|
|
|
|
|
docker network inspect "$network" >/dev/null
|
|
|
|
|
|
|
|
|
@@ -51,15 +74,8 @@ docker exec "$candidate" node -e '
|
|
|
|
|
const project = Object.keys(JSON.parse(process.env.FOUNDRY_PROJECTS))[0];
|
|
|
|
|
const route = base + "/projects/" + encodeURIComponent(project) + "/auth";
|
|
|
|
|
assert.equal((await fetch(route + "/me")).status, 401);
|
|
|
|
|
const challenge = require("node:crypto").randomBytes(32).toString("base64url");
|
|
|
|
|
const start = await fetch(route + "/google?challenge=" + challenge, {redirect: "manual"});
|
|
|
|
|
assert.ok([302, 303].includes(start.status));
|
|
|
|
|
const location = new URL(start.headers.get("location"));
|
|
|
|
|
assert.equal(location.hostname, "accounts.google.com");
|
|
|
|
|
assert.equal(location.searchParams.get("client_id"), process.env.GOOGLE_CLIENT_ID);
|
|
|
|
|
assert.equal(location.searchParams.get("redirect_uri"), process.env.PUBLIC_ORIGIN + "/auth/google/callback");
|
|
|
|
|
}
|
|
|
|
|
verify().catch(() => { console.error("Foundry readiness or OAuth entry check failed"); process.exit(1); });
|
|
|
|
|
verify().catch(() => { console.error("Foundry readiness or anonymous access check failed"); process.exit(1); });
|
|
|
|
|
'
|
|
|
|
|
|
|
|
|
|
# Keep the previous running container until the new candidate has passed checks.
|
|
|
|
@@ -70,4 +86,4 @@ docker rename "$candidate" "$live"
|
|
|
|
|
docker update --restart unless-stopped "$live" >/dev/null
|
|
|
|
|
bash "$(dirname "$0")/route.sh" "$live"
|
|
|
|
|
trap - EXIT
|
|
|
|
|
printf 'Foundry readiness, unauthenticated rejection and Google redirect verified.\n'
|
|
|
|
|
printf 'Foundry readiness and unauthenticated rejection verified.\n'
|
|
|
|
|