Skip to content

Commit a62b2a7

Browse files
authored
Merge pull request #518 from hookdeck/chore/openapi-add-gcppubsub
feat: add GCP Pub/Sub destination support with configuration and credentials schemas
2 parents 69b2f2e + 1c733bc commit a62b2a7

File tree

110 files changed

+8375
-154
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

110 files changed

+8375
-154
lines changed

.plans/spec-sdk-tests/01-ci-cd-integration.md

Lines changed: 512 additions & 0 deletions
Large diffs are not rendered by default.

.plans/spec-sdk-tests/02-coverage-reporting.md

Lines changed: 732 additions & 0 deletions
Large diffs are not rendered by default.

.plans/spec-sdk-tests/03-contributing-docs.md

Lines changed: 408 additions & 0 deletions
Large diffs are not rendered by default.

.plans/spec-sdk-tests/04-implementation-order.md

Lines changed: 475 additions & 0 deletions
Large diffs are not rendered by default.

.plans/spec-sdk-tests/README.md

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
# OpenAPI Validation Test Suite - Implementation Plans
2+
3+
This directory contains detailed planning documents for the next phases of the OpenAPI validation test suite project.
4+
5+
## Current State (Completed)
6+
7+
-**Test Suite**: 147 comprehensive tests across 8 destination types
8+
-**Test Results**: 129 passing tests (87.8% pass rate)
9+
-**Coverage**: All destination types tested (Webhook, AWS SQS, RabbitMQ, Azure Service Bus, AWS S3, Hookdeck, AWS Kinesis, GCP Pub/Sub)
10+
-**Documentation**: `TEST_STATUS.md` with detailed results and analysis
11+
-**Issue Tracking**: 3 GitHub issues created for backend improvements
12+
-**Test Infrastructure**: Factory pattern, SDK client utilities, comprehensive test suite
13+
14+
## Next Phases
15+
16+
This plan directory outlines the roadmap for enhancing the test suite with production-ready features:
17+
18+
### 1. [CI/CD Integration](./01-ci-cd-integration.md)
19+
Automate test execution in GitHub Actions to ensure continuous validation of API endpoints against the OpenAPI specification.
20+
21+
**Key Outcomes:**
22+
- Automated test runs on PRs and commits
23+
- Docker-based test environment
24+
- Test status badges
25+
- Failure notifications
26+
27+
### 2. [Coverage Reporting](./02-coverage-reporting.md)
28+
Track and visualize which OpenAPI endpoints are tested, identify gaps, and enforce coverage thresholds.
29+
30+
**Key Outcomes:**
31+
- Automated coverage reports
32+
- Visual coverage dashboards
33+
- Coverage trend tracking
34+
- Minimum coverage enforcement
35+
36+
### 3. [Contributing Documentation](./03-contributing-docs.md)
37+
Provide clear guidelines for developers to add new tests and understand the testing architecture.
38+
39+
**Key Outcomes:**
40+
- Updated CONTRIBUTING.md
41+
- Test development guide
42+
- Factory pattern documentation
43+
- Development workflow examples
44+
45+
### 4. [Implementation Order](./04-implementation-order.md)
46+
Recommended sequence for implementing the above phases with effort estimates and success criteria.
47+
48+
**Key Outcomes:**
49+
- Prioritized roadmap
50+
- Dependency mapping
51+
- Effort estimates
52+
- Success metrics
53+
54+
## Plan Structure
55+
56+
Each planning document follows this structure:
57+
58+
1. **Overview** - Purpose and goals
59+
2. **Requirements** - Specific needs and constraints
60+
3. **Technical Approach** - Implementation details
61+
4. **Examples** - Code snippets and configurations
62+
5. **Acceptance Criteria** - Definition of done
63+
6. **Dependencies** - Related systems and prerequisites
64+
7. **Risks & Considerations** - Potential challenges
65+
66+
## How to Use These Plans
67+
68+
1. **Review** - Read through each plan to understand the scope
69+
2. **Prioritize** - Use `04-implementation-order.md` to sequence work
70+
3. **Implement** - Follow the technical approaches and examples
71+
4. **Validate** - Check against acceptance criteria
72+
5. **Iterate** - Update plans based on learnings
73+
74+
## Related Documentation
75+
76+
- [`/spec-sdk-tests/README.md`](../../spec-sdk-tests/README.md) - Test suite documentation
77+
- [`/spec-sdk-tests/TEST_STATUS.md`](../../spec-sdk-tests/TEST_STATUS.md) - Current test results
78+
- [`/docs/apis/openapi.yaml`](../../docs/apis/openapi.yaml) - OpenAPI specification
79+
- [`/CONTRIBUTING.md`](../../CONTRIBUTING.md) - General contribution guidelines
80+
81+
## Feedback and Updates
82+
83+
These plans are living documents. As implementation progresses:
84+
85+
- Update plans with new learnings
86+
- Add implementation notes
87+
- Document deviations from original plan
88+
- Capture best practices discovered
89+
90+
---
91+
92+
**Last Updated**: 2025-10-12
93+
**Status**: Ready for implementation
94+
**Owner**: Engineering Team

