feat(cloud): persist device-flow Cloud SQL IAM credentials into DVC prefs#18
Merged
Merged
Conversation
…refs Replaces the static-Postgres-password client work from PR #17 (held) with the Cloud SQL IAM auth path required by the latest BDD spec. No static Postgres password is parsed, persisted, or transmitted. The poll-success response now optionally carries a database_iam bundle minted off-cluster by the admin tool (companion server PR NMGRL#43). This commit wires it through the client: - pychron/cloud/api_client.py — DeviceCodePollSuccess gains a database_iam dict slot. poll_device_code() parses the new block from the response body and strips it from the safe_raw debug dict so the embedded SA private key cannot leak into caller logs. - pychron/cloud/paths.py — new cloudsql_key_path(lab) helper that returns ~/.pychron/keys/cloudsql_<safe-lab>.json. Lab name is filesystem-sanitized so a hostile / weird lab string cannot escape the keys directory. - pychron/cloud/iam_credentials.py (NEW) — pure helpers wrapping validate → write SA key → CSV → favorites: * _validate_iam_bundle: required-field check + ip_type public/private/psc + JSON-decode SA key + cross-check key.client_email == service_account_email (defends against bridge-side key-swap). * write_sa_key_file: atomic-ish write to ~/.pychron/keys/cloudsql_<lab>.json with 0600 on POSIX. * build_iam_dvc_csv: positional CSV that DVCConnectionItem(attrs=...) rehydrates with connection_method=cloudsql_iam, the four cloudsql_* fields populated, and username/password left empty. * merge_iam_dvc_favorites: REPLACES any prior cloud-<lab> row, demotes any other default=True favorite. _row_set_field() extends short legacy rows rather than silently no-op'ing. * apply_iam_credentials_to_prefs: end-to-end glue. - pychron/cloud/workstation_setup.py — WorkstationSetup gets database_iam + default_metadata_repo attributes; from_device_code populates them from the poll body. None means HTTP-only. - pychron/cloud/tasks/preferences.py: * New _registration_status field (Registered / Partial / Unregistered) bound to a CustomLabel. * Start-device-code-enrollment refuses to proceed when the workstation is already onboarded (registration.json + keyring token both present) without an explicit confirmation dialog. * After successful enrollment, _persist_iam_credentials_from_setup writes the SA key + DVC favorite, and the same whoami probe the manual Test Connection button uses runs automatically. A parse failure is non-fatal — surfaced via the status badge so enrollment isn't rolled back. * Re-onboard / revoke / switch-lab refresh the registration status indicator on completion. - test/cloud/test_iam_credentials.py (NEW) — 23 unit tests: write_sa_key_file (correct path, 0600 perms on POSIX, overwrite on re-enrollment, slug sanitization), build_iam_dvc_csv (CSV field ordering), merge_iam_dvc_favorites (append, replace, default flag demotion, short-row extension), _row_set_field regression, apply_iam_credentials_to_prefs end-to-end + rejection paths (missing field, invalid ip_type, mismatched key.client_email, malformed key JSON, non-service_account key). - test/cloud/test_device_code_setup.py — 3 new tests: IAM bundle propagates to WorkstationSetup, missing bundle leaves attr at None, database_iam stripped from raw debug dict. Total: 166 cloud tests passing (was 140, +26 new). Replaces PR #17. Server: pychronAPI feat/workstation-iam-credentials (PR NMGRL#43). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
4 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Replaces PR #17 (which is held). Implements the Cloud SQL IAM client path required by the latest workstation-onboarding BDD spec — no static Postgres password is parsed, persisted, or transmitted.
The poll-success response now optionally carries a `database_iam` bundle minted off-cluster by the admin tool (companion server PR pychronAPI#43). This PR wires it through the client:
The client side of `DVCConnectionItem.cloudsql_iam` was already wired (Cloud SQL Python Connector custom-creator pattern at `pychron/database/core/database_adapter.py`) — this PR only populates the favorite, no DVC engine changes.
Tests
Test plan
🤖 Generated with Claude Code