scripts/agent_token.py mints the 'agents' guest user + token non-interactively, writes data/agent.env (0600, gitignored, never printed). Fixes _register_outputs dropping user_id — guest job outputs were registered ownerless, so guests could never see or download their own results. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
69 lines
2.5 KiB
Python
69 lines
2.5 KiB
Python
#!/usr/bin/env python
|
|
"""Mint (or re-mint) the shared agent credential, non-interactively.
|
|
|
|
Creates the `agents` guest user if missing (random throwaway password — agents
|
|
authenticate by token, not password), mints a fresh API token for it, and writes
|
|
a ready-to-source env file to data/agent.env (chmod 600, gitignored). The token
|
|
is never printed to stdout.
|
|
|
|
Run from the repo root:
|
|
uv run python scripts/agent_token.py # mint, write data/agent.env
|
|
uv run python scripts/agent_token.py --revoke # delete ALL of agents' old tokens first
|
|
|
|
Agents/macs then use:
|
|
source ~/Documents/MODELBEAST/data/agent.env # sets MB_HOST + MB_TOKEN
|
|
./mb ops
|
|
(from another tailnet mac: scp m3ultra:~/Documents/MODELBEAST/data/agent.env .)
|
|
|
|
The user is a GUEST on purpose: local operators only (flux_local, bg_remove_local,
|
|
trellis_mac, sf3d, ...) — all free; the owner's paid fal/OpenRouter keys are
|
|
blocked server-side. Mint an owner token from the UI if an agent ever truly needs
|
|
a cloud operator.
|
|
"""
|
|
import argparse
|
|
import secrets
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
ROOT = Path(__file__).resolve().parent.parent
|
|
sys.path.insert(0, str(ROOT))
|
|
from server import auth, db # noqa: E402
|
|
|
|
USERNAME = "agents"
|
|
MAX_JOBS = 8 # shared across every agent/mac using this credential
|
|
ENV_PATH = ROOT / "data" / "agent.env"
|
|
|
|
|
|
def main():
|
|
ap = argparse.ArgumentParser()
|
|
ap.add_argument("--revoke", action="store_true",
|
|
help="revoke all existing tokens for the agents user first")
|
|
args = ap.parse_args()
|
|
|
|
con = db.connect()
|
|
user = auth.get_user_by_name(con, USERNAME)
|
|
if user is None:
|
|
user = auth.create_user(con, USERNAME, secrets.token_hex(16),
|
|
role="guest", max_active_jobs=MAX_JOBS)
|
|
print(f"created user '{USERNAME}' (guest, max_jobs={MAX_JOBS})")
|
|
else:
|
|
print(f"user '{USERNAME}' exists ({user['role']})")
|
|
|
|
if args.revoke:
|
|
n = con.execute("DELETE FROM api_tokens WHERE user_id = ?", (user["id"],)).rowcount
|
|
con.commit()
|
|
print(f"revoked {n} old token(s)")
|
|
|
|
raw = auth.create_token(con, user["id"], name="shared-agent-cred")
|
|
ENV_PATH.parent.mkdir(parents=True, exist_ok=True)
|
|
ENV_PATH.write_text(
|
|
"# MODELBEAST shared agent credential — source this file, never commit/paste it\n"
|
|
"export MB_HOST=http://100.89.131.57:8777\n"
|
|
f"export MB_TOKEN={raw}\n")
|
|
ENV_PATH.chmod(0o600)
|
|
print(f"token written to {ENV_PATH} (not shown; source it to use)")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|