From 85befc48e9b31055659089903e13f882752fd746 Mon Sep 17 00:00:00 2001
From: Brent Shaffer <betterbrent@google.com>
Date: Tue, 21 May 2024 05:08:41 -0700
Subject: [PATCH] feat: add V1 for SecurityPublicCA (#7319)

---
 SecurityPublicCA/.OwlBot.yaml                 |   4 +-
 SecurityPublicCA/metadata/V1/Resources.php    |  34 +++
 SecurityPublicCA/metadata/V1/Service.php      |  37 +++
 .../create_external_account_key.php           |  77 +++++
 ...ublicCertificateAuthorityServiceClient.php | 263 ++++++++++++++++++
 .../V1/CreateExternalAccountKeyRequest.php    | 154 ++++++++++
 .../src/V1/ExternalAccountKey.php             | 156 +++++++++++
 SecurityPublicCA/src/V1/gapic_metadata.json   |  23 ++
 ...icate_authority_service_client_config.json |  39 +++
 ...te_authority_service_descriptor_config.php |  44 +++
 ...e_authority_service_rest_client_config.php |  41 +++
 ...cCertificateAuthorityServiceClientTest.php | 173 ++++++++++++
 12 files changed, 1043 insertions(+), 2 deletions(-)
 create mode 100644 SecurityPublicCA/metadata/V1/Resources.php
 create mode 100644 SecurityPublicCA/metadata/V1/Service.php
 create mode 100644 SecurityPublicCA/samples/V1/PublicCertificateAuthorityServiceClient/create_external_account_key.php
 create mode 100644 SecurityPublicCA/src/V1/Client/PublicCertificateAuthorityServiceClient.php
 create mode 100644 SecurityPublicCA/src/V1/CreateExternalAccountKeyRequest.php
 create mode 100644 SecurityPublicCA/src/V1/ExternalAccountKey.php
 create mode 100644 SecurityPublicCA/src/V1/gapic_metadata.json
 create mode 100644 SecurityPublicCA/src/V1/resources/public_certificate_authority_service_client_config.json
 create mode 100644 SecurityPublicCA/src/V1/resources/public_certificate_authority_service_descriptor_config.php
 create mode 100644 SecurityPublicCA/src/V1/resources/public_certificate_authority_service_rest_client_config.php
 create mode 100644 SecurityPublicCA/tests/Unit/V1/Client/PublicCertificateAuthorityServiceClientTest.php

diff --git a/SecurityPublicCA/.OwlBot.yaml b/SecurityPublicCA/.OwlBot.yaml
index f6aff046c3f0..71a093d0d049 100644
--- a/SecurityPublicCA/.OwlBot.yaml
+++ b/SecurityPublicCA/.OwlBot.yaml
@@ -1,4 +1,4 @@
 deep-copy-regex:
-    - source: /google/cloud/security/publicca/v1beta1/.*-php/(.*)
-      dest: /owl-bot-staging/SecurityPublicCA/v1beta1/$1
+    - source: /google/cloud/security/publicca/(v1|v1beta1)/.*-php/(.*)
+      dest: /owl-bot-staging/SecurityPublicCA/$1/$2
 api-name: SecurityPublicCA
diff --git a/SecurityPublicCA/metadata/V1/Resources.php b/SecurityPublicCA/metadata/V1/Resources.php
new file mode 100644
index 000000000000..c6551ee40ca3
--- /dev/null
+++ b/SecurityPublicCA/metadata/V1/Resources.php
@@ -0,0 +1,34 @@
+<?php
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# source: google/cloud/security/publicca/v1/resources.proto
+
+namespace GPBMetadata\Google\Cloud\Security\Publicca\V1;
+
+class Resources
+{
+    public static $is_initialized = false;
+
+    public static function initOnce() {
+        $pool = \Google\Protobuf\Internal\DescriptorPool::getGeneratedPool();
+
+        if (static::$is_initialized == true) {
+          return;
+        }
+        \GPBMetadata\Google\Api\FieldBehavior::initOnce();
+        \GPBMetadata\Google\Api\Resource::initOnce();
+        $pool->internalAddGeneratedFile(
+            '
+�
+1google/cloud/security/publicca/v1/resources.proto!google.cloud.security.publicca.v1google/api/resource.proto"�
+ExternalAccountKey
+name (	B�A
+key_id (	B�A
+b64_mac_key (B�A:��A�
+*publicca.googleapis.com/ExternalAccountKeyRprojects/{project}/locations/{location}/externalAccountKeys/{external_account_key}B�
+%com.google.cloud.security.publicca.v1BResourcesProtoPZAcloud.google.com/go/security/publicca/apiv1/publiccapb;publiccapb��!Google.Cloud.Security.PublicCA.V1�!Google\\Cloud\\Security\\PublicCA\\V1�%Google::Cloud::Security::PublicCA::V1bproto3'
+        , true);
+
+        static::$is_initialized = true;
+    }
+}
+
diff --git a/SecurityPublicCA/metadata/V1/Service.php b/SecurityPublicCA/metadata/V1/Service.php
new file mode 100644
index 000000000000..e5dbf8c95864
--- /dev/null
+++ b/SecurityPublicCA/metadata/V1/Service.php
@@ -0,0 +1,37 @@
+<?php
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# source: google/cloud/security/publicca/v1/service.proto
+
+namespace GPBMetadata\Google\Cloud\Security\Publicca\V1;
+
+class Service
+{
+    public static $is_initialized = false;
+
+    public static function initOnce() {
+        $pool = \Google\Protobuf\Internal\DescriptorPool::getGeneratedPool();
+
+        if (static::$is_initialized == true) {
+          return;
+        }
+        \GPBMetadata\Google\Api\Annotations::initOnce();
+        \GPBMetadata\Google\Api\Client::initOnce();
+        \GPBMetadata\Google\Api\FieldBehavior::initOnce();
+        \GPBMetadata\Google\Api\Resource::initOnce();
+        \GPBMetadata\Google\Cloud\Security\Publicca\V1\Resources::initOnce();
+        $pool->internalAddGeneratedFile(
+            '
+�
+/google/cloud/security/publicca/v1/service.proto!google.cloud.security.publicca.v1google/api/client.protogoogle/api/field_behavior.protogoogle/api/resource.proto1google/cloud/security/publicca/v1/resources.proto"�
+CreateExternalAccountKeyRequestB
+parent (	B2�A�A,*publicca.googleapis.com/ExternalAccountKeyX
+external_account_key (25.google.cloud.security.publicca.v1.ExternalAccountKeyB�A2�
+!PublicCertificateAuthorityService�
+CreateExternalAccountKeyB.google.cloud.security.publicca.v1.CreateExternalAccountKeyRequest5.google.cloud.security.publicca.v1.ExternalAccountKey"s�Aparent,external_account_key���O"7/v1/{parent=projects/*/locations/*}/externalAccountKeys:external_account_keyK�Apublicca.googleapis.com�A.https://www.googleapis.com/auth/cloud-platformB�
+%com.google.cloud.security.publicca.v1BServiceProtoPZAcloud.google.com/go/security/publicca/apiv1/publiccapb;publiccapb��!Google.Cloud.Security.PublicCA.V1�!Google\\Cloud\\Security\\PublicCA\\V1�%Google::Cloud::Security::PublicCA::V1bproto3'
+        , true);
+
+        static::$is_initialized = true;
+    }
+}
+
diff --git a/SecurityPublicCA/samples/V1/PublicCertificateAuthorityServiceClient/create_external_account_key.php b/SecurityPublicCA/samples/V1/PublicCertificateAuthorityServiceClient/create_external_account_key.php
new file mode 100644
index 000000000000..91aa21a04c6f
--- /dev/null
+++ b/SecurityPublicCA/samples/V1/PublicCertificateAuthorityServiceClient/create_external_account_key.php
@@ -0,0 +1,77 @@
+<?php
+/*
+ * Copyright 2024 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * GENERATED CODE WARNING
+ * This file was automatically generated - do not edit!
+ */
+
+require_once __DIR__ . '/../../../vendor/autoload.php';
+
+// [START publicca_v1_generated_PublicCertificateAuthorityService_CreateExternalAccountKey_sync]
+use Google\ApiCore\ApiException;
+use Google\Cloud\Security\PublicCA\V1\Client\PublicCertificateAuthorityServiceClient;
+use Google\Cloud\Security\PublicCA\V1\CreateExternalAccountKeyRequest;
+use Google\Cloud\Security\PublicCA\V1\ExternalAccountKey;
+
+/**
+ * Creates a new
+ * [ExternalAccountKey][google.cloud.security.publicca.v1.ExternalAccountKey]
+ * bound to the project.
+ *
+ * @param string $formattedParent The parent resource where this external_account_key will be
+ *                                created. Format: projects/[project_id]/locations/[location]. At present
+ *                                only the "global" location is supported. Please see
+ *                                {@see PublicCertificateAuthorityServiceClient::locationName()} for help formatting this field.
+ */
+function create_external_account_key_sample(string $formattedParent): void
+{
+    // Create a client.
+    $publicCertificateAuthorityServiceClient = new PublicCertificateAuthorityServiceClient();
+
+    // Prepare the request message.
+    $externalAccountKey = new ExternalAccountKey();
+    $request = (new CreateExternalAccountKeyRequest())
+        ->setParent($formattedParent)
+        ->setExternalAccountKey($externalAccountKey);
+
+    // Call the API and handle any network failures.
+    try {
+        /** @var ExternalAccountKey $response */
+        $response = $publicCertificateAuthorityServiceClient->createExternalAccountKey($request);
+        printf('Response data: %s' . PHP_EOL, $response->serializeToJsonString());
+    } catch (ApiException $ex) {
+        printf('Call failed with message: %s' . PHP_EOL, $ex->getMessage());
+    }
+}
+
+/**
+ * Helper to execute the sample.
+ *
+ * This sample has been automatically generated and should be regarded as a code
+ * template only. It will require modifications to work:
+ *  - It may require correct/in-range values for request initialization.
+ *  - It may require specifying regional endpoints when creating the service client,
+ *    please see the apiEndpoint client configuration option for more details.
+ */
+function callSample(): void
+{
+    $formattedParent = PublicCertificateAuthorityServiceClient::locationName('[PROJECT]', '[LOCATION]');
+
+    create_external_account_key_sample($formattedParent);
+}
+// [END publicca_v1_generated_PublicCertificateAuthorityService_CreateExternalAccountKey_sync]
diff --git a/SecurityPublicCA/src/V1/Client/PublicCertificateAuthorityServiceClient.php b/SecurityPublicCA/src/V1/Client/PublicCertificateAuthorityServiceClient.php
new file mode 100644
index 000000000000..3262f6430fd6
--- /dev/null
+++ b/SecurityPublicCA/src/V1/Client/PublicCertificateAuthorityServiceClient.php
@@ -0,0 +1,263 @@
+<?php
+/*
+ * Copyright 2024 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * GENERATED CODE WARNING
+ * Generated by gapic-generator-php from the file
+ * https://github.com/googleapis/googleapis/blob/master/google/cloud/security/publicca/v1/service.proto
+ * Updates to the above are reflected here through a refresh process.
+ */
+
+namespace Google\Cloud\Security\PublicCA\V1\Client;
+
+use Google\ApiCore\ApiException;
+use Google\ApiCore\CredentialsWrapper;
+use Google\ApiCore\GapicClientTrait;
+use Google\ApiCore\ResourceHelperTrait;
+use Google\ApiCore\RetrySettings;
+use Google\ApiCore\Transport\TransportInterface;
+use Google\ApiCore\ValidationException;
+use Google\Auth\FetchAuthTokenInterface;
+use Google\Cloud\Security\PublicCA\V1\CreateExternalAccountKeyRequest;
+use Google\Cloud\Security\PublicCA\V1\ExternalAccountKey;
+use GuzzleHttp\Promise\PromiseInterface;
+
+/**
+ * Service Description: Manages the resources required for ACME [external account
+ * binding](https://tools.ietf.org/html/rfc8555#section-7.3.4) for
+ * the public certificate authority service.
+ *
+ * This class provides the ability to make remote calls to the backing service through method
+ * calls that map to API methods.
+ *
+ * Many parameters require resource names to be formatted in a particular way. To
+ * assist with these names, this class includes a format method for each type of
+ * name, and additionally a parseName method to extract the individual identifiers
+ * contained within formatted names that are returned by the API.
+ *
+ * @method PromiseInterface createExternalAccountKeyAsync(CreateExternalAccountKeyRequest $request, array $optionalArgs = [])
+ */
+final class PublicCertificateAuthorityServiceClient
+{
+    use GapicClientTrait;
+    use ResourceHelperTrait;
+
+    /** The name of the service. */
+    private const SERVICE_NAME = 'google.cloud.security.publicca.v1.PublicCertificateAuthorityService';
+
+    /**
+     * The default address of the service.
+     *
+     * @deprecated SERVICE_ADDRESS_TEMPLATE should be used instead.
+     */
+    private const SERVICE_ADDRESS = 'publicca.googleapis.com';
+
+    /** The address template of the service. */
+    private const SERVICE_ADDRESS_TEMPLATE = 'publicca.UNIVERSE_DOMAIN';
+
+    /** The default port of the service. */
+    private const DEFAULT_SERVICE_PORT = 443;
+
+    /** The name of the code generator, to be included in the agent header. */
+    private const CODEGEN_NAME = 'gapic';
+
+    /** The default scopes required by the service. */
+    public static $serviceScopes = [
+        'https://www.googleapis.com/auth/cloud-platform',
+    ];
+
+    private static function getClientDefaults()
+    {
+        return [
+            'serviceName' => self::SERVICE_NAME,
+            'apiEndpoint' => self::SERVICE_ADDRESS . ':' . self::DEFAULT_SERVICE_PORT,
+            'clientConfig' => __DIR__ . '/../resources/public_certificate_authority_service_client_config.json',
+            'descriptorsConfigPath' => __DIR__ . '/../resources/public_certificate_authority_service_descriptor_config.php',
+            'gcpApiConfigPath' => __DIR__ . '/../resources/public_certificate_authority_service_grpc_config.json',
+            'credentialsConfig' => [
+                'defaultScopes' => self::$serviceScopes,
+            ],
+            'transportConfig' => [
+                'rest' => [
+                    'restClientConfigPath' => __DIR__ . '/../resources/public_certificate_authority_service_rest_client_config.php',
+                ],
+            ],
+        ];
+    }
+
+    /**
+     * Formats a string containing the fully-qualified path to represent a
+     * external_account_key resource.
+     *
+     * @param string $project
+     * @param string $location
+     * @param string $externalAccountKey
+     *
+     * @return string The formatted external_account_key resource.
+     */
+    public static function externalAccountKeyName(string $project, string $location, string $externalAccountKey): string
+    {
+        return self::getPathTemplate('externalAccountKey')->render([
+            'project' => $project,
+            'location' => $location,
+            'external_account_key' => $externalAccountKey,
+        ]);
+    }
+
+    /**
+     * Formats a string containing the fully-qualified path to represent a location
+     * resource.
+     *
+     * @param string $project
+     * @param string $location
+     *
+     * @return string The formatted location resource.
+     */
+    public static function locationName(string $project, string $location): string
+    {
+        return self::getPathTemplate('location')->render([
+            'project' => $project,
+            'location' => $location,
+        ]);
+    }
+
+    /**
+     * Parses a formatted name string and returns an associative array of the components in the name.
+     * The following name formats are supported:
+     * Template: Pattern
+     * - externalAccountKey: projects/{project}/locations/{location}/externalAccountKeys/{external_account_key}
+     * - location: projects/{project}/locations/{location}
+     *
+     * The optional $template argument can be supplied to specify a particular pattern,
+     * and must match one of the templates listed above. If no $template argument is
+     * provided, or if the $template argument does not match one of the templates
+     * listed, then parseName will check each of the supported templates, and return
+     * the first match.
+     *
+     * @param string $formattedName The formatted name string
+     * @param string $template      Optional name of template to match
+     *
+     * @return array An associative array from name component IDs to component values.
+     *
+     * @throws ValidationException If $formattedName could not be matched.
+     */
+    public static function parseName(string $formattedName, string $template = null): array
+    {
+        return self::parseFormattedName($formattedName, $template);
+    }
+
+    /**
+     * Constructor.
+     *
+     * @param array $options {
+     *     Optional. Options for configuring the service API wrapper.
+     *
+     *     @type string $apiEndpoint
+     *           The address of the API remote host. May optionally include the port, formatted
+     *           as "<uri>:<port>". Default 'publicca.googleapis.com:443'.
+     *     @type string|array|FetchAuthTokenInterface|CredentialsWrapper $credentials
+     *           The credentials to be used by the client to authorize API calls. This option
+     *           accepts either a path to a credentials file, or a decoded credentials file as a
+     *           PHP array.
+     *           *Advanced usage*: In addition, this option can also accept a pre-constructed
+     *           {@see \Google\Auth\FetchAuthTokenInterface} object or
+     *           {@see \Google\ApiCore\CredentialsWrapper} object. Note that when one of these
+     *           objects are provided, any settings in $credentialsConfig will be ignored.
+     *     @type array $credentialsConfig
+     *           Options used to configure credentials, including auth token caching, for the
+     *           client. For a full list of supporting configuration options, see
+     *           {@see \Google\ApiCore\CredentialsWrapper::build()} .
+     *     @type bool $disableRetries
+     *           Determines whether or not retries defined by the client configuration should be
+     *           disabled. Defaults to `false`.
+     *     @type string|array $clientConfig
+     *           Client method configuration, including retry settings. This option can be either
+     *           a path to a JSON file, or a PHP array containing the decoded JSON data. By
+     *           default this settings points to the default client config file, which is
+     *           provided in the resources folder.
+     *     @type string|TransportInterface $transport
+     *           The transport used for executing network requests. May be either the string
+     *           `rest` or `grpc`. Defaults to `grpc` if gRPC support is detected on the system.
+     *           *Advanced usage*: Additionally, it is possible to pass in an already
+     *           instantiated {@see \Google\ApiCore\Transport\TransportInterface} object. Note
+     *           that when this object is provided, any settings in $transportConfig, and any
+     *           $apiEndpoint setting, will be ignored.
+     *     @type array $transportConfig
+     *           Configuration options that will be used to construct the transport. Options for
+     *           each supported transport type should be passed in a key for that transport. For
+     *           example:
+     *           $transportConfig = [
+     *               'grpc' => [...],
+     *               'rest' => [...],
+     *           ];
+     *           See the {@see \Google\ApiCore\Transport\GrpcTransport::build()} and
+     *           {@see \Google\ApiCore\Transport\RestTransport::build()} methods for the
+     *           supported options.
+     *     @type callable $clientCertSource
+     *           A callable which returns the client cert as a string. This can be used to
+     *           provide a certificate and private key to the transport layer for mTLS.
+     * }
+     *
+     * @throws ValidationException
+     */
+    public function __construct(array $options = [])
+    {
+        $clientOptions = $this->buildClientOptions($options);
+        $this->setClientOptions($clientOptions);
+    }
+
+    /** Handles execution of the async variants for each documented method. */
+    public function __call($method, $args)
+    {
+        if (substr($method, -5) !== 'Async') {
+            trigger_error('Call to undefined method ' . __CLASS__ . "::$method()", E_USER_ERROR);
+        }
+
+        array_unshift($args, substr($method, 0, -5));
+        return call_user_func_array([$this, 'startAsyncCall'], $args);
+    }
+
+    /**
+     * Creates a new
+     * [ExternalAccountKey][google.cloud.security.publicca.v1.ExternalAccountKey]
+     * bound to the project.
+     *
+     * The async variant is
+     * {@see PublicCertificateAuthorityServiceClient::createExternalAccountKeyAsync()}
+     * .
+     *
+     * @example samples/V1/PublicCertificateAuthorityServiceClient/create_external_account_key.php
+     *
+     * @param CreateExternalAccountKeyRequest $request     A request to house fields associated with the call.
+     * @param array                           $callOptions {
+     *     Optional.
+     *
+     *     @type RetrySettings|array $retrySettings
+     *           Retry settings to use for this call. Can be a {@see RetrySettings} object, or an
+     *           associative array of retry settings parameters. See the documentation on
+     *           {@see RetrySettings} for example usage.
+     * }
+     *
+     * @return ExternalAccountKey
+     *
+     * @throws ApiException Thrown if the API call fails.
+     */
+    public function createExternalAccountKey(CreateExternalAccountKeyRequest $request, array $callOptions = []): ExternalAccountKey
+    {
+        return $this->startApiCall('CreateExternalAccountKey', $request, $callOptions)->wait();
+    }
+}
diff --git a/SecurityPublicCA/src/V1/CreateExternalAccountKeyRequest.php b/SecurityPublicCA/src/V1/CreateExternalAccountKeyRequest.php
new file mode 100644
index 000000000000..b779920a03d8
--- /dev/null
+++ b/SecurityPublicCA/src/V1/CreateExternalAccountKeyRequest.php
@@ -0,0 +1,154 @@
+<?php
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# source: google/cloud/security/publicca/v1/service.proto
+
+namespace Google\Cloud\Security\PublicCA\V1;
+
+use Google\Protobuf\Internal\GPBType;
+use Google\Protobuf\Internal\RepeatedField;
+use Google\Protobuf\Internal\GPBUtil;
+
+/**
+ * Creates a new
+ * [ExternalAccountKey][google.cloud.security.publicca.v1.ExternalAccountKey] in
+ * a given project.
+ *
+ * Generated from protobuf message <code>google.cloud.security.publicca.v1.CreateExternalAccountKeyRequest</code>
+ */
+class CreateExternalAccountKeyRequest extends \Google\Protobuf\Internal\Message
+{
+    /**
+     * Required. The parent resource where this external_account_key will be
+     * created. Format: projects/[project_id]/locations/[location]. At present
+     * only the "global" location is supported.
+     *
+     * Generated from protobuf field <code>string parent = 1 [(.google.api.field_behavior) = REQUIRED, (.google.api.resource_reference) = {</code>
+     */
+    private $parent = '';
+    /**
+     * Required. The external account key to create. This field only exists to
+     * future-proof the API. At present, all fields in ExternalAccountKey are
+     * output only and all values are ignored. For the purpose of the
+     * CreateExternalAccountKeyRequest, set it to a default/empty value.
+     *
+     * Generated from protobuf field <code>.google.cloud.security.publicca.v1.ExternalAccountKey external_account_key = 2 [(.google.api.field_behavior) = REQUIRED];</code>
+     */
+    private $external_account_key = null;
+
+    /**
+     * @param string                                                $parent             Required. The parent resource where this external_account_key will be
+     *                                                                                  created. Format: projects/[project_id]/locations/[location]. At present
+     *                                                                                  only the "global" location is supported. Please see
+     *                                                                                  {@see PublicCertificateAuthorityServiceClient::locationName()} for help formatting this field.
+     * @param \Google\Cloud\Security\PublicCA\V1\ExternalAccountKey $externalAccountKey Required. The external account key to create. This field only exists to
+     *                                                                                  future-proof the API. At present, all fields in ExternalAccountKey are
+     *                                                                                  output only and all values are ignored. For the purpose of the
+     *                                                                                  CreateExternalAccountKeyRequest, set it to a default/empty value.
+     *
+     * @return \Google\Cloud\Security\PublicCA\V1\CreateExternalAccountKeyRequest
+     *
+     * @experimental
+     */
+    public static function build(string $parent, \Google\Cloud\Security\PublicCA\V1\ExternalAccountKey $externalAccountKey): self
+    {
+        return (new self())
+            ->setParent($parent)
+            ->setExternalAccountKey($externalAccountKey);
+    }
+
+    /**
+     * Constructor.
+     *
+     * @param array $data {
+     *     Optional. Data for populating the Message object.
+     *
+     *     @type string $parent
+     *           Required. The parent resource where this external_account_key will be
+     *           created. Format: projects/[project_id]/locations/[location]. At present
+     *           only the "global" location is supported.
+     *     @type \Google\Cloud\Security\PublicCA\V1\ExternalAccountKey $external_account_key
+     *           Required. The external account key to create. This field only exists to
+     *           future-proof the API. At present, all fields in ExternalAccountKey are
+     *           output only and all values are ignored. For the purpose of the
+     *           CreateExternalAccountKeyRequest, set it to a default/empty value.
+     * }
+     */
+    public function __construct($data = NULL) {
+        \GPBMetadata\Google\Cloud\Security\Publicca\V1\Service::initOnce();
+        parent::__construct($data);
+    }
+
+    /**
+     * Required. The parent resource where this external_account_key will be
+     * created. Format: projects/[project_id]/locations/[location]. At present
+     * only the "global" location is supported.
+     *
+     * Generated from protobuf field <code>string parent = 1 [(.google.api.field_behavior) = REQUIRED, (.google.api.resource_reference) = {</code>
+     * @return string
+     */
+    public function getParent()
+    {
+        return $this->parent;
+    }
+
+    /**
+     * Required. The parent resource where this external_account_key will be
+     * created. Format: projects/[project_id]/locations/[location]. At present
+     * only the "global" location is supported.
+     *
+     * Generated from protobuf field <code>string parent = 1 [(.google.api.field_behavior) = REQUIRED, (.google.api.resource_reference) = {</code>
+     * @param string $var
+     * @return $this
+     */
+    public function setParent($var)
+    {
+        GPBUtil::checkString($var, True);
+        $this->parent = $var;
+
+        return $this;
+    }
+
+    /**
+     * Required. The external account key to create. This field only exists to
+     * future-proof the API. At present, all fields in ExternalAccountKey are
+     * output only and all values are ignored. For the purpose of the
+     * CreateExternalAccountKeyRequest, set it to a default/empty value.
+     *
+     * Generated from protobuf field <code>.google.cloud.security.publicca.v1.ExternalAccountKey external_account_key = 2 [(.google.api.field_behavior) = REQUIRED];</code>
+     * @return \Google\Cloud\Security\PublicCA\V1\ExternalAccountKey|null
+     */
+    public function getExternalAccountKey()
+    {
+        return $this->external_account_key;
+    }
+
+    public function hasExternalAccountKey()
+    {
+        return isset($this->external_account_key);
+    }
+
+    public function clearExternalAccountKey()
+    {
+        unset($this->external_account_key);
+    }
+
+    /**
+     * Required. The external account key to create. This field only exists to
+     * future-proof the API. At present, all fields in ExternalAccountKey are
+     * output only and all values are ignored. For the purpose of the
+     * CreateExternalAccountKeyRequest, set it to a default/empty value.
+     *
+     * Generated from protobuf field <code>.google.cloud.security.publicca.v1.ExternalAccountKey external_account_key = 2 [(.google.api.field_behavior) = REQUIRED];</code>
+     * @param \Google\Cloud\Security\PublicCA\V1\ExternalAccountKey $var
+     * @return $this
+     */
+    public function setExternalAccountKey($var)
+    {
+        GPBUtil::checkMessage($var, \Google\Cloud\Security\PublicCA\V1\ExternalAccountKey::class);
+        $this->external_account_key = $var;
+
+        return $this;
+    }
+
+}
+
diff --git a/SecurityPublicCA/src/V1/ExternalAccountKey.php b/SecurityPublicCA/src/V1/ExternalAccountKey.php
new file mode 100644
index 000000000000..70b0528be3df
--- /dev/null
+++ b/SecurityPublicCA/src/V1/ExternalAccountKey.php
@@ -0,0 +1,156 @@
+<?php
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# source: google/cloud/security/publicca/v1/resources.proto
+
+namespace Google\Cloud\Security\PublicCA\V1;
+
+use Google\Protobuf\Internal\GPBType;
+use Google\Protobuf\Internal\RepeatedField;
+use Google\Protobuf\Internal\GPBUtil;
+
+/**
+ * A representation of an ExternalAccountKey used for [external account
+ * binding](https://tools.ietf.org/html/rfc8555#section-7.3.4) within ACME.
+ *
+ * Generated from protobuf message <code>google.cloud.security.publicca.v1.ExternalAccountKey</code>
+ */
+class ExternalAccountKey extends \Google\Protobuf\Internal\Message
+{
+    /**
+     * Output only. Resource name.
+     * projects/{project}/locations/{location}/externalAccountKeys/{key_id}
+     *
+     * Generated from protobuf field <code>string name = 1 [(.google.api.field_behavior) = OUTPUT_ONLY];</code>
+     */
+    private $name = '';
+    /**
+     * Output only. Key ID.
+     * It is generated by the PublicCertificateAuthorityService
+     * when the ExternalAccountKey is created
+     *
+     * Generated from protobuf field <code>string key_id = 2 [(.google.api.field_behavior) = OUTPUT_ONLY];</code>
+     */
+    private $key_id = '';
+    /**
+     * Output only. Base64-URL-encoded HS256 key.
+     * It is generated by the PublicCertificateAuthorityService
+     * when the ExternalAccountKey is created
+     *
+     * Generated from protobuf field <code>bytes b64_mac_key = 3 [(.google.api.field_behavior) = OUTPUT_ONLY];</code>
+     */
+    private $b64_mac_key = '';
+
+    /**
+     * Constructor.
+     *
+     * @param array $data {
+     *     Optional. Data for populating the Message object.
+     *
+     *     @type string $name
+     *           Output only. Resource name.
+     *           projects/{project}/locations/{location}/externalAccountKeys/{key_id}
+     *     @type string $key_id
+     *           Output only. Key ID.
+     *           It is generated by the PublicCertificateAuthorityService
+     *           when the ExternalAccountKey is created
+     *     @type string $b64_mac_key
+     *           Output only. Base64-URL-encoded HS256 key.
+     *           It is generated by the PublicCertificateAuthorityService
+     *           when the ExternalAccountKey is created
+     * }
+     */
+    public function __construct($data = NULL) {
+        \GPBMetadata\Google\Cloud\Security\Publicca\V1\Resources::initOnce();
+        parent::__construct($data);
+    }
+
+    /**
+     * Output only. Resource name.
+     * projects/{project}/locations/{location}/externalAccountKeys/{key_id}
+     *
+     * Generated from protobuf field <code>string name = 1 [(.google.api.field_behavior) = OUTPUT_ONLY];</code>
+     * @return string
+     */
+    public function getName()
+    {
+        return $this->name;
+    }
+
+    /**
+     * Output only. Resource name.
+     * projects/{project}/locations/{location}/externalAccountKeys/{key_id}
+     *
+     * Generated from protobuf field <code>string name = 1 [(.google.api.field_behavior) = OUTPUT_ONLY];</code>
+     * @param string $var
+     * @return $this
+     */
+    public function setName($var)
+    {
+        GPBUtil::checkString($var, True);
+        $this->name = $var;
+
+        return $this;
+    }
+
+    /**
+     * Output only. Key ID.
+     * It is generated by the PublicCertificateAuthorityService
+     * when the ExternalAccountKey is created
+     *
+     * Generated from protobuf field <code>string key_id = 2 [(.google.api.field_behavior) = OUTPUT_ONLY];</code>
+     * @return string
+     */
+    public function getKeyId()
+    {
+        return $this->key_id;
+    }
+
+    /**
+     * Output only. Key ID.
+     * It is generated by the PublicCertificateAuthorityService
+     * when the ExternalAccountKey is created
+     *
+     * Generated from protobuf field <code>string key_id = 2 [(.google.api.field_behavior) = OUTPUT_ONLY];</code>
+     * @param string $var
+     * @return $this
+     */
+    public function setKeyId($var)
+    {
+        GPBUtil::checkString($var, True);
+        $this->key_id = $var;
+
+        return $this;
+    }
+
+    /**
+     * Output only. Base64-URL-encoded HS256 key.
+     * It is generated by the PublicCertificateAuthorityService
+     * when the ExternalAccountKey is created
+     *
+     * Generated from protobuf field <code>bytes b64_mac_key = 3 [(.google.api.field_behavior) = OUTPUT_ONLY];</code>
+     * @return string
+     */
+    public function getB64MacKey()
+    {
+        return $this->b64_mac_key;
+    }
+
+    /**
+     * Output only. Base64-URL-encoded HS256 key.
+     * It is generated by the PublicCertificateAuthorityService
+     * when the ExternalAccountKey is created
+     *
+     * Generated from protobuf field <code>bytes b64_mac_key = 3 [(.google.api.field_behavior) = OUTPUT_ONLY];</code>
+     * @param string $var
+     * @return $this
+     */
+    public function setB64MacKey($var)
+    {
+        GPBUtil::checkString($var, False);
+        $this->b64_mac_key = $var;
+
+        return $this;
+    }
+
+}
+
diff --git a/SecurityPublicCA/src/V1/gapic_metadata.json b/SecurityPublicCA/src/V1/gapic_metadata.json
new file mode 100644
index 000000000000..24cfe71a2605
--- /dev/null
+++ b/SecurityPublicCA/src/V1/gapic_metadata.json
@@ -0,0 +1,23 @@
+{
+    "schema": "1.0",
+    "comment": "This file maps proto services\/RPCs to the corresponding library clients\/methods",
+    "language": "php",
+    "protoPackage": "google.cloud.security.publicca.v1",
+    "libraryPackage": "Google\\Cloud\\Security\\PublicCA\\V1",
+    "services": {
+        "PublicCertificateAuthorityService": {
+            "clients": {
+                "grpc": {
+                    "libraryClient": "PublicCertificateAuthorityServiceGapicClient",
+                    "rpcs": {
+                        "CreateExternalAccountKey": {
+                            "methods": [
+                                "createExternalAccountKey"
+                            ]
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/SecurityPublicCA/src/V1/resources/public_certificate_authority_service_client_config.json b/SecurityPublicCA/src/V1/resources/public_certificate_authority_service_client_config.json
new file mode 100644
index 000000000000..a3415ccf86b0
--- /dev/null
+++ b/SecurityPublicCA/src/V1/resources/public_certificate_authority_service_client_config.json
@@ -0,0 +1,39 @@
+{
+    "interfaces": {
+        "google.cloud.security.publicca.v1.PublicCertificateAuthorityService": {
+            "retry_codes": {
+                "no_retry_codes": [],
+                "retry_policy_1_codes": [
+                    "UNAVAILABLE"
+                ]
+            },
+            "retry_params": {
+                "no_retry_params": {
+                    "initial_retry_delay_millis": 0,
+                    "retry_delay_multiplier": 0.0,
+                    "max_retry_delay_millis": 0,
+                    "initial_rpc_timeout_millis": 0,
+                    "rpc_timeout_multiplier": 1.0,
+                    "max_rpc_timeout_millis": 0,
+                    "total_timeout_millis": 0
+                },
+                "retry_policy_1_params": {
+                    "initial_retry_delay_millis": 100,
+                    "retry_delay_multiplier": 1.3,
+                    "max_retry_delay_millis": 60000,
+                    "initial_rpc_timeout_millis": 60000,
+                    "rpc_timeout_multiplier": 1.0,
+                    "max_rpc_timeout_millis": 60000,
+                    "total_timeout_millis": 60000
+                }
+            },
+            "methods": {
+                "CreateExternalAccountKey": {
+                    "timeout_millis": 60000,
+                    "retry_codes_name": "retry_policy_1_codes",
+                    "retry_params_name": "retry_policy_1_params"
+                }
+            }
+        }
+    }
+}
diff --git a/SecurityPublicCA/src/V1/resources/public_certificate_authority_service_descriptor_config.php b/SecurityPublicCA/src/V1/resources/public_certificate_authority_service_descriptor_config.php
new file mode 100644
index 000000000000..c586b2567746
--- /dev/null
+++ b/SecurityPublicCA/src/V1/resources/public_certificate_authority_service_descriptor_config.php
@@ -0,0 +1,44 @@
+<?php
+/*
+ * Copyright 2024 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * GENERATED CODE WARNING
+ * This file was automatically generated - do not edit!
+ */
+
+return [
+    'interfaces' => [
+        'google.cloud.security.publicca.v1.PublicCertificateAuthorityService' => [
+            'CreateExternalAccountKey' => [
+                'callType' => \Google\ApiCore\Call::UNARY_CALL,
+                'responseType' => 'Google\Cloud\Security\PublicCA\V1\ExternalAccountKey',
+                'headerParams' => [
+                    [
+                        'keyName' => 'parent',
+                        'fieldAccessors' => [
+                            'getParent',
+                        ],
+                    ],
+                ],
+            ],
+            'templateMap' => [
+                'externalAccountKey' => 'projects/{project}/locations/{location}/externalAccountKeys/{external_account_key}',
+                'location' => 'projects/{project}/locations/{location}',
+            ],
+        ],
+    ],
+];
diff --git a/SecurityPublicCA/src/V1/resources/public_certificate_authority_service_rest_client_config.php b/SecurityPublicCA/src/V1/resources/public_certificate_authority_service_rest_client_config.php
new file mode 100644
index 000000000000..c19a32d3f493
--- /dev/null
+++ b/SecurityPublicCA/src/V1/resources/public_certificate_authority_service_rest_client_config.php
@@ -0,0 +1,41 @@
+<?php
+/*
+ * Copyright 2024 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * GENERATED CODE WARNING
+ * This file was automatically generated - do not edit!
+ */
+
+return [
+    'interfaces' => [
+        'google.cloud.security.publicca.v1.PublicCertificateAuthorityService' => [
+            'CreateExternalAccountKey' => [
+                'method' => 'post',
+                'uriTemplate' => '/v1/{parent=projects/*/locations/*}/externalAccountKeys',
+                'body' => 'external_account_key',
+                'placeholders' => [
+                    'parent' => [
+                        'getters' => [
+                            'getParent',
+                        ],
+                    ],
+                ],
+            ],
+        ],
+    ],
+    'numericEnums' => true,
+];
diff --git a/SecurityPublicCA/tests/Unit/V1/Client/PublicCertificateAuthorityServiceClientTest.php b/SecurityPublicCA/tests/Unit/V1/Client/PublicCertificateAuthorityServiceClientTest.php
new file mode 100644
index 000000000000..c09338662bf4
--- /dev/null
+++ b/SecurityPublicCA/tests/Unit/V1/Client/PublicCertificateAuthorityServiceClientTest.php
@@ -0,0 +1,173 @@
+<?php
+/*
+ * Copyright 2024 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * GENERATED CODE WARNING
+ * This file was automatically generated - do not edit!
+ */
+
+namespace Google\Cloud\Security\PublicCA\Tests\Unit\V1\Client;
+
+use Google\ApiCore\ApiException;
+use Google\ApiCore\CredentialsWrapper;
+use Google\ApiCore\Testing\GeneratedTest;
+use Google\ApiCore\Testing\MockTransport;
+use Google\Cloud\Security\PublicCA\V1\Client\PublicCertificateAuthorityServiceClient;
+use Google\Cloud\Security\PublicCA\V1\CreateExternalAccountKeyRequest;
+use Google\Cloud\Security\PublicCA\V1\ExternalAccountKey;
+use Google\Rpc\Code;
+use stdClass;
+
+/**
+ * @group publicca
+ *
+ * @group gapic
+ */
+class PublicCertificateAuthorityServiceClientTest extends GeneratedTest
+{
+    /** @return TransportInterface */
+    private function createTransport($deserialize = null)
+    {
+        return new MockTransport($deserialize);
+    }
+
+    /** @return CredentialsWrapper */
+    private function createCredentials()
+    {
+        return $this->getMockBuilder(CredentialsWrapper::class)->disableOriginalConstructor()->getMock();
+    }
+
+    /** @return PublicCertificateAuthorityServiceClient */
+    private function createClient(array $options = [])
+    {
+        $options += [
+            'credentials' => $this->createCredentials(),
+        ];
+        return new PublicCertificateAuthorityServiceClient($options);
+    }
+
+    /** @test */
+    public function createExternalAccountKeyTest()
+    {
+        $transport = $this->createTransport();
+        $gapicClient = $this->createClient([
+            'transport' => $transport,
+        ]);
+        $this->assertTrue($transport->isExhausted());
+        // Mock response
+        $name = 'name3373707';
+        $keyId = 'keyId-1134673157';
+        $b64MacKey = '-48';
+        $expectedResponse = new ExternalAccountKey();
+        $expectedResponse->setName($name);
+        $expectedResponse->setKeyId($keyId);
+        $expectedResponse->setB64MacKey($b64MacKey);
+        $transport->addResponse($expectedResponse);
+        // Mock request
+        $formattedParent = $gapicClient->locationName('[PROJECT]', '[LOCATION]');
+        $externalAccountKey = new ExternalAccountKey();
+        $request = (new CreateExternalAccountKeyRequest())
+            ->setParent($formattedParent)
+            ->setExternalAccountKey($externalAccountKey);
+        $response = $gapicClient->createExternalAccountKey($request);
+        $this->assertEquals($expectedResponse, $response);
+        $actualRequests = $transport->popReceivedCalls();
+        $this->assertSame(1, count($actualRequests));
+        $actualFuncCall = $actualRequests[0]->getFuncCall();
+        $actualRequestObject = $actualRequests[0]->getRequestObject();
+        $this->assertSame('/google.cloud.security.publicca.v1.PublicCertificateAuthorityService/CreateExternalAccountKey', $actualFuncCall);
+        $actualValue = $actualRequestObject->getParent();
+        $this->assertProtobufEquals($formattedParent, $actualValue);
+        $actualValue = $actualRequestObject->getExternalAccountKey();
+        $this->assertProtobufEquals($externalAccountKey, $actualValue);
+        $this->assertTrue($transport->isExhausted());
+    }
+
+    /** @test */
+    public function createExternalAccountKeyExceptionTest()
+    {
+        $transport = $this->createTransport();
+        $gapicClient = $this->createClient([
+            'transport' => $transport,
+        ]);
+        $this->assertTrue($transport->isExhausted());
+        $status = new stdClass();
+        $status->code = Code::DATA_LOSS;
+        $status->details = 'internal error';
+        $expectedExceptionMessage  = json_encode([
+            'message' => 'internal error',
+            'code' => Code::DATA_LOSS,
+            'status' => 'DATA_LOSS',
+            'details' => [],
+        ], JSON_PRETTY_PRINT);
+        $transport->addResponse(null, $status);
+        // Mock request
+        $formattedParent = $gapicClient->locationName('[PROJECT]', '[LOCATION]');
+        $externalAccountKey = new ExternalAccountKey();
+        $request = (new CreateExternalAccountKeyRequest())
+            ->setParent($formattedParent)
+            ->setExternalAccountKey($externalAccountKey);
+        try {
+            $gapicClient->createExternalAccountKey($request);
+            // If the $gapicClient method call did not throw, fail the test
+            $this->fail('Expected an ApiException, but no exception was thrown.');
+        } catch (ApiException $ex) {
+            $this->assertEquals($status->code, $ex->getCode());
+            $this->assertEquals($expectedExceptionMessage, $ex->getMessage());
+        }
+        // Call popReceivedCalls to ensure the stub is exhausted
+        $transport->popReceivedCalls();
+        $this->assertTrue($transport->isExhausted());
+    }
+
+    /** @test */
+    public function createExternalAccountKeyAsyncTest()
+    {
+        $transport = $this->createTransport();
+        $gapicClient = $this->createClient([
+            'transport' => $transport,
+        ]);
+        $this->assertTrue($transport->isExhausted());
+        // Mock response
+        $name = 'name3373707';
+        $keyId = 'keyId-1134673157';
+        $b64MacKey = '-48';
+        $expectedResponse = new ExternalAccountKey();
+        $expectedResponse->setName($name);
+        $expectedResponse->setKeyId($keyId);
+        $expectedResponse->setB64MacKey($b64MacKey);
+        $transport->addResponse($expectedResponse);
+        // Mock request
+        $formattedParent = $gapicClient->locationName('[PROJECT]', '[LOCATION]');
+        $externalAccountKey = new ExternalAccountKey();
+        $request = (new CreateExternalAccountKeyRequest())
+            ->setParent($formattedParent)
+            ->setExternalAccountKey($externalAccountKey);
+        $response = $gapicClient->createExternalAccountKeyAsync($request)->wait();
+        $this->assertEquals($expectedResponse, $response);
+        $actualRequests = $transport->popReceivedCalls();
+        $this->assertSame(1, count($actualRequests));
+        $actualFuncCall = $actualRequests[0]->getFuncCall();
+        $actualRequestObject = $actualRequests[0]->getRequestObject();
+        $this->assertSame('/google.cloud.security.publicca.v1.PublicCertificateAuthorityService/CreateExternalAccountKey', $actualFuncCall);
+        $actualValue = $actualRequestObject->getParent();
+        $this->assertProtobufEquals($formattedParent, $actualValue);
+        $actualValue = $actualRequestObject->getExternalAccountKey();
+        $this->assertProtobufEquals($externalAccountKey, $actualValue);
+        $this->assertTrue($transport->isExhausted());
+    }
+}