powerbase-cli 0.1.5__tar.gz → 0.2.0__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.
Files changed (38) hide show
  1. {powerbase_cli-0.1.5 → powerbase_cli-0.2.0}/PKG-INFO +5 -3
  2. {powerbase_cli-0.1.5 → powerbase_cli-0.2.0}/README.md +4 -2
  3. {powerbase_cli-0.1.5 → powerbase_cli-0.2.0}/pyproject.toml +1 -4
  4. {powerbase_cli-0.1.5 → powerbase_cli-0.2.0}/src/powerbase_cli/__init__.py +1 -1
  5. {powerbase_cli-0.1.5 → powerbase_cli-0.2.0}/src/powerbase_cli/commands/parser.py +0 -16
  6. {powerbase_cli-0.1.5 → powerbase_cli-0.2.0}/src/powerbase_cli/commands/shared.py +3 -15
  7. {powerbase_cli-0.1.5 → powerbase_cli-0.2.0}/src/powerbase_cli/config.py +4 -54
  8. {powerbase_cli-0.1.5 → powerbase_cli-0.2.0}/src/powerbase_cli/session.py +1 -20
  9. {powerbase_cli-0.1.5 → powerbase_cli-0.2.0}/src/powerbase_cli/transport.py +1 -15
  10. {powerbase_cli-0.1.5 → powerbase_cli-0.2.0}/src/powerbase_cli.egg-info/PKG-INFO +5 -3
  11. {powerbase_cli-0.1.5 → powerbase_cli-0.2.0}/src/powerbase_cli.egg-info/SOURCES.txt +0 -1
  12. {powerbase_cli-0.1.5 → powerbase_cli-0.2.0}/tests/test_cli_commands.py +5 -26
  13. {powerbase_cli-0.1.5 → powerbase_cli-0.2.0}/tests/test_cli_help.py +4 -4
  14. {powerbase_cli-0.1.5 → powerbase_cli-0.2.0}/tests/test_config.py +1 -15
  15. powerbase_cli-0.2.0/tests/test_session.py +97 -0
  16. {powerbase_cli-0.1.5 → powerbase_cli-0.2.0}/tests/test_transport.py +1 -66
  17. powerbase_cli-0.1.5/src/powerbase_cli/certs/powerbase-test-ca.pem +0 -21
  18. powerbase_cli-0.1.5/tests/test_session.py +0 -194
  19. {powerbase_cli-0.1.5 → powerbase_cli-0.2.0}/setup.cfg +0 -0
  20. {powerbase_cli-0.1.5 → powerbase_cli-0.2.0}/src/powerbase_cli/__main__.py +0 -0
  21. {powerbase_cli-0.1.5 → powerbase_cli-0.2.0}/src/powerbase_cli/api.py +0 -0
  22. {powerbase_cli-0.1.5 → powerbase_cli-0.2.0}/src/powerbase_cli/cli.py +0 -0
  23. {powerbase_cli-0.1.5 → powerbase_cli-0.2.0}/src/powerbase_cli/commands/__init__.py +0 -0
  24. {powerbase_cli-0.1.5 → powerbase_cli-0.2.0}/src/powerbase_cli/commands/agent.py +0 -0
  25. {powerbase_cli-0.1.5 → powerbase_cli-0.2.0}/src/powerbase_cli/commands/auth.py +0 -0
  26. {powerbase_cli-0.1.5 → powerbase_cli-0.2.0}/src/powerbase_cli/commands/branch.py +0 -0
  27. {powerbase_cli-0.1.5 → powerbase_cli-0.2.0}/src/powerbase_cli/commands/config_cmd.py +0 -0
  28. {powerbase_cli-0.1.5 → powerbase_cli-0.2.0}/src/powerbase_cli/commands/context.py +0 -0
  29. {powerbase_cli-0.1.5 → powerbase_cli-0.2.0}/src/powerbase_cli/commands/database.py +0 -0
  30. {powerbase_cli-0.1.5 → powerbase_cli-0.2.0}/src/powerbase_cli/commands/instance.py +0 -0
  31. {powerbase_cli-0.1.5 → powerbase_cli-0.2.0}/src/powerbase_cli/commands/org.py +0 -0
  32. {powerbase_cli-0.1.5 → powerbase_cli-0.2.0}/src/powerbase_cli/commands/publish.py +0 -0
  33. {powerbase_cli-0.1.5 → powerbase_cli-0.2.0}/src/powerbase_cli/commands/sandbox.py +0 -0
  34. {powerbase_cli-0.1.5 → powerbase_cli-0.2.0}/src/powerbase_cli/commands/sql.py +0 -0
  35. {powerbase_cli-0.1.5 → powerbase_cli-0.2.0}/src/powerbase_cli.egg-info/dependency_links.txt +0 -0
  36. {powerbase_cli-0.1.5 → powerbase_cli-0.2.0}/src/powerbase_cli.egg-info/entry_points.txt +0 -0
  37. {powerbase_cli-0.1.5 → powerbase_cli-0.2.0}/src/powerbase_cli.egg-info/top_level.txt +0 -0
  38. {powerbase_cli-0.1.5 → powerbase_cli-0.2.0}/tests/test_api.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: powerbase-cli
3
- Version: 0.1.5
3
+ Version: 0.2.0
4
4
  Summary: CLI for operating Powerbase console workflows
5
5
  Author: Powerbase
6
6
  Requires-Python: >=3.11
@@ -41,10 +41,12 @@ Database model:
41
41
  Install from PyPI:
42
42
 
43
43
  ```bash
44
- python -m pip install powerbase-cli
44
+ python -m pip install --upgrade powerbase-cli==0.2.0
45
45
  powerbase --help
46
46
  ```
47
47
 
48
+ Version `0.2.x` is the production-pinned release line and always targets `https://console.appbuild.chat`.
49
+
48
50
  From the repository root during development:
49
51
 
50
52
  ```bash
@@ -121,7 +123,7 @@ powerbase auth token-set \
121
123
  --expires-at 1760000000
122
124
  ```
123
125
 
124
- Use `--base-url` or `--anon-key` here only when you intentionally want to override the built-in deployment defaults.
126
+ The CLI is pinned to the production Powerbase console deployment and no longer exposes endpoint override flags.
125
127
 
126
128
  ### Check Auth State
127
129
 
@@ -33,10 +33,12 @@ Database model:
33
33
  Install from PyPI:
34
34
 
