Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

samples: changed PAP unspecified to inherited #14141

Merged
merged 5 commits into from Oct 28, 2021

Conversation

bajajneha27
Copy link
Contributor

Thank you for opening a Pull Request! Before submitting your PR, there are a few things you can do to make sure it goes smoothly:

  • Make sure to open an issue as a bug/issue before writing your code! That way we can discuss the change, evaluate designs, and agree on the general idea.
  • Follow the instructions in CONTRIBUTING. Most importantly, ensure the tests and linter pass by running bundle exec rake ci in the gem subdirectory.
  • Update code documentation if necessary.

closes: #14083

@bajajneha27 bajajneha27 requested review from a team as code owners September 29, 2021 09:58
@product-auto-label product-auto-label bot added the samples Issues that are directly related to samples. label Sep 29, 2021
@snippet-bot
Copy link

snippet-bot bot commented Sep 29, 2021

Here is the summary of changes.

You are about to add 1 region tag.

This comment is generated by snippet-bot.
If you find problems with this result, please file an issue at:
https://github.com/googleapis/repo-automation-bots/issues.
To update this comment, add snippet-bot:force-run label or use the checkbox below:

  • Refresh this comment

@google-cla google-cla bot added the cla: yes This human has signed the Contributor License Agreement. label Sep 29, 2021
@quartzmo
Copy link
Member

@bajajneha27 Regarding the current acceptance test failures for this PR, I pulled your branch and ran the acceptance tests locally using the same project. I got 45 errors! Almost all of them are of the following three types:

Cannot insert legacy ACL

  1) Error:
Google::Cloud::Storage::File::storage#test_0027_should copy an existing file, with force_copy_metadata set to true:
Google::Cloud::InvalidArgumentError: invalid: Cannot insert legacy ACL for an object when uniform bucket-level access is enabled. Read more at https://cloud.google.com/storage/docs/uniform-bucket-level-access
    /Users/quartzmo/code/google/codez/google-cloud-ruby/google-cloud-storage/lib/google/cloud/storage/service.rb:764:in `rescue in execute'
    /Users/quartzmo/code/google/codez/google-cloud-ruby/google-cloud-storage/lib/google/cloud/storage/service.rb:761:in `execute'
    /Users/quartzmo/code/google/codez/google-cloud-ruby/google-cloud-storage/lib/google/cloud/storage/service.rb:351:in `insert_file'
    /Users/quartzmo/code/google/codez/google-cloud-ruby/google-cloud-storage/lib/google/cloud/storage/bucket.rb:1516:in `create_file'
    /Users/quartzmo/code/google/codez/google-cloud-ruby/google-cloud-storage/acceptance/storage/file_test.rb:647:in `block (2 levels) in <top (required)>'

FailedPreconditionError: conditionNotMet: Request violates constraint 'constraints/storage.uniformBucketLevelAccess'

  5) Error:
Google::Cloud::Storage::Bucket::uniform_bucket_level_access::storage#test_0014_raises when creating new bucket with public_access_prevention set to unexpected value:
Google::Cloud::FailedPreconditionError: conditionNotMet: Request violates constraint 'constraints/storage.uniformBucketLevelAccess'
    /Users/quartzmo/code/google/codez/google-cloud-ruby/google-cloud-storage/lib/google/cloud/storage/service.rb:764:in `rescue in execute'
    /Users/quartzmo/code/google/codez/google-cloud-ruby/google-cloud-storage/lib/google/cloud/storage/service.rb:761:in `execute'
    /Users/quartzmo/code/google/codez/google-cloud-ruby/google-cloud-storage/lib/google/cloud/storage/service.rb:126:in `patch_bucket'
    /Users/quartzmo/code/google/codez/google-cloud-ruby/google-cloud-storage/lib/google/cloud/storage/bucket.rb:2828:in `patch_gapi!'
    /Users/quartzmo/code/google/codez/google-cloud-ruby/google-cloud-storage/lib/google/cloud/storage/bucket.rb:885:in `uniform_bucket_level_access='
    /Users/quartzmo/code/google/codez/google-cloud-ruby/google-cloud-storage/acceptance/storage/bucket_uniform_bucket_level_access_test.rb:35:in `block (2 levels) in <top (required)>'

Cannot use ACL API to update bucket policy when uniform bucket-level access is enabled.

 16) Error:
Google::Cloud::Storage::Bucket::uniform_bucket_level_access::storage#test_0013_creates new bucket with public_access_prevention enforced then sets public_access_prevention to enforced:
Google::Cloud::InvalidArgumentError: invalid: Cannot use ACL API to update bucket policy when uniform bucket-level access is enabled. Read more at https://cloud.google.com/storage/docs/uniform-bucket-level-access
    /Users/quartzmo/code/google/codez/google-cloud-ruby/google-cloud-storage/lib/google/cloud/storage/service.rb:764:in `rescue in execute'
    /Users/quartzmo/code/google/codez/google-cloud-ruby/google-cloud-storage/lib/google/cloud/storage/service.rb:761:in `execute'
    /Users/quartzmo/code/google/codez/google-cloud-ruby/google-cloud-storage/lib/google/cloud/storage/service.rb:126:in `patch_bucket'
    /Users/quartzmo/code/google/codez/google-cloud-ruby/google-cloud-storage/lib/google/cloud/storage/bucket/acl.rb:441:in `update_predefined_acl!'
    /Users/quartzmo/code/google/codez/google-cloud-ruby/google-cloud-storage/lib/google/cloud/storage/bucket/acl.rb:409:in `public!'
    /Users/quartzmo/code/google/codez/google-cloud-ruby/google-cloud-storage/acceptance/storage/bucket_uniform_bucket_level_access_test.rb:220:in `block (2 levels) in <top (required)>'

@quartzmo
Copy link
Member

I also tried creating a new bucket manually in this project to see if UBLA is enabled by default. It is:

irb(main):002:0> bucket_name = "ublatest321423"
=> "ublatest321423"
irb(main):003:0> bucket = storage.create_bucket(bucket_name)
=> 
#<Google::Cloud::Storage::Bucket:0x00007f90456402a8
...
irb(main):004:0> bucket.uniform_bucket_level_access?
=> true
irb(main):005:0> bucket.gapi.iam_configuration
=> 
#<Google::Apis::StorageV1::Bucket::IamConfiguration:0x00007f904557a288
 @bucket_policy_only=
  #<Google::Apis::StorageV1::Bucket::IamConfiguration::BucketPolicyOnly:0x00007f9045578280 @enabled=true, @locked_time=#<DateTime: 2021-12-28T17:17:12+00:00 ((2459577j,62232s,145000000n),+0s,2299161j)>>,
 @public_access_prevention="inherited",
 @uniform_bucket_level_access=
  #<Google::Apis::StorageV1::Bucket::IamConfiguration::UniformBucketLevelAccess:0x00007f904556b120 @enabled=true, @locked_time=#<DateTime: 2021-12-28T17:17:12+00:00 ((2459577j,62232s,145000000n),+0s,2299161j)>>>

@quartzmo
Copy link
Member

I then tried manually disabling UBLA for my newly-created bucket (this is what causes many of the tests to fail at bucket_uniform_bucket_level_access_test.rb:35):

irb(main):006:0> bucket.uniform_bucket_level_access?
=> true
irb(main):007:0> bucket.uniform_bucket_level_access = false
/Users/quartzmo/code/google/codez/google-cloud-ruby/google-cloud-storage/lib/google/cloud/storage/service.rb:764:in `rescue in execute': conditionNotMet: Request violates constraint 'constraints/storage.uniformBucketLevelAccess' (Google::Cloud::FailedPreconditionError)
	from /Users/quartzmo/code/google/codez/google-cloud-ruby/google-cloud-storage/lib/google/cloud/storage/service.rb:761:in `execute'
	from /Users/quartzmo/code/google/codez/google-cloud-ruby/google-cloud-storage/lib/google/cloud/storage/service.rb:126:in `patch_bucket'
	from /Users/quartzmo/code/google/codez/google-cloud-ruby/google-cloud-storage/lib/google/cloud/storage/bucket.rb:2828:in `patch_gapi!'
	from /Users/quartzmo/code/google/codez/google-cloud-ruby/google-cloud-storage/lib/google/cloud/storage/bucket.rb:885:in `uniform_bucket_level_access='
	from (irb):6:in `<main>'

The docs say:

To support the ability to disable uniform bucket-level access and revert to using ACLs, Cloud Storage saves existing ACLs for 90 days. If you disable uniform bucket-level access during this time: Objects regain their saved ACLs.... [etc]

Therefore I'm wondering why I couldn't manually disable UBLA on a new bucket? Is this a backend bug?

@quartzmo
Copy link
Member

I am guessing that the ACL API errors above are also the result of using a shared bucket fixture that has UBLA enabled. Any tests that manipulate ACLs will now need to use a bucket without UBLA enabled.

@shaffeeullah
Copy link

I am guessing that the ACL API errors above are also the result of using a shared bucket fixture that has UBLA enabled. Any tests that manipulate ACLs will now need to use a bucket without UBLA enabled.

@quartzmo Do you know why that might be a problem now when it wasn't before? This change should be purely a naming change. No behavior should have changed at all.

@quartzmo
Copy link
Member

@shaffeeullah I haven't been involved with this library since some time, but it appears to me that newly-created buckets in the CI project now have UniformBucketLevelAccess enabled by default. See @public_access_prevention="inherited" and UniformBucketLevelAccess:0x00007f904556b120 @enabled=true below.

<Google::Apis::StorageV1::Bucket::IamConfiguration:0x00007f904557a288
 @bucket_policy_only=
  #<Google::Apis::StorageV1::Bucket::IamConfiguration::BucketPolicyOnly:0x00007f9045578280 @enabled=true, @locked_time=#<DateTime: 2021-12-28T17:17:12+00:00 ((2459577j,62232s,145000000n),+0s,2299161j)>>,
 @public_access_prevention="inherited",
 @uniform_bucket_level_access=
  #<Google::Apis::StorageV1::Bucket::IamConfiguration::UniformBucketLevelAccess:0x00007f904556b120 @enabled=true, @locked_time=#<DateTime: 2021-12-28T17:17:12+00:00 ((2459577j,62232s,145000000n),+0s,2299161j)>>>

Is this correct behavior now?

@quartzmo
Copy link
Member

There is a test setup call in bucket_test.rb that ensures that ACLs are reset to private before each test:

before do
    # always reset the bucket permissions
    bucket.acl.private!
  end

This test group uses a shared bucket fixture (search for $bucket_names.first in the acceptance directory) that is set to UniformBucketLevelAccess true in bucket_uniform_bucket_level_access_test.rb. If any tests attempt to modify ACLs after that happens, they encounter the error with the ACL API. I'm not sure how long this has been the case, but based on the current docs for UBLA it makes sense. What doesn't make sense to me is why new buckets in this project have UBLA enabled, and why it can't be disabled in those buckets, given that they are less than 90 days old.

@quartzmo
Copy link
Member

The TL;DR is that the long-time approach of sharing of a single bucket fixture among many tests is now problematic unless UBLA can be repeatedly enabled and disabled to support using the same bucket in both ACL and UBLA tests.

@bajajneha27
Copy link
Contributor Author

I tried running the acceptance test on my local and I'm facing different errors altogether:

1) Error:
Google::Cloud::Storage::Bucket::post_object::v2::storage#test_0002_generates a signed post object using signBlob API:
Google::Apis::ClientError: Invalid request
    /Users/bajajnehaa/.rvm/gems/ruby-2.7.4/gems/google-apis-core-0.4.1/lib/google/apis/core/http_command.rb:228:in `check_status'
    /Users/bajajnehaa/.rvm/gems/ruby-2.7.4/gems/google-apis-core-0.4.1/lib/google/apis/core/api_command.rb:134:in `check_status'
    /Users/bajajnehaa/.rvm/gems/ruby-2.7.4/gems/google-apis-core-0.4.1/lib/google/apis/core/http_command.rb:194:in `process_response'
    /Users/bajajnehaa/.rvm/gems/ruby-2.7.4/gems/google-apis-core-0.4.1/lib/google/apis/core/http_command.rb:310:in `execute_once'
    /Users/bajajnehaa/.rvm/gems/ruby-2.7.4/gems/google-apis-core-0.4.1/lib/google/apis/core/http_command.rb:113:in `block (2 levels) in execute'
    /Users/bajajnehaa/.rvm/gems/ruby-2.7.4/gems/retriable-3.1.2/lib/retriable.rb:61:in `block in retriable'
    /Users/bajajnehaa/.rvm/gems/ruby-2.7.4/gems/retriable-3.1.2/lib/retriable.rb:56:in `times'
    /Users/bajajnehaa/.rvm/gems/ruby-2.7.4/gems/retriable-3.1.2/lib/retriable.rb:56:in `retriable'
    /Users/bajajnehaa/.rvm/gems/ruby-2.7.4/gems/google-apis-core-0.4.1/lib/google/apis/core/http_command.rb:110:in `block in execute'
    /Users/bajajnehaa/.rvm/gems/ruby-2.7.4/gems/retriable-3.1.2/lib/retriable.rb:61:in `block in retriable'
    /Users/bajajnehaa/.rvm/gems/ruby-2.7.4/gems/retriable-3.1.2/lib/retriable.rb:56:in `times'
    /Users/bajajnehaa/.rvm/gems/ruby-2.7.4/gems/retriable-3.1.2/lib/retriable.rb:56:in `retriable'
    /Users/bajajnehaa/.rvm/gems/ruby-2.7.4/gems/google-apis-core-0.4.1/lib/google/apis/core/http_command.rb:102:in `execute'
    /Users/bajajnehaa/.rvm/gems/ruby-2.7.4/gems/google-apis-core-0.4.1/lib/google/apis/core/base_service.rb:377:in `execute_or_queue_command'
    /Users/bajajnehaa/.rvm/gems/ruby-2.7.4/gems/google-apis-iamcredentials_v1-0.7.0/lib/google/apis/iamcredentials_v1/service.rb:158:in `sign_service_account_blob'
    /Users/bajajnehaa/gcp/google-cloud-ruby/google-cloud-storage/acceptance/storage/bucket_post_object_v2_test.rb:79:in `block (3 levels) in <top (required)>'
    /Users/bajajnehaa/gcp/google-cloud-ruby/google-cloud-storage/lib/google/cloud/storage/file/signer_v2.rb:135:in `generate_signature'
    /Users/bajajnehaa/gcp/google-cloud-ruby/google-cloud-storage/lib/google/cloud/storage/file/signer_v2.rb:113:in `post_object'
    /Users/bajajnehaa/gcp/google-cloud-ruby/google-cloud-storage/lib/google/cloud/storage/bucket.rb:2079:in `post_object'
    /Users/bajajnehaa/gcp/google-cloud-ruby/google-cloud-storage/acceptance/storage/bucket_post_object_v2_test.rb:83:in `block (2 levels) in <top (required)>'
4) Error:
Google::Cloud::Storage::Bucket::encryption::storage::KMS customer-managed encryption key (CMEK)#test_0001_knows its encryption configuration:
Google::Cloud::AlreadyExistsError: conflict: You already own this bucket. Please select another name.
    /Users/bajajnehaa/gcp/google-cloud-ruby/google-cloud-storage/lib/google/cloud/storage/service.rb:764:in `rescue in execute'
    /Users/bajajnehaa/gcp/google-cloud-ruby/google-cloud-storage/lib/google/cloud/storage/service.rb:761:in `execute'
    /Users/bajajnehaa/gcp/google-cloud-ruby/google-cloud-storage/lib/google/cloud/storage/service.rb:104:in `insert_bucket'
    /Users/bajajnehaa/gcp/google-cloud-ruby/google-cloud-storage/lib/google/cloud/storage/project.rb:391:in `create_bucket'
    /Users/bajajnehaa/gcp/google-cloud-ruby/google-cloud-storage/acceptance/storage/bucket_encryption_test.rb:29:in `block (3 levels) in <top (required)>'
    /Users/bajajnehaa/gcp/google-cloud-ruby/google-cloud-storage/acceptance/storage_helper.rb:112:in `block in safe_gcs_execute'
    /Users/bajajnehaa/gcp/google-cloud-ruby/google-cloud-storage/acceptance/storage_helper.rb:110:in `loop'
    /Users/bajajnehaa/gcp/google-cloud-ruby/google-cloud-storage/acceptance/storage_helper.rb:110:in `safe_gcs_execute'
    /Users/bajajnehaa/gcp/google-cloud-ruby/google-cloud-storage/acceptance/storage/bucket_encryption_test.rb:29:in `block (2 levels) in <top (required)>'

Multiple failures with these error messages.

@quartzmo
Copy link
Member

@bajajneha27 I also see about 16 similar errors when I run acceptance tests using my personal dev project, both against your branch and against master. I think they are unrelated to this PR.

However, when running using my personal dev project against your branch, I also see these errors. They are related to this PR:

 17) Failure:
Google::Cloud::Storage::Bucket::uniform_bucket_level_access::storage#test_0013_creates new bucket with public_access_prevention enforced then sets public_access_prevention to enforced [/Users/quartzmo/code/google/codez/google-cloud-ruby/google-cloud-storage/acceptance/storage/bucket_uniform_bucket_level_access_test.rb:218]:
Expected false to be truthy.

 18) Failure:
Google::Cloud::Storage::Bucket::uniform_bucket_level_access::storage#test_0015_sets public_access_prevention to enforced [/Users/quartzmo/code/google/codez/google-cloud-ruby/google-cloud-storage/acceptance/storage/bucket_uniform_bucket_level_access_test.rb:238]:
Expected: "inherited"
  Actual: "unspecified"

@bajajneha27
Copy link
Contributor Author

@quartzmo Yes. I think those errors are popping up because the project is not whitelisted for this change.
@shaffeeullah Can you please whitelist the project helical-zone-771 ?

@shaffeeullah shaffeeullah added the kokoro:force-run Add this label to force Kokoro to re-run the tests. label Oct 1, 2021
@yoshi-kokoro yoshi-kokoro removed the kokoro:force-run Add this label to force Kokoro to re-run the tests. label Oct 1, 2021
@shaffeeullah
Copy link

