Seed with the token production is actually reachable with
secrets/amber.env holds PB_ADMIN_TOKEN and no superuser password, so the email/password-only seeder could not be pointed at the live instance without inventing a credential to satisfy it. The token is also verified up front against a superuser-only endpoint, because listing records cannot answer whether it is valid: PocketBase applies a listRule as a FILTER, so a stale token returns 200 with zero rows, indistinguishable from an empty collection. The seeder then decided all four providers were missing and the first visible error was "[FAIL] prehrajto: HTTP 403 Only superusers can perform this action", blaming the row instead of the token. Found by trying it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
57585d8ad2
commit
9dd677b442
1 changed files with 33 additions and 7 deletions
|
|
@ -14,13 +14,21 @@ Without `--force` an existing row is left alone and reported as `kept`, which
|
||||||
makes this safe to run after any deploy — the collection gets populated on a
|
makes this safe to run after any deploy — the collection gets populated on a
|
||||||
fresh instance and untouched on one that is already looked after.
|
fresh instance and untouched on one that is already looked after.
|
||||||
|
|
||||||
Never reads secrets/amber.env: the superuser credentials come from the
|
Authenticates one of two ways, in this order:
|
||||||
environment or from the local defaults, the same way scripts/verify.py takes
|
|
||||||
them, so nothing here needs access to the family's credential file.
|
PB_ADMIN_TOKEN an existing superuser token, used as-is
|
||||||
|
PB_ADMIN_EMAIL/PB_ADMIN_PASS a superuser sign-in (local default below)
|
||||||
|
|
||||||
|
The token path exists because that is what the production instance is reachable
|
||||||
|
with: `secrets/amber.env` holds `PB_ADMIN_TOKEN` and no superuser password, and
|
||||||
|
inventing one to satisfy this script would be the wrong way round. Never reads that
|
||||||
|
file itself, so nothing here needs access to the family's credentials, and never
|
||||||
|
prints the token.
|
||||||
"""
|
"""
|
||||||
import json, os, pathlib, sys, urllib.error, urllib.request
|
import json, os, pathlib, sys, urllib.error, urllib.request
|
||||||
|
|
||||||
BASE = os.environ.get("PB_BASE", "http://localhost:8090").rstrip("/")
|
BASE = os.environ.get("PB_BASE", "http://localhost:8090").rstrip("/")
|
||||||
|
ADMIN_TOKEN = os.environ.get("PB_ADMIN_TOKEN", "").strip()
|
||||||
ADMIN_EMAIL = os.environ.get("PB_ADMIN_EMAIL", "admin@myanime.local")
|
ADMIN_EMAIL = os.environ.get("PB_ADMIN_EMAIL", "admin@myanime.local")
|
||||||
ADMIN_PASS = os.environ.get("PB_ADMIN_PASS", "Sup3rSecret!123")
|
ADMIN_PASS = os.environ.get("PB_ADMIN_PASS", "Sup3rSecret!123")
|
||||||
FORCE = "--force" in sys.argv
|
FORCE = "--force" in sys.argv
|
||||||
|
|
@ -53,12 +61,30 @@ def main():
|
||||||
if unknown:
|
if unknown:
|
||||||
sys.exit(f"unknown slug(s) {sorted(unknown)} — the page has no wiring for these")
|
sys.exit(f"unknown slug(s) {sorted(unknown)} — the page has no wiring for these")
|
||||||
|
|
||||||
|
if ADMIN_TOKEN:
|
||||||
|
token = ADMIN_TOKEN
|
||||||
|
else:
|
||||||
st, auth = req("POST", "/api/collections/_superusers/auth-with-password",
|
st, auth = req("POST", "/api/collections/_superusers/auth-with-password",
|
||||||
body={"identity": ADMIN_EMAIL, "password": ADMIN_PASS})
|
body={"identity": ADMIN_EMAIL, "password": ADMIN_PASS})
|
||||||
if st != 200:
|
if st != 200:
|
||||||
sys.exit(f"superuser auth failed against {BASE}: HTTP {st} {auth}")
|
sys.exit(f"superuser auth failed against {BASE}: HTTP {st} {auth}")
|
||||||
token = auth["token"]
|
token = auth["token"]
|
||||||
|
|
||||||
|
# Prove the token is really a superuser BEFORE reading anything, against an
|
||||||
|
# endpoint only a superuser may touch.
|
||||||
|
#
|
||||||
|
# Listing records cannot answer this. PocketBase applies a collection's listRule
|
||||||
|
# as a *filter*, so a stale token comes back HTTP 200 with zero rows — identical
|
||||||
|
# to a collection that is simply empty. The seeder then decides every provider is
|
||||||
|
# missing and tries to create all four, and the first thing you see is
|
||||||
|
# "[FAIL] prehrajto: HTTP 403 Only superusers can perform this action", which
|
||||||
|
# points at the row instead of at the token. Measured, not assumed.
|
||||||
|
st, who = req("GET", "/api/collections?perPage=1", token)
|
||||||
|
if st != 200:
|
||||||
|
sys.exit(f"HTTP {st} against {BASE}: this is not a valid superuser token. "
|
||||||
|
"Refresh PB_ADMIN_TOKEN in secrets/amber.env and do not work "
|
||||||
|
"around it.")
|
||||||
|
|
||||||
st, existing = req("GET", "/api/collections/providers/records?perPage=200", token)
|
st, existing = req("GET", "/api/collections/providers/records?perPage=200", token)
|
||||||
if st != 200:
|
if st != 200:
|
||||||
sys.exit(f"cannot list providers (is the migration applied?): HTTP {st} {existing}")
|
sys.exit(f"cannot list providers (is the migration applied?): HTTP {st} {existing}")
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue