These checks exercise the Snowflake CLI (snow), and optionally the real OS keychain via Python keyring. They are opt-in and should use a non-production Snowflake account.
| Mechanism | How |
|---|---|
| Task pipeline (ordered) | task it — runs it-unit → it-smoke |
| Unit tests only | task it-unit — uv run pytest -q (offline; no snow) |
| Automated IT (scenarios 1–2 + keyring) | task it-smoke or bash scripts/it/smoke.sh — single scripted check; there is no separate pytest IT suite duplicating this. |
- Snowflake CLI installed; default connection configured (
SNOWFLAKE_DEFAULT_CONNECTION_NAMEor your usualsnowprofile). - Admin-capable role for full lifecycle (often
ACCOUNTADMINor equivalent) to create users, roles, network rules/policies, authentication policies, and PATs. - A dedicated database for policy objects (e.g.
MY_SF_UTILS) already created in the account. - Network policy: the runner’s egress IP must be allowed. For local runs,
--allow-local(default oncreate) includes your detected public CIDR; add--extra-cidrsas needed.--allow-ghadds Snowflake’s managed GitHub Actions rule to the policy (hybrid with your custom rule); requires Snowflake-managed network rules in the account (not gov regions). - Keychain: first access may prompt for OS keychain permission; unattended runners need a non-interactive keyring backend or prior approval.
- PAT limit: Snowflake allows up to 15 active PATs per user. Rotate/remove test users so you do not hit the limit during repeated IT runs.
- Government / restricted regions: Automated smoke and documented manual flows are validated in commercial-style accounts only. When a disposable Snowflake account in a gov or otherwise restricted region is available, run
SHOW NETWORK RULES IN SNOWFLAKE.NETWORK_SECURITYand exercisecreate(or--dry-run) with--allow-gh; capture whether managed GitHub rules exist, how hybrid policy SQL fails or succeeds, and update docs/SECURITY.md residual risk #5 if needed.
The sfutils-pat commands read SA_USER, SA_ROLE, and SF_UTILS_DB from the process environment (same as --user / --role / --db; legacy SNOW_UTILS_DB is still accepted). For manual scenarios 3–6, prefer the project .env (or a dedicated file such as .env.it) so you do not maintain a second variable family.
Safety: Point SA_USER / SA_ROLE / SF_UTILS_DB at disposable resources in a non-production account—not production service users.
Example workflow:
cd /path/to/sfutils-pat
uv sync
# Load vars (matches Taskfile dotenv behavior when you use task create, etc.)
set -a && source .env && set +a
# Or: set -a && source .env.it && set +a
uv run sfutils-pat create --yes
uv run sfutils-pat verify
uv run sfutils-pat rotate
uv run sfutils-pat verify
# uv run sfutils-pat show-pat # optional; confirms with warning, then prints secret (or --yes)
uv run sfutils-pat remove --drop-user --yesPass --user / --role / --db only when you need to override what is in the environment for a single invocation.
Optional: SA_ADMIN_ROLE, PAT_NAME, and SNOWFLAKE_DEFAULT_CONNECTION_NAME as documented in the main README.
If you do not want to load .env, or need to override only for a script:
| Variable | Purpose |
|---|---|
SF_UTILS_PAT_SA_USER |
Overrides SA_USER for scripts/it/smoke.sh dry-run identifiers only |
SF_UTILS_PAT_SA_ROLE |
Overrides SA_ROLE (same) |
SF_UTILS_PAT_SF_UTILS_DB |
Overrides SF_UTILS_DB / legacy SNOW_UTILS_DB (same) |
Legacy: IT_SA_USER, IT_SA_ROLE, IT_SF_UTILS_DB, and IT_SNOW_UTILS_DB are still honored in smoke.sh after the above.
These SF_UTILS_PAT_* names avoid colliding with SNOWFLAKE_* vars used by the Snowflake CLI; they are not required for normal manual IT when using .env.
The JSON includes your current session fields (e.g. User, Account, Host depending on CLI version). It does not define the PAT service user, role, or utils database—those come from .env / env (or smoke’s slug fallback when nothing is set).
scripts/it/smoke.sh loads .env from the repo root when present (set -a / source / set +a, same idea as Task’s dotenv). It resolves dry-run user / role / db in this order: SF_UTILS_PAT_* → SA_USER / SA_ROLE / SF_UTILS_DB (legacy SNOW_UTILS_DB) → IT_* → slug from connection User. The slug fallback is only suitable for dry-run; for a real create, SF_UTILS_DB in .env must name an existing database.
Use a unique prefix per engineer or CI run for SA_USER / related objects in the account.
| # | Scenario | Command / action | Risk |
|---|---|---|---|
| 1 | create dry-run (no Snowflake DDL) |
With env loaded: sfutils-pat create --dry-run --skip-network (or explicit --user / --role / --db) |
None for --skip-network path |
| 2 | Connection metadata (read-only) | snow connection test --format json |
Read-only |
| 3 | Full create → verify |
Env from .env: create --yes then verify |
Creates objects + PAT; OS keyring |
| 4 | rotate → verify |
rotate then verify |
New PAT secret |
| 5 | show-pat (optional) |
show-pat (interactive confirm; --yes to skip) |
Prints secret to stdout—avoid in shared logs |
| 6 | remove (cleanup) |
remove --drop-user --yes |
Drops PAT, policies, user; --yes skips per-step prompts (required when stdin is not a TTY); clears obsolete lines on default .env path |
For scenario 1 with full network CIDR resolution (no --skip-network), run from a network that allows the tool’s IP discovery (same as production create).
If remove fails partway, clean up objects in Snowflake and delete the keyring entry for the service string pattern documented in the main README.
Offline tests live under tests/ (e.g. keyring helpers with an in-memory backend). They do not replace it-smoke.
uv sync --extra dev
uv run pytest -qDo not run integration tests in default PR workflows unless you provide Snowflake auth, a disposable account, and teardown. Prefer manual or scheduled jobs with secrets and strict resource naming.
See scripts/it/smoke.sh and task it-smoke in the Taskfile. It:
- Optionally sources
.envin the repo root when the file exists. - Runs
snow connection test --format json. - Runs
sfutils-pat create --dry-run --skip-networkusing resolved user/role/db (precedence above). - Runs
sfutils-pat create --dry-run --no-local --allow-ghto print hybrid network policy SQL (Snowflake-managed GitHub rule only in the allow list; still no DDL). - Keyring roundtrip: stores a dummy secret via
store_pat/load_pat/delete_patusing the same service-string layout as real PATs, with fixed identitySF_UTILS_PAT_IT_SMOKE(does not overlap normal SA user names). Your OS may prompt for keychain access.
Step 5 validates the local keyring backend without creating Snowflake objects or real PATs.