.speakeasy/workflow.lock

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
1-
speakeasyVersion: 1.609.0
1+
speakeasyVersion: 1.636.3
22
sources:
33
Outpost API:
44
sourceNamespace: outpost-api
5-
sourceRevisionDigest: sha256:e09cf02de047cf6d007545274c477e2a90c561074b9de170d844d9ab9ffbbca6
6-
sourceBlobDigest: sha256:c405cfc4f2de092323a9dd68a09f7c08b563d363bce7463fc8b426d10acacf99
5+
sourceRevisionDigest: sha256:abcb227d706ddbbb55ab9a423da413260c4d83c247616a9f6067890ff4bfa997
6+
sourceBlobDigest: sha256:b8f43e14862cadf618bc568c76cec68ed15da6c4c7fec0541edd4671a3b26815
77
tags:
88
- latest
9-
- speakeasy-sdk-regen-1756922597
109
- 0.0.1
1110
targets:
1211
outpost-go:
@@ -26,10 +25,10 @@ targets:
2625
outpost-ts:
2726
source: Outpost API
2827
sourceNamespace: outpost-api
29-
sourceRevisionDigest: sha256:e09cf02de047cf6d007545274c477e2a90c561074b9de170d844d9ab9ffbbca6
30-
sourceBlobDigest: sha256:c405cfc4f2de092323a9dd68a09f7c08b563d363bce7463fc8b426d10acacf99
28+
sourceRevisionDigest: sha256:abcb227d706ddbbb55ab9a423da413260c4d83c247616a9f6067890ff4bfa997
29+
sourceBlobDigest: sha256:b8f43e14862cadf618bc568c76cec68ed15da6c4c7fec0541edd4671a3b26815
3130
codeSamplesNamespace: outpost-api-typescript-code-samples
32-
codeSamplesRevisionDigest: sha256:b1155400f3addb67547999bf99f4eb4f009470ab62329d57488f78843ff6f9b6
31+
codeSamplesRevisionDigest: sha256:58c8e1b33a4de342b37a90c0c490a21c795e4b5c6c4f2ceef9f8c45b817a56f3
3332
workflow:
3433
workflowVersion: 1.0.0
3534
speakeasyVersion: latest

docs/apis/openapi.yaml

Lines changed: 150 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -263,7 +263,7 @@ components:
263263
key_template:
264264
type: string
265265
description: JMESPath expression for generating S3 object keys. Default is join('', [time.rfc3339_nano, '_', metadata."event-id", '.json']).
266-
example: "join('/', [time.year, time.month, time.day, metadata.`\"event-id\"`, '.json'])"
266+
example: 'join(''/'', [time.year, time.month, time.day, metadata."event-id", ''.json''])'
267267
storage_class:
268268
type: string
269269
description: The storage class for the S3 objects (e.g., STANDARD, INTELLIGENT_TIERING, GLACIER, etc.). Defaults to "STANDARD".
@@ -284,6 +284,30 @@ components:
284284
type: string
285285
description: Optional AWS Session Token (for temporary credentials).
286286
example: "AQoDYXdzEPT//////////wEXAMPLE..."
287+
GCPPubSubConfig:
288+
type: object
289+
required: [project_id, topic]
290+
properties:
291+
project_id:
292+
type: string
293+
description: The GCP project ID.
294+
example: "my-project-123"
295+
topic:
296+
type: string
297+
description: The Pub/Sub topic name.
298+
example: "events-topic"
299+
endpoint:
300+
type: string
301+
description: Optional. Custom endpoint URL (e.g., localhost:8085 for emulator).
302+
example: "pubsub.googleapis.com:443"
303+
GCPPubSubCredentials:
304+
type: object
305+
required: [service_account_json]
306+
properties:
307+
service_account_json:
308+
type: string
309+
description: Service account key JSON. The entire JSON key file content as a string.
310+
example: '{"type":"service_account","project_id":"my-project","private_key_id":"key123","private_key":"-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\n","client_email":"my-service@my-project.iam.gserviceaccount.com"}'
287311

