Shared dependency management and security update scripts for IZGateway projects
A collection of automated scripts for managing npm dependencies and fixing security vulnerabilities in IZGateway projects. These scripts are used in CI/CD pipelines to keep dependencies up-to-date and secure.
Configure npm registry:
echo "@izgateway:registry=https://npm.pkg.github.com" >> .npmrcInstall package:
npm install --save-dev @izgateway/dependency-scriptsFor CI/CD, add to workflow:
- name: Setup npm authentication
run: echo "//npm.pkg.github.com/:_authToken=${{ secrets.NPM_TOKEN }}" > .npmrcAdd to your package.json:
{
"scripts": {
"fix-vulnerabilities": "fix-vulnerabilities && npm install && npm audit",
"test-overrides": "test-overrides",
"update-overrides": "update-overrides"
}
}Then run:
npm run fix-vulnerabilitiesAfter installation, commands are available globally in your project:
fix-vulnerabilities # Fix all security vulnerabilities
test-overrides # Remove unnecessary overrides
update-overrides # Update existing overrides to latestNote: In CI/CD environments, call scripts using node explicitly to avoid execution issues.
- name: Install dependencies
run: npm ci
- name: Fix vulnerabilities
run: node node_modules/@izgateway/dependency-scripts/fix-all-vulnerabilities.js
- name: Update overrides
run: node node_modules/@izgateway/dependency-scripts/update-overrides.js
- name: Test overrides
run: node node_modules/@izgateway/dependency-scripts/test-overrides.js
- name: Update package-lock
run: npm installThis repository also hosts reusable composite GitHub Actions for IZGateway CI/CD pipelines. Because they are composite actions (not reusable workflows), they run inside the calling job's workspace — no artifact upload/download is needed to access built JARs.
Path: .github/actions/cve-scan/action.yml
Runs OWASP Dependency Check against a JAR or directory using NVD + OSS Index as vulnerability sources. The Central Analyzer is disabled because OSS Index matches by GAV coordinates natively and NVD matching is accurate from POM metadata alone in a clean Maven build.
| Input | Required | Default | Description |
|---|---|---|---|
project-name |
✅ | — | Display name in the dependency-check report |
scan-path |
✅ | — | Path to the JAR or directory to scan |
oss-index-username |
✅ | — | Sonatype OSS Index username |
oss-index-password |
✅ | — | Sonatype OSS Index API token |
nvd-api-key |
✅ | — | NVD API key |
suppression-file |
❌ | ./dependency-suppression.xml |
Path to OWASP suppression XML |
report-output-dir |
❌ | target/site |
Directory for HTML/JSON report output |
fail-on-cvss |
❌ | 7 |
Minimum CVSS score that fails the build (0–10) |
continue-on-error |
❌ | false |
Set to true to report vulnerabilities without failing the build |
artifact-name |
❌ | DependencyCheck |
Name of the uploaded report artifact; set to '' to skip upload |
Replace the inline Cache Dependency-Check NVD data + Dependency Check steps in your
maven.yml with:
- name: CVE Scan
uses: IZGateway/izg-dependency-scripts/.github/actions/cve-scan@main
with:
project-name: My Project Name
scan-path: target/${{ env.IMAGE_TAG }}.jar
oss-index-username: ${{ secrets.OSS_INDEX_USERNAME }}
oss-index-password: ${{ secrets.OSS_INDEX_PASSWORD }}
nvd-api-key: ${{ secrets.NVDAPIKEY }}
artifact-name: DependencyCheck # omit or set to '' to skip uploadNote: The report upload is handled inside the action (always runs, even on scan failure). You no longer need a separate
upload-artifactstep in your calling workflow.
@main always tracks the latest action. For stability in production workflows, pin to a tag:
uses: IZGateway/izg-dependency-scripts/.github/actions/cve-scan@v1.1.0The Central Analyzer queries Maven Central's REST API to enrich CPE identifiers for NVD lookups. In a clean-build CI pipeline:
- OSS Index matches by
group:artifact:versionnatively — it doesn't use CPE at all. - NVD matching is accurate from the POM's GAV metadata alone for standard artifacts.
- Central makes additional outbound HTTP calls, adding latency and a rate-limit failure mode.
--disableCentral is therefore the correct setting for all IZGateway Maven projects.
Path: .github/workflows/ecr-scan-report.yml
Reusable workflow (on: workflow_call) that retrieves AWS Inspector2 findings for a specific
ECR image tag, filters them to vulnerabilities known at release time (vendorCreatedAt ≤ release-date),
and uploads JSON, CSV, and HTML scan report files as a GitHub Actions artifact using the CDC
naming convention (YYYYMMDD_{pkg}_vX.Y.Z_InspectorScan.{ext}).
The job runs with continue-on-error: true — a scan failure will never block a release.
| Input | Required | Default | Description |
|---|---|---|---|
ecr-repository |
✅ | — | ECR repository name (e.g. izgateway-dev-phiz-web-ws) |
image-tag |
✅ | — | Image tag pushed to ECR — {version}-RELEASE-{run} format |
gh-pkg-name |
✅ | — | GitHub package name used in CDC file naming (e.g. izgw-hub) |
release-date |
✅ | — | ISO date (YYYY-MM-DD) — filters findings to vendorCreatedAt ≤ this date |
aws-region |
❌ | us-east-1 |
AWS region where Inspector2 is enabled |
artifact-retention-days |
❌ | 90 |
Days to retain the uploaded scan artifact |
The workflow uses secrets: inherit — no explicit secret mapping is required in the caller.
Add an ecr-scan-report job to your release/publish workflow after the job that pushes to ECR.
That job must expose image_tag and release_date as named outputs.
jobs:
push-to-aphl:
outputs:
image_tag: ${{ steps.push.outputs.image_tag }}
release_date: ${{ steps.push.outputs.release_date }}
steps:
# ... build and push steps ...
- name: Set outputs
id: push
run: |
echo "image_tag=${VERSION}-RELEASE-${{ github.run_number }}" >> "$GITHUB_OUTPUT"
echo "release_date=$(date -u +%Y-%m-%d)" >> "$GITHUB_OUTPUT"
ecr-scan-report:
uses: IZGateway/izg-dependency-scripts/.github/workflows/ecr-scan-report.yml@v1
needs: [push-to-aphl]
if: always() && needs.push-to-aphl.result == 'success'
permissions:
id-token: write # required for OIDC token exchange (AWS credential configuration)
contents: read # required for actions/checkout inside the called workflow
with:
ecr-repository: <your-ecr-repo-name>
image-tag: ${{ needs.push-to-aphl.outputs.image_tag }}
gh-pkg-name: <your-github-package-name>
release-date: ${{ needs.push-to-aphl.outputs.release_date }}
secrets: inheritThe calling repository must have AWS_ROLE_ARN set as a repository or environment variable
(Settings → Secrets and variables → Variables). This is the ARN of the OIDC role assumed
during the workflow run.
The OIDC role must include inspector2:ListFindings.
Adding this permission to all service OIDC roles is tracked in
IGDD-2151.
Comprehensive automated vulnerability fixer
- ✅ Updates direct dependencies to latest compatible versions
- ✅ Adds overrides for transitive dependencies
- ✅ Handles parent package update scenarios intelligently
- ✅ Queries npm registry for latest versions
- ✅ Processes all severity levels (critical, high, moderate, low)
Example:
$ fix-vulnerabilities
🔍 Comprehensive Vulnerability Fixer - Analyzing and fixing vulnerabilities...
Found 13 vulnerable packages
⬆ jest-environment-jsdom: Updating direct dependency (29.7.0 → 30.2.0)
➕ jsdom: Adding override 28.1.0 (low, currently: 20.0.3)
➕ dompurify: Adding override 3.3.2 (moderate)
=== Applying Fixes ===
✅ Updated package.jsonAnalyzes and removes unnecessary overrides — without weakening security posture.
For each entry in package.json overrides, the script trial-removes the override in
a scratch copy of your tree (under os.tmpdir()), runs npm install --package-lock-only,
and inspects the regenerated lockfile. If the natural resolution (what npm would pick
without the override) is at or above the override floor, the override is removed.
If the natural resolution would drop below the floor, the override is kept. The
consumer's working tree is not modified except for package.json (and only when
overrides were removed).
Each override receives one of three outcomes:
| Outcome | Meaning |
|---|---|
kept |
Removing the override would cause at least one resolved instance to fall below the override floor. Override stays. |
removed |
Natural resolution already meets the floor everywhere (or the package is no longer in the graph). |
skipped |
The trial could not be completed (npm error, registry failure, non-string override, etc.). Override stays by default. |
Exit codes:
| Code | Meaning |
|---|---|
0 |
Evaluation completed. Overrides may have been removed, kept, or skipped — all are normal outcomes. |
1 |
Genuine failure before/while evaluating: missing or unparseable package.json / package-lock.json, scratch setup failure, or an uncaught exception. |
A skipped outcome (e.g. an aliased npm:<pkg>@<range> override that isn't valid
semver, or a nested override object) is not an error and does not affect the exit
code. Callers detect whether package.json changed via git diff, the same contract
used by update-overrides and fix-vulnerabilities — they should invoke this script
without an error guard and expect 0 on any successful run.
Example:
$ test-overrides
Analyzing overrides via trial removal in a scratch tree...
Checking override: postcss@8.5.15
✓ Kept: natural resolution would drop to 8.4.31
Checking override: prismjs@1.30.0
✗ Removed: natural resolution: 1.30.0
Updated package.json — removed 1 override(s)
=== Override evaluation summary ===
postcss@8.5.15 kept (natural resolution would drop to 8.4.31)
prismjs@1.30.0 removed (natural resolution: 1.30.0)Updates existing overrides to latest minor versions
- Queries npm registry for each override
- Finds latest compatible version (same major)
- Updates package.json with newer versions
Example:
$ update-overrides
Updating packages in overrides section...
⬆ prismjs: 1.29.0 → 1.30.0
✓ dompurify: Already at latest (3.2.5)
=== Updated Overrides ===
prismjs: 1.29.0 → 1.30.0
✓ Updated package.json with latest override versionsOur recommended workflow in security-updates.yml:
1. ncu --target minor # Update direct deps to latest minor
2. update-overrides # Update existing overrides
3. fix-vulnerabilities # Fix all vulnerabilities
4. test-overrides # Remove obsolete overrides
5. npm install # Update lock file
6. Run tests # Verify everything works
7. Create PR # Submit for review# Fix security issues
npm run fix-vulnerabilities
npm install
npm audit
# Run tests
npm test
# Commit changes
git add package.json package-lock.json
git commit -m "chore(deps): fix security vulnerabilities"- Node.js: >= 18.0.0
- npm: >= 9.0.0
- Dependencies: semver (peer dependency)
These scripts are designed with security in mind:
- ✅ Never installs packages without user awareness
- ✅ Only updates to non-breaking versions (same major)
- ✅ Logs all changes for review
- ✅ Works with
package-lock.jsonfor reproducibility - ✅ Respects blocklist for known breaking changes
- ✅ Handles meta-packages to avoid peer dependency conflicts
Blocklist: Packages that require manual review:
immutable- v3 → v5 breaks swagger-ui-react
Meta-packages: Packages that bundle multiple sub-packages:
typescript-eslint- Bundles @typescript-eslint/eslint-plugin, @typescript-eslint/parser, etc.- When multiple sub-packages are direct dependencies, the script updates them all together to maintain version consistency
- When only one sub-package is direct AND the meta-package is installed transitively, the script uses overrides to avoid peer dependency conflicts
- Quick Start: See Installation above
- Detailed Guide: See SHARED_SCRIPTS_GUIDE.md in this repo
- API Reference: Run commands with
--helpflag - Contributing: See CONTRIBUTING.md
We welcome contributions! Please:
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests if applicable
- Submit a pull request
See CHANGELOG.md for detailed version history.
- 1.0.0 (2026-03-06) - Initial release with fix-vulnerabilities, test-overrides, update-overrides
Found a bug or have a feature request?
- Check existing issues
- Create a new issue with:
- Description of the problem
- Steps to reproduce
- Expected vs actual behavior
- Your environment (Node version, npm version, OS)
MIT © IZGateway Team
See LICENSE file for details.
- Documentation: This README and SHARED_SCRIPTS_GUIDE.md
- Issues: GitHub Issues
- Team: Contact IZGateway development team
Made with ❤️ by the IZGateway Team