dh-cli 0.6.3__tar.gz → 0.7.1__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.
- {dh_cli-0.6.3 → dh_cli-0.7.1}/PKG-INFO +1 -1
- {dh_cli-0.6.3 → dh_cli-0.7.1}/pyproject.toml +1 -1
- dh_cli-0.7.1/src/dh_cli/_identity.py +82 -0
- dh_cli-0.7.1/src/dh_cli/github_commands.py +794 -0
- dh_cli-0.7.1/tests/github/__init__.py +1 -0
- dh_cli-0.7.1/tests/github/conftest.py +197 -0
- dh_cli-0.7.1/tests/github/test_engine_role_cannot_read_github_pat.py +46 -0
- dh_cli-0.7.1/tests/github/test_identity.py +74 -0
- dh_cli-0.7.1/tests/github/test_login.py +272 -0
- dh_cli-0.7.1/tests/github/test_login_error_paths.py +152 -0
- dh_cli-0.7.1/tests/github/test_login_security.py +152 -0
- dh_cli-0.7.1/tests/github/test_logout.py +39 -0
- dh_cli-0.7.1/tests/github/test_rotate.py +226 -0
- dh_cli-0.7.1/tests/github/test_status.py +93 -0
- dh_cli-0.6.3/src/dh_cli/github_commands.py +0 -275
- {dh_cli-0.6.3 → dh_cli-0.7.1}/.gitignore +0 -0
- {dh_cli-0.6.3 → dh_cli-0.7.1}/LICENSE +0 -0
- {dh_cli-0.6.3 → dh_cli-0.7.1}/README.md +0 -0
- {dh_cli-0.6.3 → dh_cli-0.7.1}/src/dh_cli/__init__.py +0 -0
- {dh_cli-0.6.3 → dh_cli-0.7.1}/src/dh_cli/batch/__init__.py +0 -0
- {dh_cli-0.6.3 → dh_cli-0.7.1}/src/dh_cli/batch/aws_batch.py +0 -0
- {dh_cli-0.6.3 → dh_cli-0.7.1}/src/dh_cli/batch/commands/__init__.py +0 -0
- {dh_cli-0.6.3 → dh_cli-0.7.1}/src/dh_cli/batch/commands/boltz.py +0 -0
- {dh_cli-0.6.3 → dh_cli-0.7.1}/src/dh_cli/batch/commands/cancel.py +0 -0
- {dh_cli-0.6.3 → dh_cli-0.7.1}/src/dh_cli/batch/commands/clean.py +0 -0
- {dh_cli-0.6.3 → dh_cli-0.7.1}/src/dh_cli/batch/commands/embed_t5.py +0 -0
- {dh_cli-0.6.3 → dh_cli-0.7.1}/src/dh_cli/batch/commands/finalize.py +0 -0
- {dh_cli-0.6.3 → dh_cli-0.7.1}/src/dh_cli/batch/commands/list_jobs.py +0 -0
- {dh_cli-0.6.3 → dh_cli-0.7.1}/src/dh_cli/batch/commands/local.py +0 -0
- {dh_cli-0.6.3 → dh_cli-0.7.1}/src/dh_cli/batch/commands/logs.py +0 -0
- {dh_cli-0.6.3 → dh_cli-0.7.1}/src/dh_cli/batch/commands/orca.py +0 -0
- {dh_cli-0.6.3 → dh_cli-0.7.1}/src/dh_cli/batch/commands/protmpnn.py +0 -0
- {dh_cli-0.6.3 → dh_cli-0.7.1}/src/dh_cli/batch/commands/protmpnn_to_boltz.py +0 -0
- {dh_cli-0.6.3 → dh_cli-0.7.1}/src/dh_cli/batch/commands/retry.py +0 -0
- {dh_cli-0.6.3 → dh_cli-0.7.1}/src/dh_cli/batch/commands/status.py +0 -0
- {dh_cli-0.6.3 → dh_cli-0.7.1}/src/dh_cli/batch/commands/submit.py +0 -0
- {dh_cli-0.6.3 → dh_cli-0.7.1}/src/dh_cli/batch/commands/train.py +0 -0
- {dh_cli-0.6.3 → dh_cli-0.7.1}/src/dh_cli/batch/commands/wait_for.py +0 -0
- {dh_cli-0.6.3 → dh_cli-0.7.1}/src/dh_cli/batch/fasta_utils.py +0 -0
- {dh_cli-0.6.3 → dh_cli-0.7.1}/src/dh_cli/batch/h5_utils.py +0 -0
- {dh_cli-0.6.3 → dh_cli-0.7.1}/src/dh_cli/batch/job_id.py +0 -0
- {dh_cli-0.6.3 → dh_cli-0.7.1}/src/dh_cli/batch/manifest.py +0 -0
- {dh_cli-0.6.3 → dh_cli-0.7.1}/src/dh_cli/batch/s3_transport.py +0 -0
- {dh_cli-0.6.3 → dh_cli-0.7.1}/src/dh_cli/bedrock/__init__.py +0 -0
- {dh_cli-0.6.3 → dh_cli-0.7.1}/src/dh_cli/bedrock/commands.py +0 -0
- {dh_cli-0.6.3 → dh_cli-0.7.1}/src/dh_cli/bedrock/cost_report.py +0 -0
- {dh_cli-0.6.3 → dh_cli-0.7.1}/src/dh_cli/bedrock/pricing.yaml +0 -0
- {dh_cli-0.6.3 → dh_cli-0.7.1}/src/dh_cli/cloud_commands.py +0 -0
- {dh_cli-0.6.3 → dh_cli-0.7.1}/src/dh_cli/codeartifact.py +0 -0
- {dh_cli-0.6.3 → dh_cli-0.7.1}/src/dh_cli/engines_studios/__init__.py +0 -0
- {dh_cli-0.6.3 → dh_cli-0.7.1}/src/dh_cli/engines_studios/api_client.py +0 -0
- {dh_cli-0.6.3 → dh_cli-0.7.1}/src/dh_cli/engines_studios/auth.py +0 -0
- {dh_cli-0.6.3 → dh_cli-0.7.1}/src/dh_cli/engines_studios/engine_commands.py +0 -0
- {dh_cli-0.6.3 → dh_cli-0.7.1}/src/dh_cli/engines_studios/progress.py +0 -0
- {dh_cli-0.6.3 → dh_cli-0.7.1}/src/dh_cli/engines_studios/ssh_config.py +0 -0
- {dh_cli-0.6.3 → dh_cli-0.7.1}/src/dh_cli/engines_studios/studio_commands.py +0 -0
- {dh_cli-0.6.3 → dh_cli-0.7.1}/src/dh_cli/hz/__init__.py +0 -0
- {dh_cli-0.6.3 → dh_cli-0.7.1}/src/dh_cli/hz/deploy.py +0 -0
- {dh_cli-0.6.3 → dh_cli-0.7.1}/src/dh_cli/hz/local.py +0 -0
- {dh_cli-0.6.3 → dh_cli-0.7.1}/src/dh_cli/hz/test.py +0 -0
- {dh_cli-0.6.3 → dh_cli-0.7.1}/src/dh_cli/hz/tf.py +0 -0
- {dh_cli-0.6.3 → dh_cli-0.7.1}/src/dh_cli/hz/users.py +0 -0
- {dh_cli-0.6.3 → dh_cli-0.7.1}/src/dh_cli/main.py +0 -0
- {dh_cli-0.6.3 → dh_cli-0.7.1}/src/dh_cli/utility_commands.py +0 -0
- {dh_cli-0.6.3 → dh_cli-0.7.1}/src/dh_cli/warehouse.py +0 -0
- {dh_cli-0.6.3 → dh_cli-0.7.1}/tests/bedrock/conftest.py +0 -0
- {dh_cli-0.6.3 → dh_cli-0.7.1}/tests/bedrock/fixtures/A_cache_write.json +0 -0
- {dh_cli-0.6.3 → dh_cli-0.7.1}/tests/bedrock/fixtures/B_cache_read.json +0 -0
- {dh_cli-0.6.3 → dh_cli-0.7.1}/tests/bedrock/fixtures/C_plain.json +0 -0
- {dh_cli-0.6.3 → dh_cli-0.7.1}/tests/bedrock/fixtures/D_cursor_user.json +0 -0
- {dh_cli-0.6.3 → dh_cli-0.7.1}/tests/bedrock/fixtures/E_service_role.json +0 -0
- {dh_cli-0.6.3 → dh_cli-0.7.1}/tests/bedrock/fixtures/F_legacy_shared.json +0 -0
- {dh_cli-0.6.3 → dh_cli-0.7.1}/tests/bedrock/fixtures/G_unknown_model.json +0 -0
- {dh_cli-0.6.3 → dh_cli-0.7.1}/tests/bedrock/test_build_report.py +0 -0
- {dh_cli-0.6.3 → dh_cli-0.7.1}/tests/bedrock/test_classify_arn.py +0 -0
- {dh_cli-0.6.3 → dh_cli-0.7.1}/tests/bedrock/test_cli_exit_codes.py +0 -0
- {dh_cli-0.6.3 → dh_cli-0.7.1}/tests/bedrock/test_cost_calc.py +0 -0
- {dh_cli-0.6.3 → dh_cli-0.7.1}/tests/bedrock/test_cost_command.py +0 -0
- {dh_cli-0.6.3 → dh_cli-0.7.1}/tests/bedrock/test_cur_reconciliation.py +0 -0
- {dh_cli-0.6.3 → dh_cli-0.7.1}/tests/bedrock/test_key_command.py +0 -0
- {dh_cli-0.6.3 → dh_cli-0.7.1}/tests/bedrock/test_render_formats.py +0 -0
- {dh_cli-0.6.3 → dh_cli-0.7.1}/tests/bedrock/test_resolve_base_model.py +0 -0
- {dh_cli-0.6.3 → dh_cli-0.7.1}/tests/bedrock/test_s3_walker.py +0 -0
- {dh_cli-0.6.3 → dh_cli-0.7.1}/tests/hz/test_init.py +0 -0
- {dh_cli-0.6.3 → dh_cli-0.7.1}/tests/hz/test_suites.py +0 -0
- {dh_cli-0.6.3 → dh_cli-0.7.1}/tests/hz/test_users.py +0 -0
- {dh_cli-0.6.3 → dh_cli-0.7.1}/tests/test_cloud_gcp.py +0 -0
- {dh_cli-0.6.3 → dh_cli-0.7.1}/tests/test_finalize_protmpnn.py +0 -0
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"""Identity resolution for `dh` commands that read per-developer secrets.
|
|
2
|
+
|
|
3
|
+
The `github_commands` and (future) `bedrock` commands both key per-user
|
|
4
|
+
Secrets Manager entries on the caller's Dayhoff handle. This module
|
|
5
|
+
resolves that handle from the current SSO session in a way that matches
|
|
6
|
+
the server-side resource policy (which keys on
|
|
7
|
+
`aws:PrincipalTag/Email`).
|
|
8
|
+
|
|
9
|
+
Design note — why not session tags directly?
|
|
10
|
+
|
|
11
|
+
AWS Secrets Manager resource policies evaluate
|
|
12
|
+
`aws:PrincipalTag/Email` automatically because IAM Identity Center
|
|
13
|
+
attaches an `Email` principal tag to DeveloperAccess sessions. But
|
|
14
|
+
there is no SDK API that lets a session read its own principal
|
|
15
|
+
tags back — session tags are visible *only* to IAM condition
|
|
16
|
+
evaluation, not to callers. The closest observable we have is the
|
|
17
|
+
assumed-role ARN's RoleSessionName, which Identity Center sets to
|
|
18
|
+
the user's email by default.
|
|
19
|
+
|
|
20
|
+
So the resolution below extracts the RoleSessionName and strips the
|
|
21
|
+
`@<domain>` suffix if present. This matches what the policy's
|
|
22
|
+
`aws:PrincipalTag/Email` condition will also evaluate to at
|
|
23
|
+
GetSecretValue time — i.e. "which secret can I read?" and "what
|
|
24
|
+
handle am I?" are answered by the same identity fact by
|
|
25
|
+
construction.
|
|
26
|
+
|
|
27
|
+
CANARY (resolve pre-code-freeze, plan §"Pre-implementation canaries"
|
|
28
|
+
Canary 1): confirm the RoleSessionName on DeveloperAccess is
|
|
29
|
+
`<handle>@dayhoff.com` and not `<handle>@dayhofflabs.com`. The
|
|
30
|
+
DEFAULT_DOMAIN constant below is the single place to flip that.
|
|
31
|
+
"""
|
|
32
|
+
from __future__ import annotations
|
|
33
|
+
|
|
34
|
+
import re
|
|
35
|
+
|
|
36
|
+
DEFAULT_DOMAIN = "dayhoff.com"
|
|
37
|
+
|
|
38
|
+
_SSO_ASSUMED_ROLE_RE = re.compile(
|
|
39
|
+
r"^arn:aws:sts::\d+:assumed-role/AWSReservedSSO_[^/]+/(?P<session>.+)$"
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class HandleResolutionError(RuntimeError):
|
|
44
|
+
"""Raised when the current session's handle can't be determined.
|
|
45
|
+
|
|
46
|
+
The caller is expected to turn this into a user-facing error
|
|
47
|
+
pointing at `awslogin dev-devaccess`.
|
|
48
|
+
"""
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def resolve_handle_from_session(session, *, domain: str = DEFAULT_DOMAIN) -> str:
|
|
52
|
+
"""Return the dev handle matching the SSO session's Email principal tag.
|
|
53
|
+
|
|
54
|
+
Args:
|
|
55
|
+
session: a boto3 Session configured with the caller's SSO
|
|
56
|
+
credentials. The function calls `sts:GetCallerIdentity` on
|
|
57
|
+
it; if that call would fall through to the engine instance
|
|
58
|
+
role instead of the dev's SSO creds, the caller must have
|
|
59
|
+
already detected and errored on that before getting here
|
|
60
|
+
(see `github_commands._sso_session`).
|
|
61
|
+
domain: email domain to strip from the session name. Defaults to
|
|
62
|
+
`dayhoff.com` to match `cursor_bedrock_role.tf`'s tag.
|
|
63
|
+
|
|
64
|
+
Returns:
|
|
65
|
+
The handle (e.g. `"dma"`).
|
|
66
|
+
|
|
67
|
+
Raises:
|
|
68
|
+
HandleResolutionError: the caller's ARN doesn't look like an
|
|
69
|
+
Identity Center DeveloperAccess session.
|
|
70
|
+
"""
|
|
71
|
+
arn = session.client("sts").get_caller_identity()["Arn"]
|
|
72
|
+
match = _SSO_ASSUMED_ROLE_RE.match(arn)
|
|
73
|
+
if not match:
|
|
74
|
+
raise HandleResolutionError(
|
|
75
|
+
f"Caller ARN does not look like an AWS SSO session: {arn}. "
|
|
76
|
+
f"Run `awslogin dev-devaccess` (or pass --handle explicitly)."
|
|
77
|
+
)
|
|
78
|
+
session_name = match.group("session")
|
|
79
|
+
suffix = f"@{domain}"
|
|
80
|
+
if session_name.endswith(suffix):
|
|
81
|
+
return session_name[: -len(suffix)]
|
|
82
|
+
return session_name
|