288312
# Type-Specific Destination Schemas (for Responses)
289313
DestinationWebhook:
@@ -667,6 +691,60 @@ components:
667691
credentials:
668692
key: "AKIAIOSFODNN7EXAMPLE"
669693
secret: "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
694+
DestinationGCPPubSub:
695+
type: object
696+
# Properties duplicated from DestinationBase
697+
required: [id, type, topics, config, credentials, created_at, disabled_at]
698+
properties:
699+
id:
700+
type: string
701+
description: Control plane generated ID or user provided ID for the destination.
702+
example: "des_12345"
703+
type:
704+
type: string
705+
description: Type of the destination.
706+
enum: [gcp_pubsub]
707+
example: "gcp_pubsub"
708+
topics:
709+
$ref: "#/components/schemas/Topics"
710+
disabled_at:
711+
type: string
712+
format: date-time
713+
nullable: true
714+
description: ISO Date when the destination was disabled, or null if enabled.
715+
example: null
716+
created_at:
717+
type: string
718+
format: date-time
719+
description: ISO Date when the destination was created.
720+
example: "2024-01-01T00:00:00Z"
721+
config:
722+
$ref: "#/components/schemas/GCPPubSubConfig"
723+
credentials:
724+
$ref: "#/components/schemas/GCPPubSubCredentials"
725+
target:
726+
type: string
727+
description: A human-readable representation of the destination target (project/topic). Read-only.
728+
readOnly: true
729+
example: "my-project-123/events-topic"
730+
target_url:
731+
type: string
732+
format: url
733+
nullable: true
734+
description: A URL link to the destination target (GCP Console link to the topic). Read-only.
735+
readOnly: true
736+
example: "https://console.cloud.google.com/cloudpubsub/topic/detail/events-topic?project=my-project-123"
737+
example:
738+
id: "des_gcp_pubsub_123"
739+
type: "gcp_pubsub"
740+
topics: ["order.created", "order.updated"]
741+
disabled_at: null
742+
created_at: "2024-03-10T14:30:00Z"
743+
config:
744+
project_id: "my-project-123"
745+
topic: "events-topic"
746+
credentials:
747+
service_account_json: '{"type":"service_account","project_id":"my-project-123",...}'
670748

671749
# Polymorphic Destination Schema (for Responses)
672750
Destination:
@@ -678,6 +756,7 @@ components:
678756
- $ref: "#/components/schemas/DestinationAWSKinesis"
679757
- $ref: "#/components/schemas/DestinationAzureServiceBus"
680758
- $ref: "#/components/schemas/DestinationAWSS3"
759+
- $ref: "#/components/schemas/DestinationGCPPubSub"
681760
discriminator:
682761
propertyName: type
683762
mapping:
@@ -688,6 +767,7 @@ components:
688767
aws_kinesis: "#/components/schemas/DestinationAWSKinesis"
689768
azure_servicebus: "#/components/schemas/DestinationAzureServiceBus"
690769
aws_s3: "#/components/schemas/DestinationAWSS3"
770+
gcp_pubsub: "#/components/schemas/DestinationGCPPubSub"
691771

692772
DestinationCreateWebhook:
693773
type: object
@@ -817,6 +897,24 @@ components:
817897
$ref: "#/components/schemas/AWSS3Config"
818898
credentials:
819899
$ref: "#/components/schemas/AWSS3Credentials"
900+
DestinationCreateGCPPubSub:
901+
type: object
902+
required: [type, topics, config, credentials]
903+
properties:
904+
id:
905+
type: string
906+
description: Optional user-provided ID. A UUID will be generated if empty.
907+
example: "user-provided-id"
908+
type:
909+
type: string
910+
description: Type of the destination. Must be 'gcp_pubsub'.
911+
enum: [gcp_pubsub]
912+
topics:
913+
$ref: "#/components/schemas/Topics"
914+
config:
915+
$ref: "#/components/schemas/GCPPubSubConfig"
916+
credentials:
917+
$ref: "#/components/schemas/GCPPubSubCredentials"
820918

821919
# Polymorphic Destination Creation Schema (for Request Bodies)
822920
DestinationCreate:
@@ -828,6 +926,7 @@ components:
828926
- $ref: "#/components/schemas/DestinationCreateAWSKinesis"
829927
- $ref: "#/components/schemas/DestinationCreateAzureServiceBus"
830928
- $ref: "#/components/schemas/DestinationCreateAWSS3"
929+
- $ref: "#/components/schemas/DestinationCreateGCPPubSub"
831930
discriminator:
832931
propertyName: type
833932
mapping:
@@ -838,6 +937,7 @@ components:
838937
aws_kinesis: "#/components/schemas/DestinationCreateAWSKinesis"
839938
azure_servicebus: "#/components/schemas/DestinationCreateAzureServiceBus"
840939
aws_s3: "#/components/schemas/DestinationCreateAWSS3"
940+
gcp_pubsub: "#/components/schemas/DestinationCreateGCPPubSub"
841941

