Skip to content

feat: add script to automate updating bugsnag api client#392

Draft
sazap10 wants to merge 1 commit intomainfrom
update_bugsnag_api_client
Draft

feat: add script to automate updating bugsnag api client#392
sazap10 wants to merge 1 commit intomainfrom
update_bugsnag_api_client

Conversation

@sazap10
Copy link
Contributor

@sazap10 sazap10 commented Mar 25, 2026

Goal

Automate the previously manual process for updating the Bugsnag API client.

Design

The Bugsnag API client (src/bugsnag/client/api/api.ts) is generated from SwaggerHub but requires significant manual post-processing (removing duplicate imports, pruning object-oriented wrappers/factories we don't use, removing unused API exports, etc.).

This PR introduces an automated Node.js script (scripts/update-bugsnag-api.ts) using ts-morph and the Swagger generator API to automate the end-to-end process.
The new workflow is simply running npm run update:bugsnag-api.

This script handles:

  1. Fetching the latest swagger.json directly from SmartBear's public API.
  2. Generating the base typescript-fetch client via the Swagger Generator API.
  3. Injecting our custom linting overrides and node:url imports.
  4. Parsing the AST via ts-morph to reliably delete object-oriented API classes, factories, FPs, and generic fetch APIs that aren't necessary.
  5. Evaluating export references dynamically to un-export types not consumed outside the file, preventing unused export warnings in the wider project.
  6. Automatically formatting the result via npx biome check --write --unsafe.
  7. Passing the modified file through the project's prek pre-commit hooks.

Changeset

  • Added scripts/update-bugsnag-api.ts to orchestrate AST manipulation and network requests.
  • Added "update:bugsnag-api" to package.json scripts.
  • Updated src/bugsnag/client/api/api.ts header comments to document the new 2-step process.
  • Updated the actual client code inside api.ts which has been generated and heavily trimmed by the new script, bringing it to the latest version of the spec.

Testing

Ran npm run update:bugsnag-api which successfully generated the new code, applied all AST transformations, stripped unused exports, formatted with biome, and passed prek checks.
Ran npm run test:run and confirmed all 894 unit tests continue to pass.

@sazap10 sazap10 requested a review from a team as a code owner March 25, 2026 13:28
@sazap10 sazap10 marked this pull request as draft March 25, 2026 13:29

console.log(`Downloading generated client from ${link}...`);
const zipPath = "/tmp/bugsnag-client.zip";
execSync(`curl -s "${link}" -o ${zipPath}`);

Check failure

Code scanning / CodeQL

Uncontrolled command line Critical

This command line depends on a
user-provided value
.

Copilot Autofix

AI about 16 hours ago

In general, the safest fix is to avoid constructing shell command strings from untrusted input and instead use child_process APIs that accept the command and its arguments as separate parameters without invoking a shell (execFileSync, spawnSync, etc.). This prevents shell metacharacters in the input from being interpreted as part of the command.

For this specific case, we should replace the execSync curl invocation with a call to execFileSync (from the same child_process module) and pass link and zipPath as separate arguments. That preserves existing behavior (still calling curl -s <link> -o <zipPath>) but no longer runs through a shell, so link is only ever treated as a single argument. Concretely, in scripts/update-bugsnag-api.ts around line 68, change:

  • execSync(\curl -s "${link}" -o ${zipPath}`);`

to:

  • execFileSync("curl", ["-s", link, "-o", zipPath]);

We also need to import execFileSync from child_process alongside the existing execSync import at the top of the same file. No other logic or files need to be changed.

Suggested changeset 1
scripts/update-bugsnag-api.ts

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/scripts/update-bugsnag-api.ts b/scripts/update-bugsnag-api.ts
--- a/scripts/update-bugsnag-api.ts
+++ b/scripts/update-bugsnag-api.ts
@@ -1,4 +1,4 @@
-import { execSync } from "child_process";
+import { execSync, execFileSync } from "child_process";
 import * as fs from "fs";
 import * as path from "path";
 import { Node, Project, SyntaxKind } from "ts-morph";
@@ -65,7 +65,7 @@
 
   console.log(`Downloading generated client from ${link}...`);
   const zipPath = "/tmp/bugsnag-client.zip";
-  execSync(`curl -s "${link}" -o ${zipPath}`);
+  execFileSync("curl", ["-s", link, "-o", zipPath]);
 
   console.log("Extracting api.ts...");
   const extractedApi = execSync(
EOF
@@ -1,4 +1,4 @@
import { execSync } from "child_process";
import { execSync, execFileSync } from "child_process";
import * as fs from "fs";
import * as path from "path";
import { Node, Project, SyntaxKind } from "ts-morph";
@@ -65,7 +65,7 @@

console.log(`Downloading generated client from ${link}...`);
const zipPath = "/tmp/bugsnag-client.zip";
execSync(`curl -s "${link}" -o ${zipPath}`);
execFileSync("curl", ["-s", link, "-o", zipPath]);

console.log("Extracting api.ts...");
const extractedApi = execSync(
Copilot is powered by AI and may make mistakes. Always verify output.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant