From 26f975a47eebe66e6c657f5589373cd4b61ded85 Mon Sep 17 00:00:00 2001 From: Yoshi Automation Bot Date: Mon, 1 Mar 2021 16:37:54 -0800 Subject: [PATCH] feat: added topic field to Secret (#207) PiperOrigin-RevId: 359285402 Source-Author: Google APIs Source-Date: Wed Feb 24 07:59:50 2021 -0800 Source-Repo: googleapis/googleapis Source-Sha: 8b3d36daaf5561496b7d4075fba4f2c52d18ca1c Source-Link: https://github.com/googleapis/googleapis/commit/8b3d36daaf5561496b7d4075fba4f2c52d18ca1c --- .../cloud/secretmanager/v1/resources.proto | 20 +- .../cloud/secretmanager/v1/service.proto | 2 +- protos/protos.d.ts | 96 ++++++++ protos/protos.js | 231 ++++++++++++++++++ protos/protos.json | 23 ++ src/v1/secret_manager_service_client.ts | 39 +++ synth.metadata | 6 +- test/gapic_secret_manager_service_v1.ts | 51 ++++ 8 files changed, 463 insertions(+), 5 deletions(-) diff --git a/protos/google/cloud/secretmanager/v1/resources.proto b/protos/google/cloud/secretmanager/v1/resources.proto index 7532b08..235444d 100644 --- a/protos/google/cloud/secretmanager/v1/resources.proto +++ b/protos/google/cloud/secretmanager/v1/resources.proto @@ -1,4 +1,4 @@ -// Copyright 2020 Google LLC +// Copyright 2021 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -70,6 +70,10 @@ message Secret { // No more than 64 labels can be assigned to a given resource. map labels = 4; + // Optional. A list of up to 10 Pub/Sub topics to which messages are published when + // control plane operations are called on the secret or its versions. + repeated Topic topics = 5 [(google.api.field_behavior) = OPTIONAL]; + // Expiration policy attached to the [Secret][google.cloud.secretmanager.v1.Secret]. If specified the [Secret][google.cloud.secretmanager.v1.Secret] // and all [SecretVersions][google.cloud.secretmanager.v1.SecretVersion] will be automatically deleted at // expiration. Expired secrets are irreversibly deleted. @@ -260,6 +264,20 @@ message CustomerManagedEncryptionStatus { string kms_key_version_name = 1 [(google.api.field_behavior) = REQUIRED]; } +// A Pub/Sub topic which Secret Manager will publish to when control plane +// events occur on this secret. +message Topic { + option (google.api.resource) = { + type: "pubsub.googleapis.com/Topic" + pattern: "projects/{project}/topics/{topic}" + }; + + // Required. The resource name of the Pub/Sub topic that will be published to, in the + // following format: `projects/*/topics/*`. For publication to succeed, the + // Secret Manager P4SA must have `pubsub.publisher` permissions on the topic. + string name = 1 [(google.api.field_behavior) = REQUIRED]; +} + // A secret payload resource in the Secret Manager API. This contains the // sensitive secret payload that is associated with a [SecretVersion][google.cloud.secretmanager.v1.SecretVersion]. message SecretPayload { diff --git a/protos/google/cloud/secretmanager/v1/service.proto b/protos/google/cloud/secretmanager/v1/service.proto index e54e856..1e9d3e0 100644 --- a/protos/google/cloud/secretmanager/v1/service.proto +++ b/protos/google/cloud/secretmanager/v1/service.proto @@ -1,4 +1,4 @@ -// Copyright 2020 Google LLC +// Copyright 2021 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/protos/protos.d.ts b/protos/protos.d.ts index 5366061..71a67e0 100644 --- a/protos/protos.d.ts +++ b/protos/protos.d.ts @@ -41,6 +41,9 @@ export namespace google { /** Secret labels */ labels?: ({ [k: string]: string }|null); + /** Secret topics */ + topics?: (google.cloud.secretmanager.v1.ITopic[]|null); + /** Secret expireTime */ expireTime?: (google.protobuf.ITimestamp|null); @@ -69,6 +72,9 @@ export namespace google { /** Secret labels. */ public labels: { [k: string]: string }; + /** Secret topics. */ + public topics: google.cloud.secretmanager.v1.ITopic[]; + /** Secret expireTime. */ public expireTime?: (google.protobuf.ITimestamp|null); @@ -1216,6 +1222,96 @@ export namespace google { public toJSON(): { [k: string]: any }; } + /** Properties of a Topic. */ + interface ITopic { + + /** Topic name */ + name?: (string|null); + } + + /** Represents a Topic. */ + class Topic implements ITopic { + + /** + * Constructs a new Topic. + * @param [properties] Properties to set + */ + constructor(properties?: google.cloud.secretmanager.v1.ITopic); + + /** Topic name. */ + public name: string; + + /** + * Creates a new Topic instance using the specified properties. + * @param [properties] Properties to set + * @returns Topic instance + */ + public static create(properties?: google.cloud.secretmanager.v1.ITopic): google.cloud.secretmanager.v1.Topic; + + /** + * Encodes the specified Topic message. Does not implicitly {@link google.cloud.secretmanager.v1.Topic.verify|verify} messages. + * @param message Topic message or plain object to encode + * @param [writer] Writer to encode to + * @returns Writer + */ + public static encode(message: google.cloud.secretmanager.v1.ITopic, writer?: $protobuf.Writer): $protobuf.Writer; + + /** + * Encodes the specified Topic message, length delimited. Does not implicitly {@link google.cloud.secretmanager.v1.Topic.verify|verify} messages. + * @param message Topic message or plain object to encode + * @param [writer] Writer to encode to + * @returns Writer + */ + public static encodeDelimited(message: google.cloud.secretmanager.v1.ITopic, writer?: $protobuf.Writer): $protobuf.Writer; + + /** + * Decodes a Topic message from the specified reader or buffer. + * @param reader Reader or buffer to decode from + * @param [length] Message length if known beforehand + * @returns Topic + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): google.cloud.secretmanager.v1.Topic; + + /** + * Decodes a Topic message from the specified reader or buffer, length delimited. + * @param reader Reader or buffer to decode from + * @returns Topic + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): google.cloud.secretmanager.v1.Topic; + + /** + * Verifies a Topic message. + * @param message Plain object to verify + * @returns `null` if valid, otherwise the reason why it is not + */ + public static verify(message: { [k: string]: any }): (string|null); + + /** + * Creates a Topic message from a plain object. Also converts values to their respective internal types. + * @param object Plain object + * @returns Topic + */ + public static fromObject(object: { [k: string]: any }): google.cloud.secretmanager.v1.Topic; + + /** + * Creates a plain object from a Topic message. Also converts values to other types if specified. + * @param message Topic + * @param [options] Conversion options + * @returns Plain object + */ + public static toObject(message: google.cloud.secretmanager.v1.Topic, options?: $protobuf.IConversionOptions): { [k: string]: any }; + + /** + * Converts this Topic to JSON. + * @returns JSON object + */ + public toJSON(): { [k: string]: any }; + } + /** Properties of a SecretPayload. */ interface ISecretPayload { diff --git a/protos/protos.js b/protos/protos.js index 36d7510..463e603 100644 --- a/protos/protos.js +++ b/protos/protos.js @@ -76,6 +76,7 @@ * @property {google.cloud.secretmanager.v1.IReplication|null} [replication] Secret replication * @property {google.protobuf.ITimestamp|null} [createTime] Secret createTime * @property {Object.|null} [labels] Secret labels + * @property {Array.|null} [topics] Secret topics * @property {google.protobuf.ITimestamp|null} [expireTime] Secret expireTime * @property {google.protobuf.IDuration|null} [ttl] Secret ttl */ @@ -90,6 +91,7 @@ */ function Secret(properties) { this.labels = {}; + this.topics = []; if (properties) for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) if (properties[keys[i]] != null) @@ -128,6 +130,14 @@ */ Secret.prototype.labels = $util.emptyObject; + /** + * Secret topics. + * @member {Array.} topics + * @memberof google.cloud.secretmanager.v1.Secret + * @instance + */ + Secret.prototype.topics = $util.emptyArray; + /** * Secret expireTime. * @member {google.protobuf.ITimestamp|null|undefined} expireTime @@ -191,6 +201,9 @@ if (message.labels != null && Object.hasOwnProperty.call(message, "labels")) for (var keys = Object.keys(message.labels), i = 0; i < keys.length; ++i) writer.uint32(/* id 4, wireType 2 =*/34).fork().uint32(/* id 1, wireType 2 =*/10).string(keys[i]).uint32(/* id 2, wireType 2 =*/18).string(message.labels[keys[i]]).ldelim(); + if (message.topics != null && message.topics.length) + for (var i = 0; i < message.topics.length; ++i) + $root.google.cloud.secretmanager.v1.Topic.encode(message.topics[i], writer.uint32(/* id 5, wireType 2 =*/42).fork()).ldelim(); if (message.expireTime != null && Object.hasOwnProperty.call(message, "expireTime")) $root.google.protobuf.Timestamp.encode(message.expireTime, writer.uint32(/* id 6, wireType 2 =*/50).fork()).ldelim(); if (message.ttl != null && Object.hasOwnProperty.call(message, "ttl")) @@ -260,6 +273,11 @@ } message.labels[key] = value; break; + case 5: + if (!(message.topics && message.topics.length)) + message.topics = []; + message.topics.push($root.google.cloud.secretmanager.v1.Topic.decode(reader, reader.uint32())); + break; case 6: message.expireTime = $root.google.protobuf.Timestamp.decode(reader, reader.uint32()); break; @@ -323,6 +341,15 @@ if (!$util.isString(message.labels[key[i]])) return "labels: string{k:string} expected"; } + if (message.topics != null && message.hasOwnProperty("topics")) { + if (!Array.isArray(message.topics)) + return "topics: array expected"; + for (var i = 0; i < message.topics.length; ++i) { + var error = $root.google.cloud.secretmanager.v1.Topic.verify(message.topics[i]); + if (error) + return "topics." + error; + } + } if (message.expireTime != null && message.hasOwnProperty("expireTime")) { properties.expiration = 1; { @@ -375,6 +402,16 @@ for (var keys = Object.keys(object.labels), i = 0; i < keys.length; ++i) message.labels[keys[i]] = String(object.labels[keys[i]]); } + if (object.topics) { + if (!Array.isArray(object.topics)) + throw TypeError(".google.cloud.secretmanager.v1.Secret.topics: array expected"); + message.topics = []; + for (var i = 0; i < object.topics.length; ++i) { + if (typeof object.topics[i] !== "object") + throw TypeError(".google.cloud.secretmanager.v1.Secret.topics: object expected"); + message.topics[i] = $root.google.cloud.secretmanager.v1.Topic.fromObject(object.topics[i]); + } + } if (object.expireTime != null) { if (typeof object.expireTime !== "object") throw TypeError(".google.cloud.secretmanager.v1.Secret.expireTime: object expected"); @@ -401,6 +438,8 @@ if (!options) options = {}; var object = {}; + if (options.arrays || options.defaults) + object.topics = []; if (options.objects || options.defaults) object.labels = {}; if (options.defaults) { @@ -420,6 +459,11 @@ for (var j = 0; j < keys2.length; ++j) object.labels[keys2[j]] = message.labels[keys2[j]]; } + if (message.topics && message.topics.length) { + object.topics = []; + for (var j = 0; j < message.topics.length; ++j) + object.topics[j] = $root.google.cloud.secretmanager.v1.Topic.toObject(message.topics[j], options); + } if (message.expireTime != null && message.hasOwnProperty("expireTime")) { object.expireTime = $root.google.protobuf.Timestamp.toObject(message.expireTime, options); if (options.oneofs) @@ -2873,6 +2917,193 @@ return CustomerManagedEncryptionStatus; })(); + v1.Topic = (function() { + + /** + * Properties of a Topic. + * @memberof google.cloud.secretmanager.v1 + * @interface ITopic + * @property {string|null} [name] Topic name + */ + + /** + * Constructs a new Topic. + * @memberof google.cloud.secretmanager.v1 + * @classdesc Represents a Topic. + * @implements ITopic + * @constructor + * @param {google.cloud.secretmanager.v1.ITopic=} [properties] Properties to set + */ + function Topic(properties) { + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * Topic name. + * @member {string} name + * @memberof google.cloud.secretmanager.v1.Topic + * @instance + */ + Topic.prototype.name = ""; + + /** + * Creates a new Topic instance using the specified properties. + * @function create + * @memberof google.cloud.secretmanager.v1.Topic + * @static + * @param {google.cloud.secretmanager.v1.ITopic=} [properties] Properties to set + * @returns {google.cloud.secretmanager.v1.Topic} Topic instance + */ + Topic.create = function create(properties) { + return new Topic(properties); + }; + + /** + * Encodes the specified Topic message. Does not implicitly {@link google.cloud.secretmanager.v1.Topic.verify|verify} messages. + * @function encode + * @memberof google.cloud.secretmanager.v1.Topic + * @static + * @param {google.cloud.secretmanager.v1.ITopic} message Topic message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + Topic.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.name != null && Object.hasOwnProperty.call(message, "name")) + writer.uint32(/* id 1, wireType 2 =*/10).string(message.name); + return writer; + }; + + /** + * Encodes the specified Topic message, length delimited. Does not implicitly {@link google.cloud.secretmanager.v1.Topic.verify|verify} messages. + * @function encodeDelimited + * @memberof google.cloud.secretmanager.v1.Topic + * @static + * @param {google.cloud.secretmanager.v1.ITopic} message Topic message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + Topic.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a Topic message from the specified reader or buffer. + * @function decode + * @memberof google.cloud.secretmanager.v1.Topic + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {google.cloud.secretmanager.v1.Topic} Topic + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + Topic.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.google.cloud.secretmanager.v1.Topic(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + message.name = reader.string(); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a Topic message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof google.cloud.secretmanager.v1.Topic + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {google.cloud.secretmanager.v1.Topic} Topic + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + Topic.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a Topic message. + * @function verify + * @memberof google.cloud.secretmanager.v1.Topic + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + Topic.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + if (message.name != null && message.hasOwnProperty("name")) + if (!$util.isString(message.name)) + return "name: string expected"; + return null; + }; + + /** + * Creates a Topic message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof google.cloud.secretmanager.v1.Topic + * @static + * @param {Object.} object Plain object + * @returns {google.cloud.secretmanager.v1.Topic} Topic + */ + Topic.fromObject = function fromObject(object) { + if (object instanceof $root.google.cloud.secretmanager.v1.Topic) + return object; + var message = new $root.google.cloud.secretmanager.v1.Topic(); + if (object.name != null) + message.name = String(object.name); + return message; + }; + + /** + * Creates a plain object from a Topic message. Also converts values to other types if specified. + * @function toObject + * @memberof google.cloud.secretmanager.v1.Topic + * @static + * @param {google.cloud.secretmanager.v1.Topic} message Topic + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + Topic.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (options.defaults) + object.name = ""; + if (message.name != null && message.hasOwnProperty("name")) + object.name = message.name; + return object; + }; + + /** + * Converts this Topic to JSON. + * @function toJSON + * @memberof google.cloud.secretmanager.v1.Topic + * @instance + * @returns {Object.} JSON object + */ + Topic.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + return Topic; + })(); + v1.SecretPayload = (function() { /** diff --git a/protos/protos.json b/protos/protos.json index 1543b25..75692b3 100644 --- a/protos/protos.json +++ b/protos/protos.json @@ -59,6 +59,14 @@ "type": "string", "id": 4 }, + "topics": { + "rule": "repeated", + "type": "Topic", + "id": 5, + "options": { + "(google.api.field_behavior)": "OPTIONAL" + } + }, "expireTime": { "type": "google.protobuf.Timestamp", "id": 6, @@ -274,6 +282,21 @@ } } }, + "Topic": { + "options": { + "(google.api.resource).type": "pubsub.googleapis.com/Topic", + "(google.api.resource).pattern": "projects/{project}/topics/{topic}" + }, + "fields": { + "name": { + "type": "string", + "id": 1, + "options": { + "(google.api.field_behavior)": "REQUIRED" + } + } + } + }, "SecretPayload": { "fields": { "data": { diff --git a/src/v1/secret_manager_service_client.ts b/src/v1/secret_manager_service_client.ts index 64316bf..44f1214 100644 --- a/src/v1/secret_manager_service_client.ts +++ b/src/v1/secret_manager_service_client.ts @@ -181,6 +181,9 @@ export class SecretManagerServiceClient { secretVersionPathTemplate: new this._gaxModule.PathTemplate( 'projects/{project}/secrets/{secret}/versions/{secret_version}' ), + topicPathTemplate: new this._gaxModule.PathTemplate( + 'projects/{project}/topics/{topic}' + ), }; // Some of the methods on this service return "paged" results, @@ -2130,6 +2133,42 @@ export class SecretManagerServiceClient { .secret_version; } + /** + * Return a fully-qualified topic resource name string. + * + * @param {string} project + * @param {string} topic + * @returns {string} Resource name string. + */ + topicPath(project: string, topic: string) { + return this.pathTemplates.topicPathTemplate.render({ + project: project, + topic: topic, + }); + } + + /** + * Parse the project from Topic resource. + * + * @param {string} topicName + * A fully-qualified path representing Topic resource. + * @returns {string} A string representing the project. + */ + matchProjectFromTopicName(topicName: string) { + return this.pathTemplates.topicPathTemplate.match(topicName).project; + } + + /** + * Parse the topic from Topic resource. + * + * @param {string} topicName + * A fully-qualified path representing Topic resource. + * @returns {string} A string representing the topic. + */ + matchTopicFromTopicName(topicName: string) { + return this.pathTemplates.topicPathTemplate.match(topicName).topic; + } + /** * Terminate the gRPC channel and close the client. * diff --git a/synth.metadata b/synth.metadata index 2b45996..1753a4f 100644 --- a/synth.metadata +++ b/synth.metadata @@ -4,15 +4,15 @@ "git": { "name": ".", "remote": "https://github.com/googleapis/nodejs-secret-manager.git", - "sha": "c3874cab53230dc6038647d751aba67dce8a01f3" + "sha": "7808101eaab60421361cf1efde447e480df51b2f" } }, { "git": { "name": "googleapis", "remote": "https://github.com/googleapis/googleapis.git", - "sha": "9ecdacc9a00e1dd443b11bf10215d6e7648db8a7", - "internalRef": "352563582" + "sha": "8b3d36daaf5561496b7d4075fba4f2c52d18ca1c", + "internalRef": "359285402" } }, { diff --git a/test/gapic_secret_manager_service_v1.ts b/test/gapic_secret_manager_service_v1.ts index 3324b51..922386d 100644 --- a/test/gapic_secret_manager_service_v1.ts +++ b/test/gapic_secret_manager_service_v1.ts @@ -2565,5 +2565,56 @@ describe('v1.SecretManagerServiceClient', () => { ); }); }); + + describe('topic', () => { + const fakePath = '/rendered/path/topic'; + const expectedParameters = { + project: 'projectValue', + topic: 'topicValue', + }; + const client = new secretmanagerserviceModule.v1.SecretManagerServiceClient( + { + credentials: {client_email: 'bogus', private_key: 'bogus'}, + projectId: 'bogus', + } + ); + client.initialize(); + client.pathTemplates.topicPathTemplate.render = sinon + .stub() + .returns(fakePath); + client.pathTemplates.topicPathTemplate.match = sinon + .stub() + .returns(expectedParameters); + + it('topicPath', () => { + const result = client.topicPath('projectValue', 'topicValue'); + assert.strictEqual(result, fakePath); + assert( + (client.pathTemplates.topicPathTemplate.render as SinonStub) + .getCall(-1) + .calledWith(expectedParameters) + ); + }); + + it('matchProjectFromTopicName', () => { + const result = client.matchProjectFromTopicName(fakePath); + assert.strictEqual(result, 'projectValue'); + assert( + (client.pathTemplates.topicPathTemplate.match as SinonStub) + .getCall(-1) + .calledWith(fakePath) + ); + }); + + it('matchTopicFromTopicName', () => { + const result = client.matchTopicFromTopicName(fakePath); + assert.strictEqual(result, 'topicValue'); + assert( + (client.pathTemplates.topicPathTemplate.match as SinonStub) + .getCall(-1) + .calledWith(fakePath) + ); + }); + }); }); });