Published on: October 10, 2025
13 min read
Want to transform development from chaos to compliance? Learn how we implemented governance early on rather than retrofitting when maintenance costs climb exponentially.

Recently, the GitLab Data team transformed scattered Streamlit applications into a unified, secure, and scalable solution for our Snowflake environment. To accomplish this, we packed Python, Snowflake, and Streamlit together with GitLab. Follow along on this journey and discover the results we achieved, and learn how you can, too.
Imagine this scenario: Your organization has dozens of Streamlit applications across different environments, running various Python versions, connecting to sensitive data with inconsistent security practices. Some apps work, others break mysteriously, and nobody knows who built what or how to maintain them.
This was exactly the challenge our data team faced. Applications were being created in isolation, with no standardization, no security oversight, and no clear deployment process. The result? A compliance nightmare and a maintenance burden that was growing exponentially.

================================================================================
โ
Snowflake CLI successfully installed and configured!
Connection: gitlab_streamlit
User: [email protected]
Account: gitlab
================================================================================
Using virtualenv: /Users/YOU/repos/streamlit/.venv
๐ Installing project dependencies...
Installing dependencies from lock file
No dependencies to install or update
โ
Streamlit environment prepared!
โฐโ$ make streamlit-rules
๐ Running Streamlit compliance check...
================================================================================
CODE COMPLIANCE REPORT
================================================================================
Generated: 2025-07-09 14:01:16
Files checked: 1
SUMMARY:
โ
Passed: 1
โ Failed: 0
Success Rate: 100.0%
APPLICATION COMPLIANCE SUMMARY:
๐ฑ Total Applications Checked: 1
โ ๏ธ Applications with Issues: 0
๐ File Compliance Rate: 100.0%
DETAILED RESULTS BY APPLICATION:
...
โฐโ$ make streamlit-new-page STREAMLIT_APP=sales_dashboard STREAMLIT_PAGE_NAME=analytics
๐ Generating new Streamlit page: analytics for app: sales_dashboard
๐ Create new page from template:
Page name: analytics
App directory: sales_dashboard
Template path: page_template.py
โ
Successfully created 'analytics.py' in 'sales_dashboard' directory from template
โโโ src/
โ โโโ applications/ # Folder for Streamlit applications
โ โ โโโ main_app/ # Main dashboard application
โ โ โโโ components/ # Shared components
โ โ โโโ <your_apps>/ # Your custom application
โ โ โโโ <your_apps2>/ # Your 2nd custom application
โ โโโ templates/ # Application and page templates
โ โโโ compliance/ # Compliance rules and checks
โ โโโ setup/ # Setup and configuration utilities
โโโ tests/ # Test files
โโโ config.yml # Environment configuration
โโโ Makefile # Build and deployment automation
โโโ README.md # Main README.md file

