From 56b04254371d43c060878c97bec2deb514c40cc2 Mon Sep 17 00:00:00 2001 From: Shubhangi Singh Date: Wed, 21 Jan 2026 17:27:41 +0000 Subject: [PATCH 1/6] wip-- create bucket with ip filter working --- .../lib/google/cloud/storage/bucket.rb | 9 + .../lib/google/cloud/storage/project.rb | 8 +- .../samples/acceptance/buckets_test.rb | 1163 +++++++++-------- .../storage_create_bucket_with_ip_filter.rb | 129 ++ 4 files changed, 746 insertions(+), 563 deletions(-) create mode 100644 google-cloud-storage/samples/storage_create_bucket_with_ip_filter.rb diff --git a/google-cloud-storage/lib/google/cloud/storage/bucket.rb b/google-cloud-storage/lib/google/cloud/storage/bucket.rb index ca8461354bb7..2be3ade74b38 100644 --- a/google-cloud-storage/lib/google/cloud/storage/bucket.rb +++ b/google-cloud-storage/lib/google/cloud/storage/bucket.rb @@ -1410,6 +1410,15 @@ def delete if_metageneration_match: nil, if_metageneration_not_match: nil user_project: user_project end + def ip_filter + @gapi.ip_filter + end + + def ip_filter= new_ip_filter + @gapi.ip_filter = new_ip_filter || {} + patch_gapi! :ip_filter + end + ## # Retrieves a list of files matching the criteria. # diff --git a/google-cloud-storage/lib/google/cloud/storage/project.rb b/google-cloud-storage/lib/google/cloud/storage/project.rb index 47e4ffc32da4..3d971a53af50 100644 --- a/google-cloud-storage/lib/google/cloud/storage/project.rb +++ b/google-cloud-storage/lib/google/cloud/storage/project.rb @@ -477,12 +477,15 @@ def create_bucket bucket_name, user_project: nil, autoclass_enabled: false, enable_object_retention: nil, - hierarchical_namespace: nil + hierarchical_namespace: nil, + ip_filter: nil + params = { name: bucket_name, location: location, custom_placement_config: custom_placement_config, - hierarchical_namespace: hierarchical_namespace + hierarchical_namespace: hierarchical_namespace, + ip_filter: ip_filter }.delete_if { |_, v| v.nil? } new_bucket = Google::Apis::StorageV1::Bucket.new(**params) storage_class = storage_class_for storage_class @@ -496,6 +499,7 @@ def create_bucket bucket_name, b.versioning = versioning unless versioning.nil? b.requester_pays = requester_pays unless requester_pays.nil? b.hierarchical_namespace = hierarchical_namespace unless hierarchical_namespace.nil? + b.ip_filter = ip_filter unless ip_filter.nil? end yield updater if block_given? updater.check_for_changed_labels! diff --git a/google-cloud-storage/samples/acceptance/buckets_test.rb b/google-cloud-storage/samples/acceptance/buckets_test.rb index bb78ba9bbe44..e29644d5d196 100644 --- a/google-cloud-storage/samples/acceptance/buckets_test.rb +++ b/google-cloud-storage/samples/acceptance/buckets_test.rb @@ -21,6 +21,7 @@ require_relative "../storage_create_bucket_class_location" require_relative "../storage_create_bucket_dual_region" require_relative "../storage_create_bucket_hierarchical_namespace" +require_relative "../storage_create_bucket_with_ip_filter" require_relative "../storage_create_bucket_with_object_retention" require_relative "../storage_define_bucket_website_configuration" require_relative "../storage_delete_bucket" @@ -55,6 +56,7 @@ require_relative "../storage_get_autoclass" require_relative "../storage_set_autoclass" require_relative "../storage_move_object" +require 'pry' describe "Buckets Snippets" do let(:storage_client) { Google::Cloud::Storage.new } @@ -62,577 +64,616 @@ let(:retention_period) { rand 1..99 } let(:bucket) { fixture_bucket } - describe "bucket lifecycle" do - it "create_bucket, create_bucket_class_location, list_buckets, get_bucket_metadata, delete_bucket" do - # create_bucket - bucket_name = random_bucket_name - refute storage_client.bucket bucket_name + # describe "bucket lifecycle" do + # it "create_bucket, create_bucket_class_location, list_buckets, get_bucket_metadata, delete_bucket" do + # # create_bucket + # bucket_name = random_bucket_name + # refute storage_client.bucket bucket_name + + # retry_resource_exhaustion do + # assert_output "Created bucket: #{bucket_name}\n" do + # create_bucket bucket_name: bucket_name + # end + # end + + # refute_nil storage_client.bucket bucket_name + + # # create_bucket_class_location + + # secondary_bucket_name = random_bucket_name + # location = "ASIA" + # storage_class = "COLDLINE" + # refute storage_client.bucket secondary_bucket_name + + # retry_resource_exhaustion do + # assert_output "Created bucket #{secondary_bucket_name} in #{location} with #{storage_class} class\n" do + # create_bucket_class_location bucket_name: secondary_bucket_name + # end + # end + + # secondary_bucket = storage_client.bucket secondary_bucket_name + # refute_nil secondary_bucket + # assert_equal location, secondary_bucket.location + # assert_equal storage_class, secondary_bucket.storage_class + + # # list_buckets + # out, _err = capture_io do + # list_buckets + # end + + # assert_includes out, "ruby-storage-samples-" + + # # get_bucket_metadata + # out, _err = capture_io do + # get_bucket_metadata bucket_name: bucket_name + # end + + # assert_includes out, bucket_name + + # # delete_bucket + # assert_output "Deleted bucket: #{bucket_name}\n" do + # delete_bucket bucket_name: bucket_name + # end + + + # refute storage_client.bucket bucket_name + + # delete_bucket_helper bucket_name + # delete_bucket_helper secondary_bucket_name + # end + # end + + # describe "storage_create_bucket_dual_region" do + # it "creates dual region bucket" do + # location = "US" + # region_1 = "US-EAST1" + # region_2 = "US-WEST1" + # location_type = "dual-region" + # bucket_name = random_bucket_name + # refute storage_client.bucket bucket_name + + # expected = "Bucket #{bucket_name} created:\n" + # expected += "- location: #{location}\n" + # expected += "- location_type: #{location_type}\n" + # expected += "- custom_placement_config:\n" + # expected += " - data_locations: #{[region_1, region_2]}\n" + + # retry_resource_exhaustion do + # assert_output expected do + # StorageCreateBucketDualRegion.new.storage_create_bucket_dual_region bucket_name: bucket_name, + # region_1: region_1, + # region_2: region_2 + # end + # end + + # refute_nil storage_client.bucket bucket_name + + # delete_bucket_helper bucket_name + # end + # end + + # describe "storage_create_bucket_hierarchical_namespace" do + # it "creates hierarchical namespace enabled bucket" do + # bucket_name = random_bucket_name + # refute storage_client.bucket bucket_name + + # expected = "Created bucket #{bucket_name} with Hierarchical Namespace enabled.\n" + + # retry_resource_exhaustion do + # assert_output expected do + # create_bucket_hierarchical_namespace bucket_name: bucket_name + # end + # end + + # refute_nil storage_client.bucket bucket_name + + # delete_bucket_helper bucket_name + # end + # end + + describe "storage_create_bucket_ip_filter" do - retry_resource_exhaustion do - assert_output "Created bucket: #{bucket_name}\n" do - create_bucket bucket_name: bucket_name - end - end - - refute_nil storage_client.bucket bucket_name - - # create_bucket_class_location - - secondary_bucket_name = random_bucket_name - location = "ASIA" - storage_class = "COLDLINE" - refute storage_client.bucket secondary_bucket_name - - retry_resource_exhaustion do - assert_output "Created bucket #{secondary_bucket_name} in #{location} with #{storage_class} class\n" do - create_bucket_class_location bucket_name: secondary_bucket_name - end - end - - secondary_bucket = storage_client.bucket secondary_bucket_name - refute_nil secondary_bucket - assert_equal location, secondary_bucket.location - assert_equal storage_class, secondary_bucket.storage_class - - # list_buckets - out, _err = capture_io do - list_buckets - end - - assert_includes out, "ruby-storage-samples-" - - # get_bucket_metadata - out, _err = capture_io do - get_bucket_metadata bucket_name: bucket_name - end - - assert_includes out, bucket_name - - # delete_bucket - assert_output "Deleted bucket: #{bucket_name}\n" do - delete_bucket bucket_name: bucket_name - end - - - refute storage_client.bucket bucket_name - - delete_bucket_helper bucket_name - delete_bucket_helper secondary_bucket_name - end - end - - describe "storage_create_bucket_dual_region" do - it "creates dual region bucket" do - location = "US" - region_1 = "US-EAST1" - region_2 = "US-WEST1" - location_type = "dual-region" - bucket_name = random_bucket_name - refute storage_client.bucket bucket_name - - expected = "Bucket #{bucket_name} created:\n" - expected += "- location: #{location}\n" - expected += "- location_type: #{location_type}\n" - expected += "- custom_placement_config:\n" - expected += " - data_locations: #{[region_1, region_2]}\n" - - retry_resource_exhaustion do - assert_output expected do - StorageCreateBucketDualRegion.new.storage_create_bucket_dual_region bucket_name: bucket_name, - region_1: region_1, - region_2: region_2 - end - end - - refute_nil storage_client.bucket bucket_name - - delete_bucket_helper bucket_name + before :all do + @bucket_name = random_bucket_name end - end - - describe "storage_create_bucket_hierarchical_namespace" do - it "creates hierarchical namespace enabled bucket" do - bucket_name = random_bucket_name - refute storage_client.bucket bucket_name - - expected = "Created bucket #{bucket_name} with Hierarchical Namespace enabled.\n" - - retry_resource_exhaustion do - assert_output expected do - create_bucket_hierarchical_namespace bucket_name: bucket_name - end - end - - refute_nil storage_client.bucket bucket_name - delete_bucket_helper bucket_name + after :all do + binding.pry + # delete_bucket_helper @bucket_name end - end - - describe "storage_create_bucket_with_object_retention" do - it "creates a bucket with object retention enabled." do - bucket_name = random_bucket_name - refute storage_client.bucket bucket_name - - expected = "Created bucket #{bucket_name} with object retention setting: Enabled\n" + # it "creates IP filter enabled bucket" do + # expected = "Created bucket #{@bucket_name} with IP filter enabled.\n" + # retry_resource_exhaustion do + # assert_output expected do + # create_bucket_with_ip_filter bucket_name: @bucket_name + # end + # end + # end + + # it "removes IP filter of an existing bucket" do + # expected = "Updated IP filter for bucket #{@bucket_name}.\n" + # retry_resource_exhaustion do + # assert_output expected do + # removes_bucket_ip_filter bucket_name: @bucket_name + # end + # end + # end + + it "Updates IP filter of an existing bucket" do + expected = "Updated bucket #{@bucket_name+"-1"} with IP filter enabled.\n" retry_resource_exhaustion do assert_output expected do - create_bucket_with_object_retention bucket_name: bucket_name + update_bucket_with_ip_filter bucket_name: @bucket_name+"-1" end end - - refute_nil storage_client.bucket bucket_name - - file_name = "test_object_retention" - - bucket = storage_client.bucket bucket_name - - out, _err = capture_io do - set_object_retention_policy bucket_name: bucket.name, - content: "hello world", - destination_file_name: file_name - end - - assert_includes out, "Retention policy for file #{file_name}" - - file = bucket.file file_name - file.retention = { - mode: nil, - retain_until_time: nil, - override_unlocked_retention: true - } - delete_bucket_helper bucket_name end end - describe "autoclass" do - it "get_autoclass, set_autoclass" do - bucket_name = random_bucket_name - refute storage_client.bucket bucket_name - - storage_client.create_bucket bucket_name, autoclass_enabled: true - - assert_output(/autoclass config set to true./) do - get_autoclass bucket_name: bucket_name - end - - assert_output(/autoclass terminal storage class set to NEARLINE./) do - get_autoclass bucket_name: bucket_name - end - - assert_output(/autoclass terminal storage class set to ARCHIVE./) do - set_autoclass bucket_name: bucket_name, toggle: true, terminal_storage_class: "ARCHIVE" - end - - assert_output(/autoclass config set to false./) do - set_autoclass bucket_name: bucket_name, toggle: false - end - - delete_bucket_helper bucket_name - end - end - - describe "cors" do - it "cors_configuration, remove_cors_configuration" do - bucket.cors { |c| c.clear } - assert bucket.cors.empty? - - # cors_configuration - assert_output "Set CORS policies for bucket #{bucket.name}\n" do - cors_configuration bucket_name: bucket.name - end - - bucket.refresh! - assert_equal 1, bucket.cors.count - rule = bucket.cors.first - assert_equal ["*"], rule.origin - assert_equal ["PUT", "POST"], rule.methods - assert_equal ["Content-Type", "x-goog-resumable"], rule.headers - assert_equal 3600, rule.max_age - - # remove_cors_configuration - assert_output "Remove CORS policies for bucket #{bucket.name}\n" do - remove_cors_configuration bucket_name: bucket.name - end - bucket.refresh! - assert bucket.cors.empty? - end - end - - describe "requester_pays" do - it "enable_requester_pays, disable_requester_pays, get_requester_pays_status" do - # enable_requester_pays - bucket.requester_pays = false - - assert_output "Requester pays has been enabled for #{bucket.name}\n" do - enable_requester_pays bucket_name: bucket.name - end - bucket.refresh! - assert bucket.requester_pays? - - # get_requester_pays_status - assert_output "Requester pays status is enabled for #{bucket.name}\n" do - get_requester_pays_status bucket_name: bucket.name - end - assert bucket.requester_pays? - - # disable_requester_pays - assert_output "Requester pays has been disabled for #{bucket.name}\n" do - disable_requester_pays bucket_name: bucket.name - end - bucket.refresh! - refute bucket.requester_pays? - - # get_requester_pays_status - assert_output "Requester pays status is disabled for #{bucket.name}\n" do - get_requester_pays_status bucket_name: bucket.name - end - refute bucket.requester_pays? - end - end - - describe "uniform_bucket_level_access" do - it "enable_uniform_bucket_level_access, get_uniform_bucket_level_access, disable_uniform_bucket_level_access" do - # enable_uniform_bucket_level_access - bucket.uniform_bucket_level_access = false - - assert_output "Uniform bucket-level access was enabled for #{bucket.name}.\n" do - enable_uniform_bucket_level_access bucket_name: bucket.name - end - - bucket.refresh! - assert bucket.uniform_bucket_level_access? - - # get_uniform_bucket_level_access - assert_output "Uniform bucket-level access is enabled for #{bucket.name}.\nBucket " \ - "will be locked on #{bucket.uniform_bucket_level_access_locked_at}.\n" do - get_uniform_bucket_level_access bucket_name: bucket.name - end - assert bucket.uniform_bucket_level_access? - - # disable_uniform_bucket_level_access - assert_output "Uniform bucket-level access was disabled for #{bucket.name}.\n" do - disable_uniform_bucket_level_access bucket_name: bucket.name - end - - bucket.refresh! - refute bucket.uniform_bucket_level_access? - - # get_uniform_bucket_level_access - assert_output "Uniform bucket-level access is disabled for #{bucket.name}.\n" do - get_uniform_bucket_level_access bucket_name: bucket.name - end - refute bucket.uniform_bucket_level_access? - - bucket.uniform_bucket_level_access = false - end - end - - describe "default Cloud KMS encryption key" do - it "set_bucket_default_kms_key, bucket_delete_default_kms_key" do - refute bucket.default_kms_key - - # set_bucket_default_kms_key - assert_output "Default KMS key for #{bucket.name} was set to #{kms_key}\n" do - set_bucket_default_kms_key bucket_name: bucket.name, - default_kms_key: kms_key - end - - bucket.refresh! - assert_equal bucket.default_kms_key, kms_key - - # bucket_delete_default_kms_key - assert_output "Default KMS key was removed from #{bucket.name}\n" do - bucket_delete_default_kms_key bucket_name: bucket.name - end - - bucket.refresh! - refute bucket.default_kms_key - end - end - - describe "get bucket class and location data" do - bucket_name = random_bucket_name - location = "US" - storage_class = "COLDLINE" - - it "get_bucket_class_and_location" do - storage_client.create_bucket bucket_name, - location: location, - storage_class: storage_class - expected_output = "Bucket #{bucket_name} storage class is " \ - "#{storage_class}, and the location is #{location}\n" - assert_output expected_output do - get_bucket_class_and_location bucket_name: bucket_name - end - end - end - - describe "labels" do - it "add_bucket_label, remove_bucket_label" do - # add_bucket_label - label_key = "label_key" - label_value = "label_value" - - assert_output "Added label #{label_key} with value #{label_value} to #{bucket.name}\n" do - add_bucket_label bucket_name: bucket.name, - label_value: label_value, - label_key: label_key - end - - bucket.refresh! - assert_equal bucket.labels[label_key], label_value - - # remove_bucket_label - assert_output "Deleted label #{label_key} from #{bucket.name}\n" do - remove_bucket_label bucket_name: bucket.name, - label_key: label_key - end - - bucket.refresh! - assert bucket.labels[label_key].empty? - end - end - - describe "lifecycle management" do - let(:bucket) { create_bucket_helper random_bucket_name } - after { delete_bucket_helper bucket.name } - - it "enable_bucket_lifecycle_management, disable_bucket_lifecycle_management" do - # enable_bucket_lifecycle_management - out, _err = capture_io do - enable_bucket_lifecycle_management bucket_name: bucket.name - end - - assert_includes out, "Lifecycle management is enabled" - - # disable_bucket_lifecycle_management - out, _err = capture_io do - disable_bucket_lifecycle_management bucket_name: bucket.name - end - - assert_includes out, "Lifecycle management is disabled" - end - end - - describe "retention policy" do - let(:bucket) { create_bucket_helper random_bucket_name } - after { delete_bucket_helper bucket.name } - - it "set_retention_policy, get_retention_policy, remove_retention_policy" do - # set_retention_policy - assert_output "Retention period for #{bucket.name} is now #{retention_period} seconds.\n" do - set_retention_policy bucket_name: bucket.name, - retention_period: retention_period - end - - bucket.refresh! - assert_equal bucket.retention_period, retention_period - - # get_retention_policy - out, _err = capture_io do - get_retention_policy bucket_name: bucket.name - end - - assert_includes out, "period: #{retention_period}\n" - - # remove_retention_policy - assert_equal bucket.retention_period, retention_period - assert_output "Retention policy for #{bucket.name} has been removed.\n" do - remove_retention_policy bucket_name: bucket.name - end - - bucket.refresh! - refute bucket.retention_period - - # lock_retention_policy - bucket.retention_period = retention_period - out, _err = capture_io do - lock_retention_policy bucket_name: bucket.name - end - - assert_includes out, "Retention policy for #{bucket.name} is now locked." - bucket.refresh! - assert bucket.retention_policy_locked? - - # remove_retention_policy - assert_output "Policy is locked and retention policy can't be removed.\n" do - remove_retention_policy bucket_name: bucket.name - end - end - end - - describe "default_event_based_hold" do - it "enable_default_event_based_hold, get_default_event_based_hold, disable_default_event_based_hold" do - # enable_default_event_based_hold - assert_output "Default event-based hold was enabled for #{bucket.name}.\n" do - enable_default_event_based_hold bucket_name: bucket.name - end - - bucket.refresh! - assert bucket.default_event_based_hold? - - # get_default_event_based_hold - assert_output "Default event-based hold is enabled for #{bucket.name}.\n" do - get_default_event_based_hold bucket_name: bucket.name - end - - # disable_default_event_based_hold - bucket.update do |b| - b.default_event_based_hold = true - end - - assert_output "Default event-based hold was disabled for #{bucket.name}.\n" do - disable_default_event_based_hold bucket_name: bucket.name - end - - bucket.refresh! - refute bucket.default_event_based_hold? - - # get_default_event_based_hold - assert_output "Default event-based hold is not enabled for #{bucket.name}.\n" do - get_default_event_based_hold bucket_name: bucket.name - end - end - end - - describe "storage_class" do - it "change_default_storage_class" do - assert_equal "STANDARD", bucket.storage_class - - assert_output "Default storage class for bucket #{bucket.name} has been set to COLDLINE\n" do - change_default_storage_class bucket_name: bucket.name - end - - bucket.refresh! - assert_equal "COLDLINE", bucket.storage_class - # teardown - bucket.storage_class = "STANDARD" - end - end - - describe "versioning" do - it "enable_versioning, disable_versioning" do - # enable_versioning - bucket.versioning = false - - assert_output "Versioning was enabled for bucket #{bucket.name}\n" do - enable_versioning bucket_name: bucket.name - end - bucket.refresh! - assert bucket.versioning? - - # disable_versioning - assert_output "Versioning was disabled for bucket #{bucket.name}\n" do - disable_versioning bucket_name: bucket.name - end - bucket.refresh! - refute bucket.versioning? - end - end - - describe "website_configuration" do - let(:main_page_suffix) { "index.html" } - let(:not_found_page) { "404.html" } - - it "define_bucket_website_configuration" do - expected_out = "Static website bucket #{bucket.name} is set up to use #{main_page_suffix} as the index page " \ - "and #{not_found_page} as the 404 page\n" - - assert_output expected_out do - define_bucket_website_configuration bucket_name: bucket.name, - main_page_suffix: main_page_suffix, - not_found_page: not_found_page - end - - bucket.refresh! - assert_equal main_page_suffix, bucket.website_main - assert_equal not_found_page, bucket.website_404 - end - end - - describe "public_access_prevention" do - it "set_public_access_prevention_enforced, get_public_access_prevention, " \ - "set_public_access_prevention_inherited" do - bucket.public_access_prevention = :inherited - bucket.refresh! - _(bucket.public_access_prevention).must_equal "inherited" - - # set_public_access_prevention_enforced - assert_output "Public access prevention is set to enforced for #{bucket.name}.\n" do - set_public_access_prevention_enforced bucket_name: bucket.name - end - - bucket.refresh! - _(bucket.public_access_prevention).must_equal "enforced" - - # get_public_access_prevention - assert_output "Public access prevention is 'enforced' for #{bucket.name}.\n" do - get_public_access_prevention bucket_name: bucket.name - end - _(bucket.public_access_prevention).must_equal "enforced" - - # set_public_access_prevention_inherited - assert_output "Public access prevention is 'inherited' for #{bucket.name}.\n" do - set_public_access_prevention_inherited bucket_name: bucket.name - end - - bucket.refresh! - _(bucket.public_access_prevention).must_equal "inherited" - bucket.public_access_prevention = :inherited - end - end - - describe "storage move file" do - let(:source_file) { "file_1_name_#{SecureRandom.hex}.txt" } - let(:destination_file) { "file_2_name_#{SecureRandom.hex}.txt" } - let :hns_bucket do - hierarchical_namespace = Google::Apis::StorageV1::Bucket::HierarchicalNamespace.new enabled: true - storage_client.create_bucket random_bucket_name do |b| - b.uniform_bucket_level_access = true - b.hierarchical_namespace = hierarchical_namespace - end - end - let :create_source_file do - file_content = "A" * (3 * 1024 * 1024) # 3 MB of 'A' characters - file = StringIO.new file_content - hns_bucket.create_file file, source_file - end - it "file is moved and old file is deleted" do - create_source_file - out, _err = capture_io do - move_object bucket_name: hns_bucket.name, source_file_name: source_file, destination_file_name: destination_file - end - assert_includes out, "New File #{destination_file} created\n" - refute_nil(hns_bucket.file(destination_file)) - assert_nil(hns_bucket.file(source_file)) - end - - it "raises error if source and destination are having same filename" do - create_source_file - exception = assert_raises Google::Cloud::InvalidArgumentError do - move_object bucket_name: hns_bucket.name, source_file_name: source_file, destination_file_name: source_file - end - assert_equal "invalid: Source and destination object names must be different.", exception.message - end - end - - describe "list buckets with partial success" do - it 'returns a list of bucket names if return_partial_success_flag is true' do - result = list_buckets_with_partial_success return_partial_success_flag: true - assert_kind_of Array, result - assert result.all? { |n| n.is_a? String }, "expected all items to be String" - end - - it 'returns nil for unreachable if return_partial_success_flag is false' do - result = list_buckets_with_partial_success return_partial_success_flag: false - assert_nil result - end - - it 'returns nil for unreachable if return_partial_success_flag is not passed' do - result = list_buckets_with_partial_success return_partial_success_flag: nil - assert_nil result - end - end + # describe "storage_create_bucket_with_object_retention" do + # it "creates a bucket with object retention enabled." do + # bucket_name = random_bucket_name + # refute storage_client.bucket bucket_name + + # expected = "Created bucket #{bucket_name} with object retention setting: Enabled\n" + + # retry_resource_exhaustion do + # assert_output expected do + # create_bucket_with_object_retention bucket_name: bucket_name + # end + # end + + # refute_nil storage_client.bucket bucket_name + + # file_name = "test_object_retention" + + # bucket = storage_client.bucket bucket_name + + # out, _err = capture_io do + # set_object_retention_policy bucket_name: bucket.name, + # content: "hello world", + # destination_file_name: file_name + # end + + # assert_includes out, "Retention policy for file #{file_name}" + + # file = bucket.file file_name + # file.retention = { + # mode: nil, + # retain_until_time: nil, + # override_unlocked_retention: true + # } + # delete_bucket_helper bucket_name + # end + # end + + # describe "autoclass" do + # it "get_autoclass, set_autoclass" do + # bucket_name = random_bucket_name + # refute storage_client.bucket bucket_name + + # storage_client.create_bucket bucket_name, autoclass_enabled: true + + # assert_output(/autoclass config set to true./) do + # get_autoclass bucket_name: bucket_name + # end + + # assert_output(/autoclass terminal storage class set to NEARLINE./) do + # get_autoclass bucket_name: bucket_name + # end + + # assert_output(/autoclass terminal storage class set to ARCHIVE./) do + # set_autoclass bucket_name: bucket_name, toggle: true, terminal_storage_class: "ARCHIVE" + # end + + # assert_output(/autoclass config set to false./) do + # set_autoclass bucket_name: bucket_name, toggle: false + # end + + # delete_bucket_helper bucket_name + # end + # end + + # describe "cors" do + # it "cors_configuration, remove_cors_configuration" do + # bucket.cors { |c| c.clear } + # assert bucket.cors.empty? + + # # cors_configuration + # assert_output "Set CORS policies for bucket #{bucket.name}\n" do + # cors_configuration bucket_name: bucket.name + # end + + # bucket.refresh! + # assert_equal 1, bucket.cors.count + # rule = bucket.cors.first + # assert_equal ["*"], rule.origin + # assert_equal ["PUT", "POST"], rule.methods + # assert_equal ["Content-Type", "x-goog-resumable"], rule.headers + # assert_equal 3600, rule.max_age + + # # remove_cors_configuration + # assert_output "Remove CORS policies for bucket #{bucket.name}\n" do + # remove_cors_configuration bucket_name: bucket.name + # end + # bucket.refresh! + # assert bucket.cors.empty? + # end + # end + + # describe "requester_pays" do + # it "enable_requester_pays, disable_requester_pays, get_requester_pays_status" do + # # enable_requester_pays + # bucket.requester_pays = false + + # assert_output "Requester pays has been enabled for #{bucket.name}\n" do + # enable_requester_pays bucket_name: bucket.name + # end + # bucket.refresh! + # assert bucket.requester_pays? + + # # get_requester_pays_status + # assert_output "Requester pays status is enabled for #{bucket.name}\n" do + # get_requester_pays_status bucket_name: bucket.name + # end + # assert bucket.requester_pays? + + # # disable_requester_pays + # assert_output "Requester pays has been disabled for #{bucket.name}\n" do + # disable_requester_pays bucket_name: bucket.name + # end + # bucket.refresh! + # refute bucket.requester_pays? + + # # get_requester_pays_status + # assert_output "Requester pays status is disabled for #{bucket.name}\n" do + # get_requester_pays_status bucket_name: bucket.name + # end + # refute bucket.requester_pays? + # end + # end + + # describe "uniform_bucket_level_access" do + # it "enable_uniform_bucket_level_access, get_uniform_bucket_level_access, disable_uniform_bucket_level_access" do + # # enable_uniform_bucket_level_access + # bucket.uniform_bucket_level_access = false + + # assert_output "Uniform bucket-level access was enabled for #{bucket.name}.\n" do + # enable_uniform_bucket_level_access bucket_name: bucket.name + # end + + # bucket.refresh! + # assert bucket.uniform_bucket_level_access? + + # # get_uniform_bucket_level_access + # assert_output "Uniform bucket-level access is enabled for #{bucket.name}.\nBucket " \ + # "will be locked on #{bucket.uniform_bucket_level_access_locked_at}.\n" do + # get_uniform_bucket_level_access bucket_name: bucket.name + # end + # assert bucket.uniform_bucket_level_access? + + # # disable_uniform_bucket_level_access + # assert_output "Uniform bucket-level access was disabled for #{bucket.name}.\n" do + # disable_uniform_bucket_level_access bucket_name: bucket.name + # end + + # bucket.refresh! + # refute bucket.uniform_bucket_level_access? + + # # get_uniform_bucket_level_access + # assert_output "Uniform bucket-level access is disabled for #{bucket.name}.\n" do + # get_uniform_bucket_level_access bucket_name: bucket.name + # end + # refute bucket.uniform_bucket_level_access? + + # bucket.uniform_bucket_level_access = false + # end + # end + + # describe "default Cloud KMS encryption key" do + # it "set_bucket_default_kms_key, bucket_delete_default_kms_key" do + # refute bucket.default_kms_key + + # # set_bucket_default_kms_key + # assert_output "Default KMS key for #{bucket.name} was set to #{kms_key}\n" do + # set_bucket_default_kms_key bucket_name: bucket.name, + # default_kms_key: kms_key + # end + + # bucket.refresh! + # assert_equal bucket.default_kms_key, kms_key + + # # bucket_delete_default_kms_key + # assert_output "Default KMS key was removed from #{bucket.name}\n" do + # bucket_delete_default_kms_key bucket_name: bucket.name + # end + + # bucket.refresh! + # refute bucket.default_kms_key + # end + # end + + # describe "get bucket class and location data" do + # bucket_name = random_bucket_name + # location = "US" + # storage_class = "COLDLINE" + + # it "get_bucket_class_and_location" do + # storage_client.create_bucket bucket_name, + # location: location, + # storage_class: storage_class + # expected_output = "Bucket #{bucket_name} storage class is " \ + # "#{storage_class}, and the location is #{location}\n" + # assert_output expected_output do + # get_bucket_class_and_location bucket_name: bucket_name + # end + # end + # end + + # describe "labels" do + # it "add_bucket_label, remove_bucket_label" do + # # add_bucket_label + # label_key = "label_key" + # label_value = "label_value" + + # assert_output "Added label #{label_key} with value #{label_value} to #{bucket.name}\n" do + # add_bucket_label bucket_name: bucket.name, + # label_value: label_value, + # label_key: label_key + # end + + # bucket.refresh! + # assert_equal bucket.labels[label_key], label_value + + # # remove_bucket_label + # assert_output "Deleted label #{label_key} from #{bucket.name}\n" do + # remove_bucket_label bucket_name: bucket.name, + # label_key: label_key + # end + + # bucket.refresh! + # assert bucket.labels[label_key].empty? + # end + # end + + # describe "lifecycle management" do + # let(:bucket) { create_bucket_helper random_bucket_name } + # after { delete_bucket_helper bucket.name } + + # it "enable_bucket_lifecycle_management, disable_bucket_lifecycle_management" do + # # enable_bucket_lifecycle_management + # out, _err = capture_io do + # enable_bucket_lifecycle_management bucket_name: bucket.name + # end + + # assert_includes out, "Lifecycle management is enabled" + + # # disable_bucket_lifecycle_management + # out, _err = capture_io do + # disable_bucket_lifecycle_management bucket_name: bucket.name + # end + + # assert_includes out, "Lifecycle management is disabled" + # end + # end + + # describe "retention policy" do + # let(:bucket) { create_bucket_helper random_bucket_name } + # after { delete_bucket_helper bucket.name } + + # it "set_retention_policy, get_retention_policy, remove_retention_policy" do + # # set_retention_policy + # assert_output "Retention period for #{bucket.name} is now #{retention_period} seconds.\n" do + # set_retention_policy bucket_name: bucket.name, + # retention_period: retention_period + # end + + # bucket.refresh! + # assert_equal bucket.retention_period, retention_period + + # # get_retention_policy + # out, _err = capture_io do + # get_retention_policy bucket_name: bucket.name + # end + + # assert_includes out, "period: #{retention_period}\n" + + # # remove_retention_policy + # assert_equal bucket.retention_period, retention_period + # assert_output "Retention policy for #{bucket.name} has been removed.\n" do + # remove_retention_policy bucket_name: bucket.name + # end + + # bucket.refresh! + # refute bucket.retention_period + + # # lock_retention_policy + # bucket.retention_period = retention_period + # out, _err = capture_io do + # lock_retention_policy bucket_name: bucket.name + # end + + # assert_includes out, "Retention policy for #{bucket.name} is now locked." + # bucket.refresh! + # assert bucket.retention_policy_locked? + + # # remove_retention_policy + # assert_output "Policy is locked and retention policy can't be removed.\n" do + # remove_retention_policy bucket_name: bucket.name + # end + # end + # end + + # describe "default_event_based_hold" do + # it "enable_default_event_based_hold, get_default_event_based_hold, disable_default_event_based_hold" do + # # enable_default_event_based_hold + # assert_output "Default event-based hold was enabled for #{bucket.name}.\n" do + # enable_default_event_based_hold bucket_name: bucket.name + # end + + # bucket.refresh! + # assert bucket.default_event_based_hold? + + # # get_default_event_based_hold + # assert_output "Default event-based hold is enabled for #{bucket.name}.\n" do + # get_default_event_based_hold bucket_name: bucket.name + # end + + # # disable_default_event_based_hold + # bucket.update do |b| + # b.default_event_based_hold = true + # end + + # assert_output "Default event-based hold was disabled for #{bucket.name}.\n" do + # disable_default_event_based_hold bucket_name: bucket.name + # end + + # bucket.refresh! + # refute bucket.default_event_based_hold? + + # # get_default_event_based_hold + # assert_output "Default event-based hold is not enabled for #{bucket.name}.\n" do + # get_default_event_based_hold bucket_name: bucket.name + # end + # end + # end + + # describe "storage_class" do + # it "change_default_storage_class" do + # assert_equal "STANDARD", bucket.storage_class + + # assert_output "Default storage class for bucket #{bucket.name} has been set to COLDLINE\n" do + # change_default_storage_class bucket_name: bucket.name + # end + + # bucket.refresh! + # assert_equal "COLDLINE", bucket.storage_class + # # teardown + # bucket.storage_class = "STANDARD" + # end + # end + + # describe "versioning" do + # it "enable_versioning, disable_versioning" do + # # enable_versioning + # bucket.versioning = false + + # assert_output "Versioning was enabled for bucket #{bucket.name}\n" do + # enable_versioning bucket_name: bucket.name + # end + # bucket.refresh! + # assert bucket.versioning? + + # # disable_versioning + # assert_output "Versioning was disabled for bucket #{bucket.name}\n" do + # disable_versioning bucket_name: bucket.name + # end + # bucket.refresh! + # refute bucket.versioning? + # end + # end + + # describe "website_configuration" do + # let(:main_page_suffix) { "index.html" } + # let(:not_found_page) { "404.html" } + + # it "define_bucket_website_configuration" do + # expected_out = "Static website bucket #{bucket.name} is set up to use #{main_page_suffix} as the index page " \ + # "and #{not_found_page} as the 404 page\n" + + # assert_output expected_out do + # define_bucket_website_configuration bucket_name: bucket.name, + # main_page_suffix: main_page_suffix, + # not_found_page: not_found_page + # end + + # bucket.refresh! + # assert_equal main_page_suffix, bucket.website_main + # assert_equal not_found_page, bucket.website_404 + # end + # end + + # describe "public_access_prevention" do + # it "set_public_access_prevention_enforced, get_public_access_prevention, " \ + # "set_public_access_prevention_inherited" do + # bucket.public_access_prevention = :inherited + # bucket.refresh! + # _(bucket.public_access_prevention).must_equal "inherited" + + # # set_public_access_prevention_enforced + # assert_output "Public access prevention is set to enforced for #{bucket.name}.\n" do + # set_public_access_prevention_enforced bucket_name: bucket.name + # end + + # bucket.refresh! + # _(bucket.public_access_prevention).must_equal "enforced" + + # # get_public_access_prevention + # assert_output "Public access prevention is 'enforced' for #{bucket.name}.\n" do + # get_public_access_prevention bucket_name: bucket.name + # end + # _(bucket.public_access_prevention).must_equal "enforced" + + # # set_public_access_prevention_inherited + # assert_output "Public access prevention is 'inherited' for #{bucket.name}.\n" do + # set_public_access_prevention_inherited bucket_name: bucket.name + # end + + # bucket.refresh! + # _(bucket.public_access_prevention).must_equal "inherited" + # bucket.public_access_prevention = :inherited + # end + # end + + # describe "storage move file" do + # let(:source_file) { "file_1_name_#{SecureRandom.hex}.txt" } + # let(:destination_file) { "file_2_name_#{SecureRandom.hex}.txt" } + # let :hns_bucket do + # hierarchical_namespace = Google::Apis::StorageV1::Bucket::HierarchicalNamespace.new enabled: true + # storage_client.create_bucket random_bucket_name do |b| + # b.uniform_bucket_level_access = true + # b.hierarchical_namespace = hierarchical_namespace + # end + # end + # let :create_source_file do + # file_content = "A" * (3 * 1024 * 1024) # 3 MB of 'A' characters + # file = StringIO.new file_content + # hns_bucket.create_file file, source_file + # end + # it "file is moved and old file is deleted" do + # create_source_file + # out, _err = capture_io do + # move_object bucket_name: hns_bucket.name, source_file_name: source_file, destination_file_name: destination_file + # end + # assert_includes out, "New File #{destination_file} created\n" + # refute_nil(hns_bucket.file(destination_file)) + # assert_nil(hns_bucket.file(source_file)) + # end + + # it "raises error if source and destination are having same filename" do + # create_source_file + # exception = assert_raises Google::Cloud::InvalidArgumentError do + # move_object bucket_name: hns_bucket.name, source_file_name: source_file, destination_file_name: source_file + # end + # assert_equal "invalid: Source and destination object names must be different.", exception.message + # end + # end + + # describe "list buckets with partial success" do + # it 'returns a list of bucket names if return_partial_success_flag is true' do + # result = list_buckets_with_partial_success return_partial_success_flag: true + # assert_kind_of Array, result + # assert result.all? { |n| n.is_a? String }, "expected all items to be String" + # end + + # it 'returns nil for unreachable if return_partial_success_flag is false' do + # result = list_buckets_with_partial_success return_partial_success_flag: false + # assert_nil result + # end + + # it 'returns nil for unreachable if return_partial_success_flag is not passed' do + # result = list_buckets_with_partial_success return_partial_success_flag: nil + # assert_nil result + # end + # end end diff --git a/google-cloud-storage/samples/storage_create_bucket_with_ip_filter.rb b/google-cloud-storage/samples/storage_create_bucket_with_ip_filter.rb new file mode 100644 index 000000000000..02deb4ebe75c --- /dev/null +++ b/google-cloud-storage/samples/storage_create_bucket_with_ip_filter.rb @@ -0,0 +1,129 @@ +# Copyright 2024 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. + +# [START storage_create_bucket_with_ip_filter] +def create_bucket_with_ip_filter bucket_name: + # The ID to give your GCS bucket + # bucket_name = "your-unique-bucket-name" + + require "google/cloud/storage" + + storage = Google::Cloud::Storage.new + + ip_filter = Google::Apis::StorageV1::Bucket::IpFilter.new( + mode: "Enabled", + public_network_source: Google::Apis::StorageV1::Bucket::IpFilter::PublicNetworkSource.new( + allowed_ip_cidr_ranges: [ + "0.0.0.0/0", "::/0" + ] + ), + allow_all_service_agent_access: false + ) + bucket = storage.create_bucket bucket_name do |b| + b.ip_filter = ip_filter + b.uniform_bucket_level_access = true + end + + puts "Created bucket #{bucket_name} with IP filter enabled." +end + +def removes_bucket_ip_filter bucket_name: + # The ID of your GCS bucket + # bucket_name = "your-unique-bucket-name" + + require "google/cloud/storage" + + storage = Google::Cloud::Storage.new + bucket = storage.bucket bucket_name + + ip_filter = Google::Apis::StorageV1::Bucket::IpFilter.new( + mode: "Disabled" + ) + bucket.update do |b| + b.ip_filter = ip_filter + end + + puts "Updated IP filter for bucket #{bucket_name}." +end + +def update_bucket_with_ip_filter bucket_name: + # The ID to give your GCS bucket + # bucket_name = "your-unique-bucket-name" + + require "google/cloud/resource_manager/v3" + storage = Google::Cloud::Storage.new + + ip_filter = Google::Apis::StorageV1::Bucket::IpFilter.new( + mode: "Enabled", + public_network_source: Google::Apis::StorageV1::Bucket::IpFilter::PublicNetworkSource.new( + allowed_ip_cidr_ranges: [ + "0.0.0.0/0", "::/0" + ] + ), + allow_all_service_agent_access: false + ) + # require "google/cloud/iam" + # Initialize the IAM Admin Client (Not Credentials Client) + # iam_client = Google::Cloud::Iam::Service.new + client = Google::Cloud::ResourceManager::V3::Projects::Client.new + + + project_id = "storage-sdk-vendor" + role_id = "GcsIpExemptRole" + + # Define the Custom Role + # role = Google::Cloud::Iam::V1::Role.new( + # title: "GCS IP Exemption Role", + # included_permissions: ["storage.buckets.exemptFromIpFilter"], + # stage: :GA + # ) + resource = "projects/#{project_id}" + + # Call test_iam_permissions. + # In Ruby, you can pass a Hash that matches the request structure. + response = client.test_iam_permissions( + resource: resource, + permissions: ["storage.buckets.exemptFromIpFilter"] + ) + + # The response object contains a 'permissions' array of granted permissions + puts "Granted permissions: #{response.permissions}" + + response.permissions + binding.pry + + # role = "projects/#{storage.project}/roles/GcsIpExemptRole" + member = "serviceAccount:insecure-cloudtop-shared-user@cloudtop-prod-asia-east.iam.gserviceaccount.com" + + bucket.policy requested_policy_version: 3 do |policy| + policy.bindings.insert role: role, members: [member] + end + # bucket = storage.create_bucket bucket_name + # bucket.policy do |p| + # p.add "roles/storage.buckets.exemptFromIpFilter", "serviceAccount:insecure-cloudtop-shared-user@cloudtop-prod-asia-east.iam.gserviceaccount.com" + # end + # binding.pry + + bucket.update do |b| + b.ip_filter = ip_filter + end + + + puts "Updated bucket #{bucket_name} with IP filter enabled." +end +# [END storage_create_bucket_with_ip_filter] + +if $PROGRAM_NAME == __FILE__ + create_bucket_with_ip_filter bucket_name: ARGV.shift +end From 6c1fe37b3a27387776896c1789ca21259df74157 Mon Sep 17 00:00:00 2001 From: Shubhangi Singh Date: Tue, 27 Jan 2026 10:37:13 +0000 Subject: [PATCH 2/6] wip --- .../storage_create_bucket_with_ip_filter.rb | 102 ++++++++++++------ 1 file changed, 70 insertions(+), 32 deletions(-) diff --git a/google-cloud-storage/samples/storage_create_bucket_with_ip_filter.rb b/google-cloud-storage/samples/storage_create_bucket_with_ip_filter.rb index 02deb4ebe75c..6215e7ba102d 100644 --- a/google-cloud-storage/samples/storage_create_bucket_with_ip_filter.rb +++ b/google-cloud-storage/samples/storage_create_bucket_with_ip_filter.rb @@ -30,11 +30,14 @@ def create_bucket_with_ip_filter bucket_name: ), allow_all_service_agent_access: false ) + bucket = storage.create_bucket bucket_name do |b| b.ip_filter = ip_filter b.uniform_bucket_level_access = true end + binding.pry + puts "Created bucket #{bucket_name} with IP filter enabled." end @@ -73,47 +76,82 @@ def update_bucket_with_ip_filter bucket_name: ), allow_all_service_agent_access: false ) - # require "google/cloud/iam" - # Initialize the IAM Admin Client (Not Credentials Client) - # iam_client = Google::Cloud::Iam::Service.new - client = Google::Cloud::ResourceManager::V3::Projects::Client.new + +# require "google/cloud/resource_manager" + +# Direct client initialization +client = Google::Cloud::ResourceManager::V3::Projects::Client.new + +project_id = storage.project +resource_name = "projects/#{project_id}" + +# 1. Get the current polGoogle::Cloud::Iam::V1::IAM::Client.newicy +# binding.pry +policy = client.get_iam_policy resource: resource_name +# binding.pry + +custom_role = "storage.buckets.exemptFromIpFilter" +custom_role_path = "#{resource_name}/roles/#{custom_role}" +service_account = "serviceAccount:#{storage.service_account_email}" +#{serviceAccount:storage-sdk-vendor@storage-sdk-vendor.iam.gserviceaccount.com} +binding.pry +custom_role_binding = Google::Iam::V1::Binding.new( + role: custom_role_path, + members: [service_account] +) +policy.bindings << custom_role_binding - project_id = "storage-sdk-vendor" - role_id = "GcsIpExemptRole" +client.set_iam_policy resource: resource_name, policy: policy +# Google::Cloud::PermissionDeniedError: 7:Permission 'resourcemanager.projects.setIamPolicy' denied on resource '//cloudresourcemanager.googleapis.com/projects/storage-sdk-vendor' (or it may not exist).. debug_error_string:{UNKNOWN:Error received from peer ipv4:74.125.23.95:443 {grpc_message:"Permission \'resourcemanager.projects.setIamPolicy\' denied on resource \'//cloudresourcemanager.googleapis.com/projects/storage-sdk-vendor\' (or it may not exist).", grpc_status:7}} (Google::Cloud::PermissionDeniedError) - # Define the Custom Role + +# # Optional: Log the change +# puts "Updating project policy to include #{custom_role} for #{service_account}" +# end + +puts "Project policy updated successfully." + + # project_id = "storage-sdk-vendor" + # role_id = "GcsIpExemptRole" + # binding.pry + + # # Define the Custom Role # role = Google::Cloud::Iam::V1::Role.new( # title: "GCS IP Exemption Role", # included_permissions: ["storage.buckets.exemptFromIpFilter"], # stage: :GA # ) - resource = "projects/#{project_id}" - - # Call test_iam_permissions. - # In Ruby, you can pass a Hash that matches the request structure. - response = client.test_iam_permissions( - resource: resource, - permissions: ["storage.buckets.exemptFromIpFilter"] - ) - - # The response object contains a 'permissions' array of granted permissions - puts "Granted permissions: #{response.permissions}" + # resource = "projects/#{project_id}" + # storage_project = storage.project + # resource = "projects/#{storage_project}/roles/#{role_id}" + # storage_project.policy do |p| + # p.add "roles/#{role}", member + # end + + # # Call test_iam_permissions. + # # In Ruby, you can pass a Hash that matches the request structure. + # response = client.test_iam_permissions( + # resource: resource, + # permissions: ["storage.buckets.exemptFromIpFilter"] + # ) + + # # The response object contains a 'permissions' array of granted permissions + # puts "Granted permissions: #{response.permissions}" - response.permissions - binding.pry - - # role = "projects/#{storage.project}/roles/GcsIpExemptRole" - member = "serviceAccount:insecure-cloudtop-shared-user@cloudtop-prod-asia-east.iam.gserviceaccount.com" - - bucket.policy requested_policy_version: 3 do |policy| - policy.bindings.insert role: role, members: [member] - end - # bucket = storage.create_bucket bucket_name - # bucket.policy do |p| - # p.add "roles/storage.buckets.exemptFromIpFilter", "serviceAccount:insecure-cloudtop-shared-user@cloudtop-prod-asia-east.iam.gserviceaccount.com" - # end - # binding.pry + # response.permissions + + # # role = "projects/#{storage.project}/roles/GcsIpExemptRole" + # member = "serviceAccount:insecure-cloudtop-shared-user@cloudtop-prod-asia-east.iam.gserviceaccount.com" + + # bucket.policy requested_policy_version: 3 do |policy| + # policy.bindings.insert role: "roles/storage.buckets.exemptFromIpFilter", members: ["serviceAccount:insecure-cloudtop-shared-user@cloudtop-prod-asia-east.iam.gserviceaccount.com"] + # end + # # bucket = storage.create_bucket bucket_name + # # bucket.policy do |p| + # # p.add "roles/storage.buckets.exemptFromIpFilter", "serviceAccount:insecure-cloudtop-shared-user@cloudtop-prod-asia-east.iam.gserviceaccount.com" + # # end + # # binding.pry bucket.update do |b| b.ip_filter = ip_filter From dcfdafb2026cf97c56d3e99e67c9644e6a061bb2 Mon Sep 17 00:00:00 2001 From: Shubhangi Singh Date: Thu, 21 May 2026 10:56:17 +0000 Subject: [PATCH 3/6] wip --- .../samples/acceptance/buckets_test.rb | 22 ++++++------ .../storage_create_bucket_with_ip_filter.rb | 36 +++++++++++++------ 2 files changed, 37 insertions(+), 21 deletions(-) diff --git a/google-cloud-storage/samples/acceptance/buckets_test.rb b/google-cloud-storage/samples/acceptance/buckets_test.rb index e29644d5d196..1b41b6033049 100644 --- a/google-cloud-storage/samples/acceptance/buckets_test.rb +++ b/google-cloud-storage/samples/acceptance/buckets_test.rb @@ -178,18 +178,20 @@ end after :all do - binding.pry - # delete_bucket_helper @bucket_name + # removes_bucket_ip_filter bucket_name: @bucket_name + binding.pry + + delete_bucket_helper @bucket_name end - # it "creates IP filter enabled bucket" do - # expected = "Created bucket #{@bucket_name} with IP filter enabled.\n" - # retry_resource_exhaustion do - # assert_output expected do - # create_bucket_with_ip_filter bucket_name: @bucket_name - # end - # end - # end + it "creates IP filter enabled bucket" do + expected = "Created bucket #{@bucket_name} with IP filter enabled.\n" + retry_resource_exhaustion do + assert_output expected do + create_bucket_with_ip_filter bucket_name: @bucket_name + end + end + end # it "removes IP filter of an existing bucket" do # expected = "Updated IP filter for bucket #{@bucket_name}.\n" diff --git a/google-cloud-storage/samples/storage_create_bucket_with_ip_filter.rb b/google-cloud-storage/samples/storage_create_bucket_with_ip_filter.rb index 6215e7ba102d..43f45362b76a 100644 --- a/google-cloud-storage/samples/storage_create_bucket_with_ip_filter.rb +++ b/google-cloud-storage/samples/storage_create_bucket_with_ip_filter.rb @@ -20,16 +20,33 @@ def create_bucket_with_ip_filter bucket_name: require "google/cloud/storage" storage = Google::Cloud::Storage.new + binding.pry - ip_filter = Google::Apis::StorageV1::Bucket::IpFilter.new( - mode: "Enabled", - public_network_source: Google::Apis::StorageV1::Bucket::IpFilter::PublicNetworkSource.new( + # ip_filter = Google::Apis::StorageV1::Bucket::IpFilter.new( + # mode: "Enabled", + # public_network_source: Google::Apis::StorageV1::Bucket::IpFilter::PublicNetworkSource.new( + # allowed_ip_cidr_ranges: [ + # "0.0.0.0/0", "::/0" + # ], + # vpc_network_sources: [ + # {} + # network: "projects/storage-sdk-vendor/global/networks/default", + # allowed_ip_cidr_ranges: [ + # "10.0.0.0/8" + # ] + # } + # ] + # ), + # allow_all_service_agent_access: true + # ) + ip_filter = { + mode: "Disabled", + public_network_source: { allowed_ip_cidr_ranges: [ "0.0.0.0/0", "::/0" ] - ), - allow_all_service_agent_access: false - ) + } +} bucket = storage.create_bucket bucket_name do |b| b.ip_filter = ip_filter @@ -68,14 +85,11 @@ def update_bucket_with_ip_filter bucket_name: storage = Google::Cloud::Storage.new ip_filter = Google::Apis::StorageV1::Bucket::IpFilter.new( - mode: "Enabled", public_network_source: Google::Apis::StorageV1::Bucket::IpFilter::PublicNetworkSource.new( allowed_ip_cidr_ranges: [ - "0.0.0.0/0", "::/0" + "0.0.0.3/0", "::/0" ] - ), - allow_all_service_agent_access: false - ) + )) # require "google/cloud/resource_manager" From 4d2bbe7fafb712d0fdc18faa3fa39dcead8b61cf Mon Sep 17 00:00:00 2001 From: Shubhangi Singh Date: Thu, 4 Jun 2026 04:05:49 +0000 Subject: [PATCH 4/6] check samples --- .../samples/acceptance/buckets_test.rb | 22 ++-- .../storage_create_bucket_with_ip_filter.rb | 119 ++---------------- 2 files changed, 21 insertions(+), 120 deletions(-) diff --git a/google-cloud-storage/samples/acceptance/buckets_test.rb b/google-cloud-storage/samples/acceptance/buckets_test.rb index 1b41b6033049..f71a408b3ae7 100644 --- a/google-cloud-storage/samples/acceptance/buckets_test.rb +++ b/google-cloud-storage/samples/acceptance/buckets_test.rb @@ -179,7 +179,7 @@ after :all do # removes_bucket_ip_filter bucket_name: @bucket_name - binding.pry + # binding.pry delete_bucket_helper @bucket_name end @@ -193,20 +193,20 @@ end end - # it "removes IP filter of an existing bucket" do - # expected = "Updated IP filter for bucket #{@bucket_name}.\n" - # retry_resource_exhaustion do - # assert_output expected do - # removes_bucket_ip_filter bucket_name: @bucket_name - # end - # end - # end + it "removes IP filter of an existing bucket" do + expected = "Updated IP filter for bucket #{@bucket_name}.\n" + retry_resource_exhaustion do + assert_output expected do + removes_bucket_ip_filter bucket_name: @bucket_name + end + end + end it "Updates IP filter of an existing bucket" do - expected = "Updated bucket #{@bucket_name+"-1"} with IP filter enabled.\n" + expected = "Updated bucket #{@bucket_name} with IP filter enabled.\n" retry_resource_exhaustion do assert_output expected do - update_bucket_with_ip_filter bucket_name: @bucket_name+"-1" + update_bucket_with_ip_filter bucket_name: @bucket_name end end end diff --git a/google-cloud-storage/samples/storage_create_bucket_with_ip_filter.rb b/google-cloud-storage/samples/storage_create_bucket_with_ip_filter.rb index 43f45362b76a..c31d03a076d7 100644 --- a/google-cloud-storage/samples/storage_create_bucket_with_ip_filter.rb +++ b/google-cloud-storage/samples/storage_create_bucket_with_ip_filter.rb @@ -20,41 +20,19 @@ def create_bucket_with_ip_filter bucket_name: require "google/cloud/storage" storage = Google::Cloud::Storage.new - binding.pry - - # ip_filter = Google::Apis::StorageV1::Bucket::IpFilter.new( - # mode: "Enabled", - # public_network_source: Google::Apis::StorageV1::Bucket::IpFilter::PublicNetworkSource.new( - # allowed_ip_cidr_ranges: [ - # "0.0.0.0/0", "::/0" - # ], - # vpc_network_sources: [ - # {} - # network: "projects/storage-sdk-vendor/global/networks/default", - # allowed_ip_cidr_ranges: [ - # "10.0.0.0/8" - # ] - # } - # ] - # ), - # allow_all_service_agent_access: true - # ) ip_filter = { mode: "Disabled", public_network_source: { allowed_ip_cidr_ranges: [ "0.0.0.0/0", "::/0" ] + } } -} bucket = storage.create_bucket bucket_name do |b| b.ip_filter = ip_filter b.uniform_bucket_level_access = true end - - binding.pry - puts "Created bucket #{bucket_name} with IP filter enabled." end @@ -81,97 +59,20 @@ def update_bucket_with_ip_filter bucket_name: # The ID to give your GCS bucket # bucket_name = "your-unique-bucket-name" - require "google/cloud/resource_manager/v3" storage = Google::Cloud::Storage.new + bucket = storage.bucket bucket_name - ip_filter = Google::Apis::StorageV1::Bucket::IpFilter.new( - public_network_source: Google::Apis::StorageV1::Bucket::IpFilter::PublicNetworkSource.new( - allowed_ip_cidr_ranges: [ - "0.0.0.3/0", "::/0" - ] - )) - -# require "google/cloud/resource_manager" - -# Direct client initialization -client = Google::Cloud::ResourceManager::V3::Projects::Client.new - -project_id = storage.project -resource_name = "projects/#{project_id}" - -# 1. Get the current polGoogle::Cloud::Iam::V1::IAM::Client.newicy -# binding.pry -policy = client.get_iam_policy resource: resource_name -# binding.pry - -custom_role = "storage.buckets.exemptFromIpFilter" -custom_role_path = "#{resource_name}/roles/#{custom_role}" -service_account = "serviceAccount:#{storage.service_account_email}" -#{serviceAccount:storage-sdk-vendor@storage-sdk-vendor.iam.gserviceaccount.com} - -binding.pry -custom_role_binding = Google::Iam::V1::Binding.new( - role: custom_role_path, - members: [service_account] -) -policy.bindings << custom_role_binding - -client.set_iam_policy resource: resource_name, policy: policy -# Google::Cloud::PermissionDeniedError: 7:Permission 'resourcemanager.projects.setIamPolicy' denied on resource '//cloudresourcemanager.googleapis.com/projects/storage-sdk-vendor' (or it may not exist).. debug_error_string:{UNKNOWN:Error received from peer ipv4:74.125.23.95:443 {grpc_message:"Permission \'resourcemanager.projects.setIamPolicy\' denied on resource \'//cloudresourcemanager.googleapis.com/projects/storage-sdk-vendor\' (or it may not exist).", grpc_status:7}} (Google::Cloud::PermissionDeniedError) - - -# # Optional: Log the change -# puts "Updating project policy to include #{custom_role} for #{service_account}" -# end - -puts "Project policy updated successfully." - - # project_id = "storage-sdk-vendor" - # role_id = "GcsIpExemptRole" - # binding.pry - - # # Define the Custom Role - # role = Google::Cloud::Iam::V1::Role.new( - # title: "GCS IP Exemption Role", - # included_permissions: ["storage.buckets.exemptFromIpFilter"], - # stage: :GA - # ) - # resource = "projects/#{project_id}" - # storage_project = storage.project - # resource = "projects/#{storage_project}/roles/#{role_id}" - # storage_project.policy do |p| - # p.add "roles/#{role}", member - # end - - # # Call test_iam_permissions. - # # In Ruby, you can pass a Hash that matches the request structure. - # response = client.test_iam_permissions( - # resource: resource, - # permissions: ["storage.buckets.exemptFromIpFilter"] - # ) - - # # The response object contains a 'permissions' array of granted permissions - # puts "Granted permissions: #{response.permissions}" - - # response.permissions - - # # role = "projects/#{storage.project}/roles/GcsIpExemptRole" - # member = "serviceAccount:insecure-cloudtop-shared-user@cloudtop-prod-asia-east.iam.gserviceaccount.com" - - # bucket.policy requested_policy_version: 3 do |policy| - # policy.bindings.insert role: "roles/storage.buckets.exemptFromIpFilter", members: ["serviceAccount:insecure-cloudtop-shared-user@cloudtop-prod-asia-east.iam.gserviceaccount.com"] - # end - # # bucket = storage.create_bucket bucket_name - # # bucket.policy do |p| - # # p.add "roles/storage.buckets.exemptFromIpFilter", "serviceAccount:insecure-cloudtop-shared-user@cloudtop-prod-asia-east.iam.gserviceaccount.com" - # # end - # # binding.pry - + ip_filter = { + mode: "Disabled", + public_network_source: { + allowed_ip_cidr_ranges: [ + "0.0.0.4/0", "::/0" + ] + } + } bucket.update do |b| b.ip_filter = ip_filter end - - puts "Updated bucket #{bucket_name} with IP filter enabled." end # [END storage_create_bucket_with_ip_filter] From e4877d3e67417723945cd2ffab4b2580e588db7a Mon Sep 17 00:00:00 2001 From: Shubhangi Singh Date: Sun, 7 Jun 2026 16:32:27 +0000 Subject: [PATCH 5/6] adding tests and samples --- .../storage/bucket_ip_filter_test.rb | 79 ++ .../lib/google/cloud/storage/bucket.rb | 61 + .../lib/google/cloud/storage/project.rb | 12 + .../samples/acceptance/buckets_test.rb | 1203 +++++++++-------- .../storage_create_bucket_with_ip_filter.rb | 52 +- .../storage_delete_bucket_ip_filter.rb | 41 + .../storage_enable_bucket_ip_filter.rb | 44 + .../samples/storage_get_bucket_ip_filter.rb | 40 + .../samples/storage_list_bucket_ip_filters.rb | 41 + .../storage_update_bucket_with_ip_filter.rb | 44 + .../cloud/storage/bucket_ip_filter_test.rb | 151 +++ .../test/google/cloud/storage/project_test.rb | 32 + 12 files changed, 1165 insertions(+), 635 deletions(-) create mode 100644 google-cloud-storage/acceptance/storage/bucket_ip_filter_test.rb create mode 100644 google-cloud-storage/samples/storage_delete_bucket_ip_filter.rb create mode 100644 google-cloud-storage/samples/storage_enable_bucket_ip_filter.rb create mode 100644 google-cloud-storage/samples/storage_get_bucket_ip_filter.rb create mode 100644 google-cloud-storage/samples/storage_list_bucket_ip_filters.rb create mode 100644 google-cloud-storage/samples/storage_update_bucket_with_ip_filter.rb create mode 100644 google-cloud-storage/test/google/cloud/storage/bucket_ip_filter_test.rb diff --git a/google-cloud-storage/acceptance/storage/bucket_ip_filter_test.rb b/google-cloud-storage/acceptance/storage/bucket_ip_filter_test.rb new file mode 100644 index 000000000000..ca45ce2538a5 --- /dev/null +++ b/google-cloud-storage/acceptance/storage/bucket_ip_filter_test.rb @@ -0,0 +1,79 @@ +# 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 +# +# https://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. + +require "storage_helper" + +describe Google::Cloud::Storage::Bucket, :storage do + let(:ip_filter_disabled) do + { + mode: "Disabled", + public_network_source: { + allowed_ip_cidr_ranges: ["0.0.0.0/0", "::/0"] + } + } + end + + let(:ip_filter_disabled_update) do + { + mode: "Disabled", + public_network_source: { + allowed_ip_cidr_ranges: ["8.8.8.8/32"] + } + } + end + + let(:bucket_name) { "#{$bucket_names[2]}-ip-filter" } + + it "creates, gets, updates, and deletes a bucket with ip_filter" do + # Create a bucket with ip_filter + bucket = storage.bucket(bucket_name) || + safe_gcs_execute {storage.create_bucket bucket_name, ip_filter: ip_filter_disabled} + + # _(bucket.ip_filter).wont_be_nil + _(bucket.ip_filter.mode).must_equal "Disabled" + _(bucket.ip_filter.public_network_source.allowed_ip_cidr_ranges).must_equal ["0.0.0.0/0", "::/0"] + + # Get the bucket and verify ip_filter + bucket = storage.bucket bucket_name + _(bucket.ip_filter).wont_be_nil + _(bucket.ip_filter.mode).must_equal "Disabled" + _(bucket.ip_filter.public_network_source.allowed_ip_cidr_ranges).must_equal ["0.0.0.0/0", "::/0"] + + # Update the ip_filter + safe_gcs_execute do + bucket.update do |b| + b.ip_filter = ip_filter_disabled_update + end + end + + _(bucket.ip_filter.mode).must_equal "Disabled" + _(bucket.ip_filter.public_network_source.allowed_ip_cidr_ranges).must_equal ["8.8.8.8/32"] + + # Disable ip_filter + safe_gcs_execute do + bucket.ip_filter = { + mode: "Disabled", + public_network_source: { + allowed_ip_cidr_ranges: [] + } + } + end + + _(bucket.ip_filter.public_network_source.allowed_ip_cidr_ranges).must_be_nil + + safe_gcs_execute { bucket.delete } + _(storage.bucket(bucket_name)).must_be :nil? + + end +end diff --git a/google-cloud-storage/lib/google/cloud/storage/bucket.rb b/google-cloud-storage/lib/google/cloud/storage/bucket.rb index 2be3ade74b38..f8665b203250 100644 --- a/google-cloud-storage/lib/google/cloud/storage/bucket.rb +++ b/google-cloud-storage/lib/google/cloud/storage/bucket.rb @@ -1410,10 +1410,71 @@ def delete if_metageneration_match: nil, if_metageneration_not_match: nil user_project: user_project end + ## + # The bucket's IP filter configuration. + # This value can be modified by calling {#ip_filter=}. + # + # @return [Google::Apis::StorageV1::Bucket::IpFilter, nil] The bucket's IP filter configuration, + # or `nil` if not configured. + # + # @example + # require "google/cloud/storage" + # + # storage = Google::Cloud::Storage.new + # + # bucket = storage.bucket "my-bucket" + # ip_filter = bucket.ip_filter + # if ip_filter + # puts "Mode: #{ip_filter.mode}" + # puts "Public CIDR: #{ip_filter.public_network_source&.allowed_ip_cidr_ranges}" + # end + # def ip_filter @gapi.ip_filter end + ## + # Sets the value for IP filter in the bucket. This value can + # be queried by calling {#ip_filter}. + # + # @param [Google::Apis::StorageV1::Bucket::IpFilter, Hash] new_ip_filter The bucket's new IP filter. + # Acceptable Hash structure: + # - :mode - [String] The mode of the IP filter. Acceptable values are: "Disabled", "Enforced", "Preview" + # - :public_network_source - [Hash] The public network source configuration: + # - :allowed_ip_cidr_ranges - [Array] Array of IP CIDR ranges allowed for public access. + # - :vpc_network_sources - [Array] The VPC network sources configuration: + # - :network - [String] The VPC network resource path, e.g. "projects/PROJECT_ID/global/networks/NETWORK_NAME". + # - :allowed_ip_cidr_ranges - [Array] Array of IP CIDR ranges allowed for VPC access. + # - :allow_cross_org_vpcs - [Boolean] Whether to allow cross-org VPC access. + # - :allow_all_service_agent_access - [Boolean] Whether to allow all service agent access. + # + # @example Enable IP filter with Hash: + # require "google/cloud/storage" + # + # storage = Google::Cloud::Storage.new + # + # bucket = storage.bucket "my-bucket" + # bucket.ip_filter = { + # mode: "Enabled", + # allow_all_service_agent_access: true, + # public_network_source: { + # allowed_ip_cidr_ranges: ["0.0.0.0/0", "::/0"] + # } + # } + # + # @example Clear/delete IP filter: + # require "google/cloud/storage" + # + # storage = Google::Cloud::Storage.new + # + # bucket = storage.bucket "my-bucket" + # bucket.ip_filter = { + # mode: "Disabled", + # public_network_source: { + # allowed_ip_cidr_ranges: [] + # } + # } + # def ip_filter= new_ip_filter @gapi.ip_filter = new_ip_filter || {} patch_gapi! :ip_filter diff --git a/google-cloud-storage/lib/google/cloud/storage/project.rb b/google-cloud-storage/lib/google/cloud/storage/project.rb index 3d971a53af50..c5ef54193d10 100644 --- a/google-cloud-storage/lib/google/cloud/storage/project.rb +++ b/google-cloud-storage/lib/google/cloud/storage/project.rb @@ -424,6 +424,18 @@ def bucket bucket_name, # @param [Boolean] enable_object_retention # When set to true, object retention is enabled for this bucket. # + # @param [Hash] ip_filter The bucket's IP filter configuration. + # Acceptable values are: + # - {Google::Apis::StorageV1::Bucket::IpFilter} object + # - Hash that can be converted to a {Google::Apis::StorageV1::Bucket::IpFilter} object + # - :mode - [String] The mode of the IP filter. Acceptable values are: "Disabled", "Enforced", "Preview" + # - :public_network_source - [Hash] The public network source configuration: + # - :allowed_ip_cidr_ranges - [Array] Array of IP CIDR ranges allowed for public access. + # - :vpc_network_sources - [Array] The VPC network sources configuration: + # - :network - [String] The VPC network resource path, e.g. "projects/PROJECT_ID/global/networks/NETWORK_NAME". + # - :allowed_ip_cidr_ranges - [Array] Array of IP CIDR ranges allowed for VPC access. + # - :allow_cross_org_vpcs - [Boolean] Whether to allow cross-org VPC access. + # - :allow_all_service_agent_access - [Boolean] Whether to allow all service agent access. # @yield [bucket] a block for configuring the bucket before it is # created # @yieldparam [Bucket] bucket the bucket object to be configured diff --git a/google-cloud-storage/samples/acceptance/buckets_test.rb b/google-cloud-storage/samples/acceptance/buckets_test.rb index f71a408b3ae7..7fbaf9995e7e 100644 --- a/google-cloud-storage/samples/acceptance/buckets_test.rb +++ b/google-cloud-storage/samples/acceptance/buckets_test.rb @@ -22,6 +22,11 @@ require_relative "../storage_create_bucket_dual_region" require_relative "../storage_create_bucket_hierarchical_namespace" require_relative "../storage_create_bucket_with_ip_filter" +require_relative "../storage_get_bucket_ip_filter" +require_relative "../storage_update_bucket_with_ip_filter" +require_relative "../storage_delete_bucket_ip_filter" +require_relative "../storage_enable_bucket_ip_filter" +require_relative "../storage_list_bucket_ip_filters" require_relative "../storage_create_bucket_with_object_retention" require_relative "../storage_define_bucket_website_configuration" require_relative "../storage_delete_bucket" @@ -64,618 +69,638 @@ let(:retention_period) { rand 1..99 } let(:bucket) { fixture_bucket } - # describe "bucket lifecycle" do - # it "create_bucket, create_bucket_class_location, list_buckets, get_bucket_metadata, delete_bucket" do - # # create_bucket - # bucket_name = random_bucket_name - # refute storage_client.bucket bucket_name - - # retry_resource_exhaustion do - # assert_output "Created bucket: #{bucket_name}\n" do - # create_bucket bucket_name: bucket_name - # end - # end - - # refute_nil storage_client.bucket bucket_name - - # # create_bucket_class_location - - # secondary_bucket_name = random_bucket_name - # location = "ASIA" - # storage_class = "COLDLINE" - # refute storage_client.bucket secondary_bucket_name - - # retry_resource_exhaustion do - # assert_output "Created bucket #{secondary_bucket_name} in #{location} with #{storage_class} class\n" do - # create_bucket_class_location bucket_name: secondary_bucket_name - # end - # end - - # secondary_bucket = storage_client.bucket secondary_bucket_name - # refute_nil secondary_bucket - # assert_equal location, secondary_bucket.location - # assert_equal storage_class, secondary_bucket.storage_class - - # # list_buckets - # out, _err = capture_io do - # list_buckets - # end - - # assert_includes out, "ruby-storage-samples-" - - # # get_bucket_metadata - # out, _err = capture_io do - # get_bucket_metadata bucket_name: bucket_name - # end - - # assert_includes out, bucket_name - - # # delete_bucket - # assert_output "Deleted bucket: #{bucket_name}\n" do - # delete_bucket bucket_name: bucket_name - # end - - - # refute storage_client.bucket bucket_name - - # delete_bucket_helper bucket_name - # delete_bucket_helper secondary_bucket_name - # end - # end - - # describe "storage_create_bucket_dual_region" do - # it "creates dual region bucket" do - # location = "US" - # region_1 = "US-EAST1" - # region_2 = "US-WEST1" - # location_type = "dual-region" - # bucket_name = random_bucket_name - # refute storage_client.bucket bucket_name - - # expected = "Bucket #{bucket_name} created:\n" - # expected += "- location: #{location}\n" - # expected += "- location_type: #{location_type}\n" - # expected += "- custom_placement_config:\n" - # expected += " - data_locations: #{[region_1, region_2]}\n" - - # retry_resource_exhaustion do - # assert_output expected do - # StorageCreateBucketDualRegion.new.storage_create_bucket_dual_region bucket_name: bucket_name, - # region_1: region_1, - # region_2: region_2 - # end - # end - - # refute_nil storage_client.bucket bucket_name - - # delete_bucket_helper bucket_name - # end - # end - - # describe "storage_create_bucket_hierarchical_namespace" do - # it "creates hierarchical namespace enabled bucket" do - # bucket_name = random_bucket_name - # refute storage_client.bucket bucket_name - - # expected = "Created bucket #{bucket_name} with Hierarchical Namespace enabled.\n" - - # retry_resource_exhaustion do - # assert_output expected do - # create_bucket_hierarchical_namespace bucket_name: bucket_name - # end - # end - - # refute_nil storage_client.bucket bucket_name - - # delete_bucket_helper bucket_name - # end - # end - - describe "storage_create_bucket_ip_filter" do + describe "bucket lifecycle" do + it "create_bucket, create_bucket_class_location, list_buckets, get_bucket_metadata, delete_bucket" do + # create_bucket + bucket_name = random_bucket_name + refute storage_client.bucket bucket_name - before :all do - @bucket_name = random_bucket_name + retry_resource_exhaustion do + assert_output "Created bucket: #{bucket_name}\n" do + create_bucket bucket_name: bucket_name + end + end + + refute_nil storage_client.bucket bucket_name + + # create_bucket_class_location + + secondary_bucket_name = random_bucket_name + location = "ASIA" + storage_class = "COLDLINE" + refute storage_client.bucket secondary_bucket_name + + retry_resource_exhaustion do + assert_output "Created bucket #{secondary_bucket_name} in #{location} with #{storage_class} class\n" do + create_bucket_class_location bucket_name: secondary_bucket_name + end + end + + secondary_bucket = storage_client.bucket secondary_bucket_name + refute_nil secondary_bucket + assert_equal location, secondary_bucket.location + assert_equal storage_class, secondary_bucket.storage_class + + # list_buckets + out, _err = capture_io do + list_buckets + end + + assert_includes out, "ruby-storage-samples-" + + # get_bucket_metadata + out, _err = capture_io do + get_bucket_metadata bucket_name: bucket_name + end + + assert_includes out, bucket_name + + # delete_bucket + assert_output "Deleted bucket: #{bucket_name}\n" do + delete_bucket bucket_name: bucket_name + end + + + refute storage_client.bucket bucket_name + + delete_bucket_helper bucket_name + delete_bucket_helper secondary_bucket_name end + end - after :all do - # removes_bucket_ip_filter bucket_name: @bucket_name - # binding.pry + describe "storage_create_bucket_dual_region" do + it "creates dual region bucket" do + location = "US" + region_1 = "US-EAST1" + region_2 = "US-WEST1" + location_type = "dual-region" + bucket_name = random_bucket_name + refute storage_client.bucket bucket_name + + expected = "Bucket #{bucket_name} created:\n" + expected += "- location: #{location}\n" + expected += "- location_type: #{location_type}\n" + expected += "- custom_placement_config:\n" + expected += " - data_locations: #{[region_1, region_2]}\n" + + retry_resource_exhaustion do + assert_output expected do + StorageCreateBucketDualRegion.new.storage_create_bucket_dual_region bucket_name: bucket_name, + region_1: region_1, + region_2: region_2 + end + end - delete_bucket_helper @bucket_name + refute_nil storage_client.bucket bucket_name + + delete_bucket_helper bucket_name end + end + + describe "storage_create_bucket_hierarchical_namespace" do + it "creates hierarchical namespace enabled bucket" do + bucket_name = random_bucket_name + refute storage_client.bucket bucket_name + + expected = "Created bucket #{bucket_name} with Hierarchical Namespace enabled.\n" - it "creates IP filter enabled bucket" do - expected = "Created bucket #{@bucket_name} with IP filter enabled.\n" retry_resource_exhaustion do assert_output expected do - create_bucket_with_ip_filter bucket_name: @bucket_name + create_bucket_hierarchical_namespace bucket_name: bucket_name end end + + refute_nil storage_client.bucket bucket_name + + delete_bucket_helper bucket_name end + end + + describe "storage_bucket_ip_filter" do + let(:bucket_name) { random_bucket_name } - it "removes IP filter of an existing bucket" do - expected = "Updated IP filter for bucket #{@bucket_name}.\n" + after :all do + delete_bucket_helper bucket_name + end + + it "creates, updates, gets, lists, and removes IP filter config" do + # Creates IP filter enabled bucket + expected = "Created bucket #{bucket_name} with IP filter.\n" retry_resource_exhaustion do assert_output expected do - removes_bucket_ip_filter bucket_name: @bucket_name + create_bucket_with_ip_filter bucket_name: bucket_name + end + end + + # Updates IP filter of an existing bucket + expected = "Updated bucket #{bucket_name} with IP filter.\n" + retry_resource_exhaustion do + assert_output expected do + update_bucket_with_ip_filter bucket_name: bucket_name + end + end + + # Gets IP filter of an existing bucket + expected = "Bucket #{bucket_name} has IP filter mode: Disabled.\n" \ + "Allowed public network CIDR ranges: 8.8.8.8/32.\n" + retry_resource_exhaustion do + assert_output expected do + get_bucket_ip_filter bucket_name: bucket_name + end + end + + # Lists IP filter allowed ranges + expected = "IP filter mode: Disabled\n" \ + "Allowed range: 8.8.8.8/32\n" + retry_resource_exhaustion do + assert_output expected do + list_bucket_ip_filters bucket_name: bucket_name + end + end + + # Deletes IP filter of an existing bucket + expected = "Deleted IP filter for bucket #{bucket_name}.\n" + retry_resource_exhaustion do + assert_output expected do + delete_bucket_ip_filter bucket_name: bucket_name + end + end + + # Enables IP filter of an existing bucket (SKIPPED) + skip "SKIPPED : If Ip filter is enabled, we cannot access the bucket" + expected = "Enabled IP filter for bucket #{bucket_name}.\n" + retry_resource_exhaustion do + assert_output expected do + enable_bucket_ip_filter bucket_name: bucket_name end end end + end + + describe "storage_create_bucket_with_object_retention" do + it "creates a bucket with object retention enabled." do + bucket_name = random_bucket_name + refute storage_client.bucket bucket_name + + expected = "Created bucket #{bucket_name} with object retention setting: Enabled\n" - it "Updates IP filter of an existing bucket" do - expected = "Updated bucket #{@bucket_name} with IP filter enabled.\n" retry_resource_exhaustion do assert_output expected do - update_bucket_with_ip_filter bucket_name: @bucket_name + create_bucket_with_object_retention bucket_name: bucket_name end end + + refute_nil storage_client.bucket bucket_name + + file_name = "test_object_retention" + + bucket = storage_client.bucket bucket_name + + out, _err = capture_io do + set_object_retention_policy bucket_name: bucket.name, + content: "hello world", + destination_file_name: file_name + end + + assert_includes out, "Retention policy for file #{file_name}" + + file = bucket.file file_name + file.retention = { + mode: nil, + retain_until_time: nil, + override_unlocked_retention: true + } + delete_bucket_helper bucket_name end end - # describe "storage_create_bucket_with_object_retention" do - # it "creates a bucket with object retention enabled." do - # bucket_name = random_bucket_name - # refute storage_client.bucket bucket_name - - # expected = "Created bucket #{bucket_name} with object retention setting: Enabled\n" - - # retry_resource_exhaustion do - # assert_output expected do - # create_bucket_with_object_retention bucket_name: bucket_name - # end - # end - - # refute_nil storage_client.bucket bucket_name - - # file_name = "test_object_retention" - - # bucket = storage_client.bucket bucket_name - - # out, _err = capture_io do - # set_object_retention_policy bucket_name: bucket.name, - # content: "hello world", - # destination_file_name: file_name - # end - - # assert_includes out, "Retention policy for file #{file_name}" - - # file = bucket.file file_name - # file.retention = { - # mode: nil, - # retain_until_time: nil, - # override_unlocked_retention: true - # } - # delete_bucket_helper bucket_name - # end - # end - - # describe "autoclass" do - # it "get_autoclass, set_autoclass" do - # bucket_name = random_bucket_name - # refute storage_client.bucket bucket_name - - # storage_client.create_bucket bucket_name, autoclass_enabled: true - - # assert_output(/autoclass config set to true./) do - # get_autoclass bucket_name: bucket_name - # end - - # assert_output(/autoclass terminal storage class set to NEARLINE./) do - # get_autoclass bucket_name: bucket_name - # end - - # assert_output(/autoclass terminal storage class set to ARCHIVE./) do - # set_autoclass bucket_name: bucket_name, toggle: true, terminal_storage_class: "ARCHIVE" - # end - - # assert_output(/autoclass config set to false./) do - # set_autoclass bucket_name: bucket_name, toggle: false - # end - - # delete_bucket_helper bucket_name - # end - # end - - # describe "cors" do - # it "cors_configuration, remove_cors_configuration" do - # bucket.cors { |c| c.clear } - # assert bucket.cors.empty? - - # # cors_configuration - # assert_output "Set CORS policies for bucket #{bucket.name}\n" do - # cors_configuration bucket_name: bucket.name - # end - - # bucket.refresh! - # assert_equal 1, bucket.cors.count - # rule = bucket.cors.first - # assert_equal ["*"], rule.origin - # assert_equal ["PUT", "POST"], rule.methods - # assert_equal ["Content-Type", "x-goog-resumable"], rule.headers - # assert_equal 3600, rule.max_age - - # # remove_cors_configuration - # assert_output "Remove CORS policies for bucket #{bucket.name}\n" do - # remove_cors_configuration bucket_name: bucket.name - # end - # bucket.refresh! - # assert bucket.cors.empty? - # end - # end - - # describe "requester_pays" do - # it "enable_requester_pays, disable_requester_pays, get_requester_pays_status" do - # # enable_requester_pays - # bucket.requester_pays = false - - # assert_output "Requester pays has been enabled for #{bucket.name}\n" do - # enable_requester_pays bucket_name: bucket.name - # end - # bucket.refresh! - # assert bucket.requester_pays? - - # # get_requester_pays_status - # assert_output "Requester pays status is enabled for #{bucket.name}\n" do - # get_requester_pays_status bucket_name: bucket.name - # end - # assert bucket.requester_pays? - - # # disable_requester_pays - # assert_output "Requester pays has been disabled for #{bucket.name}\n" do - # disable_requester_pays bucket_name: bucket.name - # end - # bucket.refresh! - # refute bucket.requester_pays? - - # # get_requester_pays_status - # assert_output "Requester pays status is disabled for #{bucket.name}\n" do - # get_requester_pays_status bucket_name: bucket.name - # end - # refute bucket.requester_pays? - # end - # end - - # describe "uniform_bucket_level_access" do - # it "enable_uniform_bucket_level_access, get_uniform_bucket_level_access, disable_uniform_bucket_level_access" do - # # enable_uniform_bucket_level_access - # bucket.uniform_bucket_level_access = false - - # assert_output "Uniform bucket-level access was enabled for #{bucket.name}.\n" do - # enable_uniform_bucket_level_access bucket_name: bucket.name - # end - - # bucket.refresh! - # assert bucket.uniform_bucket_level_access? - - # # get_uniform_bucket_level_access - # assert_output "Uniform bucket-level access is enabled for #{bucket.name}.\nBucket " \ - # "will be locked on #{bucket.uniform_bucket_level_access_locked_at}.\n" do - # get_uniform_bucket_level_access bucket_name: bucket.name - # end - # assert bucket.uniform_bucket_level_access? - - # # disable_uniform_bucket_level_access - # assert_output "Uniform bucket-level access was disabled for #{bucket.name}.\n" do - # disable_uniform_bucket_level_access bucket_name: bucket.name - # end - - # bucket.refresh! - # refute bucket.uniform_bucket_level_access? - - # # get_uniform_bucket_level_access - # assert_output "Uniform bucket-level access is disabled for #{bucket.name}.\n" do - # get_uniform_bucket_level_access bucket_name: bucket.name - # end - # refute bucket.uniform_bucket_level_access? - - # bucket.uniform_bucket_level_access = false - # end - # end - - # describe "default Cloud KMS encryption key" do - # it "set_bucket_default_kms_key, bucket_delete_default_kms_key" do - # refute bucket.default_kms_key - - # # set_bucket_default_kms_key - # assert_output "Default KMS key for #{bucket.name} was set to #{kms_key}\n" do - # set_bucket_default_kms_key bucket_name: bucket.name, - # default_kms_key: kms_key - # end - - # bucket.refresh! - # assert_equal bucket.default_kms_key, kms_key - - # # bucket_delete_default_kms_key - # assert_output "Default KMS key was removed from #{bucket.name}\n" do - # bucket_delete_default_kms_key bucket_name: bucket.name - # end - - # bucket.refresh! - # refute bucket.default_kms_key - # end - # end - - # describe "get bucket class and location data" do - # bucket_name = random_bucket_name - # location = "US" - # storage_class = "COLDLINE" - - # it "get_bucket_class_and_location" do - # storage_client.create_bucket bucket_name, - # location: location, - # storage_class: storage_class - # expected_output = "Bucket #{bucket_name} storage class is " \ - # "#{storage_class}, and the location is #{location}\n" - # assert_output expected_output do - # get_bucket_class_and_location bucket_name: bucket_name - # end - # end - # end - - # describe "labels" do - # it "add_bucket_label, remove_bucket_label" do - # # add_bucket_label - # label_key = "label_key" - # label_value = "label_value" - - # assert_output "Added label #{label_key} with value #{label_value} to #{bucket.name}\n" do - # add_bucket_label bucket_name: bucket.name, - # label_value: label_value, - # label_key: label_key - # end - - # bucket.refresh! - # assert_equal bucket.labels[label_key], label_value - - # # remove_bucket_label - # assert_output "Deleted label #{label_key} from #{bucket.name}\n" do - # remove_bucket_label bucket_name: bucket.name, - # label_key: label_key - # end - - # bucket.refresh! - # assert bucket.labels[label_key].empty? - # end - # end - - # describe "lifecycle management" do - # let(:bucket) { create_bucket_helper random_bucket_name } - # after { delete_bucket_helper bucket.name } - - # it "enable_bucket_lifecycle_management, disable_bucket_lifecycle_management" do - # # enable_bucket_lifecycle_management - # out, _err = capture_io do - # enable_bucket_lifecycle_management bucket_name: bucket.name - # end - - # assert_includes out, "Lifecycle management is enabled" - - # # disable_bucket_lifecycle_management - # out, _err = capture_io do - # disable_bucket_lifecycle_management bucket_name: bucket.name - # end - - # assert_includes out, "Lifecycle management is disabled" - # end - # end - - # describe "retention policy" do - # let(:bucket) { create_bucket_helper random_bucket_name } - # after { delete_bucket_helper bucket.name } - - # it "set_retention_policy, get_retention_policy, remove_retention_policy" do - # # set_retention_policy - # assert_output "Retention period for #{bucket.name} is now #{retention_period} seconds.\n" do - # set_retention_policy bucket_name: bucket.name, - # retention_period: retention_period - # end - - # bucket.refresh! - # assert_equal bucket.retention_period, retention_period - - # # get_retention_policy - # out, _err = capture_io do - # get_retention_policy bucket_name: bucket.name - # end - - # assert_includes out, "period: #{retention_period}\n" - - # # remove_retention_policy - # assert_equal bucket.retention_period, retention_period - # assert_output "Retention policy for #{bucket.name} has been removed.\n" do - # remove_retention_policy bucket_name: bucket.name - # end - - # bucket.refresh! - # refute bucket.retention_period - - # # lock_retention_policy - # bucket.retention_period = retention_period - # out, _err = capture_io do - # lock_retention_policy bucket_name: bucket.name - # end - - # assert_includes out, "Retention policy for #{bucket.name} is now locked." - # bucket.refresh! - # assert bucket.retention_policy_locked? - - # # remove_retention_policy - # assert_output "Policy is locked and retention policy can't be removed.\n" do - # remove_retention_policy bucket_name: bucket.name - # end - # end - # end - - # describe "default_event_based_hold" do - # it "enable_default_event_based_hold, get_default_event_based_hold, disable_default_event_based_hold" do - # # enable_default_event_based_hold - # assert_output "Default event-based hold was enabled for #{bucket.name}.\n" do - # enable_default_event_based_hold bucket_name: bucket.name - # end - - # bucket.refresh! - # assert bucket.default_event_based_hold? - - # # get_default_event_based_hold - # assert_output "Default event-based hold is enabled for #{bucket.name}.\n" do - # get_default_event_based_hold bucket_name: bucket.name - # end - - # # disable_default_event_based_hold - # bucket.update do |b| - # b.default_event_based_hold = true - # end - - # assert_output "Default event-based hold was disabled for #{bucket.name}.\n" do - # disable_default_event_based_hold bucket_name: bucket.name - # end - - # bucket.refresh! - # refute bucket.default_event_based_hold? - - # # get_default_event_based_hold - # assert_output "Default event-based hold is not enabled for #{bucket.name}.\n" do - # get_default_event_based_hold bucket_name: bucket.name - # end - # end - # end - - # describe "storage_class" do - # it "change_default_storage_class" do - # assert_equal "STANDARD", bucket.storage_class - - # assert_output "Default storage class for bucket #{bucket.name} has been set to COLDLINE\n" do - # change_default_storage_class bucket_name: bucket.name - # end - - # bucket.refresh! - # assert_equal "COLDLINE", bucket.storage_class - # # teardown - # bucket.storage_class = "STANDARD" - # end - # end - - # describe "versioning" do - # it "enable_versioning, disable_versioning" do - # # enable_versioning - # bucket.versioning = false - - # assert_output "Versioning was enabled for bucket #{bucket.name}\n" do - # enable_versioning bucket_name: bucket.name - # end - # bucket.refresh! - # assert bucket.versioning? - - # # disable_versioning - # assert_output "Versioning was disabled for bucket #{bucket.name}\n" do - # disable_versioning bucket_name: bucket.name - # end - # bucket.refresh! - # refute bucket.versioning? - # end - # end - - # describe "website_configuration" do - # let(:main_page_suffix) { "index.html" } - # let(:not_found_page) { "404.html" } - - # it "define_bucket_website_configuration" do - # expected_out = "Static website bucket #{bucket.name} is set up to use #{main_page_suffix} as the index page " \ - # "and #{not_found_page} as the 404 page\n" - - # assert_output expected_out do - # define_bucket_website_configuration bucket_name: bucket.name, - # main_page_suffix: main_page_suffix, - # not_found_page: not_found_page - # end - - # bucket.refresh! - # assert_equal main_page_suffix, bucket.website_main - # assert_equal not_found_page, bucket.website_404 - # end - # end - - # describe "public_access_prevention" do - # it "set_public_access_prevention_enforced, get_public_access_prevention, " \ - # "set_public_access_prevention_inherited" do - # bucket.public_access_prevention = :inherited - # bucket.refresh! - # _(bucket.public_access_prevention).must_equal "inherited" - - # # set_public_access_prevention_enforced - # assert_output "Public access prevention is set to enforced for #{bucket.name}.\n" do - # set_public_access_prevention_enforced bucket_name: bucket.name - # end - - # bucket.refresh! - # _(bucket.public_access_prevention).must_equal "enforced" - - # # get_public_access_prevention - # assert_output "Public access prevention is 'enforced' for #{bucket.name}.\n" do - # get_public_access_prevention bucket_name: bucket.name - # end - # _(bucket.public_access_prevention).must_equal "enforced" - - # # set_public_access_prevention_inherited - # assert_output "Public access prevention is 'inherited' for #{bucket.name}.\n" do - # set_public_access_prevention_inherited bucket_name: bucket.name - # end - - # bucket.refresh! - # _(bucket.public_access_prevention).must_equal "inherited" - # bucket.public_access_prevention = :inherited - # end - # end - - # describe "storage move file" do - # let(:source_file) { "file_1_name_#{SecureRandom.hex}.txt" } - # let(:destination_file) { "file_2_name_#{SecureRandom.hex}.txt" } - # let :hns_bucket do - # hierarchical_namespace = Google::Apis::StorageV1::Bucket::HierarchicalNamespace.new enabled: true - # storage_client.create_bucket random_bucket_name do |b| - # b.uniform_bucket_level_access = true - # b.hierarchical_namespace = hierarchical_namespace - # end - # end - # let :create_source_file do - # file_content = "A" * (3 * 1024 * 1024) # 3 MB of 'A' characters - # file = StringIO.new file_content - # hns_bucket.create_file file, source_file - # end - # it "file is moved and old file is deleted" do - # create_source_file - # out, _err = capture_io do - # move_object bucket_name: hns_bucket.name, source_file_name: source_file, destination_file_name: destination_file - # end - # assert_includes out, "New File #{destination_file} created\n" - # refute_nil(hns_bucket.file(destination_file)) - # assert_nil(hns_bucket.file(source_file)) - # end - - # it "raises error if source and destination are having same filename" do - # create_source_file - # exception = assert_raises Google::Cloud::InvalidArgumentError do - # move_object bucket_name: hns_bucket.name, source_file_name: source_file, destination_file_name: source_file - # end - # assert_equal "invalid: Source and destination object names must be different.", exception.message - # end - # end - - # describe "list buckets with partial success" do - # it 'returns a list of bucket names if return_partial_success_flag is true' do - # result = list_buckets_with_partial_success return_partial_success_flag: true - # assert_kind_of Array, result - # assert result.all? { |n| n.is_a? String }, "expected all items to be String" - # end - - # it 'returns nil for unreachable if return_partial_success_flag is false' do - # result = list_buckets_with_partial_success return_partial_success_flag: false - # assert_nil result - # end - - # it 'returns nil for unreachable if return_partial_success_flag is not passed' do - # result = list_buckets_with_partial_success return_partial_success_flag: nil - # assert_nil result - # end - # end + describe "autoclass" do + it "get_autoclass, set_autoclass" do + bucket_name = random_bucket_name + refute storage_client.bucket bucket_name + + storage_client.create_bucket bucket_name, autoclass_enabled: true + + assert_output(/autoclass config set to true./) do + get_autoclass bucket_name: bucket_name + end + + assert_output(/autoclass terminal storage class set to NEARLINE./) do + get_autoclass bucket_name: bucket_name + end + + assert_output(/autoclass terminal storage class set to ARCHIVE./) do + set_autoclass bucket_name: bucket_name, toggle: true, terminal_storage_class: "ARCHIVE" + end + + assert_output(/autoclass config set to false./) do + set_autoclass bucket_name: bucket_name, toggle: false + end + + delete_bucket_helper bucket_name + end + end + + describe "cors" do + it "cors_configuration, remove_cors_configuration" do + bucket.cors { |c| c.clear } + assert bucket.cors.empty? + + # cors_configuration + assert_output "Set CORS policies for bucket #{bucket.name}\n" do + cors_configuration bucket_name: bucket.name + end + + bucket.refresh! + assert_equal 1, bucket.cors.count + rule = bucket.cors.first + assert_equal ["*"], rule.origin + assert_equal ["PUT", "POST"], rule.methods + assert_equal ["Content-Type", "x-goog-resumable"], rule.headers + assert_equal 3600, rule.max_age + + # remove_cors_configuration + assert_output "Remove CORS policies for bucket #{bucket.name}\n" do + remove_cors_configuration bucket_name: bucket.name + end + bucket.refresh! + assert bucket.cors.empty? + end + end + + describe "requester_pays" do + it "enable_requester_pays, disable_requester_pays, get_requester_pays_status" do + # enable_requester_pays + bucket.requester_pays = false + + assert_output "Requester pays has been enabled for #{bucket.name}\n" do + enable_requester_pays bucket_name: bucket.name + end + bucket.refresh! + assert bucket.requester_pays? + + # get_requester_pays_status + assert_output "Requester pays status is enabled for #{bucket.name}\n" do + get_requester_pays_status bucket_name: bucket.name + end + assert bucket.requester_pays? + + # disable_requester_pays + assert_output "Requester pays has been disabled for #{bucket.name}\n" do + disable_requester_pays bucket_name: bucket.name + end + bucket.refresh! + refute bucket.requester_pays? + + # get_requester_pays_status + assert_output "Requester pays status is disabled for #{bucket.name}\n" do + get_requester_pays_status bucket_name: bucket.name + end + refute bucket.requester_pays? + end + end + + describe "uniform_bucket_level_access" do + it "enable_uniform_bucket_level_access, get_uniform_bucket_level_access, disable_uniform_bucket_level_access" do + # enable_uniform_bucket_level_access + bucket.uniform_bucket_level_access = false + + assert_output "Uniform bucket-level access was enabled for #{bucket.name}.\n" do + enable_uniform_bucket_level_access bucket_name: bucket.name + end + + bucket.refresh! + assert bucket.uniform_bucket_level_access? + + # get_uniform_bucket_level_access + assert_output "Uniform bucket-level access is enabled for #{bucket.name}.\nBucket " \ + "will be locked on #{bucket.uniform_bucket_level_access_locked_at}.\n" do + get_uniform_bucket_level_access bucket_name: bucket.name + end + assert bucket.uniform_bucket_level_access? + + # disable_uniform_bucket_level_access + assert_output "Uniform bucket-level access was disabled for #{bucket.name}.\n" do + disable_uniform_bucket_level_access bucket_name: bucket.name + end + + bucket.refresh! + refute bucket.uniform_bucket_level_access? + + # get_uniform_bucket_level_access + assert_output "Uniform bucket-level access is disabled for #{bucket.name}.\n" do + get_uniform_bucket_level_access bucket_name: bucket.name + end + refute bucket.uniform_bucket_level_access? + + bucket.uniform_bucket_level_access = false + end + end + + describe "default Cloud KMS encryption key" do + it "set_bucket_default_kms_key, bucket_delete_default_kms_key" do + refute bucket.default_kms_key + + # set_bucket_default_kms_key + assert_output "Default KMS key for #{bucket.name} was set to #{kms_key}\n" do + set_bucket_default_kms_key bucket_name: bucket.name, + default_kms_key: kms_key + end + + bucket.refresh! + assert_equal bucket.default_kms_key, kms_key + + # bucket_delete_default_kms_key + assert_output "Default KMS key was removed from #{bucket.name}\n" do + bucket_delete_default_kms_key bucket_name: bucket.name + end + + bucket.refresh! + refute bucket.default_kms_key + end + end + + describe "get bucket class and location data" do + bucket_name = random_bucket_name + location = "US" + storage_class = "COLDLINE" + + it "get_bucket_class_and_location" do + storage_client.create_bucket bucket_name, + location: location, + storage_class: storage_class + expected_output = "Bucket #{bucket_name} storage class is " \ + "#{storage_class}, and the location is #{location}\n" + assert_output expected_output do + get_bucket_class_and_location bucket_name: bucket_name + end + end + end + + describe "labels" do + it "add_bucket_label, remove_bucket_label" do + # add_bucket_label + label_key = "label_key" + label_value = "label_value" + + assert_output "Added label #{label_key} with value #{label_value} to #{bucket.name}\n" do + add_bucket_label bucket_name: bucket.name, + label_value: label_value, + label_key: label_key + end + + bucket.refresh! + assert_equal bucket.labels[label_key], label_value + + # remove_bucket_label + assert_output "Deleted label #{label_key} from #{bucket.name}\n" do + remove_bucket_label bucket_name: bucket.name, + label_key: label_key + end + + bucket.refresh! + assert bucket.labels[label_key].empty? + end + end + + describe "lifecycle management" do + let(:bucket) { create_bucket_helper random_bucket_name } + after { delete_bucket_helper bucket.name } + + it "enable_bucket_lifecycle_management, disable_bucket_lifecycle_management" do + # enable_bucket_lifecycle_management + out, _err = capture_io do + enable_bucket_lifecycle_management bucket_name: bucket.name + end + + assert_includes out, "Lifecycle management is enabled" + + # disable_bucket_lifecycle_management + out, _err = capture_io do + disable_bucket_lifecycle_management bucket_name: bucket.name + end + + assert_includes out, "Lifecycle management is disabled" + end + end + + describe "retention policy" do + let(:bucket) { create_bucket_helper random_bucket_name } + after { delete_bucket_helper bucket.name } + + it "set_retention_policy, get_retention_policy, remove_retention_policy" do + # set_retention_policy + assert_output "Retention period for #{bucket.name} is now #{retention_period} seconds.\n" do + set_retention_policy bucket_name: bucket.name, + retention_period: retention_period + end + + bucket.refresh! + assert_equal bucket.retention_period, retention_period + + # get_retention_policy + out, _err = capture_io do + get_retention_policy bucket_name: bucket.name + end + + assert_includes out, "period: #{retention_period}\n" + + # remove_retention_policy + assert_equal bucket.retention_period, retention_period + assert_output "Retention policy for #{bucket.name} has been removed.\n" do + remove_retention_policy bucket_name: bucket.name + end + + bucket.refresh! + refute bucket.retention_period + + # lock_retention_policy + bucket.retention_period = retention_period + out, _err = capture_io do + lock_retention_policy bucket_name: bucket.name + end + + assert_includes out, "Retention policy for #{bucket.name} is now locked." + bucket.refresh! + assert bucket.retention_policy_locked? + + # remove_retention_policy + assert_output "Policy is locked and retention policy can't be removed.\n" do + remove_retention_policy bucket_name: bucket.name + end + end + end + + describe "default_event_based_hold" do + it "enable_default_event_based_hold, get_default_event_based_hold, disable_default_event_based_hold" do + # enable_default_event_based_hold + assert_output "Default event-based hold was enabled for #{bucket.name}.\n" do + enable_default_event_based_hold bucket_name: bucket.name + end + + bucket.refresh! + assert bucket.default_event_based_hold? + + # get_default_event_based_hold + assert_output "Default event-based hold is enabled for #{bucket.name}.\n" do + get_default_event_based_hold bucket_name: bucket.name + end + + # disable_default_event_based_hold + bucket.update do |b| + b.default_event_based_hold = true + end + + assert_output "Default event-based hold was disabled for #{bucket.name}.\n" do + disable_default_event_based_hold bucket_name: bucket.name + end + + bucket.refresh! + refute bucket.default_event_based_hold? + + # get_default_event_based_hold + assert_output "Default event-based hold is not enabled for #{bucket.name}.\n" do + get_default_event_based_hold bucket_name: bucket.name + end + end + end + + describe "storage_class" do + it "change_default_storage_class" do + assert_equal "STANDARD", bucket.storage_class + + assert_output "Default storage class for bucket #{bucket.name} has been set to COLDLINE\n" do + change_default_storage_class bucket_name: bucket.name + end + + bucket.refresh! + assert_equal "COLDLINE", bucket.storage_class + # teardown + bucket.storage_class = "STANDARD" + end + end + + describe "versioning" do + it "enable_versioning, disable_versioning" do + # enable_versioning + bucket.versioning = false + + assert_output "Versioning was enabled for bucket #{bucket.name}\n" do + enable_versioning bucket_name: bucket.name + end + bucket.refresh! + assert bucket.versioning? + + # disable_versioning + assert_output "Versioning was disabled for bucket #{bucket.name}\n" do + disable_versioning bucket_name: bucket.name + end + bucket.refresh! + refute bucket.versioning? + end + end + + describe "website_configuration" do + let(:main_page_suffix) { "index.html" } + let(:not_found_page) { "404.html" } + + it "define_bucket_website_configuration" do + expected_out = "Static website bucket #{bucket.name} is set up to use #{main_page_suffix} as the index page " \ + "and #{not_found_page} as the 404 page\n" + + assert_output expected_out do + define_bucket_website_configuration bucket_name: bucket.name, + main_page_suffix: main_page_suffix, + not_found_page: not_found_page + end + + bucket.refresh! + assert_equal main_page_suffix, bucket.website_main + assert_equal not_found_page, bucket.website_404 + end + end + + describe "public_access_prevention" do + it "set_public_access_prevention_enforced, get_public_access_prevention, " \ + "set_public_access_prevention_inherited" do + bucket.public_access_prevention = :inherited + bucket.refresh! + _(bucket.public_access_prevention).must_equal "inherited" + + # set_public_access_prevention_enforced + assert_output "Public access prevention is set to enforced for #{bucket.name}.\n" do + set_public_access_prevention_enforced bucket_name: bucket.name + end + + bucket.refresh! + _(bucket.public_access_prevention).must_equal "enforced" + + # get_public_access_prevention + assert_output "Public access prevention is 'enforced' for #{bucket.name}.\n" do + get_public_access_prevention bucket_name: bucket.name + end + _(bucket.public_access_prevention).must_equal "enforced" + + # set_public_access_prevention_inherited + assert_output "Public access prevention is 'inherited' for #{bucket.name}.\n" do + set_public_access_prevention_inherited bucket_name: bucket.name + end + + bucket.refresh! + _(bucket.public_access_prevention).must_equal "inherited" + bucket.public_access_prevention = :inherited + end + end + + describe "storage move file" do + let(:source_file) { "file_1_name_#{SecureRandom.hex}.txt" } + let(:destination_file) { "file_2_name_#{SecureRandom.hex}.txt" } + let :hns_bucket do + hierarchical_namespace = Google::Apis::StorageV1::Bucket::HierarchicalNamespace.new enabled: true + storage_client.create_bucket random_bucket_name do |b| + b.uniform_bucket_level_access = true + b.hierarchical_namespace = hierarchical_namespace + end + end + let :create_source_file do + file_content = "A" * (3 * 1024 * 1024) # 3 MB of 'A' characters + file = StringIO.new file_content + hns_bucket.create_file file, source_file + end + it "file is moved and old file is deleted" do + create_source_file + out, _err = capture_io do + move_object bucket_name: hns_bucket.name, source_file_name: source_file, destination_file_name: destination_file + end + assert_includes out, "New File #{destination_file} created\n" + refute_nil(hns_bucket.file(destination_file)) + assert_nil(hns_bucket.file(source_file)) + end + + it "raises error if source and destination are having same filename" do + create_source_file + exception = assert_raises Google::Cloud::InvalidArgumentError do + move_object bucket_name: hns_bucket.name, source_file_name: source_file, destination_file_name: source_file + end + assert_equal "invalid: Source and destination object names must be different.", exception.message + end + end + + describe "list buckets with partial success" do + it 'returns a list of bucket names if return_partial_success_flag is true' do + result = list_buckets_with_partial_success return_partial_success_flag: true + assert_kind_of Array, result + assert result.all? { |n| n.is_a? String }, "expected all items to be String" + end + + it 'returns nil for unreachable if return_partial_success_flag is false' do + result = list_buckets_with_partial_success return_partial_success_flag: false + assert_nil result + end + + it 'returns nil for unreachable if return_partial_success_flag is not passed' do + result = list_buckets_with_partial_success return_partial_success_flag: nil + assert_nil result + end + end end diff --git a/google-cloud-storage/samples/storage_create_bucket_with_ip_filter.rb b/google-cloud-storage/samples/storage_create_bucket_with_ip_filter.rb index c31d03a076d7..b155ad7fe391 100644 --- a/google-cloud-storage/samples/storage_create_bucket_with_ip_filter.rb +++ b/google-cloud-storage/samples/storage_create_bucket_with_ip_filter.rb @@ -1,4 +1,4 @@ -# Copyright 2024 Google LLC +# 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. @@ -20,60 +20,20 @@ def create_bucket_with_ip_filter bucket_name: require "google/cloud/storage" storage = Google::Cloud::Storage.new - ip_filter = { - mode: "Disabled", - public_network_source: { - allowed_ip_cidr_ranges: [ - "0.0.0.0/0", "::/0" - ] - } - } - - bucket = storage.create_bucket bucket_name do |b| - b.ip_filter = ip_filter - b.uniform_bucket_level_access = true - end - puts "Created bucket #{bucket_name} with IP filter enabled." -end - -def removes_bucket_ip_filter bucket_name: - # The ID of your GCS bucket - # bucket_name = "your-unique-bucket-name" - - require "google/cloud/storage" - - storage = Google::Cloud::Storage.new - bucket = storage.bucket bucket_name - - ip_filter = Google::Apis::StorageV1::Bucket::IpFilter.new( - mode: "Disabled" - ) - bucket.update do |b| - b.ip_filter = ip_filter - end - - puts "Updated IP filter for bucket #{bucket_name}." -end - -def update_bucket_with_ip_filter bucket_name: - # The ID to give your GCS bucket - # bucket_name = "your-unique-bucket-name" - - storage = Google::Cloud::Storage.new - bucket = storage.bucket bucket_name - ip_filter = { mode: "Disabled", public_network_source: { allowed_ip_cidr_ranges: [ - "0.0.0.4/0", "::/0" + "0.0.0.0/0", "::/0" ] } } - bucket.update do |b| + + bucket = storage.create_bucket bucket_name do |b| b.ip_filter = ip_filter + b.uniform_bucket_level_access = true end - puts "Updated bucket #{bucket_name} with IP filter enabled." + puts "Created bucket #{bucket_name} with IP filter." end # [END storage_create_bucket_with_ip_filter] diff --git a/google-cloud-storage/samples/storage_delete_bucket_ip_filter.rb b/google-cloud-storage/samples/storage_delete_bucket_ip_filter.rb new file mode 100644 index 000000000000..f5366527769b --- /dev/null +++ b/google-cloud-storage/samples/storage_delete_bucket_ip_filter.rb @@ -0,0 +1,41 @@ +# 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. + +# [START storage_delete_ip_filtering_rules] +def delete_bucket_ip_filter bucket_name: + # The ID of your GCS bucket + # bucket_name = "your-unique-bucket-name" + + require "google/cloud/storage" + + storage = Google::Cloud::Storage.new + bucket = storage.bucket bucket_name + + # Clear IP filter configuration by setting it to empty/disabled + bucket.update do |b| + b.ip_filter = { + mode: "Disabled", + public_network_source: { + allowed_ip_cidr_ranges: [] + } + } + end + + puts "Deleted IP filter for bucket #{bucket_name}." +end +# [END storage_delete_ip_filtering_rules] + +if $PROGRAM_NAME == __FILE__ + delete_bucket_ip_filter bucket_name: ARGV.shift +end diff --git a/google-cloud-storage/samples/storage_enable_bucket_ip_filter.rb b/google-cloud-storage/samples/storage_enable_bucket_ip_filter.rb new file mode 100644 index 000000000000..6e96767479f1 --- /dev/null +++ b/google-cloud-storage/samples/storage_enable_bucket_ip_filter.rb @@ -0,0 +1,44 @@ +# 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. + +# [START storage_enable_bucket_ip_filter] +def enable_bucket_ip_filter bucket_name: + # The ID of your GCS bucket + # bucket_name = "your-unique-bucket-name" + + require "google/cloud/storage" + + storage = Google::Cloud::Storage.new + bucket = storage.bucket bucket_name + + # Enable the IP filter configuration. + ip_filter = { + mode: "Enabled", + allow_all_service_agent_access: true, + public_network_source: { + allowed_ip_cidr_ranges: ["0.0.0.0/0", "::/0"] + } + } + + bucket.update do |b| + b.ip_filter = ip_filter + end + + puts "Enabled IP filter for bucket #{bucket_name}." +end +# [END storage_enable_bucket_ip_filter] + +if $PROGRAM_NAME == __FILE__ + enable_bucket_ip_filter bucket_name: ARGV.shift +end diff --git a/google-cloud-storage/samples/storage_get_bucket_ip_filter.rb b/google-cloud-storage/samples/storage_get_bucket_ip_filter.rb new file mode 100644 index 000000000000..62f872a3fa43 --- /dev/null +++ b/google-cloud-storage/samples/storage_get_bucket_ip_filter.rb @@ -0,0 +1,40 @@ +# 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. + +# [START storage_get_bucket_ip_filter] +def get_bucket_ip_filter bucket_name: + # The ID of your GCS bucket + # bucket_name = "your-unique-bucket-name" + + require "google/cloud/storage" + + storage = Google::Cloud::Storage.new + bucket = storage.bucket bucket_name + + ip_filter = bucket.ip_filter + + if ip_filter + puts "Bucket #{bucket_name} has IP filter mode: #{ip_filter.mode}." + if ip_filter.public_network_source + puts "Allowed public network CIDR ranges: #{ip_filter.public_network_source.allowed_ip_cidr_ranges.join(', ')}." + end + else + puts "Bucket #{bucket_name} does not have an IP filter configuration." + end +end +# [END storage_get_bucket_ip_filter] + +if $PROGRAM_NAME == __FILE__ + get_bucket_ip_filter bucket_name: ARGV.shift +end diff --git a/google-cloud-storage/samples/storage_list_bucket_ip_filters.rb b/google-cloud-storage/samples/storage_list_bucket_ip_filters.rb new file mode 100644 index 000000000000..e0d294cfc436 --- /dev/null +++ b/google-cloud-storage/samples/storage_list_bucket_ip_filters.rb @@ -0,0 +1,41 @@ +# 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. + +# [START storage_list_bucket_ip_filters] +def list_bucket_ip_filters bucket_name: + # The ID of your GCS bucket + # bucket_name = "your-unique-bucket-name" + + require "google/cloud/storage" + + storage = Google::Cloud::Storage.new + bucket = storage.bucket bucket_name + + ip_filter = bucket.ip_filter + if ip_filter + puts "IP filter mode: #{ip_filter.mode}" + if ip_filter.public_network_source + ip_filter.public_network_source.allowed_ip_cidr_ranges.each do |range| + puts "Allowed range: #{range}" + end + end + else + puts "No IP filter configured on bucket #{bucket_name}." + end +end +# [END storage_list_bucket_ip_filters] + +if $PROGRAM_NAME == __FILE__ + list_bucket_ip_filters bucket_name: ARGV.shift +end diff --git a/google-cloud-storage/samples/storage_update_bucket_with_ip_filter.rb b/google-cloud-storage/samples/storage_update_bucket_with_ip_filter.rb new file mode 100644 index 000000000000..dd616d1b1001 --- /dev/null +++ b/google-cloud-storage/samples/storage_update_bucket_with_ip_filter.rb @@ -0,0 +1,44 @@ +# 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. + +# [START storage_update_bucket_with_ip_filter] +def update_bucket_with_ip_filter bucket_name: + # The ID of your GCS bucket + # bucket_name = "your-unique-bucket-name" + + require "google/cloud/storage" + + storage = Google::Cloud::Storage.new + bucket = storage.bucket bucket_name + + ip_filter = { + mode: "Disabled", + public_network_source: { + allowed_ip_cidr_ranges: [ + "8.8.8.8/32" + ] + } + } + + bucket.update do |b| + b.ip_filter = ip_filter + end + + puts "Updated bucket #{bucket_name} with IP filter." +end +# [END storage_update_bucket_with_ip_filter] + +if $PROGRAM_NAME == __FILE__ + update_bucket_with_ip_filter bucket_name: ARGV.shift +end diff --git a/google-cloud-storage/test/google/cloud/storage/bucket_ip_filter_test.rb b/google-cloud-storage/test/google/cloud/storage/bucket_ip_filter_test.rb new file mode 100644 index 000000000000..9706f05c8b74 --- /dev/null +++ b/google-cloud-storage/test/google/cloud/storage/bucket_ip_filter_test.rb @@ -0,0 +1,151 @@ +# 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 +# +# https://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. + +require "helper" + +describe Google::Cloud::Storage::Bucket, :ip_filter, :mock_storage do + let(:bucket_name) { "new-bucket-#{Time.now.to_i}" } + let(:bucket_hash) { random_bucket_hash name: bucket_name } + let(:bucket_gapi) { Google::Apis::StorageV1::Bucket.from_json bucket_hash.to_json } + let(:bucket) { Google::Cloud::Storage::Bucket.from_gapi bucket_gapi, storage.service } + + let(:ip_filter_hash) do + { + "mode" => "Disabled", + "publicNetworkSource" => { + "allowedIpCidrRanges" => ["0.0.0.0/0", "::/0"] + } + } + end + let(:ip_filter_gapi) { Google::Apis::StorageV1::Bucket::IpFilter.from_json ip_filter_hash.to_json } + + it "knows its ip_filter value" do + _(bucket.ip_filter).must_be_nil + + bucket_gapi.ip_filter = ip_filter_gapi + _(bucket.ip_filter).wont_be_nil + _(bucket.ip_filter.mode).must_equal "Disabled" + _(bucket.ip_filter.public_network_source.allowed_ip_cidr_ranges).must_equal ["0.0.0.0/0", "::/0"] + end + + + it "updates its ip_filter" do + mock = Minitest::Mock.new + mock.expect :update_bucket, resp_bucket_gapi(bucket_hash, ip_filter: ip_filter_gapi), + [bucket_name, patch_bucket_gapi(ip_filter: ip_filter_gapi)], **update_bucket_args(options: {retries: 0}) + + bucket.service.mocked_service = mock + + _(bucket.ip_filter).must_be_nil + + bucket.update do |b| + b.ip_filter = ip_filter_gapi + end + + _(bucket.ip_filter).wont_be_nil + _(bucket.ip_filter.mode).must_equal "Disabled" + _(bucket.ip_filter.public_network_source.allowed_ip_cidr_ranges).must_equal ["0.0.0.0/0", "::/0"] + + mock.verify + end + + it "enables its ip_filter" do + enable_ip_filter_hash = { + "mode" => "Enabled", + "allowAllServiceAgentAccess" => true, + "publicNetworkSource" => { + "allowedIpCidrRanges" => ["0.0.0.0/0", "::/0"] + } + } + enable_ip_filter_gapi = Google::Apis::StorageV1::Bucket::IpFilter.from_json enable_ip_filter_hash.to_json + + mock = Minitest::Mock.new + mock.expect :update_bucket, resp_bucket_gapi(bucket_hash, ip_filter: enable_ip_filter_gapi), + [bucket_name, patch_bucket_gapi(ip_filter: enable_ip_filter_gapi)], **update_bucket_args(options: {retries: 0}) + + bucket.service.mocked_service = mock + + bucket.update do |b| + b.ip_filter = { + mode: "Enabled", + allow_all_service_agent_access: true, + public_network_source: { + allowed_ip_cidr_ranges: ["0.0.0.0/0", "::/0"] + } + } + end + + _(bucket.ip_filter).wont_be_nil + _(bucket.ip_filter.mode).must_equal "Enabled" + _(bucket.ip_filter.allow_all_service_agent_access).must_equal true + _(bucket.ip_filter.public_network_source.allowed_ip_cidr_ranges).must_equal ["0.0.0.0/0", "::/0"] + + mock.verify + end + + it "deletes its ip_filter" do + delete_ip_filter_hash = { + "mode" => "Disabled", + "publicNetworkSource" => { + "allowedIpCidrRanges" => [] + } + } + delete_ip_filter_gapi = Google::Apis::StorageV1::Bucket::IpFilter.from_json delete_ip_filter_hash.to_json + + mock = Minitest::Mock.new + mock.expect :update_bucket, resp_bucket_gapi(bucket_hash, ip_filter: delete_ip_filter_gapi), + [bucket_name, patch_bucket_gapi(ip_filter: delete_ip_filter_gapi)], **update_bucket_args(options: {retries: 0}) + + bucket.service.mocked_service = mock + + bucket.update do |b| + b.ip_filter = { + mode: "Disabled", + public_network_source: { + allowed_ip_cidr_ranges: [] + } + } + end + + _(bucket.ip_filter).wont_be_nil + _(bucket.ip_filter.mode).must_equal "Disabled" + _(bucket.ip_filter.public_network_source.allowed_ip_cidr_ranges).must_be_empty + + mock.verify + end + + it "clears its ip_filter with nil" do + mock = Minitest::Mock.new + mock.expect :patch_bucket, resp_bucket_gapi(bucket_hash, ip_filter: Google::Apis::StorageV1::Bucket::IpFilter.new), + [bucket_name, patch_bucket_gapi(ip_filter: Google::Apis::StorageV1::Bucket::IpFilter.new)], **patch_bucket_args(options: {retries: 0}) + + bucket.service.mocked_service = mock + + bucket.ip_filter = nil + + mock.verify + end + + def patch_bucket_gapi ip_filter: nil + Google::Apis::StorageV1::Bucket.new( + ip_filter: ip_filter + ) + end + + def resp_bucket_gapi bucket_hash, ip_filter: nil + b = Google::Apis::StorageV1::Bucket.from_json bucket_hash.to_json + b.ip_filter = ip_filter + b + end +end diff --git a/google-cloud-storage/test/google/cloud/storage/project_test.rb b/google-cloud-storage/test/google/cloud/storage/project_test.rb index 05724226ca34..344bd8c88378 100644 --- a/google-cloud-storage/test/google/cloud/storage/project_test.rb +++ b/google-cloud-storage/test/google/cloud/storage/project_test.rb @@ -597,6 +597,38 @@ def creds.is_a? target _(bucket.hierarchical_namespace[:enabled]).must_equal false end + it "creates a bucket with block ip_filter" do + mock = Minitest::Mock.new + created_bucket = create_bucket_gapi bucket_name + ip_filter_hash = { + "mode" => "Disabled", + "publicNetworkSource" => { + "allowedIpCidrRanges" => ["0.0.0.0/0", "::/0"] + } + } + ip_filter_gapi = Google::Apis::StorageV1::Bucket::IpFilter.from_json ip_filter_hash.to_json + created_bucket.ip_filter = ip_filter_gapi + resp_bucket = bucket_with_location created_bucket + + mock.expect :insert_bucket, resp_bucket, [project, created_bucket], predefined_acl: nil, predefined_default_object_acl: nil, user_project: nil, enable_object_retention: nil, options: {} + storage.service.mocked_service = mock + + bucket = storage.create_bucket bucket_name do |b| + b.ip_filter = { + mode: "Disabled", + public_network_source: { + allowed_ip_cidr_ranges: ["0.0.0.0/0", "::/0"] + } + } + end + mock.verify + + _(bucket).must_be_kind_of Google::Cloud::Storage::Bucket + _(bucket.ip_filter).wont_be_nil + _(bucket.ip_filter.mode).must_equal "Disabled" + _(bucket.ip_filter.public_network_source.allowed_ip_cidr_ranges).must_equal ["0.0.0.0/0", "::/0"] + end + it "raises when creating a bucket with a blank name" do bucket_name = "" From e6ccd0c2594c0a28a140474dccfc3ed784e185aa Mon Sep 17 00:00:00 2001 From: Shubhangi Singh Date: Mon, 8 Jun 2026 11:00:21 +0000 Subject: [PATCH 6/6] remove pry --- google-cloud-storage/samples/acceptance/buckets_test.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/google-cloud-storage/samples/acceptance/buckets_test.rb b/google-cloud-storage/samples/acceptance/buckets_test.rb index 7fbaf9995e7e..c2a93c518022 100644 --- a/google-cloud-storage/samples/acceptance/buckets_test.rb +++ b/google-cloud-storage/samples/acceptance/buckets_test.rb @@ -61,7 +61,6 @@ require_relative "../storage_get_autoclass" require_relative "../storage_set_autoclass" require_relative "../storage_move_object" -require 'pry' describe "Buckets Snippets" do let(:storage_client) { Google::Cloud::Storage.new }