Skip to content

Commit e95674f

Browse files
authored
feat: Add SensitiveColumns to tables schema (#2134)
<!-- Explain what problem this PR addresses --> ---
1 parent 40a5c66 commit e95674f

File tree

8 files changed

+61
-3
lines changed

8 files changed

+61
-3
lines changed

internal/memdb/memdb.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ func GetNewClient(options ...Option) plugin.NewClientFunc {
5959
},
6060
},
6161
PermissionsNeeded: []string{"permission1"},
62+
SensitiveColumns: []string{"col1"},
6263
Relations: schema.Tables{
6364
{
6465
Name: "table2",

plugin/testing_validation.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,15 @@ func ValidateNoEmptyColumns(t *testing.T, tables schema.Tables, messages message
1616
}
1717
}
1818
}
19+
20+
func ValidateSensitivColumns(t *testing.T, tables schema.Tables) {
21+
for _, table := range tables.FlattenTables() {
22+
nonMatchingColumns, nonMatchingJSONColumns := schema.FindNotMatchingSensitiveColumns(table)
23+
if len(nonMatchingColumns) > 0 {
24+
t.Fatalf("found non-matching sensitive column(s): %v in %s", nonMatchingColumns, table.Name)
25+
}
26+
if len(nonMatchingJSONColumns) > 0 {
27+
t.Fatalf("found non-matching sensitive JSON column(s): %v in %s", nonMatchingJSONColumns, table.Name)
28+
}
29+
}
30+
}

schema/arrow.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ const (
2727
MetadataTableDependsOn = "cq:table_depends_on"
2828
MetadataTableIsPaid = "cq:table_paid"
2929
MetadataTablePermissionsNeeded = "cq:table_permissions_needed"
30+
MetadataTableSensitiveColumns = "cq:table_sensitive_columns"
3031
)
3132

3233
type Schemas []*arrow.Schema

