The Problem
Production bundles commonly include unnecessary files—documentation, config artifacts, source maps, test files, and tooling configs—that inflate size and slow deployments. Manually curating ignore patterns across environments is repetitive and error-prone. This repo provides a universal generator that produces gitignore-compatible exclusion rules automatically, targeting only what’s non-essential for a given build.
What This Does
untracked scans a project and generates ignore patterns covering documentation (README, CHANGELOG, LICENSE), tooling configs (Makefile, jest.config.js, karma.conf.js), assets (*.map, *.d.ts, *.flow), and common artifacts (coverage/, docs/, test*). It then reads production dependencies via npm ls --prod and emits rules that exclude everything else while preserving your dependency tree. Key internal files drive this: src/index.js defines the core flow (doNotIgnore, cleanup, untrackedWrite, untracked, removeBlacklistedDeps), while src/load-config.js handles config resolution (loadConfig, createCollection). src/default/blacklist.js provides pattern logic (capitalize, cases), and src/getProductionDeps.js resolves production dependency structure (flattenDeps, readProductionDeps). The module graph has 5 internal modules and 4 import edges with no circular dependencies, making the wiring flat and auditable. Configuration is supported via an untracked field in package.json or cosmiconfig formats (.untrackedrc, .untrackedrc.json, .untrackedrc.js, untracked.config.js).
How It Is Wired
Execution starts at src/index.js:35 (untracked), called from 2 places, which reaches 2 subsidiary functions. A distinct startup trigger is src/index.js:13 (untrackedWrite), which reaches 3 functions and is called by nothing else in the repo, making it the sole entry point for generated output. The call graph shows loadConfig invoked from 3 locations (instability 0.33), capitalize and flattenDeps each from 2. src/index is the central hub (Ca 0, Ce 2, instability 1); changes to its 6 functions propagate widely. src/load-config is imported by 2 modules (Ca 2, Ce 1). bin/index has no outgoing calls within the repo (Ca 0, Ce 1). The module graph confirms no cycles, so modifications to any single function have predictable, bounded impact—ideal for targeted changes in CI pipelines or bundle optimization.
How To Use It
Setup: Install via npm install untracked -g (or add as project dependency). The repo’s package.json implies npm/pnpm usage; no lockfile is currently committed, so installs resolve ranges.
Configuration: Add an untracked section to package.json, or place a config file (.untrackedrc, .untrackedrc.json, .untrackedrc.js, or untracked.config.js) at root. Fields whitelist, blacklist, and write control inclusion/exclusion and in-place update behavior. The .github/workflows/main.yml files manage CI integration but do not define untracked settings.
Running it:
npx untracked # generate to stdout
npx untracked > .dockerignore # write to docker ignore
npx untracked --write .dockerignore # update in place, preserving custom rules
For platform-specific pipelines, add npx untracked > .vercelignore to a Vercel prebuild script, or redirect output to .slugignore in a Heroku prebuild step.
Real-World Use
A team preparing a Docker image adds npx untracked > .dockerignore to their package.json prebuild script. The generated file excludes README.md, CHANGELOG.md, *.map, *.d.ts, coverage/, test*, and similar artifacts, leaving only production code and dependencies. The resulting image is significantly smaller, and the ignore file is versioned alongside the app. If the team later adds custom ignore rules, npx untracked --write .dockerignore merges new auto-generated patterns between ### start and ### finished markers, preserving hand-written exceptions.
Code Health & Issues
- [HIGH] Pin third-party GitHub Actions to a commit SHA –
.github/workflowsevidence:pnpm/action-setup@v6. A tag can move, so the action running with your token and secrets is whatever its owner last pushed; this is the vector by whichtj-actions/changed-filesleaked secrets from thousands of repos. Fix: replace@vNwith the 40-character commit SHA and let Dependabot bump SHAs. - [HIGH] Commit a lockfile beside the manifest –
package.jsonhas no lockfile. An unlocked range means the artifact tested and the artifact shipped can differ, allowing a malicious patch release to reach production with no diff. Fix: run the package manager once and commit the generated lockfile. - [MEDIUM] Declare least-privilege permissions for GITHUB_TOKEN –
.github/workflows/main.ymlhas 2 workflows declaring no permissions, 2 referencing secrets. Without declaration, the token inherits the repository default, allowing any injected step to push commits or mint releases from inside your own CI. Fix: addpermissions: contents: readat the top of the workflow and widen per job only where needed. - [MEDIUM] Gate pull requests on a dependency vulnerability scan – No dependency scan is configured in CI. This is the one gate that would catch a known-vulnerable package before it reaches a build, and no repository in the sample had it. Fix: add
dependency-review-actiononpull_request, orosv-scanneron push and a schedule. - [MEDIUM] Set persist-credentials: false on checkout –
checkoutkeeps the token, then dependencies are installed. The token stays in.git/configfor every later step, so a maliciouspostinstallscript reads a pushable credential without one ever being passed to it. Fix: addwith: persist-credentials: false, and pass an explicit token only to the step that pushes. - [LOW] Set timeout-minutes on the workflow jobs – 2 workflow(s) declare no job timeout. A wedged step runs to the six-hour platform default, which on a two-hourly schedule means three runs overlap behind it. Fix: add
timeout-minuteswith a realistic bound to each job.
Repository hygiene: no test files detected, CI uses GitHub Actions, no Dockerfile present, license (MIT) is present, no lockfile committed, no committed secrets found.
The Bottom Line
This repo delivers a focused, well-wired utility that automatically generates production‑ready ignore patterns, with a clean internal module graph and no circular dependencies. The main risks are operational: unpinned GitHub Actions, a missing lockfile, and CI configurations that lack least-privilege token controls and vulnerability scanning. Teams that prioritize lean bundle sizes and already manage CI via GitHub Actions will find immediate value; those needing extensive test coverage or strict supply‑chain hardening will need to address the measured findings before integrating into high‑security pipelines.