Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(providers): improve validation for connect #3109

Merged
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
6 changes: 2 additions & 4 deletions .github/workflows/validation.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,9 @@ jobs:
node-version-file: '.nvmrc'
registry-url: 'https://registry.npmjs.org'

- run: npm ci
- name: Validate YAML
run: |
npm ci

npx tsx scripts/validation/providers/validate.ts
run: npm run test:providers

- name: Validate OpenAPI
run: npm run test:openapi
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
"test:integration": "vitest --config ./vite.integration.config.ts",
"test:cli": "vitest --config ./vite.cli.config.ts",
"test:openapi": "npx @apidevtools/swagger-cli validate docs-v2/spec.yaml",
"test:providers": "npx tsx scripts/validation/providers/validate.ts",
"docs": "cd ./docs-v2 && npx mintlify dev --port 3033",
"nango": "cd ./packages/server && npm run nango",
"dev:docker": "docker compose --file dev/docker-compose.dev.yaml up -d"
Expand Down
4 changes: 1 addition & 3 deletions packages/shared/providers.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -746,7 +746,7 @@ bill-sandbox:
proxy:
base_url: https://gateway.stage.bill.com/connect
docs: https://docs.nango.dev/integrations/all/bill
docs_connect: https://docs.nango.dev/integrations/all/bill/connect
docs_connect: https://docs.nango.dev/integrations/all/bill-sandbox/connect

bill:
display_name: Bill (Connect API)
Expand Down Expand Up @@ -5995,7 +5995,6 @@ trello-scim:
headers:
Authorization: Bearer ${apiKey}
docs: https://docs.nango.dev/integrations/all/trello
docs_connect: https://docs.nango.dev/integrations/all/trello-scim/connect
credentials:
apiKey:
type: string
Expand Down Expand Up @@ -6299,7 +6298,6 @@ unipile:
headers:
x-api-key: ${apiKey}
docs: https://docs.nango.dev/integrations/all/unipile
docs_connect: https://docs.nango.dev/integrations/all/unipile/connect
credentials:
apiKey:
type: string
Expand Down
75 changes: 67 additions & 8 deletions scripts/validation/providers/validate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,9 +82,12 @@ console.log('✅ All providers are valid');
* Validate one provider
*/
function validateProvider(providerKey: string, provider: Provider) {
const filename = provider.docs.split('/').slice(-1)[0];
const filename = provider.docs.split('/').slice(-1)[0]; // filename could be different from providerConfigKey
const mdx = path.join(docsPath, `${filename}.mdx`);
const svg = path.join(svgPath, `${providerKey}.svg`);
const connectMdx = path.join(docsPath, `${providerKey}/connect.mdx`);
let hasValidConnect = false;
const headers = new Set<string>();

if (!fs.existsSync(mdx)) {
console.error(chalk.red('error'), chalk.blue(providerKey), `Documentation file not found`);
Expand All @@ -96,6 +99,26 @@ function validateProvider(providerKey: string, provider: Provider) {
console.error(`Expected file: ${svg}`);
error = true;
}
if (provider.docs_connect) {
if (!fs.existsSync(connectMdx)) {
console.error(chalk.red('error'), chalk.blue(providerKey), `Connect.mdx file not found`);
console.error(`Expected file: ${connectMdx}`);
error = true;
} else {
hasValidConnect = true;
const content = fs.readFileSync(connectMdx).toString();
const matched = content.matchAll(/^[#]+\sStep[a-zA-Z0-9:()._ -]+$/gim);
for (const match of matched) {
headers.add(
match[0]
.toLocaleLowerCase()
.replace(/^[#]+ /, '#')
.replaceAll(/\s/g, '-')
.replaceAll(/[:()._]/g, '')
);
}
}
}

// Find all connectionConfig references
const connectionConfigReferences = findConnectionConfigReferences(provider);
Expand All @@ -116,14 +139,50 @@ function validateProvider(providerKey: string, provider: Provider) {
continue;
}
}

// Check connection config validity
for (const [key, schema] of Object.entries(provider.connection_config || [])) {
if (schema.doc_section && !provider.docs_connect) {
console.error(
chalk.red('error'),
chalk.blue(providerKey),
`"connection_config > ${key}" defines a "doc_section" but has no "docs_connect" property`
);
error = true;
if (schema.doc_section) {
if (!provider.docs_connect) {
console.error(
chalk.red('error'),
chalk.blue(providerKey),
`"connection_config > ${key}" defines a "doc_section" but has no "docs_connect" property`
);
error = true;
} else if (hasValidConnect) {
if (!headers.has(schema.doc_section)) {
console.error(
chalk.red('error'),
chalk.blue(providerKey),
`"connection_config > ${key} > doc_section" does not exists in ${providerKey}/connect.mdx`
bodinsamuel marked this conversation as resolved.
Show resolved Hide resolved
);
error = true;
}
}
}
}

// Check credentials validity
for (const [key, schema] of Object.entries(provider.credentials || [])) {
if (schema.doc_section) {
if (!provider.docs_connect) {
console.error(
chalk.red('error'),
chalk.blue(providerKey),
`"credentials > ${key}" defines a "doc_section" but has no "docs_connect" property`
);
error = true;
} else if (hasValidConnect) {
if (!headers.has(schema.doc_section)) {
console.error(
chalk.red('error'),
chalk.blue(providerKey),
`"credentials > ${key} > doc_section" does not exists in ${providerKey}/connect.mdx`
bodinsamuel marked this conversation as resolved.
Show resolved Hide resolved
);
error = true;
}
}
}
}
} else if (provider.connection_config) {
Expand Down
Loading