diff --git a/.github/workflows/1-bb-masking-semantic-type-global.yml b/.github/workflows/1-bb-masking-semantic-type-global.yml index 0ea6427..6cd7464 100644 --- a/.github/workflows/1-bb-masking-semantic-type-global.yml +++ b/.github/workflows/1-bb-masking-semantic-type-global.yml @@ -78,7 +78,7 @@ jobs: echo "File content:" cat "$CHANGED_FILE" - response=$(curl -s -w "\n%{http_code}" --request PATCH "${{ steps.bytebase-login.outputs.api_url }}/settings/bb.workspace.semantic-types" \ + response=$(curl -s -w "\n%{http_code}" --request PATCH "${{ steps.bytebase-login.outputs.api_url }}/settings/SEMANTIC_TYPES" \ --header "Authorization: Bearer ${{ steps.bytebase-login.outputs.token }}" \ --header "Content-Type: application/json" \ --data @"$CHANGED_FILE") @@ -109,8 +109,9 @@ jobs: CHANGED_FILE="masking/global-masking-rule.json" echo "Processing: $CHANGED_FILE" - response=$(curl -s -w "\n%{http_code}" --request PATCH "${{ steps.bytebase-login.outputs.api_url }}/policies/masking_rule?allow_missing=true&update_mask=payload" \ + response=$(curl -s -w "\n%{http_code}" --request PATCH "${{ steps.bytebase-login.outputs.api_url }}/workspaces/-/policies/masking_rule?allowMissing=true&updateMask=payload" \ --header "Authorization: Bearer ${{ steps.bytebase-login.outputs.token }}" \ + --header "Content-Type: application/json" \ --data @"$CHANGED_FILE") # Extract status code and response body diff --git a/.github/workflows/2-bb-masking-column.yml b/.github/workflows/2-bb-masking-column.yml index eb64ae2..08d7a42 100644 --- a/.github/workflows/2-bb-masking-column.yml +++ b/.github/workflows/2-bb-masking-column.yml @@ -1,4 +1,4 @@ -name: Bytebase Masking Policy Update Column and Exception +name: Bytebase Masking Policy Update Column and Exemption on: pull_request: types: [closed] @@ -7,7 +7,7 @@ on: workflow_dispatch: jobs: - bytebase-masking-column-and-exception: + bytebase-masking-column-and-exemption: if: github.event.pull_request.merged == true runs-on: ubuntu-latest permissions: @@ -35,7 +35,7 @@ jobs: with: files: | masking/databases/**/**/database-catalog.json - masking/projects/**/masking-exception.json + masking/projects/**/masking-exemption.json since_last_remote_commit: true fetch_depth: 0 include_all_old_new_renamed_files: true @@ -49,7 +49,7 @@ jobs: echo "Modified files:" echo "${{ steps.changed-files.outputs.modified_files }}" echo "Contains database-catalog.json: ${{ contains(steps.changed-files.outputs.all_changed_files, 'database-catalog.json') }}" - echo "Contains masking-exception.json: ${{ contains(steps.changed-files.outputs.all_changed_files, 'masking-exception.json') }}" + echo "Contains masking-exemption.json: ${{ contains(steps.changed-files.outputs.all_changed_files, 'masking-exemption.json') }}" echo "Raw output:" echo "${{ toJSON(steps.changed-files.outputs) }}" @@ -89,17 +89,17 @@ jobs: fi done - - name: Apply masking exception policy - id: apply-masking-exception - if: ${{ steps.changed-files.outputs.any_changed == 'true' && contains(steps.changed-files.outputs.all_changed_files, '/masking-exception.json') }} + - name: Apply masking exemption policy + id: apply-masking-exemption + if: ${{ steps.changed-files.outputs.any_changed == 'true' && contains(steps.changed-files.outputs.all_changed_files, '/masking-exemption.json') }} run: | - # Process all masking-exception.json files - echo "${{ steps.changed-files.outputs.all_changed_files }}" | tr ' ' '\n' | grep "masking-exception.json" | while read -r CHANGED_FILE; do + # Process all masking-exemption.json files + echo "${{ steps.changed-files.outputs.all_changed_files }}" | tr ' ' '\n' | grep "masking-exemption.json" | while read -r CHANGED_FILE; do echo "Processing: $CHANGED_FILE" PROJECT_NAME=$(echo "$CHANGED_FILE" | sed -n 's/masking\/projects\/\([^/]*\).*/\1/p') echo "PROJECT_NAME=$PROJECT_NAME" - 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" \ + response=$(curl -s -w "\n%{http_code}" --request PATCH "${{ steps.bytebase-login.outputs.api_url }}/projects/${PROJECT_NAME}/policies/masking_exemption?allowMissing=true&updateMask=payload" \ --header "Authorization: Bearer ${{ steps.bytebase-login.outputs.token }}" \ --header "Content-Type: application/json" \ --data @"$CHANGED_FILE") @@ -130,7 +130,7 @@ jobs: with: script: | const changedFiles = process.env.CHANGED_FILES || ''; - let commentBody = `### Update Column Masking and Exception Summary\n\n`; + let commentBody = `### Update Column Masking and Exemption Summary\n\n`; // Add status of merge commentBody += `✅ **PR Status:** Merged\n\n`; @@ -163,18 +163,18 @@ jobs: }); } - if (changedFiles.includes('masking-exception.json')) { - const exceptionStatuses = Object.keys(${{ toJSON(steps.apply-masking-exception.outputs) }} || {}) + if (changedFiles.includes('masking-exemption.json')) { + const exceptionStatuses = Object.keys(${{ toJSON(steps.apply-masking-exemption.outputs) }} || {}) .filter(key => key.startsWith('status_code_')) .map(key => ({ name: key.replace('status_code_', ''), - status: ${{ toJSON(steps.apply-masking-exception.outputs) }}[key] + status: ${{ toJSON(steps.apply-masking-exemption.outputs) }}[key] })); exceptionStatuses.forEach(({name, status}) => { apiCallsFound = true; const success = status >= 200 && status < 300; - commentBody += `- Masking Exception (${name}): ${success ? '✅' : '❌'} ${status}\n`; + commentBody += `- Masking Exemption (${name}): ${success ? '✅' : '❌'} ${status}\n`; }); } diff --git a/.github/workflows/3-bb-masking-classification.yml b/.github/workflows/3-bb-masking-classification.yml index 3dac346..16b1eab 100644 --- a/.github/workflows/3-bb-masking-classification.yml +++ b/.github/workflows/3-bb-masking-classification.yml @@ -65,7 +65,7 @@ jobs: CHANGED_FILE="masking/data-classification.json" echo "Processing: $CHANGED_FILE" - response=$(curl -s -w "\n%{http_code}" --request PATCH "${{ steps.bytebase-login.outputs.api_url }}/settings/bb.workspace.data-classification" \ + response=$(curl -s -w "\n%{http_code}" --request PATCH "${{ steps.bytebase-login.outputs.api_url }}/settings/DATA_CLASSIFICATION" \ --header "Authorization: Bearer ${{ steps.bytebase-login.outputs.token }}" \ --header "Content-Type: application/json" \ --data @"$CHANGED_FILE") @@ -91,8 +91,9 @@ jobs: CHANGED_FILE="masking/global-masking-rule-classification.json" echo "Processing: $CHANGED_FILE" - response=$(curl -s -w "\n%{http_code}" --request PATCH "${{ steps.bytebase-login.outputs.api_url }}/policies/masking_rule?allow_missing=true&update_mask=payload" \ + response=$(curl -s -w "\n%{http_code}" --request PATCH "${{ steps.bytebase-login.outputs.api_url }}/workspaces/-/policies/masking_rule?allowMissing=true&updateMask=payload" \ --header "Authorization: Bearer ${{ steps.bytebase-login.outputs.token }}" \ + --header "Content-Type: application/json" \ --data @"$CHANGED_FILE") # Extract status code and response body diff --git a/masking/README.md b/masking/README.md index 74d4dbb..129c330 100644 --- a/masking/README.md +++ b/masking/README.md @@ -13,7 +13,7 @@ Docs: https://www.bytebase.com/docs/security/data-masking/semantic-types/ API: https://api.bytebase.com/#tag/settingservice/PATCH/v1/settings/{setting} ```bash -curl --request PATCH ${bytebase_url}/v1/settings/bb.workspace.semantic-types \ +curl --request PATCH ${bytebase_url}/v1/settings/SEMANTIC_TYPES \ --header 'Authorization: Bearer '${bytebase_token} \ --data @semantic-type.json ``` @@ -25,7 +25,7 @@ Docs: https://www.bytebase.com/docs/security/data-masking/global-masking-rule/ API: https://api.bytebase.com/#tag/orgpolicyservice/PATCH/v1/policies/{policy} ```bash -curl --request PATCH "${bytebase_url}/v1/policies/masking_rule?allow_missing=true&update_mask=payload" \ +curl --request PATCH "${bytebase_url}/v1/workspaces/-/policies/masking_rule?allowMissing=true&updateMask=payload" \ --header 'Authorization: Bearer '${bytebase_token} \ --data @global-masking-rule.json ``` @@ -37,14 +37,14 @@ Docs: https://www.bytebase.com/docs/security/data-masking/data-classification/ API: https://api.bytebase.com/#tag/settingservice/PATCH/v1/settings/{setting} ```bash -curl --request PATCH ${bytebase_url}/v1/settings/bb.workspace.data-classification \ +curl --request PATCH ${bytebase_url}/v1/settings/DATA_CLASSIFICATION \ --header 'Authorization: Bearer '${bytebase_token} \ --data @data-classification.json ``` -## Project-level masking exception +## Project-level masking exemption -Project-level masking exception to overrule the workspace-level setting. +Project-level masking exemption to overrule the workspace-level setting. https://github.com/bytebase/database-security-github-actions-example/tree/main/masking/projects/project-sample diff --git a/masking/data-classification.json b/masking/data-classification.json index d2caa69..41ed300 100644 --- a/masking/data-classification.json +++ b/masking/data-classification.json @@ -1,78 +1,66 @@ { - "name": "bb.workspace.data-classification", + "name": "settings/DATA_CLASSIFICATION", "value": { - "data_classification_setting_value": { + "dataClassification": { "configs": [ { "title": "Classification Example", "levels": [ { - "id": "1", "title": "Level 1", - "description": "" + "level": 1 }, { - "id": "2", "title": "Level 2", - "description": "" + "level": 2 }, { - "id": "3", "title": "Level 3", - "description": "" + "level": 3 }, { - "id": "4", "title": "Level 4", - "description": "" + "level": 4 } ], "classification": { "1": { "id": "1", - "title": "Basic", - "description": "" + "title": "Basic" }, "1-1": { "id": "1-1", "title": "Basic", - "description": "", - "levelId": "1" + "level": 1 }, "1-2": { "id": "1-2", "title": "Assert", - "description": "", - "levelId": "1" + "level": 1 }, "1-3": { "id": "1-3", "title": "Contact", - "description": "", - "levelId": "2" + "level": 2 }, "1-4": { "id": "1-4", "title": "Health", - "description": "", - "levelId": "2" + "level": 2 }, "2": { "id": "2", - "title": "Relationship", - "description": "" + "title": "Relationship" }, "2-1": { "id": "2-1", "title": "Social", - "description": "", - "levelId": "1" + "level": 1 }, "2-2": { "id": "2-2", "title": "Business", - "description": "", - "levelId": "1" + "level": 1 } } } diff --git a/masking/global-masking-rule-classification.json b/masking/global-masking-rule-classification.json index b17c7f5..81205f9 100644 --- a/masking/global-masking-rule-classification.json +++ b/masking/global-masking-rule-classification.json @@ -1,5 +1,5 @@ { - "name": "policies/masking_rule", + "name": "workspaces/-/policies/masking_rule", "inheritFromParent": false, "type": "MASKING_RULE", "maskingRulePolicy": { @@ -7,7 +7,7 @@ { "id": "76356d81-6231-4128-9be7-2c549fc505f5", "condition": { - "expression": "classification_level in [\"2\"]", + "expression": "resource.classification_level in [2]", "title": "", "description": "" }, @@ -16,7 +16,7 @@ { "id": "1ddc47c9-6ab6-4760-accd-947bc1a5f155", "condition": { - "expression": "classification_level in [\"4\"]", + "expression": "resource.classification_level in [4]", "title": "", "description": "" }, diff --git a/masking/global-masking-rule.json b/masking/global-masking-rule.json index 8082d4b..8164f48 100644 --- a/masking/global-masking-rule.json +++ b/masking/global-masking-rule.json @@ -1,5 +1,5 @@ { - "name": "policies/masking_rule", + "name": "workspaces/-/policies/masking_rule", "inheritFromParent": false, "type": "MASKING_RULE", "maskingRulePolicy": { @@ -7,7 +7,7 @@ { "id": "76356d81-6231-4128-9be7-2c549fc505f5", "condition": { - "expression": "environment_id == \"prod\"", + "expression": "resource.environment_id == \"prod\"", "title": "", "description": "" }, diff --git a/masking/projects/README.md b/masking/projects/README.md index ce3ecff..667a833 100644 --- a/masking/projects/README.md +++ b/masking/projects/README.md @@ -1,4 +1,4 @@ -# Project-level masking exception +# Project-level masking exemption -Masking exception is defined at the project level. It's considered as the exception to the masking +Masking exemption is defined at the project level. It's considered as the exemption to the masking policies defined at the [workspace level](https://github.com/bytebase/api-example/blob/main/data-security/masking). diff --git a/masking/projects/project-sample/README.md b/masking/projects/project-sample/README.md index 9e77b53..b33c0cd 100644 --- a/masking/projects/project-sample/README.md +++ b/masking/projects/project-sample/README.md @@ -1,4 +1,4 @@ -# Masking exception +# Masking exemption Docs: https://www.bytebase.com/docs/security/data-masking/access-unmasked-data/ @@ -6,7 +6,7 @@ API: https://api.bytebase.com/#tag/orgpolicyservice/PATCH/v1/projects/{project}/ ```bash export project_id=project-sample -curl --request PATCH "${bytebase_url}/v1/projects/${project_id}/policies/masking_exception?allow_missing=true&update_mask=payload" \ +curl --request PATCH "${bytebase_url}/v1/projects/${project_id}/policies/masking_exemption?allowMissing=true&updateMask=payload" \ --header 'Authorization: Bearer '${bytebase_token} \ - --data @masking-exception.json + --data @masking-exemption.json ``` diff --git a/masking/projects/project-sample/masking-exception.json b/masking/projects/project-sample/masking-exemption.json similarity index 77% rename from masking/projects/project-sample/masking-exception.json rename to masking/projects/project-sample/masking-exemption.json index 314a6a3..fbd79ee 100644 --- a/masking/projects/project-sample/masking-exception.json +++ b/masking/projects/project-sample/masking-exemption.json @@ -1,11 +1,10 @@ { "inheritFromParent": false, - "type": "MASKING_EXCEPTION", - "maskingExceptionPolicy": { - "maskingExceptions": [ + "type": "MASKING_EXEMPTION", + "maskingExemptionPolicy": { + "exemptions": [ { - "action": "EXPORT", - "member": "user:dev@example.com", + "members": ["user:dev@example.com"], "condition": { "expression": "resource.instance_id == \"prod-sample-instance\" && resource.database_name == \"hr_prod\" && resource.schema_name == \"public\" && resource.table_name == \"salary\" && resource.column_name == \"amount\"", "title": "", @@ -13,8 +12,7 @@ } }, { - "action": "QUERY", - "member": "user:dev2@example.com", + "members": ["user:dev2@example.com"], "condition": { "expression": "resource.instance_id == \"prod-sample-instance\" && resource.database_name == \"hr_prod\" && resource.schema_name == \"public\" && resource.table_name == \"salary\" && resource.column_name == \"amount\"", "title": "", @@ -22,8 +20,7 @@ } }, { - "action": "QUERY", - "member": "group:contractor@example.com", + "members": ["group:contractor@example.com"], "condition": { "expression": "resource.instance_id == \"prod-sample-instance\" && resource.database_name == \"hr_prod\" && resource.schema_name == \"public\" && resource.table_name == \"salary\" && resource.column_name == \"amount\"", "title": "", diff --git a/masking/semantic-type.json b/masking/semantic-type.json index f03e55c..5555da3 100644 --- a/masking/semantic-type.json +++ b/masking/semantic-type.json @@ -1,7 +1,7 @@ { - "name": "bb.workspace.semantic-types", + "name": "settings/SEMANTIC_TYPES", "value": { - "semanticTypeSettingValue": { + "semanticType": { "types": [ { "id": "bb.default",