- name
- update-deps
- description
- Audit and fix dependency vulnerabilities in Go and Node.js packages. Runs govulncheck for Go and npm audit for each package.json directory. Commits fixes directory by directory.
- argument-hint
- --fix
Audit and fix dependency vulnerabilities in this project. Follow the steps below in order.
## Step 1: Go Vulnerability Check
Run `govulncheck` in every Go module in the repository:
```
make govulncheck
cd custombuild && make govulncheck
cd e2e && make govulncheck
cd k6 && make govulncheck
cd packagetracker && make govulncheck
```
Use the module's own `make govulncheck` target if it exists; otherwise run `go tool govulncheck ./...` from that module root.
Parse the output:
- If there are **no vulnerabilities**, note it and move on.
- If there are **vulnerabilities**, for each affected module:
1. Run `go list -m -u <module>` to find the latest available version.
2. Compare the current version with the latest version:
- If the major version changes (e.g. `v1.x.x` → `v2.x.x`), this is a **major version upgrade**. Generate a **Breaking Change Report** for it (see below), defer the upgrade, and continue with any other patchable work.
- If only minor/patch version changes, proceed automatically.
3. After all patchable fixes are applied and any deferred major upgrades have been presented to the user for a decision, run `go get <module>@latest` then `go mod tidy` in all relevant directories:
- `./`
- `./custombuild`
- `./e2e`
- `./k6`
- `./packagetracker`
Important:
- `go get <module>@latest` is for Go module dependencies only. Do **not** use it to change the Go toolchain version.
- If the requested fix is a Go version bump, update the repository's Go version files and generated inputs directly instead of trying to solve it with `go get`:
- `flake.nix`
- `.tool-versions`
- `go.mod`
- `custombuild/go.mod`
- `e2e/go.mod`
- `k6/go.mod`
- `packagetracker/go.mod.tpl`
- `custombuild/cmd/authgearx/Dockerfile`
- `custombuild/cmd/portalx/Dockerfile`
- `cmd/portal/Dockerfile`
- `cmd/authgear/Dockerfile`
- `once/partial.dockerfile`
- regenerate `once/Dockerfile` with `make once/Dockerfile`
- run `make go-mod-tidy`
- If a Go version bump is needed, verify the repository-specific generation and build steps after editing the version files. Do not commit a toolchain bump that only changes `go.mod` without updating the other affected files.
**Breaking Change Report for Go (major version bumps)** must include:
- Module name, current version → proposed version
- Link to the module's changelog or migration guide if available (check the module's repository)
- Known incompatibilities (import path changes, removed/renamed symbols)
- Note that the upgrade is deferred until the end of the patchable-fix pass, then ask: "Do you want to apply this major version upgrade? (yes/no)"
After updating Go deps:
- Run `make build` or `go build ./...` to verify the build.
- If the build breaks, report the compiler errors and ask the user how to proceed. Do not commit.
- If vulnerabilities cannot be fixed (no fix available), note them in an **Unfixable Issues Report** and notify the user.
- If fixes were applied and build passes, stage and commit all affected Go module files, including `go.sum`, `go.mod`, `custombuild/go.sum`, `custombuild/go.mod`, `e2e/go.sum`, `e2e/go.mod`, `k6/go.sum`, `k6/go.mod`, and `packagetracker/go.sum`/`packagetracker/go.mod` when they change, with commit message: `chore: fix Go dependency vulnerabilities`
## Step 2: Node.js Audit — directory by directory
Process each directory that contains a `package.json` (excluding `node_modules`) in this order:
1. `portal/`
2. `authui/`
3. `portalgraphiql/`
4. `scripts/npm/`
For each directory:
1. `cd` into it and check for **stale overrides** in `package.json` before auditing. For each entry in the `"overrides"` field:
- Identify what vulnerability or issue the override was originally added to fix (check git log: `git log --oneline -10 -- <dir>/package.json`).
- Run `npm list <overridden-package> --all` to see the currently resolved versions.
- Check if the parent package that originally required the vulnerable version has since released a patch that bundles a safe version on its own (i.e. the override is no longer needed to satisfy the advisory).
- If the override is no longer needed, remove it only after you have evidence that the vulnerable resolved versions are gone. Then run `npm install` and confirm with `npm audit` that there are no regressions before proceeding. Include the removal in the same commit as any other fixes for this directory.
- Do **not** remove an override speculatively just to "see what happens". If removing it causes `npm audit` to re-report the vulnerability, restore the override and treat it as still required.
- If `npm list` shows a vulnerable transitive version that is still being suppressed by an override, keep the override unless you can point to a non-vulnerable resolved version or an upstream package release that makes the override redundant.
**After removing any override and running `npm install`, you MUST verify the removal was safe:**
- Run `npm ci --dry-run` — if it fails, the removal broke the lockfile. Restore the override.
- Run `npm ls <overridden-package> --all 2>&1 | grep -E "UNMET|invalid"` — any UNMET result means a package now depends on a version that isn't available. Restore the override.
- Check every package that previously used the removed override still has a compatible resolved version. Inspect `node_modules/<parent-pkg>/package.json` for its declared dep range on the overridden package, and confirm the now-resolved version satisfies that range. If the resolved version is a different major, the removal is incorrect — restore the override or add a scoped replacement.
The same verification applies when `npm install` shrinks the lockfile in any other way (e.g. deduplication removes nested entries). Treat any reduction in nested `node_modules/.../node_modules/` entries as an implicit override removal and apply the same checks above before committing.
2. Run `npm audit --json`.
3. Parse the output:
- If **no vulnerabilities**, note it and move on to the next directory.
- Before applying any fix, inspect what versions `npm audit fix` would install by running `npm audit fix --dry-run --json`. For each package that would be updated:
- If the proposed fix is a **major version bump** (semver major increases), it is a potential breaking change regardless of whether the build will pass.
- Collect all such packages into a **Breaking Change Report** listing:
- Package name, current version → proposed version
- Semver change type (major bump)
- Any notes from the advisory about incompatible changes
- Do not apply the major upgrade automatically. Defer it, continue with any patchable fixes in other packages/directories, and report it in the final summary for a user decision.
- For fixes with only minor/patch version bumps, run `npm audit fix` automatically.
- If the user later confirms the breaking changes, run `npm audit fix --force` (only after confirmation), then verify build and commit that directory.
- If a vulnerability can only be fixed by a major version bump, do not apply it automatically. Record it in the Breaking Change Report and revisit it only after all patchable fixes have been applied.
- If vulnerabilities are **unfixable via npm audit fix** (i.e. `npm audit fix --dry-run` shows no resolution), check if the vulnerability is in a **transitive dependency** whose parent has not yet released a patch:
1. Identify the vulnerable transitive package and the minimum safe version that fixes it (from the advisory).
2. Run `npm list <transitive-package> --all` to see **every installed version** of that package across the dependency tree. This is critical — there may be multiple versions installed at different semver ranges (e.g. `3.x`, `9.x`, `10.x`). Only the version(s) that fall in the advisory's vulnerable range need to be overridden. **Record this full list — it is your baseline.**
3. Identify the **direct parent package(s)** that pull in the vulnerable version (e.g. `eslint-plugin-sonarjs` → `minimatch@10.1.2`).
4. Check the changelog/release notes between the currently-used vulnerable version and the safe version:
- Look for any breaking changes (API removals, changed behavior, new peer-dep requirements).
- If there are **no breaking changes**, add a **scoped override** to `package.json`, targeting only the parent package that pulls in the vulnerable dep. Do **NOT** use a flat global override — it will forcibly replace all other installed versions (including non-vulnerable ones) and break unrelated packages:
```json
"overrides": {
"<direct-parent-package>": {
"<transitive-package>": "^<safe-version>"
}
}
```
Then run `npm install` to apply. **Before accepting the result**, run `npm list <transitive-package> --all` again and diff it against your baseline: only the targeted parent's instance should have changed version. If any other package's resolved version of `<transitive-package>` changed, the override is broader than intended — remove it and use a more specific scope or a per-parent override. Then run `npm audit` to confirm the vulnerability is resolved.
- If there **are breaking changes**, do not apply the override. Add the vulnerability to the **Unfixable Issues Report** and explain why the override is unsafe.
3. **After any npm operation that changes the lockfile**, run these two validation checks before touching the build or committing:
**a) Lockfile self-consistency**
Run `npm ci --dry-run`. If it fails with "Missing: <pkg>@<version> from lock file", the lockfile is inconsistent and must be fixed before proceeding. Do not commit a lockfile that fails `npm ci`.
**b) Silent dedup detection**
If the lockfile shrank significantly (many deletions, few or no insertions), nested package entries may have been removed by npm's deduplication. Removed nested entries are usually fine — unless a package's declared dependency range is no longer satisfied by the hoisted version.
Run: `git diff -- package-lock.json | grep "^-" | grep '"node_modules/.*/node_modules/' | grep -o '"[^"]*node_modules/[^"]*"' | sort -u`
For each removed nested path (e.g. `node_modules/@eslint/config-array/node_modules/minimatch`), extract the parent package and transitive package name. Then check:
```
npm ls <transitive-package> 2>&1 | grep -E "UNMET|invalid|extraneous"
```
Also inspect the parent's own `package.json` on disk (`node_modules/<parent>/package.json`) to find its declared range for the transitive dep. If the hoisted version does NOT satisfy that range (different major), the dedup is silent but incorrect.
**Fix:** Add a scoped override in the directory's `package.json` to make the upgrade intentional:
```json
"overrides": {
"<parent-package>": {
"<transitive-package>": "^<hoisted-safe-version>"
}
}
```
Then run `npm install` and re-run `npm ci --dry-run` to confirm.
**c) Jest peer alignment** (authui only)
After any npm operation in `authui/`, run:
```
npm ls jest-environment-jsdom jest-runtime 2>&1 | grep -E "jest-environment-jsdom|jest-runtime"
```
Both must resolve to the same `major.minor`. If `jest-runtime` is at `30.4.x` but `jest-environment-jsdom` is still pinned to `^30.2.0` in `package.json`, update the pin to `^30.4.0` (matching the runtime minor), then run `npm install`. Misalignment causes a runtime error (`clearMocksOnScope is not a function`) that only surfaces when tests run — not during install.
4. After applying fixes in a directory, verify the project still builds:
- For `portal/`: `npm run build` (or `npm run typecheck` if faster)
- For `authui/`: `npm run build`
- For `portalgraphiql/`: `npm run build`
- For `scripts/npm/`: skip build check (utility scripts)
5. Stage and commit changes for that directory immediately:
- `git add <dir>/package.json <dir>/package-lock.json`
- If overrides were added, include a comment in the commit body explaining which transitive dep was pinned, why, and a link to the advisory.
- Commit message: `chore: fix npm dependency vulnerabilities in <dir>`
## Step 3: Final Summary
After all directories are processed, output a summary with three sections:
### Fixed
List every package that was updated (name, old version → new version, directory).
### Breaking Changes Applied
List any breaking changes that were confirmed and applied.
### Unfixable Issues
List any vulnerabilities that could not be resolved, including:
- Package name and version
- CVE/advisory ID
- Why it cannot be fixed — be specific:
- No patch released yet by the package author
- Transitive dependency where the override would introduce breaking changes (explain what breaks)
- Locked by another dependency with no compatible version
- Recommended action (e.g., open issue with upstream, watch for future patch, manual code workaround)
GitHubで見る