-
Notifications
You must be signed in to change notification settings - Fork 2k
feat(storage): add samples and system tests for bucket encryption enforcement #4272
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
622dafd
21daffe
69a6b0d
be2f205
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,76 @@ | ||
| // Copyright 2026 Google LLC | ||
| // | ||
| // Licensed under the Apache License, Version 2.0 (the "License"); | ||
| // you may not use this file except in compliance with the License. | ||
| // You may obtain a copy of the License at | ||
| // | ||
| // http://www.apache.org/licenses/LICENSE-2.0 | ||
| // | ||
| // Unless required by applicable law or agreed to in writing, software | ||
| // distributed under the License is distributed on an "AS IS" BASIS, | ||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| // See the License for the specific language governing permissions and | ||
| // limitations under the License. | ||
|
|
||
| 'use strict'; | ||
|
|
||
| // sample-metadata: | ||
| // title: Get Bucket Encryption Enforcement | ||
| // description: Retrieves the current encryption enforcement configurations for a bucket. | ||
| // usage: node getBucketEncryptionEnforcementConfig.js <BUCKET_NAME> | ||
|
|
||
| function main(bucketName = 'my-bucket') { | ||
| // [START storage_get_encryption_enforcement_config] | ||
| /** | ||
| * TODO(developer): Uncomment the following lines before running the sample. | ||
| */ | ||
| // The ID of your GCS bucket | ||
| // const bucketName = 'your-unique-bucket-name'; | ||
|
|
||
| // Imports the Google Cloud client library | ||
| const {Storage} = require('@google-cloud/storage'); | ||
|
|
||
| // Creates a client | ||
| const storage = new Storage(); | ||
|
|
||
| async function getBucketEncryptionEnforcementConfig() { | ||
| const [metadata] = await storage.bucket(bucketName).getMetadata(); | ||
|
|
||
| console.log( | ||
| `Encryption enforcement configuration for bucket ${bucketName}.` | ||
| ); | ||
| const enc = metadata.encryption; | ||
| if (!enc) { | ||
| console.log( | ||
| 'No encryption configuration found (Default GMEK is active).' | ||
| ); | ||
| return; | ||
| } | ||
| console.log(`Default KMS Key: ${enc.defaultKmsKeyName || 'None'}`); | ||
|
|
||
| const printConfig = (label, config) => { | ||
| if (config) { | ||
| console.log(`${label}:`); | ||
| console.log(` Mode: ${config.restrictionMode}`); | ||
| console.log(` Effective: ${config.effectiveTime}`); | ||
| } | ||
| }; | ||
|
|
||
| printConfig( | ||
| 'Google Managed (GMEK) Enforcement', | ||
| enc.googleManagedEncryptionEnforcementConfig | ||
| ); | ||
| printConfig( | ||
| 'Customer Managed (CMEK) Enforcement', | ||
| enc.customerManagedEncryptionEnforcementConfig | ||
| ); | ||
| printConfig( | ||
| 'Customer Supplied (CSEK) Enforcement', | ||
| enc.customerSuppliedEncryptionEnforcementConfig | ||
| ); | ||
| } | ||
|
|
||
| getBucketEncryptionEnforcementConfig().catch(console.error); | ||
| // [END storage_get_encryption_enforcement_config] | ||
| } | ||
| main(...process.argv.slice(2)); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,93 @@ | ||
| // Copyright 2026 Google LLC | ||
| // | ||
| // Licensed under the Apache License, Version 2.0 (the "License"); | ||
| // you may not use this file except in compliance with the License. | ||
| // You may obtain a copy of the License at | ||
| // | ||
| // http://www.apache.org/licenses/LICENSE-2.0 | ||
| // | ||
| // Unless required by applicable law or agreed to in writing, software | ||
| // distributed under the License is distributed on an "AS IS" BASIS, | ||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| // See the License for the specific language governing permissions and | ||
| // limitations under the License. | ||
|
|
||
| 'use strict'; | ||
|
|
||
| // sample-metadata: | ||
| // title: Set Bucket Encryption Enforcement | ||
| // description: Configures a bucket to enforce specific encryption types (e.g., CMEK-only). | ||
| // usage: node setBucketEncryptionEnforcementConfig.js <BUCKET_NAME> <KMS_KEY_NAME> | ||
|
|
||
| function main( | ||
| bucketName = 'my-bucket', | ||
| defaultKmsKeyName = process.env.GOOGLE_CLOUD_KMS_KEY_ASIA | ||
| ) { | ||
| // [START storage_set_encryption_enforcement_config] | ||
| /** | ||
| * TODO(developer): Uncomment the following lines before running the sample. | ||
| */ | ||
| // The ID of your GCS bucket | ||
| // const bucketName = 'your-unique-bucket-name'; | ||
|
|
||
| // The name of the KMS key to be used as the default | ||
| // const defaultKmsKeyName = 'my-key'; | ||
|
|
||
| // Imports the Google Cloud client library | ||
| const {Storage} = require('@google-cloud/storage'); | ||
|
|
||
| // Creates a client | ||
| const storage = new Storage(); | ||
|
|
||
| async function setBucketEncryptionEnforcementConfig() { | ||
| const options = { | ||
| encryption: { | ||
| defaultKmsKeyName, | ||
| googleManagedEncryptionEnforcementConfig: { | ||
| restrictionMode: 'FullyRestricted', | ||
| }, | ||
| customerSuppliedEncryptionEnforcementConfig: { | ||
| restrictionMode: 'FullyRestricted', | ||
| }, | ||
| customerManagedEncryptionEnforcementConfig: { | ||
| restrictionMode: 'NotRestricted', | ||
| }, | ||
| }, | ||
| }; | ||
|
|
||
| const [metadata] = await storage.bucket(bucketName).setMetadata(options); | ||
|
|
||
| console.log( | ||
| `Encryption enforcement configuration updated for bucket ${bucketName}.` | ||
| ); | ||
| const enc = metadata.encryption; | ||
| if (enc) { | ||
| console.log(`Default KMS Key: ${enc.defaultKmsKeyName}`); | ||
|
|
||
| const logEnforcement = (label, config) => { | ||
| if (config) { | ||
| console.log(`${label}:`); | ||
| console.log(` Mode: ${config.restrictionMode}`); | ||
| console.log(` Effective: ${config.effectiveTime}`); | ||
| } | ||
| }; | ||
|
|
||
| logEnforcement( | ||
| 'Google Managed (GMEK) Enforcement', | ||
| enc.googleManagedEncryptionEnforcementConfig | ||
| ); | ||
| logEnforcement( | ||
| 'Customer Managed (CMEK) Enforcement', | ||
| enc.customerManagedEncryptionEnforcementConfig | ||
| ); | ||
| logEnforcement( | ||
| 'Customer Supplied (CSEK) Enforcement', | ||
| enc.customerSuppliedEncryptionEnforcementConfig | ||
| ); | ||
| } | ||
| } | ||
|
|
||
| setBucketEncryptionEnforcementConfig().catch(console.error); | ||
| // [END storage_set_encryption_enforcement_config] | ||
| } | ||
| main(...process.argv.slice(2)); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,112 @@ | ||
| // Copyright 2019 Google LLC | ||
| // | ||
| // Licensed under the Apache License, Version 2.0 (the "License"); | ||
| // you may not use this file except in compliance with the License. | ||
| // You may obtain a copy of the License at | ||
| // | ||
| // http://www.apache.org/licenses/LICENSE-2.0 | ||
| // | ||
| // Unless required by applicable law or agreed to in writing, software | ||
| // distributed under the License is distributed on an "AS IS" BASIS, | ||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| // See the License for the specific language governing permissions and | ||
| // limitations under the License. | ||
|
|
||
| 'use strict'; | ||
|
|
||
| const {Storage} = require('@google-cloud/storage'); | ||
| const {assert} = require('chai'); | ||
| const {before, after, afterEach, it} = require('mocha'); | ||
| const cp = require('child_process'); | ||
| const uuid = require('uuid'); | ||
|
|
||
| const execSync = cmd => cp.execSync(cmd, {encoding: 'utf-8'}); | ||
|
|
||
| const storage = new Storage(); | ||
| const samplesTestBucketPrefix = `nodejs-storage-samples-${uuid.v4()}`; | ||
| const bucketName = `${samplesTestBucketPrefix}-a`; | ||
| const defaultKmsKeyName = process.env.GOOGLE_CLOUD_KMS_KEY_ASIA; | ||
| const bucket = storage.bucket(bucketName); | ||
|
|
||
| before(async () => { | ||
| await storage.createBucket(bucketName); | ||
| }); | ||
|
|
||
| async function deleteAllBucketsAsync() { | ||
| const [buckets] = await storage.getBuckets({prefix: samplesTestBucketPrefix}); | ||
|
|
||
| for (const bucket of buckets) { | ||
| await bucket.deleteFiles({force: true}); | ||
| await bucket.delete({ignoreNotFound: true}); | ||
| } | ||
| } | ||
|
|
||
| after(deleteAllBucketsAsync); | ||
| afterEach(async () => { | ||
| await new Promise(res => setTimeout(res, 1000)); | ||
| }); | ||
|
|
||
| it('should set bucket encryption enforcement configuration', async () => { | ||
| const output = execSync( | ||
| `node setBucketEncryptionEnforcementConfig.js ${bucketName} ${defaultKmsKeyName}` | ||
| ); | ||
|
|
||
| assert.include( | ||
| output, | ||
| `Encryption enforcement configuration updated for bucket ${bucketName}.` | ||
| ); | ||
|
|
||
| assert.include(output, `Default KMS Key: ${defaultKmsKeyName}`); | ||
|
|
||
| assert.include(output, 'Google Managed (GMEK) Enforcement:'); | ||
| assert.include(output, 'Mode: FullyRestricted'); | ||
|
|
||
| assert.include(output, 'Customer Managed (CMEK) Enforcement:'); | ||
| assert.include(output, 'Mode: NotRestricted'); | ||
|
|
||
| assert.include(output, 'Customer Supplied (CSEK) Enforcement:'); | ||
| assert.include(output, 'Mode: FullyRestricted'); | ||
|
|
||
| assert.match(output, new RegExp('Effective:')); | ||
|
|
||
| const [metadata] = await bucket.getMetadata(); | ||
| assert.strictEqual( | ||
| metadata.encryption.googleManagedEncryptionEnforcementConfig | ||
| .restrictionMode, | ||
| 'FullyRestricted' | ||
| ); | ||
| }); | ||
|
|
||
| it('should get bucket encryption enforcement configuration', async () => { | ||
| const output = execSync( | ||
| `node getBucketEncryptionEnforcementConfig.js ${bucketName}` | ||
| ); | ||
|
|
||
| assert.include( | ||
| output, | ||
| `Encryption enforcement configuration for bucket ${bucketName}.` | ||
| ); | ||
| assert.include(output, `Default KMS Key: ${defaultKmsKeyName}`); | ||
|
|
||
| assert.include(output, 'Google Managed (GMEK) Enforcement:'); | ||
| assert.include(output, 'Mode: FullyRestricted'); | ||
| assert.match(output, /Effective:/); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These tests are not robust, it's just checking a substring match. as in this case you're trying to assert There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The Better Architecture: Test the State, not the String (Testing the API) // 1. Assert the script ran without throwing errors // 2. Fetch the actual truth from the GCP API // 3. Assert against the actual state object // Add equivalent assertions for CMEK and CSEK based on the actual |
||
| }); | ||
|
|
||
| it('should update and then remove bucket encryption enforcement configuration', async () => { | ||
| const output = execSync( | ||
| `node updateBucketEncryptionEnforcementConfig.js ${bucketName}` | ||
| ); | ||
|
|
||
| assert.include( | ||
| output, | ||
| `Google-managed encryption enforcement set to FullyRestricted for ${bucketName}.` | ||
| ); | ||
| assert.include( | ||
| output, | ||
| `All encryption enforcement configurations removed from bucket ${bucketName}.` | ||
| ); | ||
|
|
||
| const [metadata] = await bucket.getMetadata(); | ||
| assert.ok(!metadata.encryption); | ||
| }); | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,74 @@ | ||
| // Copyright 2026 Google LLC | ||
| // | ||
| // Licensed under the Apache License, Version 2.0 (the "License"); | ||
| // you may not use this file except in compliance with the License. | ||
| // You may obtain a copy of the License at | ||
| // | ||
| // http://www.apache.org/licenses/LICENSE-2.0 | ||
| // | ||
| // Unless required by applicable law or agreed to in writing, software | ||
| // distributed under the License is distributed on an "AS IS" BASIS, | ||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| // See the License for the specific language governing permissions and | ||
| // limitations under the License. | ||
|
|
||
| 'use strict'; | ||
|
|
||
| // sample-metadata: | ||
| // title: Update Bucket Encryption Enforcement Config | ||
| // description: Updates and then removes encryption enforcement configurations from a bucket. | ||
| // usage: node updateBucketEncryptionEnforcementConfig.js <BUCKET_NAME> | ||
|
|
||
| function main(bucketName = 'my-bucket') { | ||
| // [START storage_update_bucket_encryption_enforcement_config] | ||
| /** | ||
| * TODO(developer): Uncomment the following lines before running the sample. | ||
| */ | ||
| // The ID of your GCS bucket | ||
| // const bucketName = 'your-unique-bucket-name'; | ||
|
|
||
| // Imports the Google Cloud client library | ||
| const {Storage} = require('@google-cloud/storage'); | ||
|
|
||
| // Creates a client | ||
| const storage = new Storage(); | ||
|
|
||
| async function updateBucketEncryptionEnforcementConfig() { | ||
| const bucket = storage.bucket(bucketName); | ||
|
|
||
| // Update a specific encryption type's restriction mode | ||
| // This partial update preserves other existing encryption settings. | ||
| const updateOptions = { | ||
| encryption: { | ||
| googleManagedEncryptionEnforcementConfig: { | ||
| restrictionMode: 'FullyRestricted', | ||
| }, | ||
| }, | ||
| }; | ||
|
|
||
| await bucket.setMetadata(updateOptions); | ||
| console.log( | ||
| `Google-managed encryption enforcement set to FullyRestricted for ${bucketName}.` | ||
| ); | ||
|
|
||
| // Remove all encryption enforcement configurations altogether | ||
| // Setting these values to null removes the policies from the bucket metadata. | ||
| const clearOptions = { | ||
| encryption: { | ||
| defaultKmsKeyName: null, | ||
| googleManagedEncryptionEnforcementConfig: null, | ||
| customerSuppliedEncryptionEnforcementConfig: null, | ||
| customerManagedEncryptionEnforcementConfig: null, | ||
| }, | ||
| }; | ||
|
|
||
| await bucket.setMetadata(clearOptions); | ||
| console.log( | ||
| `All encryption enforcement configurations removed from bucket ${bucketName}.` | ||
| ); | ||
| } | ||
|
|
||
| updateBucketEncryptionEnforcementConfig().catch(console.error); | ||
| // [END storage_update_bucket_encryption_enforcement_config] | ||
| } | ||
| main(...process.argv.slice(2)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: 2026