Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
91 commits
Select commit Hold shift + click to select a range
8095322
feat: add support for plugins
JivusAyrus Jul 23, 2025
a1a93bb
Merge branch 'main' of github.com:wundergraph/cosmo into suvij/eng-75…
JivusAyrus Jul 23, 2025
5c8f5e6
fix: ci
JivusAyrus Jul 23, 2025
0b3bcea
fix: ci
JivusAyrus Jul 23, 2025
d97b4aa
fix: add generated files
JivusAyrus Jul 23, 2025
9152096
fix: ci
JivusAyrus Jul 23, 2025
7b6d513
fix: tests
JivusAyrus Jul 23, 2025
78faf29
fix: ci
JivusAyrus Jul 23, 2025
3e2a354
fix: ci
JivusAyrus Jul 23, 2025
095f0fe
fix: ci
JivusAyrus Jul 23, 2025
db8ec94
fix: ci
JivusAyrus Jul 23, 2025
aa8f56e
fix: pass proto data to build the router execution config
JivusAyrus Jul 23, 2025
7e949dc
fix: ci
JivusAyrus Jul 23, 2025
25e87a0
fix: make artifact compulsory
JivusAyrus Jul 23, 2025
9b6e827
fix: ci
JivusAyrus Jul 23, 2025
d46663f
fix: ci
JivusAyrus Jul 23, 2025
750f998
feat: add plugin management commands and enhance subgraph handling
JivusAyrus Jul 24, 2025
158b6d4
Merge branch 'main' into suvij/eng-7509-router-plugins-with-cosmo-int…
JivusAyrus Jul 24, 2025
b943dd1
fix: lint
JivusAyrus Jul 24, 2025
a1683c9
feat: add plugins to ui
JivusAyrus Jul 24, 2025
bf04436
fix: pr suggestions
JivusAyrus Jul 24, 2025
040697c
chore: merge migrations
JivusAyrus Jul 24, 2025
1cbd70a
fix: lint
JivusAyrus Jul 24, 2025
5b305a7
Merge branch 'main' into suvij/eng-7509-router-plugins-with-cosmo-int…
JivusAyrus Jul 24, 2025
114fd2e
refactor: rename Artifact to ImageReference and update related fields…
JivusAyrus Jul 24, 2025
5c7d6ef
Merge branch 'suvij/eng-7509-router-plugins-with-cosmo-integration' o…
JivusAyrus Jul 24, 2025
99a0138
fix: correct repository path format in ImageReference
JivusAyrus Jul 24, 2025
bbf3104
refactor: remove registry field from ImageReference and update field …
JivusAyrus Jul 24, 2025
067f837
refactor: remove pluginRegistryUrl field from BuildConfig interface
JivusAyrus Jul 24, 2025
bf140a9
fix: update audience key for plugin token in validateAndFetchPluginData
JivusAyrus Jul 24, 2025
3ce5a31
fix: correct audience key format for cosmoPluginKey in JWT configuration
JivusAyrus Jul 24, 2025
aec9e1a
refactor: optimize string manipulation functions in index.global.js
JivusAyrus Jul 24, 2025
0352c28
fix: publish a new version even when the schema didnt change for plugins
JivusAyrus Jul 24, 2025
56670ca
feat: add protoVersion field to Subgraph message and update related c…
JivusAyrus Jul 24, 2025
a5e7ded
feat: add reference field to ValidateAndFetchPluginDataResponse and u…
JivusAyrus Jul 25, 2025
a3c819b
fix: lint
JivusAyrus Jul 25, 2025
30d8a39
Merge branch 'main' into suvij/eng-7509-router-plugins-with-cosmo-int…
JivusAyrus Jul 25, 2025
5ea499b
fix: improve validation for subgraph type in publishFederatedSubgraph…
JivusAyrus Jul 25, 2025
7299d03
fix: update default plugin registry URL in configuration
JivusAyrus Jul 25, 2025
760a0e6
fix: update limit handling in plugin data validation to use 0 instead…
JivusAyrus Jul 25, 2025
f080c0c
test: enhance subgraph creation tests with plugin functionality and r…
JivusAyrus Jul 25, 2025
592125f
fix: enhance validation and error handling for plugin subgraph publis…
JivusAyrus Jul 25, 2025
13f3773
refactor: replace protoVersion with pluginData in Subgraph and update…
JivusAyrus Jul 25, 2025
cf12550
test: add validation checks for subgraph type, version, and platforms…
JivusAyrus Jul 25, 2025
845cd0f
test: add test for creating and deleting a plugin subgraph in delete-…
JivusAyrus Jul 25, 2025
6c36f67
fix: add 'pull' action to plugin data validation for repository refer…
JivusAyrus Jul 26, 2025
aa83d84
feat: update plugin data validation to use targetId and add comprehen…
JivusAyrus Jul 28, 2025
1b6013b
Merge branch 'main' into suvij/eng-7509-router-plugins-with-cosmo-int…
JivusAyrus Jul 28, 2025
97b55bd
fix: pr suggestions
JivusAyrus Jul 30, 2025
e81af8f
Merge branch 'main' into suvij/eng-7509-router-plugins-with-cosmo-int…
JivusAyrus Jul 30, 2025
0f006ff
fix: ci
JivusAyrus Jul 30, 2025
1eec965
refactor: revert
JivusAyrus Jul 30, 2025
ade971e
fix: update proto mapping and lock file names in publish command
JivusAyrus Jul 30, 2025
1d84031
feat: add proto and mapping files for ProjectsService and update test…
JivusAyrus Jul 30, 2025
3d6d30c
feat(router): oci plugins (#2049)
endigma Jul 30, 2025
dcb712f
fix: update plugin registry URL in config
JivusAyrus Jul 30, 2025
c039220
feat: add plugin icon to subgraph details
JivusAyrus Jul 30, 2025
19a550c
feat(router): add generate command for plugin code generation
JivusAyrus Jul 30, 2025
c8b346d
Update Dockerfile build command syntax
endigma Jul 30, 2025
5424a6b
fix(publish): update error message to use plugin name instead of subg…
JivusAyrus Jul 30, 2025
d80ade0
Merge branch 'suvij/eng-7509-router-plugins-with-cosmo-integration' o…
JivusAyrus Jul 30, 2025
98e113b
Add path sanitization to image unpacking
endigma Jul 30, 2025
c59d169
fix: ci
JivusAyrus Jul 30, 2025
1e6a36f
Various improvements
endigma Jul 30, 2025
c15b28e
Move image pull to start, fix tests
endigma Aug 1, 2025
6ccd52f
fix: handle plugin feature subgraphs
JivusAyrus Aug 4, 2025
26b37a5
Merge branch 'main' of github.com:wundergraph/cosmo into suvij/eng-75…
JivusAyrus Aug 4, 2025
3e00469
fix: tests
JivusAyrus Aug 4, 2025
4383d59
fix: update error message in publish subgraph test for clarity
JivusAyrus Aug 4, 2025
f5da110
Merge branch 'main' of github.com:wundergraph/cosmo into suvij/eng-75…
JivusAyrus Aug 5, 2025
71d2c30
Port support for otel in plugins to new plugins
endigma Aug 5, 2025
081b2de
fix: update Docker registry references to Cosmo registry in publish c…
JivusAyrus Aug 6, 2025
2caa615
Fix mutex deadlock on shutdown
endigma Aug 6, 2025
df2ce8f
Add mutex locking in GRPCPlugin fork method
endigma Aug 6, 2025
b3f0b78
fix: feature flag flow with plugins
JivusAyrus Aug 6, 2025
76a050f
Merge branch 'main' of github.com:wundergraph/cosmo into suvij/eng-75…
JivusAyrus Aug 6, 2025
3129e69
address review feedback
endigma Aug 7, 2025
30ce39c
feat: add audit logging for subgraph creation in validateAndFetchPlug…
JivusAyrus Aug 7, 2025
2ebff3a
refactor: update subgraph type from PLUGIN to GRPC_PLUGIN across mult…
JivusAyrus Aug 7, 2025
3b30ae3
refactor: simplify plugin publish command by removing platform specif…
JivusAyrus Aug 7, 2025
fbdcb25
feat: add option to specify plugin name in publish command
JivusAyrus Aug 7, 2025
4c91a52
feat: add logging for missing protobuf schema and plugin image versio…
JivusAyrus Aug 7, 2025
4398f3f
feat: add logging for missing protobuf schema and plugin image versio…
JivusAyrus Aug 7, 2025
bcd3f3d
Merge branch 'main' of github.com:wundergraph/cosmo into suvij/eng-75…
JivusAyrus Aug 7, 2025
afaa2f1
fix: tests
JivusAyrus Aug 7, 2025
c41b4bf
Merge branch 'main' into suvij/eng-7509-router-plugins-with-cosmo-int…
JivusAyrus Aug 7, 2025
ddb07b4
feat: enhance publish command to include current platform in default …
JivusAyrus Aug 8, 2025
7bbf483
refactor: simplify project directory structure in plugin initializati…
JivusAyrus Aug 8, 2025
b0ec824
feat: update plugin commands for improved user guidance and consistency
JivusAyrus Aug 8, 2025
e23121b
Merge branch 'main' of github.com:wundergraph/cosmo into suvij/eng-75…
JivusAyrus Aug 8, 2025
5b0a29d
Merge branch 'main' of github.com:wundergraph/cosmo into suvij/eng-75…
JivusAyrus Aug 12, 2025
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
2 changes: 1 addition & 1 deletion .github/workflows/controlplane-ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ jobs:
run: git diff --no-ext-diff --exit-code

- name: Build
run: pnpm run --filter ./controlplane --filter ./connect --filter ./shared --filter ./composition build
run: pnpm run --filter ./controlplane --filter ./connect --filter ./shared --filter ./composition --filter ./protographic build

- uses: actions/setup-java@v4
with:
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,6 @@ lerna-debug.log
# Go workspace files
go.work
go.work.sum

# Mise local config
**/mise.local.toml
1 change: 1 addition & 0 deletions cli/.env.example
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
COSMO_API_KEY=cosmo_669b576aaadc10ee1ae81d9193425705
COSMO_API_URL=http://localhost:3001
CDN_URL=http://localhost:11000
PLUGIN_REGISTRY_URL=

# configure running wgc behind a proxy
# HTTPS_PROXY=""
Expand Down
3 changes: 2 additions & 1 deletion cli/src/commands/feature-subgraph/commands/create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { Command, program } from 'commander';
import ora from 'ora';
import { resolve } from 'pathe';
import pc from 'picocolors';
import { SubgraphType } from '@wundergraph/cosmo-connect/dist/platform/v1/platform_pb';
import { getBaseHeaders } from '../../../core/config.js';
import { BaseCommandOptions } from '../../../core/types/types.js';
import { validateSubscriptionProtocols } from '../../../utils.js';
Expand All @@ -16,7 +17,7 @@ export default (opts: BaseCommandOptions) => {
command.description('Creates a feature subgraph on the control plane.');
command.argument('<name>', 'The name of the feature subgraph to create.');
command.option('-n, --namespace [string]', 'The namespace of the feature subgraph.');
command.requiredOption(
command.option(
'-r, --routing-url <url>',
'The routing url of your feature subgraph. This is the url at which the feature subgraph will be accessible.',
);
Expand Down
55 changes: 26 additions & 29 deletions cli/src/commands/feature-subgraph/commands/publish.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import { readFile } from 'node:fs/promises';
import { existsSync } from 'node:fs';
import { readFile } from 'node:fs/promises';
import { SubgraphType } from '@wundergraph/cosmo-connect/dist/platform/v1/platform_pb';
import { parseGraphQLSubscriptionProtocol, parseGraphQLWebsocketSubprotocol } from '@wundergraph/cosmo-shared';
import { Command, program } from 'commander';
import ora from 'ora';
import { resolve } from 'pathe';
import pc from 'picocolors';
import { parseGraphQLSubscriptionProtocol, parseGraphQLWebsocketSubprotocol } from '@wundergraph/cosmo-shared';
import { BaseCommandOptions } from '../../../core/types/types.js';
import { getBaseHeaders } from '../../../core/config.js';
import { validateSubscriptionProtocols } from '../../../utils.js';
import { websocketSubprotocolDescription } from '../../../constants.js';
import { BaseCommandOptions } from '../../../core/types/types.js';
import { handleCompositionResult } from '../../../handle-composition-result.js';
import { validateSubscriptionProtocols } from '../../../utils.js';

export default (opts: BaseCommandOptions) => {
const command = new Command('publish');
Expand Down Expand Up @@ -94,30 +94,27 @@ export default (opts: BaseCommandOptions) => {
spinner.start();
}

const resp = await opts.client.platform.publishFederatedSubgraph(
{
baseSubgraphName: options.subgraph,
disableResolvabilityValidation: options.disableResolvabilityValidation,
isFeatureSubgraph: true,
labels: [],
name,
namespace: options.namespace,
// Publish schema only
// Optional when feature subgraph does not exist yet
routingUrl: options.routingUrl,
schema,
subscriptionProtocol: options.subscriptionProtocol
? parseGraphQLSubscriptionProtocol(options.subscriptionProtocol)
: undefined,
subscriptionUrl: options.subscriptionUrl,
websocketSubprotocol: options.websocketSubprotocol
? parseGraphQLWebsocketSubprotocol(options.websocketSubprotocol)
: undefined,
},
{
headers: getBaseHeaders(),
},
);
const resp = await opts.client.platform.publishFederatedSubgraph({
baseSubgraphName: options.subgraph,
disableResolvabilityValidation: options.disableResolvabilityValidation,
isFeatureSubgraph: true,
labels: [],
name,
namespace: options.namespace,
// Publish schema only
// Optional when feature subgraph does not exist yet
routingUrl: options.routingUrl,
schema,
subscriptionProtocol: options.subscriptionProtocol
? parseGraphQLSubscriptionProtocol(options.subscriptionProtocol)
: undefined,
subscriptionUrl: options.subscriptionUrl,
websocketSubprotocol: options.websocketSubprotocol
? parseGraphQLWebsocketSubprotocol(options.websocketSubprotocol)
: undefined,
// passing Standard type to the backend, because the users have to use the 'wgc router plugin publish' command to publish the plugin
type: SubgraphType.STANDARD,
});

try {
handleCompositionResult({
Expand Down
69 changes: 69 additions & 0 deletions cli/src/commands/router/commands/plugin/commands/create.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import { existsSync } from 'node:fs';
import { readFile } from 'node:fs/promises';
import { EnumStatusCode } from '@wundergraph/cosmo-connect/dist/common/common_pb';
import { SubgraphType } from '@wundergraph/cosmo-connect/dist/platform/v1/platform_pb';
import { splitLabel } from '@wundergraph/cosmo-shared';
import { Command, program } from 'commander';
import ora from 'ora';
import { resolve } from 'pathe';
import pc from 'picocolors';
import { getBaseHeaders } from '../../../../../core/config.js';
import { BaseCommandOptions } from '../../../../../core/types/types.js';

export default (opts: BaseCommandOptions) => {
const command = new Command('create');
command.description('Creates a federated plugin subgraph on the control plane.');
command.argument(
'<name>',
'The name of the plugin subgraph to create. It is usually in the format of <org>.<service.name> and is used to uniquely identify your plugin subgraph.',
);
command.option('-n, --namespace [string]', 'The namespace of the plugin subgraph.');
command.option(
'--label [labels...]',
'The labels to apply to the subgraph. The labels are passed in the format <key>=<value> <key>=<value>.',
);
command.option('--readme <path-to-readme>', 'The markdown file which describes the subgraph.');

command.action(async (name, options) => {
let readmeFile;
if (options.readme) {
readmeFile = resolve(options.readme);
if (!existsSync(readmeFile)) {
program.error(
pc.red(
pc.bold(`The readme file '${pc.bold(readmeFile)}' does not exist. Please check the path and try again.`),
),
);
}
}

const spinner = ora('Plugin Subgraph is being created...').start();
const resp = await opts.client.platform.createFederatedSubgraph(
{
name,
namespace: options.namespace,
labels: options.label ? options.label.map((label: string) => splitLabel(label)) : [],
routingUrl: '',
readme: readmeFile ? await readFile(readmeFile, 'utf8') : undefined,
type: SubgraphType.GRPC_PLUGIN,
},
{
headers: getBaseHeaders(),
},
);

if (resp.response?.code === EnumStatusCode.OK) {
spinner.succeed('Plugin Subgraph was created successfully.');
} else {
spinner.fail('Failed to create pluginsubgraph.');
if (resp.response?.details) {
console.log(pc.red(pc.bold(resp.response?.details)));
}
process.exitCode = 1;
// eslint-disable-next-line no-useless-return
return;
}
});

return command;
};
156 changes: 156 additions & 0 deletions cli/src/commands/router/commands/plugin/commands/delete.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
import { Command } from 'commander';
import pc from 'picocolors';
import { EnumStatusCode } from '@wundergraph/cosmo-connect/dist/common/common_pb';
import inquirer from 'inquirer';
import Table from 'cli-table3';
import ora from 'ora';
import { BaseCommandOptions } from '../../../../../core/types/types.js';
import { getBaseHeaders } from '../../../../../core/config.js';

export default (opts: BaseCommandOptions) => {
const command = new Command('delete');
command.description('Deletes a plugin subgraph on the control plane.');
command.argument('<name>', 'The name of the plugin subgraph to delete.');
command.option('-n, --namespace [string]', 'The namespace of the plugin subgraph.');
command.option('-f --force', 'Flag to force the deletion (skip confirmation).');
command.option('--suppress-warnings', 'This flag suppresses any warnings produced by composition.');
command.action(async (name, options) => {
if (!options.force) {
const deletionConfirmed = await inquirer.prompt({
name: 'confirmDeletion',
type: 'confirm',
message: `Are you sure you want to delete the plugin subgraph "${name}"?`,
});
if (!deletionConfirmed.confirmDeletion) {
process.exitCode = 1;
return;
}
}

const spinner = ora(`The plugin subgraph "${name}" is being deleted...`).start();

const resp = await opts.client.platform.deleteFederatedSubgraph(
{
subgraphName: name,
namespace: options.namespace,
},
{
headers: getBaseHeaders(),
},
);

switch (resp.response?.code) {
case EnumStatusCode.OK: {
spinner.succeed(`The plugin subgraph "${name}" was deleted successfully.`);
if (resp.proposalMatchMessage) {
console.log(pc.yellow(`Warning: Proposal match failed`));
console.log(pc.yellow(resp.proposalMatchMessage));
}
break;
}
case EnumStatusCode.ERR_SCHEMA_MISMATCH_WITH_APPROVED_PROPOSAL: {
spinner.fail(`Failed to delete plugin subgraph "${name}".`);
console.log(pc.red(`Error: Proposal match failed`));
console.log(pc.red(resp.proposalMatchMessage));
break;
}
case EnumStatusCode.ERR_SUBGRAPH_COMPOSITION_FAILED: {
spinner.fail(`The plugin subgraph "${name}" was deleted but with composition errors.`);

const compositionErrorsTable = new Table({
head: [
pc.bold(pc.white('FEDERATED_GRAPH_NAME')),
pc.bold(pc.white('NAMESPACE')),
pc.bold(pc.white('FEATURE_FLAG')),
pc.bold(pc.white('ERROR_MESSAGE')),
],
colWidths: [30, 30, 30, 120],
wordWrap: true,
});

console.log(
pc.red(
`There were composition errors when composing at least one federated graph related to the` +
` plugin subgraph "${name}".\nThe router will continue to work with the latest valid schema.` +
`\n${pc.bold('Please check the errors below:')}`,
),
);
for (const compositionError of resp.compositionErrors) {
compositionErrorsTable.push([
compositionError.federatedGraphName,
compositionError.namespace,
compositionError.featureFlag || '-',
compositionError.message,
]);
}
// Don't exit here with 1 because the change was still applied
console.log(compositionErrorsTable.toString());

break;
}
case EnumStatusCode.ERR_DEPLOYMENT_FAILED: {
spinner.warn(
`The plugin subgraph "${name}" was deleted, but the updated composition could not be deployed.` +
`\nThis means the updated composition is not accessible to the router.` +
`\n${pc.bold('Please check the errors below:')}`,
);

const deploymentErrorsTable = new Table({
head: [
pc.bold(pc.white('FEDERATED_GRAPH_NAME')),
pc.bold(pc.white('NAMESPACE')),
pc.bold(pc.white('ERROR_MESSAGE')),
],
colWidths: [30, 30, 120],
wordWrap: true,
});

for (const deploymentError of resp.deploymentErrors) {
deploymentErrorsTable.push([
deploymentError.federatedGraphName,
deploymentError.namespace,
deploymentError.message,
]);
}
// Don't exit here with 1 because the change was still applied
console.log(deploymentErrorsTable.toString());

break;
}
default: {
spinner.fail(`Failed to delete the plugin subgraph "${name}".`);
if (resp.response?.details) {
console.log(pc.red(pc.bold(resp.response?.details)));
}
process.exitCode = 1;
return;
}
}

if (!options.suppressWarnings && resp.compositionWarnings.length > 0) {
const compositionWarningsTable = new Table({
head: [
pc.bold(pc.white('FEDERATED_GRAPH_NAME')),
pc.bold(pc.white('NAMESPACE')),
pc.bold(pc.white('FEATURE_FLAG')),
pc.bold(pc.white('WARNING_MESSAGE')),
],
colWidths: [30, 30, 30, 120],
wordWrap: true,
});

console.log(pc.yellow(`The following warnings were produced while composing the federated graph:`));
for (const compositionWarning of resp.compositionWarnings) {
compositionWarningsTable.push([
compositionWarning.federatedGraphName,
compositionWarning.namespace,
compositionWarning.featureFlag || '-',
compositionWarning.message,
]);
}
console.log(compositionWarningsTable.toString());
}
});

return command;
};
Loading
Loading