buildai-cli 0.3.44__tar.gz → 0.3.46__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.
- {buildai_cli-0.3.44 → buildai_cli-0.3.46}/PKG-INFO +1 -1
- {buildai_cli-0.3.44 → buildai_cli-0.3.46}/cli/auth_local.py +10 -15
- {buildai_cli-0.3.44 → buildai_cli-0.3.46}/cli/context.py +27 -2
- {buildai_cli-0.3.44 → buildai_cli-0.3.46}/cli/ops_init.py +5 -3
- {buildai_cli-0.3.44 → buildai_cli-0.3.46}/pyproject.toml +1 -1
- {buildai_cli-0.3.44 → buildai_cli-0.3.46}/.gitignore +0 -0
- {buildai_cli-0.3.44 → buildai_cli-0.3.46}/AGENTS.md +0 -0
- {buildai_cli-0.3.44 → buildai_cli-0.3.46}/CLAUDE.md +0 -0
- {buildai_cli-0.3.44 → buildai_cli-0.3.46}/buildai_bootstrap.py +0 -0
- {buildai_cli-0.3.44 → buildai_cli-0.3.46}/cli/__init__.py +0 -0
- {buildai_cli-0.3.44 → buildai_cli-0.3.46}/cli/_has_core.py +0 -0
- {buildai_cli-0.3.44 → buildai_cli-0.3.46}/cli/commands/__init__.py +0 -0
- {buildai_cli-0.3.44 → buildai_cli-0.3.46}/cli/commands/api_proxy.py +0 -0
- {buildai_cli-0.3.44 → buildai_cli-0.3.46}/cli/commands/auth.py +0 -0
- {buildai_cli-0.3.44 → buildai_cli-0.3.46}/cli/commands/db/__init__.py +0 -0
- {buildai_cli-0.3.44 → buildai_cli-0.3.46}/cli/commands/db/common.py +0 -0
- {buildai_cli-0.3.44 → buildai_cli-0.3.46}/cli/commands/db/migrate.py +0 -0
- {buildai_cli-0.3.44 → buildai_cli-0.3.46}/cli/commands/db/query.py +0 -0
- {buildai_cli-0.3.44 → buildai_cli-0.3.46}/cli/commands/db/schema.py +0 -0
- {buildai_cli-0.3.44 → buildai_cli-0.3.46}/cli/commands/db/status.py +0 -0
- {buildai_cli-0.3.44 → buildai_cli-0.3.46}/cli/commands/dev.py +0 -0
- {buildai_cli-0.3.44 → buildai_cli-0.3.46}/cli/commands/doctor.py +0 -0
- {buildai_cli-0.3.44 → buildai_cli-0.3.46}/cli/config.py +0 -0
- {buildai_cli-0.3.44 → buildai_cli-0.3.46}/cli/console.py +0 -0
- {buildai_cli-0.3.44 → buildai_cli-0.3.46}/cli/guard.py +0 -0
- {buildai_cli-0.3.44 → buildai_cli-0.3.46}/cli/internal_api.py +0 -0
- {buildai_cli-0.3.44 → buildai_cli-0.3.46}/cli/main.py +0 -0
- {buildai_cli-0.3.44 → buildai_cli-0.3.46}/cli/nl_query/__init__.py +0 -0
- {buildai_cli-0.3.44 → buildai_cli-0.3.46}/cli/nl_query/dataset_tools.py +0 -0
- {buildai_cli-0.3.44 → buildai_cli-0.3.46}/cli/output.py +0 -0
- {buildai_cli-0.3.44 → buildai_cli-0.3.46}/cli/pagination.py +0 -0
|
@@ -95,18 +95,12 @@ class ResolvedLocalAuthProfile:
|
|
|
95
95
|
f'export ALLOYDB_IAM_AUTH_{suffix}="true"',
|
|
96
96
|
]
|
|
97
97
|
)
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
]
|
|
105
|
-
)
|
|
106
|
-
else:
|
|
107
|
-
exports.append(
|
|
108
|
-
f'export ALLOYDB_RUNTIME_IMPERSONATE_SA_{suffix}="{self.target_service_account}"'
|
|
109
|
-
)
|
|
98
|
+
exports.extend(
|
|
99
|
+
[
|
|
100
|
+
f'export ALLOYDB_RUNTIME_IMPERSONATE_SA_{suffix}="{self.target_service_account}"',
|
|
101
|
+
f'export ALLOYDB_USE_AUTH_PROXY_{suffix}="false"',
|
|
102
|
+
]
|
|
103
|
+
)
|
|
110
104
|
elif self.name == "db-admin-local" and self.target_db_user and self.target_service_account:
|
|
111
105
|
exports.extend(
|
|
112
106
|
[
|
|
@@ -200,10 +194,11 @@ def sanctioned_auth_profiles() -> tuple[LocalAuthProfile, ...]:
|
|
|
200
194
|
LocalAuthProfile(
|
|
201
195
|
name="engineers-dev",
|
|
202
196
|
audience="engineers",
|
|
203
|
-
summary="Use the engineer-facing read-only DB
|
|
197
|
+
summary="Use the engineer-facing read-only DB lane.",
|
|
204
198
|
purpose=(
|
|
205
|
-
"Use this for direct CLI database reads
|
|
206
|
-
"
|
|
199
|
+
"Use this for direct CLI database reads and schema inspection through the "
|
|
200
|
+
"engineer-facing service-account identity. Local API runtime parity should "
|
|
201
|
+
"use the service-runtime profiles instead."
|
|
207
202
|
),
|
|
208
203
|
),
|
|
209
204
|
LocalAuthProfile(
|
|
@@ -22,6 +22,7 @@ from dataclasses import dataclass
|
|
|
22
22
|
from typing import TYPE_CHECKING, AsyncGenerator
|
|
23
23
|
|
|
24
24
|
import asyncpg
|
|
25
|
+
from dal import scopes as dal_scopes
|
|
25
26
|
from infra.settings import Settings, get_settings
|
|
26
27
|
|
|
27
28
|
from infra import Database, get_logger
|
|
@@ -34,6 +35,22 @@ logger = get_logger(__name__)
|
|
|
34
35
|
# Environment variable to force local PostgreSQL (for test/CI)
|
|
35
36
|
USE_LOCAL_DB = os.getenv("USE_LOCAL_DB", "false").lower() == "true"
|
|
36
37
|
_ZERO_UUID = "00000000-0000-0000-0000-000000000000"
|
|
38
|
+
_READ_SUFFIXES = (".read", ".search", ".query", ".introspection")
|
|
39
|
+
_READ_PROFILE_SCOPES = frozenset(
|
|
40
|
+
scope
|
|
41
|
+
for scope in dal_scopes.ALL_SCOPES
|
|
42
|
+
if any(scope.endswith(suffix) for suffix in _READ_SUFFIXES)
|
|
43
|
+
)
|
|
44
|
+
_CLI_PROFILE_SCOPES: dict[str, frozenset[str]] = {
|
|
45
|
+
"internal_admin": frozenset(dal_scopes.ALL_SCOPES),
|
|
46
|
+
"internal_viewer": _READ_PROFILE_SCOPES,
|
|
47
|
+
"engineers-dev": _READ_PROFILE_SCOPES,
|
|
48
|
+
"developer": frozenset(dal_scopes.ALL_SCOPES),
|
|
49
|
+
"operator": frozenset(dal_scopes.ALL_SCOPES),
|
|
50
|
+
"ml_engineer": frozenset(dal_scopes.ALL_SCOPES),
|
|
51
|
+
"mcp": _READ_PROFILE_SCOPES,
|
|
52
|
+
"agent": frozenset(dal_scopes.ALL_SCOPES),
|
|
53
|
+
}
|
|
37
54
|
_UNRESTRICTED_CLI_PROFILES = frozenset(
|
|
38
55
|
{
|
|
39
56
|
"internal_admin",
|
|
@@ -47,6 +64,14 @@ _UNRESTRICTED_CLI_PROFILES = frozenset(
|
|
|
47
64
|
)
|
|
48
65
|
|
|
49
66
|
|
|
67
|
+
def scopes_for_cli_profile(profile: str) -> frozenset[str]:
|
|
68
|
+
"""Resolve one sanctioned CLI profile to its DAL scope set."""
|
|
69
|
+
resolved = _CLI_PROFILE_SCOPES.get(profile)
|
|
70
|
+
if resolved is None:
|
|
71
|
+
raise ValueError(f"Unknown CLI profile: {profile}")
|
|
72
|
+
return resolved
|
|
73
|
+
|
|
74
|
+
|
|
50
75
|
@dataclass(frozen=True)
|
|
51
76
|
class AdminConnectionConfig:
|
|
52
77
|
"""Describe the canonical admin connection the ops-plane CLI should prefer.
|
|
@@ -281,7 +306,7 @@ async def get_cli_context(
|
|
|
281
306
|
# Test/CI: wrap local connection in context
|
|
282
307
|
async with _local_connection(settings) as conn:
|
|
283
308
|
await _stamp_cli_session_contract(conn, profile=resolved_profile)
|
|
284
|
-
ctx =
|
|
309
|
+
ctx = Context.for_cli(conn, scopes=scopes_for_cli_profile(resolved_profile))
|
|
285
310
|
yield None, ctx
|
|
286
311
|
else:
|
|
287
312
|
# Development/Production: use infra.Database
|
|
@@ -289,7 +314,7 @@ async def get_cli_context(
|
|
|
289
314
|
try:
|
|
290
315
|
await db.connect()
|
|
291
316
|
await _stamp_cli_session_contract(db.conn, profile=resolved_profile)
|
|
292
|
-
ctx =
|
|
317
|
+
ctx = Context.for_cli(db, scopes=scopes_for_cli_profile(resolved_profile))
|
|
293
318
|
yield db, ctx
|
|
294
319
|
finally:
|
|
295
320
|
await db.close()
|
|
@@ -34,11 +34,12 @@ def _parse_env(value: str) -> str:
|
|
|
34
34
|
|
|
35
35
|
|
|
36
36
|
def _auth_env_prefix(settings_app_env: object) -> str:
|
|
37
|
-
|
|
37
|
+
normalized = str(getattr(settings_app_env, "value", settings_app_env)).strip().lower()
|
|
38
|
+
if normalized == "production":
|
|
38
39
|
return "PROD"
|
|
39
|
-
if
|
|
40
|
+
if normalized == "development":
|
|
40
41
|
return "DEV"
|
|
41
|
-
if
|
|
42
|
+
if normalized == "test":
|
|
42
43
|
return "DEV"
|
|
43
44
|
return "PREVIEW"
|
|
44
45
|
|
|
@@ -160,6 +161,7 @@ def init_ops_context(ctx: typer.Context):
|
|
|
160
161
|
os.environ[f"ALLOYDB_RUNTIME_IMPERSONATE_SA_{env_prefix}"] = (
|
|
161
162
|
"engineers-dev-sa@data-470400.iam.gserviceaccount.com"
|
|
162
163
|
)
|
|
164
|
+
os.environ[f"ALLOYDB_USE_AUTH_PROXY_{env_prefix}"] = "false"
|
|
163
165
|
auth_info.append("impersonate=engineers-dev-sa")
|
|
164
166
|
|
|
165
167
|
# Reload settings with overrides
|
|
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
|