Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions controlplane/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@
"fastify-plugin": "^4.5.1",
"fastify-raw-body": "^4.3.0",
"graphql": "^16.9.0",
"https-proxy-agent": "8.0.0",
"ioredis": "^5.4.1",
"isomorphic-dompurify": "^2.33.0",
"jose": "^5.2.4",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ export function updateContract(
authContext.organizationId,
opts.logger,
opts.billingDefaultPlanId,
opts.webhookProxyUrl,
);

req.excludeTags = [...new Set(req.excludeTags)];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ export function createFeatureFlag(
authContext.organizationId,
opts.logger,
opts.billingDefaultPlanId,
opts.webhookProxyUrl,
);

req.namespace = req.namespace || DefaultNamespace;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ export function deleteFeatureFlag(
authContext.organizationId,
opts.logger,
opts.billingDefaultPlanId,
opts.webhookProxyUrl,
);

req.namespace = req.namespace || DefaultNamespace;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ export function enableFeatureFlag(
authContext.organizationId,
opts.logger,
opts.billingDefaultPlanId,
opts.webhookProxyUrl,
);

req.namespace = req.namespace || DefaultNamespace;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ export function updateFeatureFlag(
authContext.organizationId,
opts.logger,
opts.billingDefaultPlanId,
opts.webhookProxyUrl,
);

req.namespace = req.namespace || DefaultNamespace;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ export function createFederatedGraph(
authContext.organizationId,
opts.logger,
opts.billingDefaultPlanId,
opts.webhookProxyUrl,
);
const fedGraphRepo = new FederatedGraphRepository(logger, opts.db, authContext.organizationId);
const subgraphRepo = new SubgraphRepository(logger, opts.db, authContext.organizationId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ export function migrateFromApollo(
authContext.organizationId,
opts.logger,
opts.billingDefaultPlanId,
opts.webhookProxyUrl,
);
const auditLogRepo = new AuditLogRepository(opts.db);
const namespaceRepo = new NamespaceRepository(opts.db, authContext.organizationId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ export function moveFederatedGraph(
authContext.organizationId,
opts.logger,
opts.billingDefaultPlanId,
opts.webhookProxyUrl,
);
const auditLogRepo = new AuditLogRepository(tx);
const namespaceRepo = new NamespaceRepository(tx, authContext.organizationId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ export function updateFederatedGraph(
authContext.organizationId,
opts.logger,
opts.billingDefaultPlanId,
opts.webhookProxyUrl,
);

req.namespace = req.namespace || DefaultNamespace;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export function recomposeGraph(
authContext.organizationId,
opts.logger,
opts.billingDefaultPlanId,
opts.webhookProxyUrl,
);
const federatedGraphRepo = new FederatedGraphRepository(logger, opts.db, authContext.organizationId);
const orgRepo = new OrganizationRepository(logger, opts.db, opts.billingDefaultPlanId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export function publishMonograph(
authContext.organizationId,
opts.logger,
opts.billingDefaultPlanId,
opts.webhookProxyUrl,
);
const namespaceRepo = new NamespaceRepository(opts.db, authContext.organizationId);
const subgraphRepo = new SubgraphRepository(logger, opts.db, authContext.organizationId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ export function updateMonograph(
authContext.organizationId,
opts.logger,
opts.billingDefaultPlanId,
opts.webhookProxyUrl,
);

if (req.subscriptionUrl && !isValidUrl(req.subscriptionUrl)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -444,6 +444,7 @@ export function createProposal(
authContext.organizationId,
opts.logger,
opts.billingDefaultPlanId,
opts.webhookProxyUrl,
),
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ export function updateProposal(
authContext.organizationId,
opts.logger,
opts.billingDefaultPlanId,
opts.webhookProxyUrl,
);
const namespaceRepo = new NamespaceRepository(opts.db, authContext.organizationId);

Expand Down Expand Up @@ -512,6 +513,7 @@ export function updateProposal(
authContext.organizationId,
opts.logger,
opts.billingDefaultPlanId,
opts.webhookProxyUrl,
),
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ export function checkSubgraphSchema(
authContext.organizationId,
opts.logger,
opts.billingDefaultPlanId,
opts.webhookProxyUrl,
);

let linkedSubgraph:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ export function deleteFederatedSubgraph(
authContext.organizationId,
opts.logger,
opts.billingDefaultPlanId,
opts.webhookProxyUrl,
);

req.namespace = req.namespace || DefaultNamespace;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ export function moveSubgraph(
authContext.organizationId,
opts.logger,
opts.billingDefaultPlanId,
opts.webhookProxyUrl,
);

const subgraph = await subgraphRepo.byName(req.name, req.namespace);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ export function publishFederatedSubgraph(
authContext.organizationId,
opts.logger,
opts.billingDefaultPlanId,
opts.webhookProxyUrl,
);
const auditLogRepo = new AuditLogRepository(opts.db);
const fedGraphRepo = new FederatedGraphRepository(logger, opts.db, authContext.organizationId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ export function updateSubgraph(
authContext.organizationId,
opts.logger,
opts.billingDefaultPlanId,
opts.webhookProxyUrl,
);

req.namespace = req.namespace || DefaultNamespace;
Expand Down
9 changes: 8 additions & 1 deletion controlplane/src/core/build-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ export interface BuildConfig {
webhook?: {
url?: string;
key?: string;
proxyUrl?: string;
};
githubApp?: {
webhookSecret?: string;
Expand Down Expand Up @@ -350,7 +351,12 @@ export default async function build(opts: BuildConfig) {
: (opts.s3Storage.useIndividualDeletes ?? false),
});

const platformWebhooks = new PlatformWebhookService(opts.webhook?.url, opts.webhook?.key, logger);
const platformWebhooks = new PlatformWebhookService(
opts.webhook?.url,
opts.webhook?.key,
logger,
opts.webhook?.proxyUrl,
);

const readmeQueue = new AIGraphReadmeQueue(logger, fastify.redisForQueue);

Expand Down Expand Up @@ -531,6 +537,7 @@ export default async function build(opts: BuildConfig) {
},
stripeSecretKey: opts.stripe?.secret,
admissionWebhookJWTSecret: opts.admissionWebhook.secret,
webhookProxyUrl: opts.webhook?.proxyUrl,
cdnBaseUrl: opts.cdnBaseUrl,
}),
contextValues(req) {
Expand Down
1 change: 1 addition & 0 deletions controlplane/src/core/env.schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ export const envVariables = z
*/
WEBHOOK_URL: z.string().optional(),
WEBHOOK_SECRET: z.string().optional(),
WEBHOOK_PROXY_URL: z.string().url().optional(),
/**
* GitHub Integration
*/
Expand Down
1 change: 1 addition & 0 deletions controlplane/src/core/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ export interface RouterOptions {
logger: pino.Logger;
keycloakClient: Keycloak;
platformWebhooks: IPlatformWebhookService;
webhookProxyUrl?: string;
webBaseUrl: string;
githubApp?: App;
slack: { clientID?: string; clientSecret?: string };
Expand Down
13 changes: 13 additions & 0 deletions controlplane/src/core/webhooks/OrganizationWebhookService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import pino from 'pino';
import { v4 } from 'uuid';
import * as z from 'zod';
import { LintSeverity, VCSContext } from '@wundergraph/cosmo-connect/dist/platform/v1/platform_pb';
import { HttpsProxyAgent } from 'https-proxy-agent';
import * as schema from '../../db/schema.js';
import { FederatedGraphRepository } from '../repositories/FederatedGraphRepository.js';
import { OrganizationRepository } from '../repositories/OrganizationRepository.js';
Expand Down Expand Up @@ -129,11 +130,23 @@ export class OrganizationWebhookService {
private organizationId: string,
logger: pino.Logger,
defaultBillingPlanId?: string,
proxyUrl?: string,
) {
this.logger = logger.child({ organizationId });
this.defaultBillingPlanId = defaultBillingPlanId;

let agent: HttpsProxyAgent<string> | undefined;
if (proxyUrl) {
try {
agent = new HttpsProxyAgent(proxyUrl, {});
} catch (e) {
logger.error(e, 'Failed to create proxy agent');
}
}

this.httpClient = axios.create({
httpsAgent: agent,
httpAgent: agent,
timeout: 30_000,
maxContentLength: 5 * 1024 * 1024, // ~5mb
});
Expand Down
14 changes: 13 additions & 1 deletion controlplane/src/core/webhooks/PlatformWebhookService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { PlatformEventName } from '@wundergraph/cosmo-connect/dist/notifications
import pino from 'pino';
import axios, { AxiosError, AxiosInstance } from 'axios';
import axiosRetry, { exponentialDelay } from 'axios-retry';
import { HttpsProxyAgent } from 'https-proxy-agent';
import { webhookAxiosRetryCond } from '../util.js';
import { makeWebhookRequest } from './utils.js';

Expand Down Expand Up @@ -48,12 +49,23 @@ export class PlatformWebhookService implements IPlatformWebhookService {
private logger: pino.Logger;
private httpClient: AxiosInstance;

constructor(webhookURL = '', webhookKey = '', logger: pino.Logger) {
constructor(webhookURL = '', webhookKey = '', logger: pino.Logger, proxyUrl?: string) {
this.url = webhookURL;
this.key = webhookKey;
this.logger = logger;

let agent: HttpsProxyAgent<string> | undefined;
if (proxyUrl) {
try {
agent = new HttpsProxyAgent(proxyUrl);
} catch (e) {
logger.error(e, 'Could not create proxy agent');
}
}

this.httpClient = axios.create({
httpAgent: agent,
httpsAgent: agent,
timeout: 10_000,
});
axiosRetry(this.httpClient, {
Expand Down
3 changes: 1 addition & 2 deletions controlplane/src/core/webhooks/utils.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { createHmac } from 'node:crypto';
import { AxiosError, AxiosInstance } from 'axios';
import pino from 'pino';
import { AxiosInstance } from 'axios';

export const makeWebhookRequest = <Data = any, TResponse = any>(
axiosInstance: AxiosInstance,
Expand Down
2 changes: 2 additions & 0 deletions controlplane/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ const {
KC_ADMIN_USER,
WEBHOOK_URL,
WEBHOOK_SECRET,
WEBHOOK_PROXY_URL,
GITHUB_APP_WEBHOOK_SECRET,
GITHUB_APP_CLIENT_ID,
GITHUB_APP_CLIENT_SECRET,
Expand Down Expand Up @@ -114,6 +115,7 @@ const options: BuildConfig = {
webhook: {
url: WEBHOOK_URL,
key: WEBHOOK_SECRET,
proxyUrl: WEBHOOK_PROXY_URL,
},
cdnBaseUrl: CDN_BASE_URL,
admissionWebhook: {
Expand Down
1 change: 1 addition & 0 deletions helm/cosmo/charts/controlplane/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ WunderGraph Cosmo Controlplane
| configuration.smtp.username | string | `""` | The username to use. Default is "". |
| configuration.stripeSecretKey | string | `""` | |
| configuration.stripeWebhookSecret | string | `""` | |
| configuration.webhookProxyUrl | string | `""` | |
| configuration.webhookSecret | string | `""` | |
| configuration.webhookUrl | string | `""` | |
| deploymentStrategy | object | `{}` | |
Expand Down
7 changes: 7 additions & 0 deletions helm/cosmo/charts/controlplane/templates/deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,13 @@ spec:
secretKeyRef:
name: {{ include "controlplane.secretName" . }}
key: webhookSecret
{{- if .Values.configuration.webhookProxyUrl }}
- name: WEBHOOK_PROXY_URL
valueFrom:
secretKeyRef:
name: {{ include "controlplane.secretName" . }}
key: webhookProxyUrl
{{- end }}
- name: GITHUB_APP_CLIENT_ID
valueFrom:
configMapKeyRef:
Expand Down
1 change: 1 addition & 0 deletions helm/cosmo/charts/controlplane/templates/secret.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ stringData:
keycloakAdminUser: "{{ .Values.global.keycloak.adminUser }}"
keycloakAdminPassword: "{{ .Values.global.keycloak.adminPassword }}"
webhookSecret: "{{ .Values.configuration.webhookSecret }}"
webhookProxyUrl: "{{ .Values.configuration.webhookProxyUrl }}"
githubAppClientSecret: "{{ .Values.configuration.githubAppClientSecret }}"
githubAppPrivateKey: "{{ .Values.configuration.githubAppPrivateKey }}"
githubAppWebhookSecret: "{{ .Values.configuration.githubAppWebhookSecret }}"
Expand Down
1 change: 1 addition & 0 deletions helm/cosmo/charts/controlplane/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@ configuration:
clickhouseMigrationDsn: 'clickhouse://default:changeme@cosmo-clickhouse:9000?database=cosmo'
webhookUrl: ''
webhookSecret: ''
webhookProxyUrl: ''
githubAppClientId: ''
githubAppClientSecret: ''
githubAppId: ''
Expand Down
Loading
Loading