@quartzmo Yes. I think those errors are popping up because the project is not whitelisted for this change. @shaffeeullah Can you please whitelist the project helical-zone-771 ?

@bajajneha27 this project is already on the whitelist. I'm not sure what is causing these failures based on the PR changes.

@quartzmo
Copy link
Member

quartzmo commented Oct 1, 2021

this project is already on the whitelist. I'm not sure what is causing these failures based on the PR changes.

it appears to me that newly-created buckets in the CI project now have UniformBucketLevelAccess enabled by default. See @public_access_prevention="inherited" and UniformBucketLevelAccess:0x00007f904556b120 @enabled=true in my comment above. Is this correct behavior for the feature (on the allowlist)?

@quartzmo quartzmo added the api: storage Issues related to the Cloud Storage API. label Oct 4, 2021
@tritone
Copy link

tritone commented Oct 5, 2021

this project is already on the whitelist. I'm not sure what is causing these failures based on the PR changes.

it appears to me that newly-created buckets in the CI project now have UniformBucketLevelAccess enabled by default. See @public_access_prevention="inherited" and UniformBucketLevelAccess:0x00007f904556b120 @enabled=true in my comment above. Is this correct behavior for the feature (on the allowlist)?

@quartzmo I believe this may be due to internal google restrictions on testing projects. I had to apply for an exemption on my own GCS testing project and make sure it was in the correct folder that has exemptions from these restrictions so that features such as UBLA were not enabled by default.

