From 9adc9b29d41e2200e1c7016ca6036f9f1ae4528c Mon Sep 17 00:00:00 2001 From: Gabe Pearhill <86282859+pearigee@users.noreply.github.com> Date: Mon, 20 Apr 2026 16:14:32 -0700 Subject: [PATCH 1/8] chore: merge main into regional-access-boundaries to pick up new codeowners (#8085) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore: [Many APIs] migrate generator to google-cloud-node (#7992) * chore: migrate generator to google-cloud-node chore: update generator system tests PiperOrigin-RevId: 896174961 Source-Link: https://github.com/googleapis/googleapis/commit/2233f63baf69c2a481f30180045fcf036242781d Source-Link: https://github.com/googleapis/googleapis-gen/commit/c4a8c4eef959aa744fb1c6714875fa295e06aad3 Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLXNob3BwaW5nLW1lcmNoYW50LWFjY291bnRzLy5Pd2xCb3QueWFtbCIsImgiOiJjNGE4YzRlZWY5NTlhYTc0NGZiMWM2NzE0ODc1ZmEyOTVlMDZhYWQzIn0= Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLXNob3BwaW5nLW1lcmNoYW50LWNvbnZlcnNpb25zLy5Pd2xCb3QueWFtbCIsImgiOiJjNGE4YzRlZWY5NTlhYTc0NGZiMWM2NzE0ODc1ZmEyOTVlMDZhYWQzIn0= Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLXNob3BwaW5nLW1lcmNoYW50LWRhdGFzb3VyY2VzLy5Pd2xCb3QueWFtbCIsImgiOiJjNGE4YzRlZWY5NTlhYTc0NGZiMWM2NzE0ODc1ZmEyOTVlMDZhYWQzIn0= Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLXNob3BwaW5nLW1lcmNoYW50LWludmVudG9yaWVzLy5Pd2xCb3QueWFtbCIsImgiOiJjNGE4YzRlZWY5NTlhYTc0NGZiMWM2NzE0ODc1ZmEyOTVlMDZhYWQzIn0= Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLXNob3BwaW5nLW1lcmNoYW50LWlzc3VlcmVzb2x1dGlvbi8uT3dsQm90LnlhbWwiLCJoIjoiYzRhOGM0ZWVmOTU5YWE3NDRmYjFjNjcxNDg3NWZhMjk1ZTA2YWFkMyJ9 Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLXNob3BwaW5nLW1lcmNoYW50LWxmcC8uT3dsQm90LnlhbWwiLCJoIjoiYzRhOGM0ZWVmOTU5YWE3NDRmYjFjNjcxNDg3NWZhMjk1ZTA2YWFkMyJ9 Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLXNob3BwaW5nLW1lcmNoYW50LW5vdGlmaWNhdGlvbnMvLk93bEJvdC55YW1sIiwiaCI6ImM0YThjNGVlZjk1OWFhNzQ0ZmIxYzY3MTQ4NzVmYTI5NWUwNmFhZDMifQ== Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLXNob3BwaW5nLW1lcmNoYW50LW9yZGVydHJhY2tpbmcvLk93bEJvdC55YW1sIiwiaCI6ImM0YThjNGVlZjk1OWFhNzQ0ZmIxYzY3MTQ4NzVmYTI5NWUwNmFhZDMifQ== Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLXNob3BwaW5nLW1lcmNoYW50LXByb2R1Y3RzLy5Pd2xCb3QueWFtbCIsImgiOiJjNGE4YzRlZWY5NTlhYTc0NGZiMWM2NzE0ODc1ZmEyOTVlMDZhYWQzIn0= Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLXNob3BwaW5nLW1lcmNoYW50LXByb21vdGlvbnMvLk93bEJvdC55YW1sIiwiaCI6ImM0YThjNGVlZjk1OWFhNzQ0ZmIxYzY3MTQ4NzVmYTI5NWUwNmFhZDMifQ== Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLXNob3BwaW5nLW1lcmNoYW50LXF1b3RhLy5Pd2xCb3QueWFtbCIsImgiOiJjNGE4YzRlZWY5NTlhYTc0NGZiMWM2NzE0ODc1ZmEyOTVlMDZhYWQzIn0= Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLXNob3BwaW5nLW1lcmNoYW50LXJlcG9ydHMvLk93bEJvdC55YW1sIiwiaCI6ImM0YThjNGVlZjk1OWFhNzQ0ZmIxYzY3MTQ4NzVmYTI5NWUwNmFhZDMifQ== Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLXNob3BwaW5nLW1lcmNoYW50LXJldmlld3MvLk93bEJvdC55YW1sIiwiaCI6ImM0YThjNGVlZjk1OWFhNzQ0ZmIxYzY3MTQ4NzVmYTI5NWUwNmFhZDMifQ== Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLXN0b3JhZ2V0cmFuc2Zlci8uT3dsQm90LnlhbWwiLCJoIjoiYzRhOGM0ZWVmOTU5YWE3NDRmYjFjNjcxNDg3NWZhMjk1ZTA2YWFkMyJ9 Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLXN0cmVldHZpZXctcHVibGlzaC8uT3dsQm90LnlhbWwiLCJoIjoiYzRhOGM0ZWVmOTU5YWE3NDRmYjFjNjcxNDg3NWZhMjk1ZTA2YWFkMyJ9 * 🦉 Updates from OwlBot post-processor See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md --------- Co-authored-by: Owl Bot Co-authored-by: Shivanee <46910562+shivanee-p@users.noreply.github.com> Co-authored-by: Gabe Pearhill <86282859+pearigee@users.noreply.github.com> * feat: [bigquery-reservation] add principal field to BigQuery Reservation Assignment (#8042) * feat: add principal field to BigQuery Reservation Assignment docs: update the scaling mode documentation to correct an example math error PiperOrigin-RevId: 899158032 Source-Link: https://github.com/googleapis/googleapis/commit/a5bd611f6a805c60fe69e1f656a0a870e7699ba7 Source-Link: https://github.com/googleapis/googleapis-gen/commit/2bef3dbc678dae5a81806a74b7cd65043600cbe0 Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLWJpZ3F1ZXJ5LXJlc2VydmF0aW9uLy5Pd2xCb3QueWFtbCIsImgiOiIyYmVmM2RiYzY3OGRhZTVhODE4MDZhNzRiN2NkNjUwNDM2MDBjYmUwIn0= * 🦉 Updates from OwlBot post-processor See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md --------- Co-authored-by: Owl Bot * feat: [vectorsearch] Added CMEK support (#8033) * feat: Added CMEK support feat: Added UpdateIndex support docs: Updated documentation for listing locations docs: Updated documentation for Collection.data_schema PiperOrigin-RevId: 898465628 Source-Link: https://github.com/googleapis/googleapis/commit/8d0f6d8615c72d1907aeec8984d68df50fb6b697 Source-Link: https://github.com/googleapis/googleapis-gen/commit/1965238533cfce3b99d41388e9e19dd22c3490e0 Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLXZlY3RvcnNlYXJjaC8uT3dsQm90LnlhbWwiLCJoIjoiMTk2NTIzODUzM2NmY2UzYjk5ZDQxMzg4ZTllMTlkZDIyYzM0OTBlMCJ9 * 🦉 Updates from OwlBot post-processor See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md * feat: Added CMEK support feat: Added UpdateIndex support docs: Updated documentation for listing locations docs: Updated documentation for Collection.data_schema PiperOrigin-RevId: 898990233 Source-Link: https://github.com/googleapis/googleapis/commit/38ed7d6ba66a774924722146f054d12b4487a89f Source-Link: https://github.com/googleapis/googleapis-gen/commit/492368cb31a0777737f1943042c3b860abff7ba1 Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLXZlY3RvcnNlYXJjaC8uT3dsQm90LnlhbWwiLCJoIjoiNDkyMzY4Y2IzMWEwNzc3NzM3ZjE5NDMwNDJjM2I4NjBhYmZmN2JhMSJ9 * 🦉 Updates from OwlBot post-processor See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md --------- Co-authored-by: Owl Bot * chore: [Many APIs] migrate generator to google-cloud-node (#7988) * chore: migrate generator to google-cloud-node chore: update generator system tests PiperOrigin-RevId: 896174961 Source-Link: https://github.com/googleapis/googleapis/commit/2233f63baf69c2a481f30180045fcf036242781d Source-Link: https://github.com/googleapis/googleapis-gen/commit/c4a8c4eef959aa744fb1c6714875fa295e06aad3 Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLW5ldHdvcmttYW5hZ2VtZW50Ly5Pd2xCb3QueWFtbCIsImgiOiJjNGE4YzRlZWY5NTlhYTc0NGZiMWM2NzE0ODc1ZmEyOTVlMDZhYWQzIn0= Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLW5ldHdvcmtzZWN1cml0eS8uT3dsQm90LnlhbWwiLCJoIjoiYzRhOGM0ZWVmOTU5YWE3NDRmYjFjNjcxNDg3NWZhMjk1ZTA2YWFkMyJ9 Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLW5ldHdvcmtzZXJ2aWNlcy8uT3dsQm90LnlhbWwiLCJoIjoiYzRhOGM0ZWVmOTU5YWE3NDRmYjFjNjcxNDg3NWZhMjk1ZTA2YWFkMyJ9 Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLW5vdGVib29rcy8uT3dsQm90LnlhbWwiLCJoIjoiYzRhOGM0ZWVmOTU5YWE3NDRmYjFjNjcxNDg3NWZhMjk1ZTA2YWFkMyJ9 Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLW9yYWNsZWRhdGFiYXNlLy5Pd2xCb3QueWFtbCIsImgiOiJjNGE4YzRlZWY5NTlhYTc0NGZiMWM2NzE0ODc1ZmEyOTVlMDZhYWQzIn0= Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLW9yY2hlc3RyYXRpb24tYWlyZmxvdy1zZXJ2aWNlLy5Pd2xCb3QueWFtbCIsImgiOiJjNGE4YzRlZWY5NTlhYTc0NGZiMWM2NzE0ODc1ZmEyOTVlMDZhYWQzIn0= Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLW9yZ3BvbGljeS8uT3dsQm90LnlhbWwiLCJoIjoiYzRhOGM0ZWVmOTU5YWE3NDRmYjFjNjcxNDg3NWZhMjk1ZTA2YWFkMyJ9 Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLW9zY29uZmlnLy5Pd2xCb3QueWFtbCIsImgiOiJjNGE4YzRlZWY5NTlhYTc0NGZiMWM2NzE0ODc1ZmEyOTVlMDZhYWQzIn0= Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLW9zbG9naW4vLk93bEJvdC55YW1sIiwiaCI6ImM0YThjNGVlZjk1OWFhNzQ0ZmIxYzY3MTQ4NzVmYTI5NWUwNmFhZDMifQ== Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLXBhcmFsbGVsc3RvcmUvLk93bEJvdC55YW1sIiwiaCI6ImM0YThjNGVlZjk1OWFhNzQ0ZmIxYzY3MTQ4NzVmYTI5NWUwNmFhZDMifQ== Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLXBhcmFtZXRlcm1hbmFnZXIvLk93bEJvdC55YW1sIiwiaCI6ImM0YThjNGVlZjk1OWFhNzQ0ZmIxYzY3MTQ4NzVmYTI5NWUwNmFhZDMifQ== Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLXBoaXNoaW5ncHJvdGVjdGlvbi8uT3dsQm90LnlhbWwiLCJoIjoiYzRhOGM0ZWVmOTU5YWE3NDRmYjFjNjcxNDg3NWZhMjk1ZTA2YWFkMyJ9 Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLXBvbGljeXNpbXVsYXRvci8uT3dsQm90LnlhbWwiLCJoIjoiYzRhOGM0ZWVmOTU5YWE3NDRmYjFjNjcxNDg3NWZhMjk1ZTA2YWFkMyJ9 Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLXBvbGljeXRyb3VibGVzaG9vdGVyLy5Pd2xCb3QueWFtbCIsImgiOiJjNGE4YzRlZWY5NTlhYTc0NGZiMWM2NzE0ODc1ZmEyOTVlMDZhYWQzIn0= Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLXByaXZhdGVjYXRhbG9nLy5Pd2xCb3QueWFtbCIsImgiOiJjNGE4YzRlZWY5NTlhYTc0NGZiMWM2NzE0ODc1ZmEyOTVlMDZhYWQzIn0= Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLXByaXZpbGVnZWRhY2Nlc3NtYW5hZ2VyLy5Pd2xCb3QueWFtbCIsImgiOiJjNGE4YzRlZWY5NTlhYTc0NGZiMWM2NzE0ODc1ZmEyOTVlMDZhYWQzIn0= Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLXJhcGlkbWlncmF0aW9uYXNzZXNzbWVudC8uT3dsQm90LnlhbWwiLCJoIjoiYzRhOGM0ZWVmOTU5YWE3NDRmYjFjNjcxNDg3NWZhMjk1ZTA2YWFkMyJ9 Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLXJlY2FwdGNoYWVudGVycHJpc2UvLk93bEJvdC55YW1sIiwiaCI6ImM0YThjNGVlZjk1OWFhNzQ0ZmIxYzY3MTQ4NzVmYTI5NWUwNmFhZDMifQ== Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLXJlY29tbWVuZGVyLy5Pd2xCb3QueWFtbCIsImgiOiJjNGE4YzRlZWY5NTlhYTc0NGZiMWM2NzE0ODc1ZmEyOTVlMDZhYWQzIn0= Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLXJlZGlzLy5Pd2xCb3QueWFtbCIsImgiOiJjNGE4YzRlZWY5NTlhYTc0NGZiMWM2NzE0ODc1ZmEyOTVlMDZhYWQzIn0= * 🦉 Updates from OwlBot post-processor See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md --------- Co-authored-by: Owl Bot Co-authored-by: Shivanee <46910562+shivanee-p@users.noreply.github.com> * chore: release main (#8005) Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com> * feat: [chronicle] Add DataTableService to Chronicle v1 Client Libraries (#8035) * feat: Add DataTableService to Chronicle v1 Client Libraries PiperOrigin-RevId: 898791366 Source-Link: https://github.com/googleapis/googleapis/commit/e182cf5152967047b763fd88f03094cfc836d194 Source-Link: https://github.com/googleapis/googleapis-gen/commit/dab413d43bd475386b375d7dca3169cb063dcd8d Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLWNocm9uaWNsZS8uT3dsQm90LnlhbWwiLCJoIjoiZGFiNDEzZDQzYmQ0NzUzODZiMzc1ZDdkY2EzMTY5Y2IwNjNkY2Q4ZCJ9 * 🦉 Updates from OwlBot post-processor See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md --------- Co-authored-by: Owl Bot Co-authored-by: Gabe Pearhill <86282859+pearigee@users.noreply.github.com> * feat: [discoveryengine] add AUTO condition to SearchAsYouTypeSpec in v1alpha and v1beta (#8032) * feat: add AUTO condition to SearchAsYouTypeSpec in v1alpha and v1beta PiperOrigin-RevId: 897859462 Source-Link: https://github.com/googleapis/googleapis/commit/f01ba6bda9ef3a45069a699767ee7dc46f30028a Source-Link: https://github.com/googleapis/googleapis-gen/commit/f16c389d46864cbcad8ee29b47a79921894e6244 Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLWRpc2NvdmVyeWVuZ2luZS8uT3dsQm90LnlhbWwiLCJoIjoiZjE2YzM4OWQ0Njg2NGNiY2FkOGVlMjliNDdhNzk5MjE4OTRlNjI0NCJ9 * 🦉 Updates from OwlBot post-processor See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md --------- Co-authored-by: Owl Bot * feat: [merchantapi] a new field `base64_encoded_name` is added to the `Product` message (#7997) * feat: a new field `base64_encoded_name` is added to the `Product` message feat: new fields - `base64_encoded_name` and `base64_encoded_product` added to the `ProductInput` message docs: A comment for field `name` in message `.google.shopping.merchant.products.v1.ProductInput` is changed docs: A comment for field `name` in message `.google.shopping.merchant.products.v1.Product` is changed PiperOrigin-RevId: 896968813 Source-Link: https://github.com/googleapis/googleapis/commit/2aba48492ae471bfb717f5e9c5a190b7cc1c6636 Source-Link: https://github.com/googleapis/googleapis-gen/commit/820077f8f9d7dde0da2c071972068ee9c57421a8 Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLXNob3BwaW5nLW1lcmNoYW50LXByb2R1Y3RzLy5Pd2xCb3QueWFtbCIsImgiOiI4MjAwNzdmOGY5ZDdkZGUwZGEyYzA3MTk3MjA2OGVlOWM1NzQyMWE4In0= * 🦉 Updates from OwlBot post-processor See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md --------- Co-authored-by: Owl Bot Co-authored-by: Gabe Pearhill <86282859+pearigee@users.noreply.github.com> * chore: [Many APIs] migrate generator to google-cloud-node (#7989) * chore: migrate generator to google-cloud-node chore: update generator system tests PiperOrigin-RevId: 896174961 Source-Link: https://github.com/googleapis/googleapis/commit/2233f63baf69c2a481f30180045fcf036242781d Source-Link: https://github.com/googleapis/googleapis-gen/commit/c4a8c4eef959aa744fb1c6714875fa295e06aad3 Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLXJlc291cmNlbWFuYWdlci8uT3dsQm90LnlhbWwiLCJoIjoiYzRhOGM0ZWVmOTU5YWE3NDRmYjFjNjcxNDg3NWZhMjk1ZTA2YWFkMyJ9 Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLXJldGFpbC8uT3dsQm90LnlhbWwiLCJoIjoiYzRhOGM0ZWVmOTU5YWE3NDRmYjFjNjcxNDg3NWZhMjk1ZTA2YWFkMyJ9 Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLXJ1bi8uT3dsQm90LnlhbWwiLCJoIjoiYzRhOGM0ZWVmOTU5YWE3NDRmYjFjNjcxNDg3NWZhMjk1ZTA2YWFkMyJ9 Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLXNhYXNwbGF0Zm9ybS1zYWFzc2VydmljZW1nbXQvLk93bEJvdC55YW1sIiwiaCI6ImM0YThjNGVlZjk1OWFhNzQ0ZmIxYzY3MTQ4NzVmYTI5NWUwNmFhZDMifQ== Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLXNjaGVkdWxlci8uT3dsQm90LnlhbWwiLCJoIjoiYzRhOGM0ZWVmOTU5YWE3NDRmYjFjNjcxNDg3NWZhMjk1ZTA2YWFkMyJ9 Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLXNlY3JldG1hbmFnZXIvLk93bEJvdC55YW1sIiwiaCI6ImM0YThjNGVlZjk1OWFhNzQ0ZmIxYzY3MTQ4NzVmYTI5NWUwNmFhZDMifQ== Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLXNlY3VyZXNvdXJjZW1hbmFnZXIvLk93bEJvdC55YW1sIiwiaCI6ImM0YThjNGVlZjk1OWFhNzQ0ZmIxYzY3MTQ4NzVmYTI5NWUwNmFhZDMifQ== Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLXNlY3VyaXR5LXByaXZhdGVjYS8uT3dsQm90LnlhbWwiLCJoIjoiYzRhOGM0ZWVmOTU5YWE3NDRmYjFjNjcxNDg3NWZhMjk1ZTA2YWFkMyJ9 Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLXNlY3VyaXR5LXB1YmxpY2NhLy5Pd2xCb3QueWFtbCIsImgiOiJjNGE4YzRlZWY5NTlhYTc0NGZiMWM2NzE0ODc1ZmEyOTVlMDZhYWQzIn0= Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLXNlY3VyaXR5Y2VudGVyLy5Pd2xCb3QueWFtbCIsImgiOiJjNGE4YzRlZWY5NTlhYTc0NGZiMWM2NzE0ODc1ZmEyOTVlMDZhYWQzIn0= Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLXNlY3VyaXR5Y2VudGVybWFuYWdlbWVudC8uT3dsQm90LnlhbWwiLCJoIjoiYzRhOGM0ZWVmOTU5YWE3NDRmYjFjNjcxNDg3NWZhMjk1ZTA2YWFkMyJ9 Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLXNlcnZpY2VkaXJlY3RvcnkvLk93bEJvdC55YW1sIiwiaCI6ImM0YThjNGVlZjk1OWFhNzQ0ZmIxYzY3MTQ4NzVmYTI5NWUwNmFhZDMifQ== Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLXNlcnZpY2VoZWFsdGgvLk93bEJvdC55YW1sIiwiaCI6ImM0YThjNGVlZjk1OWFhNzQ0ZmIxYzY3MTQ4NzVmYTI5NWUwNmFhZDMifQ== Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLXNoZWxsLy5Pd2xCb3QueWFtbCIsImgiOiJjNGE4YzRlZWY5NTlhYTc0NGZiMWM2NzE0ODc1ZmEyOTVlMDZhYWQzIn0= Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLXNwZWVjaC8uT3dsQm90LnlhbWwiLCJoIjoiYzRhOGM0ZWVmOTU5YWE3NDRmYjFjNjcxNDg3NWZhMjk1ZTA2YWFkMyJ9 Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLXNxbC8uT3dsQm90LnlhbWwiLCJoIjoiYzRhOGM0ZWVmOTU5YWE3NDRmYjFjNjcxNDg3NWZhMjk1ZTA2YWFkMyJ9 Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLXN0b3JhZ2ViYXRjaG9wZXJhdGlvbnMvLk93bEJvdC55YW1sIiwiaCI6ImM0YThjNGVlZjk1OWFhNzQ0ZmIxYzY3MTQ4NzVmYTI5NWUwNmFhZDMifQ== Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLXN0b3JhZ2VpbnNpZ2h0cy8uT3dsQm90LnlhbWwiLCJoIjoiYzRhOGM0ZWVmOTU5YWE3NDRmYjFjNjcxNDg3NWZhMjk1ZTA2YWFkMyJ9 Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLXN1cHBvcnQvLk93bEJvdC55YW1sIiwiaCI6ImM0YThjNGVlZjk1OWFhNzQ0ZmIxYzY3MTQ4NzVmYTI5NWUwNmFhZDMifQ== Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLXRhbGVudC8uT3dsQm90LnlhbWwiLCJoIjoiYzRhOGM0ZWVmOTU5YWE3NDRmYjFjNjcxNDg3NWZhMjk1ZTA2YWFkMyJ9 * 🦉 Updates from OwlBot post-processor See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md --------- Co-authored-by: Owl Bot Co-authored-by: Shivanee <46910562+shivanee-p@users.noreply.github.com> * feat: [kms] support external-μ in the Digest (#8014) * feat: add a variable to SingleTenantHsmInstanceCreate to control whether future key portability features will be usable on the instance PiperOrigin-RevId: 897676455 Source-Link: https://github.com/googleapis/googleapis/commit/bc600b8b72913d10eaf1793a0845643fda94e4eb Source-Link: https://github.com/googleapis/googleapis-gen/commit/85de36821652045b39e5279a42bbb32fa27dab81 Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLWttcy8uT3dsQm90LnlhbWwiLCJoIjoiODVkZTM2ODIxNjUyMDQ1YjM5ZTUyNzlhNDJiYmIzMmZhMjdkYWI4MSJ9 * 🦉 Updates from OwlBot post-processor See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md * feat: support external-μ in the Digest PiperOrigin-RevId: 897686352 Source-Link: https://github.com/googleapis/googleapis/commit/7fbf256c9ee4e580bc2ffa825d8d41263d9462d3 Source-Link: https://github.com/googleapis/googleapis-gen/commit/333010db6f4001914b013ae569b3419eb77fd1e1 Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLWttcy8uT3dsQm90LnlhbWwiLCJoIjoiMzMzMDEwZGI2ZjQwMDE5MTRiMDEzYWU1NjliMzQxOWViNzdmZDFlMSJ9 * 🦉 Updates from OwlBot post-processor See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md --------- Co-authored-by: Owl Bot Co-authored-by: Gabe Pearhill <86282859+pearigee@users.noreply.github.com> * chore(main): release bigquery 8.3.0 (#7900) :robot: I have created a release *beep* *boop* --- ## [8.3.0](https://togithub.com/googleapis/google-cloud-node/compare/bigquery-v8.2.0...bigquery-v8.3.0) (2026-04-09) ### Features * **bigquery:** Allow the user to ask for skipping parsing rows when querying ([#7848](https://togithub.com/googleapis/google-cloud-node/issues/7848)) ([e500d40](https://togithub.com/googleapis/google-cloud-node/commit/e500d4077065529fbdee4be565434a34b6643c09)) ### Bug Fixes * Unblock the releases on Node Bigquery ([#7946](https://togithub.com/googleapis/google-cloud-node/issues/7946)) ([7fad2f6](https://togithub.com/googleapis/google-cloud-node/commit/7fad2f6e2ef0b16ab87a92ae471136fe6f2655ef)) --- This PR was generated with [Release Please](https://togithub.com/googleapis/release-please). See [documentation](https://togithub.com/googleapis/release-please#release-please). * chore: [control] migrate generator to google-cloud-node (#7967) - [ ] Regenerate this pull request now. chore: update generator system tests PiperOrigin-RevId: 896174961 Source-Link: https://togithub.com/googleapis/googleapis/commit/2233f63baf69c2a481f30180045fcf036242781d Source-Link: https://togithub.com/googleapis/googleapis-gen/commit/c4a8c4eef959aa744fb1c6714875fa295e06aad3 Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLXN0b3JhZ2UtY29udHJvbC8uT3dsQm90LnlhbWwiLCJoIjoiYzRhOGM0ZWVmOTU5YWE3NDRmYjFjNjcxNDg3NWZhMjk1ZTA2YWFkMyJ9 BEGIN_NESTED_COMMIT feat: [control] populate the `persisted_data_checksums` field with object checksums on write object / query write status responses docs: improve wording around `object_checksums` in bidi write object requests PiperOrigin-RevId: 895357062 Source-Link: https://togithub.com/googleapis/googleapis/commit/d73dfb3c3be52245625b951b9c0bcf65163c549f Source-Link: https://togithub.com/googleapis/googleapis-gen/commit/7e7398240bfa0cf54d7042169fe14afb9a77ac64 Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLXN0b3JhZ2UtY29udHJvbC8uT3dsQm90LnlhbWwiLCJoIjoiN2U3Mzk4MjQwYmZhMGNmNTRkNzA0MjE2OWZlMTRhZmI5YTc3YWM2NCJ9 END_NESTED_COMMIT * feat: [dataproc] Add `Engine` field to support LightningEngine in clusters and add support for stop ttl (#8008) * feat: Add `Engine` field to support LightningEngine in clusters and add support for stop ttl PiperOrigin-RevId: 897294662 Source-Link: https://github.com/googleapis/googleapis/commit/2da86587126416eb48d561cd800bb03afa2f501a Source-Link: https://github.com/googleapis/googleapis-gen/commit/ef2d7de453b229f9fa8568f90099984b7115b8c8 Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLWRhdGFwcm9jLy5Pd2xCb3QueWFtbCIsImgiOiJlZjJkN2RlNDUzYjIyOWY5ZmE4NTY4ZjkwMDk5OTg0YjcxMTViOGM4In0= * 🦉 Updates from OwlBot post-processor See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md --------- Co-authored-by: Owl Bot Co-authored-by: Shivanee <46910562+shivanee-p@users.noreply.github.com> * feat: [analytics-admin] add UserProvidedDataSettings resource and GetUserProvidedDataSettings RPC to Google Analytics (#8049) - [ ] Regenerate this pull request now. chore: update resource name fields to use IDENTIFIER field behavior across Google Analytics resources chore: add plural and singular names to google.api.resource definitions for Google Analytics resources chore: mark page_size and page_token fields as OPTIONAL in Google Analytics list request messages chore: update OAuth scopes for GetUserProvidedDataSettings and GetSubpropertySyncConfig in Google Analytics docs: update documentation for GetReportingIdentitySettings to correctly describe it as returning reporting identity settings in Google Analytics docs: update copyright year to 2026 in Google Analytics proto files PiperOrigin-RevId: 899639582 Source-Link: https://togithub.com/googleapis/googleapis/commit/fc968708d27f9aeb9f1c50a3e32d53810df843fd Source-Link: https://togithub.com/googleapis/googleapis-gen/commit/a4aa3a09be8b07588de5591432d9131726d3909a Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWFuYWx5dGljcy1hZG1pbi8uT3dsQm90LnlhbWwiLCJoIjoiYTRhYTNhMDliZThiMDc1ODhkZTU1OTE0MzJkOTEzMTcyNmQzOTA5YSJ9 * feat: [ces] Add ability to specify mocked tool responses in ExecuteTool (#8051) * feat: Add ability to specify mocked tool responses in ExecuteTool feat: Add ExportEvaluation RPC feat: Add support for app level fallback config feat: Add evaluation run and result information to ImportEvaluationsResponse PiperOrigin-RevId: 899708731 Source-Link: https://github.com/googleapis/googleapis/commit/3035633d62f5d983a186e8c672a8eede386808ad Source-Link: https://github.com/googleapis/googleapis-gen/commit/b4d5ff9cd1b366fa37e5543d127b51b7402acb12 Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLWNlcy8uT3dsQm90LnlhbWwiLCJoIjoiYjRkNWZmOWNkMWIzNjZmYTM3ZTU1NDNkMTI3YjUxYjc0MDJhY2IxMiJ9 * 🦉 Updates from OwlBot post-processor See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md --------- Co-authored-by: Owl Bot * docs: [saasservicemgmt] rebrand from "SaaS Runtime" to "App Lifecycle Manager" (#8047) * docs: rebrand from "SaaS Runtime" to "App Lifecycle Manager" PiperOrigin-RevId: 899527956 Source-Link: https://github.com/googleapis/googleapis/commit/96b171f04a80ea7747b808c823debea61087e4ae Source-Link: https://github.com/googleapis/googleapis-gen/commit/0ce27dbb7515c5c9775c893671eff58c041c7a9c Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLXNhYXNwbGF0Zm9ybS1zYWFzc2VydmljZW1nbXQvLk93bEJvdC55YW1sIiwiaCI6IjBjZTI3ZGJiNzUxNWM1Yzk3NzVjODkzNjcxZWZmNThjMDQxYzdhOWMifQ== * 🦉 Updates from OwlBot post-processor See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md --------- Co-authored-by: Owl Bot Co-authored-by: danieljbruce * build: pin packages to sinon 21.0.3 for now to dodge a build error (#8053) * build: pin sinon version in gax * build: pin packages to sinon 21.0.3 for now to dodge a build error * feat: [hypercomputecluster] Sync stable version (#8056) * feat: Sync stable version fix!: Sync stable version docs: sync stable version PiperOrigin-RevId: 899788822 Source-Link: https://github.com/googleapis/googleapis/commit/bf85cad8abc13cd38d42b0cf8545d323243ff7e2 Source-Link: https://github.com/googleapis/googleapis-gen/commit/c9e2df2dac092fc5003de8d9577d02757500f3f2 Copy-Tag: eyJwIjoicGFja2FnZXMvZ29vZ2xlLWNsb3VkLWh5cGVyY29tcHV0ZWNsdXN0ZXIvLk93bEJvdC55YW1sIiwiaCI6ImM5ZTJkZjJkYWMwOTJmYzUwMDNkZThkOTU3N2QwMjc1NzUwMGYzZjIifQ== * 🦉 Updates from OwlBot post-processor See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md --------- Co-authored-by: Owl Bot * chore(spanner): add support for new cloud client test framework in google-cloud-spanner-executor (#7593) * chore(spanner): add support for new cloud client test framework in google-cloud-spanner-executor * 🦉 Updates from OwlBot post-processor See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md --------- Co-authored-by: Owl Bot * fix(bigquery): run npm run types in correct directory in owlbot (#8061) * fix(bigquery): run npm run types in correct directory in owlbot * Add npm install to the script * chore(test-release-please-spanner): release spanner 8.7.0 (#8054) * fix(spanner): trigger release * chore: isolate Spanner and increase search depth for testing * chore: reduce batch size to avoid 502 error * chore(test-release-please-spanner): release spanner 8.7.0 * chore: restore all packages and apply search limits * fix(spanner): getTransaction type with options, cb (#8045) * fix(spanner): getTransaction type with options, cb * test(spanner): add test for getTransaction options cb * test(spanner): add assert non error on get tx with cb Co-authored-by: alkatrivedi <58396306+alkatrivedi@users.noreply.github.com> --------- Co-authored-by: alkatrivedi <58396306+alkatrivedi@users.noreply.github.com> * chore(storage-control): add stripInternal setting to tsconfig (#8057) * fix: Do not publish the protos to npm (#8079) ## Description This change solves https://togithub.com/googleapis/librarian/issues/4820 and ensures that the .proto files don't get published to npm. ## Impact This just cleans up the built packages. It will make customer dependencies smaller which could improve the performance of their applications by shrinking their node_modules folders. ## Testing Only package.json files are modified in this change so tests against the source code aren't really required here. * chore(firestore): rename named-db to enterprise (#8083) * chore: set the aion-team as code owners on google-auth-library-nodejs (#8084) * chore: set the aion-team as code owners on google-auth-library-nodejs so they can be set as reviewers * add new line in response to gemini code review --------- Co-authored-by: gcf-owl-bot[bot] <78513119+gcf-owl-bot[bot]@users.noreply.github.com> Co-authored-by: Owl Bot Co-authored-by: Shivanee <46910562+shivanee-p@users.noreply.github.com> Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com> Co-authored-by: danieljbruce Co-authored-by: feywind <57276408+feywind@users.noreply.github.com> Co-authored-by: alkatrivedi <58396306+alkatrivedi@users.noreply.github.com> Co-authored-by: Gautam Sharda <57648023+GautamSharda@users.noreply.github.com> Co-authored-by: Jan Vincent Liwanag Co-authored-by: Denis DelGrosso <85250797+ddelgrosso1@users.noreply.github.com> Co-authored-by: wu-hui <53845758+wu-hui@users.noreply.github.com> --- packages/google-ads-admanager/package.json | 3 +-- packages/google-ads-datamanager/package.json | 3 +-- packages/google-ai-generativelanguage/package.json | 3 +-- packages/google-analytics-admin/package.json | 1 - packages/google-analytics-data/package.json | 1 - packages/google-api-apikeys/package.json | 1 - packages/google-api-cloudquotas/package.json | 3 +-- packages/google-api-servicecontrol/package.json | 1 - packages/google-api-servicemanagement/package.json | 1 - packages/google-api-serviceusage/package.json | 1 - packages/google-appengine/package.json | 1 - packages/google-apps-events-subscriptions/package.json | 3 +-- packages/google-apps-meet/package.json | 3 +-- packages/google-area120-tables/package.json | 1 - packages/google-chat/package.json | 3 +-- packages/google-cloud-accessapproval/package.json | 1 - packages/google-cloud-advisorynotifications/package.json | 1 - packages/google-cloud-aiplatform/package.json | 1 - packages/google-cloud-alloydb/package.json | 1 - packages/google-cloud-apigateway/package.json | 1 - packages/google-cloud-apigeeconnect/package.json | 1 - packages/google-cloud-apigeeregistry/package.json | 3 +-- packages/google-cloud-apihub/package.json | 3 +-- packages/google-cloud-apiregistry/package.json | 3 +-- packages/google-cloud-apphub/package.json | 3 +-- packages/google-cloud-asset/package.json | 1 - packages/google-cloud-assuredworkloads/package.json | 1 - packages/google-cloud-auditmanager/package.json | 3 +-- packages/google-cloud-automl/package.json | 1 - packages/google-cloud-backupdr/package.json | 3 +-- packages/google-cloud-baremetalsolution/package.json | 1 - packages/google-cloud-batch/package.json | 1 - packages/google-cloud-beyondcorp-appconnections/package.json | 1 - packages/google-cloud-beyondcorp-appconnectors/package.json | 1 - packages/google-cloud-beyondcorp-appgateways/package.json | 1 - .../package.json | 1 - packages/google-cloud-beyondcorp-clientgateways/package.json | 1 - packages/google-cloud-bigquery-analyticshub/package.json | 1 - packages/google-cloud-bigquery-connection/package.json | 1 - packages/google-cloud-bigquery-dataexchange/package.json | 1 - packages/google-cloud-bigquery-datapolicies/package.json | 1 - packages/google-cloud-bigquery-datatransfer/package.json | 1 - packages/google-cloud-bigquery-migration/package.json | 3 +-- packages/google-cloud-bigquery-reservation/package.json | 1 - packages/google-cloud-billing-budgets/package.json | 1 - packages/google-cloud-billing/package.json | 1 - packages/google-cloud-binaryauthorization/package.json | 1 - packages/google-cloud-capacityplanner/package.json | 3 +-- packages/google-cloud-certificatemanager/package.json | 1 - packages/google-cloud-ces/package.json | 3 +-- packages/google-cloud-channel/package.json | 1 - packages/google-cloud-chronicle/package.json | 3 +-- packages/google-cloud-cloudcontrolspartner/package.json | 3 +-- packages/google-cloud-clouddms/package.json | 1 - packages/google-cloud-cloudsecuritycompliance/package.json | 3 +-- .../google-cloud-commerce-consumer-procurement/package.json | 3 +-- packages/google-cloud-compute/package.json | 1 - packages/google-cloud-confidentialcomputing/package.json | 3 +-- packages/google-cloud-config/package.json | 3 +-- packages/google-cloud-configdelivery/package.json | 3 +-- packages/google-cloud-connectors/package.json | 3 +-- packages/google-cloud-contactcenterinsights/package.json | 1 - packages/google-cloud-contentwarehouse/package.json | 1 - .../package.json | 3 +-- packages/google-cloud-datacatalog-lineage/package.json | 1 - packages/google-cloud-datacatalog/package.json | 1 - packages/google-cloud-dataform/package.json | 3 +-- packages/google-cloud-datafusion/package.json | 1 - packages/google-cloud-datalabeling/package.json | 1 - packages/google-cloud-dataplex/package.json | 1 - packages/google-cloud-dataproc/package.json | 1 - packages/google-cloud-dataqna/package.json | 1 - packages/google-cloud-datastream/package.json | 1 - packages/google-cloud-deploy/package.json | 1 - packages/google-cloud-developerconnect/package.json | 3 +-- packages/google-cloud-devicestreaming/package.json | 3 +-- packages/google-cloud-dialogflow-cx/package.json | 1 - packages/google-cloud-dialogflow/package.json | 1 - packages/google-cloud-discoveryengine/package.json | 1 - packages/google-cloud-documentai/package.json | 1 - packages/google-cloud-domains/package.json | 1 - packages/google-cloud-edgecontainer/package.json | 3 +-- packages/google-cloud-edgenetwork/package.json | 3 +-- packages/google-cloud-essentialcontacts/package.json | 1 - packages/google-cloud-eventarc-publishing/package.json | 1 - packages/google-cloud-eventarc/package.json | 1 - packages/google-cloud-filestore/package.json | 1 - packages/google-cloud-financialservices/package.json | 3 +-- packages/google-cloud-functions/package.json | 1 - packages/google-cloud-gdchardwaremanagement/package.json | 3 +-- packages/google-cloud-geminidataanalytics/package.json | 3 +-- packages/google-cloud-gkebackup/package.json | 1 - packages/google-cloud-gkeconnect-gateway/package.json | 1 - packages/google-cloud-gkehub/package.json | 1 - packages/google-cloud-gkemulticloud/package.json | 1 - packages/google-cloud-gkerecommender/package.json | 3 +-- packages/google-cloud-gsuiteaddons/package.json | 1 - packages/google-cloud-hypercomputecluster/package.json | 3 +-- packages/google-cloud-iap/package.json | 1 - packages/google-cloud-ids/package.json | 1 - packages/google-cloud-iot/package.json | 1 - packages/google-cloud-kms-inventory/package.json | 1 - packages/google-cloud-kms/package.json | 1 - packages/google-cloud-language/package.json | 1 - packages/google-cloud-licensemanager/package.json | 3 +-- packages/google-cloud-lifesciences/package.json | 1 - packages/google-cloud-locationfinder/package.json | 3 +-- packages/google-cloud-lustre/package.json | 3 +-- packages/google-cloud-maintenance-api/package.json | 3 +-- packages/google-cloud-managedidentities/package.json | 1 - packages/google-cloud-managedkafka-schemaregistry/package.json | 3 +-- packages/google-cloud-managedkafka/package.json | 3 +-- packages/google-cloud-mediatranslation/package.json | 1 - packages/google-cloud-memcache/package.json | 1 - packages/google-cloud-memorystore/package.json | 3 +-- packages/google-cloud-metastore/package.json | 1 - packages/google-cloud-migrationcenter/package.json | 3 +-- packages/google-cloud-modelarmor/package.json | 3 +-- packages/google-cloud-monitoring/package.json | 1 - packages/google-cloud-netapp/package.json | 3 +-- packages/google-cloud-networkconnectivity/package.json | 1 - packages/google-cloud-networkmanagement/package.json | 1 - packages/google-cloud-networksecurity/package.json | 1 - packages/google-cloud-networkservices/package.json | 3 +-- packages/google-cloud-notebooks/package.json | 1 - packages/google-cloud-oracledatabase/package.json | 3 +-- .../google-cloud-orchestration-airflow-service/package.json | 1 - packages/google-cloud-orgpolicy/package.json | 1 - packages/google-cloud-osconfig/package.json | 1 - packages/google-cloud-oslogin/package.json | 1 - packages/google-cloud-parallelstore/package.json | 3 +-- packages/google-cloud-parametermanager/package.json | 3 +-- packages/google-cloud-phishingprotection/package.json | 1 - packages/google-cloud-policysimulator/package.json | 3 +-- packages/google-cloud-policytroubleshooter-iam/package.json | 3 +-- packages/google-cloud-policytroubleshooter/package.json | 1 - packages/google-cloud-privatecatalog/package.json | 1 - packages/google-cloud-privilegedaccessmanager/package.json | 3 +-- packages/google-cloud-rapidmigrationassessment/package.json | 3 +-- packages/google-cloud-recaptchaenterprise/package.json | 1 - packages/google-cloud-recommender/package.json | 1 - packages/google-cloud-redis-cluster/package.json | 3 +-- packages/google-cloud-redis/package.json | 1 - packages/google-cloud-resourcemanager/package.json | 1 - packages/google-cloud-retail/package.json | 1 - packages/google-cloud-run/package.json | 1 - .../google-cloud-saasplatform-saasservicemgmt/package.json | 3 +-- packages/google-cloud-scheduler/package.json | 1 - packages/google-cloud-secretmanager/package.json | 1 - packages/google-cloud-securesourcemanager/package.json | 3 +-- packages/google-cloud-security-privateca/package.json | 1 - packages/google-cloud-security-publicca/package.json | 1 - packages/google-cloud-securitycenter/package.json | 1 - packages/google-cloud-securitycentermanagement/package.json | 3 +-- packages/google-cloud-servicedirectory/package.json | 1 - packages/google-cloud-servicehealth/package.json | 3 +-- packages/google-cloud-shell/package.json | 1 - packages/google-cloud-speech/package.json | 1 - packages/google-cloud-sql/package.json | 3 +-- packages/google-cloud-storagebatchoperations/package.json | 3 +-- packages/google-cloud-storageinsights/package.json | 3 +-- packages/google-cloud-support/package.json | 3 +-- packages/google-cloud-talent/package.json | 1 - packages/google-cloud-telcoautomation/package.json | 3 +-- packages/google-cloud-texttospeech/package.json | 1 - packages/google-cloud-tpu/package.json | 1 - packages/google-cloud-translate/package.json | 1 - packages/google-cloud-vectorsearch/package.json | 3 +-- packages/google-cloud-video-livestream/package.json | 1 - packages/google-cloud-video-stitcher/package.json | 1 - packages/google-cloud-video-transcoder/package.json | 1 - packages/google-cloud-videointelligence/package.json | 1 - packages/google-cloud-vision/package.json | 1 - packages/google-cloud-visionai/package.json | 3 +-- packages/google-cloud-vmmigration/package.json | 1 - packages/google-cloud-vmwareengine/package.json | 1 - packages/google-cloud-vpcaccess/package.json | 1 - packages/google-cloud-webrisk/package.json | 1 - packages/google-cloud-websecurityscanner/package.json | 1 - packages/google-cloud-workflows/package.json | 1 - packages/google-cloud-workloadmanager/package.json | 3 +-- packages/google-cloud-workstations/package.json | 1 - packages/google-container/package.json | 1 - packages/google-dataflow/package.json | 1 - packages/google-devtools-artifactregistry/package.json | 1 - packages/google-devtools-cloudbuild/package.json | 1 - packages/google-devtools-cloudprofiler/package.json | 3 +-- packages/google-devtools-containeranalysis/package.json | 1 - packages/google-iam-credentials/package.json | 1 - packages/google-iam/package.json | 1 - packages/google-identity-accesscontextmanager/package.json | 1 - packages/google-maps-addressvalidation/package.json | 1 - packages/google-maps-areainsights/package.json | 3 +-- packages/google-maps-fleetengine-delivery/package.json | 3 +-- packages/google-maps-fleetengine/package.json | 3 +-- packages/google-maps-geocode/package.json | 3 +-- packages/google-maps-mapsplatformdatasets/package.json | 1 - packages/google-maps-navconnect/package.json | 3 +-- packages/google-maps-places/package.json | 3 +-- packages/google-maps-routeoptimization/package.json | 3 +-- packages/google-maps-routing/package.json | 1 - packages/google-maps-solar/package.json | 3 +-- packages/google-marketingplatform-admin/package.json | 3 +-- packages/google-monitoring-dashboard/package.json | 1 - packages/google-privacy-dlp/package.json | 1 - packages/google-shopping-css/package.json | 3 +-- packages/google-shopping-merchant-accounts/package.json | 3 +-- packages/google-shopping-merchant-conversions/package.json | 3 +-- packages/google-shopping-merchant-datasources/package.json | 3 +-- packages/google-shopping-merchant-inventories/package.json | 3 +-- packages/google-shopping-merchant-issueresolution/package.json | 3 +-- packages/google-shopping-merchant-lfp/package.json | 3 +-- packages/google-shopping-merchant-notifications/package.json | 3 +-- packages/google-shopping-merchant-ordertracking/package.json | 3 +-- packages/google-shopping-merchant-products/package.json | 3 +-- packages/google-shopping-merchant-promotions/package.json | 3 +-- packages/google-shopping-merchant-quota/package.json | 3 +-- packages/google-shopping-merchant-reports/package.json | 3 +-- packages/google-shopping-merchant-reviews/package.json | 3 +-- packages/google-storage-control/package.json | 3 +-- packages/google-storagetransfer/package.json | 1 - packages/google-streetview-publish/package.json | 3 +-- packages/grafeas/package.json | 1 - 223 files changed, 92 insertions(+), 315 deletions(-) diff --git a/packages/google-ads-admanager/package.json b/packages/google-ads-admanager/package.json index 95b10b9402fd..bc5e971c6d07 100644 --- a/packages/google-ads-admanager/package.json +++ b/packages/google-ads-admanager/package.json @@ -11,8 +11,7 @@ "author": "Google LLC", "main": "build/src/index.js", "files": [ - "build/src", - "build/protos" + "build/src" ], "homepage": "https://github.com/googleapis/google-cloud-node/tree/main/packages/google-ads-admanager", "keywords": [ diff --git a/packages/google-ads-datamanager/package.json b/packages/google-ads-datamanager/package.json index 11e10a2e7e32..96e4cd79e504 100644 --- a/packages/google-ads-datamanager/package.json +++ b/packages/google-ads-datamanager/package.json @@ -11,8 +11,7 @@ "author": "Google LLC", "main": "build/src/index.js", "files": [ - "build/src", - "build/protos" + "build/src" ], "homepage": "https://github.com/googleapis/google-cloud-node/tree/main/packages/google-ads-datamanager", "keywords": [ diff --git a/packages/google-ai-generativelanguage/package.json b/packages/google-ai-generativelanguage/package.json index e3df02b0d557..e123734d863f 100644 --- a/packages/google-ai-generativelanguage/package.json +++ b/packages/google-ai-generativelanguage/package.json @@ -11,8 +11,7 @@ "author": "Google LLC", "main": "build/src/index.js", "files": [ - "build/src", - "build/protos" + "build/src" ], "homepage": "https://github.com/googleapis/google-cloud-node/tree/main/packages/google-ai-generativelanguage", "keywords": [ diff --git a/packages/google-analytics-admin/package.json b/packages/google-analytics-admin/package.json index f83f73cf07ba..97d48dccee6a 100644 --- a/packages/google-analytics-admin/package.json +++ b/packages/google-analytics-admin/package.json @@ -12,7 +12,6 @@ "main": "build/src/index.js", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "keywords": [ diff --git a/packages/google-analytics-data/package.json b/packages/google-analytics-data/package.json index 173fed47f717..7a2839f701f2 100644 --- a/packages/google-analytics-data/package.json +++ b/packages/google-analytics-data/package.json @@ -12,7 +12,6 @@ "main": "build/src/index.js", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "keywords": [ diff --git a/packages/google-api-apikeys/package.json b/packages/google-api-apikeys/package.json index 84946ff96696..7ba7b5201739 100644 --- a/packages/google-api-apikeys/package.json +++ b/packages/google-api-apikeys/package.json @@ -13,7 +13,6 @@ "main": "build/src/index.js", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "keywords": [ diff --git a/packages/google-api-cloudquotas/package.json b/packages/google-api-cloudquotas/package.json index ad2bc9b6a73a..e868ebf4f0ce 100644 --- a/packages/google-api-cloudquotas/package.json +++ b/packages/google-api-cloudquotas/package.json @@ -11,8 +11,7 @@ "author": "Google LLC", "main": "build/src/index.js", "files": [ - "build/src", - "build/protos" + "build/src" ], "homepage": "https://github.com/googleapis/google-cloud-node/tree/main/packages/google-api-cloudquotas", "keywords": [ diff --git a/packages/google-api-servicecontrol/package.json b/packages/google-api-servicecontrol/package.json index ac24a75279d5..17f21759d3a8 100644 --- a/packages/google-api-servicecontrol/package.json +++ b/packages/google-api-servicecontrol/package.json @@ -12,7 +12,6 @@ "main": "build/src/index.js", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "keywords": [ diff --git a/packages/google-api-servicemanagement/package.json b/packages/google-api-servicemanagement/package.json index 1cc33c94c124..4ac0ccf20aef 100644 --- a/packages/google-api-servicemanagement/package.json +++ b/packages/google-api-servicemanagement/package.json @@ -12,7 +12,6 @@ "main": "build/src/index.js", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "keywords": [ diff --git a/packages/google-api-serviceusage/package.json b/packages/google-api-serviceusage/package.json index 245ef944e03b..84116eb5cbe1 100644 --- a/packages/google-api-serviceusage/package.json +++ b/packages/google-api-serviceusage/package.json @@ -12,7 +12,6 @@ "main": "build/src/index.js", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "keywords": [ diff --git a/packages/google-appengine/package.json b/packages/google-appengine/package.json index cab84229b33c..5aa194da1c6a 100644 --- a/packages/google-appengine/package.json +++ b/packages/google-appengine/package.json @@ -12,7 +12,6 @@ "main": "build/src/index.js", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "keywords": [ diff --git a/packages/google-apps-events-subscriptions/package.json b/packages/google-apps-events-subscriptions/package.json index fbc82c558b79..bfc75554e661 100644 --- a/packages/google-apps-events-subscriptions/package.json +++ b/packages/google-apps-events-subscriptions/package.json @@ -11,8 +11,7 @@ "author": "Google LLC", "main": "build/src/index.js", "files": [ - "build/src", - "build/protos" + "build/src" ], "homepage": "https://github.com/googleapis/google-cloud-node/tree/main/packages/google-apps-events-subscriptions", "keywords": [ diff --git a/packages/google-apps-meet/package.json b/packages/google-apps-meet/package.json index 627bdf04b987..5b50b2847f43 100644 --- a/packages/google-apps-meet/package.json +++ b/packages/google-apps-meet/package.json @@ -11,8 +11,7 @@ "author": "Google LLC", "main": "build/src/index.js", "files": [ - "build/src", - "build/protos" + "build/src" ], "homepage": "https://github.com/googleapis/google-cloud-node/tree/main/packages/google-apps-meet", "keywords": [ diff --git a/packages/google-area120-tables/package.json b/packages/google-area120-tables/package.json index 2260ba5ebe1f..339de75f899e 100644 --- a/packages/google-area120-tables/package.json +++ b/packages/google-area120-tables/package.json @@ -12,7 +12,6 @@ "main": "build/src/index.js", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "keywords": [ diff --git a/packages/google-chat/package.json b/packages/google-chat/package.json index 643a65aaea9e..6c0e589239bd 100644 --- a/packages/google-chat/package.json +++ b/packages/google-chat/package.json @@ -11,8 +11,7 @@ "author": "Google LLC", "main": "build/src/index.js", "files": [ - "build/src", - "build/protos" + "build/src" ], "homepage": "https://github.com/googleapis/google-cloud-node/tree/main/packages/google-chat", "keywords": [ diff --git a/packages/google-cloud-accessapproval/package.json b/packages/google-cloud-accessapproval/package.json index 8d3343a90886..32fb845e2868 100644 --- a/packages/google-cloud-accessapproval/package.json +++ b/packages/google-cloud-accessapproval/package.json @@ -12,7 +12,6 @@ "main": "build/src/index.js", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "keywords": [ diff --git a/packages/google-cloud-advisorynotifications/package.json b/packages/google-cloud-advisorynotifications/package.json index 3eefafa012fe..effdf1c330b8 100644 --- a/packages/google-cloud-advisorynotifications/package.json +++ b/packages/google-cloud-advisorynotifications/package.json @@ -12,7 +12,6 @@ "main": "build/src/index.js", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "homepage": "https://github.com/googleapis/google-cloud-node/tree/main/packages/google-cloud-advisorynotifications", diff --git a/packages/google-cloud-aiplatform/package.json b/packages/google-cloud-aiplatform/package.json index 993d8f4203eb..b45ad6f8bb65 100644 --- a/packages/google-cloud-aiplatform/package.json +++ b/packages/google-cloud-aiplatform/package.json @@ -12,7 +12,6 @@ "main": "build/src/index.js", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "keywords": [ diff --git a/packages/google-cloud-alloydb/package.json b/packages/google-cloud-alloydb/package.json index b363bae9c59d..3cbef1a19f71 100644 --- a/packages/google-cloud-alloydb/package.json +++ b/packages/google-cloud-alloydb/package.json @@ -12,7 +12,6 @@ "main": "build/src/index.js", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "homepage": "https://github.com/googleapis/google-cloud-node/tree/main/packages/google-cloud-alloydb", diff --git a/packages/google-cloud-apigateway/package.json b/packages/google-cloud-apigateway/package.json index d59481d6af43..e2bb6138e4d6 100644 --- a/packages/google-cloud-apigateway/package.json +++ b/packages/google-cloud-apigateway/package.json @@ -12,7 +12,6 @@ "main": "build/src/index.js", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "keywords": [ diff --git a/packages/google-cloud-apigeeconnect/package.json b/packages/google-cloud-apigeeconnect/package.json index f533dbcb3fa1..7aba6e7bfce3 100644 --- a/packages/google-cloud-apigeeconnect/package.json +++ b/packages/google-cloud-apigeeconnect/package.json @@ -12,7 +12,6 @@ "main": "build/src/index.js", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "keywords": [ diff --git a/packages/google-cloud-apigeeregistry/package.json b/packages/google-cloud-apigeeregistry/package.json index 95c12ec6f4c6..d8b61a63cf22 100644 --- a/packages/google-cloud-apigeeregistry/package.json +++ b/packages/google-cloud-apigeeregistry/package.json @@ -11,8 +11,7 @@ "author": "Google LLC", "main": "build/src/index.js", "files": [ - "build/src", - "build/protos" + "build/src" ], "keywords": [ "google apis client", diff --git a/packages/google-cloud-apihub/package.json b/packages/google-cloud-apihub/package.json index 918d885b8cad..5f91677da1dd 100644 --- a/packages/google-cloud-apihub/package.json +++ b/packages/google-cloud-apihub/package.json @@ -11,8 +11,7 @@ "author": "Google LLC", "main": "build/src/index.js", "files": [ - "build/src", - "build/protos" + "build/src" ], "homepage": "https://github.com/googleapis/google-cloud-node/tree/main/packages/google-cloud-apihub", "keywords": [ diff --git a/packages/google-cloud-apiregistry/package.json b/packages/google-cloud-apiregistry/package.json index 97c958c03a22..39cab84a0d33 100644 --- a/packages/google-cloud-apiregistry/package.json +++ b/packages/google-cloud-apiregistry/package.json @@ -11,8 +11,7 @@ "author": "Google LLC", "main": "build/src/index.js", "files": [ - "build/src", - "build/protos" + "build/src" ], "homepage": "https://github.com/googleapis/google-cloud-node/tree/main/packages/google-cloud-apiregistry", "keywords": [ diff --git a/packages/google-cloud-apphub/package.json b/packages/google-cloud-apphub/package.json index 9303e65606c6..d81e5d2e095e 100644 --- a/packages/google-cloud-apphub/package.json +++ b/packages/google-cloud-apphub/package.json @@ -11,8 +11,7 @@ "author": "Google LLC", "main": "build/src/index.js", "files": [ - "build/src", - "build/protos" + "build/src" ], "homepage": "https://github.com/googleapis/google-cloud-node/tree/main/packages/google-cloud-apphub", "keywords": [ diff --git a/packages/google-cloud-asset/package.json b/packages/google-cloud-asset/package.json index 8174dc8d485d..bae894738ecf 100644 --- a/packages/google-cloud-asset/package.json +++ b/packages/google-cloud-asset/package.json @@ -15,7 +15,6 @@ "main": "build/src/index.js", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "keywords": [ diff --git a/packages/google-cloud-assuredworkloads/package.json b/packages/google-cloud-assuredworkloads/package.json index 39580a5f1c01..8ae5b845bc2f 100644 --- a/packages/google-cloud-assuredworkloads/package.json +++ b/packages/google-cloud-assuredworkloads/package.json @@ -12,7 +12,6 @@ "main": "build/src/index.js", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "keywords": [ diff --git a/packages/google-cloud-auditmanager/package.json b/packages/google-cloud-auditmanager/package.json index 25c2e441c2fd..4e3f590cb940 100644 --- a/packages/google-cloud-auditmanager/package.json +++ b/packages/google-cloud-auditmanager/package.json @@ -11,8 +11,7 @@ "author": "Google LLC", "main": "build/src/index.js", "files": [ - "build/src", - "build/protos" + "build/src" ], "homepage": "https://github.com/googleapis/google-cloud-node/tree/main/packages/google-cloud-auditmanager", "keywords": [ diff --git a/packages/google-cloud-automl/package.json b/packages/google-cloud-automl/package.json index 6917e1b5dab5..74513d7c4ac0 100644 --- a/packages/google-cloud-automl/package.json +++ b/packages/google-cloud-automl/package.json @@ -14,7 +14,6 @@ }, "main": "build/src/index.js", "files": [ - "build/protos", "build/src" ], "keywords": [ diff --git a/packages/google-cloud-backupdr/package.json b/packages/google-cloud-backupdr/package.json index 96cd30e9320a..3f5ccc916b5b 100644 --- a/packages/google-cloud-backupdr/package.json +++ b/packages/google-cloud-backupdr/package.json @@ -11,8 +11,7 @@ "author": "Google LLC", "main": "build/src/index.js", "files": [ - "build/src", - "build/protos" + "build/src" ], "homepage": "https://github.com/googleapis/google-cloud-node/tree/main/packages/google-cloud-backupdr", "keywords": [ diff --git a/packages/google-cloud-baremetalsolution/package.json b/packages/google-cloud-baremetalsolution/package.json index 60cd3a5b2c51..f630a6efb563 100644 --- a/packages/google-cloud-baremetalsolution/package.json +++ b/packages/google-cloud-baremetalsolution/package.json @@ -12,7 +12,6 @@ "main": "build/src/index.js", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "keywords": [ diff --git a/packages/google-cloud-batch/package.json b/packages/google-cloud-batch/package.json index a29d67baa6d9..5911af269ad8 100644 --- a/packages/google-cloud-batch/package.json +++ b/packages/google-cloud-batch/package.json @@ -13,7 +13,6 @@ "main": "build/src/index.js", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "keywords": [ diff --git a/packages/google-cloud-beyondcorp-appconnections/package.json b/packages/google-cloud-beyondcorp-appconnections/package.json index cda7d6a7abb6..3d00ff2c1ad3 100644 --- a/packages/google-cloud-beyondcorp-appconnections/package.json +++ b/packages/google-cloud-beyondcorp-appconnections/package.json @@ -13,7 +13,6 @@ "main": "build/src/index.js", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "keywords": [ diff --git a/packages/google-cloud-beyondcorp-appconnectors/package.json b/packages/google-cloud-beyondcorp-appconnectors/package.json index 29f488a2a44d..53ad14b79435 100644 --- a/packages/google-cloud-beyondcorp-appconnectors/package.json +++ b/packages/google-cloud-beyondcorp-appconnectors/package.json @@ -13,7 +13,6 @@ "main": "build/src/index.js", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "keywords": [ diff --git a/packages/google-cloud-beyondcorp-appgateways/package.json b/packages/google-cloud-beyondcorp-appgateways/package.json index 2db3a8c5f69f..533fa2218a56 100644 --- a/packages/google-cloud-beyondcorp-appgateways/package.json +++ b/packages/google-cloud-beyondcorp-appgateways/package.json @@ -13,7 +13,6 @@ "main": "build/src/index.js", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "keywords": [ diff --git a/packages/google-cloud-beyondcorp-clientconnectorservices/package.json b/packages/google-cloud-beyondcorp-clientconnectorservices/package.json index 5cf6a535c9a8..0156743958e9 100644 --- a/packages/google-cloud-beyondcorp-clientconnectorservices/package.json +++ b/packages/google-cloud-beyondcorp-clientconnectorservices/package.json @@ -13,7 +13,6 @@ "main": "build/src/index.js", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "keywords": [ diff --git a/packages/google-cloud-beyondcorp-clientgateways/package.json b/packages/google-cloud-beyondcorp-clientgateways/package.json index 271b2f51975f..5dd7d8abb10d 100644 --- a/packages/google-cloud-beyondcorp-clientgateways/package.json +++ b/packages/google-cloud-beyondcorp-clientgateways/package.json @@ -13,7 +13,6 @@ "main": "build/src/index.js", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "keywords": [ diff --git a/packages/google-cloud-bigquery-analyticshub/package.json b/packages/google-cloud-bigquery-analyticshub/package.json index 8c5e32208741..6bb9038bb978 100644 --- a/packages/google-cloud-bigquery-analyticshub/package.json +++ b/packages/google-cloud-bigquery-analyticshub/package.json @@ -13,7 +13,6 @@ "main": "build/src/index.js", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "keywords": [ diff --git a/packages/google-cloud-bigquery-connection/package.json b/packages/google-cloud-bigquery-connection/package.json index 1441951fe361..2fc601cf1887 100644 --- a/packages/google-cloud-bigquery-connection/package.json +++ b/packages/google-cloud-bigquery-connection/package.json @@ -12,7 +12,6 @@ "main": "build/src/index.js", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "keywords": [ diff --git a/packages/google-cloud-bigquery-dataexchange/package.json b/packages/google-cloud-bigquery-dataexchange/package.json index e169b3c47d0e..75f0ca5df1b2 100644 --- a/packages/google-cloud-bigquery-dataexchange/package.json +++ b/packages/google-cloud-bigquery-dataexchange/package.json @@ -13,7 +13,6 @@ "main": "build/src/index.js", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "keywords": [ diff --git a/packages/google-cloud-bigquery-datapolicies/package.json b/packages/google-cloud-bigquery-datapolicies/package.json index e5dc0c04aebd..c673077d2fd5 100644 --- a/packages/google-cloud-bigquery-datapolicies/package.json +++ b/packages/google-cloud-bigquery-datapolicies/package.json @@ -13,7 +13,6 @@ "main": "build/src/index.js", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "keywords": [ diff --git a/packages/google-cloud-bigquery-datatransfer/package.json b/packages/google-cloud-bigquery-datatransfer/package.json index e80d51d87020..f6483fe18dd4 100644 --- a/packages/google-cloud-bigquery-datatransfer/package.json +++ b/packages/google-cloud-bigquery-datatransfer/package.json @@ -15,7 +15,6 @@ "homepage": "https://github.com/googleapis/google-cloud-node/tree/main/packages/google-cloud-bigquery-datatransfer", "main": "build/src/index.js", "files": [ - "build/protos", "build/src", "!build/src/**/*.map" ], diff --git a/packages/google-cloud-bigquery-migration/package.json b/packages/google-cloud-bigquery-migration/package.json index 3327bb76974b..15a29b016a8d 100644 --- a/packages/google-cloud-bigquery-migration/package.json +++ b/packages/google-cloud-bigquery-migration/package.json @@ -11,8 +11,7 @@ "author": "Google LLC", "main": "build/src/index.js", "files": [ - "build/src", - "build/protos" + "build/src" ], "keywords": [ "google apis client", diff --git a/packages/google-cloud-bigquery-reservation/package.json b/packages/google-cloud-bigquery-reservation/package.json index 6920ef193933..0164d5bb5c1d 100644 --- a/packages/google-cloud-bigquery-reservation/package.json +++ b/packages/google-cloud-bigquery-reservation/package.json @@ -13,7 +13,6 @@ "main": "build/src/index.js", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "keywords": [ diff --git a/packages/google-cloud-billing-budgets/package.json b/packages/google-cloud-billing-budgets/package.json index 55b33bde7556..2cb2e0dcff53 100644 --- a/packages/google-cloud-billing-budgets/package.json +++ b/packages/google-cloud-billing-budgets/package.json @@ -11,7 +11,6 @@ "main": "build/src/index.js", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "devDependencies": { diff --git a/packages/google-cloud-billing/package.json b/packages/google-cloud-billing/package.json index 6b5758d6eaeb..bf31c367632a 100644 --- a/packages/google-cloud-billing/package.json +++ b/packages/google-cloud-billing/package.json @@ -11,7 +11,6 @@ "author": "Google LLC", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "main": "build/src/index.js", diff --git a/packages/google-cloud-binaryauthorization/package.json b/packages/google-cloud-binaryauthorization/package.json index 82f50c373bc2..fa567d24883f 100644 --- a/packages/google-cloud-binaryauthorization/package.json +++ b/packages/google-cloud-binaryauthorization/package.json @@ -12,7 +12,6 @@ "main": "build/src/index.js", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "keywords": [ diff --git a/packages/google-cloud-capacityplanner/package.json b/packages/google-cloud-capacityplanner/package.json index 036385eab352..4d2636e022fb 100644 --- a/packages/google-cloud-capacityplanner/package.json +++ b/packages/google-cloud-capacityplanner/package.json @@ -11,8 +11,7 @@ "author": "Google LLC", "main": "build/src/index.js", "files": [ - "build/src", - "build/protos" + "build/src" ], "homepage": "https://github.com/googleapis/google-cloud-node/tree/main/packages/google-cloud-capacityplanner", "keywords": [ diff --git a/packages/google-cloud-certificatemanager/package.json b/packages/google-cloud-certificatemanager/package.json index a7d0c4af0e3c..fd9aa5a25250 100644 --- a/packages/google-cloud-certificatemanager/package.json +++ b/packages/google-cloud-certificatemanager/package.json @@ -13,7 +13,6 @@ "main": "build/src/index.js", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "keywords": [ diff --git a/packages/google-cloud-ces/package.json b/packages/google-cloud-ces/package.json index 6f6142b5f4e6..93f4a6a41618 100644 --- a/packages/google-cloud-ces/package.json +++ b/packages/google-cloud-ces/package.json @@ -11,8 +11,7 @@ "author": "Google LLC", "main": "build/src/index.js", "files": [ - "build/src", - "build/protos" + "build/src" ], "homepage": "https://github.com/googleapis/google-cloud-node/tree/main/packages/google-cloud-ces", "keywords": [ diff --git a/packages/google-cloud-channel/package.json b/packages/google-cloud-channel/package.json index da1a4e4066c5..5a6f0b8554fa 100644 --- a/packages/google-cloud-channel/package.json +++ b/packages/google-cloud-channel/package.json @@ -12,7 +12,6 @@ "main": "build/src/index.js", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "keywords": [ diff --git a/packages/google-cloud-chronicle/package.json b/packages/google-cloud-chronicle/package.json index 27822363cdca..925367099268 100644 --- a/packages/google-cloud-chronicle/package.json +++ b/packages/google-cloud-chronicle/package.json @@ -11,8 +11,7 @@ "author": "Google LLC", "main": "build/src/index.js", "files": [ - "build/src", - "build/protos" + "build/src" ], "homepage": "https://github.com/googleapis/google-cloud-node/tree/main/packages/google-cloud-chronicle", "keywords": [ diff --git a/packages/google-cloud-cloudcontrolspartner/package.json b/packages/google-cloud-cloudcontrolspartner/package.json index 4a8f2ecf4f6f..f250a144ae49 100644 --- a/packages/google-cloud-cloudcontrolspartner/package.json +++ b/packages/google-cloud-cloudcontrolspartner/package.json @@ -11,8 +11,7 @@ "author": "Google LLC", "main": "build/src/index.js", "files": [ - "build/src", - "build/protos" + "build/src" ], "homepage": "https://github.com/googleapis/google-cloud-node/tree/main/packages/google-cloud-cloudcontrolspartner", "keywords": [ diff --git a/packages/google-cloud-clouddms/package.json b/packages/google-cloud-clouddms/package.json index 54a3d19047ea..7c21f65d335b 100644 --- a/packages/google-cloud-clouddms/package.json +++ b/packages/google-cloud-clouddms/package.json @@ -15,7 +15,6 @@ "main": "build/src/index.js", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "keywords": [ diff --git a/packages/google-cloud-cloudsecuritycompliance/package.json b/packages/google-cloud-cloudsecuritycompliance/package.json index 6203d043a617..d9ca96278d98 100644 --- a/packages/google-cloud-cloudsecuritycompliance/package.json +++ b/packages/google-cloud-cloudsecuritycompliance/package.json @@ -11,8 +11,7 @@ "author": "Google LLC", "main": "build/src/index.js", "files": [ - "build/src", - "build/protos" + "build/src" ], "homepage": "https://github.com/googleapis/google-cloud-node/tree/main/packages/google-cloud-cloudsecuritycompliance", "keywords": [ diff --git a/packages/google-cloud-commerce-consumer-procurement/package.json b/packages/google-cloud-commerce-consumer-procurement/package.json index 1c3a913ed9cc..ba9aa1fdcece 100644 --- a/packages/google-cloud-commerce-consumer-procurement/package.json +++ b/packages/google-cloud-commerce-consumer-procurement/package.json @@ -11,8 +11,7 @@ "author": "Google LLC", "main": "build/src/index.js", "files": [ - "build/src", - "build/protos" + "build/src" ], "homepage": "https://github.com/googleapis/google-cloud-node/tree/main/packages/google-cloud-commerce-consumer-procurement", "keywords": [ diff --git a/packages/google-cloud-compute/package.json b/packages/google-cloud-compute/package.json index fe7d6a4f1381..98b4abf49881 100644 --- a/packages/google-cloud-compute/package.json +++ b/packages/google-cloud-compute/package.json @@ -15,7 +15,6 @@ "main": "build/src/index.js", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "keywords": [ diff --git a/packages/google-cloud-confidentialcomputing/package.json b/packages/google-cloud-confidentialcomputing/package.json index 9168e7d984dc..5f70ef024598 100644 --- a/packages/google-cloud-confidentialcomputing/package.json +++ b/packages/google-cloud-confidentialcomputing/package.json @@ -11,8 +11,7 @@ "author": "Google LLC", "main": "build/src/index.js", "files": [ - "build/src", - "build/protos" + "build/src" ], "homepage": "https://github.com/googleapis/google-cloud-node/tree/main/packages/google-cloud-confidentialcomputing", "keywords": [ diff --git a/packages/google-cloud-config/package.json b/packages/google-cloud-config/package.json index fabd149c2b67..1d8e3a2a2289 100644 --- a/packages/google-cloud-config/package.json +++ b/packages/google-cloud-config/package.json @@ -11,8 +11,7 @@ "author": "Google LLC", "main": "build/src/index.js", "files": [ - "build/src", - "build/protos" + "build/src" ], "homepage": "https://github.com/googleapis/google-cloud-node/tree/main/packages/google-cloud-config", "keywords": [ diff --git a/packages/google-cloud-configdelivery/package.json b/packages/google-cloud-configdelivery/package.json index 0e4bd820198f..0fc85faa7a3c 100644 --- a/packages/google-cloud-configdelivery/package.json +++ b/packages/google-cloud-configdelivery/package.json @@ -11,8 +11,7 @@ "author": "Google LLC", "main": "build/src/index.js", "files": [ - "build/src", - "build/protos" + "build/src" ], "homepage": "https://github.com/googleapis/google-cloud-node/tree/main/packages/google-cloud-configdelivery", "keywords": [ diff --git a/packages/google-cloud-connectors/package.json b/packages/google-cloud-connectors/package.json index b931ac4a6ca8..58622585086a 100644 --- a/packages/google-cloud-connectors/package.json +++ b/packages/google-cloud-connectors/package.json @@ -11,8 +11,7 @@ "author": "Google LLC", "main": "build/src/index.js", "files": [ - "build/src", - "build/protos" + "build/src" ], "homepage": "https://github.com/googleapis/google-cloud-node/tree/main/packages/google-cloud-connectors", "keywords": [ diff --git a/packages/google-cloud-contactcenterinsights/package.json b/packages/google-cloud-contactcenterinsights/package.json index 9524c38e99fa..a81cee4110ee 100644 --- a/packages/google-cloud-contactcenterinsights/package.json +++ b/packages/google-cloud-contactcenterinsights/package.json @@ -12,7 +12,6 @@ "main": "build/src/index.js", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "keywords": [ diff --git a/packages/google-cloud-contentwarehouse/package.json b/packages/google-cloud-contentwarehouse/package.json index dff48a842a21..60e02b0051b1 100644 --- a/packages/google-cloud-contentwarehouse/package.json +++ b/packages/google-cloud-contentwarehouse/package.json @@ -13,7 +13,6 @@ "main": "build/src/index.js", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "keywords": [ diff --git a/packages/google-cloud-datacatalog-lineage-configmanagement/package.json b/packages/google-cloud-datacatalog-lineage-configmanagement/package.json index 94a4d8004033..2fb0c39d36ab 100644 --- a/packages/google-cloud-datacatalog-lineage-configmanagement/package.json +++ b/packages/google-cloud-datacatalog-lineage-configmanagement/package.json @@ -11,8 +11,7 @@ "author": "Google LLC", "main": "build/src/index.js", "files": [ - "build/src", - "build/protos" + "build/src" ], "homepage": "https://github.com/googleapis/google-cloud-node/tree/main/packages/google-cloud-datacatalog-lineage-configmanagement", "keywords": [ diff --git a/packages/google-cloud-datacatalog-lineage/package.json b/packages/google-cloud-datacatalog-lineage/package.json index b200468c73fc..149148ddcc29 100644 --- a/packages/google-cloud-datacatalog-lineage/package.json +++ b/packages/google-cloud-datacatalog-lineage/package.json @@ -12,7 +12,6 @@ "main": "build/src/index.js", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "homepage": "https://github.com/googleapis/google-cloud-node/tree/main/packages/google-cloud-datacatalog-lineage", diff --git a/packages/google-cloud-datacatalog/package.json b/packages/google-cloud-datacatalog/package.json index e7fb11ad0d9a..c48483866ae3 100644 --- a/packages/google-cloud-datacatalog/package.json +++ b/packages/google-cloud-datacatalog/package.json @@ -11,7 +11,6 @@ "main": "build/src/index.js", "files": [ "build/src", - "build/protos", "AUTHORS", "COPYING", "!build/src/**/*.map" diff --git a/packages/google-cloud-dataform/package.json b/packages/google-cloud-dataform/package.json index ec724f949873..de6c7d9a6735 100644 --- a/packages/google-cloud-dataform/package.json +++ b/packages/google-cloud-dataform/package.json @@ -11,8 +11,7 @@ "author": "Google LLC", "main": "build/src/index.js", "files": [ - "build/src", - "build/protos" + "build/src" ], "homepage": "https://github.com/googleapis/google-cloud-node/tree/main/packages/google-cloud-dataform", "keywords": [ diff --git a/packages/google-cloud-datafusion/package.json b/packages/google-cloud-datafusion/package.json index e914acd929b7..61fc5c436440 100644 --- a/packages/google-cloud-datafusion/package.json +++ b/packages/google-cloud-datafusion/package.json @@ -12,7 +12,6 @@ "main": "build/src/index.js", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "keywords": [ diff --git a/packages/google-cloud-datalabeling/package.json b/packages/google-cloud-datalabeling/package.json index b1a08f1fe461..5f0e60f82cea 100644 --- a/packages/google-cloud-datalabeling/package.json +++ b/packages/google-cloud-datalabeling/package.json @@ -14,7 +14,6 @@ }, "main": "build/src/index.js", "files": [ - "build/protos", "build/src", "!build/src/**/*.map" ], diff --git a/packages/google-cloud-dataplex/package.json b/packages/google-cloud-dataplex/package.json index f9d7e263434f..c5d2d1a9f519 100644 --- a/packages/google-cloud-dataplex/package.json +++ b/packages/google-cloud-dataplex/package.json @@ -13,7 +13,6 @@ "main": "build/src/index.js", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "keywords": [ diff --git a/packages/google-cloud-dataproc/package.json b/packages/google-cloud-dataproc/package.json index f65b9ba66b28..b6abe95c2bbc 100644 --- a/packages/google-cloud-dataproc/package.json +++ b/packages/google-cloud-dataproc/package.json @@ -14,7 +14,6 @@ }, "main": "build/src/index.js", "files": [ - "build/protos", "build/src", "!build/src/**/*.map" ], diff --git a/packages/google-cloud-dataqna/package.json b/packages/google-cloud-dataqna/package.json index 5ada76a9db02..a716065f4dd2 100644 --- a/packages/google-cloud-dataqna/package.json +++ b/packages/google-cloud-dataqna/package.json @@ -12,7 +12,6 @@ "main": "build/src/index.js", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "keywords": [ diff --git a/packages/google-cloud-datastream/package.json b/packages/google-cloud-datastream/package.json index b7e21f25cea7..301a4a0d46c4 100644 --- a/packages/google-cloud-datastream/package.json +++ b/packages/google-cloud-datastream/package.json @@ -12,7 +12,6 @@ "main": "build/src/index.js", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "keywords": [ diff --git a/packages/google-cloud-deploy/package.json b/packages/google-cloud-deploy/package.json index 3368e381b647..0561508ffc95 100644 --- a/packages/google-cloud-deploy/package.json +++ b/packages/google-cloud-deploy/package.json @@ -13,7 +13,6 @@ "main": "build/src/index.js", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "keywords": [ diff --git a/packages/google-cloud-developerconnect/package.json b/packages/google-cloud-developerconnect/package.json index e33e0489c3e4..582d4893831a 100644 --- a/packages/google-cloud-developerconnect/package.json +++ b/packages/google-cloud-developerconnect/package.json @@ -11,8 +11,7 @@ "author": "Google LLC", "main": "build/src/index.js", "files": [ - "build/src", - "build/protos" + "build/src" ], "homepage": "https://github.com/googleapis/google-cloud-node/tree/main/packages/google-cloud-developerconnect", "keywords": [ diff --git a/packages/google-cloud-devicestreaming/package.json b/packages/google-cloud-devicestreaming/package.json index d37f4f234762..e11b65df50ff 100644 --- a/packages/google-cloud-devicestreaming/package.json +++ b/packages/google-cloud-devicestreaming/package.json @@ -11,8 +11,7 @@ "author": "Google LLC", "main": "build/src/index.js", "files": [ - "build/src", - "build/protos" + "build/src" ], "homepage": "https://github.com/googleapis/google-cloud-node/tree/main/packages/google-cloud-devicestreaming", "keywords": [ diff --git a/packages/google-cloud-dialogflow-cx/package.json b/packages/google-cloud-dialogflow-cx/package.json index 0a21a5e82300..9b40d734e88c 100644 --- a/packages/google-cloud-dialogflow-cx/package.json +++ b/packages/google-cloud-dialogflow-cx/package.json @@ -12,7 +12,6 @@ "main": "build/src/index.js", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "keywords": [ diff --git a/packages/google-cloud-dialogflow/package.json b/packages/google-cloud-dialogflow/package.json index 9c8cdd4f026a..ec1d0ab8d186 100644 --- a/packages/google-cloud-dialogflow/package.json +++ b/packages/google-cloud-dialogflow/package.json @@ -14,7 +14,6 @@ }, "main": "build/src/index.js", "files": [ - "build/protos", "build/src", "!build/src/**/*.map" ], diff --git a/packages/google-cloud-discoveryengine/package.json b/packages/google-cloud-discoveryengine/package.json index 9148550e0040..cbf9d50ad917 100644 --- a/packages/google-cloud-discoveryengine/package.json +++ b/packages/google-cloud-discoveryengine/package.json @@ -13,7 +13,6 @@ "main": "build/src/index.js", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "keywords": [ diff --git a/packages/google-cloud-documentai/package.json b/packages/google-cloud-documentai/package.json index 31744e90a877..6bc34b8ca2fc 100644 --- a/packages/google-cloud-documentai/package.json +++ b/packages/google-cloud-documentai/package.json @@ -11,7 +11,6 @@ "author": "Google LLC", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "main": "build/src/index.js", diff --git a/packages/google-cloud-domains/package.json b/packages/google-cloud-domains/package.json index 498ed8c5a408..2b8c7f281ed5 100644 --- a/packages/google-cloud-domains/package.json +++ b/packages/google-cloud-domains/package.json @@ -12,7 +12,6 @@ "main": "build/src/index.js", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "keywords": [ diff --git a/packages/google-cloud-edgecontainer/package.json b/packages/google-cloud-edgecontainer/package.json index 43393263ea42..ae4cbc4817e6 100644 --- a/packages/google-cloud-edgecontainer/package.json +++ b/packages/google-cloud-edgecontainer/package.json @@ -11,8 +11,7 @@ "author": "Google LLC", "main": "build/src/index.js", "files": [ - "build/src", - "build/protos" + "build/src" ], "homepage": "https://github.com/googleapis/google-cloud-node/tree/main/packages/google-cloud-edgecontainer", "keywords": [ diff --git a/packages/google-cloud-edgenetwork/package.json b/packages/google-cloud-edgenetwork/package.json index b8a779798059..9f762ca14e8c 100644 --- a/packages/google-cloud-edgenetwork/package.json +++ b/packages/google-cloud-edgenetwork/package.json @@ -11,8 +11,7 @@ "author": "Google LLC", "main": "build/src/index.js", "files": [ - "build/src", - "build/protos" + "build/src" ], "homepage": "https://github.com/googleapis/google-cloud-node/tree/main/packages/google-cloud-edgenetwork", "keywords": [ diff --git a/packages/google-cloud-essentialcontacts/package.json b/packages/google-cloud-essentialcontacts/package.json index 6238de65fa3b..80729108af26 100644 --- a/packages/google-cloud-essentialcontacts/package.json +++ b/packages/google-cloud-essentialcontacts/package.json @@ -12,7 +12,6 @@ "main": "build/src/index.js", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "keywords": [ diff --git a/packages/google-cloud-eventarc-publishing/package.json b/packages/google-cloud-eventarc-publishing/package.json index 4d561d439114..b48825433c14 100644 --- a/packages/google-cloud-eventarc-publishing/package.json +++ b/packages/google-cloud-eventarc-publishing/package.json @@ -12,7 +12,6 @@ "main": "build/src/index.js", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "keywords": [ diff --git a/packages/google-cloud-eventarc/package.json b/packages/google-cloud-eventarc/package.json index 9149772226b9..ad6224a5a805 100644 --- a/packages/google-cloud-eventarc/package.json +++ b/packages/google-cloud-eventarc/package.json @@ -12,7 +12,6 @@ "main": "build/src/index.js", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "keywords": [ diff --git a/packages/google-cloud-filestore/package.json b/packages/google-cloud-filestore/package.json index be2e1a2aa12d..b9fe19d72289 100644 --- a/packages/google-cloud-filestore/package.json +++ b/packages/google-cloud-filestore/package.json @@ -12,7 +12,6 @@ "main": "build/src/index.js", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "keywords": [ diff --git a/packages/google-cloud-financialservices/package.json b/packages/google-cloud-financialservices/package.json index cc99c51efa83..a78613ca9d91 100644 --- a/packages/google-cloud-financialservices/package.json +++ b/packages/google-cloud-financialservices/package.json @@ -11,8 +11,7 @@ "author": "Google LLC", "main": "build/src/index.js", "files": [ - "build/src", - "build/protos" + "build/src" ], "homepage": "https://github.com/googleapis/google-cloud-node/tree/main/packages/google-cloud-financialservices", "keywords": [ diff --git a/packages/google-cloud-functions/package.json b/packages/google-cloud-functions/package.json index 4bfde7324b73..9535258ffe0e 100644 --- a/packages/google-cloud-functions/package.json +++ b/packages/google-cloud-functions/package.json @@ -12,7 +12,6 @@ "main": "build/src/index.js", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "keywords": [ diff --git a/packages/google-cloud-gdchardwaremanagement/package.json b/packages/google-cloud-gdchardwaremanagement/package.json index daa27a032126..3e1230739292 100644 --- a/packages/google-cloud-gdchardwaremanagement/package.json +++ b/packages/google-cloud-gdchardwaremanagement/package.json @@ -11,8 +11,7 @@ "author": "Google LLC", "main": "build/src/index.js", "files": [ - "build/src", - "build/protos" + "build/src" ], "homepage": "https://github.com/googleapis/google-cloud-node/tree/main/packages/google-cloud-gdchardwaremanagement", "keywords": [ diff --git a/packages/google-cloud-geminidataanalytics/package.json b/packages/google-cloud-geminidataanalytics/package.json index 0a0c332cc5e7..f03e4268af2f 100644 --- a/packages/google-cloud-geminidataanalytics/package.json +++ b/packages/google-cloud-geminidataanalytics/package.json @@ -11,8 +11,7 @@ "author": "Google LLC", "main": "build/src/index.js", "files": [ - "build/src", - "build/protos" + "build/src" ], "homepage": "https://github.com/googleapis/google-cloud-node/tree/main/packages/google-cloud-geminidataanalytics", "keywords": [ diff --git a/packages/google-cloud-gkebackup/package.json b/packages/google-cloud-gkebackup/package.json index 26bd31dec664..816edce7558c 100644 --- a/packages/google-cloud-gkebackup/package.json +++ b/packages/google-cloud-gkebackup/package.json @@ -12,7 +12,6 @@ "main": "build/src/index.js", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "keywords": [ diff --git a/packages/google-cloud-gkeconnect-gateway/package.json b/packages/google-cloud-gkeconnect-gateway/package.json index 35a2f998ee5a..f2ae1c3337e4 100644 --- a/packages/google-cloud-gkeconnect-gateway/package.json +++ b/packages/google-cloud-gkeconnect-gateway/package.json @@ -13,7 +13,6 @@ "main": "build/src/index.js", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "keywords": [ diff --git a/packages/google-cloud-gkehub/package.json b/packages/google-cloud-gkehub/package.json index f666e06f5522..8ecde6aa4132 100644 --- a/packages/google-cloud-gkehub/package.json +++ b/packages/google-cloud-gkehub/package.json @@ -12,7 +12,6 @@ "main": "build/src/index.js", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "keywords": [ diff --git a/packages/google-cloud-gkemulticloud/package.json b/packages/google-cloud-gkemulticloud/package.json index 40d34d63d94c..b98ba4de6126 100644 --- a/packages/google-cloud-gkemulticloud/package.json +++ b/packages/google-cloud-gkemulticloud/package.json @@ -13,7 +13,6 @@ "main": "build/src/index.js", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "keywords": [ diff --git a/packages/google-cloud-gkerecommender/package.json b/packages/google-cloud-gkerecommender/package.json index 03dd14944644..54936e28df31 100644 --- a/packages/google-cloud-gkerecommender/package.json +++ b/packages/google-cloud-gkerecommender/package.json @@ -11,8 +11,7 @@ "author": "Google LLC", "main": "build/src/index.js", "files": [ - "build/src", - "build/protos" + "build/src" ], "homepage": "https://github.com/googleapis/google-cloud-node/tree/main/packages/google-cloud-gkerecommender", "keywords": [ diff --git a/packages/google-cloud-gsuiteaddons/package.json b/packages/google-cloud-gsuiteaddons/package.json index 8409f3d02c40..0faeacf7dc09 100644 --- a/packages/google-cloud-gsuiteaddons/package.json +++ b/packages/google-cloud-gsuiteaddons/package.json @@ -12,7 +12,6 @@ "main": "build/src/index.js", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "homepage": "https://github.com/googleapis/google-cloud-node/tree/main/packages/google-cloud-gsuiteaddons", diff --git a/packages/google-cloud-hypercomputecluster/package.json b/packages/google-cloud-hypercomputecluster/package.json index c8a890a05608..1c4f9fd302ea 100644 --- a/packages/google-cloud-hypercomputecluster/package.json +++ b/packages/google-cloud-hypercomputecluster/package.json @@ -11,8 +11,7 @@ "author": "Google LLC", "main": "build/src/index.js", "files": [ - "build/src", - "build/protos" + "build/src" ], "homepage": "https://github.com/googleapis/google-cloud-node/tree/main/packages/google-cloud-hypercomputecluster", "keywords": [ diff --git a/packages/google-cloud-iap/package.json b/packages/google-cloud-iap/package.json index 751e874f108d..ea9e551a46d4 100644 --- a/packages/google-cloud-iap/package.json +++ b/packages/google-cloud-iap/package.json @@ -12,7 +12,6 @@ "main": "build/src/index.js", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "keywords": [ diff --git a/packages/google-cloud-ids/package.json b/packages/google-cloud-ids/package.json index 21343b4ba784..0ea2c20a889f 100644 --- a/packages/google-cloud-ids/package.json +++ b/packages/google-cloud-ids/package.json @@ -12,7 +12,6 @@ "main": "build/src/index.js", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "keywords": [ diff --git a/packages/google-cloud-iot/package.json b/packages/google-cloud-iot/package.json index bea04c806631..8e0a884c0c39 100644 --- a/packages/google-cloud-iot/package.json +++ b/packages/google-cloud-iot/package.json @@ -14,7 +14,6 @@ }, "main": "build/src/index.js", "files": [ - "build/protos", "build/src", "!build/src/**/*.map" ], diff --git a/packages/google-cloud-kms-inventory/package.json b/packages/google-cloud-kms-inventory/package.json index 63febbeeb37e..8479c5332ac3 100644 --- a/packages/google-cloud-kms-inventory/package.json +++ b/packages/google-cloud-kms-inventory/package.json @@ -12,7 +12,6 @@ "main": "build/src/index.js", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "keywords": [ diff --git a/packages/google-cloud-kms/package.json b/packages/google-cloud-kms/package.json index 2a5f9b8b1cb3..897c59b616ff 100644 --- a/packages/google-cloud-kms/package.json +++ b/packages/google-cloud-kms/package.json @@ -14,7 +14,6 @@ }, "main": "build/src/index.js", "files": [ - "build/protos", "build/src", "!build/src/**/*.map" ], diff --git a/packages/google-cloud-language/package.json b/packages/google-cloud-language/package.json index 1e7fee968379..1f234b812ff7 100644 --- a/packages/google-cloud-language/package.json +++ b/packages/google-cloud-language/package.json @@ -15,7 +15,6 @@ "homepage": "https://github.com/googleapis/google-cloud-node/tree/main/packages/google-cloud-language", "main": "build/src/index.js", "files": [ - "build/protos", "build/src", "AUTHORS", "CONTRIBUTORS", diff --git a/packages/google-cloud-licensemanager/package.json b/packages/google-cloud-licensemanager/package.json index 7841e3b04616..dfffc8fb22fd 100644 --- a/packages/google-cloud-licensemanager/package.json +++ b/packages/google-cloud-licensemanager/package.json @@ -11,8 +11,7 @@ "author": "Google LLC", "main": "build/src/index.js", "files": [ - "build/src", - "build/protos" + "build/src" ], "homepage": "https://github.com/googleapis/google-cloud-node/tree/main/packages/google-cloud-licensemanager", "keywords": [ diff --git a/packages/google-cloud-lifesciences/package.json b/packages/google-cloud-lifesciences/package.json index 823026f96ef2..e05721854e69 100644 --- a/packages/google-cloud-lifesciences/package.json +++ b/packages/google-cloud-lifesciences/package.json @@ -12,7 +12,6 @@ "main": "build/src/index.js", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "keywords": [ diff --git a/packages/google-cloud-locationfinder/package.json b/packages/google-cloud-locationfinder/package.json index 8797e696df46..a3eee0df79f0 100644 --- a/packages/google-cloud-locationfinder/package.json +++ b/packages/google-cloud-locationfinder/package.json @@ -11,8 +11,7 @@ "author": "Google LLC", "main": "build/src/index.js", "files": [ - "build/src", - "build/protos" + "build/src" ], "homepage": "https://github.com/googleapis/google-cloud-node/tree/main/packages/google-cloud-locationfinder", "keywords": [ diff --git a/packages/google-cloud-lustre/package.json b/packages/google-cloud-lustre/package.json index ef51c87c0397..2dec5ce19723 100644 --- a/packages/google-cloud-lustre/package.json +++ b/packages/google-cloud-lustre/package.json @@ -11,8 +11,7 @@ "author": "Google LLC", "main": "build/src/index.js", "files": [ - "build/src", - "build/protos" + "build/src" ], "homepage": "https://github.com/googleapis/google-cloud-node/tree/main/packages/google-cloud-lustre", "keywords": [ diff --git a/packages/google-cloud-maintenance-api/package.json b/packages/google-cloud-maintenance-api/package.json index 9bef47ad6503..5cf3052338b0 100644 --- a/packages/google-cloud-maintenance-api/package.json +++ b/packages/google-cloud-maintenance-api/package.json @@ -11,8 +11,7 @@ "author": "Google LLC", "main": "build/src/index.js", "files": [ - "build/src", - "build/protos" + "build/src" ], "homepage": "https://github.com/googleapis/google-cloud-node/tree/main/packages/google-cloud-maintenance-api", "keywords": [ diff --git a/packages/google-cloud-managedidentities/package.json b/packages/google-cloud-managedidentities/package.json index bd7b1c68eb7e..cd14199d803a 100644 --- a/packages/google-cloud-managedidentities/package.json +++ b/packages/google-cloud-managedidentities/package.json @@ -12,7 +12,6 @@ "main": "build/src/index.js", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "keywords": [ diff --git a/packages/google-cloud-managedkafka-schemaregistry/package.json b/packages/google-cloud-managedkafka-schemaregistry/package.json index b632bee45700..e266a6714c81 100644 --- a/packages/google-cloud-managedkafka-schemaregistry/package.json +++ b/packages/google-cloud-managedkafka-schemaregistry/package.json @@ -11,8 +11,7 @@ "author": "Google LLC", "main": "build/src/index.js", "files": [ - "build/src", - "build/protos" + "build/src" ], "homepage": "https://github.com/googleapis/google-cloud-node/tree/main/packages/google-cloud-managedkafka-schemaregistry", "keywords": [ diff --git a/packages/google-cloud-managedkafka/package.json b/packages/google-cloud-managedkafka/package.json index f2971ecedcf3..344e59aeb8e8 100644 --- a/packages/google-cloud-managedkafka/package.json +++ b/packages/google-cloud-managedkafka/package.json @@ -11,8 +11,7 @@ "author": "Google LLC", "main": "build/src/index.js", "files": [ - "build/src", - "build/protos" + "build/src" ], "homepage": "https://github.com/googleapis/google-cloud-node/tree/main/packages/google-cloud-managedkafka", "keywords": [ diff --git a/packages/google-cloud-mediatranslation/package.json b/packages/google-cloud-mediatranslation/package.json index c57e69b8314e..b61a55a24d7c 100644 --- a/packages/google-cloud-mediatranslation/package.json +++ b/packages/google-cloud-mediatranslation/package.json @@ -11,7 +11,6 @@ "author": "Google LLC", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "main": "build/src/index.js", diff --git a/packages/google-cloud-memcache/package.json b/packages/google-cloud-memcache/package.json index 0e96d438d49f..c8936ce49316 100644 --- a/packages/google-cloud-memcache/package.json +++ b/packages/google-cloud-memcache/package.json @@ -13,7 +13,6 @@ "main": "build/src/index.js", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "scripts": { diff --git a/packages/google-cloud-memorystore/package.json b/packages/google-cloud-memorystore/package.json index 3555f35a0204..c8aa61f28329 100644 --- a/packages/google-cloud-memorystore/package.json +++ b/packages/google-cloud-memorystore/package.json @@ -11,8 +11,7 @@ "author": "Google LLC", "main": "build/src/index.js", "files": [ - "build/src", - "build/protos" + "build/src" ], "homepage": "https://github.com/googleapis/google-cloud-node/tree/main/packages/google-cloud-memorystore", "keywords": [ diff --git a/packages/google-cloud-metastore/package.json b/packages/google-cloud-metastore/package.json index aea12215ebac..0fd1bd10682d 100644 --- a/packages/google-cloud-metastore/package.json +++ b/packages/google-cloud-metastore/package.json @@ -12,7 +12,6 @@ "main": "build/src/index.js", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "keywords": [ diff --git a/packages/google-cloud-migrationcenter/package.json b/packages/google-cloud-migrationcenter/package.json index c300a93ce876..1bdda5796adf 100644 --- a/packages/google-cloud-migrationcenter/package.json +++ b/packages/google-cloud-migrationcenter/package.json @@ -11,8 +11,7 @@ "author": "Google LLC", "main": "build/src/index.js", "files": [ - "build/src", - "build/protos" + "build/src" ], "homepage": "https://github.com/googleapis/google-cloud-node/tree/main/packages/google-cloud-migrationcenter", "keywords": [ diff --git a/packages/google-cloud-modelarmor/package.json b/packages/google-cloud-modelarmor/package.json index 71da28620250..38af82f7e1ea 100644 --- a/packages/google-cloud-modelarmor/package.json +++ b/packages/google-cloud-modelarmor/package.json @@ -11,8 +11,7 @@ "author": "Google LLC", "main": "build/src/index.js", "files": [ - "build/src", - "build/protos" + "build/src" ], "homepage": "https://github.com/googleapis/google-cloud-node/tree/main/packages/google-cloud-modelarmor", "keywords": [ diff --git a/packages/google-cloud-monitoring/package.json b/packages/google-cloud-monitoring/package.json index 47b2a38ac121..91f7686015b9 100644 --- a/packages/google-cloud-monitoring/package.json +++ b/packages/google-cloud-monitoring/package.json @@ -15,7 +15,6 @@ "main": "build/src/index.js", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "keywords": [ diff --git a/packages/google-cloud-netapp/package.json b/packages/google-cloud-netapp/package.json index 65bd700ed5e0..fa24d3461ebf 100644 --- a/packages/google-cloud-netapp/package.json +++ b/packages/google-cloud-netapp/package.json @@ -11,8 +11,7 @@ "author": "Google LLC", "main": "build/src/index.js", "files": [ - "build/src", - "build/protos" + "build/src" ], "homepage": "https://github.com/googleapis/google-cloud-node/tree/main/packages/google-cloud-netapp", "keywords": [ diff --git a/packages/google-cloud-networkconnectivity/package.json b/packages/google-cloud-networkconnectivity/package.json index 6e053c7ff1e5..1fdd7a98efb7 100644 --- a/packages/google-cloud-networkconnectivity/package.json +++ b/packages/google-cloud-networkconnectivity/package.json @@ -12,7 +12,6 @@ "main": "build/src/index.js", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "keywords": [ diff --git a/packages/google-cloud-networkmanagement/package.json b/packages/google-cloud-networkmanagement/package.json index 5b489227d809..b1bde7733493 100644 --- a/packages/google-cloud-networkmanagement/package.json +++ b/packages/google-cloud-networkmanagement/package.json @@ -12,7 +12,6 @@ "main": "build/src/index.js", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "keywords": [ diff --git a/packages/google-cloud-networksecurity/package.json b/packages/google-cloud-networksecurity/package.json index 40e35985e725..c6526bc4dec4 100644 --- a/packages/google-cloud-networksecurity/package.json +++ b/packages/google-cloud-networksecurity/package.json @@ -12,7 +12,6 @@ "main": "build/src/index.js", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "keywords": [ diff --git a/packages/google-cloud-networkservices/package.json b/packages/google-cloud-networkservices/package.json index 580657039847..d84593847ec4 100644 --- a/packages/google-cloud-networkservices/package.json +++ b/packages/google-cloud-networkservices/package.json @@ -11,8 +11,7 @@ "author": "Google LLC", "main": "build/src/index.js", "files": [ - "build/src", - "build/protos" + "build/src" ], "homepage": "https://github.com/googleapis/google-cloud-node/tree/main/packages/google-cloud-networkservices", "keywords": [ diff --git a/packages/google-cloud-notebooks/package.json b/packages/google-cloud-notebooks/package.json index e31df74385e6..b8a49b16bfca 100644 --- a/packages/google-cloud-notebooks/package.json +++ b/packages/google-cloud-notebooks/package.json @@ -12,7 +12,6 @@ "main": "build/src/index.js", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "keywords": [ diff --git a/packages/google-cloud-oracledatabase/package.json b/packages/google-cloud-oracledatabase/package.json index fe422f296afe..1fd7e20b8731 100644 --- a/packages/google-cloud-oracledatabase/package.json +++ b/packages/google-cloud-oracledatabase/package.json @@ -11,8 +11,7 @@ "author": "Google LLC", "main": "build/src/index.js", "files": [ - "build/src", - "build/protos" + "build/src" ], "homepage": "https://github.com/googleapis/google-cloud-node/tree/main/packages/google-cloud-oracledatabase", "keywords": [ diff --git a/packages/google-cloud-orchestration-airflow-service/package.json b/packages/google-cloud-orchestration-airflow-service/package.json index 0eb52f7c894c..eb827ae8437a 100644 --- a/packages/google-cloud-orchestration-airflow-service/package.json +++ b/packages/google-cloud-orchestration-airflow-service/package.json @@ -12,7 +12,6 @@ "main": "build/src/index.js", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "keywords": [ diff --git a/packages/google-cloud-orgpolicy/package.json b/packages/google-cloud-orgpolicy/package.json index f9a597d2fbcb..4525dde631da 100644 --- a/packages/google-cloud-orgpolicy/package.json +++ b/packages/google-cloud-orgpolicy/package.json @@ -12,7 +12,6 @@ "main": "build/src/index.js", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "keywords": [ diff --git a/packages/google-cloud-osconfig/package.json b/packages/google-cloud-osconfig/package.json index c87e8a6f2566..95ac39c88dfc 100644 --- a/packages/google-cloud-osconfig/package.json +++ b/packages/google-cloud-osconfig/package.json @@ -12,7 +12,6 @@ "main": "build/src/index.js", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "scripts": { diff --git a/packages/google-cloud-oslogin/package.json b/packages/google-cloud-oslogin/package.json index 25fa1fc97696..ce0346e79b01 100644 --- a/packages/google-cloud-oslogin/package.json +++ b/packages/google-cloud-oslogin/package.json @@ -15,7 +15,6 @@ "homepage": "https://github.com/googleapis/google-cloud-node/tree/main/packages/google-cloud-oslogin", "main": "build/src/index.js", "files": [ - "build/protos", "build/src", "AUTHORS", "COPYING", diff --git a/packages/google-cloud-parallelstore/package.json b/packages/google-cloud-parallelstore/package.json index f6516cc47f96..ec8e1bf674aa 100644 --- a/packages/google-cloud-parallelstore/package.json +++ b/packages/google-cloud-parallelstore/package.json @@ -11,8 +11,7 @@ "author": "Google LLC", "main": "build/src/index.js", "files": [ - "build/src", - "build/protos" + "build/src" ], "homepage": "https://github.com/googleapis/google-cloud-node/tree/main/packages/google-cloud-parallelstore", "keywords": [ diff --git a/packages/google-cloud-parametermanager/package.json b/packages/google-cloud-parametermanager/package.json index 08526ba3e788..bc9e66066a36 100644 --- a/packages/google-cloud-parametermanager/package.json +++ b/packages/google-cloud-parametermanager/package.json @@ -11,8 +11,7 @@ "author": "Google LLC", "main": "build/src/index.js", "files": [ - "build/src", - "build/protos" + "build/src" ], "homepage": "https://github.com/googleapis/google-cloud-node/tree/main/packages/google-cloud-parametermanager", "keywords": [ diff --git a/packages/google-cloud-phishingprotection/package.json b/packages/google-cloud-phishingprotection/package.json index b9d3d1504cec..c623b4afe2f9 100644 --- a/packages/google-cloud-phishingprotection/package.json +++ b/packages/google-cloud-phishingprotection/package.json @@ -11,7 +11,6 @@ "description": "Phishing Protection API client for Node.js", "main": "build/src/index.js", "files": [ - "build/protos", "build/src", "!build/src/**/*.map" ], diff --git a/packages/google-cloud-policysimulator/package.json b/packages/google-cloud-policysimulator/package.json index eda18a7d008f..f6afe35edad0 100644 --- a/packages/google-cloud-policysimulator/package.json +++ b/packages/google-cloud-policysimulator/package.json @@ -11,8 +11,7 @@ "author": "Google LLC", "main": "build/src/index.js", "files": [ - "build/src", - "build/protos" + "build/src" ], "homepage": "https://github.com/googleapis/google-cloud-node/tree/main/packages/google-cloud-policysimulator", "keywords": [ diff --git a/packages/google-cloud-policytroubleshooter-iam/package.json b/packages/google-cloud-policytroubleshooter-iam/package.json index 630a8da306e1..43d2166ee720 100644 --- a/packages/google-cloud-policytroubleshooter-iam/package.json +++ b/packages/google-cloud-policytroubleshooter-iam/package.json @@ -11,8 +11,7 @@ "author": "Google LLC", "main": "build/src/index.js", "files": [ - "build/src", - "build/protos" + "build/src" ], "keywords": [ "google apis client", diff --git a/packages/google-cloud-policytroubleshooter/package.json b/packages/google-cloud-policytroubleshooter/package.json index 7cb0e448f488..a93e968f7b83 100644 --- a/packages/google-cloud-policytroubleshooter/package.json +++ b/packages/google-cloud-policytroubleshooter/package.json @@ -13,7 +13,6 @@ "main": "build/src/index.js", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "keywords": [ diff --git a/packages/google-cloud-privatecatalog/package.json b/packages/google-cloud-privatecatalog/package.json index 65dead7e5191..3d4c6b1a04a9 100644 --- a/packages/google-cloud-privatecatalog/package.json +++ b/packages/google-cloud-privatecatalog/package.json @@ -12,7 +12,6 @@ "main": "build/src/index.js", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "keywords": [ diff --git a/packages/google-cloud-privilegedaccessmanager/package.json b/packages/google-cloud-privilegedaccessmanager/package.json index 89cf305fe242..4a5fb8cdefb0 100644 --- a/packages/google-cloud-privilegedaccessmanager/package.json +++ b/packages/google-cloud-privilegedaccessmanager/package.json @@ -11,8 +11,7 @@ "author": "Google LLC", "main": "build/src/index.js", "files": [ - "build/src", - "build/protos" + "build/src" ], "homepage": "https://github.com/googleapis/google-cloud-node/tree/main/packages/google-cloud-privilegedaccessmanager", "keywords": [ diff --git a/packages/google-cloud-rapidmigrationassessment/package.json b/packages/google-cloud-rapidmigrationassessment/package.json index 2803740c7afb..b5e3a35239a3 100644 --- a/packages/google-cloud-rapidmigrationassessment/package.json +++ b/packages/google-cloud-rapidmigrationassessment/package.json @@ -11,8 +11,7 @@ "author": "Google LLC", "main": "build/src/index.js", "files": [ - "build/src", - "build/protos" + "build/src" ], "homepage": "https://github.com/googleapis/google-cloud-node/tree/main/packages/google-cloud-rapidmigrationassessment", "keywords": [ diff --git a/packages/google-cloud-recaptchaenterprise/package.json b/packages/google-cloud-recaptchaenterprise/package.json index 61c626a44767..8cd9cb298989 100644 --- a/packages/google-cloud-recaptchaenterprise/package.json +++ b/packages/google-cloud-recaptchaenterprise/package.json @@ -10,7 +10,6 @@ "description": "reCAPTCHA Enterprise API client for Node.js", "main": "build/src/index.js", "files": [ - "build/protos", "build/src", "AUTHORS", "COPYING", diff --git a/packages/google-cloud-recommender/package.json b/packages/google-cloud-recommender/package.json index 7b05024d5c10..aaeeea8c4587 100644 --- a/packages/google-cloud-recommender/package.json +++ b/packages/google-cloud-recommender/package.json @@ -12,7 +12,6 @@ "author": "Google LLC", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "main": "build/src/index.js", diff --git a/packages/google-cloud-redis-cluster/package.json b/packages/google-cloud-redis-cluster/package.json index b6e680951cc9..20f80ab8711d 100644 --- a/packages/google-cloud-redis-cluster/package.json +++ b/packages/google-cloud-redis-cluster/package.json @@ -11,8 +11,7 @@ "author": "Google LLC", "main": "build/src/index.js", "files": [ - "build/src", - "build/protos" + "build/src" ], "homepage": "https://github.com/googleapis/google-cloud-node/tree/main/packages/google-cloud-redis-cluster", "keywords": [ diff --git a/packages/google-cloud-redis/package.json b/packages/google-cloud-redis/package.json index 1cc16ca7c98e..ab65a4e8022f 100644 --- a/packages/google-cloud-redis/package.json +++ b/packages/google-cloud-redis/package.json @@ -15,7 +15,6 @@ "homepage": "https://github.com/googleapis/google-cloud-node/tree/main/packages/google-cloud-redis", "main": "build/src/index.js", "files": [ - "build/protos", "build/src", "!build/src/**/*.map" ], diff --git a/packages/google-cloud-resourcemanager/package.json b/packages/google-cloud-resourcemanager/package.json index 495304ce738e..513f77b6a8b3 100644 --- a/packages/google-cloud-resourcemanager/package.json +++ b/packages/google-cloud-resourcemanager/package.json @@ -17,7 +17,6 @@ "types": "./build/src/index.d.ts", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "keywords": [ diff --git a/packages/google-cloud-retail/package.json b/packages/google-cloud-retail/package.json index 2ed434e78791..eb54aff7be04 100644 --- a/packages/google-cloud-retail/package.json +++ b/packages/google-cloud-retail/package.json @@ -12,7 +12,6 @@ "main": "build/src/index.js", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "keywords": [ diff --git a/packages/google-cloud-run/package.json b/packages/google-cloud-run/package.json index 2ca3429b94fe..2bedef3bfe94 100644 --- a/packages/google-cloud-run/package.json +++ b/packages/google-cloud-run/package.json @@ -11,7 +11,6 @@ "author": "Google LLC", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "keywords": [ diff --git a/packages/google-cloud-saasplatform-saasservicemgmt/package.json b/packages/google-cloud-saasplatform-saasservicemgmt/package.json index 23698e87a4bf..a33abef9aa42 100644 --- a/packages/google-cloud-saasplatform-saasservicemgmt/package.json +++ b/packages/google-cloud-saasplatform-saasservicemgmt/package.json @@ -11,8 +11,7 @@ "author": "Google LLC", "main": "build/src/index.js", "files": [ - "build/src", - "build/protos" + "build/src" ], "homepage": "https://github.com/googleapis/google-cloud-node/tree/main/packages/google-cloud-saasplatform-saasservicemgmt", "keywords": [ diff --git a/packages/google-cloud-scheduler/package.json b/packages/google-cloud-scheduler/package.json index 31424589034b..e57e0c20e6b9 100644 --- a/packages/google-cloud-scheduler/package.json +++ b/packages/google-cloud-scheduler/package.json @@ -14,7 +14,6 @@ }, "main": "build/src/index.js", "files": [ - "build/protos", "build/src", "!build/src/**/*.map" ], diff --git a/packages/google-cloud-secretmanager/package.json b/packages/google-cloud-secretmanager/package.json index cc9a937d2e0c..7e0701fb6e9e 100644 --- a/packages/google-cloud-secretmanager/package.json +++ b/packages/google-cloud-secretmanager/package.json @@ -11,7 +11,6 @@ "author": "Google LLC", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "keywords": [ diff --git a/packages/google-cloud-securesourcemanager/package.json b/packages/google-cloud-securesourcemanager/package.json index 32689672b885..c75dc068c767 100644 --- a/packages/google-cloud-securesourcemanager/package.json +++ b/packages/google-cloud-securesourcemanager/package.json @@ -11,8 +11,7 @@ "author": "Google LLC", "main": "build/src/index.js", "files": [ - "build/src", - "build/protos" + "build/src" ], "homepage": "https://github.com/googleapis/google-cloud-node/tree/main/packages/google-cloud-securesourcemanager", "keywords": [ diff --git a/packages/google-cloud-security-privateca/package.json b/packages/google-cloud-security-privateca/package.json index cb75c8d81065..1fdb207ceb98 100644 --- a/packages/google-cloud-security-privateca/package.json +++ b/packages/google-cloud-security-privateca/package.json @@ -12,7 +12,6 @@ "main": "build/src/index.js", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "keywords": [ diff --git a/packages/google-cloud-security-publicca/package.json b/packages/google-cloud-security-publicca/package.json index f8d637b78cdf..57f8e77c6efe 100644 --- a/packages/google-cloud-security-publicca/package.json +++ b/packages/google-cloud-security-publicca/package.json @@ -13,7 +13,6 @@ "main": "build/src/index.js", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "keywords": [ diff --git a/packages/google-cloud-securitycenter/package.json b/packages/google-cloud-securitycenter/package.json index d7a4c3f08a20..81fff4d17495 100644 --- a/packages/google-cloud-securitycenter/package.json +++ b/packages/google-cloud-securitycenter/package.json @@ -14,7 +14,6 @@ }, "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "main": "build/src/index.js", diff --git a/packages/google-cloud-securitycentermanagement/package.json b/packages/google-cloud-securitycentermanagement/package.json index a892c12b1892..664f8fef393f 100644 --- a/packages/google-cloud-securitycentermanagement/package.json +++ b/packages/google-cloud-securitycentermanagement/package.json @@ -11,8 +11,7 @@ "author": "Google LLC", "main": "build/src/index.js", "files": [ - "build/src", - "build/protos" + "build/src" ], "homepage": "https://github.com/googleapis/google-cloud-node/tree/main/packages/google-cloud-securitycentermanagement", "keywords": [ diff --git a/packages/google-cloud-servicedirectory/package.json b/packages/google-cloud-servicedirectory/package.json index 9e13a0e424b8..38991f9a9c1d 100644 --- a/packages/google-cloud-servicedirectory/package.json +++ b/packages/google-cloud-servicedirectory/package.json @@ -11,7 +11,6 @@ "author": "Google LLC", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "main": "build/src/index.js", diff --git a/packages/google-cloud-servicehealth/package.json b/packages/google-cloud-servicehealth/package.json index a39f895ce54f..7f4afdef7983 100644 --- a/packages/google-cloud-servicehealth/package.json +++ b/packages/google-cloud-servicehealth/package.json @@ -11,8 +11,7 @@ "author": "Google LLC", "main": "build/src/index.js", "files": [ - "build/src", - "build/protos" + "build/src" ], "homepage": "https://github.com/googleapis/google-cloud-node/tree/main/packages/google-cloud-servicehealth", "keywords": [ diff --git a/packages/google-cloud-shell/package.json b/packages/google-cloud-shell/package.json index 6af9a5bcd6ed..165a43be404d 100644 --- a/packages/google-cloud-shell/package.json +++ b/packages/google-cloud-shell/package.json @@ -13,7 +13,6 @@ "main": "build/src/index.js", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "keywords": [ diff --git a/packages/google-cloud-speech/package.json b/packages/google-cloud-speech/package.json index 1e2c1f3648e8..e3660fc2d2be 100644 --- a/packages/google-cloud-speech/package.json +++ b/packages/google-cloud-speech/package.json @@ -14,7 +14,6 @@ }, "main": "./build/src/index.js", "files": [ - "build/protos", "build/src", "AUTHORS", "LICENSE", diff --git a/packages/google-cloud-sql/package.json b/packages/google-cloud-sql/package.json index 1bcee49d2c3b..e7fc8484b20c 100644 --- a/packages/google-cloud-sql/package.json +++ b/packages/google-cloud-sql/package.json @@ -12,8 +12,7 @@ "author": "Google LLC", "main": "build/src/index.js", "files": [ - "build/src", - "build/protos" + "build/src" ], "keywords": [ "google apis client", diff --git a/packages/google-cloud-storagebatchoperations/package.json b/packages/google-cloud-storagebatchoperations/package.json index 36851693093c..3579a24f0c34 100644 --- a/packages/google-cloud-storagebatchoperations/package.json +++ b/packages/google-cloud-storagebatchoperations/package.json @@ -11,8 +11,7 @@ "author": "Google LLC", "main": "build/src/index.js", "files": [ - "build/src", - "build/protos" + "build/src" ], "homepage": "https://github.com/googleapis/google-cloud-node/tree/main/packages/google-cloud-storagebatchoperations", "keywords": [ diff --git a/packages/google-cloud-storageinsights/package.json b/packages/google-cloud-storageinsights/package.json index 44a056e855f9..11c51292f0bc 100644 --- a/packages/google-cloud-storageinsights/package.json +++ b/packages/google-cloud-storageinsights/package.json @@ -11,8 +11,7 @@ "author": "Google LLC", "main": "build/src/index.js", "files": [ - "build/src", - "build/protos" + "build/src" ], "homepage": "https://github.com/googleapis/google-cloud-node/tree/main/packages/google-cloud-storageinsights", "keywords": [ diff --git a/packages/google-cloud-support/package.json b/packages/google-cloud-support/package.json index 4aa01d27af77..fe41ce90d844 100644 --- a/packages/google-cloud-support/package.json +++ b/packages/google-cloud-support/package.json @@ -11,8 +11,7 @@ "author": "Google LLC", "main": "build/src/index.js", "files": [ - "build/src", - "build/protos" + "build/src" ], "homepage": "https://github.com/googleapis/google-cloud-node/tree/main/packages/google-cloud-support", "keywords": [ diff --git a/packages/google-cloud-talent/package.json b/packages/google-cloud-talent/package.json index 8ce162d521ba..5264228fd428 100644 --- a/packages/google-cloud-talent/package.json +++ b/packages/google-cloud-talent/package.json @@ -14,7 +14,6 @@ }, "main": "build/src/index.js", "files": [ - "build/protos", "build/src", "!build/src/**/*.map" ], diff --git a/packages/google-cloud-telcoautomation/package.json b/packages/google-cloud-telcoautomation/package.json index 8e545a45eeb0..27dba675fe65 100644 --- a/packages/google-cloud-telcoautomation/package.json +++ b/packages/google-cloud-telcoautomation/package.json @@ -11,8 +11,7 @@ "author": "Google LLC", "main": "build/src/index.js", "files": [ - "build/src", - "build/protos" + "build/src" ], "homepage": "https://github.com/googleapis/google-cloud-node/tree/main/packages/google-cloud-telcoautomation", "keywords": [ diff --git a/packages/google-cloud-texttospeech/package.json b/packages/google-cloud-texttospeech/package.json index b8869e4ca20b..4491bf003e2f 100644 --- a/packages/google-cloud-texttospeech/package.json +++ b/packages/google-cloud-texttospeech/package.json @@ -14,7 +14,6 @@ }, "main": "build/src/index.js", "files": [ - "build/protos", "build/src", "!build/src/**/*.map" ], diff --git a/packages/google-cloud-tpu/package.json b/packages/google-cloud-tpu/package.json index 96b34e790eb6..a2357c17c13e 100644 --- a/packages/google-cloud-tpu/package.json +++ b/packages/google-cloud-tpu/package.json @@ -12,7 +12,6 @@ "main": "build/src/index.js", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "keywords": [ diff --git a/packages/google-cloud-translate/package.json b/packages/google-cloud-translate/package.json index 5da83865c29f..ff069882945f 100644 --- a/packages/google-cloud-translate/package.json +++ b/packages/google-cloud-translate/package.json @@ -16,7 +16,6 @@ "types": "build/src/index.d.ts", "files": [ "build/src", - "build/protos", "!build/src/**/*.map", "!build/src/**/*.map" ], diff --git a/packages/google-cloud-vectorsearch/package.json b/packages/google-cloud-vectorsearch/package.json index 74982db39501..8ea3a769e6d1 100644 --- a/packages/google-cloud-vectorsearch/package.json +++ b/packages/google-cloud-vectorsearch/package.json @@ -11,8 +11,7 @@ "author": "Google LLC", "main": "build/src/index.js", "files": [ - "build/src", - "build/protos" + "build/src" ], "homepage": "https://github.com/googleapis/google-cloud-node/tree/main/packages/google-cloud-vectorsearch", "keywords": [ diff --git a/packages/google-cloud-video-livestream/package.json b/packages/google-cloud-video-livestream/package.json index 23ca35dbe24f..592a34d916e3 100644 --- a/packages/google-cloud-video-livestream/package.json +++ b/packages/google-cloud-video-livestream/package.json @@ -12,7 +12,6 @@ "main": "build/src/index.js", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "keywords": [ diff --git a/packages/google-cloud-video-stitcher/package.json b/packages/google-cloud-video-stitcher/package.json index 2511ba940485..257f729fc5ab 100644 --- a/packages/google-cloud-video-stitcher/package.json +++ b/packages/google-cloud-video-stitcher/package.json @@ -12,7 +12,6 @@ "main": "build/src/index.js", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "keywords": [ diff --git a/packages/google-cloud-video-transcoder/package.json b/packages/google-cloud-video-transcoder/package.json index 1e2096fe9337..d5f6313ff4eb 100644 --- a/packages/google-cloud-video-transcoder/package.json +++ b/packages/google-cloud-video-transcoder/package.json @@ -12,7 +12,6 @@ "main": "build/src/index.js", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "keywords": [ diff --git a/packages/google-cloud-videointelligence/package.json b/packages/google-cloud-videointelligence/package.json index 4abd179afb17..7f95cea664e0 100644 --- a/packages/google-cloud-videointelligence/package.json +++ b/packages/google-cloud-videointelligence/package.json @@ -14,7 +14,6 @@ }, "main": "build/src/index.js", "files": [ - "build/protos", "build/src", "LICENSE", "!build/src/**/*.map" diff --git a/packages/google-cloud-vision/package.json b/packages/google-cloud-vision/package.json index 9a7e7517108c..e2904818b1df 100644 --- a/packages/google-cloud-vision/package.json +++ b/packages/google-cloud-vision/package.json @@ -15,7 +15,6 @@ "main": "build/src/index.js", "types": "build/src/index.d.ts", "files": [ - "build/protos", "build/src", "!build/src/**/*.map" ], diff --git a/packages/google-cloud-visionai/package.json b/packages/google-cloud-visionai/package.json index 3dab6549b7ce..a3abcd03faec 100644 --- a/packages/google-cloud-visionai/package.json +++ b/packages/google-cloud-visionai/package.json @@ -11,8 +11,7 @@ "author": "Google LLC", "main": "build/src/index.js", "files": [ - "build/src", - "build/protos" + "build/src" ], "homepage": "https://github.com/googleapis/google-cloud-node/tree/main/packages/google-cloud-visionai", "keywords": [ diff --git a/packages/google-cloud-vmmigration/package.json b/packages/google-cloud-vmmigration/package.json index 023ff779d106..b887dbd35a9b 100644 --- a/packages/google-cloud-vmmigration/package.json +++ b/packages/google-cloud-vmmigration/package.json @@ -12,7 +12,6 @@ "main": "build/src/index.js", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "keywords": [ diff --git a/packages/google-cloud-vmwareengine/package.json b/packages/google-cloud-vmwareengine/package.json index 6d234f852114..2f7e4efee1b7 100644 --- a/packages/google-cloud-vmwareengine/package.json +++ b/packages/google-cloud-vmwareengine/package.json @@ -12,7 +12,6 @@ "main": "build/src/index.js", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "homepage": "https://github.com/googleapis/google-cloud-node/tree/main/packages/google-cloud-vmwareengine", diff --git a/packages/google-cloud-vpcaccess/package.json b/packages/google-cloud-vpcaccess/package.json index 29e90e030777..cc5165564e66 100644 --- a/packages/google-cloud-vpcaccess/package.json +++ b/packages/google-cloud-vpcaccess/package.json @@ -12,7 +12,6 @@ "main": "build/src/index.js", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "keywords": [ diff --git a/packages/google-cloud-webrisk/package.json b/packages/google-cloud-webrisk/package.json index 9b58e1072aac..21abc5a28e62 100644 --- a/packages/google-cloud-webrisk/package.json +++ b/packages/google-cloud-webrisk/package.json @@ -10,7 +10,6 @@ "description": "Web Risk API client for Node.js", "main": "build/src/index.js", "files": [ - "build/protos", "build/src", "!build/src/**/*.map" ], diff --git a/packages/google-cloud-websecurityscanner/package.json b/packages/google-cloud-websecurityscanner/package.json index 3d04f97d309e..94eeccd658b5 100644 --- a/packages/google-cloud-websecurityscanner/package.json +++ b/packages/google-cloud-websecurityscanner/package.json @@ -12,7 +12,6 @@ "main": "build/src/index.js", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "keywords": [ diff --git a/packages/google-cloud-workflows/package.json b/packages/google-cloud-workflows/package.json index 32e7e1072dc9..1c8ed149655c 100644 --- a/packages/google-cloud-workflows/package.json +++ b/packages/google-cloud-workflows/package.json @@ -12,7 +12,6 @@ "main": "build/src/index.js", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "keywords": [ diff --git a/packages/google-cloud-workloadmanager/package.json b/packages/google-cloud-workloadmanager/package.json index 7447f84df3f0..db867feea798 100644 --- a/packages/google-cloud-workloadmanager/package.json +++ b/packages/google-cloud-workloadmanager/package.json @@ -11,8 +11,7 @@ "author": "Google LLC", "main": "build/src/index.js", "files": [ - "build/src", - "build/protos" + "build/src" ], "homepage": "https://github.com/googleapis/google-cloud-node/tree/main/packages/google-cloud-workloadmanager", "keywords": [ diff --git a/packages/google-cloud-workstations/package.json b/packages/google-cloud-workstations/package.json index cc323da30f41..f15a6929b242 100644 --- a/packages/google-cloud-workstations/package.json +++ b/packages/google-cloud-workstations/package.json @@ -12,7 +12,6 @@ "main": "build/src/index.js", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "homepage": "https://github.com/googleapis/google-cloud-node/tree/main/packages/google-cloud-workstations", diff --git a/packages/google-container/package.json b/packages/google-container/package.json index 0c08e8af6745..8545bd15460f 100644 --- a/packages/google-container/package.json +++ b/packages/google-container/package.json @@ -14,7 +14,6 @@ }, "main": "build/src/index.js", "files": [ - "build/protos", "build/src", "!build/src/**/*.map" ], diff --git a/packages/google-dataflow/package.json b/packages/google-dataflow/package.json index bb9f73ca3a1e..43aa1351f558 100644 --- a/packages/google-dataflow/package.json +++ b/packages/google-dataflow/package.json @@ -12,7 +12,6 @@ "main": "build/src/index.js", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "keywords": [ diff --git a/packages/google-devtools-artifactregistry/package.json b/packages/google-devtools-artifactregistry/package.json index 8ac2562c6aaa..e4132ab755bc 100644 --- a/packages/google-devtools-artifactregistry/package.json +++ b/packages/google-devtools-artifactregistry/package.json @@ -13,7 +13,6 @@ "main": "build/src/index.js", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "keywords": [ diff --git a/packages/google-devtools-cloudbuild/package.json b/packages/google-devtools-cloudbuild/package.json index 4fec7a8be3f3..ed81e79bfb4e 100644 --- a/packages/google-devtools-cloudbuild/package.json +++ b/packages/google-devtools-cloudbuild/package.json @@ -12,7 +12,6 @@ "browser": "src/browser.js", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "keywords": [ diff --git a/packages/google-devtools-cloudprofiler/package.json b/packages/google-devtools-cloudprofiler/package.json index a824c067fffd..fcb3ce9cf039 100644 --- a/packages/google-devtools-cloudprofiler/package.json +++ b/packages/google-devtools-cloudprofiler/package.json @@ -11,8 +11,7 @@ "author": "Google LLC", "main": "build/src/index.js", "files": [ - "build/src", - "build/protos" + "build/src" ], "homepage": "https://github.com/googleapis/google-cloud-node/tree/main/packages/google-devtools-cloudprofiler", "keywords": [ diff --git a/packages/google-devtools-containeranalysis/package.json b/packages/google-devtools-containeranalysis/package.json index 8a4f5b3fda22..77b5311fce9c 100644 --- a/packages/google-devtools-containeranalysis/package.json +++ b/packages/google-devtools-containeranalysis/package.json @@ -13,7 +13,6 @@ "main": "build/src/index.js", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "keywords": [ diff --git a/packages/google-iam-credentials/package.json b/packages/google-iam-credentials/package.json index 8bc2f83a5b6d..63a349458dbc 100644 --- a/packages/google-iam-credentials/package.json +++ b/packages/google-iam-credentials/package.json @@ -12,7 +12,6 @@ "main": "build/src/index.js", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "keywords": [ diff --git a/packages/google-iam/package.json b/packages/google-iam/package.json index be05131d0b84..084d7f7e87f5 100644 --- a/packages/google-iam/package.json +++ b/packages/google-iam/package.json @@ -13,7 +13,6 @@ "main": "build/src/index.js", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "keywords": [ diff --git a/packages/google-identity-accesscontextmanager/package.json b/packages/google-identity-accesscontextmanager/package.json index aaa51f646f19..c9d72d776a33 100644 --- a/packages/google-identity-accesscontextmanager/package.json +++ b/packages/google-identity-accesscontextmanager/package.json @@ -12,7 +12,6 @@ "main": "build/src/index.js", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "keywords": [ diff --git a/packages/google-maps-addressvalidation/package.json b/packages/google-maps-addressvalidation/package.json index d283929400a7..b51d0d48d797 100644 --- a/packages/google-maps-addressvalidation/package.json +++ b/packages/google-maps-addressvalidation/package.json @@ -13,7 +13,6 @@ "main": "build/src/index.js", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "keywords": [ diff --git a/packages/google-maps-areainsights/package.json b/packages/google-maps-areainsights/package.json index bf1e8cbcbb7a..81924913b1c8 100644 --- a/packages/google-maps-areainsights/package.json +++ b/packages/google-maps-areainsights/package.json @@ -11,8 +11,7 @@ "author": "Google LLC", "main": "build/src/index.js", "files": [ - "build/src", - "build/protos" + "build/src" ], "homepage": "https://github.com/googleapis/google-cloud-node/tree/main/packages/google-maps-areainsights", "keywords": [ diff --git a/packages/google-maps-fleetengine-delivery/package.json b/packages/google-maps-fleetengine-delivery/package.json index 1bec5713fb4c..1d84158cc1d5 100644 --- a/packages/google-maps-fleetengine-delivery/package.json +++ b/packages/google-maps-fleetengine-delivery/package.json @@ -11,8 +11,7 @@ "author": "Google LLC", "main": "build/src/index.js", "files": [ - "build/src", - "build/protos" + "build/src" ], "homepage": "https://github.com/googleapis/google-cloud-node/tree/main/packages/google-maps-fleetengine-delivery", "keywords": [ diff --git a/packages/google-maps-fleetengine/package.json b/packages/google-maps-fleetengine/package.json index 1b865b8a6ad2..d618f1e5ac8b 100644 --- a/packages/google-maps-fleetengine/package.json +++ b/packages/google-maps-fleetengine/package.json @@ -11,8 +11,7 @@ "author": "Google LLC", "main": "build/src/index.js", "files": [ - "build/src", - "build/protos" + "build/src" ], "homepage": "https://github.com/googleapis/google-cloud-node/tree/main/packages/google-maps-fleetengine", "keywords": [ diff --git a/packages/google-maps-geocode/package.json b/packages/google-maps-geocode/package.json index da9f9bf07d4a..557b1c2a5062 100644 --- a/packages/google-maps-geocode/package.json +++ b/packages/google-maps-geocode/package.json @@ -11,8 +11,7 @@ "author": "Google LLC", "main": "build/src/index.js", "files": [ - "build/src", - "build/protos" + "build/src" ], "homepage": "https://github.com/googleapis/google-cloud-node/tree/main/packages/google-maps-geocode", "keywords": [ diff --git a/packages/google-maps-mapsplatformdatasets/package.json b/packages/google-maps-mapsplatformdatasets/package.json index 2b3fab5f2ca1..3e35bc3ff7df 100644 --- a/packages/google-maps-mapsplatformdatasets/package.json +++ b/packages/google-maps-mapsplatformdatasets/package.json @@ -12,7 +12,6 @@ "main": "build/src/index.js", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "homepage": "https://github.com/googleapis/google-cloud-node/tree/main/packages/google-maps-mapsplatformdatasets", diff --git a/packages/google-maps-navconnect/package.json b/packages/google-maps-navconnect/package.json index f99069ac6e8a..3a15d0158de9 100644 --- a/packages/google-maps-navconnect/package.json +++ b/packages/google-maps-navconnect/package.json @@ -11,8 +11,7 @@ "author": "Google LLC", "main": "build/src/index.js", "files": [ - "build/src", - "build/protos" + "build/src" ], "homepage": "https://github.com/googleapis/google-cloud-node/tree/main/packages/google-maps-navconnect", "keywords": [ diff --git a/packages/google-maps-places/package.json b/packages/google-maps-places/package.json index 0a5cc7a1febb..6bc980f3efb2 100644 --- a/packages/google-maps-places/package.json +++ b/packages/google-maps-places/package.json @@ -11,8 +11,7 @@ "author": "Google LLC", "main": "build/src/index.js", "files": [ - "build/src", - "build/protos" + "build/src" ], "homepage": "https://github.com/googleapis/google-cloud-node/tree/main/packages/google-maps-places", "keywords": [ diff --git a/packages/google-maps-routeoptimization/package.json b/packages/google-maps-routeoptimization/package.json index 644456e6057b..0a0528c148aa 100644 --- a/packages/google-maps-routeoptimization/package.json +++ b/packages/google-maps-routeoptimization/package.json @@ -11,8 +11,7 @@ "author": "Google LLC", "main": "build/src/index.js", "files": [ - "build/src", - "build/protos" + "build/src" ], "homepage": "https://github.com/googleapis/google-cloud-node/tree/main/packages/google-maps-routeoptimization", "keywords": [ diff --git a/packages/google-maps-routing/package.json b/packages/google-maps-routing/package.json index 31bedb4cfe8d..4e32d178aa73 100644 --- a/packages/google-maps-routing/package.json +++ b/packages/google-maps-routing/package.json @@ -13,7 +13,6 @@ "main": "build/src/index.js", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "keywords": [ diff --git a/packages/google-maps-solar/package.json b/packages/google-maps-solar/package.json index e6739c5e9f93..772e6fca90be 100644 --- a/packages/google-maps-solar/package.json +++ b/packages/google-maps-solar/package.json @@ -11,8 +11,7 @@ "author": "Google LLC", "main": "build/src/index.js", "files": [ - "build/src", - "build/protos" + "build/src" ], "homepage": "https://github.com/googleapis/google-cloud-node/tree/main/packages/google-maps-solar", "keywords": [ diff --git a/packages/google-marketingplatform-admin/package.json b/packages/google-marketingplatform-admin/package.json index df5edfb9379f..8093d6e063bd 100644 --- a/packages/google-marketingplatform-admin/package.json +++ b/packages/google-marketingplatform-admin/package.json @@ -11,8 +11,7 @@ "author": "Google LLC", "main": "build/src/index.js", "files": [ - "build/src", - "build/protos" + "build/src" ], "homepage": "https://github.com/googleapis/google-cloud-node/tree/main/packages/google-marketingplatform-admin", "keywords": [ diff --git a/packages/google-monitoring-dashboard/package.json b/packages/google-monitoring-dashboard/package.json index 841f16d29db6..b7d061f86113 100644 --- a/packages/google-monitoring-dashboard/package.json +++ b/packages/google-monitoring-dashboard/package.json @@ -12,7 +12,6 @@ "author": "Google LLC", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "main": "build/src/index.js", diff --git a/packages/google-privacy-dlp/package.json b/packages/google-privacy-dlp/package.json index 4c30af21c31f..131976fd4f0c 100644 --- a/packages/google-privacy-dlp/package.json +++ b/packages/google-privacy-dlp/package.json @@ -14,7 +14,6 @@ }, "main": "build/src/index.js", "files": [ - "build/protos", "build/src", "!build/src/**/*.map" ], diff --git a/packages/google-shopping-css/package.json b/packages/google-shopping-css/package.json index 856d6449e89c..5a2e363bea32 100644 --- a/packages/google-shopping-css/package.json +++ b/packages/google-shopping-css/package.json @@ -11,8 +11,7 @@ "author": "Google LLC", "main": "build/src/index.js", "files": [ - "build/src", - "build/protos" + "build/src" ], "homepage": "https://github.com/googleapis/google-cloud-node/tree/main/packages/google-shopping-css", "keywords": [ diff --git a/packages/google-shopping-merchant-accounts/package.json b/packages/google-shopping-merchant-accounts/package.json index c82f199f828b..0b4ba69c002c 100644 --- a/packages/google-shopping-merchant-accounts/package.json +++ b/packages/google-shopping-merchant-accounts/package.json @@ -11,8 +11,7 @@ "author": "Google LLC", "main": "build/src/index.js", "files": [ - "build/src", - "build/protos" + "build/src" ], "homepage": "https://github.com/googleapis/google-cloud-node/tree/main/packages/google-shopping-merchant-accounts", "keywords": [ diff --git a/packages/google-shopping-merchant-conversions/package.json b/packages/google-shopping-merchant-conversions/package.json index 6a6b31fe5af8..5f7d31e1e6cc 100644 --- a/packages/google-shopping-merchant-conversions/package.json +++ b/packages/google-shopping-merchant-conversions/package.json @@ -11,8 +11,7 @@ "author": "Google LLC", "main": "build/src/index.js", "files": [ - "build/src", - "build/protos" + "build/src" ], "homepage": "https://github.com/googleapis/google-cloud-node/tree/main/packages/google-shopping-merchant-conversions", "keywords": [ diff --git a/packages/google-shopping-merchant-datasources/package.json b/packages/google-shopping-merchant-datasources/package.json index 15c35404310b..7aad38fb953b 100644 --- a/packages/google-shopping-merchant-datasources/package.json +++ b/packages/google-shopping-merchant-datasources/package.json @@ -11,8 +11,7 @@ "author": "Google LLC", "main": "build/src/index.js", "files": [ - "build/src", - "build/protos" + "build/src" ], "homepage": "https://github.com/googleapis/google-cloud-node/tree/main/packages/google-shopping-merchant-datasources", "keywords": [ diff --git a/packages/google-shopping-merchant-inventories/package.json b/packages/google-shopping-merchant-inventories/package.json index 7a26b6989518..3e13679a3bb1 100644 --- a/packages/google-shopping-merchant-inventories/package.json +++ b/packages/google-shopping-merchant-inventories/package.json @@ -11,8 +11,7 @@ "author": "Google LLC", "main": "build/src/index.js", "files": [ - "build/src", - "build/protos" + "build/src" ], "homepage": "https://github.com/googleapis/google-cloud-node/tree/main/packages/google-shopping-merchant-inventories", "keywords": [ diff --git a/packages/google-shopping-merchant-issueresolution/package.json b/packages/google-shopping-merchant-issueresolution/package.json index 37076822f893..e217b56e4d7f 100644 --- a/packages/google-shopping-merchant-issueresolution/package.json +++ b/packages/google-shopping-merchant-issueresolution/package.json @@ -11,8 +11,7 @@ "author": "Google LLC", "main": "build/src/index.js", "files": [ - "build/src", - "build/protos" + "build/src" ], "homepage": "https://github.com/googleapis/google-cloud-node/tree/main/packages/google-shopping-merchant-issueresolution", "keywords": [ diff --git a/packages/google-shopping-merchant-lfp/package.json b/packages/google-shopping-merchant-lfp/package.json index ee125338c3aa..8fb93296965a 100644 --- a/packages/google-shopping-merchant-lfp/package.json +++ b/packages/google-shopping-merchant-lfp/package.json @@ -11,8 +11,7 @@ "author": "Google LLC", "main": "build/src/index.js", "files": [ - "build/src", - "build/protos" + "build/src" ], "homepage": "https://github.com/googleapis/google-cloud-node/tree/main/packages/google-shopping-merchant-lfp", "keywords": [ diff --git a/packages/google-shopping-merchant-notifications/package.json b/packages/google-shopping-merchant-notifications/package.json index 6f79520704ea..64bc95b39e35 100644 --- a/packages/google-shopping-merchant-notifications/package.json +++ b/packages/google-shopping-merchant-notifications/package.json @@ -11,8 +11,7 @@ "author": "Google LLC", "main": "build/src/index.js", "files": [ - "build/src", - "build/protos" + "build/src" ], "homepage": "https://github.com/googleapis/google-cloud-node/tree/main/packages/google-shopping-merchant-notifications", "keywords": [ diff --git a/packages/google-shopping-merchant-ordertracking/package.json b/packages/google-shopping-merchant-ordertracking/package.json index 69e2dbe9fe8e..45b65b37c580 100644 --- a/packages/google-shopping-merchant-ordertracking/package.json +++ b/packages/google-shopping-merchant-ordertracking/package.json @@ -11,8 +11,7 @@ "author": "Google LLC", "main": "build/src/index.js", "files": [ - "build/src", - "build/protos" + "build/src" ], "homepage": "https://github.com/googleapis/google-cloud-node/tree/main/packages/google-shopping-merchant-ordertracking", "keywords": [ diff --git a/packages/google-shopping-merchant-products/package.json b/packages/google-shopping-merchant-products/package.json index 2e375ba6fa8a..c507ecdc408d 100644 --- a/packages/google-shopping-merchant-products/package.json +++ b/packages/google-shopping-merchant-products/package.json @@ -11,8 +11,7 @@ "author": "Google LLC", "main": "build/src/index.js", "files": [ - "build/src", - "build/protos" + "build/src" ], "homepage": "https://github.com/googleapis/google-cloud-node/tree/main/packages/google-shopping-merchant-products", "keywords": [ diff --git a/packages/google-shopping-merchant-promotions/package.json b/packages/google-shopping-merchant-promotions/package.json index 6ff4476e1df4..4509604343b9 100644 --- a/packages/google-shopping-merchant-promotions/package.json +++ b/packages/google-shopping-merchant-promotions/package.json @@ -11,8 +11,7 @@ "author": "Google LLC", "main": "build/src/index.js", "files": [ - "build/src", - "build/protos" + "build/src" ], "homepage": "https://github.com/googleapis/google-cloud-node/tree/main/packages/google-shopping-merchant-promotions", "keywords": [ diff --git a/packages/google-shopping-merchant-quota/package.json b/packages/google-shopping-merchant-quota/package.json index e248d18e65a9..2b0c14ede5e3 100644 --- a/packages/google-shopping-merchant-quota/package.json +++ b/packages/google-shopping-merchant-quota/package.json @@ -11,8 +11,7 @@ "author": "Google LLC", "main": "build/src/index.js", "files": [ - "build/src", - "build/protos" + "build/src" ], "homepage": "https://github.com/googleapis/google-cloud-node/tree/main/packages/google-shopping-merchant-quota", "keywords": [ diff --git a/packages/google-shopping-merchant-reports/package.json b/packages/google-shopping-merchant-reports/package.json index 0fbdd9781e40..a168d64457e7 100644 --- a/packages/google-shopping-merchant-reports/package.json +++ b/packages/google-shopping-merchant-reports/package.json @@ -11,8 +11,7 @@ "author": "Google LLC", "main": "build/src/index.js", "files": [ - "build/src", - "build/protos" + "build/src" ], "homepage": "https://github.com/googleapis/google-cloud-node/tree/main/packages/google-shopping-merchant-reports", "keywords": [ diff --git a/packages/google-shopping-merchant-reviews/package.json b/packages/google-shopping-merchant-reviews/package.json index 0d11ef5e8fcc..121b14228a55 100644 --- a/packages/google-shopping-merchant-reviews/package.json +++ b/packages/google-shopping-merchant-reviews/package.json @@ -11,8 +11,7 @@ "author": "Google LLC", "main": "build/src/index.js", "files": [ - "build/src", - "build/protos" + "build/src" ], "homepage": "https://github.com/googleapis/google-cloud-node/tree/main/packages/google-shopping-merchant-reviews", "keywords": [ diff --git a/packages/google-storage-control/package.json b/packages/google-storage-control/package.json index 55686cf6a02f..9862ec7542a9 100644 --- a/packages/google-storage-control/package.json +++ b/packages/google-storage-control/package.json @@ -11,8 +11,7 @@ "author": "Google LLC", "main": "build/src/index.js", "files": [ - "build/src", - "build/protos" + "build/src" ], "homepage": "https://github.com/googleapis/google-cloud-node/tree/main/packages/google-storage-control", "keywords": [ diff --git a/packages/google-storagetransfer/package.json b/packages/google-storagetransfer/package.json index c05a215e8ac5..418a503670a9 100644 --- a/packages/google-storagetransfer/package.json +++ b/packages/google-storagetransfer/package.json @@ -12,7 +12,6 @@ "main": "build/src/index.js", "files": [ "build/src", - "build/protos", "!build/src/**/*.map" ], "keywords": [ diff --git a/packages/google-streetview-publish/package.json b/packages/google-streetview-publish/package.json index 19bc0e0d9017..a640fad33ba7 100644 --- a/packages/google-streetview-publish/package.json +++ b/packages/google-streetview-publish/package.json @@ -11,8 +11,7 @@ "author": "Google LLC", "main": "build/src/index.js", "files": [ - "build/src", - "build/protos" + "build/src" ], "homepage": "https://github.com/googleapis/google-cloud-node/tree/main/packages/google-streetview-publish", "keywords": [ diff --git a/packages/grafeas/package.json b/packages/grafeas/package.json index 71e4475056e2..364b88950c9c 100644 --- a/packages/grafeas/package.json +++ b/packages/grafeas/package.json @@ -10,7 +10,6 @@ "description": "Grafeas API client for Node.js", "main": "build/src/index.js", "files": [ - "build/protos", "build/src", "!build/src/**/*.map" ], From fbd9594af53ef16655e91e08e758d89ad108d682 Mon Sep 17 00:00:00 2001 From: werman Date: Wed, 22 Apr 2026 11:56:37 -0700 Subject: [PATCH 2/8] feat: Regional Access Boundary Migration. (#8043) --- .../src/auth/authclient.ts | 91 +++++- .../src/auth/baseexternalclient.ts | 84 ++++-- .../src/auth/computeclient.ts | 42 +++ .../src/auth/downscopedclient.ts | 16 +- .../externalAccountAuthorizedUserClient.ts | 55 +++- .../src/auth/idtokenclient.ts | 11 +- .../src/auth/impersonated.ts | 25 ++ .../src/auth/jwtclient.ts | 27 +- .../src/auth/oauth2client.ts | 29 +- .../src/auth/regionalaccessboundary.ts | 278 ++++++++++++++++++ .../google-auth-library-nodejs/src/util.ts | 37 +++ .../test/test.authclient.ts | 242 ++++++++++++++- .../test/test.baseexternalclient.ts | 235 +++++++++++++++ .../test/test.compute.ts | 112 ++++++- ...est.externalaccountauthorizeduserclient.ts | 101 ++++++- .../test/test.externalclient.ts | 71 ++--- .../test/test.impersonated.ts | 110 +++++++ .../test/test.jwt.ts | 173 +++++++++++ .../google-auth-library-nodejs/tsconfig.json | 5 +- 19 files changed, 1627 insertions(+), 117 deletions(-) create mode 100644 core/packages/google-auth-library-nodejs/src/auth/regionalaccessboundary.ts diff --git a/core/packages/google-auth-library-nodejs/src/auth/authclient.ts b/core/packages/google-auth-library-nodejs/src/auth/authclient.ts index f18dd58e2abf..ea9ff1abdd31 100644 --- a/core/packages/google-auth-library-nodejs/src/auth/authclient.ts +++ b/core/packages/google-auth-library-nodejs/src/auth/authclient.ts @@ -20,6 +20,11 @@ import {OriginalAndCamel, originalOrCamelOptions} from '../util'; import {log as makeLog} from 'google-logging-utils'; import {PRODUCT_NAME, USER_AGENT} from '../shared.cjs'; +import { + isRegionalAccessBoundaryEnabled, + RegionalAccessBoundaryData, + RegionalAccessBoundaryManager, +} from './regionalaccessboundary'; /** * An interface for enforcing `fetch`-type compliance. @@ -232,6 +237,8 @@ export abstract class AuthClient eagerRefreshThresholdMillis = DEFAULT_EAGER_REFRESH_THRESHOLD_MILLIS; forceRefreshOnFailure = false; universeDomain = DEFAULT_UNIVERSE; + regionalAccessBoundaryEnabled: boolean; + protected regionalAccessBoundaryManager: RegionalAccessBoundaryManager; /** * Symbols that can be added to GaxiosOptions to specify the method name that is @@ -254,10 +261,17 @@ export abstract class AuthClient this.quotaProjectId = options.get('quota_project_id'); this.credentials = options.get('credentials') ?? {}; this.universeDomain = options.get('universe_domain') ?? DEFAULT_UNIVERSE; + this.regionalAccessBoundaryEnabled = isRegionalAccessBoundaryEnabled(); // Shared client options this.transporter = opts.transporter ?? new Gaxios(opts.transporterOptions); + this.regionalAccessBoundaryManager = new RegionalAccessBoundaryManager({ + transporter: this.transporter, + getLookupUrl: async () => this.getRegionalAccessBoundaryUrl(), + isUniverseDomainDefault: () => this.universeDomain === DEFAULT_UNIVERSE, + }); + if (options.get('useAuthRequestParameters') !== false) { this.transporter.interceptors.request.add( AuthClient.DEFAULT_REQUEST_INTERCEPTOR, @@ -361,6 +375,21 @@ export abstract class AuthClient res?: GaxiosResponse | null; }>; + /** + * Returns the regional access boundary lookup URL for the current client. + * This method is intended for internal use by the RegionalAccessBoundaryManager + * and should not be called directly by users. + * + * @return The regional access boundary URL string, or `null` if the client type + * does not support regional access boundaries. + * @throws {Error} If the URL cannot be constructed for a compatible client, + * for instance, if a required property like a service account email is missing. + * @internal + */ + public async getRegionalAccessBoundaryUrl(): Promise { + return null; + } + /** * Sets the auth credentials. */ @@ -368,6 +397,22 @@ export abstract class AuthClient this.credentials = credentials; } + /** + * Returns the current regional access boundary data. + * @internal + */ + getRegionalAccessBoundary(): RegionalAccessBoundaryData | null { + return this.regionalAccessBoundaryManager.data; + } + + /** + * Returns the current regional access boundary cooldown time in milliseconds. + * @internal + */ + getRegionalAccessBoundaryCooldownTime(): number { + return this.regionalAccessBoundaryManager.cooldownTime; + } + /** * Append additional headers, e.g., x-goog-user-project, shared across the * classes inheriting AuthClient. This method should be used by any method @@ -386,23 +431,47 @@ export abstract class AuthClient ) { headers.set('x-goog-user-project', this.quotaProjectId); } + return headers; } /** - * Adds the `x-goog-user-project` and `authorization` headers to the target Headers + * Applies regional access boundary rules to the provided headers. + * This includes adding the x-allowed-locations header and triggering + * a background refresh if needed. + * @param headers The headers to update. + * @param url Optional destination URL of the request. If missing, assumed global. + */ + protected applyRegionalAccessBoundary( + headers: Headers, + url?: string | URL, + ): void { + const rabHeader = + this.regionalAccessBoundaryManager.getRegionalAccessBoundaryHeader( + url, + headers, + ); + if (rabHeader) { + headers.set('x-allowed-locations', rabHeader); + } + } + + /** + * Adds the `x-goog-user-project`, `authorization`, and 'x-allowed-locations' + * headers to the target Headers * object, if they exist on the source. * * @param target the headers to target * @param source the headers to source from * @returns the target headers */ - protected addUserProjectAndAuthHeaders( + protected applyHeadersFromSource( target: T, source: Headers, ): T { const xGoogUserProject = source.get('x-goog-user-project'); const authorizationHeader = source.get('authorization'); + const xGoogAllowedLocs = source.get('x-allowed-locations'); if (xGoogUserProject) { target.set('x-goog-user-project', xGoogUserProject); @@ -412,6 +481,10 @@ export abstract class AuthClient target.set('authorization', authorizationHeader); } + if (xGoogAllowedLocs) { + target.set('x-allowed-locations', xGoogAllowedLocs); + } + return target; } @@ -549,6 +622,20 @@ export abstract class AuthClient }, }; } + + /** + * Returns whether the provided credentials are expired or will expire within + * eagerRefreshThresholdMillismilliseconds. + * If there is no expiry time, assumes the token is not expired or expiring. + * @param credentials The credentials to check for expiration. + * @return Whether the credentials are expired or not. + */ + protected isExpired(credentials: Credentials = this.credentials): boolean { + const now = new Date().getTime(); + return credentials.expiry_date + ? now >= credentials.expiry_date - this.eagerRefreshThresholdMillis + : false; + } } // TypeScript does not have `HeadersInit` in the standard types yet diff --git a/core/packages/google-auth-library-nodejs/src/auth/baseexternalclient.ts b/core/packages/google-auth-library-nodejs/src/auth/baseexternalclient.ts index 48111eb6345a..f569a590fc29 100644 --- a/core/packages/google-auth-library-nodejs/src/auth/baseexternalclient.ts +++ b/core/packages/google-auth-library-nodejs/src/auth/baseexternalclient.ts @@ -31,7 +31,16 @@ import { import * as sts from './stscredentials'; import {ClientAuthentication} from './oauth2common'; import {SnakeToCamelObject, originalOrCamelOptions} from '../util'; +import { + getWorkforcePoolIdFromAudience, + getWorkloadPoolIdFromAudience, +} from '../util'; import {pkg} from '../shared.cjs'; +import { + SERVICE_ACCOUNT_LOOKUP_ENDPOINT, + WORKFORCE_LOOKUP_ENDPOINT, + WORKLOAD_LOOKUP_ENDPOINT, +} from './regionalaccessboundary'; /** * The required token exchange grant_type: rfc8693#section-2.1 @@ -415,11 +424,12 @@ export abstract class BaseExternalAccountClient extends AuthClient { * The result has the form: * { authorization: 'Bearer ' } */ - async getRequestHeaders(): Promise { + async getRequestHeaders(url?: string | URL): Promise { const accessTokenResponse = await this.getAccessToken(); const headers = new Headers({ authorization: `Bearer ${accessTokenResponse.token}`, }); + this.applyRegionalAccessBoundary(headers, url); return this.addSharedMetadataHeaders(headers); } @@ -499,13 +509,14 @@ export abstract class BaseExternalAccountClient extends AuthClient { reAuthRetried = false, ): Promise> { let response: GaxiosResponse; + const requestOpts = {...opts}; try { - const requestHeaders = await this.getRequestHeaders(); - opts.headers = Gaxios.mergeHeaders(opts.headers); + const requestHeaders = await this.getRequestHeaders(opts.url); + requestOpts.headers = Gaxios.mergeHeaders(requestOpts.headers); - this.addUserProjectAndAuthHeaders(opts.headers, requestHeaders); + this.applyHeadersFromSource(requestOpts.headers, requestHeaders); - response = await this.transporter.request(opts); + response = await this.transporter.request(requestOpts); } catch (e) { const res = (e as GaxiosError).response; if (res) { @@ -684,19 +695,6 @@ export abstract class BaseExternalAccountClient extends AuthClient { }; } - /** - * Returns whether the provided credentials are expired or not. - * If there is no expiry time, assumes the token is not expired or expiring. - * @param accessToken The credentials to check for expiration. - * @return Whether the credentials are expired or not. - */ - private isExpired(accessToken: Credentials): boolean { - const now = new Date().getTime(); - return accessToken.expiry_date - ? now >= accessToken.expiry_date - this.eagerRefreshThresholdMillis - : false; - } - /** * @return The list of scopes for the requested GCP access token. */ @@ -722,4 +720,54 @@ export abstract class BaseExternalAccountClient extends AuthClient { protected getTokenUrl(): string { return this.tokenUrl; } + + /** + * Returns the regional access boundary lookup URL for the external account. + * This implementation constructs the URL based on the audience of the + * workforce or workload pool. If the client is configured for service account + * impersonation, it uses the target service account email to generate + * the lookup endpoint. + * + * @return The regional access boundary URL string. + * @internal + */ + public async getRegionalAccessBoundaryUrl(): Promise { + if (this.serviceAccountImpersonationUrl) { + // When impersonating a service account, the regional access boundary is determined + // by the security policies of the target service account. + const email = this.getServiceAccountEmail(); + if (!email) { + throw new Error( + `RegionalAccessBoundary: A service account email is required for regional access boundary lookups but could not be determined from the serviceAccountImpersonationUrl ${this.serviceAccountImpersonationUrl}.`, + ); + } + return SERVICE_ACCOUNT_LOOKUP_ENDPOINT.replace( + '{service_account_email}', + encodeURIComponent(email), + ); + } + + // Check if the audience corresponds to a workload identity pool. + const wfPoolId = getWorkforcePoolIdFromAudience(this.audience); + if (wfPoolId) { + return WORKFORCE_LOOKUP_ENDPOINT.replace( + '{pool_id}', + encodeURIComponent(wfPoolId), + ); + } + + // Check if the audience corresponds to a workforce identity pool. + const wlPoolId = getWorkloadPoolIdFromAudience(this.audience); + const projectNumber = this.getProjectNumber(this.audience); + if (wlPoolId && projectNumber) { + return WORKLOAD_LOOKUP_ENDPOINT.replace( + '{project_id}', + projectNumber, + ).replace('{pool_id}', wlPoolId); + } + + throw new RangeError( + `RegionalAccessBoundary: Invalid audience provided: "${this.audience}" does not correspond to a workforce or workload pool.`, + ); + } } diff --git a/core/packages/google-auth-library-nodejs/src/auth/computeclient.ts b/core/packages/google-auth-library-nodejs/src/auth/computeclient.ts index 36ca73d172aa..a5329e4cfa2b 100644 --- a/core/packages/google-auth-library-nodejs/src/auth/computeclient.ts +++ b/core/packages/google-auth-library-nodejs/src/auth/computeclient.ts @@ -21,6 +21,7 @@ import { OAuth2Client, OAuth2ClientOptions, } from './oauth2client'; +import {SERVICE_ACCOUNT_LOOKUP_ENDPOINT} from './regionalaccessboundary'; export interface ComputeOptions extends OAuth2ClientOptions { /** @@ -137,4 +138,45 @@ export class Compute extends OAuth2Client { } } } + + /** + * Returns the regional access boundary lookup URL for the GCE instance. + * This implementation resolves the default service account email of the GCE + * instance to construct the lookup endpoint. + * + * @return The regional access boundary URL string. + * @internal + */ + public async getRegionalAccessBoundaryUrl(): Promise { + const email = await this.resolveServiceAccountEmail(); + const regionalAccessBoundaryUrl = SERVICE_ACCOUNT_LOOKUP_ENDPOINT.replace( + '{service_account_email}', + encodeURIComponent(email), + ); + return regionalAccessBoundaryUrl; + } + + /** + * Resolves the service account email. If the email is set to 'default', + * it fetches the email from the GCE metadata server. + * @returns A promise that resolves with the service account email. + */ + private async resolveServiceAccountEmail(): Promise { + if (this.serviceAccountEmail !== 'default') { + // If a specific email is provided, return it directly. + return this.serviceAccountEmail; + } + + // Otherwise, fetch the default email from the metadata server. + try { + return await gcpMetadata.instance('service-accounts/default/email'); + } catch (e) { + throw new Error( + 'RegionalAccessBoundary: Failed to retrieve default service account email from metadata server.', + { + cause: e, + }, + ); + } + } } diff --git a/core/packages/google-auth-library-nodejs/src/auth/downscopedclient.ts b/core/packages/google-auth-library-nodejs/src/auth/downscopedclient.ts index bc0d19b16b81..cbb6a1e255b2 100644 --- a/core/packages/google-auth-library-nodejs/src/auth/downscopedclient.ts +++ b/core/packages/google-auth-library-nodejs/src/auth/downscopedclient.ts @@ -290,7 +290,7 @@ export class DownscopedClient extends AuthClient { const requestHeaders = await this.getRequestHeaders(); opts.headers = Gaxios.mergeHeaders(opts.headers); - this.addUserProjectAndAuthHeaders(opts.headers, requestHeaders); + this.applyHeadersFromSource(opts.headers, requestHeaders); response = await this.transporter.request(opts); } catch (e) { @@ -381,18 +381,4 @@ export class DownscopedClient extends AuthClient { // Return the cached access token. return this.cachedDownscopedAccessToken; } - - /** - * Returns whether the provided credentials are expired or not. - * If there is no expiry time, assumes the token is not expired or expiring. - * @param downscopedAccessToken The credentials to check for expiration. - * @return Whether the credentials are expired or not. - */ - private isExpired(downscopedAccessToken: Credentials): boolean { - const now = new Date().getTime(); - return downscopedAccessToken.expiry_date - ? now >= - downscopedAccessToken.expiry_date - this.eagerRefreshThresholdMillis - : false; - } } diff --git a/core/packages/google-auth-library-nodejs/src/auth/externalAccountAuthorizedUserClient.ts b/core/packages/google-auth-library-nodejs/src/auth/externalAccountAuthorizedUserClient.ts index 320db05546ad..59d8f42f6f43 100644 --- a/core/packages/google-auth-library-nodejs/src/auth/externalAccountAuthorizedUserClient.ts +++ b/core/packages/google-auth-library-nodejs/src/auth/externalAccountAuthorizedUserClient.ts @@ -33,6 +33,8 @@ import { EXPIRATION_TIME_OFFSET, SharedExternalAccountClientOptions, } from './baseexternalclient'; +import {WORKFORCE_LOOKUP_ENDPOINT} from './regionalaccessboundary'; +import {getWorkforcePoolIdFromAudience} from '../util'; /** * The credentials JSON file type for external account authorized user clients. @@ -159,6 +161,7 @@ export class ExternalAccountAuthorizedUserClient extends AuthClient { private cachedAccessToken: CredentialsWithResponse | null; private readonly externalAccountAuthorizedUserHandler: ExternalAccountAuthorizedUserHandler; private refreshToken: string; + private readonly audience: string; /** * Instantiates an ExternalAccountAuthorizedUserClient instances using the @@ -172,6 +175,7 @@ export class ExternalAccountAuthorizedUserClient extends AuthClient { if (options.universe_domain) { this.universeDomain = options.universe_domain; } + this.audience = options.audience; this.refreshToken = options.refresh_token; const clientAuthentication = { confidentialClientType: 'basic', @@ -218,11 +222,20 @@ export class ExternalAccountAuthorizedUserClient extends AuthClient { }; } - async getRequestHeaders(): Promise { + /** + * The main authentication interface. It takes an optional url which when + * present is the endpoint being accessed, and returns a Promise which + * resolves with authorization header fields. + * + * @param url The URI being authorized. + * @returns A promise that resolves with authorization header fields. + */ + async getRequestHeaders(url?: string | URL): Promise { const accessTokenResponse = await this.getAccessToken(); const headers = new Headers({ authorization: `Bearer ${accessTokenResponse.token}`, }); + this.applyRegionalAccessBoundary(headers, url); return this.addSharedMetadataHeaders(headers); } @@ -256,13 +269,14 @@ export class ExternalAccountAuthorizedUserClient extends AuthClient { reAuthRetried = false, ): Promise> { let response: GaxiosResponse; + const requestOpts = {...opts}; try { - const requestHeaders = await this.getRequestHeaders(); - opts.headers = Gaxios.mergeHeaders(opts.headers); + const requestHeaders = await this.getRequestHeaders(opts.url); + requestOpts.headers = Gaxios.mergeHeaders(requestOpts.headers); - this.addUserProjectAndAuthHeaders(opts.headers, requestHeaders); + this.applyHeadersFromSource(requestOpts.headers, requestHeaders); - response = await this.transporter.request(opts); + response = await this.transporter.request(requestOpts); } catch (e) { const res = (e as GaxiosError).response; if (res) { @@ -308,21 +322,34 @@ export class ExternalAccountAuthorizedUserClient extends AuthClient { if (refreshResponse.refresh_token !== undefined) { this.refreshToken = refreshResponse.refresh_token; + + // Set credentials. + this.credentials = {...this.cachedAccessToken}; + delete (this.credentials as CredentialsWithResponse).res; } return this.cachedAccessToken; } /** - * Returns whether the provided credentials are expired or not. - * If there is no expiry time, assumes the token is not expired or expiring. - * @param credentials The credentials to check for expiration. - * @return Whether the credentials are expired or not. + * Returns the regional access boundary lookup URL for the external account + * authorized user. + * This implementation constructs the lookup endpoint using the workforce + * pool ID resolved from the audience. + * + * @return The regional access boundary URL string. + * @internal */ - private isExpired(credentials: Credentials): boolean { - const now = new Date().getTime(); - return credentials.expiry_date - ? now >= credentials.expiry_date - this.eagerRefreshThresholdMillis - : false; + public async getRegionalAccessBoundaryUrl(): Promise { + const poolId = getWorkforcePoolIdFromAudience(this.audience); + if (!poolId) { + throw new Error( + `RegionalAccessBoundary: A workforce pool ID is required for regional access boundary lookups but could not be determined from the audience: ${this.audience}.`, + ); + } + return WORKFORCE_LOOKUP_ENDPOINT.replace( + '{pool_id}', + encodeURIComponent(poolId), + ); } } diff --git a/core/packages/google-auth-library-nodejs/src/auth/idtokenclient.ts b/core/packages/google-auth-library-nodejs/src/auth/idtokenclient.ts index 68303c97e36a..638b6db8a4ec 100644 --- a/core/packages/google-auth-library-nodejs/src/auth/idtokenclient.ts +++ b/core/packages/google-auth-library-nodejs/src/auth/idtokenclient.ts @@ -54,7 +54,7 @@ export class IdTokenClient extends OAuth2Client { if ( !this.credentials.id_token || !this.credentials.expiry_date || - this.isTokenExpiring() + this.isExpired() ) { const idToken = await this.idTokenProvider.fetchIdToken( this.targetAudience, @@ -68,7 +68,12 @@ export class IdTokenClient extends OAuth2Client { const headers = new Headers({ authorization: 'Bearer ' + this.credentials.id_token, }); - return {headers}; + return { + headers, + // Since ID-tokens are outside RAB scope, isIDToken is used as a flag + // to avoid RAB lookup. + isIDToken: true, + }; } private getIdTokenExpiryDate(idToken: string): number | void { @@ -80,4 +85,4 @@ export class IdTokenClient extends OAuth2Client { return payload.exp * 1000; } } -} +} \ No newline at end of file diff --git a/core/packages/google-auth-library-nodejs/src/auth/impersonated.ts b/core/packages/google-auth-library-nodejs/src/auth/impersonated.ts index 97742ef668b3..d146c11f31de 100644 --- a/core/packages/google-auth-library-nodejs/src/auth/impersonated.ts +++ b/core/packages/google-auth-library-nodejs/src/auth/impersonated.ts @@ -24,6 +24,7 @@ import {IdTokenProvider} from './idtokenclient'; import {GaxiosError} from 'gaxios'; import {SignBlobResponse} from './googleauth'; import {originalOrCamelOptions} from '../util'; +import {SERVICE_ACCOUNT_LOOKUP_ENDPOINT} from './regionalaccessboundary'; export interface ImpersonatedOptions extends OAuth2ClientOptions { /** @@ -202,6 +203,7 @@ export class Impersonated extends OAuth2Client implements IdTokenProvider { const tokenResponse = res.data; this.credentials.access_token = tokenResponse.accessToken; this.credentials.expiry_date = Date.parse(tokenResponse.expireTime); + return { tokens: this.credentials, res, @@ -260,4 +262,27 @@ export class Impersonated extends OAuth2Client implements IdTokenProvider { return res.data.token; } + + /** + * Returns the regional access boundary lookup URL for the impersonated + * service account. + * This implementation uses the target principal (service account email) + * to construct the lookup endpoint. + * + * @return The regional access boundary URL string. + * @internal + */ + public async getRegionalAccessBoundaryUrl(): Promise { + const targetPrincipal = this.getTargetPrincipal(); + if (!targetPrincipal) { + throw new Error( + 'RegionalAccessBoundary: A targetPrincipal is required for regional access boundary lookups but was not provided in the ImpersonatedClient options.', + ); + } + const regionalAccessBoundaryUrl = SERVICE_ACCOUNT_LOOKUP_ENDPOINT.replace( + '{service_account_email}', + encodeURIComponent(targetPrincipal), + ); + return regionalAccessBoundaryUrl; + } } diff --git a/core/packages/google-auth-library-nodejs/src/auth/jwtclient.ts b/core/packages/google-auth-library-nodejs/src/auth/jwtclient.ts index 55ce73e849e7..2f5c0bda0ec6 100644 --- a/core/packages/google-auth-library-nodejs/src/auth/jwtclient.ts +++ b/core/packages/google-auth-library-nodejs/src/auth/jwtclient.ts @@ -26,6 +26,7 @@ import { RequestMetadataResponse, } from './oauth2client'; import {DEFAULT_UNIVERSE} from './authclient'; +import {SERVICE_ACCOUNT_LOOKUP_ENDPOINT} from './regionalaccessboundary'; export interface JWTOptions extends OAuth2ClientOptions { /** @@ -147,6 +148,9 @@ export class JWT extends OAuth2Client implements IdTokenProvider { authorization: `Bearer ${tokens.id_token}`, }), ), + // Since ID-tokens are outside RAB scope, + // isIDToken is used as a flag to avoid RAB lookup. + isIDToken: true, }; } else { // no scopes have been set, but a uri has been provided. Use JWTAccess @@ -271,7 +275,7 @@ export class JWT extends OAuth2Client implements IdTokenProvider { protected async refreshTokenNoCache(): Promise { const gtoken = this.createGToken(); const token = await gtoken.getToken({ - forceRefresh: this.isTokenExpiring(), + forceRefresh: this.isExpired(), }); const tokens = { access_token: token.access_token, @@ -408,4 +412,25 @@ export class JWT extends OAuth2Client implements IdTokenProvider { } throw new Error('A key or a keyFile must be provided to getCredentials.'); } + + /** + * Returns the regional access boundary lookup URL for the service account. + * This implementation uses the configured service account email to construct + * the lookup endpoint. + * + * @return The regional access boundary URL string. + * @internal + */ + public async getRegionalAccessBoundaryUrl(): Promise { + if (!this.email) { + throw new Error( + 'RegionalAccessBoundary: An email address is required for regional access boundary lookups but was not provided in the JwtClient options.', + ); + } + const regionalAccessBoundaryUrl = SERVICE_ACCOUNT_LOOKUP_ENDPOINT.replace( + '{service_account_email}', + encodeURIComponent(this.email), + ); + return regionalAccessBoundaryUrl; + } } diff --git a/core/packages/google-auth-library-nodejs/src/auth/oauth2client.ts b/core/packages/google-auth-library-nodejs/src/auth/oauth2client.ts index 138e66c462b5..4bf698df95e9 100644 --- a/core/packages/google-auth-library-nodejs/src/auth/oauth2client.ts +++ b/core/packages/google-auth-library-nodejs/src/auth/oauth2client.ts @@ -378,6 +378,11 @@ export interface RefreshAccessTokenResponse { export interface RequestMetadataResponse { headers: Headers; res?: GaxiosResponse | null; + /** + * Whether the returned headers contain an ID token (OIDC) instead of an + * access token. ID tokens are out of scope for Regional Access Boundaries. + */ + isIDToken?: boolean; } export interface RequestMetadataCallback { @@ -901,8 +906,7 @@ export class OAuth2Client extends AuthClient { } private async getAccessTokenAsync(): Promise { - const shouldRefresh = - !this.credentials.access_token || this.isTokenExpiring(); + const shouldRefresh = !this.credentials.access_token || this.isExpired(); if (shouldRefresh) { if (!this.credentials.refresh_token) { if (this.refreshHandler) { @@ -938,7 +942,10 @@ export class OAuth2Client extends AuthClient { * { authorization: 'Bearer ' } */ async getRequestHeaders(url?: string | URL): Promise { - const headers = (await this.getRequestMetadataAsync(url)).headers; + const {headers, isIDToken} = await this.getRequestMetadataAsync(url); + if (!isIDToken) { + this.applyRegionalAccessBoundary(headers, url); + } return headers; } @@ -1118,17 +1125,23 @@ export class OAuth2Client extends AuthClient { opts: GaxiosOptions, reAuthRetried = false, ): Promise> { + const requestOpts = {...opts}; try { - const r = await this.getRequestMetadataAsync(); - opts.headers = Gaxios.mergeHeaders(opts.headers); + const {headers, isIDToken} = await this.getRequestMetadataAsync(); + requestOpts.headers = Gaxios.mergeHeaders(requestOpts.headers); - this.addUserProjectAndAuthHeaders(opts.headers, r.headers); + this.applyHeadersFromSource(requestOpts.headers, headers); if (this.apiKey) { - opts.headers.set('X-Goog-Api-Key', this.apiKey); + requestOpts.headers.set('X-Goog-Api-Key', this.apiKey); + } + + if (!isIDToken) { + // Id token flows are outside the scope of Regional Access Boundary. + this.applyRegionalAccessBoundary(requestOpts.headers, opts.url); } - return await this.transporter.request(opts); + return await this.transporter.request(requestOpts); } catch (e) { const res = (e as GaxiosError).response; if (res) { diff --git a/core/packages/google-auth-library-nodejs/src/auth/regionalaccessboundary.ts b/core/packages/google-auth-library-nodejs/src/auth/regionalaccessboundary.ts new file mode 100644 index 000000000000..8a8b591972c9 --- /dev/null +++ b/core/packages/google-auth-library-nodejs/src/auth/regionalaccessboundary.ts @@ -0,0 +1,278 @@ +// 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. + +import {Gaxios, GaxiosOptions} from 'gaxios'; +import {log as makeLog} from 'google-logging-utils'; + +const log = makeLog('auth'); + +export const SERVICE_ACCOUNT_LOOKUP_ENDPOINT = + 'https://staging-iamcredentials.sandbox.googleapis.com/v1/projects/-/serviceAccounts/{service_account_email}/allowedLocations'; + +export const WORKLOAD_LOOKUP_ENDPOINT = + 'https://staging-iamcredentials.sandbox.googleapis.com/v1/projects/{project_id}/locations/global/workloadIdentityPools/{pool_id}/allowedLocations'; + +export const WORKFORCE_LOOKUP_ENDPOINT = + 'https://staging-iamcredentials.sandbox.googleapis.com/v1/locations/global/workforcePools/{pool_id}/allowedLocations'; + +/** + * RAB is considered valid for 6 hours. + */ +const RAB_TTL_MILLIS = 6 * 60 * 60 * 1000; + +/** + * Grace period before hard expiry to trigger a background refresh (1 hour). + */ +const RAB_SOFT_EXPIRY_GRACE_PERIOD_MILLIS = 1 * 60 * 60 * 1000; + +/** + * Initial cooldown period for RAB lookup failures (15 minutes). + */ +const RAB_INITIAL_COOLDOWN_MILLIS = 15 * 60 * 1000; + +/** + * Maximum cooldown period for RAB lookup failures. + * Set as 6 hours. + */ +const RAB_MAX_COOLDOWN_MILLIS = 6 * 60 * 60 * 1000; + +/** + * Holds regional access boundary related information like locations + * where the credentials can be used. + */ +export interface RegionalAccessBoundaryData { + /** + * The readable text format of the allowed regional access boundary locations. + */ + locations?: string[]; + + /** + * The encoded text format of allowed regional access boundary locations. + */ + encodedLocations: string; +} + +export function isRegionalAccessBoundaryEnabled() { + const rabEnabled = + process.env['GOOGLE_AUTH_TRUST_BOUNDARY_ENABLE_EXPERIMENT']; + if (rabEnabled === undefined || rabEnabled === null) { + return false; + } + const lowercasedRabEnabled = rabEnabled.toLowerCase(); + if (lowercasedRabEnabled === 'true' || rabEnabled === '1') { + return true; + } + return false; +} + +export interface RegionalAccessBoundaryManagerOptions { + transporter: Gaxios; + getLookupUrl: () => Promise; + isUniverseDomainDefault: () => boolean; +} + +export class RegionalAccessBoundaryManager { + private regionalAccessBoundary: RegionalAccessBoundaryData | null = null; + private regionalAccessBoundaryExpiry = 0; + private regionalAccessBoundaryRefreshPromise: Promise | null = null; + private regionalAccessBoundaryCooldownTime = 0; + private regionalAccessBoundaryCooldownBackoff = RAB_INITIAL_COOLDOWN_MILLIS; + private options: RegionalAccessBoundaryManagerOptions; + + constructor(options: RegionalAccessBoundaryManagerOptions) { + this.options = options; + } + + get enabled(): boolean { + return isRegionalAccessBoundaryEnabled(); + } + + /** + * @internal + */ + get data(): RegionalAccessBoundaryData | null { + return this.regionalAccessBoundary; + } + + /** + * @internal + */ + get cooldownTime(): number { + return this.regionalAccessBoundaryCooldownTime; + } + + /** + * Returns the encoded locations string if the RAB is active and valid. + * Also triggers a background refresh if needed. + * @param url Optional endpoint URL being accessed. If missing, assumed global. + * @param headers The headers of the current request. + */ + getRegionalAccessBoundaryHeader( + url: string | URL | undefined, + headers: Headers, + ): string | null { + if (!this.enabled || !this.options.isUniverseDomainDefault()) { + return null; + } + + // Only attach/refresh for global endpoints + if (url && !this.isGlobalEndpoint(url)) { + return null; + } + + // Attempt to trigger refresh if we have a token. + const authHeader = headers.get('authorization'); + if (authHeader && authHeader.startsWith('Bearer ')) { + // authHeader.substring(7) as auth header is of type 'Bearer XYZ...' + this.maybeTriggerRegionalAccessBoundaryRefresh(authHeader.substring(7)); + } + + if ( + this.regionalAccessBoundary && + this.regionalAccessBoundary.encodedLocations && + Date.now() < this.regionalAccessBoundaryExpiry + ) { + return this.regionalAccessBoundary.encodedLocations; + } + return null; + } + + /** + * Checks if the given URL is a global endpoint (not regional). + * @param url The URL to check. + */ + private isGlobalEndpoint(url: string | URL): boolean { + try { + const hostname = + url instanceof URL ? url.hostname : new URL(url).hostname; + return ( + !hostname.endsWith('.rep.googleapis.com') && + !hostname.endsWith('.rep.sandbox.googleapis.com') + ); + } catch { + // If the URL is relative or malformed, assume it is global. + return true; + } + } + + /** + * Triggers an asynchronous regional access boundary refresh if needed. + * @param accessToken The access token to use for the lookup. + */ + private maybeTriggerRegionalAccessBoundaryRefresh(accessToken: string): void { + if (this.regionalAccessBoundaryRefreshPromise) { + return; + } + + const now = Date.now(); + + // Check if in cooldown + if (now < this.regionalAccessBoundaryCooldownTime) { + return; + } + + // Check if expired or never fetched (using soft expiry grace period) + const softExpiryThreshold = + this.regionalAccessBoundaryExpiry - RAB_SOFT_EXPIRY_GRACE_PERIOD_MILLIS; + if (!this.regionalAccessBoundary || now >= softExpiryThreshold) { + this.regionalAccessBoundaryRefreshPromise = + this.backgroundRefreshRegionalAccessBoundary(accessToken); + } + } + + /** + * Performs the background refresh of the regional access boundary. + * @param accessToken The access token to use for the lookup. + */ + private async backgroundRefreshRegionalAccessBoundary( + accessToken: string, + ): Promise { + try { + const data = await this.fetchRegionalAccessBoundary(accessToken); + if (data) { + this.regionalAccessBoundary = data; + this.regionalAccessBoundaryExpiry = Date.now() + RAB_TTL_MILLIS; + // Reset cooldown on success. + this.regionalAccessBoundaryCooldownTime = 0; + this.regionalAccessBoundaryCooldownBackoff = + RAB_INITIAL_COOLDOWN_MILLIS; + } + } catch (error) { + // Non-retryable or all retries failed: enter cooldown, + // initially for 15 mins which doubles after each failed cooldown 'exit' attempt. + this.regionalAccessBoundaryCooldownTime = + Date.now() + this.regionalAccessBoundaryCooldownBackoff; + this.regionalAccessBoundaryCooldownBackoff = Math.min( + this.regionalAccessBoundaryCooldownBackoff * 2, + RAB_MAX_COOLDOWN_MILLIS, + ); + log.error( + 'RegionalAccessBoundary: Lookup failed. Entering cooldown.', + error, + ); + } finally { + this.regionalAccessBoundaryRefreshPromise = null; + } + } + + /** + * Internal method to fetch RAB data. + * Retries for retryable 5xx errors from the RAB lookup endpoint. + * Throws if response from lookup is malformed. + */ + private async fetchRegionalAccessBoundary( + accessToken?: string, + ): Promise { + const regionalAccessBoundaryUrl = await this.options.getLookupUrl(); + if (!regionalAccessBoundaryUrl) { + return null; + } + + if (!accessToken) { + throw new Error( + 'RegionalAccessBoundary: Error calling lookup endpoint without valid access token', + ); + } + + const headers = new Headers({ + authorization: 'Bearer ' + accessToken, + }); + + const opts: GaxiosOptions = { + retry: true, + retryConfig: { + retry: 9, // Approximately 1 minute with default exponential backoff + retryDelay: 100, + httpMethodsToRetry: ['GET'], + statusCodesToRetry: [ + [500, 500], + [502, 504], + ], + }, + headers, + url: regionalAccessBoundaryUrl, + }; + + const {data: regionalAccessBoundaryData} = + await this.options.transporter.request(opts); + + if (!regionalAccessBoundaryData.encodedLocations) { + throw new Error( + 'RegionalAccessBoundary: Malformed response from lookup endpoint.', + ); + } + + return regionalAccessBoundaryData; + } +} \ No newline at end of file diff --git a/core/packages/google-auth-library-nodejs/src/util.ts b/core/packages/google-auth-library-nodejs/src/util.ts index 238ab604b109..d965887f5d52 100644 --- a/core/packages/google-auth-library-nodejs/src/util.ts +++ b/core/packages/google-auth-library-nodejs/src/util.ts @@ -300,3 +300,40 @@ export function getWellKnownCertificateConfigFileLocation(): string { function _isWindows(): boolean { return os.platform().startsWith('win'); } + +/** + * Returns the workforce identity pool ID if it is determinable + * from the audience resource name. + * @param audience The audience used to determine the pool ID. + * @return The pool ID associated with the workforce identity pool, if + * this can be determined from the audience field. Otherwise, null is + * returned. + */ +export function getWorkforcePoolIdFromAudience( + audience: string, +): string | null { + // STS audience pattern: + // .../workforcePools/$WORKFORCE_POOL_ID/providers/... + return ( + audience.match(/\/workforcePools\/(?[^/]+)\/providers\//)?.groups + ?.poolId ?? null + ); +} + +/** + * Returns the workload identity pool ID if it is determinable + * from the audience resource name. + * @param audience The audience used to determine the pool ID. + * @return The pool ID associated with the workload identity pool, if + * this can be determined from the audience field. Otherwise, null is + * returned. + */ +export function getWorkloadPoolIdFromAudience(audience: string): string | null { + // STS audience pattern: + // .../workloadIdentityPools/POOL_ID/providers/... + return ( + audience.match( + /\/workloadIdentityPools\/(?[^/]+)\/providers\//, + )?.groups?.workloadPool ?? null + ); +} \ No newline at end of file diff --git a/core/packages/google-auth-library-nodejs/test/test.authclient.ts b/core/packages/google-auth-library-nodejs/test/test.authclient.ts index 22b2528c6497..7c4748f5e790 100644 --- a/core/packages/google-auth-library-nodejs/test/test.authclient.ts +++ b/core/packages/google-auth-library-nodejs/test/test.authclient.ts @@ -13,7 +13,6 @@ // limitations under the License. import {strict as assert} from 'assert'; - import * as nock from 'nock'; import { Gaxios, @@ -23,10 +22,16 @@ import { GaxiosResponse, } from 'gaxios'; -import {AuthClient, PassThroughClient} from '../src'; +import {AuthClient, Compute, PassThroughClient} from '../src'; import {snakeToCamel} from '../src/util'; import {PRODUCT_NAME, USER_AGENT} from '../src/shared.cjs'; import * as logging from 'google-logging-utils'; +import {BASE_PATH, HOST_ADDRESS, HEADERS} from 'gcp-metadata'; +import sinon = require('sinon'); +import { + RegionalAccessBoundaryData, + SERVICE_ACCOUNT_LOOKUP_ENDPOINT, +} from '../src/auth/regionalaccessboundary'; // Fakes for the logger, to capture logs that would've happened. interface TestLog { @@ -54,6 +59,17 @@ class TestLogSink implements logging.DebugLogBackend { } describe('AuthClient', () => { + let sandbox: sinon.SinonSandbox; + + beforeEach(() => { + sandbox = sinon.createSandbox(); + }); + + afterEach(() => { + sandbox.restore(); + nock.cleanAll(); + }); + it('should accept and normalize snake case options to camel case', () => { const expected = { project_id: 'my-projectId', @@ -376,5 +392,225 @@ describe('AuthClient', () => { }); }); }); + + describe('regional access boundaries', () => { + const MOCK_ACCESS_TOKEN = 'abc123'; + const SERVICE_ACCOUNT_EMAIL = 'service-account@example.com'; + const EXPECTED_RAB_DATA: RegionalAccessBoundaryData = { + locations: ['us-central1', 'europe-west1'], + encodedLocations: '0x123', + }; + + function setupTokenNock( + email: string | 'default' = 'default', + ): nock.Scope { + const tokenPath = + email === 'default' + ? `${BASE_PATH}/instance/service-accounts/default/token` + : `${BASE_PATH}/instance/service-accounts/${email}/token`; + return nock(HOST_ADDRESS) + .get(tokenPath) + .reply( + 200, + {access_token: MOCK_ACCESS_TOKEN, expires_in: 10000}, + HEADERS, + ); + } + + beforeEach(() => { + process.env['GOOGLE_AUTH_TRUST_BOUNDARY_ENABLE_EXPERIMENT'] = 'true'; + }); + + afterEach(() => { + delete process.env['GOOGLE_AUTH_TRUST_BOUNDARY_ENABLE_EXPERIMENT']; + }); + + it('should trigger asynchronous background refresh and not block', async () => { + const compute = new Compute({ + serviceAccountEmail: SERVICE_ACCOUNT_EMAIL, + }); + // Set up nocks + const tokenScope = setupTokenNock(SERVICE_ACCOUNT_EMAIL); + // Use a promise to track when the RAB lookup is actually called + let rabLookupCalled = false; + const rabUrl = SERVICE_ACCOUNT_LOOKUP_ENDPOINT.replace( + '{service_account_email}', + encodeURIComponent(SERVICE_ACCOUNT_EMAIL), + ); + + const rabScope = nock(new URL(rabUrl).origin) + .get(new URL(rabUrl).pathname) + .reply(() => { + rabLookupCalled = true; + return [200, EXPECTED_RAB_DATA]; + }); + + // Initial call - should NOT have the header yet because refresh is async + const headers = await compute.getRequestHeaders( + 'https://pubsub.googleapis.com', + ); + + assert.strictEqual(headers.get('x-allowed-locations'), null); + + // Wait for the background task to complete (not ideal but necessary for testing side effect) + // In a real scenario we'd use a better way to wait for the internal promise + let attempts = 0; + while (!rabLookupCalled && attempts < 10) { + await new Promise(r => setTimeout(r, 50)); + attempts++; + } + + assert.strictEqual(rabLookupCalled, true); + + // Give the background processing a moment to update the class member + await new Promise(r => setTimeout(r, 50)); + assert.deepStrictEqual( + compute.getRegionalAccessBoundary(), + EXPECTED_RAB_DATA, + ); + + tokenScope.done(); + rabScope.done(); + }); + + it('should NOT trigger lookup for regional endpoints', async () => { + const compute = new Compute({ + serviceAccountEmail: SERVICE_ACCOUNT_EMAIL, + }); + + const tokenScope = setupTokenNock(SERVICE_ACCOUNT_EMAIL); + // No RAB nock setup here. If it's called, nock will throw. + + await compute.getRequestHeaders('https://us-east1.rep.googleapis.com'); + + tokenScope.done(); + // Assert no RAB lookup was attempted (implicitly verified by lack of nock error) + }); + + it('should NOT trigger lookup for non-GDU universes', async () => { + const compute = new Compute({ + serviceAccountEmail: SERVICE_ACCOUNT_EMAIL, + universe_domain: 'custom-universe.com', + }); + + const tokenScope = setupTokenNock(SERVICE_ACCOUNT_EMAIL); + + await compute.getRequestHeaders('https://pubsub.googleapis.com'); + + tokenScope.done(); + // Assert no RAB lookup was attempted + }); + + it('should NOT crash and should trigger lookup for relative URLs', async () => { + const compute = new Compute({ + serviceAccountEmail: SERVICE_ACCOUNT_EMAIL, + }); + + const tokenScope = setupTokenNock(SERVICE_ACCOUNT_EMAIL); + // If it treats the relative URL as global, it should try to call the RAB endpoint. + const rabUrl = SERVICE_ACCOUNT_LOOKUP_ENDPOINT.replace( + '{universe_domain}', + 'googleapis.com', + ).replace( + '{service_account_email}', + encodeURIComponent(SERVICE_ACCOUNT_EMAIL), + ); + + const rabScope = nock(new URL(rabUrl).origin) + .get(new URL(rabUrl).pathname) + .reply(200, EXPECTED_RAB_DATA); + + // This should NOT throw even though '/v1/resource' is relative + await compute.getRequestHeaders('/v1/resource'); + + // Wait for the background task to complete + let attempts = 0; + while (!compute.getRegionalAccessBoundary() && attempts < 10) { + await new Promise(r => setTimeout(r, 50)); + attempts++; + } + + assert.deepStrictEqual( + compute.getRegionalAccessBoundary(), + EXPECTED_RAB_DATA, + ); + + tokenScope.done(); + rabScope.done(); + }); + + it('should retry on retryable errors in background', async () => { + const compute = new Compute({ + serviceAccountEmail: SERVICE_ACCOUNT_EMAIL, + }); + + setupTokenNock(SERVICE_ACCOUNT_EMAIL); + + // Mock 503 then 200 + const rabUrl = SERVICE_ACCOUNT_LOOKUP_ENDPOINT.replace( + '{service_account_email}', + encodeURIComponent(SERVICE_ACCOUNT_EMAIL), + ); + + const rabFail = nock(new URL(rabUrl).origin) + .get(new URL(rabUrl).pathname) + .reply(503); + const rabSuccess = nock(new URL(rabUrl).origin) + .get(new URL(rabUrl).pathname) + .reply(200, EXPECTED_RAB_DATA); + + await compute.getRequestHeaders('https://pubsub.googleapis.com'); + + // Wait for retries (exponential backoff might take a moment) + let attempts = 0; + while (!compute.getRegionalAccessBoundary() && attempts < 20) { + await new Promise(r => setTimeout(r, 150)); + attempts++; + } + + assert.deepStrictEqual( + compute.getRegionalAccessBoundary(), + EXPECTED_RAB_DATA, + ); + rabFail.done(); + rabSuccess.done(); + }); + + it('should enter cooldown on non-retryable error', async () => { + const compute = new Compute({ + serviceAccountEmail: SERVICE_ACCOUNT_EMAIL, + }); + + setupTokenNock(SERVICE_ACCOUNT_EMAIL); + + const rabUrl = SERVICE_ACCOUNT_LOOKUP_ENDPOINT.replace( + '{service_account_email}', + encodeURIComponent(SERVICE_ACCOUNT_EMAIL), + ); + + const rabFail = nock(new URL(rabUrl).origin) + .get(new URL(rabUrl).pathname) + .reply(400, {error: 'Permanent failure'}); + + await compute.getRequestHeaders('https://pubsub.googleapis.com'); + + // Wait for it to fail and enter cooldown + let attempts = 0; + while ( + !compute.getRegionalAccessBoundaryCooldownTime() && + attempts < 10 + ) { + await new Promise(r => setTimeout(r, 50)); + attempts++; + } + + assert.ok(compute.getRegionalAccessBoundaryCooldownTime() > Date.now()); + + // Subsequent call should NOT trigger nock (which would fail as we only set up 1) + await compute.getRequestHeaders('https://pubsub.googleapis.com'); + + rabFail.done(); + }); + }); }); -}); +}); \ No newline at end of file diff --git a/core/packages/google-auth-library-nodejs/test/test.baseexternalclient.ts b/core/packages/google-auth-library-nodejs/test/test.baseexternalclient.ts index 3020b47cd49e..573a4df0083e 100644 --- a/core/packages/google-auth-library-nodejs/test/test.baseexternalclient.ts +++ b/core/packages/google-auth-library-nodejs/test/test.baseexternalclient.ts @@ -38,9 +38,16 @@ import { mockGenerateAccessToken, mockStsTokenExchange, getExpectedExternalAccountMetricsHeaderValue, + saEmail, } from './externalclienthelper'; import {DEFAULT_UNIVERSE} from '../src/auth/authclient'; import {TestUtils} from './utils'; +import { + RegionalAccessBoundaryData, + SERVICE_ACCOUNT_LOOKUP_ENDPOINT, + WORKFORCE_LOOKUP_ENDPOINT, + WORKLOAD_LOOKUP_ENDPOINT, +} from '../src/auth/regionalaccessboundary'; nock.disableNetConnect(); interface SampleResponse { @@ -2706,4 +2713,232 @@ describe('BaseExternalAccountClient', () => { ); }); }); + + describe('regional access boundaries', () => { + const MOCK_ACCESS_TOKEN = 'ACCESS_TOKEN'; + const MOCK_AUTH_HEADER = `Bearer ${MOCK_ACCESS_TOKEN}`; + const EXPECTED_RAB_DATA: RegionalAccessBoundaryData = { + locations: ['some-locations'], + encodedLocations: '0xdeadbeef', + }; + + beforeEach(() => { + process.env['GOOGLE_AUTH_TRUST_BOUNDARY_ENABLE_EXPERIMENT'] = 'true'; + }); + + afterEach(() => { + delete process.env['GOOGLE_AUTH_TRUST_BOUNDARY_ENABLE_EXPERIMENT']; + nock.cleanAll(); + }); + + it('should trigger asynchronous RAB refresh for workload identity', async () => { + const projectNumber = '12345'; + const workloadPoolId = 'my-pool'; + const workloadAudience = `//iam.googleapis.com/projects/${projectNumber}/locations/global/workloadIdentityPools/${workloadPoolId}/providers/my-provider`; + const workloadOptions = { + ...externalAccountOptions, + audience: workloadAudience, + }; + const client = new TestExternalAccountClient(workloadOptions); + + const stsScope = mockStsTokenExchange([ + { + statusCode: 200, + response: {...stsSuccessfulResponse, access_token: MOCK_ACCESS_TOKEN}, + request: { + grant_type: 'urn:ietf:params:oauth:grant-type:token-exchange', + audience: workloadAudience, + scope: 'https://www.googleapis.com/auth/cloud-platform', + requested_token_type: + 'urn:ietf:params:oauth:token-type:access_token', + subject_token: 'subject_token_0', + subject_token_type: 'urn:ietf:params:oauth:token-type:jwt', + }, + }, + ]); + + const lookupUrl = WORKLOAD_LOOKUP_ENDPOINT.replace( + '{project_id}', + projectNumber, + ).replace('{pool_id}', workloadPoolId); + + let rabLookupCalled = false; + const rabScope = nock(new URL(lookupUrl).origin) + .get(new URL(lookupUrl).pathname) + .matchHeader('authorization', MOCK_AUTH_HEADER) + .reply(() => { + rabLookupCalled = true; + return [200, EXPECTED_RAB_DATA]; + }); + + // Initial call - should NOT have the header yet + const headers = await client.getRequestHeaders(); + assert.strictEqual(headers.get('x-allowed-locations'), null); + + // Wait for background lookup + let attempts = 0; + while (!rabLookupCalled && attempts < 10) { + await new Promise(r => setTimeout(r, 50)); + attempts++; + } + assert.strictEqual(rabLookupCalled, true); + + await new Promise(r => setTimeout(r, 50)); + assert.deepStrictEqual( + client.getRegionalAccessBoundary(), + EXPECTED_RAB_DATA, + ); + + stsScope.done(); + rabScope.done(); + }); + + it('should trigger asynchronous RAB refresh for workforce identity', async () => { + const workforcePoolId = 'my-workforce-pool'; + const location = 'global'; + const workforceAudience = `//iam.googleapis.com/locations/${location}/workforcePools/${workforcePoolId}/providers/my-provider`; + const workforceOptions = { + ...externalAccountOptions, + audience: workforceAudience, + }; + const client = new TestExternalAccountClient(workforceOptions); + + const stsScope = mockStsTokenExchange([ + { + statusCode: 200, + response: {...stsSuccessfulResponse, access_token: MOCK_ACCESS_TOKEN}, + request: { + grant_type: 'urn:ietf:params:oauth:grant-type:token-exchange', + audience: workforceAudience, + scope: 'https://www.googleapis.com/auth/cloud-platform', + requested_token_type: + 'urn:ietf:params:oauth:token-type:access_token', + subject_token: 'subject_token_0', + subject_token_type: 'urn:ietf:params:oauth:token-type:jwt', + }, + }, + ]); + + const lookupUrl = WORKFORCE_LOOKUP_ENDPOINT.replace( + '{location}', + location, + ).replace('{pool_id}', workforcePoolId); + + let rabLookupCalled = false; + const rabScope = nock(new URL(lookupUrl).origin) + .get(new URL(lookupUrl).pathname) + .matchHeader('authorization', MOCK_AUTH_HEADER) + .reply(() => { + rabLookupCalled = true; + return [200, EXPECTED_RAB_DATA]; + }); + + const headers = await client.getRequestHeaders(); + assert.strictEqual(headers.get('x-allowed-locations'), null); + + let attempts = 0; + while (!rabLookupCalled && attempts < 10) { + await new Promise(r => setTimeout(r, 50)); + attempts++; + } + assert.strictEqual(rabLookupCalled, true); + + await new Promise(r => setTimeout(r, 50)); + assert.deepStrictEqual( + client.getRegionalAccessBoundary(), + EXPECTED_RAB_DATA, + ); + + stsScope.done(); + rabScope.done(); + }); + + it('should fail background lookup for an invalid audience', async () => { + const invalidAudience = 'invalid-audience-format/providers/1235'; + const invalidOptions = { + ...externalAccountOptions, + audience: invalidAudience, + }; + const client = new TestExternalAccountClient(invalidOptions); + + // Note: background refresh fails silently in terms of getRequestHeaders resolving. + // But we can manually trigger getRegionalAccessBoundaryUrl to verify it throws. + await assert.rejects( + client.getRegionalAccessBoundaryUrl(), + /RegionalAccessBoundary: Invalid audience provided/, + ); + }); + + it('should trigger asynchronous RAB refresh for impersonated service account', async () => { + const projectNumber = '12345'; + const workloadPoolId = 'my-pool'; + const workloadAudience = `//iam.googleapis.com/projects/${projectNumber}/locations/global/workloadIdentityPools/${workloadPoolId}/providers/my-provider`; + const workloadOptions = { + ...externalAccountOptionsWithSA, + audience: workloadAudience, + }; + const client = new TestExternalAccountClient(workloadOptions); + + const stsScope = mockStsTokenExchange([ + { + statusCode: 200, + response: {...stsSuccessfulResponse, access_token: MOCK_ACCESS_TOKEN}, + request: { + grant_type: 'urn:ietf:params:oauth:grant-type:token-exchange', + audience: workloadAudience, + scope: 'https://www.googleapis.com/auth/cloud-platform', + requested_token_type: + 'urn:ietf:params:oauth:token-type:access_token', + subject_token: 'subject_token_0', + subject_token_type: 'urn:ietf:params:oauth:token-type:jwt', + }, + }, + ]); + + const saSuccessResponse = { + accessToken: 'SA_ACCESS_TOKEN', + expireTime: new Date(Date.now() + 60 * 60 * 100).toISOString(), + }; + const impersonatedScope = mockGenerateAccessToken({ + statusCode: 200, + response: saSuccessResponse, + token: stsSuccessfulResponse.access_token, + scopes: ['https://www.googleapis.com/auth/cloud-platform'], + }); + + const lookupUrl = SERVICE_ACCOUNT_LOOKUP_ENDPOINT.replace( + '{service_account_email}', + encodeURIComponent(saEmail), + ); + + let rabLookupCalled = false; + const rabScope = nock(new URL(lookupUrl).origin) + .get(new URL(lookupUrl).pathname) + .matchHeader('authorization', `Bearer ${saSuccessResponse.accessToken}`) + .reply(() => { + rabLookupCalled = true; + return [200, EXPECTED_RAB_DATA]; + }); + + const headers = await client.getRequestHeaders(); + assert.strictEqual(headers.get('x-allowed-locations'), null); + + let attempts = 0; + while (!rabLookupCalled && attempts < 10) { + await new Promise(r => setTimeout(r, 50)); + attempts++; + } + assert.strictEqual(rabLookupCalled, true); + + await new Promise(r => setTimeout(r, 50)); + assert.deepStrictEqual( + client.getRegionalAccessBoundary(), + EXPECTED_RAB_DATA, + ); + + stsScope.done(); + rabScope.done(); + impersonatedScope.done(); + }); + }); }); diff --git a/core/packages/google-auth-library-nodejs/test/test.compute.ts b/core/packages/google-auth-library-nodejs/test/test.compute.ts index 981eac6c4f69..301a75691c1b 100644 --- a/core/packages/google-auth-library-nodejs/test/test.compute.ts +++ b/core/packages/google-auth-library-nodejs/test/test.compute.ts @@ -17,7 +17,11 @@ import {describe, it, beforeEach, afterEach} from 'mocha'; import {BASE_PATH, HEADERS, HOST_ADDRESS} from 'gcp-metadata'; import * as nock from 'nock'; import * as sinon from 'sinon'; -import {Compute} from '../src'; +import { Compute, gcpMetadata } from '../src'; +import { + SERVICE_ACCOUNT_LOOKUP_ENDPOINT, + RegionalAccessBoundaryData, +} from '../src/auth/regionalaccessboundary'; nock.disableNetConnect(); @@ -261,4 +265,110 @@ describe('compute', () => { assert.fail('failed to throw'); }); + describe('regional access boundaries', () => { + let sandbox: sinon.SinonSandbox; + + const MOCK_ACCESS_TOKEN = 'abc123'; + const MOCK_AUTH_HEADER = `Bearer ${MOCK_ACCESS_TOKEN}`; + const EXPECTED_RAB_DATA: RegionalAccessBoundaryData = { + locations: ['sadad', 'asdad'], + encodedLocations: '000x9', + }; + + function setupTokenNock(email: string | 'default' = 'default'): nock.Scope { + const tokenPath = + email === 'default' + ? `${BASE_PATH}/instance/service-accounts/default/token` + : `${BASE_PATH}/instance/service-accounts/${email}/token`; + return nock(HOST_ADDRESS) + .get(tokenPath) + .reply( + 200, + { access_token: MOCK_ACCESS_TOKEN, expires_in: 10000 }, + HEADERS, + ); + } + + function setupRegionalAccessBoundaryNock( + email: string, + regionalAccessBoundaryData: RegionalAccessBoundaryData = EXPECTED_RAB_DATA, + ): nock.Scope { + const lookupUrl = SERVICE_ACCOUNT_LOOKUP_ENDPOINT.replace( + '{service_account_email}', + encodeURIComponent(email), + ); + return nock(new URL(lookupUrl).origin) + .get(new URL(lookupUrl).pathname) + .matchHeader('authorization', MOCK_AUTH_HEADER) + .reply(200, regionalAccessBoundaryData); + } + + beforeEach(() => { + sandbox = sinon.createSandbox(); + process.env['GOOGLE_AUTH_TRUST_BOUNDARY_ENABLE_EXPERIMENT'] = 'true'; + }); + + afterEach(() => { + delete process.env['GOOGLE_AUTH_TRUST_BOUNDARY_ENABLE_EXPERIMENT']; + sandbox.restore(); + nock.cleanAll(); + }); + + it('should trigger asynchronous RAB refresh using email from metadata server', async () => { + const compute = new Compute(); + const fakeEmail = 'fake-default-sa@developer.gserviceaccount.com'; + const metadataStub = sandbox.stub(gcpMetadata, 'instance'); + metadataStub.callThrough(); + metadataStub + .withArgs('service-accounts/default/email') + .resolves(fakeEmail); + + const tokenScope = setupTokenNock('default'); + const rabScope = setupRegionalAccessBoundaryNock(fakeEmail); + let rabLookupCalled = false; + rabScope.on('request', () => { + rabLookupCalled = true; + }); + + const url = 'https://pubsub.googleapis.com'; + const headers = await compute.getRequestHeaders(url); + + // Initial headers should NOT have RAB + assert.strictEqual(headers.get('x-allowed-locations'), null); + + // Wait for background tasks (email resolution + RAB lookup) + let attempts = 0; + while (!rabLookupCalled && attempts < 10) { + await new Promise(r => setTimeout(r, 100)); + attempts++; + } + assert.strictEqual(rabLookupCalled, true); + + await new Promise(r => setTimeout(r, 50)); + assert.deepStrictEqual( + compute.getRegionalAccessBoundary(), + EXPECTED_RAB_DATA, + ); + + tokenScope.done(); + rabScope.done(); + }); + + it('should fail getRegionalAccessBoundaryUrl in background if metadata call fails', async () => { + const compute = new Compute(); + + const metadataStub = sandbox.stub(gcpMetadata, 'instance'); + metadataStub.callThrough(); + metadataStub + .withArgs('service-accounts/default/email') + .rejects(new Error('metadata failure')); + + // Error happens in background, so getRequestHeaders resolves fine. + // We manually call getRegionalAccessBoundaryUrl to verify the failure logic. + await assert.rejects( + compute.getRegionalAccessBoundaryUrl(), + /RegionalAccessBoundary: Failed to retrieve default service account email from metadata server./, + ); + }); + }); }); diff --git a/core/packages/google-auth-library-nodejs/test/test.externalaccountauthorizeduserclient.ts b/core/packages/google-auth-library-nodejs/test/test.externalaccountauthorizeduserclient.ts index e5aca190ebc9..cefe14e0fce6 100644 --- a/core/packages/google-auth-library-nodejs/test/test.externalaccountauthorizeduserclient.ts +++ b/core/packages/google-auth-library-nodejs/test/test.externalaccountauthorizeduserclient.ts @@ -17,7 +17,7 @@ import {describe, it, afterEach, beforeEach} from 'mocha'; import * as nock from 'nock'; import * as sinon from 'sinon'; import * as qs from 'querystring'; -import {assertGaxiosResponsePresent, getAudience} from './externalclienthelper'; +import {assertGaxiosResponsePresent} from './externalclienthelper'; import { EXTERNAL_ACCOUNT_AUTHORIZED_USER_TYPE, ExternalAccountAuthorizedUserClient, @@ -31,6 +31,10 @@ import { } from '../src/auth/oauth2common'; import {DEFAULT_UNIVERSE} from '../src/auth/authclient'; import {TestUtils} from './utils'; +import { + RegionalAccessBoundaryData, + WORKFORCE_LOOKUP_ENDPOINT, +} from '../src/auth/regionalaccessboundary'; nock.disableNetConnect(); @@ -83,10 +87,11 @@ describe('ExternalAccountAuthorizedUserClient', () => { let clock: sinon.SinonFakeTimers; const referenceDate = new Date('2020-08-11T06:55:22.345Z'); - const audience = getAudience(); + const workforcePoolAudience = + '//iam.googleapis.com/locations/global/workforcePools/pool-id-123/providers/provider-id-abc'; const externalAccountAuthorizedUserCredentialOptions = { type: EXTERNAL_ACCOUNT_AUTHORIZED_USER_TYPE, - audience: audience, + audience: workforcePoolAudience, client_id: 'clientId', client_secret: 'clientSecret', refresh_token: 'refreshToken', @@ -95,7 +100,7 @@ describe('ExternalAccountAuthorizedUserClient', () => { } as ExternalAccountAuthorizedUserClientOptions; const externalAccountAuthorizedUserCredentialOptionsNoToken = { type: EXTERNAL_ACCOUNT_AUTHORIZED_USER_TYPE, - audience: audience, + audience: workforcePoolAudience, client_id: 'clientId', client_secret: 'clientSecret', refresh_token: 'refreshToken', @@ -893,4 +898,92 @@ describe('ExternalAccountAuthorizedUserClient', () => { scopes.forEach(scope => scope.done()); }); }); + + describe('regional access boundaries', () => { + const MOCK_ACCESS_TOKEN = 'newAccessToken'; + const MOCK_AUTH_HEADER = `Bearer ${MOCK_ACCESS_TOKEN}`; + const EXPECTED_RAB_DATA: RegionalAccessBoundaryData = { + locations: ['some-locations'], + encodedLocations: '0xdeadbeef', + }; + + beforeEach(() => { + clock.restore(); + process.env['GOOGLE_AUTH_TRUST_BOUNDARY_ENABLE_EXPERIMENT'] = 'true'; + }); + + afterEach(() => { + delete process.env['GOOGLE_AUTH_TRUST_BOUNDARY_ENABLE_EXPERIMENT']; + nock.cleanAll(); + }); + + it('should trigger asynchronous RAB refresh successfully', async () => { + const workforcePoolId = 'pool-id-123'; + const client = new ExternalAccountAuthorizedUserClient( + externalAccountAuthorizedUserCredentialOptions, + ); + + const stsScope = mockStsTokenRefresh(BASE_URL, REFRESH_PATH, [ + { + statusCode: 200, + response: successfulRefreshResponse, + request: { + grant_type: 'refresh_token', + refresh_token: 'refreshToken', + }, + }, + ]); + + const lookupUrl = WORKFORCE_LOOKUP_ENDPOINT.replace( + '{pool_id}', + encodeURIComponent(workforcePoolId), + ); + + let rabLookupCalled = false; + const rabScope = nock(new URL(lookupUrl).origin) + .get(new URL(lookupUrl).pathname) + .matchHeader('authorization', MOCK_AUTH_HEADER) + .reply(() => { + rabLookupCalled = true; + return [200, EXPECTED_RAB_DATA]; + }); + + // Initial call - should NOT have the header yet + const headers = await client.getRequestHeaders(); + assert.strictEqual(headers.get('x-allowed-locations'), null); + + // Wait for background lookup + let attempts = 0; + while (!rabLookupCalled && attempts < 20) { + await new Promise(r => setTimeout(r, 100)); + attempts++; + } + assert.strictEqual(rabLookupCalled, true); + + await new Promise(r => setTimeout(r, 100)); + assert.deepStrictEqual( + client.getRegionalAccessBoundary(), + EXPECTED_RAB_DATA, + ); + + stsScope.done(); + rabScope.done(); + }); + + it('should fail background lookup for an invalid audience', async () => { + const invalidAudience = 'invalid-audience-format'; + const options = { + ...externalAccountAuthorizedUserCredentialOptions, + audience: invalidAudience, + }; + const client = new ExternalAccountAuthorizedUserClient(options); + + // Note: background refresh fails silently in terms of getRequestHeaders resolving. + // But we can manually trigger getRegionalAccessBoundaryUrl to verify it throws. + await assert.rejects( + client.getRegionalAccessBoundaryUrl(), + /RegionalAccessBoundary: A workforce pool ID is required for regional access boundary lookups but could not be determined from the audience/, + ); + }); + }); }); diff --git a/core/packages/google-auth-library-nodejs/test/test.externalclient.ts b/core/packages/google-auth-library-nodejs/test/test.externalclient.ts index d85a420b7fc3..6c64d360150f 100644 --- a/core/packages/google-auth-library-nodejs/test/test.externalclient.ts +++ b/core/packages/google-auth-library-nodejs/test/test.externalclient.ts @@ -109,45 +109,35 @@ describe('ExternalAccountClient', () => { ]; it('should return IdentityPoolClient on IdentityPoolClientOptions', () => { - const expectedClient = new IdentityPoolClient(fileSourcedOptions); - - assert.deepStrictEqual( - ExternalAccountClient.fromJSON(fileSourcedOptions), - expectedClient, - ); + const client = ExternalAccountClient.fromJSON(fileSourcedOptions); + assert.ok(client instanceof IdentityPoolClient); }); it('should return IdentityPoolClient with expected RefreshOptions', () => { - const expectedClient = new IdentityPoolClient({ + const client = ExternalAccountClient.fromJSON({ ...fileSourcedOptions, ...refreshOptions, }); - assert.deepStrictEqual( - ExternalAccountClient.fromJSON({ - ...fileSourcedOptions, - ...refreshOptions, - }), - expectedClient, - ); + assert.ok(client instanceof IdentityPoolClient); + assert.strictEqual(client!.eagerRefreshThresholdMillis, 10000); + assert.strictEqual(client!.forceRefreshOnFailure, true); }); it('should return AwsClient on AwsClientOptions', () => { - const expectedClient = new AwsClient(awsOptions); - - assert.deepStrictEqual( - ExternalAccountClient.fromJSON(awsOptions), - expectedClient, - ); + const client = ExternalAccountClient.fromJSON(awsOptions); + assert.ok(client instanceof AwsClient); }); it('should return AwsClient with expected RefreshOptions', () => { - const expectedClient = new AwsClient({...awsOptions, ...refreshOptions}); + const client = ExternalAccountClient.fromJSON({ + ...awsOptions, + ...refreshOptions, + }); - assert.deepStrictEqual( - ExternalAccountClient.fromJSON({...awsOptions, ...refreshOptions}), - expectedClient, - ); + assert.ok(client instanceof AwsClient); + assert.strictEqual(client!.eagerRefreshThresholdMillis, 10000); + assert.strictEqual(client!.forceRefreshOnFailure, true); }); it('should return an IdentityPoolClient with a workforce config', () => { @@ -167,41 +157,28 @@ describe('ExternalAccountClient', () => { for (const validWorkforceIdentityPoolClientAudience of validWorkforceIdentityPoolClientAudiences) { workforceFileSourcedOptions.audience = validWorkforceIdentityPoolClientAudience; - const expectedClient = new IdentityPoolClient( - workforceFileSourcedOptions, - ); - assert.deepStrictEqual( - ExternalAccountClient.fromJSON(workforceFileSourcedOptions), - expectedClient, + const client = ExternalAccountClient.fromJSON( + workforceFileSourcedOptions, ); + assert.ok(client instanceof IdentityPoolClient); } }); it('should return PluggableAuthClient on PluggableAuthClientOptions', () => { - const expectedClient = new PluggableAuthClient( - pluggableAuthClientOptions, - ); - - assert.deepStrictEqual( - ExternalAccountClient.fromJSON(pluggableAuthClientOptions), - expectedClient, - ); + const client = ExternalAccountClient.fromJSON(pluggableAuthClientOptions); + assert.ok(client instanceof PluggableAuthClient); }); it('should return PluggableAuthClient with expected RefreshOptions', () => { - const expectedClient = new PluggableAuthClient({ + const client = ExternalAccountClient.fromJSON({ ...pluggableAuthClientOptions, ...refreshOptions, }); - assert.deepStrictEqual( - ExternalAccountClient.fromJSON({ - ...pluggableAuthClientOptions, - ...refreshOptions, - }), - expectedClient, - ); + assert.ok(client instanceof PluggableAuthClient); + assert.strictEqual(client!.eagerRefreshThresholdMillis, 10000); + assert.strictEqual(client!.forceRefreshOnFailure, true); }); invalidWorkforceIdentityPoolClientAudiences.forEach( diff --git a/core/packages/google-auth-library-nodejs/test/test.impersonated.ts b/core/packages/google-auth-library-nodejs/test/test.impersonated.ts index e7be5ddf177b..b8ea708414d8 100644 --- a/core/packages/google-auth-library-nodejs/test/test.impersonated.ts +++ b/core/packages/google-auth-library-nodejs/test/test.impersonated.ts @@ -19,6 +19,11 @@ import * as nock from 'nock'; import {describe, it, afterEach} from 'mocha'; import {Impersonated, JWT, UserRefreshClient} from '../src'; import {CredentialRequest} from '../src/auth/credentials'; +import { + SERVICE_ACCOUNT_LOOKUP_ENDPOINT, + RegionalAccessBoundaryData, +} from '../src/auth/regionalaccessboundary'; +import sinon = require('sinon'); const PEM_PATH = './test/fixtures/private.pem'; @@ -589,4 +594,109 @@ describe('impersonated', () => { assert.equal(resp.signedBlob, expectedSignedBlob); scopes.forEach(s => s.done()); }); + + describe('regional access boundaries', () => { + let sandbox: sinon.SinonSandbox; + const TARGET_PRINCIPAL_EMAIL = 'target@project.iam.gserviceaccount.com'; + const MOCK_ACCESS_TOKEN = 'abc123'; + const MOCK_AUTH_HEADER = `Bearer ${MOCK_ACCESS_TOKEN}`; + + const EXPECTED_RAB_DATA: RegionalAccessBoundaryData = { + locations: ['sadad', 'asdad'], + encodedLocations: '000x9', + }; + + function setupRegionalAccessBoundaryNock( + email: string, + regionalAccessBoundaryData: RegionalAccessBoundaryData = EXPECTED_RAB_DATA, + ): nock.Scope { + const lookupUrl = SERVICE_ACCOUNT_LOOKUP_ENDPOINT.replace( + '{service_account_email}', + encodeURIComponent(email), + ); + return nock(new URL(lookupUrl).origin) + .get(new URL(lookupUrl).pathname) + .matchHeader('authorization', MOCK_AUTH_HEADER) + .reply(200, regionalAccessBoundaryData); + } + + beforeEach(() => { + sandbox = sinon.createSandbox(); + process.env['GOOGLE_AUTH_TRUST_BOUNDARY_ENABLE_EXPERIMENT'] = 'true'; + }); + + afterEach(() => { + delete process.env['GOOGLE_AUTH_TRUST_BOUNDARY_ENABLE_EXPERIMENT']; + sandbox.restore(); + nock.cleanAll(); + }); + + it('should trigger asynchronous RAB refresh', async () => { + const tomorrow = new Date(); + tomorrow.setDate(tomorrow.getDate() + 1); + const impersonated = new Impersonated({ + sourceClient: createSampleJWTClient(), + targetPrincipal: TARGET_PRINCIPAL_EMAIL, + lifetime: 30, + delegates: [], + targetScopes: ['https://www.googleapis.com/auth/cloud-platform'], + }); + + const tokenScope = createGTokenMock({access_token: MOCK_ACCESS_TOKEN}); + const saScope = nock('https://iamcredentials.googleapis.com') + .post( + `/v1/projects/-/serviceAccounts/${TARGET_PRINCIPAL_EMAIL}:generateAccessToken`, + ) + .reply(200, { + accessToken: MOCK_ACCESS_TOKEN, + expireTime: tomorrow.toISOString(), + }); + + let rabLookupCalled = false; + const rabScope = setupRegionalAccessBoundaryNock(TARGET_PRINCIPAL_EMAIL); + rabScope.on('request', () => { + rabLookupCalled = true; + }); + + const url = 'https://pubsub.googleapis.com'; + const headers = await impersonated.getRequestHeaders(url); + + // Initial headers should NOT have RAB + assert.strictEqual(headers.get('x-allowed-locations'), null); + + // Wait for background lookup + let attempts = 0; + while (!rabLookupCalled && attempts < 10) { + await new Promise(r => setTimeout(r, 50)); + attempts++; + } + assert.strictEqual(rabLookupCalled, true); + + await new Promise(r => setTimeout(r, 50)); + assert.deepStrictEqual( + impersonated.getRegionalAccessBoundary(), + EXPECTED_RAB_DATA, + ); + + tokenScope.done(); + saScope.done(); + rabScope.done(); + }); + + it('should fail getRegionalAccessBoundaryUrl in background if no target principal is specified', async () => { + const impersonated = new Impersonated({ + sourceClient: createSampleJWTClient(), + // targetPrincipal missing + lifetime: 30, + delegates: [], + targetScopes: ['https://www.googleapis.com/auth/cloud-platform'], + }); + + // Error happens in background. + await assert.rejects( + impersonated.getRegionalAccessBoundaryUrl(), + /RegionalAccessBoundary: A targetPrincipal is required for regional access boundary lookups but was not provided in the ImpersonatedClient options./, + ); + }); + }); }); diff --git a/core/packages/google-auth-library-nodejs/test/test.jwt.ts b/core/packages/google-auth-library-nodejs/test/test.jwt.ts index cb5ed85ba4ce..338de68c44f5 100644 --- a/core/packages/google-auth-library-nodejs/test/test.jwt.ts +++ b/core/packages/google-auth-library-nodejs/test/test.jwt.ts @@ -22,6 +22,10 @@ import * as sinon from 'sinon'; import {GoogleAuth, JWT} from '../src'; import {CredentialRequest, JWTInput} from '../src/auth/credentials'; import * as jwtaccess from '../src/auth/jwtaccess'; +import { + SERVICE_ACCOUNT_LOOKUP_ENDPOINT, + RegionalAccessBoundaryData, +} from '../src/auth/regionalaccessboundary'; function removeBearerFromAuthorizationHeader(headers: Headers): string { return (headers.get('authorization') || '').replace('Bearer ', ''); @@ -1244,4 +1248,173 @@ describe('jwt', () => { assert.strictEqual(headers.get('authorization'), want); }); }); + + describe('regional access boundaries', () => { + let sandbox: sinon.SinonSandbox; + const SERVICE_ACCOUNT_EMAIL = 'service-account@example.com'; + const MOCK_ACCESS_TOKEN = 'abc123'; + const MOCK_AUTH_HEADER = `Bearer ${MOCK_ACCESS_TOKEN}`; + + const EXPECTED_RAB_DATA: RegionalAccessBoundaryData = { + locations: ['sadad', 'asdad'], + encodedLocations: '000x9', + }; + + function setupRegionalAccessBoundaryNock( + email: string, + regionalAccessBoundaryData: RegionalAccessBoundaryData = EXPECTED_RAB_DATA, + authHeader = MOCK_AUTH_HEADER, + ): nock.Scope { + const lookupUrl = SERVICE_ACCOUNT_LOOKUP_ENDPOINT.replace( + '{service_account_email}', + encodeURIComponent(email), + ); + return nock(new URL(lookupUrl).origin) + .get(new URL(lookupUrl).pathname) + .matchHeader('authorization', authHeader) + .reply(200, regionalAccessBoundaryData); + } + + beforeEach(() => { + sandbox = sinon.createSandbox(); + process.env['GOOGLE_AUTH_TRUST_BOUNDARY_ENABLE_EXPERIMENT'] = 'true'; + }); + + afterEach(() => { + delete process.env['GOOGLE_AUTH_TRUST_BOUNDARY_ENABLE_EXPERIMENT']; + sandbox.restore(); + nock.cleanAll(); + }); + + it('should trigger asynchronous regional access boundaries refresh', async () => { + const jwt = new JWT({ + email: SERVICE_ACCOUNT_EMAIL, + keyFile: PEM_PATH, + scopes: ['http://bar', 'http://foo'], + subject: 'bar@subjectaccount.com', + }); + jwt.credentials = { refresh_token: 'jwt-placeholder' }; + + const tokenScope = createGTokenMock({ access_token: MOCK_ACCESS_TOKEN }); + + let rabLookupCalled = false; + const rabScope = setupRegionalAccessBoundaryNock(SERVICE_ACCOUNT_EMAIL); + rabScope.on('request', () => { + rabLookupCalled = true; + }); + + // Initial call - headers should NOT have the RAB yet + const headers = await jwt.getRequestHeaders( + 'https://pubsub.googleapis.com', + ); + assert.strictEqual(headers.get('x-allowed-locations'), null); + + // Wait for background lookup + let attempts = 0; + while (!rabLookupCalled && attempts < 10) { + await new Promise(r => setTimeout(r, 50)); + attempts++; + } + assert.strictEqual(rabLookupCalled, true); + + // Give it a moment to update state + await new Promise(r => setTimeout(r, 50)); + assert.deepStrictEqual( + jwt.getRegionalAccessBoundary(), + EXPECTED_RAB_DATA, + ); + + tokenScope.done(); + rabScope.done(); + }); + + it('should trigger RAB refresh for self-signed JWT', async () => { + // Self-signed JWT (no scopes) + const keys = keypair(512); + const jwt = new JWT({ + email: SERVICE_ACCOUNT_EMAIL, + key: keys.private, + }); + jwt.credentials = { refresh_token: 'jwt-placeholder' }; + + const lookupUrl = SERVICE_ACCOUNT_LOOKUP_ENDPOINT.replace( + '{service_account_email}', + encodeURIComponent(SERVICE_ACCOUNT_EMAIL), + ); + + let rabLookupCalled = false; + // For self-signed JWT, the lookup uses the JWT itself as the token + const rabScope = nock(new URL(lookupUrl).origin) + .get(new URL(lookupUrl).pathname) + .reply(() => { + rabLookupCalled = true; + return [200, EXPECTED_RAB_DATA]; + }); + + const url = 'https://pubsub.googleapis.com'; + const headers = await jwt.getRequestHeaders(url); + + // Verify headers contain the self-signed JWT + const authHeader = headers.get('authorization'); + assert.ok(authHeader?.startsWith('Bearer ')); + + // Wait for background lookup + let attempts = 0; + while (!rabLookupCalled && attempts < 10) { + await new Promise(r => setTimeout(r, 50)); + attempts++; + } + assert.strictEqual(rabLookupCalled, true); + + await new Promise(r => setTimeout(r, 50)); + assert.deepStrictEqual( + jwt.getRegionalAccessBoundary(), + EXPECTED_RAB_DATA, + ); + + rabScope.done(); + }); + + it('should NOT add RAB headers for ID tokens', async () => { + const jwt = new JWT({ + email: SERVICE_ACCOUNT_EMAIL, + key: PEM_CONTENTS, + additionalClaims: { target_audience: 'some-audience' }, + }); + + // Setup a RAB lookup mock that should NOT be hit + const rabScope = setupRegionalAccessBoundaryNock(SERVICE_ACCOUNT_EMAIL); + + const scope = createGTokenMock({ id_token: 'id-token-abc' }); + const headers = await jwt.getRequestHeaders( + 'https://pubsub.googleapis.com', + ); + + assert.strictEqual(headers.get('authorization'), 'Bearer id-token-abc'); + // Should NOT have the RAB header because it's an ID token + assert.strictEqual(headers.get('x-allowed-locations'), null); + + // Ensure RAB lookup was NOT called + assert.strictEqual(rabScope.isDone(), false); + + scope.done(); + }); + + it('should fail getRegionalAccessBoundaryUrl if no email is passed', async () => { + const jwt = new JWT({ + keyFile: PEM_PATH, + scopes: ['http://bar', 'http://foo'], + subject: 'bar@subjectaccount.com', + }); + // Ensure email is explicitly undefined + jwt.email = undefined; + + // Note: error happens in background during getRequestHeaders, + // but we can manually call getRegionalAccessBoundaryUrl to verify it throws. + await assert.rejects( + jwt.getRegionalAccessBoundaryUrl(), + /RegionalAccessBoundary: An email address is required for regional access boundary lookups but was not provided in the JwtClient options./, + ); + }); + }); }); diff --git a/core/packages/google-auth-library-nodejs/tsconfig.json b/core/packages/google-auth-library-nodejs/tsconfig.json index 572f3da71667..b9f7f940bae4 100644 --- a/core/packages/google-auth-library-nodejs/tsconfig.json +++ b/core/packages/google-auth-library-nodejs/tsconfig.json @@ -1,7 +1,10 @@ { "extends": "./node_modules/gts/tsconfig-google.json", "compilerOptions": { - "lib": ["DOM"], + "lib": [ + "es2023", + "DOM" + ], "composite": true, "rootDir": ".", "outDir": "build", From 501505ef0e4cdf544cdebaa37e361bcf94d2448b Mon Sep 17 00:00:00 2001 From: werman Date: Mon, 11 May 2026 12:10:22 -0700 Subject: [PATCH 3/8] feat: Update Regional Access Boundaries (#8099) * RAB endpoints changed from staging to prod; Removed RAB env variable gate; updated tests. * removed sinon.createSandbox from nested beforeEach blocks in test.compute.ts, test.jwt.ts, and test.impersonated.ts. --- .../src/auth/authclient.ts | 3 --- .../src/auth/idtokenclient.ts | 2 +- .../src/auth/regionalaccessboundary.ts | 27 ++++--------------- .../google-auth-library-nodejs/src/util.ts | 2 +- .../test/test.authclient.ts | 10 +------ .../test/test.baseexternalclient.ts | 15 +++++++++-- .../test/test.compute.ts | 16 +++++------ ...est.externalaccountauthorizeduserclient.ts | 2 -- .../test/test.impersonated.ts | 15 +++++++---- .../test/test.jwt.ts | 19 +++++++------ 10 files changed, 48 insertions(+), 63 deletions(-) diff --git a/core/packages/google-auth-library-nodejs/src/auth/authclient.ts b/core/packages/google-auth-library-nodejs/src/auth/authclient.ts index ea9ff1abdd31..216e3390fdc4 100644 --- a/core/packages/google-auth-library-nodejs/src/auth/authclient.ts +++ b/core/packages/google-auth-library-nodejs/src/auth/authclient.ts @@ -21,7 +21,6 @@ import {log as makeLog} from 'google-logging-utils'; import {PRODUCT_NAME, USER_AGENT} from '../shared.cjs'; import { - isRegionalAccessBoundaryEnabled, RegionalAccessBoundaryData, RegionalAccessBoundaryManager, } from './regionalaccessboundary'; @@ -237,7 +236,6 @@ export abstract class AuthClient eagerRefreshThresholdMillis = DEFAULT_EAGER_REFRESH_THRESHOLD_MILLIS; forceRefreshOnFailure = false; universeDomain = DEFAULT_UNIVERSE; - regionalAccessBoundaryEnabled: boolean; protected regionalAccessBoundaryManager: RegionalAccessBoundaryManager; /** @@ -261,7 +259,6 @@ export abstract class AuthClient this.quotaProjectId = options.get('quota_project_id'); this.credentials = options.get('credentials') ?? {}; this.universeDomain = options.get('universe_domain') ?? DEFAULT_UNIVERSE; - this.regionalAccessBoundaryEnabled = isRegionalAccessBoundaryEnabled(); // Shared client options this.transporter = opts.transporter ?? new Gaxios(opts.transporterOptions); diff --git a/core/packages/google-auth-library-nodejs/src/auth/idtokenclient.ts b/core/packages/google-auth-library-nodejs/src/auth/idtokenclient.ts index 638b6db8a4ec..58ed71ae210a 100644 --- a/core/packages/google-auth-library-nodejs/src/auth/idtokenclient.ts +++ b/core/packages/google-auth-library-nodejs/src/auth/idtokenclient.ts @@ -85,4 +85,4 @@ export class IdTokenClient extends OAuth2Client { return payload.exp * 1000; } } -} \ No newline at end of file +} diff --git a/core/packages/google-auth-library-nodejs/src/auth/regionalaccessboundary.ts b/core/packages/google-auth-library-nodejs/src/auth/regionalaccessboundary.ts index 8a8b591972c9..b2b5c598e095 100644 --- a/core/packages/google-auth-library-nodejs/src/auth/regionalaccessboundary.ts +++ b/core/packages/google-auth-library-nodejs/src/auth/regionalaccessboundary.ts @@ -18,13 +18,13 @@ import {log as makeLog} from 'google-logging-utils'; const log = makeLog('auth'); export const SERVICE_ACCOUNT_LOOKUP_ENDPOINT = - 'https://staging-iamcredentials.sandbox.googleapis.com/v1/projects/-/serviceAccounts/{service_account_email}/allowedLocations'; + 'https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/{service_account_email}/allowedLocations'; export const WORKLOAD_LOOKUP_ENDPOINT = - 'https://staging-iamcredentials.sandbox.googleapis.com/v1/projects/{project_id}/locations/global/workloadIdentityPools/{pool_id}/allowedLocations'; + 'https://iamcredentials.googleapis.com/v1/projects/{project_id}/locations/global/workloadIdentityPools/{pool_id}/allowedLocations'; export const WORKFORCE_LOOKUP_ENDPOINT = - 'https://staging-iamcredentials.sandbox.googleapis.com/v1/locations/global/workforcePools/{pool_id}/allowedLocations'; + 'https://iamcredentials.googleapis.com/v1/locations/global/workforcePools/{pool_id}/allowedLocations'; /** * RAB is considered valid for 6 hours. @@ -63,19 +63,6 @@ export interface RegionalAccessBoundaryData { encodedLocations: string; } -export function isRegionalAccessBoundaryEnabled() { - const rabEnabled = - process.env['GOOGLE_AUTH_TRUST_BOUNDARY_ENABLE_EXPERIMENT']; - if (rabEnabled === undefined || rabEnabled === null) { - return false; - } - const lowercasedRabEnabled = rabEnabled.toLowerCase(); - if (lowercasedRabEnabled === 'true' || rabEnabled === '1') { - return true; - } - return false; -} - export interface RegionalAccessBoundaryManagerOptions { transporter: Gaxios; getLookupUrl: () => Promise; @@ -94,10 +81,6 @@ export class RegionalAccessBoundaryManager { this.options = options; } - get enabled(): boolean { - return isRegionalAccessBoundaryEnabled(); - } - /** * @internal */ @@ -122,7 +105,7 @@ export class RegionalAccessBoundaryManager { url: string | URL | undefined, headers: Headers, ): string | null { - if (!this.enabled || !this.options.isUniverseDomainDefault()) { + if (!this.options.isUniverseDomainDefault()) { return null; } @@ -275,4 +258,4 @@ export class RegionalAccessBoundaryManager { return regionalAccessBoundaryData; } -} \ No newline at end of file +} diff --git a/core/packages/google-auth-library-nodejs/src/util.ts b/core/packages/google-auth-library-nodejs/src/util.ts index d965887f5d52..0d9081c4c2dc 100644 --- a/core/packages/google-auth-library-nodejs/src/util.ts +++ b/core/packages/google-auth-library-nodejs/src/util.ts @@ -336,4 +336,4 @@ export function getWorkloadPoolIdFromAudience(audience: string): string | null { /\/workloadIdentityPools\/(?[^/]+)\/providers\//, )?.groups?.workloadPool ?? null ); -} \ No newline at end of file +} diff --git a/core/packages/google-auth-library-nodejs/test/test.authclient.ts b/core/packages/google-auth-library-nodejs/test/test.authclient.ts index 7c4748f5e790..892fafe3b0ef 100644 --- a/core/packages/google-auth-library-nodejs/test/test.authclient.ts +++ b/core/packages/google-auth-library-nodejs/test/test.authclient.ts @@ -417,14 +417,6 @@ describe('AuthClient', () => { ); } - beforeEach(() => { - process.env['GOOGLE_AUTH_TRUST_BOUNDARY_ENABLE_EXPERIMENT'] = 'true'; - }); - - afterEach(() => { - delete process.env['GOOGLE_AUTH_TRUST_BOUNDARY_ENABLE_EXPERIMENT']; - }); - it('should trigger asynchronous background refresh and not block', async () => { const compute = new Compute({ serviceAccountEmail: SERVICE_ACCOUNT_EMAIL, @@ -613,4 +605,4 @@ describe('AuthClient', () => { }); }); }); -}); \ No newline at end of file +}); diff --git a/core/packages/google-auth-library-nodejs/test/test.baseexternalclient.ts b/core/packages/google-auth-library-nodejs/test/test.baseexternalclient.ts index 573a4df0083e..112da7c6016d 100644 --- a/core/packages/google-auth-library-nodejs/test/test.baseexternalclient.ts +++ b/core/packages/google-auth-library-nodejs/test/test.baseexternalclient.ts @@ -162,11 +162,20 @@ describe('BaseExternalAccountClient', () => { '//iam.googleapis.com/projects_suffix/123456', ]; + let sandbox: sinon.SinonSandbox; + beforeEach(() => { + sandbox = sinon.createSandbox(); + sandbox + .stub(BaseExternalAccountClient.prototype, 'getRegionalAccessBoundaryUrl') + .resolves(undefined); + }); + afterEach(() => { nock.cleanAll(); if (clock) { clock.restore(); } + sandbox.restore(); }); describe('Constructor', () => { @@ -2723,11 +2732,13 @@ describe('BaseExternalAccountClient', () => { }; beforeEach(() => { - process.env['GOOGLE_AUTH_TRUST_BOUNDARY_ENABLE_EXPERIMENT'] = 'true'; + ( + BaseExternalAccountClient.prototype + .getRegionalAccessBoundaryUrl as sinon.SinonStub + ).restore(); }); afterEach(() => { - delete process.env['GOOGLE_AUTH_TRUST_BOUNDARY_ENABLE_EXPERIMENT']; nock.cleanAll(); }); diff --git a/core/packages/google-auth-library-nodejs/test/test.compute.ts b/core/packages/google-auth-library-nodejs/test/test.compute.ts index 301a75691c1b..52c6ae85cf4d 100644 --- a/core/packages/google-auth-library-nodejs/test/test.compute.ts +++ b/core/packages/google-auth-library-nodejs/test/test.compute.ts @@ -17,7 +17,7 @@ import {describe, it, beforeEach, afterEach} from 'mocha'; import {BASE_PATH, HEADERS, HOST_ADDRESS} from 'gcp-metadata'; import * as nock from 'nock'; import * as sinon from 'sinon'; -import { Compute, gcpMetadata } from '../src'; +import {Compute, gcpMetadata} from '../src'; import { SERVICE_ACCOUNT_LOOKUP_ENDPOINT, RegionalAccessBoundaryData, @@ -48,6 +48,9 @@ describe('compute', () => { let compute: Compute; beforeEach(() => { compute = new Compute(); + sandbox + .stub(Compute.prototype, 'getRegionalAccessBoundaryUrl') + .resolves(undefined); }); afterEach(() => { @@ -266,8 +269,6 @@ describe('compute', () => { assert.fail('failed to throw'); }); describe('regional access boundaries', () => { - let sandbox: sinon.SinonSandbox; - const MOCK_ACCESS_TOKEN = 'abc123'; const MOCK_AUTH_HEADER = `Bearer ${MOCK_ACCESS_TOKEN}`; const EXPECTED_RAB_DATA: RegionalAccessBoundaryData = { @@ -284,7 +285,7 @@ describe('compute', () => { .get(tokenPath) .reply( 200, - { access_token: MOCK_ACCESS_TOKEN, expires_in: 10000 }, + {access_token: MOCK_ACCESS_TOKEN, expires_in: 10000}, HEADERS, ); } @@ -304,13 +305,12 @@ describe('compute', () => { } beforeEach(() => { - sandbox = sinon.createSandbox(); - process.env['GOOGLE_AUTH_TRUST_BOUNDARY_ENABLE_EXPERIMENT'] = 'true'; + ( + Compute.prototype.getRegionalAccessBoundaryUrl as sinon.SinonStub + ).restore(); }); afterEach(() => { - delete process.env['GOOGLE_AUTH_TRUST_BOUNDARY_ENABLE_EXPERIMENT']; - sandbox.restore(); nock.cleanAll(); }); diff --git a/core/packages/google-auth-library-nodejs/test/test.externalaccountauthorizeduserclient.ts b/core/packages/google-auth-library-nodejs/test/test.externalaccountauthorizeduserclient.ts index cefe14e0fce6..ee46da87740f 100644 --- a/core/packages/google-auth-library-nodejs/test/test.externalaccountauthorizeduserclient.ts +++ b/core/packages/google-auth-library-nodejs/test/test.externalaccountauthorizeduserclient.ts @@ -909,11 +909,9 @@ describe('ExternalAccountAuthorizedUserClient', () => { beforeEach(() => { clock.restore(); - process.env['GOOGLE_AUTH_TRUST_BOUNDARY_ENABLE_EXPERIMENT'] = 'true'; }); afterEach(() => { - delete process.env['GOOGLE_AUTH_TRUST_BOUNDARY_ENABLE_EXPERIMENT']; nock.cleanAll(); }); diff --git a/core/packages/google-auth-library-nodejs/test/test.impersonated.ts b/core/packages/google-auth-library-nodejs/test/test.impersonated.ts index b8ea708414d8..e97d77c74a32 100644 --- a/core/packages/google-auth-library-nodejs/test/test.impersonated.ts +++ b/core/packages/google-auth-library-nodejs/test/test.impersonated.ts @@ -74,8 +74,15 @@ interface ImpersonatedCredentialRequest { } describe('impersonated', () => { + beforeEach(() => { + sinon + .stub(Impersonated.prototype, 'getRegionalAccessBoundaryUrl') + .resolves(undefined); + }); + afterEach(() => { nock.cleanAll(); + sinon.restore(); }); it('should request impersonated credentials on first request', async () => { @@ -596,7 +603,6 @@ describe('impersonated', () => { }); describe('regional access boundaries', () => { - let sandbox: sinon.SinonSandbox; const TARGET_PRINCIPAL_EMAIL = 'target@project.iam.gserviceaccount.com'; const MOCK_ACCESS_TOKEN = 'abc123'; const MOCK_AUTH_HEADER = `Bearer ${MOCK_ACCESS_TOKEN}`; @@ -621,13 +627,12 @@ describe('impersonated', () => { } beforeEach(() => { - sandbox = sinon.createSandbox(); - process.env['GOOGLE_AUTH_TRUST_BOUNDARY_ENABLE_EXPERIMENT'] = 'true'; + ( + Impersonated.prototype.getRegionalAccessBoundaryUrl as sinon.SinonStub + ).restore(); }); afterEach(() => { - delete process.env['GOOGLE_AUTH_TRUST_BOUNDARY_ENABLE_EXPERIMENT']; - sandbox.restore(); nock.cleanAll(); }); diff --git a/core/packages/google-auth-library-nodejs/test/test.jwt.ts b/core/packages/google-auth-library-nodejs/test/test.jwt.ts index 338de68c44f5..d9c4f93cc3b9 100644 --- a/core/packages/google-auth-library-nodejs/test/test.jwt.ts +++ b/core/packages/google-auth-library-nodejs/test/test.jwt.ts @@ -72,6 +72,9 @@ describe('jwt', () => { json = createJSON(); jwt = new JWT(); sandbox = sinon.createSandbox(); + sandbox + .stub(JWT.prototype, 'getRegionalAccessBoundaryUrl') + .resolves(undefined); }); afterEach(() => { @@ -1250,7 +1253,6 @@ describe('jwt', () => { }); describe('regional access boundaries', () => { - let sandbox: sinon.SinonSandbox; const SERVICE_ACCOUNT_EMAIL = 'service-account@example.com'; const MOCK_ACCESS_TOKEN = 'abc123'; const MOCK_AUTH_HEADER = `Bearer ${MOCK_ACCESS_TOKEN}`; @@ -1276,13 +1278,10 @@ describe('jwt', () => { } beforeEach(() => { - sandbox = sinon.createSandbox(); - process.env['GOOGLE_AUTH_TRUST_BOUNDARY_ENABLE_EXPERIMENT'] = 'true'; + (JWT.prototype.getRegionalAccessBoundaryUrl as sinon.SinonStub).restore(); }); afterEach(() => { - delete process.env['GOOGLE_AUTH_TRUST_BOUNDARY_ENABLE_EXPERIMENT']; - sandbox.restore(); nock.cleanAll(); }); @@ -1293,9 +1292,9 @@ describe('jwt', () => { scopes: ['http://bar', 'http://foo'], subject: 'bar@subjectaccount.com', }); - jwt.credentials = { refresh_token: 'jwt-placeholder' }; + jwt.credentials = {refresh_token: 'jwt-placeholder'}; - const tokenScope = createGTokenMock({ access_token: MOCK_ACCESS_TOKEN }); + const tokenScope = createGTokenMock({access_token: MOCK_ACCESS_TOKEN}); let rabLookupCalled = false; const rabScope = setupRegionalAccessBoundaryNock(SERVICE_ACCOUNT_EMAIL); @@ -1335,7 +1334,7 @@ describe('jwt', () => { email: SERVICE_ACCOUNT_EMAIL, key: keys.private, }); - jwt.credentials = { refresh_token: 'jwt-placeholder' }; + jwt.credentials = {refresh_token: 'jwt-placeholder'}; const lookupUrl = SERVICE_ACCOUNT_LOOKUP_ENDPOINT.replace( '{service_account_email}', @@ -1379,13 +1378,13 @@ describe('jwt', () => { const jwt = new JWT({ email: SERVICE_ACCOUNT_EMAIL, key: PEM_CONTENTS, - additionalClaims: { target_audience: 'some-audience' }, + additionalClaims: {target_audience: 'some-audience'}, }); // Setup a RAB lookup mock that should NOT be hit const rabScope = setupRegionalAccessBoundaryNock(SERVICE_ACCOUNT_EMAIL); - const scope = createGTokenMock({ id_token: 'id-token-abc' }); + const scope = createGTokenMock({id_token: 'id-token-abc'}); const headers = await jwt.getRequestHeaders( 'https://pubsub.googleapis.com', ); From 2df956eb65f5b24bc79e1e254a459ed3503a8055 Mon Sep 17 00:00:00 2001 From: Pranav Iyer Date: Fri, 5 Jun 2026 19:06:15 -0700 Subject: [PATCH 4/8] feat(auth): Added logic to dynamically switch to mTLS RAB lookup endpoint. --- .../auth/certificatesubjecttokensupplier.ts | 159 +----------- .../src/auth/mtlsutils.ts | 229 ++++++++++++++++++ .../src/auth/regionalaccessboundary.ts | 19 +- .../test/test.authclient.ts | 5 + .../test/test.baseexternalclient.ts | 5 + .../test/test.compute.ts | 64 +++++ ...est.externalaccountauthorizeduserclient.ts | 6 + .../test/test.identitypoolclient.ts | 2 +- .../test/test.impersonated.ts | 5 + .../test/test.jwt.ts | 5 + .../test/test.mtlsutils.ts | 101 ++++++++ 11 files changed, 448 insertions(+), 152 deletions(-) create mode 100644 core/packages/google-auth-library-nodejs/src/auth/mtlsutils.ts create mode 100644 core/packages/google-auth-library-nodejs/test/test.mtlsutils.ts diff --git a/core/packages/google-auth-library-nodejs/src/auth/certificatesubjecttokensupplier.ts b/core/packages/google-auth-library-nodejs/src/auth/certificatesubjecttokensupplier.ts index d09382c3983c..23cc9ccfc66d 100644 --- a/core/packages/google-auth-library-nodejs/src/auth/certificatesubjecttokensupplier.ts +++ b/core/packages/google-auth-library-nodejs/src/auth/certificatesubjecttokensupplier.ts @@ -13,33 +13,15 @@ // limitations under the License. import {SubjectTokenSupplier} from './identitypoolclient'; -import {getWellKnownCertificateConfigFileLocation, isValidFile} from '../util'; +import {isValidFile} from '../util'; import * as fs from 'fs'; -import {createPrivateKey, X509Certificate} from 'crypto'; +import {X509Certificate} from 'crypto'; import * as https from 'https'; - -export const CERTIFICATE_CONFIGURATION_ENV_VARIABLE = - 'GOOGLE_API_CERTIFICATE_CONFIG'; - -/** - * Thrown when the certificate source cannot be located or accessed. - */ -export class CertificateSourceUnavailableError extends Error { - constructor(message: string) { - super(message); - this.name = 'CertificateSourceUnavailableError'; - } -} - -/** - * Thrown for invalid configuration that is not related to file availability. - */ -export class InvalidConfigurationError extends Error { - constructor(message: string) { - super(message); - this.name = 'InvalidConfigurationError'; - } -} +import { + CertificateSourceUnavailableError, + InvalidConfigurationError, + getClientCertAndKey, +} from './mtlsutils'; /** * Defines options for creating a {@link CertificateSubjectTokenSupplier}. @@ -130,135 +112,12 @@ export class CertificateSubjectTokenSupplier implements SubjectTokenSupplier { public async getSubjectToken(): Promise { // The "subject token" in this context is the processed certificate chain. - this.certificateConfigPath = await this.#resolveCertificateConfigFilePath(); - - const {certPath, keyPath} = await this.#getCertAndKeyPaths(); - - ({cert: this.cert, key: this.key} = await this.#getKeyAndCert( - certPath, - keyPath, - )); + // getClientCertAndKey handles path resolution, file reading, and validation + ({cert: this.cert, key: this.key} = await getClientCertAndKey(this.certificateConfigPath)); return await this.#processChainFromPaths(this.cert); } - /** - * Resolves the absolute path to the certificate configuration file - * by checking the "certificate_config_location" provided in the ADC file, - * or the "GOOGLE_API_CERTIFICATE_CONFIG" environment variable - * or in the default gcloud path. - * @param overridePath An optional path to check first. - * @returns The resolved file path. - */ - async #resolveCertificateConfigFilePath(): Promise { - // 1. Check for the override path from constructor options. - const overridePath = this.certificateConfigPath; - if (overridePath) { - if (await isValidFile(overridePath)) { - return overridePath; - } - throw new CertificateSourceUnavailableError( - `Provided certificate config path is invalid: ${overridePath}`, - ); - } - - // 2. Check the standard environment variable. - const envPath = process.env[CERTIFICATE_CONFIGURATION_ENV_VARIABLE]; - if (envPath) { - if (await isValidFile(envPath)) { - return envPath; - } - throw new CertificateSourceUnavailableError( - `Path from environment variable "${CERTIFICATE_CONFIGURATION_ENV_VARIABLE}" is invalid: ${envPath}`, - ); - } - - // 3. Check the well-known gcloud config location. - const wellKnownPath = getWellKnownCertificateConfigFileLocation(); - if (await isValidFile(wellKnownPath)) { - return wellKnownPath; - } - - // 4. If none are found, throw an error. - throw new CertificateSourceUnavailableError( - 'Could not find certificate configuration file. Searched override path, ' + - `the "${CERTIFICATE_CONFIGURATION_ENV_VARIABLE}" env var, and the gcloud path (${wellKnownPath}).`, - ); - } - - /** - * Reads and parses the certificate config JSON file to extract the certificate and key paths. - * @returns An object containing the certificate and key paths. - */ - async #getCertAndKeyPaths(): Promise<{ - certPath: string; - keyPath: string; - }> { - const configPath = this.certificateConfigPath; - let fileContents: string; - try { - fileContents = await fs.promises.readFile(configPath, 'utf8'); - } catch (err) { - throw new CertificateSourceUnavailableError( - `Failed to read certificate config file at: ${configPath}`, - ); - } - - try { - const config = JSON.parse(fileContents) as CertificateConfigFileJson; - const certPath = config?.cert_configs?.workload?.cert_path; - const keyPath = config?.cert_configs?.workload?.key_path; - - if (!certPath || !keyPath) { - throw new InvalidConfigurationError( - `Certificate config file (${configPath}) is missing required "cert_path" or "key_path" in the workload config.`, - ); - } - return {certPath, keyPath}; - } catch (e) { - if (e instanceof InvalidConfigurationError) throw e; - throw new InvalidConfigurationError( - `Failed to parse certificate config from ${configPath}: ${ - (e as Error).message - }`, - ); - } - } - - /** - * Reads and parses the cert and key files get their content and check valid format. - * @returns An object containing the cert content and key content in buffer format. - */ - async #getKeyAndCert( - certPath: string, - keyPath: string, - ): Promise<{ - cert: Buffer; - key: Buffer; - }> { - let cert, key; - try { - cert = await fs.promises.readFile(certPath); - new X509Certificate(cert); - } catch (err) { - const message = err instanceof Error ? err.message : String(err); - throw new CertificateSourceUnavailableError( - `Failed to read certificate file at ${certPath}: ${message}`, - ); - } - try { - key = await fs.promises.readFile(keyPath); - createPrivateKey(key); - } catch (err) { - const message = err instanceof Error ? err.message : String(err); - throw new CertificateSourceUnavailableError( - `Failed to read private key file at ${keyPath}: ${message}`, - ); - } - - return {cert, key}; - } - /** * Reads the leaf certificate and trust chain, combines them, * and returns a JSON array of base64-encoded certificates. diff --git a/core/packages/google-auth-library-nodejs/src/auth/mtlsutils.ts b/core/packages/google-auth-library-nodejs/src/auth/mtlsutils.ts new file mode 100644 index 000000000000..5b0fa174d4ae --- /dev/null +++ b/core/packages/google-auth-library-nodejs/src/auth/mtlsutils.ts @@ -0,0 +1,229 @@ +// 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. + +import * as fs from 'fs'; +import {createPrivateKey, X509Certificate} from 'crypto'; +import {getWellKnownCertificateConfigFileLocation, isValidFile} from '../util'; + +export const CERTIFICATE_CONFIGURATION_ENV_VARIABLE = + 'GOOGLE_API_CERTIFICATE_CONFIG'; + +/** + * Thrown when the certificate source cannot be located or accessed. + */ +export class CertificateSourceUnavailableError extends Error { + constructor(message: string) { + super(message); + this.name = 'CertificateSourceUnavailableError'; + } +} + +/** + * Thrown for invalid configuration that is not related to file availability. + * Re-exported for use in CertificateSubjectTokenSupplier validation. + */ +export class InvalidConfigurationError extends Error { + constructor(message: string) { + super(message); + this.name = 'InvalidConfigurationError'; + } +} + +/** + * Endpoint usage policy for mutual TLS (mTLS). + */ +export enum MtlsEndpointUsagePolicy { + ALWAYS = 'always', + NEVER = 'never', + AUTO = 'auto', +} + +/** + * Resolves the mTLS endpoint usage policy based on the `GOOGLE_API_USE_MTLS_ENDPOINT` + * environment variable. + * + * @returns The resolved MtlsEndpointUsagePolicy. + */ +export function getMtlsEndpointUsagePolicy(): MtlsEndpointUsagePolicy { + const policy = process.env.GOOGLE_API_USE_MTLS_ENDPOINT; + if (policy === 'never') { + return MtlsEndpointUsagePolicy.NEVER; + } else if (policy === 'always') { + return MtlsEndpointUsagePolicy.ALWAYS; + } + return MtlsEndpointUsagePolicy.AUTO; +} + +/** + * Centralized helper method to determine if mutual TLS (mTLS) can be enabled. + * + * Checks for the environment policy constraints and parses the certificate configuration file. + * + * @param certConfigPathOverride Optional path to override the certificate configuration file. + * @returns A promise that resolves to `true` if mTLS can be enabled, `false` otherwise. + * @throws {Error} If a configuration file is resolved but contains malformed contents or missing files. + */ +export async function canMtlsBeEnabled(certConfigPathOverride?: string): Promise { + if (process.env.GOOGLE_API_USE_CLIENT_CERTIFICATE === 'false') { + return false; + } + if (getMtlsEndpointUsagePolicy() === MtlsEndpointUsagePolicy.NEVER) { + return false; + } + + // Check for certificate configuration file + let configPath: string | null = null; + try { + configPath = await resolveCertificateConfigFilePath(certConfigPathOverride); + } catch (e) { + // Config file is simply not present. + return false; + } + + // Config file exists / was specified. We must validate it. + // Any failure here must propagate as a hard error. + const {certPath, keyPath} = await getCertAndKeyFilePathsFromConfig(configPath); + if (!(await isValidFile(certPath)) || !(await isValidFile(keyPath))) { + throw new Error( + `Certificate configuration exists but referenced files are missing: cert_path=${certPath}, key_path=${keyPath}` + ); + } + return true; +} + +/** + * Resolves the path to the certificate configuration JSON file. + * Checks the override path, standard environment variable, and well-known location. + * + * @param certConfigPathOverride Optional override path. + * @returns The resolved absolute path to the configuration file. + * @throws {CertificateSourceUnavailableError} If the configuration file cannot be found. + */ +export async function resolveCertificateConfigFilePath( + certConfigPathOverride?: string +): Promise { + // Step 1: Check if an override path was passed directly (highest precedence) + if (certConfigPathOverride) { + if (await isValidFile(certConfigPathOverride)) { + return certConfigPathOverride; + } + throw new CertificateSourceUnavailableError( + `Provided certificate config path is invalid: ${certConfigPathOverride}`, + ); + } + + // Step 2: Check if the configuration path environment variable is defined + const envPath = process.env[CERTIFICATE_CONFIGURATION_ENV_VARIABLE]; + if (envPath) { + if (await isValidFile(envPath)) { + return envPath; + } + throw new CertificateSourceUnavailableError( + `Path from environment variable "${CERTIFICATE_CONFIGURATION_ENV_VARIABLE}" is invalid: ${envPath}`, + ); + } + + // Step 3: Check in the default well-known gcloud location (lowest precedence) + const wellKnownPath = getWellKnownCertificateConfigFileLocation(); + if (await isValidFile(wellKnownPath)) { + return wellKnownPath; + } + + // Step 4: Throw error if no configuration file could be resolved + throw new CertificateSourceUnavailableError( + 'Could not find certificate configuration file. Searched override path, ' + + `the "${CERTIFICATE_CONFIGURATION_ENV_VARIABLE}" env var, and the gcloud path (${wellKnownPath}).`, + ); +} + +/** + * Reads and parses the certificate configuration JSON file to extract the + * certificate and private key file paths from the workload configuration block. + * + * @param configPath Absolute path to the certificate config file. + * @returns The file paths to the certificate and key. + * @throws {CertificateSourceUnavailableError} If the configuration file is unreadable. + * @throws {InvalidConfigurationError} If the JSON contents are invalid or missing required paths. + */ +export async function getCertAndKeyFilePathsFromConfig( + configPath: string +): Promise<{certPath: string; keyPath: string}> { + let fileContents: string; + try { + fileContents = await fs.promises.readFile(configPath, 'utf8'); + } catch (err) { + throw new CertificateSourceUnavailableError( + `Failed to read certificate config file at: ${configPath}`, + ); + } + + try { + const config = JSON.parse(fileContents); + const certPath = config?.cert_configs?.workload?.cert_path; + const keyPath = config?.cert_configs?.workload?.key_path; + + if (!certPath || !keyPath) { + throw new InvalidConfigurationError( + `Certificate config file (${configPath}) is missing required "cert_path" or "key_path" in the workload config.`, + ); + } + return {certPath, keyPath}; + } catch (e) { + if (e instanceof InvalidConfigurationError || e instanceof CertificateSourceUnavailableError) { + throw e; + } + throw new InvalidConfigurationError( + `Failed to parse certificate config from ${configPath}: ${ + (e as Error).message + }`, + ); + } +} + +/** + * Loads the actual certificate and private key bytes from disk. + * Prioritizes the configuration file. Validates the loaded files are in the correct format. + * + * @param certConfigPathOverride Optional override path. + * @returns The loaded cert and private key buffers. + * @throws {Error} If no credentials could be resolved or if validation fails. + */ +export async function getClientCertAndKey( + certConfigPathOverride?: string +): Promise<{cert: Buffer; key: Buffer}> { + const configPath = await resolveCertificateConfigFilePath(certConfigPathOverride); + const {certPath, keyPath} = await getCertAndKeyFilePathsFromConfig(configPath); + + let cert, key; + try { + cert = await fs.promises.readFile(certPath); + new X509Certificate(cert); + } catch (err) { + const message = err instanceof Error ? err.message : String(err); + throw new CertificateSourceUnavailableError( + `Failed to read certificate file at ${certPath}: ${message}`, + ); + } + try { + key = await fs.promises.readFile(keyPath); + createPrivateKey(key); + } catch (err) { + const message = err instanceof Error ? err.message : String(err); + throw new CertificateSourceUnavailableError( + `Failed to read private key file at ${keyPath}: ${message}`, + ); + } + + return {cert, key}; +} diff --git a/core/packages/google-auth-library-nodejs/src/auth/regionalaccessboundary.ts b/core/packages/google-auth-library-nodejs/src/auth/regionalaccessboundary.ts index b2b5c598e095..56ef39b6da88 100644 --- a/core/packages/google-auth-library-nodejs/src/auth/regionalaccessboundary.ts +++ b/core/packages/google-auth-library-nodejs/src/auth/regionalaccessboundary.ts @@ -14,6 +14,8 @@ import {Gaxios, GaxiosOptions} from 'gaxios'; import {log as makeLog} from 'google-logging-utils'; +import * as https from 'https'; +import {canMtlsBeEnabled, getClientCertAndKey} from './mtlsutils'; const log = makeLog('auth'); @@ -217,7 +219,7 @@ export class RegionalAccessBoundaryManager { private async fetchRegionalAccessBoundary( accessToken?: string, ): Promise { - const regionalAccessBoundaryUrl = await this.options.getLookupUrl(); + let regionalAccessBoundaryUrl = await this.options.getLookupUrl(); if (!regionalAccessBoundaryUrl) { return null; } @@ -247,6 +249,21 @@ export class RegionalAccessBoundaryManager { url: regionalAccessBoundaryUrl, }; + // If mTLS can be enabled, use mTLS agent and switch to the mTLS endpoint + try { + if (await canMtlsBeEnabled()) { + const {cert, key} = await getClientCertAndKey(); + opts.agent = new https.Agent({cert, key}); + regionalAccessBoundaryUrl = regionalAccessBoundaryUrl.replace( + 'iamcredentials.googleapis.com', + 'iamcredentials.mtls.googleapis.com' + ); + opts.url = regionalAccessBoundaryUrl; + } + } catch (e) { + log.error('RegionalAccessBoundary: Failed to initialize mTLS: ', e); + } + const {data: regionalAccessBoundaryData} = await this.options.transporter.request(opts); diff --git a/core/packages/google-auth-library-nodejs/test/test.authclient.ts b/core/packages/google-auth-library-nodejs/test/test.authclient.ts index 892fafe3b0ef..a288fee4cde0 100644 --- a/core/packages/google-auth-library-nodejs/test/test.authclient.ts +++ b/core/packages/google-auth-library-nodejs/test/test.authclient.ts @@ -63,6 +63,11 @@ describe('AuthClient', () => { beforeEach(() => { sandbox = sinon.createSandbox(); + sandbox.stub(process, 'env').value({ + ...process.env, + GOOGLE_API_USE_CLIENT_CERTIFICATE: undefined, + GOOGLE_API_CERTIFICATE_CONFIG: undefined, + }); }); afterEach(() => { diff --git a/core/packages/google-auth-library-nodejs/test/test.baseexternalclient.ts b/core/packages/google-auth-library-nodejs/test/test.baseexternalclient.ts index 112da7c6016d..2f079f57cf57 100644 --- a/core/packages/google-auth-library-nodejs/test/test.baseexternalclient.ts +++ b/core/packages/google-auth-library-nodejs/test/test.baseexternalclient.ts @@ -165,6 +165,11 @@ describe('BaseExternalAccountClient', () => { let sandbox: sinon.SinonSandbox; beforeEach(() => { sandbox = sinon.createSandbox(); + sandbox.stub(process, 'env').value({ + ...process.env, + GOOGLE_API_USE_CLIENT_CERTIFICATE: undefined, + GOOGLE_API_CERTIFICATE_CONFIG: undefined, + }); sandbox .stub(BaseExternalAccountClient.prototype, 'getRegionalAccessBoundaryUrl') .resolves(undefined); diff --git a/core/packages/google-auth-library-nodejs/test/test.compute.ts b/core/packages/google-auth-library-nodejs/test/test.compute.ts index 52c6ae85cf4d..d8b959c084af 100644 --- a/core/packages/google-auth-library-nodejs/test/test.compute.ts +++ b/core/packages/google-auth-library-nodejs/test/test.compute.ts @@ -47,6 +47,11 @@ describe('compute', () => { const sandbox = sinon.createSandbox(); let compute: Compute; beforeEach(() => { + sandbox.stub(process, 'env').value({ + ...process.env, + GOOGLE_API_USE_CLIENT_CERTIFICATE: undefined, + GOOGLE_API_CERTIFICATE_CONFIG: undefined, + }); compute = new Compute(); sandbox .stub(Compute.prototype, 'getRegionalAccessBoundaryUrl') @@ -354,6 +359,65 @@ describe('compute', () => { rabScope.done(); }); + it('should trigger asynchronous RAB refresh using mTLS when enabled', async () => { + const compute = new Compute(); + const fakeEmail = 'fake-default-sa@developer.gserviceaccount.com'; + const metadataStub = sandbox.stub(gcpMetadata, 'instance'); + metadataStub.callThrough(); + metadataStub + .withArgs('service-accounts/default/email') + .resolves(fakeEmail); + + process.env.GOOGLE_API_USE_CLIENT_CERTIFICATE = 'true'; + process.env.GOOGLE_API_CERTIFICATE_CONFIG = + './test/fixtures/external-account-cert/cert_config.json'; + + const tokenScope = setupTokenNock('default'); + + // The lookup url should be replaced with iamcredentials.mtls.googleapis.com + const lookupUrl = SERVICE_ACCOUNT_LOOKUP_ENDPOINT.replace( + '{service_account_email}', + encodeURIComponent(fakeEmail), + ).replace( + 'iamcredentials.googleapis.com', + 'iamcredentials.mtls.googleapis.com' + ); + + const rabScope = nock(new URL(lookupUrl).origin) + .get(new URL(lookupUrl).pathname) + .matchHeader('authorization', MOCK_AUTH_HEADER) + .reply(200, EXPECTED_RAB_DATA); + + let rabLookupCalled = false; + rabScope.on('request', () => { + rabLookupCalled = true; + }); + + const url = 'https://pubsub.googleapis.com'; + const headers = await compute.getRequestHeaders(url); + + assert.strictEqual(headers.get('x-allowed-locations'), null); + + let attempts = 0; + while (!rabLookupCalled && attempts < 10) { + await new Promise(r => setTimeout(r, 100)); + attempts++; + } + assert.strictEqual(rabLookupCalled, true); + + await new Promise(r => setTimeout(r, 50)); + assert.deepStrictEqual( + compute.getRegionalAccessBoundary(), + EXPECTED_RAB_DATA, + ); + + tokenScope.done(); + rabScope.done(); + + delete process.env.GOOGLE_API_USE_CLIENT_CERTIFICATE; + delete process.env.GOOGLE_API_CERTIFICATE_CONFIG; + }); + it('should fail getRegionalAccessBoundaryUrl in background if metadata call fails', async () => { const compute = new Compute(); diff --git a/core/packages/google-auth-library-nodejs/test/test.externalaccountauthorizeduserclient.ts b/core/packages/google-auth-library-nodejs/test/test.externalaccountauthorizeduserclient.ts index ee46da87740f..713941f8d1ef 100644 --- a/core/packages/google-auth-library-nodejs/test/test.externalaccountauthorizeduserclient.ts +++ b/core/packages/google-auth-library-nodejs/test/test.externalaccountauthorizeduserclient.ts @@ -116,6 +116,11 @@ describe('ExternalAccountAuthorizedUserClient', () => { expires_in: 3600, }; beforeEach(() => { + sinon.stub(process, 'env').value({ + ...process.env, + GOOGLE_API_USE_CLIENT_CERTIFICATE: undefined, + GOOGLE_API_CERTIFICATE_CONFIG: undefined, + }); clock = TestUtils.useFakeTimers(sinon, referenceDate); }); @@ -124,6 +129,7 @@ describe('ExternalAccountAuthorizedUserClient', () => { if (clock) { clock.restore(); } + sinon.restore(); }); describe('Constructor', () => { diff --git a/core/packages/google-auth-library-nodejs/test/test.identitypoolclient.ts b/core/packages/google-auth-library-nodejs/test/test.identitypoolclient.ts index d8b2ff3665d8..4653238bc105 100644 --- a/core/packages/google-auth-library-nodejs/test/test.identitypoolclient.ts +++ b/core/packages/google-auth-library-nodejs/test/test.identitypoolclient.ts @@ -39,7 +39,7 @@ import { CERTIFICATE_CONFIGURATION_ENV_VARIABLE, CertificateSourceUnavailableError, InvalidConfigurationError, -} from '../src/auth/certificatesubjecttokensupplier'; +} from '../src/auth/mtlsutils'; import * as sinon from 'sinon'; import * as util from '../src/util'; diff --git a/core/packages/google-auth-library-nodejs/test/test.impersonated.ts b/core/packages/google-auth-library-nodejs/test/test.impersonated.ts index e97d77c74a32..7c7a021a39de 100644 --- a/core/packages/google-auth-library-nodejs/test/test.impersonated.ts +++ b/core/packages/google-auth-library-nodejs/test/test.impersonated.ts @@ -75,6 +75,11 @@ interface ImpersonatedCredentialRequest { describe('impersonated', () => { beforeEach(() => { + sinon.stub(process, 'env').value({ + ...process.env, + GOOGLE_API_USE_CLIENT_CERTIFICATE: undefined, + GOOGLE_API_CERTIFICATE_CONFIG: undefined, + }); sinon .stub(Impersonated.prototype, 'getRegionalAccessBoundaryUrl') .resolves(undefined); diff --git a/core/packages/google-auth-library-nodejs/test/test.jwt.ts b/core/packages/google-auth-library-nodejs/test/test.jwt.ts index d9c4f93cc3b9..a4b1e3147da9 100644 --- a/core/packages/google-auth-library-nodejs/test/test.jwt.ts +++ b/core/packages/google-auth-library-nodejs/test/test.jwt.ts @@ -72,6 +72,11 @@ describe('jwt', () => { json = createJSON(); jwt = new JWT(); sandbox = sinon.createSandbox(); + sandbox.stub(process, 'env').value({ + ...process.env, + GOOGLE_API_USE_CLIENT_CERTIFICATE: undefined, + GOOGLE_API_CERTIFICATE_CONFIG: undefined, + }); sandbox .stub(JWT.prototype, 'getRegionalAccessBoundaryUrl') .resolves(undefined); diff --git a/core/packages/google-auth-library-nodejs/test/test.mtlsutils.ts b/core/packages/google-auth-library-nodejs/test/test.mtlsutils.ts new file mode 100644 index 000000000000..f07a87573ea6 --- /dev/null +++ b/core/packages/google-auth-library-nodejs/test/test.mtlsutils.ts @@ -0,0 +1,101 @@ +// 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. + +import * as assert from 'assert'; +import {describe, it, beforeEach, afterEach} from 'mocha'; +import * as sinon from 'sinon'; +import * as fs from 'fs'; +import * as path from 'path'; +import * as os from 'os'; +import { + canMtlsBeEnabled, + getClientCertAndKey, +} from '../src/auth/mtlsutils'; +import * as util from '../src/util'; + +describe('mtlsutils', () => { + let sandbox: sinon.SinonSandbox; + let tempDir: string; + + beforeEach(async () => { + sandbox = sinon.createSandbox(); + sandbox.stub(process, 'env').value({ ...process.env }); + tempDir = await fs.promises.mkdtemp(path.join(os.tmpdir(), 'mtls-tests-')); + }); + + afterEach(async () => { + sandbox.restore(); + await fs.promises.rm(tempDir, {recursive: true, force: true}); + }); + + describe('canMtlsBeEnabled', () => { + it('returns false if GOOGLE_API_USE_CLIENT_CERTIFICATE is false', async () => { + process.env.GOOGLE_API_USE_CLIENT_CERTIFICATE = 'false'; + const result = await canMtlsBeEnabled(); + assert.strictEqual(result, false); + }); + + it('returns false if GOOGLE_API_USE_MTLS_ENDPOINT is never', async () => { + process.env.GOOGLE_API_USE_MTLS_ENDPOINT = 'never'; + const result = await canMtlsBeEnabled(); + assert.strictEqual(result, false); + }); + + it('returns true if valid cert config file is present', async () => { + process.env.GOOGLE_API_CERTIFICATE_CONFIG = + './test/fixtures/external-account-cert/cert_config.json'; + const result = await canMtlsBeEnabled(); + assert.strictEqual(result, true); + }); + + it('throws error if cert config file is malformed', async () => { + process.env.GOOGLE_API_CERTIFICATE_CONFIG = + './test/fixtures/external-account-cert/cert_config_empty.json'; + await assert.rejects(canMtlsBeEnabled()); + }); + + it('throws error if cert config has missing files', async () => { + process.env.GOOGLE_API_CERTIFICATE_CONFIG = + './test/fixtures/external-account-cert/cert_config_missing_cert_path.json'; + await assert.rejects(canMtlsBeEnabled()); + }); + + it('returns false if no config is present', async () => { + delete process.env.GOOGLE_API_CERTIFICATE_CONFIG; + sandbox.stub(util, 'getWellKnownCertificateConfigFileLocation').returns( + path.join(tempDir, 'non_existent.json') + ); + const result = await canMtlsBeEnabled(); + assert.strictEqual(result, false); + }); + }); + + describe('getClientCertAndKey', () => { + it('loads cert and key from config successfully', async () => { + const result = await getClientCertAndKey( + './test/fixtures/external-account-cert/cert_config.json' + ); + assert.ok(result.cert); + assert.ok(result.key); + }); + + it('throws error if files resolved by config are malformed', async () => { + await assert.rejects( + getClientCertAndKey( + './test/fixtures/external-account-cert/cert_config_with_malformed_key.json' + ) + ); + }); + }); +}); From 6ab81e88264e83735e78d43019b7de3be51e4a87 Mon Sep 17 00:00:00 2001 From: Pranav Iyer Date: Fri, 5 Jun 2026 19:15:33 -0700 Subject: [PATCH 5/8] lint and other nit fixes. --- .../auth/certificatesubjecttokensupplier.ts | 20 +------ .../src/auth/mtlsutils.ts | 55 +++++++++++++------ .../src/auth/regionalaccessboundary.ts | 2 +- .../test/test.compute.ts | 6 +- .../test/test.mtlsutils.ts | 19 +++---- 5 files changed, 53 insertions(+), 49 deletions(-) diff --git a/core/packages/google-auth-library-nodejs/src/auth/certificatesubjecttokensupplier.ts b/core/packages/google-auth-library-nodejs/src/auth/certificatesubjecttokensupplier.ts index 23cc9ccfc66d..9cbe1f6d2f63 100644 --- a/core/packages/google-auth-library-nodejs/src/auth/certificatesubjecttokensupplier.ts +++ b/core/packages/google-auth-library-nodejs/src/auth/certificatesubjecttokensupplier.ts @@ -13,7 +13,6 @@ // limitations under the License. import {SubjectTokenSupplier} from './identitypoolclient'; -import {isValidFile} from '../util'; import * as fs from 'fs'; import {X509Certificate} from 'crypto'; import * as https from 'https'; @@ -47,21 +46,6 @@ export interface CertificateSubjectTokenSupplierOptions { * Represents the "workload" block within the certificate configuration file. * @internal */ -interface WorkloadCertConfigJson { - cert_path: string; - key_path: string; -} - -/** - * Represents the structure of the certificate_config.json file. - * @internal - */ -interface CertificateConfigFileJson { - version: number; - cert_configs: { - workload?: WorkloadCertConfigJson; - }; -} /** * A subject token supplier that uses a client certificate for authentication. @@ -113,7 +97,9 @@ export class CertificateSubjectTokenSupplier implements SubjectTokenSupplier { // The "subject token" in this context is the processed certificate chain. // getClientCertAndKey handles path resolution, file reading, and validation - ({cert: this.cert, key: this.key} = await getClientCertAndKey(this.certificateConfigPath)); + ({cert: this.cert, key: this.key} = await getClientCertAndKey( + this.certificateConfigPath, + )); return await this.#processChainFromPaths(this.cert); } diff --git a/core/packages/google-auth-library-nodejs/src/auth/mtlsutils.ts b/core/packages/google-auth-library-nodejs/src/auth/mtlsutils.ts index 5b0fa174d4ae..399053c17d8a 100644 --- a/core/packages/google-auth-library-nodejs/src/auth/mtlsutils.ts +++ b/core/packages/google-auth-library-nodejs/src/auth/mtlsutils.ts @@ -16,6 +16,18 @@ import * as fs from 'fs'; import {createPrivateKey, X509Certificate} from 'crypto'; import {getWellKnownCertificateConfigFileLocation, isValidFile} from '../util'; +interface WorkloadCertConfigJson { + cert_path: string; + key_path: string; +} + +interface CertificateConfigFileJson { + version: number; + cert_configs: { + workload?: WorkloadCertConfigJson; + }; +} + export const CERTIFICATE_CONFIGURATION_ENV_VARIABLE = 'GOOGLE_API_CERTIFICATE_CONFIG'; @@ -52,7 +64,7 @@ export enum MtlsEndpointUsagePolicy { /** * Resolves the mTLS endpoint usage policy based on the `GOOGLE_API_USE_MTLS_ENDPOINT` * environment variable. - * + * * @returns The resolved MtlsEndpointUsagePolicy. */ export function getMtlsEndpointUsagePolicy(): MtlsEndpointUsagePolicy { @@ -67,14 +79,16 @@ export function getMtlsEndpointUsagePolicy(): MtlsEndpointUsagePolicy { /** * Centralized helper method to determine if mutual TLS (mTLS) can be enabled. - * + * * Checks for the environment policy constraints and parses the certificate configuration file. - * + * * @param certConfigPathOverride Optional path to override the certificate configuration file. * @returns A promise that resolves to `true` if mTLS can be enabled, `false` otherwise. * @throws {Error} If a configuration file is resolved but contains malformed contents or missing files. */ -export async function canMtlsBeEnabled(certConfigPathOverride?: string): Promise { +export async function canMtlsBeEnabled( + certConfigPathOverride?: string, +): Promise { if (process.env.GOOGLE_API_USE_CLIENT_CERTIFICATE === 'false') { return false; } @@ -93,10 +107,11 @@ export async function canMtlsBeEnabled(certConfigPathOverride?: string): Promise // Config file exists / was specified. We must validate it. // Any failure here must propagate as a hard error. - const {certPath, keyPath} = await getCertAndKeyFilePathsFromConfig(configPath); + const {certPath, keyPath} = + await getCertAndKeyFilePathsFromConfig(configPath); if (!(await isValidFile(certPath)) || !(await isValidFile(keyPath))) { throw new Error( - `Certificate configuration exists but referenced files are missing: cert_path=${certPath}, key_path=${keyPath}` + `Certificate configuration exists but referenced files are missing: cert_path=${certPath}, key_path=${keyPath}`, ); } return true; @@ -105,13 +120,13 @@ export async function canMtlsBeEnabled(certConfigPathOverride?: string): Promise /** * Resolves the path to the certificate configuration JSON file. * Checks the override path, standard environment variable, and well-known location. - * + * * @param certConfigPathOverride Optional override path. * @returns The resolved absolute path to the configuration file. * @throws {CertificateSourceUnavailableError} If the configuration file cannot be found. */ export async function resolveCertificateConfigFilePath( - certConfigPathOverride?: string + certConfigPathOverride?: string, ): Promise { // Step 1: Check if an override path was passed directly (highest precedence) if (certConfigPathOverride) { @@ -150,14 +165,14 @@ export async function resolveCertificateConfigFilePath( /** * Reads and parses the certificate configuration JSON file to extract the * certificate and private key file paths from the workload configuration block. - * + * * @param configPath Absolute path to the certificate config file. * @returns The file paths to the certificate and key. * @throws {CertificateSourceUnavailableError} If the configuration file is unreadable. * @throws {InvalidConfigurationError} If the JSON contents are invalid or missing required paths. */ export async function getCertAndKeyFilePathsFromConfig( - configPath: string + configPath: string, ): Promise<{certPath: string; keyPath: string}> { let fileContents: string; try { @@ -169,7 +184,7 @@ export async function getCertAndKeyFilePathsFromConfig( } try { - const config = JSON.parse(fileContents); + const config = JSON.parse(fileContents) as CertificateConfigFileJson; const certPath = config?.cert_configs?.workload?.cert_path; const keyPath = config?.cert_configs?.workload?.key_path; @@ -180,7 +195,10 @@ export async function getCertAndKeyFilePathsFromConfig( } return {certPath, keyPath}; } catch (e) { - if (e instanceof InvalidConfigurationError || e instanceof CertificateSourceUnavailableError) { + if ( + e instanceof InvalidConfigurationError || + e instanceof CertificateSourceUnavailableError + ) { throw e; } throw new InvalidConfigurationError( @@ -194,17 +212,20 @@ export async function getCertAndKeyFilePathsFromConfig( /** * Loads the actual certificate and private key bytes from disk. * Prioritizes the configuration file. Validates the loaded files are in the correct format. - * + * * @param certConfigPathOverride Optional override path. * @returns The loaded cert and private key buffers. * @throws {Error} If no credentials could be resolved or if validation fails. */ export async function getClientCertAndKey( - certConfigPathOverride?: string + certConfigPathOverride?: string, ): Promise<{cert: Buffer; key: Buffer}> { - const configPath = await resolveCertificateConfigFilePath(certConfigPathOverride); - const {certPath, keyPath} = await getCertAndKeyFilePathsFromConfig(configPath); - + const configPath = await resolveCertificateConfigFilePath( + certConfigPathOverride, + ); + const {certPath, keyPath} = + await getCertAndKeyFilePathsFromConfig(configPath); + let cert, key; try { cert = await fs.promises.readFile(certPath); diff --git a/core/packages/google-auth-library-nodejs/src/auth/regionalaccessboundary.ts b/core/packages/google-auth-library-nodejs/src/auth/regionalaccessboundary.ts index 56ef39b6da88..0f690f76b5e8 100644 --- a/core/packages/google-auth-library-nodejs/src/auth/regionalaccessboundary.ts +++ b/core/packages/google-auth-library-nodejs/src/auth/regionalaccessboundary.ts @@ -256,7 +256,7 @@ export class RegionalAccessBoundaryManager { opts.agent = new https.Agent({cert, key}); regionalAccessBoundaryUrl = regionalAccessBoundaryUrl.replace( 'iamcredentials.googleapis.com', - 'iamcredentials.mtls.googleapis.com' + 'iamcredentials.mtls.googleapis.com', ); opts.url = regionalAccessBoundaryUrl; } diff --git a/core/packages/google-auth-library-nodejs/test/test.compute.ts b/core/packages/google-auth-library-nodejs/test/test.compute.ts index d8b959c084af..c1c1b0104940 100644 --- a/core/packages/google-auth-library-nodejs/test/test.compute.ts +++ b/core/packages/google-auth-library-nodejs/test/test.compute.ts @@ -373,16 +373,16 @@ describe('compute', () => { './test/fixtures/external-account-cert/cert_config.json'; const tokenScope = setupTokenNock('default'); - + // The lookup url should be replaced with iamcredentials.mtls.googleapis.com const lookupUrl = SERVICE_ACCOUNT_LOOKUP_ENDPOINT.replace( '{service_account_email}', encodeURIComponent(fakeEmail), ).replace( 'iamcredentials.googleapis.com', - 'iamcredentials.mtls.googleapis.com' + 'iamcredentials.mtls.googleapis.com', ); - + const rabScope = nock(new URL(lookupUrl).origin) .get(new URL(lookupUrl).pathname) .matchHeader('authorization', MOCK_AUTH_HEADER) diff --git a/core/packages/google-auth-library-nodejs/test/test.mtlsutils.ts b/core/packages/google-auth-library-nodejs/test/test.mtlsutils.ts index f07a87573ea6..9e1919b0323c 100644 --- a/core/packages/google-auth-library-nodejs/test/test.mtlsutils.ts +++ b/core/packages/google-auth-library-nodejs/test/test.mtlsutils.ts @@ -18,10 +18,7 @@ import * as sinon from 'sinon'; import * as fs from 'fs'; import * as path from 'path'; import * as os from 'os'; -import { - canMtlsBeEnabled, - getClientCertAndKey, -} from '../src/auth/mtlsutils'; +import {canMtlsBeEnabled, getClientCertAndKey} from '../src/auth/mtlsutils'; import * as util from '../src/util'; describe('mtlsutils', () => { @@ -30,7 +27,7 @@ describe('mtlsutils', () => { beforeEach(async () => { sandbox = sinon.createSandbox(); - sandbox.stub(process, 'env').value({ ...process.env }); + sandbox.stub(process, 'env').value({...process.env}); tempDir = await fs.promises.mkdtemp(path.join(os.tmpdir(), 'mtls-tests-')); }); @@ -73,9 +70,9 @@ describe('mtlsutils', () => { it('returns false if no config is present', async () => { delete process.env.GOOGLE_API_CERTIFICATE_CONFIG; - sandbox.stub(util, 'getWellKnownCertificateConfigFileLocation').returns( - path.join(tempDir, 'non_existent.json') - ); + sandbox + .stub(util, 'getWellKnownCertificateConfigFileLocation') + .returns(path.join(tempDir, 'non_existent.json')); const result = await canMtlsBeEnabled(); assert.strictEqual(result, false); }); @@ -84,7 +81,7 @@ describe('mtlsutils', () => { describe('getClientCertAndKey', () => { it('loads cert and key from config successfully', async () => { const result = await getClientCertAndKey( - './test/fixtures/external-account-cert/cert_config.json' + './test/fixtures/external-account-cert/cert_config.json', ); assert.ok(result.cert); assert.ok(result.key); @@ -93,8 +90,8 @@ describe('mtlsutils', () => { it('throws error if files resolved by config are malformed', async () => { await assert.rejects( getClientCertAndKey( - './test/fixtures/external-account-cert/cert_config_with_malformed_key.json' - ) + './test/fixtures/external-account-cert/cert_config_with_malformed_key.json', + ), ); }); }); From 1150afa1455c11a63aa824ebdc798723c0a05972 Mon Sep 17 00:00:00 2001 From: Pranav Iyer Date: Wed, 10 Jun 2026 19:52:47 -0700 Subject: [PATCH 6/8] Added calling the RAB mtls endpoint if isMTLS set to ALWAYS. --- .../src/auth/mtlsutils.ts | 11 ++- .../src/auth/regionalaccessboundary.ts | 11 ++- .../test/test.jwt.ts | 83 +++++++++++++++++++ .../test/test.mtlsutils.ts | 19 +++++ 4 files changed, 122 insertions(+), 2 deletions(-) diff --git a/core/packages/google-auth-library-nodejs/src/auth/mtlsutils.ts b/core/packages/google-auth-library-nodejs/src/auth/mtlsutils.ts index 399053c17d8a..912729ba3bd8 100644 --- a/core/packages/google-auth-library-nodejs/src/auth/mtlsutils.ts +++ b/core/packages/google-auth-library-nodejs/src/auth/mtlsutils.ts @@ -89,12 +89,21 @@ export function getMtlsEndpointUsagePolicy(): MtlsEndpointUsagePolicy { export async function canMtlsBeEnabled( certConfigPathOverride?: string, ): Promise { + const policy = getMtlsEndpointUsagePolicy(); if (process.env.GOOGLE_API_USE_CLIENT_CERTIFICATE === 'false') { + if (policy === MtlsEndpointUsagePolicy.ALWAYS) { + throw new CertificateSourceUnavailableError( + 'mTLS is configured to ALWAYS, but client certificate usage was explicitly disabled via GOOGLE_API_USE_CLIENT_CERTIFICATE=false.', + ); + } return false; } - if (getMtlsEndpointUsagePolicy() === MtlsEndpointUsagePolicy.NEVER) { + if (policy === MtlsEndpointUsagePolicy.NEVER) { return false; } + if (policy === MtlsEndpointUsagePolicy.ALWAYS) { + return true; + } // Check for certificate configuration file let configPath: string | null = null; diff --git a/core/packages/google-auth-library-nodejs/src/auth/regionalaccessboundary.ts b/core/packages/google-auth-library-nodejs/src/auth/regionalaccessboundary.ts index 0f690f76b5e8..57f1cc94569c 100644 --- a/core/packages/google-auth-library-nodejs/src/auth/regionalaccessboundary.ts +++ b/core/packages/google-auth-library-nodejs/src/auth/regionalaccessboundary.ts @@ -15,7 +15,12 @@ import {Gaxios, GaxiosOptions} from 'gaxios'; import {log as makeLog} from 'google-logging-utils'; import * as https from 'https'; -import {canMtlsBeEnabled, getClientCertAndKey} from './mtlsutils'; +import { + canMtlsBeEnabled, + getClientCertAndKey, + getMtlsEndpointUsagePolicy, + MtlsEndpointUsagePolicy, +} from './mtlsutils'; const log = makeLog('auth'); @@ -262,6 +267,10 @@ export class RegionalAccessBoundaryManager { } } catch (e) { log.error('RegionalAccessBoundary: Failed to initialize mTLS: ', e); + // If mTLS is configured to ALWAYS, propagate the error instead of falling back to the standard endpoint. + if (getMtlsEndpointUsagePolicy() === MtlsEndpointUsagePolicy.ALWAYS) { + throw e; + } } const {data: regionalAccessBoundaryData} = diff --git a/core/packages/google-auth-library-nodejs/test/test.jwt.ts b/core/packages/google-auth-library-nodejs/test/test.jwt.ts index a4b1e3147da9..1cb05438ebab 100644 --- a/core/packages/google-auth-library-nodejs/test/test.jwt.ts +++ b/core/packages/google-auth-library-nodejs/test/test.jwt.ts @@ -1332,6 +1332,89 @@ describe('jwt', () => { rabScope.done(); }); + it('should fail RAB lookup if GOOGLE_API_USE_MTLS_ENDPOINT is always but client certificate is disabled', async () => { + process.env.GOOGLE_API_USE_MTLS_ENDPOINT = 'always'; + process.env.GOOGLE_API_USE_CLIENT_CERTIFICATE = 'false'; + + const jwt = new JWT({ + email: SERVICE_ACCOUNT_EMAIL, + keyFile: PEM_PATH, + scopes: ['http://bar', 'http://foo'], + subject: 'bar@subjectaccount.com', + }); + jwt.credentials = {refresh_token: 'jwt-placeholder'}; + + const tokenScope = createGTokenMock({access_token: MOCK_ACCESS_TOKEN}); + + // We trigger the background lookup by getting request headers. + await jwt.getRequestHeaders('https://pubsub.googleapis.com'); + + // Wait a bit for the async task to execute and fail + let attempts = 0; + while (!jwt.getRegionalAccessBoundaryCooldownTime() && attempts < 10) { + await new Promise(r => setTimeout(r, 50)); + attempts++; + } + + // It should enter cooldown because it failed to initialize mTLS + assert.ok(jwt.getRegionalAccessBoundaryCooldownTime() > Date.now()); + + tokenScope.done(); + }); + + it('should use mTLS endpoint for RAB lookup if GOOGLE_API_USE_MTLS_ENDPOINT is always and valid cert config is present', async () => { + process.env.GOOGLE_API_USE_MTLS_ENDPOINT = 'always'; + process.env.GOOGLE_API_CERTIFICATE_CONFIG = + './test/fixtures/external-account-cert/cert_config.json'; + + const jwt = new JWT({ + email: SERVICE_ACCOUNT_EMAIL, + keyFile: PEM_PATH, + scopes: ['http://bar', 'http://foo'], + subject: 'bar@subjectaccount.com', + }); + jwt.credentials = {refresh_token: 'jwt-placeholder'}; + + const tokenScope = createGTokenMock({access_token: MOCK_ACCESS_TOKEN}); + + // Construct and mock the mTLS lookup URL + const lookupUrl = SERVICE_ACCOUNT_LOOKUP_ENDPOINT.replace( + '{service_account_email}', + encodeURIComponent(SERVICE_ACCOUNT_EMAIL), + ).replace( + 'iamcredentials.googleapis.com', + 'iamcredentials.mtls.googleapis.com', + ); + + let rabLookupCalled = false; + const rabScope = nock(new URL(lookupUrl).origin) + .get(new URL(lookupUrl).pathname) + .matchHeader('authorization', MOCK_AUTH_HEADER) + .reply(() => { + rabLookupCalled = true; + return [200, EXPECTED_RAB_DATA]; + }); + + // We trigger the background lookup by getting request headers. + await jwt.getRequestHeaders('https://pubsub.googleapis.com'); + + // Wait a bit for the async task to execute + let attempts = 0; + while (!rabLookupCalled && attempts < 10) { + await new Promise(r => setTimeout(r, 50)); + attempts++; + } + + assert.strictEqual(rabLookupCalled, true); + assert.deepStrictEqual( + jwt.getRegionalAccessBoundary(), + EXPECTED_RAB_DATA, + ); + + tokenScope.done(); + rabScope.done(); + }); + it('should trigger RAB refresh for self-signed JWT', async () => { // Self-signed JWT (no scopes) const keys = keypair(512); diff --git a/core/packages/google-auth-library-nodejs/test/test.mtlsutils.ts b/core/packages/google-auth-library-nodejs/test/test.mtlsutils.ts index 9e1919b0323c..a09e54695bd7 100644 --- a/core/packages/google-auth-library-nodejs/test/test.mtlsutils.ts +++ b/core/packages/google-auth-library-nodejs/test/test.mtlsutils.ts @@ -76,6 +76,25 @@ describe('mtlsutils', () => { const result = await canMtlsBeEnabled(); assert.strictEqual(result, false); }); + + it('returns true if GOOGLE_API_USE_MTLS_ENDPOINT is always, even if no config file is present', async () => { + process.env.GOOGLE_API_USE_MTLS_ENDPOINT = 'always'; + delete process.env.GOOGLE_API_CERTIFICATE_CONFIG; + sandbox + .stub(util, 'getWellKnownCertificateConfigFileLocation') + .returns(path.join(tempDir, 'non_existent.json')); + const result = await canMtlsBeEnabled(); + assert.strictEqual(result, true); + }); + + it('throws error if GOOGLE_API_USE_MTLS_ENDPOINT is always and GOOGLE_API_USE_CLIENT_CERTIFICATE is false', async () => { + process.env.GOOGLE_API_USE_MTLS_ENDPOINT = 'always'; + process.env.GOOGLE_API_USE_CLIENT_CERTIFICATE = 'false'; + await assert.rejects( + canMtlsBeEnabled(), + /mTLS is configured to ALWAYS, but client certificate usage was explicitly disabled via GOOGLE_API_USE_CLIENT_CERTIFICATE=false\./, + ); + }); }); describe('getClientCertAndKey', () => { From c4917ac626a085e498ca9864d5faf3e6db2bf454 Mon Sep 17 00:00:00 2001 From: Pranav Iyer Date: Wed, 10 Jun 2026 20:12:20 -0700 Subject: [PATCH 7/8] canMtlsBeEnabled no longer does file reads. --- .../src/auth/mtlsutils.ts | 33 +++++---- .../test/test.mtlsutils.ts | 74 +++++++++++++++++-- 2 files changed, 87 insertions(+), 20 deletions(-) diff --git a/core/packages/google-auth-library-nodejs/src/auth/mtlsutils.ts b/core/packages/google-auth-library-nodejs/src/auth/mtlsutils.ts index 912729ba3bd8..a2578b02972b 100644 --- a/core/packages/google-auth-library-nodejs/src/auth/mtlsutils.ts +++ b/core/packages/google-auth-library-nodejs/src/auth/mtlsutils.ts @@ -106,24 +106,27 @@ export async function canMtlsBeEnabled( } // Check for certificate configuration file - let configPath: string | null = null; - try { - configPath = await resolveCertificateConfigFilePath(certConfigPathOverride); - } catch (e) { - // Config file is simply not present. - return false; + if ( + certConfigPathOverride || + process.env[CERTIFICATE_CONFIGURATION_ENV_VARIABLE] + ) { + const configPath = + certConfigPathOverride || + process.env[CERTIFICATE_CONFIGURATION_ENV_VARIABLE]!; + if (!(await isValidFile(configPath))) { + throw new CertificateSourceUnavailableError( + `Certificate configuration file does not exist or is not a file: ${configPath}`, + ); + } + return true; } - // Config file exists / was specified. We must validate it. - // Any failure here must propagate as a hard error. - const {certPath, keyPath} = - await getCertAndKeyFilePathsFromConfig(configPath); - if (!(await isValidFile(certPath)) || !(await isValidFile(keyPath))) { - throw new Error( - `Certificate configuration exists but referenced files are missing: cert_path=${certPath}, key_path=${keyPath}`, - ); + const wellKnownPath = getWellKnownCertificateConfigFileLocation(); + if (await isValidFile(wellKnownPath)) { + return true; } - return true; + + return false; } /** diff --git a/core/packages/google-auth-library-nodejs/test/test.mtlsutils.ts b/core/packages/google-auth-library-nodejs/test/test.mtlsutils.ts index a09e54695bd7..f6979baf5316 100644 --- a/core/packages/google-auth-library-nodejs/test/test.mtlsutils.ts +++ b/core/packages/google-auth-library-nodejs/test/test.mtlsutils.ts @@ -18,7 +18,12 @@ import * as sinon from 'sinon'; import * as fs from 'fs'; import * as path from 'path'; import * as os from 'os'; -import {canMtlsBeEnabled, getClientCertAndKey} from '../src/auth/mtlsutils'; +import { + canMtlsBeEnabled, + getClientCertAndKey, + CertificateSourceUnavailableError, + InvalidConfigurationError, +} from '../src/auth/mtlsutils'; import * as util from '../src/util'; describe('mtlsutils', () => { @@ -56,16 +61,37 @@ describe('mtlsutils', () => { assert.strictEqual(result, true); }); - it('throws error if cert config file is malformed', async () => { + it('returns true even if cert config file is malformed', async () => { process.env.GOOGLE_API_CERTIFICATE_CONFIG = './test/fixtures/external-account-cert/cert_config_empty.json'; - await assert.rejects(canMtlsBeEnabled()); + const result = await canMtlsBeEnabled(); + assert.strictEqual(result, true); }); - it('throws error if cert config has missing files', async () => { + it('returns true even if cert config is missing required workload properties', async () => { process.env.GOOGLE_API_CERTIFICATE_CONFIG = './test/fixtures/external-account-cert/cert_config_missing_cert_path.json'; - await assert.rejects(canMtlsBeEnabled()); + const result = await canMtlsBeEnabled(); + assert.strictEqual(result, true); + }); + + it('returns true even if cert config referenced files do not exist', async () => { + const invalidConfigPath = path.join(tempDir, 'invalid_config.json'); + const invalidConfigJson = { + cert_configs: { + workload: { + cert_path: path.join(tempDir, 'non_existent.crt'), + key_path: path.join(tempDir, 'non_existent.key'), + }, + }, + }; + await fs.promises.writeFile( + invalidConfigPath, + JSON.stringify(invalidConfigJson), + ); + process.env.GOOGLE_API_CERTIFICATE_CONFIG = invalidConfigPath; + const result = await canMtlsBeEnabled(); + assert.strictEqual(result, true); }); it('returns false if no config is present', async () => { @@ -113,5 +139,43 @@ describe('mtlsutils', () => { ), ); }); + + it('throws error if cert config file is malformed', async () => { + await assert.rejects( + getClientCertAndKey( + './test/fixtures/external-account-cert/cert_config_empty.json', + ), + InvalidConfigurationError, + ); + }); + + it('throws error if cert config is missing required workload properties', async () => { + await assert.rejects( + getClientCertAndKey( + './test/fixtures/external-account-cert/cert_config_missing_cert_path.json', + ), + InvalidConfigurationError, + ); + }); + + it('throws error if cert config referenced files do not exist', async () => { + const invalidConfigPath = path.join(tempDir, 'invalid_config.json'); + const invalidConfigJson = { + cert_configs: { + workload: { + cert_path: path.join(tempDir, 'non_existent.crt'), + key_path: path.join(tempDir, 'non_existent.key'), + }, + }, + }; + await fs.promises.writeFile( + invalidConfigPath, + JSON.stringify(invalidConfigJson), + ); + await assert.rejects( + getClientCertAndKey(invalidConfigPath), + CertificateSourceUnavailableError, + ); + }); }); }); From e9a52df272bfc3df0d5a75959930a28cbb5d7c81 Mon Sep 17 00:00:00 2001 From: Pranav Iyer Date: Fri, 10 Jul 2026 17:17:08 -0700 Subject: [PATCH 8/8] Case in-sensitive mTLS Endpoint Usage Policy. --- .../src/auth/mtlsutils.ts | 2 +- .../test/test.mtlsutils.ts | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/core/packages/google-auth-library-nodejs/src/auth/mtlsutils.ts b/core/packages/google-auth-library-nodejs/src/auth/mtlsutils.ts index a2578b02972b..bd6986e329dd 100644 --- a/core/packages/google-auth-library-nodejs/src/auth/mtlsutils.ts +++ b/core/packages/google-auth-library-nodejs/src/auth/mtlsutils.ts @@ -68,7 +68,7 @@ export enum MtlsEndpointUsagePolicy { * @returns The resolved MtlsEndpointUsagePolicy. */ export function getMtlsEndpointUsagePolicy(): MtlsEndpointUsagePolicy { - const policy = process.env.GOOGLE_API_USE_MTLS_ENDPOINT; + const policy = process.env.GOOGLE_API_USE_MTLS_ENDPOINT?.toLowerCase(); if (policy === 'never') { return MtlsEndpointUsagePolicy.NEVER; } else if (policy === 'always') { diff --git a/core/packages/google-auth-library-nodejs/test/test.mtlsutils.ts b/core/packages/google-auth-library-nodejs/test/test.mtlsutils.ts index f6979baf5316..4a661b990ddd 100644 --- a/core/packages/google-auth-library-nodejs/test/test.mtlsutils.ts +++ b/core/packages/google-auth-library-nodejs/test/test.mtlsutils.ts @@ -23,6 +23,8 @@ import { getClientCertAndKey, CertificateSourceUnavailableError, InvalidConfigurationError, + getMtlsEndpointUsagePolicy, + MtlsEndpointUsagePolicy, } from '../src/auth/mtlsutils'; import * as util from '../src/util'; @@ -178,4 +180,20 @@ describe('mtlsutils', () => { ); }); }); + + describe('getMtlsEndpointUsagePolicy', () => { + it('returns NEVER or ALWAYS case-insensitively', () => { + process.env.GOOGLE_API_USE_MTLS_ENDPOINT = 'NeVeR'; + assert.strictEqual( + getMtlsEndpointUsagePolicy(), + MtlsEndpointUsagePolicy.NEVER, + ); + + process.env.GOOGLE_API_USE_MTLS_ENDPOINT = 'AlWaYs'; + assert.strictEqual( + getMtlsEndpointUsagePolicy(), + MtlsEndpointUsagePolicy.ALWAYS, + ); + }); + }); });