35
35
  ```bash
36
- python -m pip install powerbase-cli
36
+ python -m pip install --upgrade powerbase-cli==0.2.0
37
37
  powerbase --help
38
38
  ```
39
39
 
40
+ Version `0.2.x` is the production-pinned release line and always targets `https://console.appbuild.chat`.
41
+
40
42
  From the repository root during development:
41
43
 
42
44
  ```bash
@@ -113,7 +115,7 @@ powerbase auth token-set \
113
115
  --expires-at 1760000000
114
116
  ```
115
117
 
116
- Use `--base-url` or `--anon-key` here only when you intentionally want to override the built-in deployment defaults.
118
+ The CLI is pinned to the production Powerbase console deployment and no longer exposes endpoint override flags.
117
119
 
118
120
  ### Check Auth State
119
121
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "powerbase-cli"
7
- version = "0.1.5"
7
+ version = "0.2.0"
8
8
  description = "CLI for operating Powerbase console workflows"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"
@@ -17,8 +17,5 @@ powerbase = "powerbase_cli.cli:main"
17
17
  [tool.setuptools]
18
18
  package-dir = { "" = "src" }
19
19
 
20
- [tool.setuptools.package-data]
21
- powerbase_cli = ["certs/*.pem"]
22
-
23
20
  [tool.setuptools.packages.find]
24
21
  where = ["src"]
@@ -2,4 +2,4 @@
2
2
 
3
3
  __all__ = ["__version__"]
4
4
 
5
- __version__ = "0.1.0"
5
+ __version__ = "0.2.0"
@@ -19,10 +19,6 @@ from .sql import register_sql_commands
19
19
 
20
20
  GLOBAL_OPTION_ARITY = {
21
21
  "--config-dir": 1,
22
- "--base-url": 1,
23
- "--anon-key": 1,
24
- "--ca-cert": 1,
25
- "--insecure": 0,
26
22
  "--json": 0,
27
23
  }
28
24
 
@@ -74,18 +70,6 @@ def build_parser() -> argparse.ArgumentParser:
74
70
  ),
75
71
  )
76
72
  parser.add_argument("--config-dir", help="Override the config directory. Defaults to ~/.config/powerbase.")
77
- parser.add_argument("--base-url", help="Console base URL. Overrides the built-in default console endpoint.")
78
- parser.add_argument("--anon-key", help="Supabase anon key used for functions and auth requests. Overrides the built-in default.")
79
- parser.add_argument(
80
- "--ca-cert",
81
- dest="ca_cert_file",
82
- help="Path to a CA certificate PEM file to trust for HTTPS requests.",
83
- )
84
- parser.add_argument(
85
- "--insecure",
86
- action="store_true",
87
- help="Disable TLS certificate verification for HTTPS requests. Use only for testing with self-signed certs.",
88
- )
89
73
  parser.add_argument("--json", action="store_true", help="Print JSON output.")
90
74
 
91
75
  subparsers = parser.add_subparsers(dest="command")
@@ -8,7 +8,6 @@ from typing import Any
8
8
 
9
9
  from ..api import PowerbaseApi