@bajajneha27 can we follow up offline to fix the project permissions? Also, there may be additional issues with your personal project that we can help with.

@quartzmo
Copy link
Member

quartzmo commented Oct 5, 2021

@tritone Thanks for the background info regarding the testing projects. In order to get this PR to a state in which it can be approved, our Ruby CI project will need to reflect exactly the same backend behavior that will be public when the PR is merged and released. Once we're certain of that in the CI environment, I can advise @bajajneha27 about any changes needed to the tests. (Because of the use of shared buckets in the system tests, they are fairly brittle.)

@dazuma
Copy link
Member

dazuma commented Oct 21, 2021

Okay, good news: we got the policy change approved and enacted. It should now be possible to disable UBLA for helical-zone-771's buckets.

@bajajneha27 bajajneha27 added the kokoro:force-run Add this label to force Kokoro to re-run the tests. label Oct 23, 2021
@yoshi-kokoro yoshi-kokoro removed the kokoro:force-run Add this label to force Kokoro to re-run the tests. label Oct 23, 2021
@bajajneha27
Copy link
Contributor Author

Okay, good news: we got the policy change approved and enacted. It should now be possible to disable UBLA for helical-zone-771's buckets.

All tests have now passed. :) Can we merge the PR now?

#
def public_access_prevention_unspecified?
def public_access_prevention_inherited?
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of making this breaking change, I would recommend adding a new method #public_access_prevention_inherited?, and deprecating #public_access_prevention_unspecified?.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I made an alias of this method at #1035

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, sorry, I missed that. If inherited and unspecified have the same meaning, then the alias is OK.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using an alias still changes the behavior of #public_access_prevention_unspecified? which is a breaking change. I think we should keep the original method but deprecate it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree, best to deprecate with a reference to the new method.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, now that I think about it some more, the right thing to do kind of depends on the behavior of the backend.

