Skip to content

Commit c5d72eb

Browse files
authored
Merge pull request #6 from ApplauseOSS/feat/change-roles-structure
feat(role): refactor and extend role management functionality
2 parents e8c9b68 + f39fb01 commit c5d72eb

7 files changed

Lines changed: 952 additions & 180 deletions

File tree

README.md

Lines changed: 47 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,56 @@
1-
# snowflizzle
1+
# Snowflizzle
22

3-
A mapping tool from User's login_name to Snowflake roles.
3+
Snowflizzle is a tool for declaratively managing Snowflake roles, users, and their permissions using a YAML configuration file. It enables mapping users (by login name or email) to Snowflake roles, and automates the granting and revoking of database, schema, and table privileges, including support for wildcards and partial name matching. The tool is designed for automation and integrates with Snowflake using a service user and key-pair authentication.
44

5-
exmaple mapping file:
5+
## Key Features
66

7-
```yaml
8-
roles:
9-
example_role_ro:
10-
- <login_name>
11-
```
12-
13-
roles.yaml
7+
- Declarative YAML configuration for roles, members, and permissions
8+
- Grant and revoke privileges on databases, schemas, and tables
9+
- Supports wildcard and partial matching for schema and table names
10+
- Dry-run mode for previewing changes without applying them
11+
- Validation of configuration files before applying changes
12+
- Automated warehouse creation and role assignment
13+
- Designed for integration with CI/CD and automation workflows
1414

1515
```yaml
16+
# snowflizzle roles mapping example roles.yaml
17+
---
1618
roles:
17-
example_role_ro:
18-
- user1@example.com
19-
- user2@example.com
20-
example_role_rw:
21-
- user1@example.com
22-
- user2@example.com
19+
- name: team_role
20+
members:
21+
- email: exemployee1@example.com
22+
- email: exemployee2@example.com
23+
removed: true
24+
permissions:
25+
# Option for names
26+
# - database_name
27+
databases:
28+
- name: test_a_db
29+
grants:
30+
- USAGE
31+
- name: test_b_db
32+
remove: true
33+
schemas:
34+
# Options for names
35+
# - database_name.schema_name
36+
# - database_name.*
37+
# - database_name.*schema_partial
38+
# - database_name.schema_partial*
39+
- name: test_c_db.credentials
40+
grants:
41+
- USAGE
42+
- name: test_b_db.assets
43+
tables:
44+
# Options for names
45+
# - database_name.*.*
46+
# - database_name.schema_name.*
47+
# - database_name.schema_partial_*.*
48+
# - database_name.*_schema_partial.*
49+
# - database_name.schema_name.table_name
50+
- name: test_c_db.credentials
51+
grants:
52+
- SELECT
53+
- name: test_b_db.*.*
2354
```
2455
2556
Prepare snowflizzle service user in snowflake

cmd/sync.go

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,13 @@ func SyncFile(filePath string, dryRun bool) {
6666
os.Exit(1)
6767
}
6868

69-
rm, err := role.ValidateRolesFile(filePath)
69+
rc, err := role.LoadRolesConfig(filePath)
70+
if err != nil {
71+
logger.Error("Failed to load roles config", "error", err)
72+
os.Exit(1)
73+
}
74+
75+
err = role.ValidateRolesConfig(rc)
7076
if err != nil {
7177
logger.Error("Validation failed", "error", err)
7278
os.Exit(1)
@@ -84,7 +90,12 @@ func SyncFile(filePath string, dryRun bool) {
8490
}
8591
}()
8692