842942
# Type-Specific Destination Update Schemas (for Request Bodies)
843943
WebhookCredentialsUpdate:
@@ -905,6 +1005,16 @@ components:
9051005
$ref: "#/components/schemas/AWSKinesisConfig" # stream_name/region required here, but PATCH means optional
9061006
credentials:
9071007
$ref: "#/components/schemas/AWSKinesisCredentials" # key/secret required here, but PATCH means optional
1008+
DestinationUpdateAzureServiceBus:
1009+
type: object
1010+
# Properties duplicated from DestinationUpdateBase
1011+
properties:
1012+
topics:
1013+
$ref: "#/components/schemas/Topics"
1014+
config:
1015+
$ref: "#/components/schemas/AzureServiceBusConfig" # name required here, but PATCH means optional
1016+
credentials:
1017+
$ref: "#/components/schemas/AzureServiceBusCredentials" # connection_string required here, but PATCH means optional
9081018

9091019
DestinationUpdateAWSS3:
9101020
type: object
@@ -916,6 +1026,16 @@ components:
9161026
$ref: "#/components/schemas/AWSS3Config" # bucket/region required here, but PATCH means optional
9171027
credentials:
9181028
$ref: "#/components/schemas/AWSS3Credentials" # key/secret required here, but PATCH means optional
1029+
DestinationUpdateGCPPubSub:
1030+
type: object
1031+
# Properties duplicated from DestinationUpdateBase
1032+
properties:
1033+
topics:
1034+
$ref: "#/components/schemas/Topics"
1035+
config:
1036+
$ref: "#/components/schemas/GCPPubSubConfig" # project_id/topic required here, but PATCH means optional
1037+
credentials:
1038+
$ref: "#/components/schemas/GCPPubSubCredentials" # service_account_json required here, but PATCH means optional
9191039

9201040
# Polymorphic Destination Update Schema (for Request Bodies)
9211041
DestinationUpdate:
@@ -925,7 +1045,9 @@ components:
9251045
- $ref: "#/components/schemas/DestinationUpdateRabbitMQ"
9261046
- $ref: "#/components/schemas/DestinationUpdateHookdeck"
9271047
- $ref: "#/components/schemas/DestinationUpdateAWSKinesis"
1048+
- $ref: "#/components/schemas/DestinationUpdateAzureServiceBus"
9281049
- $ref: "#/components/schemas/DestinationUpdateAWSS3"
1050+
- $ref: "#/components/schemas/DestinationUpdateGCPPubSub"
9291051
# Event Schemas
9301052
PublishRequest:
9311053
type: object
@@ -996,10 +1118,15 @@ components:
9961118
example: "2024-01-01T00:00:00Z"
9971119
metadata:
9981120
type: object
1121+
nullable: true
9991122
description: Key-value string pairs of metadata associated with the event.
10001123
additionalProperties:
10011124
type: string
10021125
example: { "source": "crm" }
1126+
status:
1127+
type: string
1128+
enum: [success, failed]
1129+
example: "success"
10031130
data:
10041131
type: object
10051132
description: Freeform JSON data of the event.
@@ -1338,11 +1465,31 @@ paths:
13381465
schema:
13391466
oneOf:
13401467
- type: string
1341-
enum: [webhook, aws_sqs, rabbitmq, hookdeck, aws_kinesis, aws_s3]
1468+
enum:
1469+
[
1470+
webhook,
1471+
aws_sqs,
1472+
rabbitmq,
1473+
hookdeck,
1474+
aws_kinesis,
1475+
azure_servicebus,
1476+
aws_s3,
1477+
gcp_pubsub,
1478+
]
13421479
- type: array
13431480
items:
13441481
type: string
1345-
enum: [webhook, aws_sqs, rabbitmq, hookdeck, aws_kinesis, aws_s3]
1482+
enum:
1483+
[
1484+
webhook,
1485+
aws_sqs,
1486+
rabbitmq,
1487+
hookdeck,
1488+
aws_kinesis,
1489+
azure_servicebus,
1490+
aws_s3,
1491+
gcp_pubsub,
1492+
]
13461493
description: Filter destinations by type(s).
13471494
- name: topics
13481495
in: query

examples/demos/nodejs/src/portal-urls.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,13 @@ const main = async () => {
88
const portalUrl = await outpost.getPortalURL(org.id);
99
console.log(`Portal URL for ${org.id}:`, portalUrl);
1010
}
11+
12+
try {
13+
const portalUrl = await outpost.getPortalURL("test-tenant");
14+
console.log(`Portal URL for test-tenant:`, portalUrl);
15+
} catch (error) {
16+
console.error(`Failed to create portal for test-tenant:`, error);
17+
}
1118
};
1219

1320
main()

0 commit comments

Comments
 (0)