(1) If the values are being changed transparently by the backend, i.e. anything that used to be returned as "unspecified" are now magically returned as "inherited" by the backend, then yes, we should keep the alias in order to preserve the semantics of the call. (But in this case we might also need to update the setter so that if the user passes in :unspecified, we turn it into :inherited before we send it, in case the backend doesn't map that for us.)
(2) If the values are not being changed transparently, i.e. we are expecting the user to shift their usage, then we should keep the existing method but deprecate it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think point 1 stands correct here but @shaffeeullah can confirm.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@shaffeeullah @tritone Can either of you shed any light on this? Specifically:

  1. After this change launches in the backend, If an existing bucket already had PAP set to unspecified prior to the change, does the backend still return the value unspecified or does it map the value to inherited and return that?
  2. After this change launches in the backend, if a user explicitly sets the value to unspecified, will the backend automatically interpret it as inherited or are we depending on users to alter their usage in order to get the desired functionality?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. Currently, yes, if it was set to unspecified, it will return unspecified. In the future, unspecified will be deprecated and everything that was unspecified will be returning inherited instead.
  2. The backend will accept both unspecified and inherited. Eventually, setting unspecified will return inherited. This is not the case yet.

Another note, for allowlisted projects, the default value is currently inherited. This will roll out to be the behavior for all projects early November. This changes the default from the previous unspecified. For all projects (regardless of allowlist), setting inherited will work as intended (even if it isn't the default).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @shaffeeullah! Given this info, I think what we should do is:

  • #public_access_prevention_inherited? should return true for either value (inherited or unspecified).
  • #public_access_prevention_unspecified? should alias #public_access_prevention_inherited?, so it also returns true for either value.
  • The setter should remain as-is.

@bajajneha27
Copy link
Contributor Author

@shaffeeullah @tritone Does this look good to you? Shall we go ahead and merge this PR ?

Copy link

@tritone tritone left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, please merge when you're ready

@bajajneha27 bajajneha27 merged commit 87710b8 into googleapis:main Oct 28, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
api: storage Issues related to the Cloud Storage API. cla: yes This human has signed the Contributor License Agreement. samples Issues that are directly related to samples.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Change Public Access Prevention "unspecified" to "inherited"
6 participants