87-
if err := role.GrantRolesToUsers(db, rm, dryRun); err != nil {
93+
rp, err := role.NewRoleProcessor(db, rc, dryRun)
94+
if err != nil {
95+
logger.Error("Failed to initialize role processor", "error", err)
96+
os.Exit(1)
97+
}
98+
if err := rp.Process(); err != nil {
8899
logger.Error("Failed to grant roles to users", "error", err)
89100
os.Exit(1)
90101
}

cmd/validate.go

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,17 @@ var validateCmd = &cobra.Command{
3030
Long: `Validate the roles.yaml file to ensure it conforms to the expected format
3131
and contains valid data for mapping roles from AD to Snowflake.`,
3232
Run: func(cmd *cobra.Command, args []string) {
33-
filepath := args[0]
33+
filePath := args[0]
3434
logger := logging.GetLogger()
35-
logger.Info("Validating", "filepath", filepath)
36-
_, err := role.ValidateRolesFile(filepath)
35+
logger.Info("Validating", "filePath", filePath)
36+
37+
rc, err := role.LoadRolesConfig(filePath)
38+
if err != nil {
39+
logger.Error("Failed to load roles config", "error", err)
40+
os.Exit(1)
41+
}
42+
43+
err = role.ValidateRolesConfig(rc)
3744
if err != nil {
3845
logger.Error("Validation failed", "error", err)
3946
os.Exit(1)

go.mod

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ toolchain go1.24.1
77
require (
88
github.com/DATA-DOG/go-sqlmock v1.5.2
99
github.com/joho/godotenv v1.5.1
10-
github.com/snowflakedb/gosnowflake v1.14.0
10+
github.com/snowflakedb/gosnowflake v1.14.1
1111
github.com/spf13/cobra v1.9.1
1212
gopkg.in/yaml.v3 v3.0.1
1313
)
@@ -23,16 +23,22 @@ require (
2323
github.com/apache/arrow-go/v18 v18.0.0 // indirect
2424
github.com/aws/aws-sdk-go-v2 v1.26.1 // indirect
2525
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.2 // indirect
26+
github.com/aws/aws-sdk-go-v2/config v1.27.11 // indirect
2627
github.com/aws/aws-sdk-go-v2/credentials v1.17.11 // indirect
28+
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.1 // indirect
2729
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.16.15 // indirect
2830
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.5 // indirect
2931
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.5 // indirect
32+
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 // indirect
3033
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.5 // indirect
3134
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.2 // indirect
3235
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.7 // indirect
3336
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.7 // indirect
3437
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.5 // indirect
3538
github.com/aws/aws-sdk-go-v2/service/s3 v1.53.1 // indirect
39+
github.com/aws/aws-sdk-go-v2/service/sso v1.20.5 // indirect
40+
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.23.4 // indirect
41+
github.com/aws/aws-sdk-go-v2/service/sts v1.28.6 // indirect
3642
github.com/aws/smithy-go v1.20.2 // indirect
3743
github.com/danieljoos/wincred v1.2.2 // indirect
3844
github.com/dvsekhvalnov/jose2go v1.6.0 // indirect
@@ -52,6 +58,8 @@ require (
5258
github.com/sirupsen/logrus v1.9.3 // indirect
5359
github.com/spf13/pflag v1.0.6 // indirect
5460
github.com/zeebo/xxh3 v1.0.2 // indirect
61+
go.opentelemetry.io/otel v1.35.0 // indirect
62+
go.opentelemetry.io/otel/trace v1.35.0 // indirect
5563
golang.org/x/crypto v0.36.0 // indirect
5664
golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 // indirect
5765
golang.org/x/mod v0.22.0 // indirect

go.sum

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,10 @@ github.com/dvsekhvalnov/jose2go v1.6.0 h1:Y9gnSnP4qEI0+/uQkHvFXeD2PLPJeXEL+ySMEA
7474
github.com/dvsekhvalnov/jose2go v1.6.0/go.mod h1:QsHjhyTlD/lAVqn/NSbVZmSCGeDehTB/mPZadG+mhXU=
7575
github.com/gabriel-vasile/mimetype v1.4.7 h1:SKFKl7kD0RiPdbht0s7hFtjl489WcQ1VyPW8ZzUMYCA=
7676
github.com/gabriel-vasile/mimetype v1.4.7/go.mod h1:GDlAgAyIRT27BhFl53XNAFtfjzOkLaF35JdEG0P7LtU=
77+
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
78+
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
79+
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
80+
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
7781
github.com/goccy/go-json v0.10.4 h1:JSwxQzIqKfmFX1swYPpUThQZp/Ka4wzJdK0LWVytLPM=
7882
github.com/goccy/go-json v0.10.4/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
7983
github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 h1:ZpnhV/YsD2/4cESfV5+Hoeu/iUR3ruzNvZ+yQfO03a0=
@@ -86,8 +90,8 @@ github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
8690
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
8791
github.com/google/flatbuffers v24.12.23+incompatible h1:ubBKR94NR4pXUCY/MUsRVzd9umNW7ht7EG9hHfS9FX8=
8892
github.com/google/flatbuffers v24.12.23+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
89-
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
90-
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
93+
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
94+
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
9195
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
9296
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
9397
github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c h1:6rhixN/i8ZofjG1Y75iExal34USq5p+wiN1tpie8IrU=
@@ -107,8 +111,6 @@ github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IX
107111
github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=
108112
github.com/klauspost/cpuid/v2 v2.2.9 h1:66ze0taIn2H33fBvCkXuv9BmCwDfafmiIVpKV9kKGuY=
109113
github.com/klauspost/cpuid/v2 v2.2.9/go.mod h1:rqkxqrZ1EhYM9G+hXH7YdowN5R5RGN6NK4QwQ3WMXF8=
110-
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
111-
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
112114
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
113115
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
114116
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
@@ -121,20 +123,19 @@ github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3 h1:+n/aFZefKZp7spd8D
121123
github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3/go.mod h1:RagcQ7I8IeTMnF8JTXieKnO4Z6JCsikNEzj0DwauVzE=
122124
github.com/mtibben/percent v0.2.1 h1:5gssi8Nqo8QU/r2pynCm+hBQHpkB/uNK7BJCFogWdzs=
123125
github.com/mtibben/percent v0.2.1/go.mod h1:KG9uO+SZkUp+VkRHsCdYQV3XSZrrSpR3O9ibNBTZrns=
126+
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
124127
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
125128
github.com/pierrec/lz4/v4 v4.1.22 h1:cKFw6uJDK+/gfw5BcDL0JL5aBsAFdsIT18eRtLj7VIU=
126129
github.com/pierrec/lz4/v4 v4.1.22/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
127130
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU=
128131
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI=
129132
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
130133
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
131-
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
132-
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
133134
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
134135
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
135136
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
136-
github.com/snowflakedb/gosnowflake v1.14.0 h1:lP91Y47ho3dzpTxWr7wjpvDXteh+ZttsLaw1WXzHS34=
137-
github.com/snowflakedb/gosnowflake v1.14.0/go.mod h1:NUxNYUdyPn9sRoYB/udq/fXBXuhLS3SBTPI2/OT79uc=
137+
github.com/snowflakedb/gosnowflake v1.14.1 h1:FnnlaSAm6Zyq3ujqa0JmeU1Ivj7Iz+A0C2YGV6nbRSw=
138+
github.com/snowflakedb/gosnowflake v1.14.1/go.mod h1:+3Eh8swS12G6Fbt/wb5Vcse2Id7VU9HGgKSH8ydiumU=
138139
github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo=
139140
github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0=
140141
github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
@@ -143,12 +144,22 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
143144
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
144145
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
145146
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
146-
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
147-
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
147+
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
148+
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
148149
github.com/zeebo/assert v1.3.0 h1:g7C04CbJuIDKNPFHmsk4hwZDO5O+kntRxzaUoNXj+IQ=
149150
github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0=
150151
github.com/zeebo/xxh3 v1.0.2 h1:xZmwmqxHZA8AI603jOQ0tMqmBr9lPeFwGg6d+xy9DC0=
151152
github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA=
153+
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
154+
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
155+
go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ=
156+
go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y=
157+
go.opentelemetry.io/otel/metric v1.35.0 h1:0znxYu2SNyuMSQT4Y9WDWej0VpcsxkuklLa4/siN90M=
158+
go.opentelemetry.io/otel/metric v1.35.0/go.mod h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE=
159+
go.opentelemetry.io/otel/sdk v1.35.0 h1:iPctf8iprVySXSKJffSS79eOjl9pvxV9ZqOWT0QejKY=
160+
go.opentelemetry.io/otel/sdk v1.35.0/go.mod h1:+ga1bZliga3DxJ3CQGg3updiaAJoNECOgJREo9KHGQg=
161+
go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt/xgMs=
162+
go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc=
152163
golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34=
153164
golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc=
154165
golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 h1:e66Fs6Z+fZTbFBAxKfP3PALWBtpfqks2bwGcexMxgtk=
@@ -176,9 +187,8 @@ golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da/go.mod h1:NDW/Ps6MPRej6f
176187
gonum.org/v1/gonum v0.15.1 h1:FNy7N6OUZVUaWG9pTiD+jlhdQ3lMP+/LcTpJ6+a8sQ0=
177188
gonum.org/v1/gonum v0.15.1/go.mod h1:eZTZuRFrzu5pcyjN5wJhcIhnUdNijYxX1T2IcrOGY0o=
178189
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
190+
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b h1:QRR6H1YWRnHb4Y/HeNFCTJLFVxaq6wH4YuVdsUOr75U=
179191
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
180-
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
181-
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
182192
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
183193
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
184194
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=

0 commit comments

Comments
 (0)