dh-cli 0.7.0__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.
Files changed (88) hide show
  1. {dh_cli-0.7.0 → dh_cli-0.7.1}/PKG-INFO +1 -1
  2. {dh_cli-0.7.0 → dh_cli-0.7.1}/pyproject.toml +1 -1
  3. dh_cli-0.7.1/src/dh_cli/_identity.py +82 -0
  4. dh_cli-0.7.1/src/dh_cli/github_commands.py +794 -0
  5. dh_cli-0.7.1/tests/github/__init__.py +1 -0
  6. dh_cli-0.7.1/tests/github/conftest.py +197 -0
  7. dh_cli-0.7.1/tests/github/test_engine_role_cannot_read_github_pat.py +46 -0
  8. dh_cli-0.7.1/tests/github/test_identity.py +74 -0
  9. dh_cli-0.7.1/tests/github/test_login.py +272 -0
  10. dh_cli-0.7.1/tests/github/test_login_error_paths.py +152 -0
  11. dh_cli-0.7.1/tests/github/test_login_security.py +152 -0
  12. dh_cli-0.7.1/tests/github/test_logout.py +39 -0
  13. dh_cli-0.7.1/tests/github/test_rotate.py +226 -0
  14. dh_cli-0.7.1/tests/github/test_status.py +93 -0
  15. dh_cli-0.7.0/src/dh_cli/github_commands.py +0 -275
  16. {dh_cli-0.7.0 → dh_cli-0.7.1}/.gitignore +0 -0
  17. {dh_cli-0.7.0 → dh_cli-0.7.1}/LICENSE +0 -0
  18. {dh_cli-0.7.0 → dh_cli-0.7.1}/README.md +0 -0
  19. {dh_cli-0.7.0 → dh_cli-0.7.1}/src/dh_cli/__init__.py +0 -0
  20. {dh_cli-0.7.0 → dh_cli-0.7.1}/src/dh_cli/batch/__init__.py +0 -0
  21. {dh_cli-0.7.0 → dh_cli-0.7.1}/src/dh_cli/batch/aws_batch.py +0 -0
  22. {dh_cli-0.7.0 → dh_cli-0.7.1}/src/dh_cli/batch/commands/__init__.py +0 -0
  23. {dh_cli-0.7.0 → dh_cli-0.7.1}/src/dh_cli/batch/commands/boltz.py +0 -0
  24. {dh_cli-0.7.0 → dh_cli-0.7.1}/src/dh_cli/batch/commands/cancel.py +0 -0
  25. {dh_cli-0.7.0 → dh_cli-0.7.1}/src/dh_cli/batch/commands/clean.py +0 -0
  26. {dh_cli-0.7.0 → dh_cli-0.7.1}/src/dh_cli/batch/commands/embed_t5.py +0 -0
  27. {dh_cli-0.7.0 → dh_cli-0.7.1}/src/dh_cli/batch/commands/finalize.py +0 -0
  28. {dh_cli-0.7.0 → dh_cli-0.7.1}/src/dh_cli/batch/commands/list_jobs.py +0 -0
  29. {dh_cli-0.7.0 → dh_cli-0.7.1}/src/dh_cli/batch/commands/local.py +0 -0
  30. {dh_cli-0.7.0 → dh_cli-0.7.1}/src/dh_cli/batch/commands/logs.py +0 -0
  31. {dh_cli-0.7.0 → dh_cli-0.7.1}/src/dh_cli/batch/commands/orca.py +0 -0
  32. {dh_cli-0.7.0 → dh_cli-0.7.1}/src/dh_cli/batch/commands/protmpnn.py +0 -0
  33. {dh_cli-0.7.0 → dh_cli-0.7.1}/src/dh_cli/batch/commands/protmpnn_to_boltz.py +0 -0
  34. {dh_cli-0.7.0 → dh_cli-0.7.1}/src/dh_cli/batch/commands/retry.py +0 -0
  35. {dh_cli-0.7.0 → dh_cli-0.7.1}/src/dh_cli/batch/commands/status.py +0 -0
  36. {dh_cli-0.7.0 → dh_cli-0.7.1}/src/dh_cli/batch/commands/submit.py +0 -0
  37. {dh_cli-0.7.0 → dh_cli-0.7.1}/src/dh_cli/batch/commands/train.py +0 -0
  38. {dh_cli-0.7.0 → dh_cli-0.7.1}/src/dh_cli/batch/commands/wait_for.py +0 -0
  39. {dh_cli-0.7.0 → dh_cli-0.7.1}/src/dh_cli/batch/fasta_utils.py +0 -0
  40. {dh_cli-0.7.0 → dh_cli-0.7.1}/src/dh_cli/batch/h5_utils.py +0 -0
  41. {dh_cli-0.7.0 → dh_cli-0.7.1}/src/dh_cli/batch/job_id.py +0 -0
  42. {dh_cli-0.7.0 → dh_cli-0.7.1}/src/dh_cli/batch/manifest.py +0 -0
  43. {dh_cli-0.7.0 → dh_cli-0.7.1}/src/dh_cli/batch/s3_transport.py +0 -0
  44. {dh_cli-0.7.0 → dh_cli-0.7.1}/src/dh_cli/bedrock/__init__.py +0 -0
  45. {dh_cli-0.7.0 → dh_cli-0.7.1}/src/dh_cli/bedrock/commands.py +0 -0
  46. {dh_cli-0.7.0 → dh_cli-0.7.1}/src/dh_cli/bedrock/cost_report.py +0 -0
  47. {dh_cli-0.7.0 → dh_cli-0.7.1}/src/dh_cli/bedrock/pricing.yaml +0 -0
  48. {dh_cli-0.7.0 → dh_cli-0.7.1}/src/dh_cli/cloud_commands.py +0 -0
  49. {dh_cli-0.7.0 → dh_cli-0.7.1}/src/dh_cli/codeartifact.py +0 -0
  50. {dh_cli-0.7.0 → dh_cli-0.7.1}/src/dh_cli/engines_studios/__init__.py +0 -0
  51. {dh_cli-0.7.0 → dh_cli-0.7.1}/src/dh_cli/engines_studios/api_client.py +0 -0
  52. {dh_cli-0.7.0 → dh_cli-0.7.1}/src/dh_cli/engines_studios/auth.py +0 -0
  53. {dh_cli-0.7.0 → dh_cli-0.7.1}/src/dh_cli/engines_studios/engine_commands.py +0 -0
  54. {dh_cli-0.7.0 → dh_cli-0.7.1}/src/dh_cli/engines_studios/progress.py +0 -0
  55. {dh_cli-0.7.0 → dh_cli-0.7.1}/src/dh_cli/engines_studios/ssh_config.py +0 -0
  56. {dh_cli-0.7.0 → dh_cli-0.7.1}/src/dh_cli/engines_studios/studio_commands.py +0 -0
  57. {dh_cli-0.7.0 → dh_cli-0.7.1}/src/dh_cli/hz/__init__.py +0 -0
  58. {dh_cli-0.7.0 → dh_cli-0.7.1}/src/dh_cli/hz/deploy.py +0 -0
  59. {dh_cli-0.7.0 → dh_cli-0.7.1}/src/dh_cli/hz/local.py +0 -0
  60. {dh_cli-0.7.0 → dh_cli-0.7.1}/src/dh_cli/hz/test.py +0 -0
  61. {dh_cli-0.7.0 → dh_cli-0.7.1}/src/dh_cli/hz/tf.py +0 -0
  62. {dh_cli-0.7.0 → dh_cli-0.7.1}/src/dh_cli/hz/users.py +0 -0
  63. {dh_cli-0.7.0 → dh_cli-0.7.1}/src/dh_cli/main.py +0 -0
  64. {dh_cli-0.7.0 → dh_cli-0.7.1}/src/dh_cli/utility_commands.py +0 -0
  65. {dh_cli-0.7.0 → dh_cli-0.7.1}/src/dh_cli/warehouse.py +0 -0
  66. {dh_cli-0.7.0 → dh_cli-0.7.1}/tests/bedrock/conftest.py +0 -0
  67. {dh_cli-0.7.0 → dh_cli-0.7.1}/tests/bedrock/fixtures/A_cache_write.json +0 -0
  68. {dh_cli-0.7.0 → dh_cli-0.7.1}/tests/bedrock/fixtures/B_cache_read.json +0 -0
  69. {dh_cli-0.7.0 → dh_cli-0.7.1}/tests/bedrock/fixtures/C_plain.json +0 -0
  70. {dh_cli-0.7.0 → dh_cli-0.7.1}/tests/bedrock/fixtures/D_cursor_user.json +0 -0
  71. {dh_cli-0.7.0 → dh_cli-0.7.1}/tests/bedrock/fixtures/E_service_role.json +0 -0
  72. {dh_cli-0.7.0 → dh_cli-0.7.1}/tests/bedrock/fixtures/F_legacy_shared.json +0 -0
  73. {dh_cli-0.7.0 → dh_cli-0.7.1}/tests/bedrock/fixtures/G_unknown_model.json +0 -0
  74. {dh_cli-0.7.0 → dh_cli-0.7.1}/tests/bedrock/test_build_report.py +0 -0
  75. {dh_cli-0.7.0 → dh_cli-0.7.1}/tests/bedrock/test_classify_arn.py +0 -0
  76. {dh_cli-0.7.0 → dh_cli-0.7.1}/tests/bedrock/test_cli_exit_codes.py +0 -0
  77. {dh_cli-0.7.0 → dh_cli-0.7.1}/tests/bedrock/test_cost_calc.py +0 -0
  78. {dh_cli-0.7.0 → dh_cli-0.7.1}/tests/bedrock/test_cost_command.py +0 -0
  79. {dh_cli-0.7.0 → dh_cli-0.7.1}/tests/bedrock/test_cur_reconciliation.py +0 -0
  80. {dh_cli-0.7.0 → dh_cli-0.7.1}/tests/bedrock/test_key_command.py +0 -0
  81. {dh_cli-0.7.0 → dh_cli-0.7.1}/tests/bedrock/test_render_formats.py +0 -0
  82. {dh_cli-0.7.0 → dh_cli-0.7.1}/tests/bedrock/test_resolve_base_model.py +0 -0
  83. {dh_cli-0.7.0 → dh_cli-0.7.1}/tests/bedrock/test_s3_walker.py +0 -0
  84. {dh_cli-0.7.0 → dh_cli-0.7.1}/tests/hz/test_init.py +0 -0
  85. {dh_cli-0.7.0 → dh_cli-0.7.1}/tests/hz/test_suites.py +0 -0
  86. {dh_cli-0.7.0 → dh_cli-0.7.1}/tests/hz/test_users.py +0 -0
  87. {dh_cli-0.7.0 → dh_cli-0.7.1}/tests/test_cloud_gcp.py +0 -0
  88. {dh_cli-0.7.0 → dh_cli-0.7.1}/tests/test_finalize_protmpnn.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dh-cli
3
- Version: 0.7.0
3
+ Version: 0.7.1
4
4
  Summary: Dayhoff Labs developer CLI
5
5
  Author-email: Dayhoff Labs <dev@dayhofflabs.com>
6
6
  License: # PolyForm Noncommercial License 1.0.0
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "dh-cli"
7
- version = "0.7.0"
7
+ version = "0.7.1"
8
8
  description = "Dayhoff Labs developer CLI"
9
9
  requires-python = ">=3.11"
10
10
  readme = "README.md"
@@ -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