tundri is a Python package to declaratively create, drop, and alter Snowflake objects and manage their permissions with Permifrost.
Motivation
Permifrost is great at managing permissions, but it doesn't create or alter objects. As GitLab's data team handbook states:
Object creation and deletion is not managed by permifrost
With only Permifrost, one would have to manually create the objects and then run Permifrost to set the permissions. This is error prone and time consuming. That is where tundri comes in.
In a nutshell
tundri reads the Permifrost spec file and compares with the current state of the Snowflake account. It then creates, drops, and alters the objects to match. It leverages Permifrost's YAML meta tags to set attributes like default_role for users and warehouse_size for warehouses. Once the objects are created, tundri runs Permifrost to set the permissions.
Reconciliation logic
tundri compares the desired state (spec) with the current Snowflake state and generates the minimum set of DDL statements needed:
| Scenario | Action |
|---|---|
| Object in spec, not in Snowflake | CREATE |
| Object in Snowflake, not in spec | DROP |
| Object in both, params changed | ALTER ... SET ... |
| Param removed from spec, has value in Snowflake | ALTER ... UNSET ... |
Getting started
Prerequisites
- Credentials to a Snowflake user account with the
securityadminrole - A Permifrost spec file
Install
pip install tundri
Configure
Permifrost
Add a valid Permifrost spec file to your repository. You can use the files in the examples folder as reference.
Snowflake
Set up your Snowflake connection details in the environment variables listed below.
PERMISSION_BOT_ACCOUNT=abc134.west-europe.azure # Your account identifier
PERMISSION_BOT_USER=PERMIFROST
PERMISSION_BOT_PASSWORD=...
PERMISSION_BOT_ROLE=SECURITYADMIN # Permifrost requires it to be `SECURITYADMIN`
PERMISSION_BOT_DATABASE=PERMIFROST
PERMISSION_BOT_WAREHOUSE=ADMIN
Usage
The run subcommand is going to drop/create objects and run Permifrost.
Dry run
tundri run --permifrost_spec_path examples/permifrost.yml --dry
Normal run
tundri run --permifrost_spec_path examples/permifrost.yml
Getting help
tundri --help
Development
Local setup
Install the development dependencies
uv sync
Run tests
Run the tests
uv run pytest -v
Formatting
Run the command below to format the code
uv run black .
Testing locally
Dry run with the example spec file
uv run tundri run --dry -p examples/permifrost.yml
Contributing
Release process
The release process is automated using GitHub Actions. Here's how it works:
-
Adding new features or bug fixes
- PR tests run automatically to verify the changes on each PR
- Multiple PRs can be merged to main until a release-ready state is reached
-
Initiating a Release
- A maintainer triggers the manual release workflow
- They specify the version bump type (
major,minor, orpatch) - This creates a release branch and PR with updated version
-
Release Creation
- When the release PR is merged to main:
- A Git tag is created (e.g.,
v1.2.3) - A GitHub release is created
- The package is published to PyPI
- A Git tag is created (e.g.,
- When the release PR is merged to main:
The process requires the following GitHub secrets to be configured:
PYPI_API_TOKEN: For production PyPI publishingTEST_PYPI_API_TOKEN: For TestPyPI publishingSNOWFLAKE_*: Snowflake credentials for running tests
For full details on the release workflow, see RELEASE_WORKFLOW.md.
Metadata
Release files for tundri 1.5.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| tundri-1.5.0.tar.gz | 416.4 kB | Without provenance | Details for tundri-1.5.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| tundri-1.5.0-py3-none-any.whl | Python 3 | none | any | Details for tundri-1.5.0-py3-none-any.whl |
Total release size: 433.2 kB
Release files / tundri-1.5.0.tar.gz
| Download URL | tundri-1.5.0.tar.gz |
|---|---|
| Size | 416.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
74a49c3fb945154fefa3bf2fe37499ada57338c12de30fe58af67e0bb6ee5605
|
|
BLAKE2b-256 checksum How to use checksums |
71ed9776ed6d66775c1bd5cfa99696b6a5990fb9040f0f6de6117add99546b81
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.13
|
Release files / tundri-1.5.0-py3-none-any.whl
| Download URL | tundri-1.5.0-py3-none-any.whl |
|---|---|
| Size | 16.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
0c166fb723bc330a77baac41f0cf7981d6f7fab7c1f7d488a3ca21f142f13802
|
|
BLAKE2b-256 checksum How to use checksums |
bd51ccb92f913a4524e7a0d6d5487436610add52ff1def5fdeee40a99412e031
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.13
|
Security for tundri 1.5.0
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.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.