{"id":28389352,"url":"https://github.com/datnguye/sqlmesh-snow-mask","last_synced_at":"2026-05-01T06:32:50.445Z","repository":{"id":192747557,"uuid":"687284785","full_name":"datnguye/sqlmesh-snow-mask","owner":"datnguye","description":"SQLMesh macros used for ❄️ Dynamic Masking Policies implementation ✏️, and the Snowflake Hooker CLI (sfhook) ⭐","archived":false,"fork":false,"pushed_at":"2023-09-23T07:21:00.000Z","size":99,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-11-27T22:42:40.970Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/datnguye.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2023-09-05T03:29:50.000Z","updated_at":"2023-09-16T06:34:53.000Z","dependencies_parsed_at":null,"dependency_job_id":"848b90bc-0649-4b9c-a8a4-8faecab871f4","html_url":"https://github.com/datnguye/sqlmesh-snow-mask","commit_stats":null,"previous_names":["datnguye/sqlmesh-snow-mask"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/datnguye/sqlmesh-snow-mask","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/datnguye%2Fsqlmesh-snow-mask","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/datnguye%2Fsqlmesh-snow-mask/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/datnguye%2Fsqlmesh-snow-mask/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/datnguye%2Fsqlmesh-snow-mask/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/datnguye","download_url":"https://codeload.github.com/datnguye/sqlmesh-snow-mask/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/datnguye%2Fsqlmesh-snow-mask/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32487404,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-30T13:12:12.517Z","status":"online","status_checked_at":"2026-05-01T02:00:05.856Z","response_time":64,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-05-31T01:08:24.730Z","updated_at":"2026-05-01T06:32:50.439Z","avatar_url":"https://github.com/datnguye.png","language":"Python","funding_links":["https://www.buymeacoffee.com/datnguye"],"categories":[],"sub_categories":[],"readme":"# sqlmeshsm [EXPERIMENTAL]\n\n[![PyPI version](https://badge.fury.io/py/sqlmeshsm.svg)](https://pypi.org/project/sqlmeshsm/)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n[![python](https://img.shields.io/badge/Python-3.9|3.10|3.11-3776AB.svg?style=flat\u0026logo=python\u0026logoColor=white)](https://www.python.org)\n[![codecov](https://codecov.io/gh/datnguye/sqlmesh-snow-mask/graph/badge.svg?token=ZcuyauQqoq)](https://codecov.io/gh/datnguye/sqlmesh-snow-mask)\n\n[SQLMesh macros](https://sqlmesh.readthedocs.io/en/stable/concepts/macros/sqlmesh_macros/) used for ❄️ [Dynamic Masking Policies](https://docs.snowflake.com/en/user-guide/security-column-ddm-use) Implementation ✏️\n\n**_Macro(s)_** 🚧 _(currently blocked by awaiting for more supports from the sqlmesh's  Macro Context)_\n\n- `create_masking_policy` ([source](./sqlmeshsm/macros/create_masking_policy.py))\n- `apply_masking_policy` ([source](./sqlmeshsm/macros/apply_masking_policy.py))\n\nAnd, the Snowflake Hooker CLI (`hook`) ⭐\n\n**_Hook(s)_** ✅\n\n- `hook drop_masking_policy -c {config.yml} -mp {func}`\n\n## Data Masking Development\n\n### 1. Installation\n\n```bash\npip install sqlmeshsm --upgrade\n```\n\nIn your `(sqlmesh-project-dir)/macros/__init__.py`, let's import our lib:\n\n```python\nfrom sqlmeshsm import macros\n```\n\n### 2. Create masking policy functions\n\n_For example_, the `customer` table needs the following masking policies:\n\n- First Name: mask with `*` except the first 3 characters, fixed length of 10, no masking of `null`\n- Last Name: mask with the first character of Full Name, no masking of `null`\n\nThere are 2 **masking functions**, they **must be created with following requirements**:\n\n- 📂 Files located under `(your-sqlmesh-project)/macros/snow-mask-ddl`\n- 🆎 File name format: `{mp_schema}.{mp_function_name}`\n\n```sql\n-- /snow-mask-ddl/mp_schema.mp_first_name.sql\nCREATE MASKING POLICY IF NOT EXISTS @schema.mp_first_name AS (\n    masked_column string\n) RETURNS string -\u003e\n    LEFT(CASE\n        WHEN masked_column IS NOT NULL THEN LEFT(masked_column, 3)\n        ELSE NULL\n    END || '**********', 10);\n```\n\n```sql\n-- /snow-mask-ddl/mp_schema.mp_last_name.sql\nCREATE MASKING POLICY IF NOT EXISTS @schema.mp_last_name AS (\n    masked_column string,\n    full_name_column string\n) RETURNS string -\u003e\n    CASE\n        WHEN masked_column IS NOT NULL THEN LEFT(full_name_column, 1)\n        ELSE NULL\n    END;\n```\n\n\u003e `@schema` is the keyword to indicate the schema name which matches to the first part of the file name\n\n## 3. Decide to mask model's columns\n\n```sql\n/* /models/my_customer_model.sql */\nMODEL(\n    name my_schema.my_customer_model\n    kind FULL\n    ...\n)\n\n/* MODEL SQL CODE HERE */\n\n/* (optional) ADD this if `mp_schema` schema is not part of any models */\nCREATE SCHEMA IF NOT EXISTS mp_schema;\n\n/* REGISTER the masking functions */\n@create_masking_policy(mp_schema.mp_first_name)\n@create_masking_policy(mp_schema.mp_last_name)\n\n/* APPLY the masking policies */\n@apply_masking_policy(first_name, mp_schema.mp_first_name)\n@apply_masking_policy(my_schema.my_customer_model, last_name, mp_schema.mp_last_name, ['full_name'])\n```\n\nLet's plan and apply it now: `sqlmesh plan --select-model my_schema.my_customer_model`\n\n## 4. (Optional) Decide to clean up the masking policies\n\nLet's run the built-in hooks:\n\n```bash\nhook drop_masking_policy \\\n    -c /path/to/sqlmesh/config.yml \\\n    -mp you_mp_function_name\n\n# for example:\nhook drop_masking_policy \\\n    -c ~\\.sqlmesh\\config.yml\n    -mp common.mp_first_name\n```\n\nHere is the sample `config.yml` file, if you're not using sqlmesh but wanted to try the CLI:\n\n```yml\n# config.yml\n\ngateways:\n    masking_policy:\n        connection:\n            type: snowflake\n            account: YOUR_VALUE\n            user: YOUR_VALUE\n            authenticator: externalbrowser\n            # password: YOUR_VALUE\n            warehouse: YOUR_VALUE\n            database: YOUR_VALUE\n            role: YOUR_VALUE\ndefault_gateway: masking_policy\n```\n\n\u003e Try `hook -h` for more options.\n\n**_Voila! Happy Masking 🎉_**\n\n## Contribution\n\n[![buy me a coffee](https://img.shields.io/badge/buy%20me%20a%20coffee-donate-yellow.svg?logo=buy-me-a-coffee\u0026logoColor=white\u0026labelColor=ff813f\u0026style=for-the-badge)](https://www.buymeacoffee.com/datnguye)\n\nIf you've ever wanted to contribute to this tool, and a great cause, now is your chance!\n\nSee the contributing docs [CONTRIBUTING](./CONTRIBUTING.md) for more information.\n\nOur **_Contributors_**:\n\n\u003ca href=\"https://github.com/datnguye/sqlmesh-snow-mask/graphs/contributors\"\u003e\n  \u003cimg src=\"https://contrib.rocks/image?repo=datnguye/sqlmesh-snow-mask\" /\u003e\n\u003c/a\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdatnguye%2Fsqlmesh-snow-mask","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdatnguye%2Fsqlmesh-snow-mask","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdatnguye%2Fsqlmesh-snow-mask/lists"}