Skip to content

Commit b76b895

Browse files
update
1 parent 58917b8 commit b76b895

File tree

3 files changed

+193
-4
lines changed

3 files changed

+193
-4
lines changed
Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
name: Bytebase Masking Policy Update
2+
on:
3+
pull_request:
4+
types: [closed]
5+
branches:
6+
- main
7+
workflow_dispatch:
8+
9+
jobs:
10+
bytebase-masking-1:
11+
if: github.event.pull_request.merged == true
12+
runs-on: ubuntu-latest
13+
permissions:
14+
pull-requests: write
15+
issues: write
16+
contents: read
17+
steps:
18+
- name: Checkout code
19+
uses: actions/checkout@v4
20+
with:
21+
ref: ${{ github.event.pull_request.head.sha }}
22+
fetch-depth: 0
23+
24+
- name: Login Bytebase
25+
id: bytebase-login
26+
uses: bytebase/[email protected]
27+
with:
28+
bytebase-url: ${{ secrets.BYTEBASE_URL }}
29+
service-key: ${{ secrets.BYTEBASE_SERVICE_KEY }}
30+
service-secret: ${{ secrets.BYTEBASE_SERVICE_SECRET }}
31+
32+
- name: Get changed files
33+
id: changed-files
34+
uses: tj-actions/changed-files@v42
35+
with:
36+
files: |
37+
masking/databases/**/**/database-catalog.json
38+
masking/projects/**/masking-exception.json
39+
since_last_remote_commit: true
40+
fetch_depth: 0
41+
include_all_old_new_renamed_files: true
42+
43+
- name: Debug changed files in detail
44+
run: |
45+
echo "All changed files:"
46+
echo "${{ steps.changed-files.outputs.all_changed_files }}"
47+
echo "Added files:"
48+
echo "${{ steps.changed-files.outputs.added_files }}"
49+
echo "Modified files:"
50+
echo "${{ steps.changed-files.outputs.modified_files }}"
51+
echo "Contains database-catalog.json: ${{ contains(steps.changed-files.outputs.all_changed_files, 'database-catalog.json') }}"
52+
echo "Contains masking-exception.json: ${{ contains(steps.changed-files.outputs.all_changed_files, 'masking-exception.json') }}"
53+
echo "Raw output:"
54+
echo "${{ toJSON(steps.changed-files.outputs) }}"
55+
56+
- name: Apply column masking policy
57+
id: apply-column-masking
58+
if: ${{ steps.changed-files.outputs.any_changed == 'true' && contains(steps.changed-files.outputs.all_changed_files, '/database-catalog.json') }}
59+
run: |
60+
# Process all database-catalog.json files
61+
echo "${{ steps.changed-files.outputs.all_changed_files }}" | tr ' ' '\n' | grep "database-catalog.json" | while read -r CHANGED_FILE; do
62+
echo "Processing: $CHANGED_FILE"
63+
INSTANCE_NAME=$(echo "$CHANGED_FILE" | sed -n 's/masking\/databases\/\([^/]*\)\/\([^/]*\).*/\1/p')
64+
DATABASE_NAME=$(echo "$CHANGED_FILE" | sed -n 's/masking\/databases\/\([^/]*\)\/\([^/]*\).*/\2/p')
65+
echo "INSTANCE_NAME=$INSTANCE_NAME"
66+
echo "DATABASE_NAME=$DATABASE_NAME"
67+
68+
response=$(curl -s -w "\n%{http_code}" --request PATCH "${{ steps.bytebase-login.outputs.api_url }}/instances/${INSTANCE_NAME}/databases/${DATABASE_NAME}/catalog" \
69+
--header "Authorization: Bearer ${{ steps.bytebase-login.outputs.token }}" \
70+
--header "Content-Type: application/json" \
71+
--data @"$CHANGED_FILE")
72+
73+
# Extract status code and response body
74+
status_code=$(echo "$response" | tail -n1)
75+
body=$(echo "$response" | sed '$d')
76+
77+
echo "Status code: $status_code"
78+
echo "Response body: $body"
79+
80+
# Append to outputs (with unique identifiers)
81+
echo "status_code_${DATABASE_NAME}=${status_code}" >> $GITHUB_OUTPUT
82+
echo "response_${DATABASE_NAME}<<EOF" >> $GITHUB_OUTPUT
83+
echo "${body}" >> $GITHUB_OUTPUT
84+
echo "EOF" >> $GITHUB_OUTPUT
85+
86+
if [[ $status_code -lt 200 || $status_code -ge 300 ]]; then
87+
echo "Failed with status code: $status_code for database: $DATABASE_NAME"
88+
exit 1
89+
fi
90+
done
91+
92+
- name: Apply masking exception policy
93+
id: apply-masking-exception
94+
if: ${{ steps.changed-files.outputs.any_changed == 'true' && contains(steps.changed-files.outputs.all_changed_files, '/masking-exception.json') }}
95+
run: |
96+
# Process all masking-exception.json files
97+
echo "${{ steps.changed-files.outputs.all_changed_files }}" | tr ' ' '\n' | grep "masking-exception.json" | while read -r CHANGED_FILE; do
98+
echo "Processing: $CHANGED_FILE"
99+
PROJECT_NAME=$(echo "$CHANGED_FILE" | sed -n 's/masking\/projects\/\([^/]*\).*/\1/p')
100+
echo "PROJECT_NAME=$PROJECT_NAME"
101+
102+
response=$(curl -s -w "\n%{http_code}" --request PATCH "${{ steps.bytebase-login.outputs.api_url }}/projects/${PROJECT_NAME}/policies/masking_exception?allow_missing=true&update_mask=payload" \
103+
--header "Authorization: Bearer ${{ steps.bytebase-login.outputs.token }}" \
104+
--header "Content-Type: application/json" \
105+
--data @"$CHANGED_FILE")
106+
107+
# Extract status code and response body
108+
status_code=$(echo "$response" | tail -n1)
109+
body=$(echo "$response" | sed '$d')
110+
111+
echo "Status code: $status_code"
112+
echo "Response body: $body"
113+
114+
# Append to outputs (with unique identifiers)
115+
echo "status_code_${PROJECT_NAME}=${status_code}" >> $GITHUB_OUTPUT
116+
echo "response_${PROJECT_NAME}<<EOF" >> $GITHUB_OUTPUT
117+
echo "${body}" >> $GITHUB_OUTPUT
118+
echo "EOF" >> $GITHUB_OUTPUT
119+
120+
if [[ $status_code -lt 200 || $status_code -ge 300 ]]; then
121+
echo "Failed with status code: $status_code for project: $PROJECT_NAME"
122+
exit 1
123+
fi
124+
done
125+
126+
- name: Comment on PR
127+
uses: actions/github-script@v7
128+
env:
129+
CHANGED_FILES: ${{ steps.changed-files.outputs.all_changed_files }}
130+
with:
131+
script: |
132+
const changedFiles = process.env.CHANGED_FILES || '';
133+
let commentBody = `### Masking Policy Update Summary\n\n`;
134+
135+
// Add status of merge
136+
commentBody += `✅ **PR Status:** Merged\n\n`;
137+
138+
// Add changed files section
139+
commentBody += `📝 **Changed Files:**\n\n`;
140+
if (changedFiles.trim()) {
141+
commentBody += changedFiles.split(' ').map(f => `- ${f}`).join('\n');
142+
} else {
143+
commentBody += `None`;
144+
}
145+
commentBody += '\n\n';
146+
147+
// Add API calls summary
148+
commentBody += `🔄 **API Calls:**\n\n`;
149+
let apiCallsFound = false;
150+
151+
if (changedFiles.includes('database-catalog.json')) {
152+
const maskingStatuses = Object.keys(${{ toJSON(steps.apply-column-masking.outputs) }} || {})
153+
.filter(key => key.startsWith('status_code_'))
154+
.map(key => ({
155+
name: key.replace('status_code_', ''),
156+
status: ${{ toJSON(steps.apply-column-masking.outputs) }}[key]
157+
}));
158+
159+
maskingStatuses.forEach(({name, status}) => {
160+
apiCallsFound = true;
161+
const success = status >= 200 && status < 300;
162+
commentBody += `- Column Masking (${name}): ${success ? '✅' : '❌'} ${status}\n`;
163+
});
164+
}
165+
166+
if (changedFiles.includes('masking-exception.json')) {
167+
const exceptionStatuses = Object.keys(${{ toJSON(steps.apply-masking-exception.outputs) }} || {})
168+
.filter(key => key.startsWith('status_code_'))
169+
.map(key => ({
170+
name: key.replace('status_code_', ''),
171+
status: ${{ toJSON(steps.apply-masking-exception.outputs) }}[key]
172+
}));
173+
174+
exceptionStatuses.forEach(({name, status}) => {
175+
apiCallsFound = true;
176+
const success = status >= 200 && status < 300;
177+
commentBody += `- Masking Exception (${name}): ${success ? '✅' : '❌'} ${status}\n`;
178+
});
179+
}
180+
181+
if (!apiCallsFound) {
182+
commentBody += `None`;
183+
}
184+
185+
await github.rest.issues.createComment({
186+
...context.repo,
187+
issue_number: context.issue.number,
188+
body: commentBody
189+
});

