powerbase-cli 0.1.2__tar.gz → 0.1.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {powerbase_cli-0.1.2 → powerbase_cli-0.1.4}/PKG-INFO +21 -20
- {powerbase_cli-0.1.2 → powerbase_cli-0.1.4}/README.md +20 -19
- {powerbase_cli-0.1.2 → powerbase_cli-0.1.4}/pyproject.toml +1 -1
- {powerbase_cli-0.1.2 → powerbase_cli-0.1.4}/src/powerbase_cli/commands/auth.py +46 -41
- {powerbase_cli-0.1.2 → powerbase_cli-0.1.4}/src/powerbase_cli/session.py +3 -2
- {powerbase_cli-0.1.2 → powerbase_cli-0.1.4}/src/powerbase_cli/transport.py +3 -2
- {powerbase_cli-0.1.2 → powerbase_cli-0.1.4}/src/powerbase_cli.egg-info/PKG-INFO +21 -20
- {powerbase_cli-0.1.2 → powerbase_cli-0.1.4}/tests/test_cli_commands.py +14 -14
- {powerbase_cli-0.1.2 → powerbase_cli-0.1.4}/tests/test_cli_help.py +11 -2
- {powerbase_cli-0.1.2 → powerbase_cli-0.1.4}/tests/test_session.py +2 -1
- {powerbase_cli-0.1.2 → powerbase_cli-0.1.4}/tests/test_transport.py +4 -2
- {powerbase_cli-0.1.2 → powerbase_cli-0.1.4}/setup.cfg +0 -0
- {powerbase_cli-0.1.2 → powerbase_cli-0.1.4}/src/powerbase_cli/__init__.py +0 -0
- {powerbase_cli-0.1.2 → powerbase_cli-0.1.4}/src/powerbase_cli/__main__.py +0 -0
- {powerbase_cli-0.1.2 → powerbase_cli-0.1.4}/src/powerbase_cli/api.py +0 -0
- {powerbase_cli-0.1.2 → powerbase_cli-0.1.4}/src/powerbase_cli/certs/powerbase-test-ca.pem +0 -0
- {powerbase_cli-0.1.2 → powerbase_cli-0.1.4}/src/powerbase_cli/cli.py +0 -0
- {powerbase_cli-0.1.2 → powerbase_cli-0.1.4}/src/powerbase_cli/commands/__init__.py +0 -0
- {powerbase_cli-0.1.2 → powerbase_cli-0.1.4}/src/powerbase_cli/commands/agent.py +0 -0
- {powerbase_cli-0.1.2 → powerbase_cli-0.1.4}/src/powerbase_cli/commands/branch.py +0 -0
- {powerbase_cli-0.1.2 → powerbase_cli-0.1.4}/src/powerbase_cli/commands/config_cmd.py +0 -0
- {powerbase_cli-0.1.2 → powerbase_cli-0.1.4}/src/powerbase_cli/commands/context.py +0 -0
- {powerbase_cli-0.1.2 → powerbase_cli-0.1.4}/src/powerbase_cli/commands/database.py +0 -0
- {powerbase_cli-0.1.2 → powerbase_cli-0.1.4}/src/powerbase_cli/commands/instance.py +0 -0
- {powerbase_cli-0.1.2 → powerbase_cli-0.1.4}/src/powerbase_cli/commands/org.py +0 -0
- {powerbase_cli-0.1.2 → powerbase_cli-0.1.4}/src/powerbase_cli/commands/parser.py +0 -0
- {powerbase_cli-0.1.2 → powerbase_cli-0.1.4}/src/powerbase_cli/commands/publish.py +0 -0
- {powerbase_cli-0.1.2 → powerbase_cli-0.1.4}/src/powerbase_cli/commands/sandbox.py +0 -0
- {powerbase_cli-0.1.2 → powerbase_cli-0.1.4}/src/powerbase_cli/commands/shared.py +0 -0
- {powerbase_cli-0.1.2 → powerbase_cli-0.1.4}/src/powerbase_cli/commands/sql.py +0 -0
- {powerbase_cli-0.1.2 → powerbase_cli-0.1.4}/src/powerbase_cli/config.py +0 -0
- {powerbase_cli-0.1.2 → powerbase_cli-0.1.4}/src/powerbase_cli.egg-info/SOURCES.txt +0 -0
- {powerbase_cli-0.1.2 → powerbase_cli-0.1.4}/src/powerbase_cli.egg-info/dependency_links.txt +0 -0
- {powerbase_cli-0.1.2 → powerbase_cli-0.1.4}/src/powerbase_cli.egg-info/entry_points.txt +0 -0
- {powerbase_cli-0.1.2 → powerbase_cli-0.1.4}/src/powerbase_cli.egg-info/top_level.txt +0 -0
- {powerbase_cli-0.1.2 → powerbase_cli-0.1.4}/tests/test_api.py +0 -0
- {powerbase_cli-0.1.2 → powerbase_cli-0.1.4}/tests/test_config.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: powerbase-cli
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.4
|
|
4
4
|
Summary: CLI for operating Powerbase console workflows
|
|
5
5
|
Author: Powerbase
|
|
6
6
|
Requires-Python: >=3.11
|
|
@@ -91,6 +91,7 @@ The preferred flow is:
|
|
|
91
91
|
|
|
92
92
|
```bash
|
|
93
93
|
powerbase auth login
|
|
94
|
+
powerbase auth wait --login-id LOGIN_ID
|
|
94
95
|
```
|
|
95
96
|
|
|
96
97
|
The CLI now includes a built-in `base_url` and `anon_key` default for this deployment. The test package also bundles this environment's self-signed CA certificate, so most users can start with browser login directly and only use flags or environment variables when overriding that default.
|
|
@@ -100,16 +101,14 @@ The bundled CA is a test-only convenience for the current self-signed deployment
|
|
|
100
101
|
This will:
|
|
101
102
|
|
|
102
103
|
1. request a CLI login session from Powerbase
|
|
103
|
-
2.
|
|
104
|
-
3.
|
|
105
|
-
4.
|
|
104
|
+
2. return a `login_id` and browser URL
|
|
105
|
+
3. wait for the user to approve the request in their own browser
|
|
106
|
+
4. poll with `powerbase auth wait --login-id ...` until approval or until `--timeout` elapses (default **600** seconds, ten minutes)
|
|
107
|
+
5. save the resulting session to `~/.config/powerbase/auth.json`
|
|
106
108
|
|
|
107
|
-
Use `--timeout 0` to wait without a time limit. Use a larger value if users need more than ten minutes to complete login.
|
|
108
|
-
For agent-guided workflows,
|
|
109
|
-
If the browser link expires or the user is not currently signed in to the console, rerun `powerbase auth login --
|
|
110
|
-
If an agent or wrapper script is coordinating the workflow, it is still helpful
|
|
111
|
-
to tell the user: after browser approval, return to the current session so the
|
|
112
|
-
remaining steps can continue.
|
|
109
|
+
Use `--timeout 0` on `auth wait` to wait without a time limit. Use a larger value if users need more than ten minutes to complete login.
|
|
110
|
+
For agent-guided workflows, run `powerbase auth login --json`, return the `login_url` to the user, stop, and wait for the user to confirm browser approval before running `powerbase auth wait --login-id ... --json`.
|
|
111
|
+
If the browser link expires or the user is not currently signed in to the console, rerun `powerbase auth login --json` to generate a fresh login URL before retrying.
|
|
113
112
|
|
|
114
113
|
### Manual Token Import
|
|
115
114
|
|
|
@@ -280,22 +279,24 @@ When Openclaw or another LLM agent uses `powerbase`:
|
|
|
280
279
|
- run discovery commands before write operations
|
|
281
280
|
- set context for long multi-step tasks
|
|
282
281
|
- use `auth status` before workflows that assume login
|
|
283
|
-
-
|
|
284
|
-
- if a protected command says authentication is missing or expired, rerun `auth login --no-wait --json` to generate a fresh login URL
|
|
282
|
+
- use `auth login --json` to generate a login URL, then stop and hand `login_url` to the user
|
|
285
283
|
- do not have the agent open the browser login URL itself; the user must complete that approval step
|
|
284
|
+
- after the user confirms approval, run `auth wait --login-id ... --json` to complete login
|
|
285
|
+
- if a protected command says authentication is missing or expired, rerun `auth login --json` to generate a fresh login URL
|
|
286
286
|
- remember that `--json` overrides a saved `config output text` setting for that command
|
|
287
287
|
|
|
288
288
|
Recommended agent sequence:
|
|
289
289
|
|
|
290
290
|
1. `powerbase auth status --json`
|
|
291
|
-
2. If unauthenticated, or if a protected command reports an auth error, run `powerbase auth login --
|
|
292
|
-
3. `powerbase
|
|
293
|
-
4.
|
|
294
|
-
5. If no
|
|
295
|
-
6.
|
|
296
|
-
7.
|
|
297
|
-
8.
|
|
298
|
-
9.
|
|
291
|
+
2. If unauthenticated, or if a protected command reports an auth error, run `powerbase auth login --json` and return the `login_url` plus `login_id` to the user
|
|
292
|
+
3. After the user confirms browser approval, run `powerbase auth wait --login-id LOGIN_ID --json`
|
|
293
|
+
4. `powerbase context show --json`
|
|
294
|
+
5. If no instance is selected, run `powerbase instance list --json`
|
|
295
|
+
6. If no suitable instance exists, prefer `powerbase instance create --name ... --org-id ... --json`
|
|
296
|
+
7. Use `powerbase database ...` only for the advanced bring-your-own-database path
|
|
297
|
+
8. Set context with `powerbase context use-instance ...`
|
|
298
|
+
9. If you want the sandbox agent preview on a non-main branch, run `powerbase branch switch ...`
|
|
299
|
+
10. Continue with `branch`, `sql`, `publish`, `sandbox files`, or `agent` commands
|
|
299
300
|
|
|
300
301
|
## Testing
|
|
301
302
|
|
|
@@ -83,6 +83,7 @@ The preferred flow is:
|
|
|
83
83
|
|
|
84
84
|
```bash
|
|
85
85
|
powerbase auth login
|
|
86
|
+
powerbase auth wait --login-id LOGIN_ID
|
|
86
87
|
```
|
|
87
88
|
|
|
88
89
|
The CLI now includes a built-in `base_url` and `anon_key` default for this deployment. The test package also bundles this environment's self-signed CA certificate, so most users can start with browser login directly and only use flags or environment variables when overriding that default.
|
|
@@ -92,16 +93,14 @@ The bundled CA is a test-only convenience for the current self-signed deployment
|
|
|
92
93
|
This will:
|
|
93
94
|
|
|
94
95
|
1. request a CLI login session from Powerbase
|
|
95
|
-
2.
|
|
96
|
-
3.
|
|
97
|
-
4.
|
|
96
|
+
2. return a `login_id` and browser URL
|
|
97
|
+
3. wait for the user to approve the request in their own browser
|
|
98
|
+
4. poll with `powerbase auth wait --login-id ...` until approval or until `--timeout` elapses (default **600** seconds, ten minutes)
|
|
99
|
+
5. save the resulting session to `~/.config/powerbase/auth.json`
|
|
98
100
|
|
|
99
|
-
Use `--timeout 0` to wait without a time limit. Use a larger value if users need more than ten minutes to complete login.
|
|
100
|
-
For agent-guided workflows,
|
|
101
|
-
If the browser link expires or the user is not currently signed in to the console, rerun `powerbase auth login --
|
|
102
|
-
If an agent or wrapper script is coordinating the workflow, it is still helpful
|
|
103
|
-
to tell the user: after browser approval, return to the current session so the
|
|
104
|
-
remaining steps can continue.
|
|
101
|
+
Use `--timeout 0` on `auth wait` to wait without a time limit. Use a larger value if users need more than ten minutes to complete login.
|
|
102
|
+
For agent-guided workflows, run `powerbase auth login --json`, return the `login_url` to the user, stop, and wait for the user to confirm browser approval before running `powerbase auth wait --login-id ... --json`.
|
|
103
|
+
If the browser link expires or the user is not currently signed in to the console, rerun `powerbase auth login --json` to generate a fresh login URL before retrying.
|
|
105
104
|
|
|
106
105
|
### Manual Token Import
|
|
107
106
|
|
|
@@ -272,22 +271,24 @@ When Openclaw or another LLM agent uses `powerbase`:
|
|
|
272
271
|
- run discovery commands before write operations
|
|
273
272
|
- set context for long multi-step tasks
|
|
274
273
|
- use `auth status` before workflows that assume login
|
|
275
|
-
-
|
|
276
|
-
- if a protected command says authentication is missing or expired, rerun `auth login --no-wait --json` to generate a fresh login URL
|
|
274
|
+
- use `auth login --json` to generate a login URL, then stop and hand `login_url` to the user
|
|
277
275
|
- do not have the agent open the browser login URL itself; the user must complete that approval step
|
|
276
|
+
- after the user confirms approval, run `auth wait --login-id ... --json` to complete login
|
|
277
|
+
- if a protected command says authentication is missing or expired, rerun `auth login --json` to generate a fresh login URL
|
|
278
278
|
- remember that `--json` overrides a saved `config output text` setting for that command
|
|
279
279
|
|
|
280
280
|
Recommended agent sequence:
|
|
281
281
|
|
|
282
282
|
1. `powerbase auth status --json`
|
|
283
|
-
2. If unauthenticated, or if a protected command reports an auth error, run `powerbase auth login --
|
|
284
|
-
3. `powerbase
|
|
285
|
-
4.
|
|
286
|
-
5. If no
|
|
287
|
-
6.
|
|
288
|
-
7.
|
|
289
|
-
8.
|
|
290
|
-
9.
|
|
283
|
+
2. If unauthenticated, or if a protected command reports an auth error, run `powerbase auth login --json` and return the `login_url` plus `login_id` to the user
|
|
284
|
+
3. After the user confirms browser approval, run `powerbase auth wait --login-id LOGIN_ID --json`
|
|
285
|
+
4. `powerbase context show --json`
|
|
286
|
+
5. If no instance is selected, run `powerbase instance list --json`
|
|
287
|
+
6. If no suitable instance exists, prefer `powerbase instance create --name ... --org-id ... --json`
|
|
288
|
+
7. Use `powerbase database ...` only for the advanced bring-your-own-database path
|
|
289
|
+
8. Set context with `powerbase context use-instance ...`
|
|
290
|
+
9. If you want the sandbox agent preview on a non-main branch, run `powerbase branch switch ...`
|
|
291
|
+
10. Continue with `branch`, `sql`, `publish`, `sandbox files`, or `agent` commands
|
|
291
292
|
|
|
292
293
|
## Testing
|
|
293
294
|
|
|
@@ -6,40 +6,18 @@ import time
|
|
|
6
6
|
from .shared import AuthSession, AuthState, build_api, now_iso, render_output
|
|
7
7
|
|
|
8
8
|
|
|
9
|
-
def
|
|
9
|
+
def _poll_login_until_approved(args: argparse.Namespace, *, login_id: str) -> int:
|
|
10
10
|
store, config, _, _, api = build_api(args)
|
|
11
|
-
data = api.start_cli_login()
|
|
12
|
-
login_id = data["login_id"]
|
|
13
|
-
if getattr(args, "no_wait_login", False):
|
|
14
|
-
render_output(
|
|
15
|
-
args,
|
|
16
|
-
{
|
|
17
|
-
"status": "pending",
|
|
18
|
-
"login_id": login_id,
|
|
19
|
-
"login_url": data["login_url"],
|
|
20
|
-
"poll_interval": data.get("poll_interval", 2),
|
|
21
|
-
"next_action": "ask_user_to_open_url",
|
|
22
|
-
"message": (
|
|
23
|
-
"Ask the user to open login_url in a browser and approve the request. "
|
|
24
|
-
"If the user is not already signed in to the console or this link expires, "
|
|
25
|
-
"rerun `powerbase auth login --no-wait --json` to generate a fresh login URL. "
|
|
26
|
-
"After approval, rerun `powerbase auth status --json` or invoke "
|
|
27
|
-
"`powerbase auth login` without `--no-wait` to finish in this session."
|
|
28
|
-
),
|
|
29
|
-
},
|
|
30
|
-
)
|
|
31
|
-
return 0
|
|
32
11
|
timeout_sec = int(args.login_timeout)
|
|
33
12
|
if timeout_sec < 0:
|
|
34
13
|
raise RuntimeError("--timeout must be >= 0 (0 means wait indefinitely).")
|
|
35
14
|
deadline: float | None = None
|
|
36
15
|
if timeout_sec > 0:
|
|
37
16
|
deadline = time.monotonic() + timeout_sec
|
|
38
|
-
print(f"Open this URL in your browser:\n{data['login_url']}\n")
|
|
39
17
|
if deadline is not None:
|
|
40
|
-
print(f"Waiting for authorization (timeout {timeout_sec}s)...")
|
|
18
|
+
print(f"Waiting for authorization for login_id {login_id} (timeout {timeout_sec}s)...")
|
|
41
19
|
else:
|
|
42
|
-
print("Waiting for authorization (no timeout)...")
|
|
20
|
+
print(f"Waiting for authorization for login_id {login_id} (no timeout)...")
|
|
43
21
|
while True:
|
|
44
22
|
polled = api.poll_cli_login(login_id)
|
|
45
23
|
status = polled.get("status")
|
|
@@ -49,8 +27,9 @@ def handle_auth_login(args: argparse.Namespace) -> int:
|
|
|
49
27
|
if remaining <= 0:
|
|
50
28
|
raise RuntimeError(
|
|
51
29
|
f"Login timed out after {timeout_sec} seconds without browser approval. "
|
|
52
|
-
"
|
|
53
|
-
"
|
|
30
|
+
"Generate a fresh login URL with `powerbase auth login`, ask the user to "
|
|
31
|
+
"approve it in their own browser, then rerun `powerbase auth wait --login-id ...`. "
|
|
32
|
+
"Or pass a larger `--timeout` "
|
|
54
33
|
"(use `--timeout 0` to wait indefinitely)."
|
|
55
34
|
)
|
|
56
35
|
else:
|
|
@@ -83,6 +62,32 @@ def handle_auth_login(args: argparse.Namespace) -> int:
|
|
|
83
62
|
raise RuntimeError(f"Login failed with status: {status}")
|
|
84
63
|
|
|
85
64
|
|
|
65
|
+
def handle_auth_login(args: argparse.Namespace) -> int:
|
|
66
|
+
_, _, _, _, api = build_api(args)
|
|
67
|
+
data = api.start_cli_login()
|
|
68
|
+
login_id = data["login_id"]
|
|
69
|
+
render_output(
|
|
70
|
+
args,
|
|
71
|
+
{
|
|
72
|
+
"status": "pending",
|
|
73
|
+
"login_id": login_id,
|
|
74
|
+
"login_url": data["login_url"],
|
|
75
|
+
"poll_interval": data.get("poll_interval", 2),
|
|
76
|
+
"next_action": "ask_user_to_open_url",
|
|
77
|
+
"message": (
|
|
78
|
+
"Return login_url to the user and stop. "
|
|
79
|
+
"Do not open the URL or poll yet. After the user confirms approval, run "
|
|
80
|
+
f"`powerbase auth wait --login-id {login_id} --json`."
|
|
81
|
+
),
|
|
82
|
+
},
|
|
83
|
+
)
|
|
84
|
+
return 0
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def handle_auth_wait(args: argparse.Namespace) -> int:
|
|
88
|
+
return _poll_login_until_approved(args, login_id=args.login_id)
|
|
89
|
+
|
|
90
|
+
|
|
86
91
|
def handle_auth_status(args: argparse.Namespace) -> int:
|
|
87
92
|
store, _, _, session_manager, _ = build_api(args)
|
|
88
93
|
auth = session_manager.get_auth_state()
|
|
@@ -138,27 +143,27 @@ def register_auth_commands(subparsers: argparse._SubParsersAction[argparse.Argum
|
|
|
138
143
|
)
|
|
139
144
|
auth_sub = auth.add_subparsers(
|
|
140
145
|
dest="auth_command",
|
|
141
|
-
metavar="{login,status,refresh,logout}",
|
|
146
|
+
metavar="{login,wait,status,refresh,logout}",
|
|
142
147
|
)
|
|
143
148
|
p = auth_sub.add_parser(
|
|
144
149
|
"login",
|
|
145
|
-
help="
|
|
150
|
+
help="Generate browser login URL.",
|
|
146
151
|
description=(
|
|
147
|
-
"Start browser
|
|
148
|
-
"
|
|
149
|
-
"
|
|
150
|
-
"Use --no-wait to print the login URL and exit immediately without polling."
|
|
152
|
+
"Start browser login and return login_url plus login_id. "
|
|
153
|
+
"Give the URL to the user. Do not open it or poll yet. "
|
|
154
|
+
"After the user confirms approval, run `powerbase auth wait --login-id ...`."
|
|
151
155
|
),
|
|
152
156
|
)
|
|
153
|
-
p.
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
"
|
|
159
|
-
"
|
|
157
|
+
p.set_defaults(handler=handle_auth_login)
|
|
158
|
+
p = auth_sub.add_parser(
|
|
159
|
+
"wait",
|
|
160
|
+
help="Poll for browser approval.",
|
|
161
|
+
description=(
|
|
162
|
+
"Poll a previously started browser login by login_id. Run this only after the user "
|
|
163
|
+
"confirms they approved the login request in their own browser."
|
|
160
164
|
),
|
|
161
165
|
)
|
|
166
|
+
p.add_argument("--login-id", required=True, help="Login ID returned by `powerbase auth login`.")
|
|
162
167
|
p.add_argument(
|
|
163
168
|
"--timeout",
|
|
164
169
|
dest="login_timeout",
|
|
@@ -170,7 +175,7 @@ def register_auth_commands(subparsers: argparse._SubParsersAction[argparse.Argum
|
|
|
170
175
|
"Pass 0 to wait indefinitely."
|
|
171
176
|
),
|
|
172
177
|
)
|
|
173
|
-
p.set_defaults(handler=
|
|
178
|
+
p.set_defaults(handler=handle_auth_wait)
|
|
174
179
|
p = auth_sub.add_parser(
|
|
175
180
|
"status",
|
|
176
181
|
help="Show current auth status.",
|
|
@@ -41,8 +41,9 @@ class SessionManager:
|
|
|
41
41
|
|
|
42
42
|
def _login_guidance(self) -> str:
|
|
43
43
|
return (
|
|
44
|
-
"Run `powerbase auth login --
|
|
45
|
-
"ask the user to open it in their own browser, and
|
|
44
|
+
"Run `powerbase auth login --json` to generate a fresh login URL, "
|
|
45
|
+
"ask the user to open it in their own browser, and after they confirm approval "
|
|
46
|
+
"run `powerbase auth wait --login-id ... --json`."
|
|
46
47
|
)
|
|
47
48
|
|
|
48
49
|
def _urlopen(self, req: request.Request):
|
|
@@ -29,8 +29,9 @@ class PowerbaseTransport:
|
|
|
29
29
|
|
|
30
30
|
def _login_guidance(self) -> str:
|
|
31
31
|
return (
|
|
32
|
-
"Run `powerbase auth login --
|
|
33
|
-
"ask the user to open it in their own browser, and
|
|
32
|
+
"Run `powerbase auth login --json` to generate a fresh login URL, "
|
|
33
|
+
"ask the user to open it in their own browser, and after they confirm approval "
|
|
34
|
+
"run `powerbase auth wait --login-id ... --json`."
|
|
34
35
|
)
|
|
35
36
|
|
|
36
37
|
def _urlopen(self, req: request.Request):
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: powerbase-cli
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.4
|
|
4
4
|
Summary: CLI for operating Powerbase console workflows
|
|
5
5
|
Author: Powerbase
|
|
6
6
|
Requires-Python: >=3.11
|
|
@@ -91,6 +91,7 @@ The preferred flow is:
|
|
|
91
91
|
|
|
92
92
|
```bash
|
|
93
93
|
powerbase auth login
|
|
94
|
+
powerbase auth wait --login-id LOGIN_ID
|
|
94
95
|
```
|
|
95
96
|
|
|
96
97
|
The CLI now includes a built-in `base_url` and `anon_key` default for this deployment. The test package also bundles this environment's self-signed CA certificate, so most users can start with browser login directly and only use flags or environment variables when overriding that default.
|
|
@@ -100,16 +101,14 @@ The bundled CA is a test-only convenience for the current self-signed deployment
|
|
|
100
101
|
This will:
|
|
101
102
|
|
|
102
103
|
1. request a CLI login session from Powerbase
|
|
103
|
-
2.
|
|
104
|
-
3.
|
|
105
|
-
4.
|
|
104
|
+
2. return a `login_id` and browser URL
|
|
105
|
+
3. wait for the user to approve the request in their own browser
|
|
106
|
+
4. poll with `powerbase auth wait --login-id ...` until approval or until `--timeout` elapses (default **600** seconds, ten minutes)
|
|
107
|
+
5. save the resulting session to `~/.config/powerbase/auth.json`
|
|
106
108
|
|
|
107
|
-
Use `--timeout 0` to wait without a time limit. Use a larger value if users need more than ten minutes to complete login.
|
|
108
|
-
For agent-guided workflows,
|
|
109
|
-
If the browser link expires or the user is not currently signed in to the console, rerun `powerbase auth login --
|
|
110
|
-
If an agent or wrapper script is coordinating the workflow, it is still helpful
|
|
111
|
-
to tell the user: after browser approval, return to the current session so the
|
|
112
|
-
remaining steps can continue.
|
|
109
|
+
Use `--timeout 0` on `auth wait` to wait without a time limit. Use a larger value if users need more than ten minutes to complete login.
|
|
110
|
+
For agent-guided workflows, run `powerbase auth login --json`, return the `login_url` to the user, stop, and wait for the user to confirm browser approval before running `powerbase auth wait --login-id ... --json`.
|
|
111
|
+
If the browser link expires or the user is not currently signed in to the console, rerun `powerbase auth login --json` to generate a fresh login URL before retrying.
|
|
113
112
|
|
|
114
113
|
### Manual Token Import
|
|
115
114
|
|
|
@@ -280,22 +279,24 @@ When Openclaw or another LLM agent uses `powerbase`:
|
|
|
280
279
|
- run discovery commands before write operations
|
|
281
280
|
- set context for long multi-step tasks
|
|
282
281
|
- use `auth status` before workflows that assume login
|
|
283
|
-
-
|
|
284
|
-
- if a protected command says authentication is missing or expired, rerun `auth login --no-wait --json` to generate a fresh login URL
|
|
282
|
+
- use `auth login --json` to generate a login URL, then stop and hand `login_url` to the user
|
|
285
283
|
- do not have the agent open the browser login URL itself; the user must complete that approval step
|
|
284
|
+
- after the user confirms approval, run `auth wait --login-id ... --json` to complete login
|
|
285
|
+
- if a protected command says authentication is missing or expired, rerun `auth login --json` to generate a fresh login URL
|
|
286
286
|
- remember that `--json` overrides a saved `config output text` setting for that command
|
|
287
287
|
|
|
288
288
|
Recommended agent sequence:
|
|
289
289
|
|
|
290
290
|
1. `powerbase auth status --json`
|
|
291
|
-
2. If unauthenticated, or if a protected command reports an auth error, run `powerbase auth login --
|
|
292
|
-
3. `powerbase
|
|
293
|
-
4.
|
|
294
|
-
5. If no
|
|
295
|
-
6.
|
|
296
|
-
7.
|
|
297
|
-
8.
|
|
298
|
-
9.
|
|
291
|
+
2. If unauthenticated, or if a protected command reports an auth error, run `powerbase auth login --json` and return the `login_url` plus `login_id` to the user
|
|
292
|
+
3. After the user confirms browser approval, run `powerbase auth wait --login-id LOGIN_ID --json`
|
|
293
|
+
4. `powerbase context show --json`
|
|
294
|
+
5. If no instance is selected, run `powerbase instance list --json`
|
|
295
|
+
6. If no suitable instance exists, prefer `powerbase instance create --name ... --org-id ... --json`
|
|
296
|
+
7. Use `powerbase database ...` only for the advanced bring-your-own-database path
|
|
297
|
+
8. Set context with `powerbase context use-instance ...`
|
|
298
|
+
9. If you want the sandbox agent preview on a non-main branch, run `powerbase branch switch ...`
|
|
299
|
+
10. Continue with `branch`, `sql`, `publish`, `sandbox files`, or `agent` commands
|
|
299
300
|
|
|
300
301
|
## Testing
|
|
301
302
|
|
|
@@ -12,6 +12,7 @@ from unittest import mock
|
|
|
12
12
|
sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "src"))
|
|
13
13
|
|
|
14
14
|
from powerbase_cli.commands.auth import handle_auth_login as auth_handle_auth_login
|
|
15
|
+
from powerbase_cli.commands.auth import handle_auth_wait as auth_handle_auth_wait
|
|
15
16
|
from powerbase_cli.commands.agent import handle_agent_chat as agent_handle_agent_chat
|
|
16
17
|
from powerbase_cli.commands.shared import resolve_config as shared_resolve_config
|
|
17
18
|
from powerbase_cli.config import (
|
|
@@ -37,16 +38,16 @@ class FakeApiPending:
|
|
|
37
38
|
return {"status": "pending", "poll_interval": 2}
|
|
38
39
|
|
|
39
40
|
|
|
40
|
-
class
|
|
41
|
+
class FakeApiStartOnly:
|
|
41
42
|
def start_cli_login(self):
|
|
42
43
|
return {
|
|
43
|
-
"login_id": "login-
|
|
44
|
-
"login_url": "https://console.example.com/cli-auth/login-
|
|
44
|
+
"login_id": "login-start",
|
|
45
|
+
"login_url": "https://console.example.com/cli-auth/login-start",
|
|
45
46
|
"poll_interval": 2,
|
|
46
47
|
}
|
|
47
48
|
|
|
48
49
|
def poll_cli_login(self, login_id: str):
|
|
49
|
-
raise AssertionError("poll_cli_login should not be called
|
|
50
|
+
raise AssertionError("poll_cli_login should not be called by auth login")
|
|
50
51
|
|
|
51
52
|
|
|
52
53
|
class FakeApi:
|
|
@@ -120,14 +121,14 @@ class CliCommandTests(unittest.TestCase):
|
|
|
120
121
|
anon_key=None,
|
|
121
122
|
json=True,
|
|
122
123
|
login_timeout=300,
|
|
123
|
-
|
|
124
|
+
login_id="login-1",
|
|
124
125
|
insecure=False,
|
|
125
126
|
)
|
|
126
127
|
|
|
127
128
|
with mock.patch("powerbase_cli.commands.auth.build_api", return_value=(store, config, None, None, FakeApi())):
|
|
128
129
|
with mock.patch("powerbase_cli.commands.auth.time.sleep", return_value=None):
|
|
129
130
|
with mock.patch("sys.stdout", new=StringIO()):
|
|
130
|
-
exit_code =
|
|
131
|
+
exit_code = auth_handle_auth_wait(args)
|
|
131
132
|
|
|
132
133
|
self.assertEqual(exit_code, 0)
|
|
133
134
|
saved = store.load_auth()
|
|
@@ -135,7 +136,7 @@ class CliCommandTests(unittest.TestCase):
|
|
|
135
136
|
self.assertEqual(saved.session.access_token, "new-access")
|
|
136
137
|
self.assertEqual(saved.user["id"], "user-1")
|
|
137
138
|
|
|
138
|
-
def
|
|
139
|
+
def test_auth_login_returns_login_url_without_polling(self) -> None:
|
|
139
140
|
with tempfile.TemporaryDirectory() as temp_dir:
|
|
140
141
|
store = ConfigStore(Path(temp_dir))
|
|
141
142
|
config = AppConfig(base_url="https://console.example.com", anon_key="anon")
|
|
@@ -144,24 +145,23 @@ class CliCommandTests(unittest.TestCase):
|
|
|
144
145
|
base_url=None,
|
|
145
146
|
anon_key=None,
|
|
146
147
|
json=True,
|
|
147
|
-
login_timeout=300,
|
|
148
|
-
no_wait_login=True,
|
|
149
148
|
insecure=False,
|
|
150
149
|
)
|
|
151
150
|
|
|
152
|
-
with mock.patch("powerbase_cli.commands.auth.build_api", return_value=(store, config, None, None,
|
|
151
|
+
with mock.patch("powerbase_cli.commands.auth.build_api", return_value=(store, config, None, None, FakeApiStartOnly())):
|
|
153
152
|
with mock.patch("sys.stdout", new=StringIO()) as stdout:
|
|
154
153
|
exit_code = auth_handle_auth_login(args)
|
|
155
154
|
|
|
156
155
|
self.assertEqual(exit_code, 0)
|
|
157
156
|
payload = json.loads(stdout.getvalue())
|
|
158
157
|
self.assertEqual(payload["status"], "pending")
|
|
159
|
-
self.assertEqual(payload["login_id"], "login-
|
|
158
|
+
self.assertEqual(payload["login_id"], "login-start")
|
|
160
159
|
self.assertEqual(payload["next_action"], "ask_user_to_open_url")
|
|
161
160
|
self.assertIn("login_url", payload)
|
|
161
|
+
self.assertIn("powerbase auth wait --login-id login-start --json", payload["message"])
|
|
162
162
|
self.assertIsNone(store.load_auth())
|
|
163
163
|
|
|
164
|
-
def
|
|
164
|
+
def test_auth_wait_times_out(self) -> None:
|
|
165
165
|
clock = {"t": 0.0}
|
|
166
166
|
|
|
167
167
|
def fake_monotonic() -> float:
|
|
@@ -179,7 +179,7 @@ class CliCommandTests(unittest.TestCase):
|
|
|
179
179
|
anon_key=None,
|
|
180
180
|
json=False,
|
|
181
181
|
login_timeout=5,
|
|
182
|
-
|
|
182
|
+
login_id="login-pending",
|
|
183
183
|
insecure=False,
|
|
184
184
|
)
|
|
185
185
|
|
|
@@ -188,7 +188,7 @@ class CliCommandTests(unittest.TestCase):
|
|
|
188
188
|
with mock.patch("powerbase_cli.commands.auth.time.sleep", fake_sleep):
|
|
189
189
|
with mock.patch("sys.stdout", new=StringIO()):
|
|
190
190
|
with self.assertRaises(RuntimeError) as ctx:
|
|
191
|
-
|
|
191
|
+
auth_handle_auth_wait(args)
|
|
192
192
|
|
|
193
193
|
self.assertIn("timed out", str(ctx.exception).lower())
|
|
194
194
|
self.assertIn("5", str(ctx.exception))
|
|
@@ -22,13 +22,22 @@ class CliHelpTests(unittest.TestCase):
|
|
|
22
22
|
self.assertIn("--insecure", help_text)
|
|
23
23
|
self.assertIn("--ca-cert", help_text)
|
|
24
24
|
|
|
25
|
-
def
|
|
25
|
+
def test_auth_login_help_mentions_wait_follow_up(self) -> None:
|
|
26
26
|
parser = build_parser()
|
|
27
27
|
auth_parser = parser._subparsers._group_actions[0].choices["auth"]
|
|
28
28
|
login_parser = auth_parser._subparsers._group_actions[0].choices["login"]
|
|
29
29
|
help_text = login_parser.format_help()
|
|
30
|
+
self.assertIn("login_id", help_text)
|
|
31
|
+
self.assertIn("Do not open", help_text)
|
|
32
|
+
self.assertIn("powerbase auth wait", help_text)
|
|
33
|
+
|
|
34
|
+
def test_auth_wait_help_mentions_timeout(self) -> None:
|
|
35
|
+
parser = build_parser()
|
|
36
|
+
auth_parser = parser._subparsers._group_actions[0].choices["auth"]
|
|
37
|
+
wait_parser = auth_parser._subparsers._group_actions[0].choices["wait"]
|
|
38
|
+
help_text = wait_parser.format_help()
|
|
39
|
+
self.assertIn("--login-id", help_text)
|
|
30
40
|
self.assertIn("--timeout", help_text)
|
|
31
|
-
self.assertIn("--no-wait", help_text)
|
|
32
41
|
self.assertIn("600", help_text)
|
|
33
42
|
|
|
34
43
|
def test_auth_help_does_not_list_token_set_subcommand(self) -> None:
|
|
@@ -38,7 +38,8 @@ class SessionManagerTests(unittest.TestCase):
|
|
|
38
38
|
manager.refresh()
|
|
39
39
|
|
|
40
40
|
self.assertIn("No authentication session available", str(ctx.exception))
|
|
41
|
-
self.assertIn("powerbase auth login --
|
|
41
|
+
self.assertIn("powerbase auth login --json", str(ctx.exception))
|
|
42
|
+
self.assertIn("powerbase auth wait --login-id ... --json", str(ctx.exception))
|
|
42
43
|
|
|
43
44
|
def test_refresh_updates_saved_auth_file(self) -> None:
|
|
44
45
|
with tempfile.TemporaryDirectory() as temp_dir:
|
|
@@ -47,7 +47,8 @@ class PowerbaseTransportTests(unittest.TestCase):
|
|
|
47
47
|
|
|
48
48
|
self.assertEqual(ctx.exception.status, 401)
|
|
49
49
|
self.assertIn("No authentication session available", str(ctx.exception))
|
|
50
|
-
self.assertIn("powerbase auth login --
|
|
50
|
+
self.assertIn("powerbase auth login --json", str(ctx.exception))
|
|
51
|
+
self.assertIn("powerbase auth wait --login-id ... --json", str(ctx.exception))
|
|
51
52
|
self.assertEqual(urlopen_mock.call_count, 0)
|
|
52
53
|
|
|
53
54
|
def test_invoke_uses_unverified_tls_context_when_insecure(self) -> None:
|
|
@@ -182,7 +183,8 @@ class PowerbaseTransportTests(unittest.TestCase):
|
|
|
182
183
|
transport.invoke("instances", method="GET")
|
|
183
184
|
|
|
184
185
|
self.assertEqual(ctx.exception.status, 401)
|
|
185
|
-
self.assertIn("powerbase auth login --
|
|
186
|
+
self.assertIn("powerbase auth login --json", str(ctx.exception))
|
|
187
|
+
self.assertIn("powerbase auth wait --login-id ... --json", str(ctx.exception))
|
|
186
188
|
self.assertEqual(refresh_mock.call_count, 0)
|
|
187
189
|
self.assertEqual(urlopen_mock.call_count, 1)
|
|
188
190
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|