schema/table.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@ type Table struct {
6666
Description string `json:"description"`
6767
// List of permissions needed to access this table, if any. For example ["Microsoft.Network/dnsZones/read"] or ["storage.buckets.list"]
6868
PermissionsNeeded []string `json:"permissions_needed"`
69+
// List of columns that may contain sensitive or secret data
70+
SensitiveColumns []string `json:"sensitive_columns"`
6971
// Columns are the set of fields that are part of this table
7072
Columns ColumnList `json:"columns"`
7173
// Relations are a set of related tables defines
@@ -188,6 +190,7 @@ func NewTableFromArrowSchema(sc *arrow.Schema) (*Table, error) {
188190
title, _ := tableMD.GetValue(MetadataTableTitle)
189191
dependsOn, _ := tableMD.GetValue(MetadataTableDependsOn)
190192
permissionsNeeded, _ := tableMD.GetValue(MetadataTablePermissionsNeeded)
193+
sensitiveColumns, _ := tableMD.GetValue(MetadataTableSensitiveColumns)
191194
var parent *Table
192195
if dependsOn != "" {
193196
parent = &Table{Name: dependsOn}
@@ -200,6 +203,8 @@ func NewTableFromArrowSchema(sc *arrow.Schema) (*Table, error) {
200203

201204
var permissionsNeededArr []string
202205
_ = json.Unmarshal([]byte(permissionsNeeded), &permissionsNeededArr)
206+
var sensitiveColumnsArr []string
207+
_ = json.Unmarshal([]byte(sensitiveColumns), &sensitiveColumnsArr)
203208
table := &Table{
204209
Name: name,
205210
Description: description,
@@ -208,6 +213,7 @@ func NewTableFromArrowSchema(sc *arrow.Schema) (*Table, error) {
208213
Title: title,
209214
Parent: parent,
210215
PermissionsNeeded: permissionsNeededArr,
216+
SensitiveColumns: sensitiveColumnsArr,
211217
}
212218
if isIncremental, found := tableMD.GetValue(MetadataIncremental); found {
213219
table.IsIncremental = isIncremental == MetadataTrue
@@ -493,6 +499,8 @@ func (t *Table) ToArrowSchema() *arrow.Schema {
493499
}
494500
asJSON, _ := json.Marshal(t.PermissionsNeeded)
495501
md[MetadataTablePermissionsNeeded] = string(asJSON)
502+
asJSON, _ = json.Marshal(t.SensitiveColumns)
503+
md[MetadataTableSensitiveColumns] = string(asJSON)
496504

497505
schemaMd := arrow.MetadataFrom(md)
498506
for i, c := range t.Columns {

schema/table_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -731,6 +731,7 @@ func TestTablesToAndFromArrow(t *testing.T) {
731731
{Name: "multiple_attributes", Type: arrow.BinaryTypes.String, PrimaryKey: true, IncrementalKey: true, NotNull: true, Unique: true},
732732
},
733733
PermissionsNeeded: []string{"storage.buckets.list", "compute.acceleratorTypes.list", "test,test"},
734+
SensitiveColumns: []string{"string", "json"},
734735
},
735736
}
736737

schema/validators.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ package schema
22

33
import (
44
"encoding/json"
5+
"slices"
6+
"strings"
57

68
"github.com/apache/arrow-go/v18/arrow"
79
"github.com/cloudquery/plugin-sdk/v4/types"
@@ -40,6 +42,35 @@ func FindEmptyColumns(table *Table, records []arrow.Record) []string {
4042
return emptyColumns
4143
}
4244

45+
func FindNotMatchingSensitiveColumns(table *Table) (nonMatchingColumns []string, nonMatchingJSONColumns []string) {
46+
if len(table.SensitiveColumns) == 0 {
47+
return []string{}, []string{}
48+
}
49+
nonMatchingColumns = make([]string, 0)
50+
nonMatchingJSONColumns = make([]string, 0)
51+
tableColumns := table.Columns.Names()
52+
for _, c := range table.SensitiveColumns {
53+
isJSONPath := false
54+
if strings.Contains(c, ".") {
55+
c = strings.Split(c, ".")[0]
56+
isJSONPath = true
57+
}
58+
if !slices.Contains(tableColumns, c) {
59+
nonMatchingColumns = append(nonMatchingColumns, c)
60+
continue
61+
}
62+
if !isJSONPath {
63+
continue
64+
}
65+
col := table.Columns.Get(c)
66+
if !arrow.TypeEqual(col.Type, types.ExtensionTypes.JSON) {
67+
nonMatchingJSONColumns = append(nonMatchingJSONColumns, c)
68+
continue
69+
}
70+
}
71+
return nonMatchingColumns, nonMatchingJSONColumns
72+
}
73+
4374
func isEmptyJSON(msg json.RawMessage) bool {
4475
if len(msg) == 0 {
4576
return true

serve/package.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ func (s *PluginServe) writeTablesJSON(ctx context.Context, dir string) error {
103103
Title: &table.Title,
104104
Columns: &columns,
105105
PermissionsNeeded: &table.PermissionsNeeded,
106+
SensitiveColumns: &table.SensitiveColumns,
106107
})
107108
}
108109
buffer := &bytes.Buffer{}

serve/testdata/memdbtables.json

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@
1717
"relations": ["table2"],
1818
"title": "",
1919
"is_paid": false,
20-
"permissions_needed": ["permission1"]
20+
"permissions_needed": ["permission1"],
21+
"sensitive_columns": ["col1"]
2122
},
2223
{
2324
"columns": [
@@ -38,7 +39,8 @@
3839
"name": "table2",
3940
"title": "",
4041
"is_paid": false,
41-
"permissions_needed": null
42+
"permissions_needed": null,
43+
"sensitive_columns": null
4244
},
4345
{
4446
"columns": [
@@ -59,6 +61,7 @@
5961
"name": "table3",
6062
"title": "",
6163
"is_paid": true,
62-
"permissions_needed": null
64+
"permissions_needed": null,
65+
"sensitive_columns": null
6366
}
6467
]

0 commit comments

Comments
 (0)