Skip to main content

Tundra

A fork of Permifrost for managing Snowflake permissions from a declarative YAML spec. It's faster on big accounts and understands the object types Snowflake has shipped since Permifrost stopped keeping up.

Anything not covered here (spec structure, read/write semantics, wildcards, ownership, --diff, --role, --user, !include, require-owner) works exactly as it does upstream. See the Permifrost README.

pip install tundra-cli
# or the latest main
pip install git+https://github.com/henryupton/tundra.git

tundra run spec.yml --dry
tundra spec-test spec.yml

Performance

Permifrost runs every Snowflake round trip serially, and on a large account most of them are wasted.

  • Parallel fetch. Role grants, user grants and table-existence checks are fetched concurrently and merged back in a deterministic order, so output is identical run to run. Concurrency is --max-workers (or PERMISSION_BOT_MAX_WORKERS, default 8), and the connection pool is sized to match.
  • No enumeration under wildcards. A db.schema.* grant is issued as ON ALL plus ON FUTURE, yet Permifrost still ran SHOW <objects> IN SCHEMA per schema, per object type, per role just to build its revoke allowlist. Tundra tracks wildcard coverage by schema scope instead, so those calls are gone. On one production spec that was 1,658s of a 4,938s apply. Emitted SQL is unchanged.
  • Skip what you don't need. --skip-validation skips the entity-existence checks, and --ignore-missing-objects drops grants on missing objects rather than failing the run.

New object types

All table-like types ride the existing tables read/write lists, and a wildcard covers every type.

Type read write Schema write adds
Iceberg table select insert, update, delete, truncate, references create iceberg table
Dynamic table select monitor, operate
Streamlit usage usage create streamlit
Semantic view select select create semantic view

These matter because Snowflake's ON ALL TABLES / ON ALL VIEWS don't reach any of them, so under Permifrost they go silently ungranted. Schema write also grants create cortex search service and create mcp server. New types are one entry in src/tundra/table_object_types.py.

External volumes are a top-level spec section, granted USAGE from a role's external_volumes: list (needed to read or write Iceberg tables):

external_volumes:
  - s3_iceberg:
      storage_provider: s3

roles:
  - data_engineer:
      external_volumes: [s3_iceberg]

Database and application roles

A member_of entry containing a period is a DB.ROLE reference. Tundra checks it against SHOW DATABASE ROLES, falls back to SHOW APPLICATION ROLES for an application of the same name, and grants or revokes accordingly. Membership is fully managed: anything granted but not listed is revoked.

roles:
  - monitor:
      member_of:
        - snowflake.usage_viewer                    # database role
        - snowflake.cortex_analyst_requests_viewer  # application role

Database and application roles are referenced, never defined, and must already exist. Spec roles can't contain a period, and users can't be granted either kind. Grants an application made itself are never revoked. MANAGE GRANTS doesn't reach the SNOWFLAKE application's roles, so the role Tundra runs as must hold every application role the spec hands out.

Users

On top of Permifrost's user properties:

users:
  - etl_service:
      can_login: true
      type: service                 # person (default), service, legacy_service
      default_secondary_roles: [all]
      parameters:
        timezone: Pacific/Auckland  # validated IANA name
        week_start: 1
  • has_password: true rewrites type: service to legacy_service, since Snowflake won't let a SERVICE user hold a password. has_password: false sets PASSWORD = NULL. Omit it for SERVICE users.
  • parameters sets user-level session defaults. Allowed keys are timezone, week_start, week_of_year_policy, the *_output_format family, timestamp_type_mapping, query_tag, statement_timeout_in_seconds, statement_queued_timeout_in_seconds and client_session_keep_alive. Removing one leaves the value in place.
  • User identifiers and property values are quoted and uppercased properly.

Spec directories

run and spec-test accept a directory. Every .yml/.yaml under it (recursive, sorted, dotfiles skipped) is a fragment holding any top-level keys, merged before validation:

spec/
  settings.yml
  databases.yml
  roles/custom.yml
  users/service.yml

List sections concatenate. An entity defined twice is an error naming both files. Scalar settings must agree.

Running it

Objects dropped mid-run. Grants are planned from a snapshot, so a schema that CI drops and recreates while Tundra is applying would fail every queued statement. Tundra re-looks up the object instead: gone prints [VANISHED] (not a failure), recreated is retried once. Every [ERROR] prints Snowflake's message beneath it.

Running role. The current role must be SECURITYADMIN or a role that has been granted it (checked with IS_ROLE_IN_SESSION), so a purpose-built role works.

Workload identity federation. Short-lived OIDC tokens (GitHub Actions, say) with no stored secret:

PERMISSION_BOT_AUTHENTICATOR=WORKLOAD_IDENTITY
PERMISSION_BOT_WORKLOAD_IDENTITY_PROVIDER=OIDC
PERMISSION_BOT_TOKEN_COMMAND='python mint_token.py --audience my-account'

The command's stdout is the token, and it's rerun for every pooled connection so a long run never reuses an expired one. It takes precedence over the other auth methods, which are otherwise as upstream.

Warehouses. size is optional.

Contributing

Issues and PRs welcome on GitHub. Tests run on every PR. Versions are bumped by the release workflow on merge to main, not by hand.

PYTHONPATH=src python -m pytest tests -q

Metadata

Release files for tundra-cli 1.0.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for tundra-cli 1.0.1
File Size Uploaded
tundra_cli-1.0.1.tar.gz 95.6 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for tundra-cli 1.0.1
File Interpreter ABI Platform
tundra_cli-1.0.1-py3-none-any.whl Python 3 none any Details

Total release size: 147.4 kB

Release files / tundra_cli-1.0.1.tar.gz

Download URL tundra_cli-1.0.1.tar.gz
Size 95.6 kB
Tags Source
SHA-256 checksum
How to use checksums
8c84eb8cbb681a946286f843e0ddc898986fe2436c87e26fb0ea9ef0b2e46c8c
BLAKE2b-256 checksum
How to use checksums
ce18548ca35614defb7f61963b4a580c6ec1cc557809cde9b518c03f2d3ca5a2
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 14, 2026.

Transparency log

Release files / tundra_cli-1.0.1-py3-none-any.whl

Download URL tundra_cli-1.0.1-py3-none-any.whl
Size 51.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
9f1740089ec121a37c7cdcf6b81b2202496c5dc5a79714dcd3d8c4fdbe6e4027
BLAKE2b-256 checksum
How to use checksums
ce72c3675b9d1c119c449200af78495c6f788198a953a8444b9071342f7c28b8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 14, 2026.

Transparency log
Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page