masking/databases/test-sample-instance/hr_test/database-catalog.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
"columns": [
1111
{
1212
"name": "amount",
13-
"semanticType": "bb.default",
13+
"semanticType": "bb.default-partial",
1414
"labels": {},
1515
"classification": ""
1616
}

masking/projects/project-sample/masking-exception.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
"maskingExceptions": [
66
{
77
"action": "EXPORT",
8-
"member": "user:dev@x.com",
8+
"member": "user:dev@example.com",
99
"condition": {
1010
"expression": "resource.instance_id == \"prod-sample-instance\" && resource.database_name == \"hr_prod\" && resource.schema_name == \"public\" && resource.table_name == \"salary\" && resource.column_name == \"amount\"",
1111
"title": "",
@@ -14,7 +14,7 @@
1414
},
1515
{
1616
"action": "QUERY",
17-
"member": "user:dev2@x.com",
17+
"member": "user:dev2@example.com",
1818
"condition": {
1919
"expression": "resource.instance_id == \"prod-sample-instance\" && resource.database_name == \"hr_prod\" && resource.schema_name == \"public\" && resource.table_name == \"salary\" && resource.column_name == \"amount\"",
2020
"title": "",
@@ -23,7 +23,7 @@
2323
},
2424
{
2525
"action": "QUERY",
26-
"member": "group:contractor@x.com",
26+
"member": "group:contractor@example.com",
2727
"condition": {
2828
"expression": "resource.instance_id == \"prod-sample-instance\" && resource.database_name == \"hr_prod\" && resource.schema_name == \"public\" && resource.table_name == \"salary\" && resource.column_name == \"amount\"",
2929
"title": "",

0 commit comments

Comments
 (0)