class_rules:
- name: "Inherit code for the page from GitLabDataStreamlitInit"
description: "All Streamlit apps must inherit from GitLabDataStreamlitInit"
severity: "error"
required: true
class_name: "*"
required_base_classes:
- "GitLabDataStreamlitInit"
required_methods:
- "__init__"
- "set_page_layout"
- "setup_ui"
- "run"
function_rules:
- name: "Main function required"
description: "Must have a main() function"
severity: "error"
required: true
function_name: "main"
import_rules:
- name: "Import GitLabDataStreamlitInit"
description: "Must import the mandatory base class"
severity: "error"
required: true
module_name: "gitlab_data_streamlit_init"
required_items:
- "GitLabDataStreamlitInit"
- name: "Import streamlit"
description: "Must import streamlit library"
severity: "error"
required: true
module_name: "streamlit"
file_rules:
- name: "Snowflake configuration required (snowflake.yml)"
description: "Each application must have a snowflake.yml configuration file"
severity: "error"
required: true
file_pattern: "**/applications/**/snowflake.yml"
base_path: ""
- name: "Snowflake environment required (environment.yml)"
description: "Each application must have a environment.yml configuration file"
severity: "error"
required: true
file_pattern: "**/applications/**/environment.yml"
base_path: ""
- name: "Share specification required (share.yml)"
description: "Each application must have a share.yml file"
severity: "warning"
required: true
file_pattern: "**/applications/**/share.yml"
base_path: ""
- name: "README.md required (README.md)"
description: "Each application should have a README.md file with a proper documentation"
severity: "error"
required: true
file_pattern: "**/applications/**/README.md"
base_path: ""
- name: "Starting point recommended (dashboard.py)"
description: "Each application must have a dashboard.py as a starting point"
severity: "warning"
required: true
file_pattern: "**/applications/**/dashboard.py"
base_path: ""
sql_rules:
- name: "SQL files must contain only SELECT statements"
description: "SQL files and SQL code in other files should only contain SELECT statements for data safety"
severity: "error"
required: true
file_extensions: [".sql", ".py"]
select_only: true
forbidden_statements:
- ....
case_sensitive: false
- name: "SQL queries should include proper SELECT statements"
description: "When SQL is present, it should contain proper SELECT statements"
severity: "warning"
required: false
file_extensions: [".sql", ".py"]
required_statements:
- "SELECT"
case_sensitive: false
share_rules:
- name: "Valid functional roles in share.yml"
description: "Share.yml files must contain only valid functional roles from the approved list"
severity: "error"
required: true
file_pattern: "**/applications/**/share.yml"
valid_roles:
- ...
safe_data_roles:
- ...
- name: "Share.yml file format validation"
description: "Share.yml files must follow the correct YAML format structure"
severity: "error"
required: true
file_pattern: "**/applications/**/share.yml"
required_keys:
- "share"
min_roles: 1
max_roles: 10
With one command running:
โฐโ$ make streamlit-rules
We can verify all the rules we have created and validate that the developers (who are building a Streamlit application) are following the policy specified by the creators (who determine the policies and building blocks of the framework), and that all the building blocks are in the right place. This ensures consistent behavior across all Streamlit applications.
๐ Running Streamlit compliance check...
================================================================================
CODE COMPLIANCE REPORT
================================================================================
Generated: 2025-08-18 17:05:12
Files checked: 4
SUMMARY:
โ
Passed: 4
โ Failed: 0
Success Rate: 100.0%
APPLICATION COMPLIANCE SUMMARY:
๐ฑ Total Applications Checked: 1
โ ๏ธ Applications with Issues: 0
๐ File Compliance Rate: 100.0%
DETAILED RESULTS BY APPLICATION:
================================================================================
โ
PASS APPLICATION: main_app
------------------------------------------------------------
๐ FILES ANALYZED (4):
โ
dashboard.py
๐ฆ Classes: SnowflakeConnectionTester
๐ง Functions: main
๐ฅ Imports: os, pwd, gitlab_data_streamlit_init, snowflake.snowpark.exceptions, streamlit
โ
show_streamlit_apps.py
๐ฆ Classes: ShowStreamlitApps
๐ง Functions: main
๐ฅ Imports: pandas, gitlab_data_streamlit_init, snowflake_session, streamlit
โ
available_packages.py
๐ฆ Classes: AvailablePackages
๐ง Functions: main
๐ฅ Imports: pandas, gitlab_data_streamlit_init, streamlit
โ
share.yml
๐ฅ Share Roles: snowflake_analyst_safe
๐ FILE COMPLIANCE FOR MAIN_APP:
โ
Required files found:
โ snowflake.yml
โ environment.yml
โ share.yml
โ README.md
โ dashboard.py
RULES CHECKED:
----------------------------------------
Class Rules (1):
- Inherit code for the page from GitLabDataStreamlitInit (error)
Function Rules (1):
- Main function required (error)
Import Rules (2):
- Import GitLabDataStreamlitInit (error)
- Import streamlit (error)
File Rules (5):
- Snowflake configuration required (snowflake.yml) (error)
- Snowflake environment required (environment.yml) (error)
- Share specification required (share.yml) (warning)
- README.md required (README.md) (error)
- Starting point recommended (dashboard.py) (warning)
SQL Rules (2):
- SQL files must contain only SELECT statements (error)
๐ SELECT-only mode enabled
๐จ Forbidden: INSERT, UPDATE, DELETE, DROP, ALTER...
- SQL queries should include proper SELECT statements (warning)
Share Rules (2):
- Valid functional roles in share.yml (error)
๐ฅ Valid roles: 15 roles defined
๐ Safe data roles: 11 roles
- Share.yml file format validation (error)
------------------------------------------------------------
โ
Compliance check passed
-----------------------------------------------------------
Whether you prefer your favorite IDE, a web-based development environment, or Snowflake Snowsight, the experience remains consistent. The framework provides:
โฐโ$ make streamlit-new-app NAME=sales_dashboard
๐ง Configuration Environment: TEST
๐ Configuration File: config.yml
๐ Config Loader Script: ./setup/get_config.sh
๐ Python Version: 3.12
๐ Applications Directory: ./src/applications
๐ Database: ...
๐ Schema: ...
๐ Stage: ...
๐ญ Warehouse: ...
๐ Creating new Streamlit app: sales_dashboard
Initialized the new project in ./src/applications/sales_dashboard
[tool.poetry]
name = "GitLab Data Streamlit"
version = "0.1.1"
description = "GitLab Data Team Streamlit project"
authors = ["GitLab Data Team <*****@gitlab.com>"]
readme = "README.md"
[tool.poetry.dependencies]
python = "<3.13,>=3.12"
snowflake-snowpark-python = "==1.32.0"
snowflake-connector-python = {extras = ["development", "pandas", "secure-local-storage"], version = "^3.15.0"}
streamlit = "==1.22.0"
watchdog = "^6.0.0"
types-toml = "^0.10.8.20240310"
pytest = "==7.0.0"
black = "==25.1.0"
importlib-metadata = "==4.13.0"
pyyaml = "==6.0.2"
python-qualiter = "*"
ruff = "^0.1.0"
types-pyyaml = "^6.0.12.20250516"
jinja2 = "==3.1.6"
[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"

make streamlit-push-test APPLICATION_NAME=sales_dashboard
๐ค Deploying Streamlit app to test environment: sales_dashboard
...
------------------------------------------------------------------------------------------------------------
๐ Running share command for application: sales_dashboard
Running commands to grant shares
๐ Executing: snow streamlit share sales_dashboard with SOME_NICE_ROLE
โ
Command executed successfully
๐ Execution Summary: 1/1 commands succeeded
Comprehensive Makefile: All common commands are wrapped in simple Makefile commands, from local development to testing and deployment, including CI/CD pipelines.
Safe local development: Everything runs in isolated Poetry environments, protecting your system while providing production-like experiences.


This framework represents more than just a technical solution โ it's a paradigm shift toward treating data applications as first-class citizens in your enterprise (data) architecture. By providing structure without sacrificing flexibility, the GitLab Data team created an environment where anyone in the company with minimal technical knowledge can innovate rapidly while maintaining the highest standards of security and compliance.
We're continuing to enhance the framework based on user feedback and emerging needs. Future improvements include expanded template libraries, enhanced monitoring capabilities, more flexibility, and a smoother user experience. The goal isn't just to solve today's problems, but to create a foundation that scales with your organization's growing data application needs.
The GitLab Data Team transformed dozens of scattered, insecure Streamlit applications with no standardization into a unified, enterprise-grade framework that separates roles cleanly:
And we used these building blocks: