Dependencies & Supply Chain
Versioning, lockfiles, and the code you did not write but do ship.
Questions
Easy / Med / Hard
Your accuracy
Most of what you deploy is code somebody else wrote. Managing that is a first-class engineering concern.
Semantic versioning encodes intent in MAJOR.MINOR.PATCH: major means a breaking change, minor adds functionality compatibly, patch fixes bugs compatibly. Range specifiers build on it — a caret (^1.2.3) accepts minor and patch updates, a tilde (~1.2.3) accepts only patch. The convention only helps to the extent maintainers honour it, which is why lockfiles exist.
A lockfile records the exact resolved version of every package, including transitive ones. Without it, two installs a week apart produce different dependency trees, and "works on my machine" becomes literally true. Commit it, and use the CI-specific install command (npm ci, pnpm install --frozen-lockfile) so a build fails rather than silently resolving something new.
Transitive dependencies are where the risk concentrates. You choose ten packages and install four hundred. Most of what ships is code you never evaluated, from maintainers you have never heard of.
Supply chain attacks exploit exactly that. Typosquatting registers names close to popular packages. Dependency confusion publishes a public package matching your private internal name, hoping the resolver prefers the public registry. A compromised maintainer account pushes a malicious patch release that everyone on a caret range picks up automatically. Installation itself can run scripts, so the damage happens before your code executes.
An SBOM — software bill of materials — is the inventory of everything you ship, and it is what makes "are we affected by this CVE?" answerable in minutes rather than days.
Keep dependencies current in small increments. A dependency two years stale is not a stable dependency, it is a migration you have deferred, and the security patch will arrive when you least want the work.