OpenSpace/openspace/cloud/cli/auth.py
2026-06-02 16:28:29 +08:00

128 lines
4.7 KiB
Python

#!/usr/bin/env python3
"""Run OpenSpace cloud auth and agent-key provisioning flows."""
from __future__ import annotations
import argparse
from dataclasses import replace
import getpass
import json
import sys
from openspace.cloud.auth_flow import cloud_auth_flow
from openspace.cloud.config import load_cloud_config, normalize_cloud_base_url
from openspace.cloud.redaction import redact_cloud_secret
def _password(value: str | None) -> str:
return value if value is not None else getpass.getpass("Password: ")
def _print_json(value: object) -> None:
print(json.dumps(value, indent=2, ensure_ascii=False))
def main() -> None:
parser = argparse.ArgumentParser(
prog="openspace-cloud-auth",
description="Register users and provision OpenSpace cloud agent API keys.",
)
parser.add_argument("--cloud-base-url", default=None, help="OpenSpace cloud service root URL")
parser.add_argument("--credentials-path", default=None, help="Local env file for OPENSPACE_CLOUD_*")
sub = parser.add_subparsers(dest="command", required=True)
register = sub.add_parser("register-user", help="Register or reuse an owner user")
register.add_argument("--email", required=True)
register.add_argument("--password", default=None)
register.add_argument("--name", default=None)
login = sub.add_parser("login-user", help="Verify user credentials without printing bearer tokens")
login.add_argument("--email", required=True)
login.add_argument("--password", default=None)
bootstrap = sub.add_parser(
"bootstrap-agent-key",
help="Create or recover an owner-scoped agent key and store it locally",
)
bootstrap.add_argument("--email", required=True)
bootstrap.add_argument("--password", default=None)
bootstrap.add_argument("--name", default=None)
bootstrap.add_argument("--agent-name", required=True)
bootstrap.add_argument("--no-persist", action="store_true")
list_agents = sub.add_parser("list-agents", help="List agents owned by a user")
list_agents.add_argument("--email", required=True)
list_agents.add_argument("--password", default=None)
rotate = sub.add_parser("rotate-agent-key", help="Rotate an owned agent key and store it locally")
rotate.add_argument("--email", required=True)
rotate.add_argument("--password", default=None)
rotate.add_argument("--agent-id", required=True)
rotate.add_argument("--no-persist", action="store_true")
sub.add_parser("verify-agent-key", help="Verify the current stored OPENSPACE_CLOUD_API_KEY")
args = parser.parse_args()
try:
config = load_cloud_config()
if args.cloud_base_url:
config = replace(config, base_url=normalize_cloud_base_url(args.cloud_base_url))
common = {
"config": config,
"credentials_path": args.credentials_path,
}
if args.command == "register-user":
result = cloud_auth_flow(
action="register_user",
email=args.email,
password=_password(args.password),
name=args.name,
**common,
)
elif args.command == "login-user":
result = cloud_auth_flow(
action="login_user",
email=args.email,
password=_password(args.password),
**common,
)
elif args.command == "bootstrap-agent-key":
result = cloud_auth_flow(
action="bootstrap_agent_key",
email=args.email,
password=_password(args.password),
name=args.name,
agent_name=args.agent_name,
persist=not args.no_persist,
**common,
)
elif args.command == "list-agents":
result = cloud_auth_flow(
action="list_agents",
email=args.email,
password=_password(args.password),
**common,
)
elif args.command == "rotate-agent-key":
result = cloud_auth_flow(
action="rotate_agent_key",
email=args.email,
password=_password(args.password),
agent_id=args.agent_id,
persist=not args.no_persist,
**common,
)
elif args.command == "verify-agent-key":
result = cloud_auth_flow(action="verify_agent_key", **common)
else:
parser.error("unknown command")
return
_print_json(result)
except Exception as exc:
print(f"ERROR: {redact_cloud_secret(str(exc))}", file=sys.stderr)
sys.exit(1)
if __name__ == "__main__":
main()