Skip to content

Self-serve provisioning of an isolated Snowflake test account (#42)#44

Open
GClunies wants to merge 2 commits into
datacoves:mainfrom
GClunies:snowcap-42
Open

Self-serve provisioning of an isolated Snowflake test account (#42)#44
GClunies wants to merge 2 commits into
datacoves:mainfrom
GClunies:snowcap-42

Conversation

@GClunies

Copy link
Copy Markdown
Contributor

Problem

Contributors must never run the integration test suite (pytest tests/ --snowflake) against their personal or employer Snowflake account — those tests create and mutate real objects. Today there's no self-serve way to get an isolated, disposable Snowflake account for this purpose.

Flow

make provision-test-account EMAIL=you@example.com
pytest tests/ --snowflake
make drop-test-account
  • provision mirrors the contributor's current edition/cloud/region (detected from their normal SNOWFLAKE_* credentials) by default, with --edition/--cloud/--region overrides.
  • It creates the account, polls until reachable, bootstraps it via the existing reset_test_account flow plus static resources, and writes a ready-to-use tests/.env.
  • Re-running provision against an existing account resumes (skips CREATE ACCOUNT) rather than failing.
  • drop gates on tests/.env agreement (or --yes), confirms the resolved account identifier, and issues DROP ACCOUNT ... GRACE_PERIOD_IN_DAYS=<n> (default/minimum 3).

Credential separation & zero-leakage construction

  • ORGADMIN credentials come exclusively from dedicated SNOWFLAKE_ORG_ACCOUNT/SNOWFLAKE_ORG_USER/SNOWFLAKE_ORG_PASSWORD env vars, used only for CREATE ACCOUNT/DROP ACCOUNT — they are never written to tests/.env or any other file (asserted by a unit test on render_test_env).
  • The new account's admin is a freshly created SERVICE user with a freshly generated local RSA key pair (2048-bit, written atomically at 0600, backed up before any overwrite) — no password is ever set for it.
  • Bootstrap vars passed to reset_test_account are built explicitly from generated values and inert placeholders; a contributor's own SNOWCAP_VAR_* environment never reaches the new account.
  • All generated key/env artifacts (tests/.env, tests/.env.bak*, tests/.env.dropped*, tests/.snowcap_test_account_rsa_key.p8*) are git-ignored.

Testing done

  • 49 new mocked unit tests in tests/test_manage_test_account.py covering SQL builders (including identifier/injection validation), region resolution, env rendering (including the "never contains SNOWFLAKE_ORG" assertion), key/password generation, the org-connection env contract, poll timeout/narrow-exception behavior, provision_test_account's safety-critical branches (resume-skips-create, backup-before-overwrite, apply.sh failure surfacing, upfront input validation before any filesystem mutation), drop_test_account's safety gates, and CLI defaults/--help contracts.
  • Full unit suite is green: .venv/bin/python -m pytest → 1582 passed, 245 skipped.
  • Live end-to-end provisioning against a real Snowflake organization was not run in this environment — there are no SNOWFLAKE_ORG_* credentials available here. Coverage is limited to the mocked unit tests plus --help smoke checks.

Intentional follow-ups (not addressed in this PR)

  • generate_rsa_keypair could reuse snowcap.operations.connector.SecurePath for the 0600 secret write instead of its own os.open/fdopen logic. Left as-is to avoid churning working, security-equivalent code.
  • The pre-existing dead reset_test_account() statement after main() in the tools/manage_test_account.py __main__ block (unreachable — click's main() raises SystemExit) was left untouched; it predates this change.

Closes #42

🤖 Generated with Claude Code

https://claude.ai/code/session_01Lkii1Y1STX9aNPLQu5tAJf

@gitguardian

gitguardian Bot commented Jul 21, 2026

Copy link
Copy Markdown

️✅ There are no secrets present in this pull request anymore.

If these secrets were true positive and are still valid, we highly recommend you to revoke them.
While these secrets were previously flagged, we no longer have a reference to the
specific commits where they were detected. Once a secret has been leaked into a git
repository, you should consider it compromised, even if it was deleted immediately.
Find here more information about risks.


🦉 GitGuardian detects secrets in your source code to help developers and security teams secure the modern development process. You are seeing this because you or someone else with access to this repository has authorized GitGuardian to scan your pull request.

…account

Add `provision` and `drop` subcommands to tools/manage_test_account.py plus
`make provision-test-account EMAIL=...` / `make drop-test-account` targets
(closes datacoves#42):

- provision mirrors the developer's current edition/cloud/region by default
  (detected from their normal SNOWFLAKE_* credentials) with optional
  --edition/--cloud/--region overrides
- ORGADMIN credentials come only from dedicated SNOWFLAKE_ORG_* env vars and
  are used only for CREATE ACCOUNT / DROP ACCOUNT — never written to any file
- the new account's admin is a SERVICE user with a freshly generated local
  RSA key pair (0600, backed up before overwrite); no password is ever set
- polls until the account is reachable, bootstraps it via the existing
  reset_test_account flow plus static resources, and writes a ready-to-use
  tests/.env (existing file backed up first)
- drop gates on tests/.env agreement, confirms the resolved identifier, and
  takes --grace-period-in-days (default 3, Snowflake's minimum)
- unit tests (49) mock everything testable without a live org
- TESTING.md documents prerequisites, provisioning, resume semantics,
  teardown, and expected cost

Note: the pre-existing unreachable reset_test_account() call after main() in
the __main__ block is intentionally left untouched.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Lkii1Y1STX9aNPLQu5tAJf
… before key mutation

Post-review hardening of the provision flow:

- SHOW ACCOUNTS rows expose the account name as account_name, not name -
  the resume check would have raised KeyError against a live org (test
  fixtures updated to the documented column so a regression fails)
- composed region and region group are now validated up front, before the
  key file is archived/overwritten; a mistyped --region can no longer
  orphan a working key
- recovery hint now covers CREATE ACCOUNT itself: a failure there raises
  a ClickException with re-run/drop guidance instead of a raw traceback
- --grace-period-in-days gets help text; orchestration functions get
  type hints
- tests: shared drop_deps fixture; patch subprocess.run instead of the
  whole module

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Lkii1Y1STX9aNPLQu5tAJf
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add make command to isolate Snowcap integration-tests from contributors Snowflake account

1 participant