chore: Fix 33 vulnerabilities, replace dead gulp build, restore tests and CI - #1
chore: Fix 33 vulnerabilities, replace dead gulp build, restore tests and CI#1fuzzie360 wants to merge 7 commits into
Conversation
The gulp 3 toolchain has not been runnable for years. On Node 22 it dies immediately with "ReferenceError: primordials is not defined" (gulp 3 -> vinyl-fs -> graceful-fs 1.x -> natives), so neither `gulp tsbuild` nor `gulp copy` could be executed at all. The gulp stack was also the source of nearly all of the project's vulnerable transitive dependencies. Replace it with a direct `tsc` invocation and npm scripts: - Drop gulp, gulp-*, browser-sync, merge2 and the stray babel plugin. - Upgrade the remaining toolchain to current releases: esprima 3 -> 4, TypeScript 2 -> 5, mocha 3 -> 11, chai 3 -> 4. chai is deliberately held at 4.x because chai 5 is ESM-only and the test harness is CommonJS. - Add `build`, `prepare` and `pretest` scripts. Previously `npm test` failed on a clean checkout with "Cannot find module '../bin/transpiler_base.js'" because bin/ is gitignored and nothing built it; `pretest` fixes that. - Add `copy:lib` to stage the browser test libraries that `gulp copy` used to produce, dropping its reference to requirejs which was never actually a dependency. - Point `main` at bin/transpiler_esprima.js and emit declarations. The old `main` referenced dist/gpujs-transpile.js, a bundle only the (now removed) gulp task claimed to build, and which that task could not have produced anyway since `--out` is rejected for module-based code. - Modernize tsconfig: replace the obsolete `filesGlob`/`compileOnSave` atom-typescript keys with `include`, drop `noResolve`, and set `"types": []`. Under TypeScript 2.9 the auto-included @types/node and @types/ws emitted 9 parse errors on every build; those are now gone. Node >=20 is declared in engines. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…ript mocha 11.7.6 is the latest release and still resolves three transitively vulnerable packages. There is no newer mocha to upgrade to, so pin the patched versions with npm `overrides`: - brace-expansion -> ^5.0.8 for GHSA-mh99-v99m-4gvg (high, DoS via unbounded expansion). Affects <= 5.0.7; the 2.x line mocha resolves through minimatch has no patched release, so 5.0.8 is the only fix. This also clears the derived minimatch and glob advisories. - diff -> ^8.0.4 for GHSA-73rr-hh4g-fpgx (low, ReDoS in parsePatch / applyPatch). Affects >= 6.0.0 < 8.0.3; mocha pins ^7.0.0. - serialize-javascript -> ^7.0.7 for GHSA-5c6j-r48x-rmvq (high, RCE via RegExp.flags) and GHSA-qj8w-gfj5-8c6v (moderate, CPU exhaustion). Affects <= 7.0.2 and < 7.0.5 respectively; mocha pins ^6.0.2. All three cross a major version boundary for mocha, so the affected code paths were exercised directly: the test suite passes, the reporter still renders assertion diffs correctly (diff), and `mocha --parallel` still serializes results across workers (serialize-javascript). npm audit goes from 33 vulnerabilities (2 low, 2 moderate, 24 high, 5 critical) to 0. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The repository had no lockfile, which meant GitHub's dependency graph could only see the four direct ranges in package.json and none of the transitive tree. That is why Dependabot reported zero alerts for a dependency set that npm audit scored at 33 vulnerabilities: the vulnerable packages were all transitive and therefore invisible. Committing the lockfile makes the resolved tree visible to Dependabot, pins the `overrides` added in the previous commit, and lets CI use `npm ci` for reproducible installs. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The repository had no CI at all, so the fact that the build had stopped working entirely on modern Node went unnoticed. Adds a GitHub Actions workflow running `npm ci`, `npm run build` and `npm test` against the currently supported Node.js release lines, plus a guard that the build really emitted bin/*.js. bin/ is gitignored, so a skipped build would otherwise surface only as a confusing "Cannot find module" from inside mocha. `npm audit --audit-level=high` runs as a separate job so a newly published advisory turning CI red is never mistaken for a build or test regression. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Two defects made transpiler_base.parse() unable to reach any of its own error reporting. generateAstConfig() creates a field named `resArr` (matching `resStr`), but parse() read and wrote `astConfig.retArr`. That field is always undefined, so parse() passed undefined into ast_generic() and then called .join() on whatever came back, silently leaving `resArr` empty and adding a stray `retArr` to the returned config. ast_errorOutput() built its error context from `ast.src`, but the source text lives on astConfig, not on the AST node. Since esprima is invoked with `range: true` every node has a `range`, so the guarded branch was always taken and always threw "Cannot read properties of undefined (reading 'slice')" — a TypeError that replaced the descriptive message the transpiler was trying to raise. The slice was also wrong independently: it passed 25 as an absolute end offset rather than a length, so any node starting past offset 25 would yield an empty string. Read from astConfig.src and slice 25 characters from the node's own start offset. Both fixes are covered by new tests, which fail against the previous source with exactly these symptoms. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
transpiler_esprima read esprima off a bare global. That works for the browser build, which loads it with a <script> tag, and for the node test harness, which happens to leak an implicit global from run-node.js. It does not work for anyone requiring the package: `main` resolves fine but the first generateAst() call dies with "ReferenceError: esprima is not defined", despite esprima being a declared runtime dependency. Add resolveEsprima(), which prefers an existing global and otherwise requires the esprima package. The browser path is unchanged, since the global still takes precedence, and both branches are covered by tests. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The README only mentioned `npm test` and predates both the build script and the removal of gulp, so nothing explained how bin/ gets produced or how to run the browser suite now that `gulp bsync` is gone. Also records that the transpiler is an unfinished prototype. Every concrete AST node type in ast_generic is still commented out, so parse() raises "Unknown ast type" for real input; that is worth stating up front rather than leaving a reader to discover it from the source. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
|
Warning Review the following alerts detected in dependencies. According to your organization's Security Policy, it is recommended to resolve "Warn" alerts. Learn more about Socket for GitHub.
|
Summary
Security remediation and modernization for a repo whose last commit was 2016-12-10. The build system was not merely stale but unrunnable,
npm testfailed on a clean checkout, and the resolved dependency tree carried 33 vulnerabilities that Dependabot could not see.This does not attempt to finish the transpiler —
ast_generic's commented-out node handlers are the actual unfinished work, and completing them is a feature project, not modernization. The prototype status is now documented in the README instead.Security
Dependabot reported 0 alerts, and that was a false negative. Alerts are enabled (the API returns
200 [], andvulnerability-alertsreturns204; automated fixes are off), but the repo had no lockfile — so the dependency graph could only see the four direct ranges inpackage.json, and every vulnerable package was transitive and therefore invisible.Auditing the resolved tree locally showed the real picture:
npm auditnpm ci+ buildtscemitted 9 errorsnpm testtsc)overrides, because mocha 11.7.6 is already the newest release and still resolves vulnerable transitives:brace-expansion→^5.0.8(GHSA-mh99-v99m-4gvg, high). The 2.x line mocha reaches via minimatch has no patched release, so the major jump is the only fix. This also cleared the derivedminimatchandglobalerts.serialize-javascript→^7.0.7(GHSA-5c6j-r48x-rmvq, high RCE + GHSA-qj8w-gfj5-8c6v, moderate); mocha pins^6.0.2.diff→^8.0.4(GHSA-73rr-hh4g-fpgx, low); mocha pins^7.0.0.All three cross a major boundary for mocha, so the affected code paths were exercised directly rather than assumed: the reporter still renders assertion diffs (
diff), andmocha --parallelstill serializes across workers (serialize-javascript). These pins are worth revisiting if mocha later widens its own ranges rather than being left indefinitely.Bugs fixed
Each is pinned by a test confirmed to fail against the unfixed source.
parse()read and wroteastConfig.retArr, butgenerateAstConfig()createsresArr. Result:resArrwas always left empty and a strayretArrwas added.ast_errorOutput()built its context fromast.src, but the source lives onastConfig. Since esprima runs withrange: true, every node has arange, so this branch always fired and always threwCannot read properties of undefined (reading 'slice')— aTypeErrorthat replaced the descriptive error the transpiler was trying to raise. The slice was independently wrong too, passing25as an absolute end offset rather than a length.transpiler_esprimaread esprima off a bare global, so requiring the package died withReferenceError: esprima is not defineddespite esprima being a declared dependency. AddedresolveEsprima(); a global still takes precedence, so the browser path is unchanged.Modernization
ReferenceError: primordials is not defined— and itstsbuildtask could never have worked anyway, since it used--outagainstexport defaultcode, which tsc rejects. Replaced with a plaintscinvocation.npm teston a clean checkout. It previously failed withCannot find module '../bin/transpiler_base.js'—bin/is gitignored and no script built it. Addedbuild/prepare/pretest.main, which pointed atdist/gpujs-transpile.js, a bundle nothing could produce. Nowbin/transpiler_esprima.js, with declarations emitted.filesGlob/compileOnSavekeys andnoResolve, addedincludeand"types": [].npm audit --audit-level=highjob so a newly published advisory turning CI red is not mistaken for a test regression. Committed the lockfile so Dependabot can finally see the tree.gulp copywithnpm run copy:lib, preserving the browser test page and dropping its reference torequirejs, which was never actually a dependency.Testing
From a fresh clone of this branch:
tscexits 0,npm test→ 10 passing,npm audit→ 0 vulnerabilities.Pre-existing failures, distinguished from new work:
npm testwas already broken on a clean checkout before these changes — it only passed if you manually rantscfirst.tscunder TypeScript 2.9 already emitted 9 errors from auto-included@types/nodeand@types/ws(TS1084,TS1005,TS1011). It still emitted JS becausenoEmitOnErrorwas unset, so the breakage was silent. Fixed by"types": [].gulpwas already 100% dead on modern Node.No new failures were introduced. The 4 new tests were each confirmed to fail against the unfixed source with the exact expected symptom.
Deliberately out of scope: no transpiler rewrite, no
strictTypeScript (the code is implicit-anythroughout; enabling it would be a large diff with no security or compatibility benefit), no chai 5 / ESM migration, no test-runner swap.🤖 Generated with Claude Code