10
10
  from ..config import (
11
- BUNDLED_CA_CERT_SENTINEL,
12
11
  DEFAULT_ANON_KEY,
13
12
  DEFAULT_BASE_URL,
14
13
  AppConfig,
@@ -16,8 +15,6 @@ from ..config import (
16
15
  AuthState,
17
16
  ConfigStore,
18
17
  ContextState,
19
- load_bundled_ca_cert,
20
- merge_config_with_env,
21
18
  merge_context_with_env,
22
19
  )
23
20
  from ..session import SessionManager
@@ -33,18 +30,11 @@ def build_store(args: argparse.Namespace) -> ConfigStore:
33
30
 
34
31
 
35
32
  def resolve_config(args: argparse.Namespace, store: ConfigStore) -> AppConfig:
36
- config = merge_config_with_env(store.load_config())
37
- saved_auth = store.load_auth()
38
- explicit_ca_cert_file = getattr(args, "ca_cert_file", None) or config.ca_cert_file
33
+ config = store.load_config()
39
34
  return AppConfig(
40
- base_url=args.base_url or config.base_url or (saved_auth.base_url if saved_auth else None) or DEFAULT_BASE_URL,
41
- anon_key=args.anon_key or config.anon_key or (saved_auth.anon_key if saved_auth else None) or DEFAULT_ANON_KEY,
35
+ base_url=DEFAULT_BASE_URL,
36
+ anon_key=DEFAULT_ANON_KEY,
42
37
  output="json" if args.json else config.output,
43
- tls_insecure=bool(getattr(args, "insecure", False) or config.tls_insecure),
44
- # Keep explicit CA settings first. The bundled test CA is only the final fallback for the
45
- # current self-signed test environment and should be removed once the deployment uses a
46
- # publicly trusted certificate.
47
- ca_cert_file=explicit_ca_cert_file or (BUNDLED_CA_CERT_SENTINEL if load_bundled_ca_cert() else None),
48
38
  )
49
39
 
50
40
 
@@ -60,8 +50,6 @@ def build_api(args: argparse.Namespace) -> tuple[ConfigStore, AppConfig, Context
60
50
  store,
61
51
  config.base_url,
62
52
  config.anon_key,
63
- tls_insecure=config.tls_insecure,
64
- ca_cert_file=config.ca_cert_file,
65
53
  )
66
54
  api = PowerbaseApi(PowerbaseTransport(config, session_manager))
67
55
  return store, config, context, session_manager, api
@@ -1,6 +1,5 @@
1
1
  from __future__ import annotations
2
2
 
3
- import importlib.resources
4
3
  import json
5
4
  import os
6
5
  from dataclasses import asdict, dataclass
@@ -12,13 +11,8 @@ try:
12
11
  except ModuleNotFoundError: # pragma: no cover
13
12
  tomllib = None # type: ignore[assignment]
14
13
 
15
- DEFAULT_BASE_URL = "https://console.6.12.235.165.nip.io"
14
+ DEFAULT_BASE_URL = "https://console.appbuild.chat"
16
15
  DEFAULT_ANON_KEY = "reallyreallyreallyreallyverysafe"
17
- # This bundled CA is only for the self-signed test deployment so `pip install powerbase-cli`
18
- # can work out of the box. Remove it after the deployed console switches to a publicly trusted
19
- # TLS certificate, then delete the bundled PEM file and its package-data entry as well.
20
- BUNDLED_CA_CERT_SENTINEL = "<bundled test CA>"
21
- BUNDLED_CA_CERT_RESOURCE = "certs/powerbase-test-ca.pem"
22
16
 
23
17
 
24
18
  def default_config_dir() -> Path:
@@ -33,8 +27,6 @@ class AppConfig:
33
27
  base_url: str | None = DEFAULT_BASE_URL
34
28
  anon_key: str | None = DEFAULT_ANON_KEY
35
29
  output: str = "text"
36
- tls_insecure: bool = False
37
- ca_cert_file: str | None = None
38
30
 
39
31
 
40
32
  @dataclass
@@ -69,26 +61,6 @@ def _as_path(path: str | Path | None) -> Path:
69
61
  return Path(path).expanduser()
70
62
 
71
63
 
72
- def env_flag(name: str) -> bool:
73
- value = os.environ.get(name)
74
- if value is None:
75
- return False
76
- return value.strip().lower() in {"1", "true", "yes", "on"}
77
-
78
-
79
- def load_bundled_ca_cert() -> str | None:
80
- # The PEM contents are loaded at runtime so test builds can trust the packaged self-signed CA
81
- # without asking end users to pass `--ca-cert`. Once the server uses a trusted certificate,
82
- # this helper and its callers can be removed.
83
- try:
84
- resource = importlib.resources.files("powerbase_cli").joinpath(BUNDLED_CA_CERT_RESOURCE)
85
- if not resource.is_file():
86
- return None
87
- return resource.read_text(encoding="utf-8")
88
- except (FileNotFoundError, ModuleNotFoundError):
89
- return None
90
-
91
-
92
64
  class ConfigStore:
93
65
  def __init__(self, base_dir: str | Path | None = None) -> None:
94
66
  self.base_dir = _as_path(base_dir)
@@ -101,31 +73,19 @@ class ConfigStore:
101
73
 
102
74
  def load_config(self) -> AppConfig:
103
75
  if not self.config_path.exists():
104
- return AppConfig(base_url=None, anon_key=None)
76
+ return AppConfig()
105
77
  if tomllib is None:
106
78
  raise RuntimeError("tomllib is required to read config.toml")
107
79
  data = tomllib.loads(self.config_path.read_text(encoding="utf-8"))
108
80
  return AppConfig(
109
- base_url=data.get("base_url"),
110
- anon_key=data.get("anon_key"),
111
81
  output=data.get("output", "text"),
112
- tls_insecure=bool(data.get("tls_insecure", False)),
113
- ca_cert_file=data.get("ca_cert_file"),
114
82
  )
115
83
 
116
84
  def save_config(self, config: AppConfig) -> None:
117
85
  self.ensure_base_dir()
118
86
  lines = []
119
- if config.base_url and config.base_url != DEFAULT_BASE_URL:
120
- lines.append(f'base_url = "{config.base_url}"')
121
- if config.anon_key and config.anon_key != DEFAULT_ANON_KEY:
122
- lines.append(f'anon_key = "{config.anon_key}"')
123
87
  if config.output:
124
88
  lines.append(f'output = "{config.output}"')
125
- if config.tls_insecure:
126
- lines.append("tls_insecure = true")
127
- if config.ca_cert_file:
128
- lines.append(f'ca_cert_file = "{config.ca_cert_file}"')
129
89
  self.config_path.write_text("\n".join(lines) + ("\n" if lines else ""), encoding="utf-8")
130
90
 
131
91
  def load_auth(self) -> AuthState | None:
@@ -210,8 +170,8 @@ def env_auth_state() -> AuthState | None:
210
170
  expires_at = int(expires_at_raw) if expires_at_raw and expires_at_raw.isdigit() else None
211
171
  return AuthState(
212
172
  source="env",
213
- base_url=os.environ.get("POWERBASE_BASE_URL"),
214
- anon_key=os.environ.get("POWERBASE_ANON_KEY"),
173
+ base_url=DEFAULT_BASE_URL,
174
+ anon_key=DEFAULT_ANON_KEY,
215
175
  session=AuthSession(
216
176
  access_token=access_token,
217
177
  refresh_token=refresh_token,
@@ -220,16 +180,6 @@ def env_auth_state() -> AuthState | None:
220
180
  )
221
181
 
222
182
 
223
- def merge_config_with_env(config: AppConfig) -> AppConfig:
224
- return AppConfig(
225
- base_url=os.environ.get("POWERBASE_BASE_URL") or config.base_url,
226
- anon_key=os.environ.get("POWERBASE_ANON_KEY") or config.anon_key,
227
- output=os.environ.get("POWERBASE_OUTPUT") or config.output,
228
- tls_insecure=env_flag("POWERBASE_TLS_INSECURE") or config.tls_insecure,
229
- ca_cert_file=os.environ.get("POWERBASE_CA_CERT_FILE") or config.ca_cert_file,
230
- )
231
-
232
-
233
183
  def merge_context_with_env(context: ContextState) -> ContextState:
234
184
  return ContextState(
235
185
  instance_id=os.environ.get("POWERBASE_INSTANCE_ID") or context.instance_id,
@@ -11,7 +11,7 @@ from typing import Iterator
11
11
  from urllib import request
12
12
  from urllib.error import HTTPError, URLError
13
13
 
14
- from .config import BUNDLED_CA_CERT_SENTINEL, AuthState, ConfigStore, env_auth_state, load_bundled_ca_cert
14
+ from .config import AuthState, ConfigStore, env_auth_state
15
15
 
16
16
  try:
17
17
  import fcntl
@@ -29,15 +29,10 @@ class SessionManager:
29
29
  store: ConfigStore,
30
30
  base_url: str | None,
31
31
  anon_key: str | None,
32
- *,
33
- tls_insecure: bool = False,
34
- ca_cert_file: str | None = None,
35
32
  ) -> None:
36
33
  self.store = store
37
34
  self.base_url = base_url
38
35
  self.anon_key = anon_key
39
- self.tls_insecure = tls_insecure
40
- self.ca_cert_file = ca_cert_file
41
36
 
42
37
  def _login_guidance(self) -> str:
43
38
  return (
@@ -47,20 +42,6 @@ class SessionManager:
47
42
  )
48
43
 
49
44
  def _urlopen(self, req: request.Request):
50
- if self.tls_insecure:
51
- context = ssl.create_default_context()
52
- context.check_hostname = False
53
- context.verify_mode = ssl.CERT_NONE
54
- return request.urlopen(req, context=context)
55
- if self.ca_cert_file:
56
- if self.ca_cert_file == BUNDLED_CA_CERT_SENTINEL:
57
- bundled_ca_cert = load_bundled_ca_cert()
58
- if not bundled_ca_cert:
59
- raise SessionError("Bundled test CA certificate is unavailable.")
60
- context = ssl.create_default_context(cadata=bundled_ca_cert)
61
- else:
62
- context = ssl.create_default_context(cafile=self.ca_cert_file)
63
- return request.urlopen(req, context=context)
64
45
  return request.urlopen(req)
65
46
 
66
47
  def get_auth_state(self) -> AuthState | None:
@@ -7,7 +7,7 @@ from typing import Any
7
7
  from urllib import request
8
8
  from urllib.error import HTTPError, URLError
9
9
 
10
- from .config import BUNDLED_CA_CERT_SENTINEL, AppConfig, load_bundled_ca_cert
10
+ from .config import AppConfig
11
11
  from .session import SessionError, SessionManager
12
12
 
13
13
 
@@ -35,20 +35,6 @@ class PowerbaseTransport:
35
35
  )
36
36
 
37
37
  def _urlopen(self, req: request.Request):
38
- if self.config.tls_insecure:
39
- context = ssl.create_default_context()
40
- context.check_hostname = False
41
- context.verify_mode = ssl.CERT_NONE
42
- return request.urlopen(req, context=context)
43
- if self.config.ca_cert_file:
44
- if self.config.ca_cert_file == BUNDLED_CA_CERT_SENTINEL:
45
- bundled_ca_cert = load_bundled_ca_cert()
46
- if not bundled_ca_cert:
47
- raise ApiError("Bundled test CA certificate is unavailable.")
48
- context = ssl.create_default_context(cadata=bundled_ca_cert)
49
- else:
50
- context = ssl.create_default_context(cafile=self.config.ca_cert_file)
51
- return request.urlopen(req, context=context)
52
38
  return request.urlopen(req)
53
39
 
54
40
  def _build_headers(
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: powerbase-cli
3
- Version: 0.1.5
3
+ Version: 0.2.0
4
4
  Summary: CLI for operating Powerbase console workflows
5
5
  Author: Powerbase
6
6
  Requires-Python: >=3.11
@@ -41,10 +41,12 @@ Database model:
41
41
  Install from PyPI:
42
42
 
43
43
  ```bash
44
- python -m pip install powerbase-cli
44
+ python -m pip install --upgrade powerbase-cli==0.2.0
45
45
  powerbase --help
46
46
  ```
47
47
 
48
+ Version `0.2.x` is the production-pinned release line and always targets `https://console.appbuild.chat`.
49
+
48
50
  From the repository root during development:
49
51
 
50
52
  ```bash
@@ -121,7 +123,7 @@ powerbase auth token-set \
121
123
  --expires-at 1760000000
122
124
  ```
123
125
 
124
- Use `--base-url` or `--anon-key` here only when you intentionally want to override the built-in deployment defaults.
126
+ The CLI is pinned to the production Powerbase console deployment and no longer exposes endpoint override flags.
125
127
 
126
128
  ### Check Auth State
127
129
 
@@ -12,7 +12,6 @@ src/powerbase_cli.egg-info/SOURCES.txt
12
12
  src/powerbase_cli.egg-info/dependency_links.txt
13
13
  src/powerbase_cli.egg-info/entry_points.txt
14
14
  src/powerbase_cli.egg-info/top_level.txt
15
- src/powerbase_cli/certs/powerbase-test-ca.pem
16
15
  src/powerbase_cli/commands/__init__.py
17
16
  src/powerbase_cli/commands/agent.py
18
17
  src/powerbase_cli/commands/auth.py
@@ -16,7 +16,6 @@ from powerbase_cli.commands.auth import handle_auth_wait as auth_handle_auth_wai
16
16
  from powerbase_cli.commands.agent import handle_agent_chat as agent_handle_agent_chat
17
17
  from powerbase_cli.commands.shared import resolve_config as shared_resolve_config
18
18
  from powerbase_cli.config import (
19
- BUNDLED_CA_CERT_SENTINEL,
20
19
  AppConfig,
21
20
  AuthSession,
22
21
  AuthState,
@@ -82,20 +81,12 @@ class CliCommandTests(unittest.TestCase):
82
81
  def test_resolve_config_falls_back_to_builtin_service_defaults(self) -> None:
83
82
  with tempfile.TemporaryDirectory() as temp_dir:
84
83
  store = ConfigStore(Path(temp_dir))
85
- args = Namespace(
86
- config_dir=temp_dir,
87
- base_url=None,
88
- anon_key=None,
89
- json=False,
90
- insecure=False,
91
- ca_cert_file=None,
92
- )
84
+ args = Namespace(config_dir=temp_dir, json=False)
93
85
  resolved = shared_resolve_config(args, store)
94
86
  self.assertEqual(resolved.base_url, DEFAULT_BASE_URL)
95
87
  self.assertEqual(resolved.anon_key, DEFAULT_ANON_KEY)
96
- self.assertEqual(resolved.ca_cert_file, BUNDLED_CA_CERT_SENTINEL)
97
88
 
98
- def test_resolve_config_falls_back_to_saved_auth_values(self) -> None:
89
+ def test_resolve_config_ignores_saved_auth_endpoint_overrides(self) -> None:
99
90
  with tempfile.TemporaryDirectory() as temp_dir:
100
91
  store = ConfigStore(Path(temp_dir))
101
92
  store.save_auth(
@@ -106,10 +97,10 @@ class CliCommandTests(unittest.TestCase):
106
97
  session=AuthSession(access_token="token"),
107
98
  )
108
99
  )
109
- args = Namespace(config_dir=temp_dir, base_url=None, anon_key=None, json=False, insecure=False, ca_cert_file=None)
100
+ args = Namespace(config_dir=temp_dir, json=False)
110
101
  resolved = shared_resolve_config(args, store)
111
- self.assertEqual(resolved.base_url, "https://console.example.com")
112
- self.assertEqual(resolved.anon_key, "anon")
102
+ self.assertEqual(resolved.base_url, DEFAULT_BASE_URL)
103
+ self.assertEqual(resolved.anon_key, DEFAULT_ANON_KEY)
113
104
 
114
105
  def test_auth_login_saves_polled_session(self) -> None:
115
106
  with tempfile.TemporaryDirectory() as temp_dir:
@@ -117,12 +108,9 @@ class CliCommandTests(unittest.TestCase):
117
108
  config = AppConfig(base_url="https://console.example.com", anon_key="anon")
118
109
  args = Namespace(
119
110
  config_dir=temp_dir,
120
- base_url=None,
121
- anon_key=None,
122
111
  json=True,
123
112
  login_timeout=300,
124
113
  login_id="login-1",
125
- insecure=False,
126
114
  )
127
115
 
128
116
  with mock.patch("powerbase_cli.commands.auth.build_api", return_value=(store, config, None, None, FakeApi())):
@@ -142,10 +130,7 @@ class CliCommandTests(unittest.TestCase):
142
130
  config = AppConfig(base_url="https://console.example.com", anon_key="anon")
143
131
  args = Namespace(
144
132
  config_dir=temp_dir,
145
- base_url=None,
146
- anon_key=None,
147
133
  json=True,
148
- insecure=False,
149
134
  )
150
135
 
151
136
  with mock.patch("powerbase_cli.commands.auth.build_api", return_value=(store, config, None, None, FakeApiStartOnly())):
@@ -175,12 +160,9 @@ class CliCommandTests(unittest.TestCase):
175
160
  config = AppConfig(base_url="https://console.example.com", anon_key="anon")
176
161
  args = Namespace(
177
162
  config_dir=temp_dir,
178
- base_url=None,
179
- anon_key=None,
180
163
  json=False,
181
164
  login_timeout=5,
182
165
  login_id="login-pending",
183
- insecure=False,
184
166
  )
185
167
 
186
168
  with mock.patch("powerbase_cli.commands.auth.build_api", return_value=(store, config, None, None, FakeApiPending())):
@@ -197,10 +179,7 @@ class CliCommandTests(unittest.TestCase):
197
179
  def test_agent_chat_streams_jsonl(self) -> None:
198
180
  args = Namespace(
199
181
  config_dir=None,
200
- base_url=None,
201
- anon_key=None,
202
182
  json=False,
203
- insecure=False,
204
183
  instance_id="inst-1",
205
184
  provider="cursor",
206
185
  session_id="sess-1",
@@ -21,8 +21,8 @@ class CliHelpTests(unittest.TestCase):
21
21
  self.assertIn("Operate Powerbase console workflows", help_text)
22
22
  self.assertIn("agent-driven development", help_text)
23
23
  self.assertIn("default implementation interface", help_text)
24
- self.assertIn("--insecure", help_text)
25
- self.assertIn("--ca-cert", help_text)
24
+ self.assertIn("--config-dir", help_text)
25
+ self.assertIn("--json", help_text)
26
26
 
27
27
  def test_auth_login_help_mentions_wait_follow_up(self) -> None:
28
28
  parser = build_parser()
@@ -142,8 +142,8 @@ class CliHelpTests(unittest.TestCase):
142
142
  self.assertIn("release", help_text)
143
143
 
144
144
  def test_normalize_global_argv_moves_root_flags_forward(self) -> None:
145
- normalized = normalize_global_argv(["auth", "status", "--json", "--config-dir", "/tmp/pb", "--insecure"])
146
- self.assertEqual(normalized, ["--json", "--config-dir", "/tmp/pb", "--insecure", "auth", "status"])
145
+ normalized = normalize_global_argv(["auth", "status", "--json", "--config-dir", "/tmp/pb"])
146
+ self.assertEqual(normalized, ["--json", "--config-dir", "/tmp/pb", "auth", "status"])
147
147
 
148
148
  def test_main_normalizes_sys_argv_when_called_without_explicit_args(self) -> None:
149
149
  with mock.patch.object(sys, "argv", ["powerbase", "auth", "status", "--json"]):
@@ -17,18 +17,11 @@ from powerbase_cli.config import (
17
17
  AuthState,
18
18
  ConfigStore,
19
19
  ContextState,
20
- load_bundled_ca_cert,
21
- merge_config_with_env,
22
20
  merge_context_with_env,
23
21
  )
24
22
 
25
23
 
26
24
  class ConfigStoreTests(unittest.TestCase):
27
- def test_load_bundled_ca_cert_returns_pem(self) -> None:
28
- cert_pem = load_bundled_ca_cert()
29
- assert cert_pem is not None
30
- self.assertIn("BEGIN CERTIFICATE", cert_pem)
31
-
32
25
  def test_app_config_uses_builtin_service_defaults(self) -> None:
33
26
  config = AppConfig()
34
27
  self.assertEqual(config.base_url, DEFAULT_BASE_URL)
@@ -76,18 +69,11 @@ class ConfigStoreTests(unittest.TestCase):
76
69
  self.assertEqual(loaded.org_id, "o1")
77
70
  self.assertEqual(loaded.branch, "main")
78
71
 
79
- def test_merge_env_overrides(self) -> None:
72
+ def test_merge_context_env_overrides(self) -> None:
80
73
  old = dict(os.environ)
81
74
  try:
82
- os.environ["POWERBASE_BASE_URL"] = "https://env.example.com"
83
75
  os.environ["POWERBASE_INSTANCE_ID"] = "env-instance"
84
- os.environ["POWERBASE_TLS_INSECURE"] = "true"
85
- os.environ["POWERBASE_CA_CERT_FILE"] = "/tmp/test-ca.pem"
86
- merged_config = merge_config_with_env(AppConfig(base_url="https://file.example.com", anon_key="a"))
87
76
  merged_context = merge_context_with_env(ContextState(instance_id="file-instance", branch="main"))
88
- self.assertEqual(merged_config.base_url, "https://env.example.com")
89
- self.assertTrue(merged_config.tls_insecure)
90
- self.assertEqual(merged_config.ca_cert_file, "/tmp/test-ca.pem")
91
77
  self.assertEqual(merged_context.instance_id, "env-instance")
92
78
  finally:
93
79
  os.environ.clear()
@@ -0,0 +1,97 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ import os
5
+ import sys
6
+ import tempfile
7
+ import unittest
8
+ from pathlib import Path
9
+ from unittest import mock
10
+
11
+ sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "src"))
12
+
13
+ from powerbase_cli.config import AuthSession, AuthState, ConfigStore
14
+ from powerbase_cli.session import SessionError, SessionManager
15
+
16
+
17
+ class FakeResponse:
18
+ def __init__(self, payload: dict[str, object]) -> None:
19
+ self.payload = payload
20
+
21
+ def __enter__(self) -> "FakeResponse":
22
+ return self
23
+
24
+ def __exit__(self, exc_type, exc, tb) -> None:
25
+ return None
26
+
27
+ def read(self) -> bytes:
28
+ return json.dumps(self.payload).encode("utf-8")
29
+
30
+
31
+ class SessionManagerTests(unittest.TestCase):
32
+ def test_refresh_without_auth_instructs_user_to_log_in_again(self) -> None:
33
+ with tempfile.TemporaryDirectory() as temp_dir:
34
+ store = ConfigStore(Path(temp_dir))
35
+ manager = SessionManager(store, "https://console.example.com", "anon")
36
+
37
+ with self.assertRaises(SessionError) as ctx:
38
+ manager.refresh()
39
+
40
+ self.assertIn("No authentication session available", str(ctx.exception))
41
+ self.assertIn("powerbase auth login --json", str(ctx.exception))
42
+ self.assertIn("powerbase auth wait --login-id ... --json", str(ctx.exception))
43
+
44
+ def test_refresh_updates_saved_auth_file(self) -> None:
45
+ with tempfile.TemporaryDirectory() as temp_dir:
46
+ store = ConfigStore(Path(temp_dir))
47
+ store.save_auth(
48
+ AuthState(
49
+ source="login",
50
+ base_url="https://console.example.com",
51
+ anon_key="anon",
52
+ session=AuthSession(
53
+ access_token="old-access",
54
+ refresh_token="old-refresh",
55
+ expires_at=1,
56
+ ),
57
+ )
58
+ )
59
+ manager = SessionManager(store, "https://console.example.com", "anon")
60
+
61
+ with mock.patch("powerbase_cli.session.request.urlopen", return_value=FakeResponse({
62
+ "access_token": "new-access",
63
+ "refresh_token": "new-refresh",
64
+ "expires_at": 9999999999,
65
+ "token_type": "bearer",
66
+ "user": {"id": "user-1"},
67
+ })):
68
+ refreshed = manager.refresh()
69
+
70
+ self.assertEqual(refreshed.session.access_token, "new-access")
71
+ saved = store.load_auth()
72
+ assert saved is not None
73
+ self.assertEqual(saved.session.refresh_token, "new-refresh")
74
+
75
+ def test_env_session_can_refresh_without_writing_auth_file(self) -> None:
76
+ with tempfile.TemporaryDirectory() as temp_dir:
77
+ store = ConfigStore(Path(temp_dir))
78
+ manager = SessionManager(store, "https://console.example.com", "anon")
79
+ old_env = dict(os.environ)
80
+ try:
81
+ os.environ["POWERBASE_ACCESS_TOKEN"] = "env-access"
82
+ os.environ["POWERBASE_REFRESH_TOKEN"] = "env-refresh"
83
+ os.environ["POWERBASE_EXPIRES_AT"] = "1"
84
+ with mock.patch("powerbase_cli.session.request.urlopen", return_value=FakeResponse({
85
+ "access_token": "env-new-access",
86
+ "refresh_token": "env-new-refresh",
87
+ "expires_at": 9999999999,
88
+ "token_type": "bearer",
89
+ })):
90
+ refreshed = manager.ensure_valid()
91
+ assert refreshed is not None
92
+ self.assertEqual(refreshed.session.access_token, "env-new-access")
93
+ self.assertFalse(store.auth_path.exists())
94
+ finally:
95
+ os.environ.clear()
96
+ os.environ.update(old_env)
97
+
@@ -11,7 +11,7 @@ from urllib.error import HTTPError, URLError
11
11
 
12
12
  sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "src"))
13
13
 
14
- from powerbase_cli.config import BUNDLED_CA_CERT_SENTINEL, AppConfig, AuthSession, AuthState, ConfigStore
14
+ from powerbase_cli.config import AppConfig, AuthSession, AuthState, ConfigStore
15
15
  from powerbase_cli.session import SessionManager
16
16
  from powerbase_cli.transport import ApiError, PowerbaseTransport
17
17
 
@@ -51,71 +51,6 @@ class PowerbaseTransportTests(unittest.TestCase):
51
51
  self.assertIn("powerbase auth wait --login-id ... --json", str(ctx.exception))
52
52
  self.assertEqual(urlopen_mock.call_count, 0)
53
53
 
54
- def test_invoke_uses_unverified_tls_context_when_insecure(self) -> None:
55
- with tempfile.TemporaryDirectory() as temp_dir:
56
- store = ConfigStore(Path(temp_dir))
57
- manager = SessionManager(store, "https://console.example.com", "anon", tls_insecure=True)
58
- transport = PowerbaseTransport(
59
- AppConfig(base_url="https://console.example.com", anon_key="anon", tls_insecure=True),
60
- manager,
61
- )
62
-
63
- with mock.patch(
64
- "powerbase_cli.transport.request.urlopen",
65
- return_value=FakeResponse({"success": True, "data": {"ok": True}}),
66
- ) as urlopen_mock:
67
- result = transport.invoke("instances", method="GET", requires_auth=False)
68
-
69
- self.assertEqual(result["data"]["ok"], True)
70
- context = urlopen_mock.call_args.kwargs["context"]
71
- self.assertFalse(context.check_hostname)
72
-
73
- def test_invoke_uses_ca_cert_context_when_configured(self) -> None:
74
- with tempfile.TemporaryDirectory() as temp_dir:
75
- store = ConfigStore(Path(temp_dir))
76
- manager = SessionManager(store, "https://console.example.com", "anon", ca_cert_file="/tmp/test-ca.pem")
77
- transport = PowerbaseTransport(
78
- AppConfig(base_url="https://console.example.com", anon_key="anon", ca_cert_file="/tmp/test-ca.pem"),
79
- manager,
80
- )
81
-
82
- with mock.patch("powerbase_cli.transport.ssl.create_default_context") as context_factory:
83
- fake_context = object()
84
- context_factory.return_value = fake_context
85
- with mock.patch(
86
- "powerbase_cli.transport.request.urlopen",
87
- return_value=FakeResponse({"success": True, "data": {"ok": True}}),
88
- ) as urlopen_mock:
89
- result = transport.invoke("instances", method="GET", requires_auth=False)
90
-
91
- self.assertEqual(result["data"]["ok"], True)
92
- context_factory.assert_called_once_with(cafile="/tmp/test-ca.pem")
93
- self.assertIs(urlopen_mock.call_args.kwargs["context"], fake_context)
94
-
95
- def test_invoke_uses_bundled_ca_cert_when_configured(self) -> None:
96
- with tempfile.TemporaryDirectory() as temp_dir:
97
- store = ConfigStore(Path(temp_dir))
98
- manager = SessionManager(store, "https://console.example.com", "anon", ca_cert_file=BUNDLED_CA_CERT_SENTINEL)
99
- transport = PowerbaseTransport(
100
- AppConfig(base_url="https://console.example.com", anon_key="anon", ca_cert_file=BUNDLED_CA_CERT_SENTINEL),
101
- manager,
102
- )
103
-
104
- with mock.patch("powerbase_cli.transport.load_bundled_ca_cert", return_value="PEM DATA") as bundled_cert:
105
- with mock.patch("powerbase_cli.transport.ssl.create_default_context") as context_factory:
106
- fake_context = object()
107
- context_factory.return_value = fake_context
108
- with mock.patch(
109
- "powerbase_cli.transport.request.urlopen",
110
- return_value=FakeResponse({"success": True, "data": {"ok": True}}),
111
- ) as urlopen_mock:
112
- result = transport.invoke("instances", method="GET", requires_auth=False)
113
-
114
- self.assertEqual(result["data"]["ok"], True)
115
- bundled_cert.assert_called_once_with()
116
- context_factory.assert_called_once_with(cadata="PEM DATA")
117
- self.assertIs(urlopen_mock.call_args.kwargs["context"], fake_context)
118
-
119
54
  def test_invoke_refreshes_and_retries_once_on_401(self) -> None:
120
55
  with tempfile.TemporaryDirectory() as temp_dir:
121
56
  store = ConfigStore(Path(temp_dir))
@@ -1,21 +0,0 @@
1
- -----BEGIN CERTIFICATE-----
2
- MIIDhDCCAmygAwIBAgIUWu1JfeyC2qw56+7PUB5QY9w1MG8wDQYJKoZIhvcNAQEL
3
- BQAwHjEcMBoGA1UEAwwTNi4xMi4yMzUuMTY1Lm5pcC5pbzAeFw0yNjA0MDcwNTUx
4
- MjZaFw0yNzA0MDcwNTUxMjZaMB4xHDAaBgNVBAMMEzYuMTIuMjM1LjE2NS5uaXAu
5
- aW8wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDVaa9eQzG9t/WNcoP8
6
- vJDX41oELoz/LOVzmr9zuFK3jQnIrVjFW8MdBHq1pOBLyHjKtnhKPo1n0br4/iPP
7
- /TiJNwAuybN6iiSxWSsGpzFv7gIyJivdr65khzeLNda6HyBFxsRsVZAKKe8tueB4
8
- FQM0YWxHkfAMw5bigDumZq3wzLUuvB7EtscVtl0dV0tcqovLq1Lg9/eBDSqfWuxv
9
- hW9iROv23ryJETE/8Wh/2Gd5UV0E8CEX8As30+5nJ2jGF6O8abDRipvqc67+5v7h
10
- dEXT2xIg4Fh8DAhlbgzM6Sj6I70pWiro+Q+N8GWvpJeJYGZu7J97eEOw+u1C2pCV
11
- sbiBAgMBAAGjgbkwgbYwHQYDVR0OBBYEFODuAm1rmrl2GyZBcClH9HVE9kGMMB8G
12
- A1UdIwQYMBaAFODuAm1rmrl2GyZBcClH9HVE9kGMMA8GA1UdEwEB/wQFMAMBAf8w
13
- YwYDVR0RBFwwWoITNi4xMi4yMzUuMTY1Lm5pcC5pb4IbY29uc29sZS42LjEyLjIz
14
- NS4xNjUubmlwLmlvghUqLjYuMTIuMjM1LjE2NS5uaXAuaW+CCWxvY2FsaG9zdIcE
15
- fwAAATANBgkqhkiG9w0BAQsFAAOCAQEAmvCeJ4Xnx8rXmU+oxiDiDZRfUK204Ta7
16
- hztXu9LvxheW99p2R1AP2F7VUJOTq31HY9/r2p3qCEyz8F4nc/GPunHfF3y8mMiB
17
- beFDdwrw8NWTRLGlOJynjsOXtkRkFa03DTKa4x9roZo10S+imDk1/DywWlv7UoAK
18
- 9OsUB1zb8c6m7uZXrOTAZOzvO2fBrdymXnQ4tMvl54iyVT8X1rft5NUywfBzCtzB
19
- g/OxLM2zJg3kz9kFztRuf1e07Tz6cqSy2CzClvhxaYJSfnlT2b73SceKy3kHn7Sh
20
- VXA8yjqcTjk6wkMlHueIWnjnjYkRSpFjw3/ODNXbGJjxh+86l/ekPQ==
21
- -----END CERTIFICATE-----
@@ -1,194 +0,0 @@
1
- from __future__ import annotations
2
-
3
- import json
4
- import os
5
- import sys
6
- import tempfile
7
- import unittest
8
- from pathlib import Path
9
- from unittest import mock
10
-
11
- sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "src"))
12
-
13
- from powerbase_cli.config import BUNDLED_CA_CERT_SENTINEL, AuthSession, AuthState, ConfigStore
14
- from powerbase_cli.session import SessionError, SessionManager
15
-
16
-
17
- class FakeResponse:
18
- def __init__(self, payload: dict[str, object]) -> None:
19
- self.payload = payload
20
-
21
- def __enter__(self) -> "FakeResponse":
22
- return self
23
-
24
- def __exit__(self, exc_type, exc, tb) -> None:
25
- return None
26
-
27
- def read(self) -> bytes:
28
- return json.dumps(self.payload).encode("utf-8")
29
-
30
-
31
- class SessionManagerTests(unittest.TestCase):
32
- def test_refresh_without_auth_instructs_user_to_log_in_again(self) -> None:
33
- with tempfile.TemporaryDirectory() as temp_dir:
34
- store = ConfigStore(Path(temp_dir))
35
- manager = SessionManager(store, "https://console.example.com", "anon")
36
-
37
- with self.assertRaises(SessionError) as ctx:
38
- manager.refresh()
39
-
40
- self.assertIn("No authentication session available", str(ctx.exception))
41
- self.assertIn("powerbase auth login --json", str(ctx.exception))
42
- self.assertIn("powerbase auth wait --login-id ... --json", str(ctx.exception))
43
-
44
- def test_refresh_updates_saved_auth_file(self) -> None:
45
- with tempfile.TemporaryDirectory() as temp_dir:
46
- store = ConfigStore(Path(temp_dir))
47
- store.save_auth(
48
- AuthState(
49
- source="login",
50
- base_url="https://console.example.com",
51
- anon_key="anon",
52
- session=AuthSession(
53
- access_token="old-access",
54
- refresh_token="old-refresh",
55
- expires_at=1,
56
- ),
57
- )
58
- )
59
- manager = SessionManager(store, "https://console.example.com", "anon")
60
-
61
- with mock.patch("powerbase_cli.session.request.urlopen", return_value=FakeResponse({
62
- "access_token": "new-access",
63
- "refresh_token": "new-refresh",
64
- "expires_at": 9999999999,
65
- "token_type": "bearer",
66
- "user": {"id": "user-1"},
67
- })):
68
- refreshed = manager.refresh()
69
-
70
- self.assertEqual(refreshed.session.access_token, "new-access")
71
- saved = store.load_auth()
72
- assert saved is not None
73
- self.assertEqual(saved.session.refresh_token, "new-refresh")
74
-
75
- def test_env_session_can_refresh_without_writing_auth_file(self) -> None:
76
- with tempfile.TemporaryDirectory() as temp_dir:
77
- store = ConfigStore(Path(temp_dir))
78
- manager = SessionManager(store, "https://console.example.com", "anon")
79
- old_env = dict(os.environ)
80
- try:
81
- os.environ["POWERBASE_ACCESS_TOKEN"] = "env-access"
82
- os.environ["POWERBASE_REFRESH_TOKEN"] = "env-refresh"
83
- os.environ["POWERBASE_EXPIRES_AT"] = "1"
84
- os.environ["POWERBASE_BASE_URL"] = "https://console.example.com"
85
- os.environ["POWERBASE_ANON_KEY"] = "anon"
86
- with mock.patch("powerbase_cli.session.request.urlopen", return_value=FakeResponse({
87
- "access_token": "env-new-access",
88
- "refresh_token": "env-new-refresh",
89
- "expires_at": 9999999999,
90
- "token_type": "bearer",
91
- })):
92
- refreshed = manager.ensure_valid()
93
- assert refreshed is not None
94
- self.assertEqual(refreshed.session.access_token, "env-new-access")
95
- self.assertFalse(store.auth_path.exists())
96
- finally:
97
- os.environ.clear()
98
- os.environ.update(old_env)
99
-
100
- def test_refresh_uses_unverified_tls_context_when_insecure(self) -> None:
101
- with tempfile.TemporaryDirectory() as temp_dir:
102
- store = ConfigStore(Path(temp_dir))
103
- store.save_auth(
104
- AuthState(
105
- source="login",
106
- base_url="https://console.example.com",
107
- anon_key="anon",
108
- session=AuthSession(access_token="old-access", refresh_token="old-refresh", expires_at=1),
109
- )
110
- )
111
- manager = SessionManager(store, "https://console.example.com", "anon", tls_insecure=True)
112
-
113
- with mock.patch(
114
- "powerbase_cli.session.request.urlopen",
115
- return_value=FakeResponse(
116
- {
117
- "access_token": "new-access",
118
- "refresh_token": "new-refresh",
119
- "expires_at": 9999999999,
120
- "token_type": "bearer",
121
- }
122
- ),
123
- ) as urlopen_mock:
124
- manager.refresh()
125
-
126
- context = urlopen_mock.call_args.kwargs["context"]
127
- self.assertFalse(context.check_hostname)
128
-
129
- def test_refresh_uses_ca_cert_context_when_configured(self) -> None:
130
- with tempfile.TemporaryDirectory() as temp_dir:
131
- store = ConfigStore(Path(temp_dir))
132
- store.save_auth(
133
- AuthState(
134
- source="login",
135
- base_url="https://console.example.com",
136
- anon_key="anon",
137
- session=AuthSession(access_token="old-access", refresh_token="old-refresh", expires_at=1),
138
- )
139
- )
140
- manager = SessionManager(store, "https://console.example.com", "anon", ca_cert_file="/tmp/test-ca.pem")
141
-
142
- with mock.patch("powerbase_cli.session.ssl.create_default_context") as context_factory:
143
- fake_context = object()
144
- context_factory.return_value = fake_context
145
- with mock.patch(
146
- "powerbase_cli.session.request.urlopen",
147
- return_value=FakeResponse(
148
- {
149
- "access_token": "new-access",
150
- "refresh_token": "new-refresh",
151
- "expires_at": 9999999999,
152
- "token_type": "bearer",
153
- }
154
- ),
155
- ) as urlopen_mock:
156
- manager.refresh()
157
-
158
- context_factory.assert_called_once_with(cafile="/tmp/test-ca.pem")
159
- self.assertIs(urlopen_mock.call_args.kwargs["context"], fake_context)
160
-
161
- def test_refresh_uses_bundled_ca_cert_when_configured(self) -> None:
162
- with tempfile.TemporaryDirectory() as temp_dir:
163
- store = ConfigStore(Path(temp_dir))
164
- store.save_auth(
165
- AuthState(
166
- source="login",
167
- base_url="https://console.example.com",
168
- anon_key="anon",
169
- session=AuthSession(access_token="old-access", refresh_token="old-refresh", expires_at=1),
170
- )
171
- )
172
- manager = SessionManager(store, "https://console.example.com", "anon", ca_cert_file=BUNDLED_CA_CERT_SENTINEL)
173
-
174
- with mock.patch("powerbase_cli.session.load_bundled_ca_cert", return_value="PEM DATA") as bundled_cert:
175
- with mock.patch("powerbase_cli.session.ssl.create_default_context") as context_factory:
176
- fake_context = object()
177
- context_factory.return_value = fake_context
178
- with mock.patch(
179
- "powerbase_cli.session.request.urlopen",
180
- return_value=FakeResponse(
181
- {
182
- "access_token": "new-access",
183
- "refresh_token": "new-refresh",
184
- "expires_at": 9999999999,
185
- "token_type": "bearer",
186
- }
187
- ),
188
- ) as urlopen_mock:
189
- manager.refresh()
190
-
191
- bundled_cert.assert_called_once_with()
192
- context_factory.assert_called_once_with(cadata="PEM DATA")
193
- self.assertIs(urlopen_mock.call_args.kwargs["context"], fake_context)
194
-
File without changes