{"authors":[{"name":"Martin Stühmer","url":"https://daily-devops.net/authors/martin/"},{"name":"Jendrik Brack","url":"https://daily-devops.net/authors/jendrik/"}],"description":"Recent content in Dependency Management for .NET Projects on Daily DevOps \u0026 .NET","favicon":"https://daily-devops.net/images/logo_hu_6465d873dfa490cf.png","feed_url":"https://daily-devops.net/tags/dependency-management/feed.json","home_page_url":"https://daily-devops.net/tags/dependency-management/","icon":"https://daily-devops.net/images/logo_hu_5926de77762241ba.png","items":[{"authors":[{"name":"Martin Stühmer","url":"https://daily-devops.net/authors/martin/"}],"content_html":"\u003cp\u003eYour organization probably has a detailed vendor approval process. Procurement forms. Security questionnaires. Legal reviews. Contract negotiations that span months.\u003c/p\u003e\n\u003cp\u003eAnd then your developers add \u003ccode\u003enpm install some-random-package\u003c/code\u003e to the build script, pulling in 247 transitive dependencies from strangers on the internet, and nobody blinks.\u003c/p\u003e\n\u003cp\u003eThat\u0026rsquo;s the supply chain security paradox. ISO/IEC 27001 Control A.15 demands rigorous supplier relationship management—but most organizations treat their dependency tree as if it doesn\u0026rsquo;t exist. The SolarWinds breach, the Log4Shell vulnerability, and countless package hijacking incidents prove this oversight isn\u0026rsquo;t theoretical. Your dependencies \u003cem\u003eare\u003c/em\u003e your suppliers, and they\u0026rsquo;re the ones with root access.\u003c/p\u003e\n\u003cp\u003eGitHub Dependabot, dependency review actions, and Software Bill of Materials (SBOM) generation aren\u0026rsquo;t trendy DevOps tools. They\u0026rsquo;re the technical implementation of what ISO 27001 actually requires in A.15.1.1 (Information security policy for supplier relationships), A.15.1.3 (Information and communication technology supply chain), and A.15.2.1 (Monitoring and review of supplier services). Here\u0026rsquo;s how to implement them properly—and why treating this as optional is compliance theater.\u003c/p\u003e\n\n\n\n\n\u003ch2 id=\"the-fatal-approach-trust-without-verification\"\u003e\u003ca href=\"/posts/supply-chain-security-github-dependabot/#the-fatal-approach-trust-without-verification\" title=\"The Fatal Approach: Trust Without Verification\"\u003eThe Fatal Approach: Trust Without Verification\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eLet me show you what most organizations actually do when it comes to dependency management. This is disturbingly common:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003e# .github/workflows/ci.yml - The \u0026#34;we have CI at home\u0026#34; version\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003ename\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l\"\u003eCI\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003eon\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"l\"\u003epush, pull_request]\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003ejobs\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e  \u003c/span\u003e\u003cspan class=\"nt\"\u003ebuild\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"nt\"\u003eruns-on\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l\"\u003eubuntu-latest\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"nt\"\u003esteps\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e      \u003c/span\u003e- \u003cspan class=\"nt\"\u003euses\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l\"\u003eactions/checkout@v4\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e      \n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e      \u003c/span\u003e- \u003cspan class=\"nt\"\u003ename\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l\"\u003eSetup .NET\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e        \u003c/span\u003e\u003cspan class=\"nt\"\u003euses\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l\"\u003eactions/setup-dotnet@v4\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e        \u003c/span\u003e\u003cspan class=\"nt\"\u003ewith\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e          \u003c/span\u003e\u003cspan class=\"nt\"\u003edotnet-version\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;9.0.x\u0026#39;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e      \n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e      \u003c/span\u003e- \u003cspan class=\"nt\"\u003ename\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l\"\u003eRestore dependencies\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e        \u003c/span\u003e\u003cspan class=\"nt\"\u003erun\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l\"\u003edotnet restore\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e      \n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e      \u003c/span\u003e- \u003cspan class=\"nt\"\u003ename\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l\"\u003eBuild\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e        \u003c/span\u003e\u003cspan class=\"nt\"\u003erun\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l\"\u003edotnet build --no-restore\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e      \n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e      \u003c/span\u003e- \u003cspan class=\"nt\"\u003ename\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l\"\u003eTest\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e        \u003c/span\u003e\u003cspan class=\"nt\"\u003erun\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l\"\u003edotnet test --no-build\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eLooks reasonable? It\u0026rsquo;s not. Here\u0026rsquo;s what\u0026rsquo;s happening behind the scenes:\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eNo dependency vulnerability scanning.\u003c/strong\u003e The pipeline blindly restores whatever\u0026rsquo;s in your lock file. If a package has a critical CVE published yesterday, this build will still succeed. The automated security update emails from GitHub? Developers ignore those. They\u0026rsquo;re busy shipping features.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eNo review of new dependencies.\u003c/strong\u003e Pull requests that add 15 new packages go through the same review process as typo fixes. Reviewers check the code logic but ignore that the developer just gave a package maintainer they\u0026rsquo;ve never heard of the ability to exfiltrate environment variables during the build.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eNo Software Bill of Materials.\u003c/strong\u003e When you need to answer \u0026ldquo;do we use this vulnerable component?\u0026rdquo; you grep through lock files manually and hope transitive dependencies aren\u0026rsquo;t hiding something. Auditors ask for your supplier list, and you hand them a procurement spreadsheet that doesn\u0026rsquo;t mention the 847 npm packages running in production.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eAutomatic merging without context.\u003c/strong\u003e Some teams enable Dependabot but configure it to auto-merge. Congratulations, you\u0026rsquo;ve automated the process of giving strangers write access to production with zero review:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003e# .github/dependabot.yml - The \u0026#34;what could go wrong?\u0026#34; configuration\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003eversion\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e2\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003eupdates\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e  \u003c/span\u003e- \u003cspan class=\"nt\"\u003epackage-ecosystem\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;nuget\u0026#34;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"nt\"\u003edirectory\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;/\u0026#34;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"nt\"\u003eschedule\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e      \u003c/span\u003e\u003cspan class=\"nt\"\u003einterval\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;weekly\u0026#34;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"c\"\u003e# Auto-merge enabled elsewhere, no version constraints, no review required\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003cstrong\u003eNo package source verification.\u003c/strong\u003e Your \u003ccode\u003enuget.config\u003c/code\u003e allows any source. Developers occasionally switch to alternative feeds \u0026ldquo;temporarily\u0026rdquo; to test something. Those sources stick around. Nobody verifies package signatures because .NET doesn\u0026rsquo;t enforce it by default.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eNo incident response integration.\u003c/strong\u003e Your IR plan has sections for ransomware and DDoS attacks but nothing for supply chain compromises. When a widely-used package is hijacked, you spend three days figuring out if you\u0026rsquo;re affected instead of checking an SBOM and responding in minutes.\u003c/p\u003e\n\u003cp\u003eThis isn\u0026rsquo;t negligence—it\u0026rsquo;s the default state. And it violates every principle ISO 27001 A.15 tries to enforce.\u003c/p\u003e\n\n\n\n\n\u003ch2 id=\"iso-27001-a15-what-the-standard-actually-requires\"\u003e\u003ca href=\"/posts/supply-chain-security-github-dependabot/#iso-27001-a15-what-the-standard-actually-requires\" title=\"ISO 27001 A.15: What the Standard Actually Requires\"\u003eISO 27001 A.15: What the Standard Actually Requires\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eLet\u0026rsquo;s map the standard to reality. ISO 27001\u0026rsquo;s supplier relationship controls aren\u0026rsquo;t written with NuGet in mind, but the requirements are unambiguous:\u003c/p\u003e\n\n\n\n\n\u003ch3 id=\"a1511-information-security-policy-for-supplier-relationships\"\u003e\u003ca href=\"/posts/supply-chain-security-github-dependabot/#a1511-information-security-policy-for-supplier-relationships\" title=\"A.15.1.1: Information Security Policy for Supplier Relationships\"\u003eA.15.1.1: Information Security Policy for Supplier Relationships\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e\u003cem\u003e\u0026ldquo;Information security requirements for mitigating the risks associated with supplier\u0026rsquo;s access to the organization\u0026rsquo;s assets shall be agreed with the supplier and documented.\u0026rdquo;\u003c/em\u003e\u003c/p\u003e\n\u003cp\u003eTranslation: You need a defined approval process for dependencies. Adding a new package isn\u0026rsquo;t just a developer decision—it\u0026rsquo;s introducing a new supplier relationship. That means:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eSecurity review before introduction\u003c/strong\u003e: New dependencies require explicit approval with documented risk assessment.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eApproved sources only\u003c/strong\u003e: Package feeds must be controlled and validated.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eContractual clarity\u003c/strong\u003e: Even open-source dependencies have terms (licenses) that need review.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eIn .NET terms, this means dependency review workflows that block unapproved packages and enforce source restrictions.\u003c/p\u003e\n\n\n\n\n\u003ch3 id=\"a1513-information-and-communication-technology-supply-chain\"\u003e\u003ca href=\"/posts/supply-chain-security-github-dependabot/#a1513-information-and-communication-technology-supply-chain\" title=\"A.15.1.3: Information and Communication Technology Supply Chain\"\u003eA.15.1.3: Information and Communication Technology Supply Chain\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e\u003cem\u003e\u0026ldquo;Agreements with suppliers shall include requirements to address the information security risks associated with information and communications technology services and product supply chain.\u0026rdquo;\u003c/em\u003e\u003c/p\u003e\n\u003cp\u003eTranslation: You need to know what\u0026rsquo;s in your supply chain. Not just direct dependencies—transitive ones too. And you need mechanisms to respond when components are compromised.\u003c/p\u003e\n\u003cp\u003eThis is where SBOMs become mandatory, not nice-to-have. The standard explicitly requires supply chain visibility.\u003c/p\u003e\n\n\n\n\n\u003ch3 id=\"a1521-monitoring-and-review-of-supplier-services\"\u003e\u003ca href=\"/posts/supply-chain-security-github-dependabot/#a1521-monitoring-and-review-of-supplier-services\" title=\"A.15.2.1: Monitoring and Review of Supplier Services\"\u003eA.15.2.1: Monitoring and Review of Supplier Services\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e\u003cem\u003e\u0026ldquo;Organizations shall regularly monitor, review and audit supplier service delivery.\u0026rdquo;\u003c/em\u003e\u003c/p\u003e\n\u003cp\u003eTranslation: It\u0026rsquo;s not enough to approve dependencies once. You need continuous monitoring for vulnerabilities, license changes, and maintenance status.\u003c/p\u003e\n\u003cp\u003eDependabot security updates and dependency freshness checks aren\u0026rsquo;t automation luxuries—they\u0026rsquo;re compliance requirements.\u003c/p\u003e\n\n\n\n\n\u003ch2 id=\"the-correct-approach-defense-in-depth-for-dependencies\"\u003e\u003ca href=\"/posts/supply-chain-security-github-dependabot/#the-correct-approach-defense-in-depth-for-dependencies\" title=\"The Correct Approach: Defense in Depth for Dependencies\"\u003eThe Correct Approach: Defense in Depth for Dependencies\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eHere\u0026rsquo;s how to implement supply chain security that actually satisfies ISO 27001 controls and prevents breaches. This isn\u0026rsquo;t theoretical—it\u0026rsquo;s based on configurations running in production environments that pass ISO audits.\u003c/p\u003e\n\n\n\n\n\u003ch3 id=\"step-1-configure-dependabot-for-security-updates\"\u003e\u003ca href=\"/posts/supply-chain-security-github-dependabot/#step-1-configure-dependabot-for-security-updates\" title=\"Step 1: Configure Dependabot for Security Updates\"\u003eStep 1: Configure Dependabot for Security Updates\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003eDependabot is GitHub\u0026rsquo;s built-in tool for monitoring dependencies. Configure it properly:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003e# .github/dependabot.yml\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003eversion\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e2\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003eupdates\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e  \u003c/span\u003e- \u003cspan class=\"nt\"\u003epackage-ecosystem\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;nuget\u0026#34;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"nt\"\u003edirectory\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;/\u0026#34;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"nt\"\u003eschedule\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e      \u003c/span\u003e\u003cspan class=\"nt\"\u003einterval\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;daily\u0026#34;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"nt\"\u003eopen-pull-requests-limit\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e10\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"nt\"\u003etarget-branch\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;main\u0026#34;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"nt\"\u003egroups\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e      \u003c/span\u003e\u003cspan class=\"nt\"\u003eproduction-dependencies\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e        \u003c/span\u003e\u003cspan class=\"nt\"\u003epatterns\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;*\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e        \u003c/span\u003e\u003cspan class=\"nt\"\u003eupdate-types\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;minor\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;patch\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"nt\"\u003elabels\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;dependencies\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;security\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"nt\"\u003eversioning-strategy\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l\"\u003eincrease\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e  \u003c/span\u003e- \u003cspan class=\"nt\"\u003epackage-ecosystem\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;github-actions\u0026#34;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"nt\"\u003edirectory\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;/\u0026#34;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"nt\"\u003eschedule\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e      \u003c/span\u003e\u003cspan class=\"nt\"\u003einterval\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;weekly\u0026#34;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"nt\"\u003elabels\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;dependencies\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;github-actions\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003cstrong\u003eWhy this works\u003c/strong\u003e: Daily security scans ensure vulnerabilities are detected within 24 hours. Grouping minor updates reduces notification fatigue. Separate GitHub Actions updates prevent action supply chain attacks (yes, those happen too).\u003c/p\u003e\n\n\n\n\n\u003ch3 id=\"step-2-implement-dependency-review-action\"\u003e\u003ca href=\"/posts/supply-chain-security-github-dependabot/#step-2-implement-dependency-review-action\" title=\"Step 2: Implement Dependency Review Action\"\u003eStep 2: Implement Dependency Review Action\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003eBlock PRs that introduce known vulnerabilities before they merge:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003e# .github/workflows/dependency-review.yml\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003ename\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l\"\u003eDependency Review\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003eon\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e  \u003c/span\u003e\u003cspan class=\"nt\"\u003epull_request\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"nt\"\u003ebranches\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"l\"\u003emain, develop]\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003epermissions\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e  \u003c/span\u003e\u003cspan class=\"nt\"\u003econtents\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l\"\u003eread\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e  \u003c/span\u003e\u003cspan class=\"nt\"\u003epull-requests\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l\"\u003ewrite\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003ejobs\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e  \u003c/span\u003e\u003cspan class=\"nt\"\u003edependency-review\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"nt\"\u003eruns-on\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l\"\u003eubuntu-latest\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"nt\"\u003esteps\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e      \u003c/span\u003e- \u003cspan class=\"nt\"\u003euses\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l\"\u003eactions/checkout@v4\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e      \u003c/span\u003e- \u003cspan class=\"nt\"\u003euses\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l\"\u003eactions/dependency-review-action@v4\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e        \u003c/span\u003e\u003cspan class=\"nt\"\u003ewith\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e          \u003c/span\u003e\u003cspan class=\"nt\"\u003efail-on-severity\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l\"\u003emoderate\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e          \u003c/span\u003e\u003cspan class=\"nt\"\u003edeny-licenses\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l\"\u003eGPL-2.0, GPL-3.0, AGPL-3.0\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e          \u003c/span\u003e\u003cspan class=\"nt\"\u003ewarn-on-stale-maintainers\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kc\"\u003etrue\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e          \u003c/span\u003e\u003cspan class=\"nt\"\u003ecomment-summary-in-pr\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l\"\u003ealways\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003cstrong\u003eWhy this matters\u003c/strong\u003e: This implements A.15.1.1\u0026rsquo;s requirement for security assessment before supplier introduction. Developers get instant feedback in the PR. Security teams have audit trails of what was blocked and why.\u003c/p\u003e\n\n\n\n\n\u003ch3 id=\"step-3-generate-and-publish-sboms\"\u003e\u003ca href=\"/posts/supply-chain-security-github-dependabot/#step-3-generate-and-publish-sboms\" title=\"Step 3: Generate and Publish SBOMs\"\u003eStep 3: Generate and Publish SBOMs\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003eSoftware Bill of Materials makes your dependency tree visible and queryable:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003e# .github/workflows/sbom.yml\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003ename\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l\"\u003eGenerate SBOM\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003eon\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e  \u003c/span\u003e\u003cspan class=\"nt\"\u003epush\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"nt\"\u003ebranches\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"l\"\u003emain]\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e  \u003c/span\u003e\u003cspan class=\"nt\"\u003erelease\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"nt\"\u003etypes\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"l\"\u003epublished]\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003epermissions\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e  \u003c/span\u003e\u003cspan class=\"nt\"\u003econtents\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l\"\u003ewrite\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e  \u003c/span\u003e\u003cspan class=\"nt\"\u003eid-token\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l\"\u003ewrite\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003ejobs\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e  \u003c/span\u003e\u003cspan class=\"nt\"\u003esbom\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"nt\"\u003eruns-on\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l\"\u003eubuntu-latest\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"nt\"\u003esteps\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e      \u003c/span\u003e- \u003cspan class=\"nt\"\u003euses\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l\"\u003eactions/checkout@v4\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e      \u003c/span\u003e- \u003cspan class=\"nt\"\u003euses\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l\"\u003eactions/setup-dotnet@v4\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e        \u003c/span\u003e\u003cspan class=\"nt\"\u003ewith\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e          \u003c/span\u003e\u003cspan class=\"nt\"\u003edotnet-version\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;9.0.x\u0026#39;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e      \u003c/span\u003e- \u003cspan class=\"nt\"\u003erun\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l\"\u003edotnet restore\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e      \u003c/span\u003e- \u003cspan class=\"nt\"\u003ename\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l\"\u003eGenerate SBOM\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e        \u003c/span\u003e\u003cspan class=\"nt\"\u003erun\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e|\u003c/span\u003e\u003cspan class=\"sd\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"sd\"\u003e          dotnet tool install --global Microsoft.Sbom.DotNetTool\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"sd\"\u003e          sbom-tool generate -b ./bin/sbom -bc . \\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"sd\"\u003e            -pn \u0026#34;YourProject\u0026#34; -pv \u0026#34;1.0.0\u0026#34; -ps \u0026#34;YourOrganization\u0026#34;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e      \u003c/span\u003e- \u003cspan class=\"nt\"\u003euses\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l\"\u003eactions/upload-artifact@v4\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e        \u003c/span\u003e\u003cspan class=\"nt\"\u003ewith\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e          \u003c/span\u003e\u003cspan class=\"nt\"\u003ename\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l\"\u003esbom\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e          \u003c/span\u003e\u003cspan class=\"nt\"\u003epath\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l\"\u003e./bin/sbom/_manifest/spdx_2.2/manifest.spdx.json\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e          \u003c/span\u003e\u003cspan class=\"nt\"\u003eretention-days\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e90\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003cstrong\u003eWhy this is critical\u003c/strong\u003e: When CVE-2024-XXXXX drops, you query your SBOM inventory instead of manually searching codebases. Attestation provides cryptographic proof the SBOM hasn\u0026rsquo;t been tampered with. This satisfies A.15.1.3\u0026rsquo;s supply chain visibility requirement.\u003c/p\u003e\n\n\n\n\n\u003ch3 id=\"step-4-package-approval-workflow\"\u003e\u003ca href=\"/posts/supply-chain-security-github-dependabot/#step-4-package-approval-workflow\" title=\"Step 4: Package Approval Workflow\"\u003eStep 4: Package Approval Workflow\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003eRequire security team approval for new dependencies:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003e# .github/workflows/package-approval.yml\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003ename\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l\"\u003ePackage Approval\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003eon\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e  \u003c/span\u003e\u003cspan class=\"nt\"\u003epull_request\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"nt\"\u003epaths\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e      \u003c/span\u003e- \u003cspan class=\"s1\"\u003e\u0026#39;**/packages.lock.json\u0026#39;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e      \u003c/span\u003e- \u003cspan class=\"s1\"\u003e\u0026#39;**/*.csproj\u0026#39;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e      \u003c/span\u003e- \u003cspan class=\"s1\"\u003e\u0026#39;**/package.json\u0026#39;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003epermissions\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e  \u003c/span\u003e\u003cspan class=\"nt\"\u003econtents\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l\"\u003eread\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e  \u003c/span\u003e\u003cspan class=\"nt\"\u003epull-requests\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l\"\u003ewrite\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003ejobs\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e  \u003c/span\u003e\u003cspan class=\"nt\"\u003edetect-new-packages\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"nt\"\u003eruns-on\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l\"\u003eubuntu-latest\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"nt\"\u003esteps\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e      \u003c/span\u003e- \u003cspan class=\"nt\"\u003euses\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l\"\u003eactions/checkout@v4\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e        \u003c/span\u003e\u003cspan class=\"nt\"\u003ewith\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e          \u003c/span\u003e\u003cspan class=\"nt\"\u003efetch-depth\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e0\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e      \u003c/span\u003e- \u003cspan class=\"nt\"\u003ename\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l\"\u003eDetect new dependencies\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e        \u003c/span\u003e\u003cspan class=\"nt\"\u003eid\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l\"\u003edetect\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e        \u003c/span\u003e\u003cspan class=\"nt\"\u003erun\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e|\u003c/span\u003e\u003cspan class=\"sd\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"sd\"\u003e          git diff origin/${{ github.base_ref }}...HEAD --name-only | \\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"sd\"\u003e            grep -E \u0026#39;lock\\.json\u0026#39; \u0026gt; changed.txt || true\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"sd\"\u003e          [ -s changed.txt ] \u0026amp;\u0026amp; echo \u0026#34;new_deps=true\u0026#34; \u0026gt;\u0026gt; $GITHUB_OUTPUT\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e      \u003c/span\u003e- \u003cspan class=\"nt\"\u003ename\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l\"\u003eRequest security review\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e        \u003c/span\u003e\u003cspan class=\"nt\"\u003eif\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l\"\u003esteps.detect.outputs.new_deps == \u0026#39;true\u0026#39;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e        \u003c/span\u003e\u003cspan class=\"nt\"\u003euses\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l\"\u003eactions/github-script@v7\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e        \u003c/span\u003e\u003cspan class=\"nt\"\u003ewith\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e          \u003c/span\u003e\u003cspan class=\"nt\"\u003escript\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e|\u003c/span\u003e\u003cspan class=\"sd\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"sd\"\u003e            github.rest.pulls.requestReviewers({\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"sd\"\u003e              ...context.repo, pull_number: context.issue.number,\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"sd\"\u003e              team_reviewers: [\u0026#39;security-team\u0026#39;]\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"sd\"\u003e            });\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003cstrong\u003eWhy this works\u003c/strong\u003e: A.15.1.1 requires documented supplier approval. This workflow creates an audit trail: who approved what dependency, when, and based on what criteria. Compliance evidence that actually exists when auditors ask.\u003c/p\u003e\n\n\n\n\n\u003ch3 id=\"step-5-continuous-dependency-health-monitoring\"\u003e\u003ca href=\"/posts/supply-chain-security-github-dependabot/#step-5-continuous-dependency-health-monitoring\" title=\"Step 5: Continuous Dependency Health Monitoring\"\u003eStep 5: Continuous Dependency Health Monitoring\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003eMonitor dependency freshness and vulnerability status:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003e# .github/workflows/dependency-health.yml\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003ename\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l\"\u003eDependency Health Check\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003eon\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e  \u003c/span\u003e\u003cspan class=\"nt\"\u003eschedule\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e- \u003cspan class=\"nt\"\u003ecron\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;0 6 * * 1\u0026#39;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e  \u003c/span\u003e\u003cspan class=\"nt\"\u003eworkflow_dispatch\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003epermissions\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e  \u003c/span\u003e\u003cspan class=\"nt\"\u003econtents\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l\"\u003eread\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e  \u003c/span\u003e\u003cspan class=\"nt\"\u003eissues\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l\"\u003ewrite\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003ejobs\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e  \u003c/span\u003e\u003cspan class=\"nt\"\u003ehealth-check\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"nt\"\u003eruns-on\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l\"\u003eubuntu-latest\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"nt\"\u003esteps\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e      \u003c/span\u003e- \u003cspan class=\"nt\"\u003euses\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l\"\u003eactions/checkout@v4\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e      \u003c/span\u003e- \u003cspan class=\"nt\"\u003euses\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l\"\u003eactions/setup-dotnet@v4\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e        \u003c/span\u003e\u003cspan class=\"nt\"\u003ewith\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e          \u003c/span\u003e\u003cspan class=\"nt\"\u003edotnet-version\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;9.0.x\u0026#39;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e      \u003c/span\u003e- \u003cspan class=\"nt\"\u003ename\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l\"\u003eCheck vulnerabilities\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e        \u003c/span\u003e\u003cspan class=\"nt\"\u003eid\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l\"\u003evuln\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e        \u003c/span\u003e\u003cspan class=\"nt\"\u003erun\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e|\u003c/span\u003e\u003cspan class=\"sd\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"sd\"\u003e          dotnet list package --vulnerable --include-transitive \u0026gt; vuln.txt\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"sd\"\u003e          grep -q \u0026#34;\u0026gt;\u0026#34; vuln.txt \u0026amp;\u0026amp; echo \u0026#34;found=true\u0026#34; \u0026gt;\u0026gt; $GITHUB_OUTPUT || true\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e      \u003c/span\u003e- \u003cspan class=\"nt\"\u003ename\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l\"\u003eCreate issue\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e        \u003c/span\u003e\u003cspan class=\"nt\"\u003eif\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l\"\u003esteps.vuln.outputs.found == \u0026#39;true\u0026#39;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e        \u003c/span\u003e\u003cspan class=\"nt\"\u003euses\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l\"\u003eactions/github-script@v7\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e        \u003c/span\u003e\u003cspan class=\"nt\"\u003ewith\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e          \u003c/span\u003e\u003cspan class=\"nt\"\u003escript\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e|\u003c/span\u003e\u003cspan class=\"sd\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"sd\"\u003e            const vuln = require(\u0026#39;fs\u0026#39;).readFileSync(\u0026#39;vuln.txt\u0026#39;, \u0026#39;utf8\u0026#39;);\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"sd\"\u003e            github.rest.issues.create({\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"sd\"\u003e              ...context.repo,\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"sd\"\u003e              title: \u0026#39;Vulnerable Dependencies Detected\u0026#39;,\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"sd\"\u003e              body: \u0026#39;```\\n\u0026#39; + vuln + \u0026#39;\\n```\\nSLA: 7 days for critical.\u0026#39;,\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"sd\"\u003e              labels: [\u0026#39;security\u0026#39;, \u0026#39;dependencies\u0026#39;]\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"sd\"\u003e            });\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003cstrong\u003eWhy this is essential\u003c/strong\u003e: A.15.2.1 requires ongoing monitoring of supplier services. This workflow provides weekly health checks, automatic issue creation for vulnerabilities, and documented SLAs for remediation.\u003c/p\u003e\n\n\n\n\n\u003ch2 id=\"mapping-implementation-to-iso-controls\"\u003e\u003ca href=\"/posts/supply-chain-security-github-dependabot/#mapping-implementation-to-iso-controls\" title=\"Mapping Implementation to ISO Controls\"\u003eMapping Implementation to ISO Controls\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eHere\u0026rsquo;s the explicit compliance mapping auditors need:\u003c/p\u003e\n\u003ctable\u003e\n\t\u003cthead\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003cth\u003eISO 27001 Control\u003c/th\u003e\n\t\t\t\t\t\u003cth\u003eImplementation\u003c/th\u003e\n\t\t\t\t\t\u003cth\u003eEvidence\u003c/th\u003e\n\t\t\t\u003c/tr\u003e\n\t\u003c/thead\u003e\n\t\u003ctbody\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003ctd\u003e\u003cstrong\u003eA.15.1.1\u003c/strong\u003e - Security policy for suppliers\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003ePackage approval workflow requiring security review\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003eGitHub PR approval logs, review checklists, team assignments\u003c/td\u003e\n\t\t\t\u003c/tr\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003ctd\u003e\u003cstrong\u003eA.15.1.3\u003c/strong\u003e - ICT supply chain security\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003eSBOM generation, dependency review action blocking vulnerabilities\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003eSBOM artifacts, dependency-review workflow logs, blocked PR records\u003c/td\u003e\n\t\t\t\u003c/tr\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003ctd\u003e\u003cstrong\u003eA.15.2.1\u003c/strong\u003e - Monitoring supplier services\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003eDependabot security updates, weekly health checks, vulnerability SLA tracking\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003eDependabot PR history, health check workflow runs, issue resolution times\u003c/td\u003e\n\t\t\t\u003c/tr\u003e\n\t\u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp\u003eYour ISMS documentation should reference these workflows as technical controls. Include workflow YAML files as appendices. Point auditors to GitHub Actions logs as evidence of continuous monitoring.\u003c/p\u003e\n\n\n\n\n\u003ch2 id=\"the-hard-parts-nobody-talks-about\"\u003e\u003ca href=\"/posts/supply-chain-security-github-dependabot/#the-hard-parts-nobody-talks-about\" title=\"The Hard Parts Nobody Talks About\"\u003eThe Hard Parts Nobody Talks About\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eImplementing this correctly requires addressing several organizational challenges:\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eAlert fatigue is real.\u003c/strong\u003e Dependabot can generate dozens of PRs weekly. Teams that don\u0026rsquo;t group updates or prioritize security-only PRs end up ignoring all of them. Configure update grouping. Separate security updates (urgent) from version updates (scheduled).\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eBreaking changes break builds.\u003c/strong\u003e Major version updates aren\u0026rsquo;t just security patches—they introduce breaking changes. Your approval workflow should distinguish between patch updates (can be automated) and major updates (require testing). Don\u0026rsquo;t auto-merge everything blindly.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eFalse positives happen.\u003c/strong\u003e Not every CVE applies to your usage pattern. Vulnerability scanners flag issues in dependencies you don\u0026rsquo;t use. Document exceptions explicitly with justification. Auditors understand risk acceptance—they don\u0026rsquo;t understand ignored alerts.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eLicense compliance isn\u0026rsquo;t just security.\u003c/strong\u003e Pulling in GPL dependencies into proprietary software creates legal risk. The dependency review action\u0026rsquo;s license blocking prevents this, but somebody needs to maintain the deny-list based on your organization\u0026rsquo;s license policy.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eSBOMs need governance.\u003c/strong\u003e Generating an SBOM is the easy part. The hard part is: who reviews it? Who\u0026rsquo;s responsible when a component shows up in a breach announcement? Your incident response plan needs SBOM query procedures documented.\u003c/p\u003e\n\n\n\n\n\u003ch2 id=\"when-compliance-meets-reality\"\u003e\u003ca href=\"/posts/supply-chain-security-github-dependabot/#when-compliance-meets-reality\" title=\"When Compliance Meets Reality\"\u003eWhen Compliance Meets Reality\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eISO 27001 certification doesn\u0026rsquo;t require specific tools—it requires demonstrable controls. GitHub Dependabot isn\u0026rsquo;t mandatory. But you need \u003cem\u003esomething\u003c/em\u003e that achieves the same outcomes: documented approval processes, supply chain visibility, continuous monitoring, and vulnerability response SLAs.\u003c/p\u003e\n\u003cp\u003eThe alternative—manual dependency reviews and spreadsheet tracking—technically satisfies the standard but fails in practice. I\u0026rsquo;ve seen organizations attempt manual SBOM maintenance. It becomes outdated within a week and worthless for incident response.\u003c/p\u003e\n\u003cp\u003eAutomation isn\u0026rsquo;t laziness. It\u0026rsquo;s the only practical way to implement supplier relationship controls at the scale of modern software dependencies. A typical .NET microservice has 200+ transitive dependencies. Managing those relationships manually is compliance theater, not security.\u003c/p\u003e\n\n\n\n\n\u003ch2 id=\"practical-implementation-timeline\"\u003e\u003ca href=\"/posts/supply-chain-security-github-dependabot/#practical-implementation-timeline\" title=\"Practical Implementation Timeline\"\u003ePractical Implementation Timeline\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eIf you\u0026rsquo;re starting from zero, here\u0026rsquo;s a realistic rollout:\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eWeek 1\u003c/strong\u003e: Enable Dependabot for security updates only. Don\u0026rsquo;t auto-merge anything yet. Just observe what gets flagged.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eWeek 2\u003c/strong\u003e: Implement dependency review action on new PRs. Set \u003ccode\u003efail-on-severity: high\u003c/code\u003e initially to avoid blocking everything immediately.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eWeek 3\u003c/strong\u003e: Configure SBOM generation for main branch builds. Start collecting SBOMs but don\u0026rsquo;t enforce anything yet.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eWeek 4\u003c/strong\u003e: Add package approval workflow. Route new dependencies to security team review. Document approval criteria.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eWeek 5\u003c/strong\u003e: Enable weekly dependency health checks. Create issues for vulnerabilities automatically but give teams time to establish remediation workflows.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eWeek 6\u003c/strong\u003e: Lower dependency review threshold to \u003ccode\u003emoderate\u003c/code\u003e. At this point, you should have enough data to tune false positive handling.\u003c/p\u003e\n\u003cp\u003eDon\u0026rsquo;t try to implement everything simultaneously. Gradual rollout lets teams adapt and provides time to tune configurations based on real usage patterns.\u003c/p\u003e\n\n\n\n\n\u003ch2 id=\"the-bottom-line\"\u003e\u003ca href=\"/posts/supply-chain-security-github-dependabot/#the-bottom-line\" title=\"The Bottom Line\"\u003eThe Bottom Line\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eISO 27001 Control A.15 treats supplier relationships as security-critical. Your dependency tree \u003cem\u003eis\u003c/em\u003e a supplier relationship. Hundreds of them, actually.\u003c/p\u003e\n\u003cp\u003eGitHub Dependabot, dependency review actions, and SBOM generation aren\u0026rsquo;t optional DevOps add-ons. They\u0026rsquo;re the technical implementation of what the standard requires: documented approval processes (A.15.1.1), supply chain visibility (A.15.1.3), and continuous monitoring (A.15.2.1).\u003c/p\u003e\n\u003cp\u003eOrganizations that ignore supply chain security aren\u0026rsquo;t just risking breaches—they\u0026rsquo;re in violation of their own ISMS requirements. The next time your auditor asks about supplier management controls, showing them your procurement process isn\u0026rsquo;t enough. They need to see how you manage the suppliers running in production: your dependencies.\u003c/p\u003e\n\u003cp\u003eThe fatal approach treats dependencies as an afterthought. The correct approach treats them as the critical third-party relationships they actually are—with approval workflows, continuous monitoring, vulnerability SLAs, and documented evidence that survives audit scrutiny.\u003c/p\u003e\n\u003cp\u003eYour dependency manager is either your weakest link or your best security control. The difference is whether you implement it deliberately or ignore it hopefully.\u003c/p\u003e\n","date_modified":"2026-05-26T10:22:03+02:00","date_published":"2026-04-09T17:00:00+02:00","id":"https://daily-devops.net/posts/supply-chain-security-github-dependabot/","language":"en","summary":"npm install pulls 247 strangers past your vendor approval gate. Wire up Dependabot, dependency review, and SBOMs to satisfy ISO 27001 A.15 properly.\n","tags":["iso-standards","security","github","dependency-management","automation","technicaldebt"],"title":"247 Strangers Have Root Access to Your Production\n","url":"https://daily-devops.net/posts/supply-chain-security-github-dependabot/"},{"authors":[{"name":"Martin Stühmer","url":"https://daily-devops.net/authors/martin/"}],"content_html":"\u003cp\u003eYou wouldn\u0026rsquo;t let a stranger walk into your datacenter and install software on your production servers. Yet every time you execute \u003ccode\u003edotnet add package\u003c/code\u003e, you\u0026rsquo;re doing exactly that: inviting third-party code into your application without verification, without approval, and often without even knowing what transitive dependencies tagged along for the ride.\u003c/p\u003e\n\u003cp\u003eISO/IEC 27001 Control A.15.1 (Information security in supplier relationships) doesn\u0026rsquo;t care whether your \u0026ldquo;supplier\u0026rdquo; is a cloud vendor with million-dollar contracts or an open-source maintainer distributing NuGet packages from their basement. Both are suppliers. Both introduce supply chain risk. And both require the same systematic approach to security.\u003c/p\u003e\n\u003cp\u003eAfter seeing enterprise teams discover critical vulnerabilities in packages that had been sitting in production for years (packages they couldn\u0026rsquo;t even remember adding), I\u0026rsquo;ve learned that dependency management isn\u0026rsquo;t a developer convenience feature. It\u0026rsquo;s a fundamental security control that most organizations handle with alarming negligence.\u003c/p\u003e\n\n\n\n\n\u003ch2 id=\"the-fatal-pattern-nuget-as-a-free-for-all\"\u003e\u003ca href=\"/posts/dependency-management-nuget-security/#the-fatal-pattern-nuget-as-a-free-for-all\" title=\"The Fatal Pattern: NuGet as a Free-for-All\"\u003eThe Fatal Pattern: NuGet as a Free-for-All\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eHere\u0026rsquo;s what I see in most .NET codebases when I perform security audits:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-csharp\" data-lang=\"csharp\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// ProjectA.csproj\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eItemGroup\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"p\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003ePackageReference\u003c/span\u003e \u003cspan class=\"n\"\u003eInclude\u003c/span\u003e\u003cspan class=\"p\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;Newtonsoft.Json\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003eVersion\u003c/span\u003e\u003cspan class=\"p\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;11.0.2\u0026#34;\u003c/span\u003e \u003cspan class=\"p\"\u003e/\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"p\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003ePackageReference\u003c/span\u003e \u003cspan class=\"n\"\u003eInclude\u003c/span\u003e\u003cspan class=\"p\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;Serilog\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003eVersion\u003c/span\u003e\u003cspan class=\"p\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;2.8.0\u0026#34;\u003c/span\u003e \u003cspan class=\"p\"\u003e/\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e\u0026lt;/\u003c/span\u003e\u003cspan class=\"n\"\u003eItemGroup\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// ProjectB.csproj\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eItemGroup\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"p\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003ePackageReference\u003c/span\u003e \u003cspan class=\"n\"\u003eInclude\u003c/span\u003e\u003cspan class=\"p\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;Newtonsoft.Json\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003eVersion\u003c/span\u003e\u003cspan class=\"p\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;12.0.3\u0026#34;\u003c/span\u003e \u003cspan class=\"p\"\u003e/\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"p\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003ePackageReference\u003c/span\u003e \u003cspan class=\"n\"\u003eInclude\u003c/span\u003e\u003cspan class=\"p\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;AutoMapper\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003eVersion\u003c/span\u003e\u003cspan class=\"p\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;9.0.0\u0026#34;\u003c/span\u003e \u003cspan class=\"p\"\u003e/\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e\u0026lt;/\u003c/span\u003e\u003cspan class=\"n\"\u003eItemGroup\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// ProjectC.csproj\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003eItemGroup\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"p\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003ePackageReference\u003c/span\u003e \u003cspan class=\"n\"\u003eInclude\u003c/span\u003e\u003cspan class=\"p\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;Newtonsoft.Json\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003eVersion\u003c/span\u003e\u003cspan class=\"p\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;10.0.3\u0026#34;\u003c/span\u003e \u003cspan class=\"p\"\u003e/\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"p\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"n\"\u003ePackageReference\u003c/span\u003e \u003cspan class=\"n\"\u003eInclude\u003c/span\u003e\u003cspan class=\"p\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;Serilog\u0026#34;\u003c/span\u003e \u003cspan class=\"n\"\u003eVersion\u003c/span\u003e\u003cspan class=\"p\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;2.10.0\u0026#34;\u003c/span\u003e \u003cspan class=\"p\"\u003e/\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e\u0026lt;/\u003c/span\u003e\u003cspan class=\"n\"\u003eItemGroup\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eThree projects, three different versions of the same package, zero visibility into transitive dependencies, and absolutely no process for:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eVulnerability scanning\u003c/strong\u003e: Nobody knows which CVEs affect any of these versions\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eApproval workflow\u003c/strong\u003e: Developers add packages with \u003ccode\u003eInstall-Package\u003c/code\u003e during development\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eVersion consistency\u003c/strong\u003e: Each project picks its own version creating assembly binding nightmares\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eDependency tracking\u003c/strong\u003e: What pulled in that obscure \u003ccode\u003eSystem.Text.Encodings.Web\u003c/code\u003e version?\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eSecurity patches\u003c/strong\u003e: Versions pinned years ago, never updated, accumulating vulnerabilities\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eAnd the internal package repository? Configured like this:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-xml\" data-lang=\"xml\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003e\u0026lt;!-- nuget.config --\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cp\"\u003e\u0026lt;?xml version=\u0026#34;1.0\u0026#34; encoding=\u0026#34;utf-8\u0026#34;?\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003e\u0026lt;configuration\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"nt\"\u003e\u0026lt;packageSources\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"nt\"\u003e\u0026lt;add\u003c/span\u003e \u003cspan class=\"na\"\u003ekey=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;nuget.org\u0026#34;\u003c/span\u003e \u003cspan class=\"na\"\u003evalue=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;https://api.nuget.org/v3/index.json\u0026#34;\u003c/span\u003e \u003cspan class=\"nt\"\u003e/\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"nt\"\u003e\u0026lt;add\u003c/span\u003e \u003cspan class=\"na\"\u003ekey=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;internal\u0026#34;\u003c/span\u003e \u003cspan class=\"na\"\u003evalue=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;http://internal-nuget.company.local/nuget\u0026#34;\u003c/span\u003e \u003cspan class=\"nt\"\u003e/\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"nt\"\u003e\u0026lt;/packageSources\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"c\"\u003e\u0026lt;!-- No authentication configured --\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"c\"\u003e\u0026lt;!-- No signature verification --\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"c\"\u003e\u0026lt;!-- No HTTPS enforcement --\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003e\u0026lt;/configuration\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eThis violates \u003cstrong\u003eISO/IEC 27001 A.15.1.1\u003c/strong\u003e (Information security policy for supplier relationships) by failing to establish security requirements for third-party code. It violates \u003cstrong\u003eA.15.1.3\u003c/strong\u003e (Supply chain security) by not monitoring the supply chain for security events. And it completely ignores \u003cstrong\u003eA.18.2.3\u003c/strong\u003e (Technical compliance review) by skipping any technical verification of dependencies.\u003c/p\u003e\n\u003cp\u003eIn practical terms: any developer can add any package from any source, those packages can pull in dozens of transitive dependencies, and nobody discovers the vulnerable packages until a security incident forces an emergency audit.\u003c/p\u003e\n\n\n\n\n\u003ch2 id=\"the-systematic-approach-dependency-management-as-security-control\"\u003e\u003ca href=\"/posts/dependency-management-nuget-security/#the-systematic-approach-dependency-management-as-security-control\" title=\"The Systematic Approach: Dependency Management as Security Control\"\u003eThe Systematic Approach: Dependency Management as Security Control\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eISO 27001 requires treating suppliers as part of your security perimeter. For NuGet packages, this means implementing controls at multiple levels:\u003c/p\u003e\n\n\n\n\n\u003ch3 id=\"1-central-package-management-directorypackagesprops\"\u003e\u003ca href=\"/posts/dependency-management-nuget-security/#1-central-package-management-directorypackagesprops\" title=\"1. Central Package Management (Directory.Packages.props)\"\u003e1. Central Package Management (Directory.Packages.props)\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003eFirst, enforce version consistency across your entire codebase:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-xml\" data-lang=\"xml\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003e\u0026lt;!-- Directory.Packages.props (at solution root) --\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003e\u0026lt;Project\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"nt\"\u003e\u0026lt;PropertyGroup\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"nt\"\u003e\u0026lt;ManagePackageVersionsCentrally\u0026gt;\u003c/span\u003etrue\u003cspan class=\"nt\"\u003e\u0026lt;/ManagePackageVersionsCentrally\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"nt\"\u003e\u0026lt;/PropertyGroup\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"nt\"\u003e\u0026lt;ItemGroup\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"nt\"\u003e\u0026lt;PackageVersion\u003c/span\u003e \u003cspan class=\"na\"\u003eInclude=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;Newtonsoft.Json\u0026#34;\u003c/span\u003e \u003cspan class=\"na\"\u003eVersion=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;13.0.3\u0026#34;\u003c/span\u003e \u003cspan class=\"nt\"\u003e/\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"nt\"\u003e\u0026lt;PackageVersion\u003c/span\u003e \u003cspan class=\"na\"\u003eInclude=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;Serilog\u0026#34;\u003c/span\u003e \u003cspan class=\"na\"\u003eVersion=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;3.1.1\u0026#34;\u003c/span\u003e \u003cspan class=\"nt\"\u003e/\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"c\"\u003e\u0026lt;!-- Version range: auto-update patches, block major versions --\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"nt\"\u003e\u0026lt;PackageVersion\u003c/span\u003e \u003cspan class=\"na\"\u003eInclude=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;Azure.Identity\u0026#34;\u003c/span\u003e \u003cspan class=\"na\"\u003eVersion=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;[1.10.4,2.0)\u0026#34;\u003c/span\u003e \u003cspan class=\"nt\"\u003e/\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"nt\"\u003e\u0026lt;/ItemGroup\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003e\u0026lt;/Project\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eProject files now reference packages without versions:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-xml\" data-lang=\"xml\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003e\u0026lt;!-- ProjectA.csproj --\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003e\u0026lt;ItemGroup\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"nt\"\u003e\u0026lt;PackageReference\u003c/span\u003e \u003cspan class=\"na\"\u003eInclude=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;Newtonsoft.Json\u0026#34;\u003c/span\u003e \u003cspan class=\"nt\"\u003e/\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"nt\"\u003e\u0026lt;PackageReference\u003c/span\u003e \u003cspan class=\"na\"\u003eInclude=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;Serilog\u0026#34;\u003c/span\u003e \u003cspan class=\"nt\"\u003e/\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003e\u0026lt;/ItemGroup\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003cstrong\u003eWhy this matters for ISO 27001\u003c/strong\u003e: Control A.15.1.1 requires establishing security requirements. Central Package Management enforces a single source of truth for dependency versions, making vulnerability tracking and patching possible across your entire codebase.\u003c/p\u003e\n\u003cp\u003eNote the version range syntax \u003ccode\u003e[8.0.1,9.0)\u003c/code\u003e for security-critical packages. This allows NuGet to automatically pull patch versions (8.0.2, 8.0.3, etc.) that fix security vulnerabilities while preventing breaking changes from major version updates.\u003c/p\u003e\n\n\n\n\n\u003ch3 id=\"2-automated-vulnerability-scanning-in-cicd\"\u003e\u003ca href=\"/posts/dependency-management-nuget-security/#2-automated-vulnerability-scanning-in-cicd\" title=\"2. Automated Vulnerability Scanning in CI/CD\"\u003e2. Automated Vulnerability Scanning in CI/CD\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003eEvery build must check for known vulnerabilities:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003e# .github/workflows/build.yml\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003ename\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l\"\u003eBuild with Security Checks\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003eon\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"l\"\u003epush, pull_request]\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003ejobs\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e  \u003c/span\u003e\u003cspan class=\"nt\"\u003esecurity-scan\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"nt\"\u003eruns-on\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l\"\u003eubuntu-latest\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"nt\"\u003esteps\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e- \u003cspan class=\"nt\"\u003euses\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l\"\u003eactions/checkout@v4\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e- \u003cspan class=\"nt\"\u003euses\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l\"\u003eactions/setup-dotnet@v4\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e      \u003c/span\u003e\u003cspan class=\"nt\"\u003ewith\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e        \u003c/span\u003e\u003cspan class=\"nt\"\u003edotnet-version\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;8.0.x\u0026#39;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e- \u003cspan class=\"nt\"\u003ename\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l\"\u003eCheck for vulnerable packages\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e      \u003c/span\u003e\u003cspan class=\"nt\"\u003erun\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e|\u003c/span\u003e\u003cspan class=\"sd\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"sd\"\u003e        dotnet restore\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"sd\"\u003e        dotnet list package --vulnerable --include-transitive\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"sd\"\u003e        # Fails if vulnerabilities found\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"sd\"\u003e        dotnet build /p:TreatWarningsAsErrors=true\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eThis implements \u003cstrong\u003eA.18.2.3\u003c/strong\u003e (Technical compliance review) by automatically verifying that dependencies meet security requirements before code reaches production.\u003c/p\u003e\n\n\n\n\n\u003ch3 id=\"3-github-dependabot-configuration\"\u003e\u003ca href=\"/posts/dependency-management-nuget-security/#3-github-dependabot-configuration\" title=\"3. GitHub Dependabot Configuration\"\u003e3. GitHub Dependabot Configuration\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003eEnable automated vulnerability alerts and patching:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003e# .github/dependabot.yml\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003eversion\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"m\"\u003e2\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003eupdates\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e  \u003c/span\u003e- \u003cspan class=\"nt\"\u003epackage-ecosystem\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;nuget\u0026#34;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"nt\"\u003edirectory\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;/\u0026#34;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"nt\"\u003eschedule\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e      \u003c/span\u003e\u003cspan class=\"nt\"\u003einterval\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;weekly\u0026#34;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"nt\"\u003egroups\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e      \u003c/span\u003e\u003cspan class=\"nt\"\u003esecurity-updates\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e        \u003c/span\u003e\u003cspan class=\"nt\"\u003eupdate-types\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;security\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"nt\"\u003ereviewers\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e      \u003c/span\u003e- \u003cspan class=\"s2\"\u003e\u0026#34;security-team\u0026#34;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"nt\"\u003elabels\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e      \u003c/span\u003e- \u003cspan class=\"s2\"\u003e\u0026#34;dependencies\u0026#34;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eThis addresses \u003cstrong\u003eA.15.1.3\u003c/strong\u003e (Supply chain security) by continuously monitoring your supply chain for security events and automatically proposing remediation.\u003c/p\u003e\n\n\n\n\n\u003ch3 id=\"4-package-source-authentication-and-verification\"\u003e\u003ca href=\"/posts/dependency-management-nuget-security/#4-package-source-authentication-and-verification\" title=\"4. Package Source Authentication and Verification\"\u003e4. Package Source Authentication and Verification\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003eSecure your package sources with authentication and signature verification:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-xml\" data-lang=\"xml\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003e\u0026lt;!-- nuget.config --\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003e\u0026lt;configuration\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"nt\"\u003e\u0026lt;packageSources\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"nt\"\u003e\u0026lt;clear\u003c/span\u003e \u003cspan class=\"nt\"\u003e/\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"nt\"\u003e\u0026lt;add\u003c/span\u003e \u003cspan class=\"na\"\u003ekey=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;nuget.org\u0026#34;\u003c/span\u003e \u003cspan class=\"na\"\u003evalue=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;https://api.nuget.org/v3/index.json\u0026#34;\u003c/span\u003e \u003cspan class=\"nt\"\u003e/\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"nt\"\u003e\u0026lt;/packageSources\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"nt\"\u003e\u0026lt;packageSourceMapping\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"nt\"\u003e\u0026lt;packageSource\u003c/span\u003e \u003cspan class=\"na\"\u003ekey=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;nuget.org\u0026#34;\u003c/span\u003e\u003cspan class=\"nt\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      \u003cspan class=\"nt\"\u003e\u0026lt;package\u003c/span\u003e \u003cspan class=\"na\"\u003epattern=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;Microsoft.*\u0026#34;\u003c/span\u003e \u003cspan class=\"nt\"\u003e/\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      \u003cspan class=\"nt\"\u003e\u0026lt;package\u003c/span\u003e \u003cspan class=\"na\"\u003epattern=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;System.*\u0026#34;\u003c/span\u003e \u003cspan class=\"nt\"\u003e/\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"nt\"\u003e\u0026lt;/packageSource\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"nt\"\u003e\u0026lt;/packageSourceMapping\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"nt\"\u003e\u0026lt;config\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"nt\"\u003e\u0026lt;add\u003c/span\u003e \u003cspan class=\"na\"\u003ekey=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;signatureValidationMode\u0026#34;\u003c/span\u003e \u003cspan class=\"na\"\u003evalue=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;require\u0026#34;\u003c/span\u003e \u003cspan class=\"nt\"\u003e/\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"nt\"\u003e\u0026lt;/config\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003e\u0026lt;/configuration\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eThis configuration clears default sources and whitelists approved feeds, maps package patterns to specific sources (preventing substitution attacks), and enables signature verification.\u003c/p\u003e\n\n\n\n\n\u003ch3 id=\"5-health-checks-for-package-repository-availability\"\u003e\u003ca href=\"/posts/dependency-management-nuget-security/#5-health-checks-for-package-repository-availability\" title=\"5. Health Checks for Package Repository Availability\"\u003e5. Health Checks for Package Repository Availability\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003eYour CI/CD pipeline depends on NuGet feeds being available. If \u003ccode\u003enuget.org\u003c/code\u003e goes down during a critical deployment, you need to know. Add a simple health check to your monitoring:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-csharp\" data-lang=\"csharp\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e// Check NuGet feed availability\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003evar\u003c/span\u003e \u003cspan class=\"n\"\u003eclient\u003c/span\u003e \u003cspan class=\"p\"\u003e=\u003c/span\u003e \u003cspan class=\"k\"\u003enew\u003c/span\u003e \u003cspan class=\"n\"\u003eHttpClient\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kt\"\u003evar\u003c/span\u003e \u003cspan class=\"n\"\u003eresponse\u003c/span\u003e \u003cspan class=\"p\"\u003e=\u003c/span\u003e \u003cspan class=\"k\"\u003eawait\u003c/span\u003e \u003cspan class=\"n\"\u003eclient\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eGetAsync\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;https://api.nuget.org/v3/index.json\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(!\u003c/span\u003e\u003cspan class=\"n\"\u003eresponse\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eIsSuccessStatusCode\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003elogger\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eLogWarning\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;NuGet feed unavailable\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eThis is critical for \u003cstrong\u003eA.15.1.3\u003c/strong\u003e (Supply chain security): you need to know when your dependency supply chain is disrupted.\u003c/p\u003e\n\n\n\n\n\u003ch2 id=\"regular-dependency-audits\"\u003e\u003ca href=\"/posts/dependency-management-nuget-security/#regular-dependency-audits\" title=\"Regular Dependency Audits\"\u003eRegular Dependency Audits\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eFinally, schedule regular dependency reviews as part of your security process:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# Monthly security audit\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003edotnet list package --outdated\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003edotnet list package --vulnerable --include-transitive\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003edotnet list package --deprecated\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eRun this monthly and review results with your security team. This provides evidence for \u003cstrong\u003eA.18.2.3\u003c/strong\u003e (Technical compliance review).\u003c/p\u003e\n\n\n\n\n\u003ch2 id=\"the-pragmatic-reality\"\u003e\u003ca href=\"/posts/dependency-management-nuget-security/#the-pragmatic-reality\" title=\"The Pragmatic Reality\"\u003eThe Pragmatic Reality\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eI\u0026rsquo;ve seen teams spend months achieving ISO 27001 certification only to completely ignore Control A.15.1 when it comes to NuGet packages. The assumption seems to be that because packages are \u0026ldquo;just open source\u0026rdquo; or \u0026ldquo;from Microsoft,\u0026rdquo; they don\u0026rsquo;t count as suppliers.\u003c/p\u003e\n\u003cp\u003eThey absolutely count. Every package is a supplier relationship. Every transitive dependency is a third-party component in your production system. And every vulnerability in those dependencies is your responsibility under ISO 27001.\u003c/p\u003e\n\u003cp\u003eThe good news: modern tooling makes this manageable. Central Package Management eliminates version chaos. Dependabot provides automated monitoring. GitHub Actions enables vulnerability scanning without infrastructure investment. Package signing prevents tampering.\u003c/p\u003e\n\u003cp\u003eThe bad news: none of this happens automatically. You must implement these controls deliberately, enforce them consistently, and audit them regularly.\u003c/p\u003e\n\n\n\n\n\u003ch2 id=\"key-takeaways\"\u003e\u003ca href=\"/posts/dependency-management-nuget-security/#key-takeaways\" title=\"Key Takeaways\"\u003eKey Takeaways\u003c/a\u003e\u003c/h2\u003e\n\u003col\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cstrong\u003eEvery NuGet package is a supplier relationship\u003c/strong\u003e under ISO/IEC 27001 Control A.15.1, requiring security evaluation and monitoring.\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cstrong\u003eCentral Package Management is mandatory\u003c/strong\u003e for any codebase with multiple projects. It\u0026rsquo;s the foundation for vulnerability tracking and consistent patching.\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cstrong\u003eFail builds on known vulnerabilities\u003c/strong\u003e using \u003ccode\u003edotnet list package --vulnerable\u003c/code\u003e in CI/CD pipelines. Security issues should block deployment, not generate ignored warnings.\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cstrong\u003eVersion ranges enable automatic security patches\u003c/strong\u003e: use \u003ccode\u003e[8.0.1,9.0)\u003c/code\u003e syntax for dependencies where security matters more than version stability.\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cstrong\u003ePackage signature verification prevents supply chain attacks\u003c/strong\u003e: configure trusted signers and require signature validation in nuget.config.\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cstrong\u003eAutomated scanning finds problems; human review approves solutions\u003c/strong\u003e: let Dependabot detect issues, but require security team approval for dependency changes.\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cstrong\u003eMonitor your supply chain availability\u003c/strong\u003e: health checks for package repositories should be part of your operational monitoring.\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003eSupply chain security isn\u0026rsquo;t a checkbox on a compliance form. It\u0026rsquo;s a systematic approach to managing the third-party code that forms 70-90% of modern applications. ISO 27001 provides the framework; NuGet tooling provides the implementation. Your job is to connect them before the next CVE announcement forces you to audit thousands of dependencies under emergency conditions.\u003c/p\u003e\n\u003cp\u003eAfter 15 years of seeing teams scramble to patch vulnerabilities in packages they didn\u0026rsquo;t know they had, I can promise you this: the time you invest in dependency management today will save you countless emergency responses tomorrow. And unlike most security theater, these controls actually work.\u003c/p\u003e\n","date_modified":"2026-05-26T10:22:03+02:00","date_published":"2026-02-19T17:00:00+01:00","id":"https://daily-devops.net/posts/dependency-management-nuget-security/","language":"en","summary":"dotnet add package invites unvetted suppliers into production. Enforce Central Package Management, signature checks, and vulnerability scans.","tags":["iso-standards","security","nuget","dotnet","dependency-management"],"title":"NuGet Packages: The Suppliers You Forgot to Audit","url":"https://daily-devops.net/posts/dependency-management-nuget-security/"},{"authors":[{"name":"Martin Stühmer","url":"https://daily-devops.net/authors/martin/"}],"content_html":"\u003cp\u003eNuGet has been the backbone of .NET dependency management for over a decade. It\u0026rsquo;s mature. It\u0026rsquo;s reliable. It mostly works.\u003c/p\u003e\n\u003cp\u003eAnd then there\u0026rsquo;s \u003cstrong\u003ePackageDownload\u003c/strong\u003e — a feature introduced in 2018 that solves a legitimate problem, but in a way that makes you wonder whether anyone thought about how it would integrate with the rest of the ecosystem.\u003c/p\u003e\n\u003cp\u003ePackageDownload lets you download NuGet packages to your build environment \u003cstrong\u003ewithout adding assembly references\u003c/strong\u003e. That\u0026rsquo;s useful. It\u0026rsquo;s not glamorous, but it fills a gap. The problem is how it does it: with mandatory version range syntax, zero integration with Central Package Management, and documentation that assumes you already know what you\u0026rsquo;re doing.\u003c/p\u003e\n\u003cp\u003eThis article isn\u0026rsquo;t about celebrating NuGet. It\u0026rsquo;s about understanding PackageDownload — what it does well, where it fails, and why those failures matter.\u003c/p\u003e\n\n\n\n\n\u003ch2 id=\"what-packagedownload-actually-does\"\u003e\u003ca href=\"/posts/nuget-packagedownload-functionality/#what-packagedownload-actually-does\" title=\"What PackageDownload Actually Does\"\u003eWhat PackageDownload Actually Does\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eWhen you add a package reference with \u003ccode\u003e\u0026lt;PackageReference\u0026gt;\u003c/code\u003e, NuGet does two things simultaneously: it downloads the package to your local cache and adds its assemblies to your project\u0026rsquo;s compilation and runtime dependencies. That\u0026rsquo;s fine for libraries, frameworks, and application dependencies. But what if you need the package contents during the build process without those assemblies polluting your dependency graph?\u003c/p\u003e\n\u003cp\u003eThat\u0026rsquo;s where PackageDownload comes in.\u003c/p\u003e\n\n\n\n\n\u003ch3 id=\"the-basic-syntax\"\u003e\u003ca href=\"/posts/nuget-packagedownload-functionality/#the-basic-syntax\" title=\"The Basic Syntax\"\u003eThe Basic Syntax\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003ePackageDownload is defined in your \u003ccode\u003e.csproj\u003c/code\u003e file:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-xml\" data-lang=\"xml\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003e\u0026lt;ItemGroup\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"nt\"\u003e\u0026lt;PackageDownload\u003c/span\u003e \u003cspan class=\"na\"\u003eInclude=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;Newtonsoft.Json\u0026#34;\u003c/span\u003e \u003cspan class=\"na\"\u003eVersion=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;[13.0.1]\u0026#34;\u003c/span\u003e \u003cspan class=\"nt\"\u003e/\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003e\u0026lt;/ItemGroup\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eUnlike \u003ccode\u003e\u0026lt;PackageReference\u0026gt;\u003c/code\u003e, this downloads the package but \u003cstrong\u003edoes not reference its assemblies\u003c/strong\u003e. The package sits in your NuGet cache, available for MSBuild tasks or custom build logic, but it doesn\u0026rsquo;t touch your dependency tree.\u003c/p\u003e\n\u003cp\u003eSimple enough. Until you hit the version requirement.\u003c/p\u003e\n\n\n\n\n\u003ch2 id=\"why-youd-use-this\"\u003e\u003ca href=\"/posts/nuget-packagedownload-functionality/#why-youd-use-this\" title=\"Why You\u0026rsquo;d Use This\"\u003eWhy You\u0026rsquo;d Use This\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003ePackageDownload isn\u0026rsquo;t a mainstream feature. Most developers will never need it. But when you do, it\u0026rsquo;s the only clean option.\u003c/p\u003e\n\n\n\n\n\u003ch3 id=\"1-build-time-tools-and-analyzers\"\u003e\u003ca href=\"/posts/nuget-packagedownload-functionality/#1-build-time-tools-and-analyzers\" title=\"1. Build-Time Tools and Analyzers\"\u003e1. Build-Time Tools and Analyzers\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003eSome packages contain Roslyn analyzers or code generators that run during compilation. You need the package on disk for MSBuild to find it, but you don\u0026rsquo;t want it as a runtime dependency.\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-xml\" data-lang=\"xml\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003e\u0026lt;PackageDownload\u003c/span\u003e \u003cspan class=\"na\"\u003eInclude=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;Microsoft.CodeAnalysis.NetAnalyzers\u0026#34;\u003c/span\u003e \u003cspan class=\"na\"\u003eVersion=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;[7.0.0]\u0026#34;\u003c/span\u003e \u003cspan class=\"nt\"\u003e/\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eThe analyzer runs during the build. It doesn\u0026rsquo;t ship with your application.\u003c/p\u003e\n\n\n\n\n\u003ch3 id=\"2-non-code-assets\"\u003e\u003ca href=\"/posts/nuget-packagedownload-functionality/#2-non-code-assets\" title=\"2. Non-Code Assets\"\u003e2. Non-Code Assets\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003eIf you\u0026rsquo;re distributing build scripts, configuration files, or schemas via NuGet, PackageDownload lets you pull them down without dragging in unnecessary assemblies.\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-xml\" data-lang=\"xml\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003e\u0026lt;PackageDownload\u003c/span\u003e \u003cspan class=\"na\"\u003eInclude=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;CompanyBuildTools\u0026#34;\u003c/span\u003e \u003cspan class=\"na\"\u003eVersion=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;[2.3.0]\u0026#34;\u003c/span\u003e \u003cspan class=\"nt\"\u003e/\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\n\n\n\u003ch3 id=\"3-avoiding-transitive-dependency-conflicts\"\u003e\u003ca href=\"/posts/nuget-packagedownload-functionality/#3-avoiding-transitive-dependency-conflicts\" title=\"3. Avoiding Transitive Dependency Conflicts\"\u003e3. Avoiding Transitive Dependency Conflicts\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003eIn complex solutions, pulling in a package for its metadata or documentation can trigger unwanted transitive dependencies. PackageDownload sidesteps that entirely.\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-xml\" data-lang=\"xml\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003e\u0026lt;PackageDownload\u003c/span\u003e \u003cspan class=\"na\"\u003eInclude=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;XmlSchemas.Library\u0026#34;\u003c/span\u003e \u003cspan class=\"na\"\u003eVersion=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;[2.1.0]\u0026#34;\u003c/span\u003e \u003cspan class=\"nt\"\u003e/\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\n\n\n\u003ch3 id=\"4-version-pinning-for-build-reproducibility\"\u003e\u003ca href=\"/posts/nuget-packagedownload-functionality/#4-version-pinning-for-build-reproducibility\" title=\"4. Version Pinning for Build Reproducibility\"\u003e4. Version Pinning for Build Reproducibility\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003eWhen you need an exact package version available during the build — not approximately, not \u0026ldquo;compatible with,\u0026rdquo; but \u003cstrong\u003eexactly that version\u003c/strong\u003e — PackageDownload enforces it.\u003c/p\u003e\n\n\n\n\n\u003ch2 id=\"how-it-works\"\u003e\u003ca href=\"/posts/nuget-packagedownload-functionality/#how-it-works\" title=\"How It Works\"\u003eHow It Works\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eWhen MSBuild encounters a \u003ccode\u003e\u0026lt;PackageDownload\u0026gt;\u003c/code\u003e element, NuGet resolves the specified version and downloads the package to the global cache — typically \u003ccode\u003e%USERPROFILE%\\.nuget\\packages\u003c/code\u003e on Windows or \u003ccode\u003e~/.nuget/packages\u003c/code\u003e on Linux and macOS. Crucially, no assembly references are added to your project. The package contents sit there, available for custom MSBuild tasks, targets, or extraction logic, but they don\u0026rsquo;t touch your dependency tree.\u003c/p\u003e\n\u003cp\u003eThat\u0026rsquo;s straightforward. The frustration starts with the version syntax.\u003c/p\u003e\n\n\n\n\n\u003ch2 id=\"the-version-range-requirement-a-painful-design-choice\"\u003e\u003ca href=\"/posts/nuget-packagedownload-functionality/#the-version-range-requirement-a-painful-design-choice\" title=\"The Version Range Requirement: A Painful Design Choice\"\u003eThe Version Range Requirement: A Painful Design Choice\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eHere\u0026rsquo;s the part that trips up everyone who tries PackageDownload for the first time:\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eYou must specify the version using range notation.\u003c/strong\u003e\u003c/p\u003e\n\n\n\n\n\u003ch3 id=\"the-hard-requirement\"\u003e\u003ca href=\"/posts/nuget-packagedownload-functionality/#the-hard-requirement\" title=\"The Hard Requirement\"\u003eThe Hard Requirement\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003eUnlike \u003ccode\u003e\u0026lt;PackageReference\u0026gt;\u003c/code\u003e, which accepts a simple version like \u003ccode\u003eVersion=\u0026quot;13.0.1\u0026quot;\u003c/code\u003e, PackageDownload demands version ranges:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-xml\" data-lang=\"xml\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003e\u0026lt;!-- This does NOT work --\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003e\u0026lt;PackageDownload\u003c/span\u003e \u003cspan class=\"na\"\u003eInclude=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;Newtonsoft.Json\u0026#34;\u003c/span\u003e \u003cspan class=\"na\"\u003eVersion=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;13.0.1\u0026#34;\u003c/span\u003e \u003cspan class=\"nt\"\u003e/\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003e\u0026lt;!-- You must use this --\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003e\u0026lt;PackageDownload\u003c/span\u003e \u003cspan class=\"na\"\u003eInclude=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;Newtonsoft.Json\u0026#34;\u003c/span\u003e \u003cspan class=\"na\"\u003eVersion=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;[13.0.1]\u0026#34;\u003c/span\u003e \u003cspan class=\"nt\"\u003e/\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eThe square brackets \u003ccode\u003e[13.0.1]\u003c/code\u003e mean \u003cstrong\u003eexactly version 13.0.1\u003c/strong\u003e. No flexibility. No approximation. That specific version, or the restore fails.\u003c/p\u003e\n\n\n\n\n\u003ch3 id=\"why-this-is-a-problem\"\u003e\u003ca href=\"/posts/nuget-packagedownload-functionality/#why-this-is-a-problem\" title=\"Why This Is a Problem\"\u003eWhy This Is a Problem\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003eThis requirement creates unnecessary friction in several ways. First, the syntax is unintuitive — developers familiar with \u003ccode\u003e\u0026lt;PackageReference\u0026gt;\u003c/code\u003e expect the same syntax to work, but it doesn\u0026rsquo;t. The version range requirement isn\u0026rsquo;t obvious, and the error messages when you get it wrong are cryptic at best.\u003c/p\u003e\n\u003cp\u003eSecond, and more frustratingly, there\u0026rsquo;s no integration with Central Package Management. When Microsoft introduced CPM in 2022, it promised to centralize version control across solutions. Define versions once in \u003ccode\u003eDirectory.Packages.props\u003c/code\u003e, reference them everywhere. PackageDownload doesn\u0026rsquo;t care.\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-xml\" data-lang=\"xml\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003e\u0026lt;!-- Directory.Packages.props --\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003e\u0026lt;ItemGroup\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"nt\"\u003e\u0026lt;PackageVersion\u003c/span\u003e \u003cspan class=\"na\"\u003eInclude=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;Newtonsoft.Json\u0026#34;\u003c/span\u003e \u003cspan class=\"na\"\u003eVersion=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;13.0.1\u0026#34;\u003c/span\u003e \u003cspan class=\"nt\"\u003e/\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003e\u0026lt;/ItemGroup\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003e\u0026lt;!-- Project file - this FAILS --\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003e\u0026lt;ItemGroup\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"nt\"\u003e\u0026lt;PackageDownload\u003c/span\u003e \u003cspan class=\"na\"\u003eInclude=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;Newtonsoft.Json\u0026#34;\u003c/span\u003e \u003cspan class=\"nt\"\u003e/\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"c\"\u003e\u0026lt;!-- Still requires: Version=\u0026#34;[13.0.1]\u0026#34; --\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003e\u0026lt;/ItemGroup\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eYou still need to manually specify the version in every \u003ccode\u003e\u0026lt;PackageDownload\u0026gt;\u003c/code\u003e entry. CPM is ignored completely. This creates manual maintenance overhead — if you\u0026rsquo;re using PackageDownload across multiple projects, updating a version means editing every single file. There\u0026rsquo;s no centralized control. It defeats the entire purpose of modern dependency management.\u003c/p\u003e\n\n\n\n\n\u003ch3 id=\"the-missed-opportunity\"\u003e\u003ca href=\"/posts/nuget-packagedownload-functionality/#the-missed-opportunity\" title=\"The Missed Opportunity\"\u003eThe Missed Opportunity\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003ePackageDownload was introduced in 2018. CPM arrived in 2022. As of 2025, they still don\u0026rsquo;t work together. This isn\u0026rsquo;t an oversight — it\u0026rsquo;s a conscious decision not to invest in making older features compatible with newer workflows. And it shows.\u003c/p\u003e\n\u003cp\u003eThe result is a bifurcated system where you use CPM for \u003ccode\u003e\u0026lt;PackageReference\u0026gt;\u003c/code\u003e (modern, clean, centralized) but inline versions for \u003ccode\u003e\u0026lt;PackageDownload\u0026gt;\u003c/code\u003e (legacy, manual, error-prone). It\u0026rsquo;s frustrating because it didn\u0026rsquo;t have to be this way.\u003c/p\u003e\n\n\n\n\n\u003ch2 id=\"real-world-scenarios\"\u003e\u003ca href=\"/posts/nuget-packagedownload-functionality/#real-world-scenarios\" title=\"Real-World Scenarios\"\u003eReal-World Scenarios\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eDespite the rough edges, PackageDownload has legitimate use cases.\u003c/p\u003e\n\n\n\n\n\u003ch3 id=\"roslyn-analyzers-in-multi-project-solutions\"\u003e\u003ca href=\"/posts/nuget-packagedownload-functionality/#roslyn-analyzers-in-multi-project-solutions\" title=\"Roslyn Analyzers in Multi-Project Solutions\"\u003eRoslyn Analyzers in Multi-Project Solutions\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003eIf you\u0026rsquo;re using StyleCop or custom analyzers that should run during the build but not ship with your application:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-xml\" data-lang=\"xml\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003e\u0026lt;ItemGroup\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"nt\"\u003e\u0026lt;PackageDownload\u003c/span\u003e \u003cspan class=\"na\"\u003eInclude=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;StyleCop.Analyzers\u0026#34;\u003c/span\u003e \u003cspan class=\"na\"\u003eVersion=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;[1.2.0-beta.435]\u0026#34;\u003c/span\u003e \u003cspan class=\"nt\"\u003e/\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003e\u0026lt;/ItemGroup\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eThe analyzer is downloaded, applied during compilation, and ignored at runtime.\u003c/p\u003e\n\n\n\n\n\u003ch3 id=\"extracting-package-contents\"\u003e\u003ca href=\"/posts/nuget-packagedownload-functionality/#extracting-package-contents\" title=\"Extracting Package Contents\"\u003eExtracting Package Contents\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003eCustom MSBuild tasks can extract specific files from downloaded packages:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-xml\" data-lang=\"xml\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003e\u0026lt;ItemGroup\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"nt\"\u003e\u0026lt;PackageDownload\u003c/span\u003e \u003cspan class=\"na\"\u003eInclude=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;CompanyAssets\u0026#34;\u003c/span\u003e \u003cspan class=\"na\"\u003eVersion=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;[2.5.0]\u0026#34;\u003c/span\u003e \u003cspan class=\"nt\"\u003e/\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003e\u0026lt;/ItemGroup\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003e\u0026lt;Target\u003c/span\u003e \u003cspan class=\"na\"\u003eName=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;ExtractAssets\u0026#34;\u003c/span\u003e \u003cspan class=\"na\"\u003eAfterTargets=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;Restore\u0026#34;\u003c/span\u003e\u003cspan class=\"nt\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"nt\"\u003e\u0026lt;Copy\u003c/span\u003e \u003cspan class=\"na\"\u003eSourceFiles=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;$(NuGetPackageRoot)companyassets\\2.5.0\\content\\config.json\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"na\"\u003eDestinationFolder=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;$(OutputPath)\u0026#34;\u003c/span\u003e \u003cspan class=\"nt\"\u003e/\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003e\u0026lt;/Target\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eThis turns NuGet into a distribution mechanism for non-code assets.\u003c/p\u003e\n\n\n\n\n\u003ch3 id=\"build-tools-with-exact-versions\"\u003e\u003ca href=\"/posts/nuget-packagedownload-functionality/#build-tools-with-exact-versions\" title=\"Build Tools with Exact Versions\"\u003eBuild Tools with Exact Versions\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003eFor reproducible builds, you might need specific tool versions:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-xml\" data-lang=\"xml\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003e\u0026lt;ItemGroup\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"nt\"\u003e\u0026lt;PackageDownload\u003c/span\u003e \u003cspan class=\"na\"\u003eInclude=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;GitVersion.Tool\u0026#34;\u003c/span\u003e \u003cspan class=\"na\"\u003eVersion=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;[5.12.0]\u0026#34;\u003c/span\u003e \u003cspan class=\"nt\"\u003e/\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003e\u0026lt;/ItemGroup\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003ePackageDownload guarantees that exact version is available, no matter what.\u003c/p\u003e\n\n\n\n\n\u003ch2 id=\"the-broader-pattern-incomplete-evolution\"\u003e\u003ca href=\"/posts/nuget-packagedownload-functionality/#the-broader-pattern-incomplete-evolution\" title=\"The Broader Pattern: Incomplete Evolution\"\u003eThe Broader Pattern: Incomplete Evolution\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003ePackageDownload is emblematic of how mature platforms evolve — slowly, incrementally, and often without full integration.\u003c/p\u003e\n\u003cp\u003eConsider the timeline:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003e2010\u003c/strong\u003e: NuGet 1.0 launches\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e2018\u003c/strong\u003e: PackageDownload is introduced in NuGet 4.8\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e2022\u003c/strong\u003e: Central Package Management arrives\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e2025\u003c/strong\u003e: PackageDownload still doesn\u0026rsquo;t integrate with CPM\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eThis reveals a fundamental challenge: maintaining backward compatibility while adding new capabilities. Every feature must coexist with a decade of existing workflows. Sometimes that means compromise. Other times it means neglect.\u003c/p\u003e\n\n\n\n\n\u003ch3 id=\"what-should-have-happened\"\u003e\u003ca href=\"/posts/nuget-packagedownload-functionality/#what-should-have-happened\" title=\"What Should Have Happened\"\u003eWhat Should Have Happened\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003ePackageDownload should have been updated when CPM launched. At minimum, it should respect CPM versions, allowing PackageDownload to read from \u003ccode\u003eDirectory.Packages.props\u003c/code\u003e and falling back to inline versions only when necessary. The version syntax should have been simplified to support both simple versions and ranges, with clear guidance on when each applies. Visual Studio and the CLI should provide first-class support for managing PackageDownload entries, and the official docs should explain the version requirement prominently, not bury it in footnotes.\u003c/p\u003e\n\u003cp\u003eNone of that happened. PackageDownload works. But it doesn\u0026rsquo;t integrate.\u003c/p\u003e\n\n\n\n\n\u003ch2 id=\"practical-guidelines\"\u003e\u003ca href=\"/posts/nuget-packagedownload-functionality/#practical-guidelines\" title=\"Practical Guidelines\"\u003ePractical Guidelines\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eIf you\u0026rsquo;re using PackageDownload, here\u0026rsquo;s how to avoid the pain points.\u003c/p\u003e\n\n\n\n\n\u003ch3 id=\"when-to-use-it\"\u003e\u003ca href=\"/posts/nuget-packagedownload-functionality/#when-to-use-it\" title=\"When to Use It\"\u003eWhen to Use It\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003ePackageDownload makes sense for build-time tools or analyzers that shouldn\u0026rsquo;t be runtime dependencies, for non-code assets distributed via NuGet, for custom MSBuild tasks requiring specific package versions, and in scenarios where transitive dependencies would create conflicts. These are real use cases where PackageDownload genuinely solves problems.\u003c/p\u003e\n\n\n\n\n\u003ch3 id=\"when-to-avoid-it\"\u003e\u003ca href=\"/posts/nuget-packagedownload-functionality/#when-to-avoid-it\" title=\"When to Avoid It\"\u003eWhen to Avoid It\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003eDon\u0026rsquo;t use PackageDownload if you need the package\u0026rsquo;s assemblies — that\u0026rsquo;s what \u003ccode\u003e\u0026lt;PackageReference\u0026gt;\u003c/code\u003e is for. Don\u0026rsquo;t expect CPM integration because it doesn\u0026rsquo;t exist. And be aware that automatic version updates via Dependabot get complicated when you\u0026rsquo;re using version ranges.\u003c/p\u003e\n\n\n\n\n\u003ch3 id=\"best-practices\"\u003e\u003ca href=\"/posts/nuget-packagedownload-functionality/#best-practices\" title=\"Best Practices\"\u003eBest Practices\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003eDocument your intent by adding comments explaining why you\u0026rsquo;re using PackageDownload instead of PackageReference. It saves confusion later. Since CPM doesn\u0026rsquo;t work, centralize versions manually using MSBuild properties:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-xml\" data-lang=\"xml\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003e\u0026lt;!-- Using PackageDownload to avoid runtime dependency on StyleCop --\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003e\u0026lt;PackageDownload\u003c/span\u003e \u003cspan class=\"na\"\u003eInclude=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;StyleCop.Analyzers\u0026#34;\u003c/span\u003e \u003cspan class=\"na\"\u003eVersion=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;[1.2.0]\u0026#34;\u003c/span\u003e \u003cspan class=\"nt\"\u003e/\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eThis approach at least keeps versions in one place, even if it\u0026rsquo;s not as elegant as CPM. And always test in clean environments — PackageDownload failures often appear only during initial restore, not in your local development setup where everything\u0026rsquo;s already cached.\u003c/p\u003e\n\n\n\n\n\u003ch2 id=\"final-thoughts-a-tool-that-works-with-caveats\"\u003e\u003ca href=\"/posts/nuget-packagedownload-functionality/#final-thoughts-a-tool-that-works-with-caveats\" title=\"Final Thoughts: A Tool That Works, With Caveats\"\u003eFinal Thoughts: A Tool That Works, With Caveats\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003ePackageDownload solves a real problem. It enables scenarios that would otherwise require awkward workarounds or custom scripting. For teams managing complex build pipelines, it\u0026rsquo;s indispensable.\u003c/p\u003e\n\u003cp\u003eBut its limitations aren\u0026rsquo;t minor inconveniences. The version range requirement is unintuitive. The lack of CPM integration is inexcusable. And the documentation assumes you already know what you\u0026rsquo;re doing.\u003c/p\u003e\n\u003cp\u003eThis is what happens when platforms evolve without a coherent strategy. Features get added. They solve problems. But they don\u0026rsquo;t integrate. They coexist, awkwardly, creating friction for developers who just want things to work.\u003c/p\u003e\n\u003cp\u003ePackageDownload is powerful. It\u0026rsquo;s also a reminder that mature ecosystems carry baggage. Sometimes that baggage is worth the trade-off. Other times, it\u0026rsquo;s just frustrating.\u003c/p\u003e\n\u003cp\u003eKnow when you need it. Understand its limitations. And hope that someday, Microsoft decides to make it work with the rest of the tooling.\u003c/p\u003e\n\u003cp\u003eUntil then, it\u0026rsquo;s another tool in your arsenal — useful, imperfect, and occasionally infuriating.\u003c/p\u003e\n","date_modified":"2026-05-26T10:22:03+02:00","date_published":"2025-10-29T18:00:00+01:00","id":"https://daily-devops.net/posts/nuget-packagedownload-functionality/","language":"en","summary":"PackageDownload solves a real problem most developers don't know exists. But its painful limitations reveal the cost of evolving mature platforms.\n","tags":["nuget","dotnet","dependency-management","msbuild","bestpractices","technicaldebt"],"title":"PackageDownload: NuGet's Forgotten Power Tool\n","url":"https://daily-devops.net/posts/nuget-packagedownload-functionality/"},{"authors":[{"name":"Martin Stühmer","url":"https://daily-devops.net/authors/martin/"}],"content_html":"\u003cp\u003eIn software development, there’s a silent debt that accrues interest over time, often hidden beneath layers of code and decisions made in haste or ignorance. This debt is aptly termed \u003cem\u003etechnical debt\u003c/em\u003e. Much like the german proverb, \u003cem\u003e\u0026ldquo;Wer den Pfennig nicht ehrt, ist den Taler nicht wert\u0026rdquo;,\u003c/em\u003e (or the english equivalent, \u003cem\u003e\u0026ldquo;A penny saved is a penny earned\u0026rdquo;\u003c/em\u003e) technical debt reminds us that small oversights or compromises in the present can snowball into significant challenges down the road. This article critically examines the parallels between financial principles and technical debt, emphasizing the importance of addressing both direct and indirect debt while understanding its distinction from external risks such as hacking or abuse.\u003c/p\u003e\n\n\n\n\n\u003ch2 id=\"understanding-technical-debt-an-analogy-to-finance\"\u003e\u003ca href=\"/posts/tale-of-forgotten-pennies-and-lost-dollars/#understanding-technical-debt-an-analogy-to-finance\" title=\"Understanding Technical Debt: An Analogy to Finance\"\u003eUnderstanding Technical Debt: An Analogy to Finance\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eAt its core, technical debt is a metaphor borrowed from finance. When developers take shortcuts—perhaps by writing suboptimal code or delaying refactoring—they incur a \u0026ldquo;debt\u0026rdquo; that must eventually be \u0026ldquo;repaid\u0026rdquo; through additional effort, time, and resources. Like monetary debt, technical debt accumulates interest in the form of maintenance overhead, slower development cycles, and reduced system stability.\u003c/p\u003e\n\u003cp\u003eIn financial terms, there are two types of debt:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eGood Debt\u003c/strong\u003e: Investments like mortgages or education loans, where borrowing yields long-term benefits.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eBad Debt\u003c/strong\u003e: High-interest loans or credit card balances, where borrowing becomes a perpetual burden.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eSimilarly, technical debt can be intentional or unintentional:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eIntentional Technical Debt\u003c/strong\u003e: Decisions made knowingly to meet deadlines or prioritize feature delivery. This is akin to taking a calculated loan with the intention to repay soon.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eUnintentional Technical Debt\u003c/strong\u003e: Debt accrued due to lack of knowledge, poor design, or inadequate code reviews. This resembles bad debt—unplanned and harmful over time.\u003c/li\u003e\n\u003c/ul\u003e\n\n\n\n\n\u003ch2 id=\"intentional-vs-unintentional-technical-debt\"\u003e\u003ca href=\"/posts/tale-of-forgotten-pennies-and-lost-dollars/#intentional-vs-unintentional-technical-debt\" title=\"Intentional vs. Unintentional Technical Debt\"\u003eIntentional vs. Unintentional Technical Debt\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eNot all technical debt is created equal. To fully grasp its impact, it’s critical to differentiate between \u003cstrong\u003eintentional\u003c/strong\u003e and \u003cstrong\u003eunintentional\u003c/strong\u003e technical debt.\u003c/p\u003e\n\n\n\n\n\u003ch3 id=\"intentional-technical-debt\"\u003e\u003ca href=\"/posts/tale-of-forgotten-pennies-and-lost-dollars/#intentional-technical-debt\" title=\"Intentional Technical Debt\"\u003eIntentional Technical Debt\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003eThis is the visible and measurable debt—the code shortcuts, hardcoded values, or outdated libraries. Developers know it exists and can point to it with precision. Examples include:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eSkipping unit tests to deliver a feature faster.\u003c/li\u003e\n\u003cli\u003eWriting non-optimized SQL queries.\u003c/li\u003e\n\u003cli\u003eUsing deprecated APIs for quicker implementation.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eDirect technical debt is like borrowing a small sum with a clear repayment plan. The problem arises when repayment is delayed, leading to compounding interest.\u003c/p\u003e\n\n\n\n\n\u003ch3 id=\"indirect-technical-debt\"\u003e\u003ca href=\"/posts/tale-of-forgotten-pennies-and-lost-dollars/#indirect-technical-debt\" title=\"Indirect Technical Debt\"\u003eIndirect Technical Debt\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003eThis is the hidden debt that manifests indirectly over time, often as a consequence of direct debt or systemic issues. Examples include:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003ePoorly documented code leading to knowledge silos.\u003c/li\u003e\n\u003cli\u003eOutdated infrastructure that becomes harder to replace.\u003c/li\u003e\n\u003cli\u003eAccumulated complexity that slows innovation.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eIndirect debt is insidious—it’s harder to quantify and often only becomes apparent when the system begins to falter.\u003c/p\u003e\n\n\n\n\n\u003ch2 id=\"the-compound-interest-effect-in-technical-debt\"\u003e\u003ca href=\"/posts/tale-of-forgotten-pennies-and-lost-dollars/#the-compound-interest-effect-in-technical-debt\" title=\"The Compound Interest Effect in Technical Debt\"\u003eThe Compound Interest Effect in Technical Debt\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eA defining feature of both financial and technical debt is \u003cem\u003ecompound interest\u003c/em\u003e. In software, this translates to the exponential growth of effort required to address issues as they remain unresolved.\u003c/p\u003e\n\n\n\n\n\u003ch3 id=\"financial-analogy-the-power-of-compound-interest\"\u003e\u003ca href=\"/posts/tale-of-forgotten-pennies-and-lost-dollars/#financial-analogy-the-power-of-compound-interest\" title=\"Financial Analogy: The Power of Compound Interest\"\u003eFinancial Analogy: The Power of Compound Interest\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003eIn finance, compound interest is a double-edged sword. For savings, it’s a wealth generator. For debt, it’s a destroyer. A $1,000 credit card balance at 20% annual interest, left unpaid, grows to over $6,000 in just 10 years.\u003c/p\u003e\n\n\n\n\n\u003ch3 id=\"technical-debts-compound-interest\"\u003e\u003ca href=\"/posts/tale-of-forgotten-pennies-and-lost-dollars/#technical-debts-compound-interest\" title=\"Technical Debt’s Compound Interest\"\u003eTechnical Debt’s Compound Interest\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003eIn technical systems, unresolved debt compounds in the following ways:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\u003cstrong\u003eIncreased Maintenance Costs\u003c/strong\u003e: Every new feature or bug fix becomes harder to implement in a convoluted codebase.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eTeam Productivity Decline\u003c/strong\u003e: Developers spend more time deciphering old code instead of writing new features.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eHigher Failure Risk\u003c/strong\u003e: Overloaded systems are more prone to bugs and outages.\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003eFor instance, ignoring outdated dependencies today might seem trivial, but in a year, these dependencies could cause compatibility issues that require a complete system overhaul.\u003c/p\u003e\n\n\n\n\n\u003ch2 id=\"the-financial-mindset-paying-off-debt-wisely\"\u003e\u003ca href=\"/posts/tale-of-forgotten-pennies-and-lost-dollars/#the-financial-mindset-paying-off-debt-wisely\" title=\"The Financial Mindset: Paying Off Debt Wisely\"\u003eThe Financial Mindset: Paying Off Debt Wisely\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eTo manage technical debt effectively, developers and stakeholders need to adopt a financial mindset, considering concepts like \u003cstrong\u003eamortization\u003c/strong\u003e, \u003cstrong\u003eprincipal repayment\u003c/strong\u003e, and \u003cstrong\u003erisk assessment\u003c/strong\u003e.\u003c/p\u003e\n\n\n\n\n\u003ch3 id=\"amortization-gradual-repayment\"\u003e\u003ca href=\"/posts/tale-of-forgotten-pennies-and-lost-dollars/#amortization-gradual-repayment\" title=\"Amortization: Gradual Repayment\"\u003eAmortization: Gradual Repayment\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003eAmortization is the process of gradually paying off a debt over time. In technical debt terms, this means allocating time in each sprint or release to tackle existing debt. For example:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003ePrincipal\u003c/strong\u003e: Refactor key modules incrementally.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eInterest\u003c/strong\u003e: Address bugs and performance issues caused by the debt.\u003c/li\u003e\n\u003c/ul\u003e\n\n\n\n\n\u003ch3 id=\"cost-benefit-analysis\"\u003e\u003ca href=\"/posts/tale-of-forgotten-pennies-and-lost-dollars/#cost-benefit-analysis\" title=\"Cost-Benefit Analysis\"\u003eCost-Benefit Analysis\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003eEvery debt repayment decision should involve a cost-benefit analysis. Ask questions like:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eWhat’s the effort required to fix this debt?\u003c/li\u003e\n\u003cli\u003eWhat’s the risk of leaving it unresolved?\u003c/li\u003e\n\u003cli\u003eWill repaying it now unlock future opportunities?\u003c/li\u003e\n\u003c/ul\u003e\n\n\n\n\n\u003ch3 id=\"debt-consolidation-strategic-prioritization\"\u003e\u003ca href=\"/posts/tale-of-forgotten-pennies-and-lost-dollars/#debt-consolidation-strategic-prioritization\" title=\"Debt Consolidation: Strategic Prioritization\"\u003eDebt Consolidation: Strategic Prioritization\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003eIn finance, consolidating loans simplifies repayment. Similarly, technical debt can be \u0026ldquo;consolidated\u0026rdquo; by identifying the most critical areas to address first. Focus on high-impact debt—areas where small fixes can yield significant improvements.\u003c/p\u003e\n\n\n\n\n\u003ch2 id=\"external-risks-are-not-technical-debt\"\u003e\u003ca href=\"/posts/tale-of-forgotten-pennies-and-lost-dollars/#external-risks-are-not-technical-debt\" title=\"External Risks Are Not Technical Debt\"\u003eExternal Risks Are Not Technical Debt\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eIt’s essential to distinguish technical debt from external risks such as hacking, misuse, or other security vulnerabilities. While they may share some consequences, the root causes and solutions differ.\u003c/p\u003e\n\n\n\n\n\u003ch3 id=\"differences-in-scope\"\u003e\u003ca href=\"/posts/tale-of-forgotten-pennies-and-lost-dollars/#differences-in-scope\" title=\"Differences in Scope\"\u003eDifferences in Scope\u003c/a\u003e\u003c/h3\u003e\n\u003ctable\u003e\n\t\u003cthead\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003cth\u003e\u003cstrong\u003eAspect\u003c/strong\u003e\u003c/th\u003e\n\t\t\t\t\t\u003cth\u003e\u003cstrong\u003eTechnical Debt\u003c/strong\u003e\u003c/th\u003e\n\t\t\t\t\t\u003cth\u003e\u003cstrong\u003eExternal Risks\u003c/strong\u003e\u003c/th\u003e\n\t\t\t\u003c/tr\u003e\n\t\u003c/thead\u003e\n\t\u003ctbody\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003ctd\u003e\u003cstrong\u003eOrigin\u003c/strong\u003e\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003eInternal decisions or shortcuts\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003eExternal threats or bad actors\u003c/td\u003e\n\t\t\t\u003c/tr\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003ctd\u003e\u003cstrong\u003eControl\u003c/strong\u003e\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003eFully within the development team’s control\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003ePartially or entirely external\u003c/td\u003e\n\t\t\t\u003c/tr\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003ctd\u003e\u003cstrong\u003eMitigation\u003c/strong\u003e\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003eRefactoring, tests, documentation\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003eSecurity protocols, firewalls, monitoring\u003c/td\u003e\n\t\t\t\u003c/tr\u003e\n\t\u003c/tbody\u003e\n\u003c/table\u003e\n\n\n\n\n\u003ch3 id=\"overlap-when-risks-become-debt\"\u003e\u003ca href=\"/posts/tale-of-forgotten-pennies-and-lost-dollars/#overlap-when-risks-become-debt\" title=\"Overlap: When Risks Become Debt\"\u003eOverlap: When Risks Become Debt\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003eOccasionally, external risks can create technical debt. For example, failing to patch a known vulnerability due to resource constraints incurs a debt that compounds if the system is exploited.\u003c/p\u003e\n\n\n\n\n\u003ch2 id=\"a-self-reflective-look-where-we-fall-short\"\u003e\u003ca href=\"/posts/tale-of-forgotten-pennies-and-lost-dollars/#a-self-reflective-look-where-we-fall-short\" title=\"A Self-Reflective Look: Where We Fall Short\"\u003eA Self-Reflective Look: Where We Fall Short\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eAs developers, we often rationalize technical debt. We promise to revisit a quick fix later or assume that future teams will handle the mess we leave behind. These assumptions are rarely true. In reality:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\u003cstrong\u003eShort-Term Thinking Prevails\u003c/strong\u003e: Deadlines often take precedence over quality, leading to rushed decisions.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eDebt Is Underestimated\u003c/strong\u003e: Teams often misjudge the time and effort required to repay debt.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eStakeholders Lack Awareness\u003c/strong\u003e: Non-technical stakeholders may not understand the implications of debt, leading to underinvestment in addressing it.\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003eThis self-critique is not to assign blame but to encourage accountability. We must recognize our role in creating and perpetuating debt, as well as our power to mitigate it.\u003c/p\u003e\n\n\n\n\n\u003ch2 id=\"honoring-the-penny-practical-steps-forward\"\u003e\u003ca href=\"/posts/tale-of-forgotten-pennies-and-lost-dollars/#honoring-the-penny-practical-steps-forward\" title=\"Honoring the Penny: Practical Steps Forward\"\u003eHonoring the Penny: Practical Steps Forward\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eTo honor the \u0026ldquo;penny\u0026rdquo; of technical debt and avoid losing the \u0026ldquo;dollar\u0026rdquo; of system stability, consider the following practices:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\u003cstrong\u003eTrack Debt Transparently\u003c/strong\u003e: Use tools to log and prioritize technical debt alongside feature development.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eImplement Governance\u003c/strong\u003e: Establish policies for code quality, testing, and documentation to minimize unintentional debt.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eEducate Stakeholders\u003c/strong\u003e: Communicate the cost of debt in terms stakeholders understand—time, money, and risk.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eCelebrate Refactoring\u003c/strong\u003e: Make debt repayment a visible and celebrated part of your team’s work.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eAutomate Debt Detection\u003c/strong\u003e: Use static analysis tools to identify debt early in the development process.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eEncourage Ownership\u003c/strong\u003e: Empower developers and operations to take responsibility for the debt they create and resolve it proactively.\u003c/li\u003e\n\u003c/ol\u003e\n\n\n\n\n\u003ch2 id=\"conclusion\"\u003e\u003ca href=\"/posts/tale-of-forgotten-pennies-and-lost-dollars/#conclusion\" title=\"Conclusion\"\u003eConclusion\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eThe proverb \u003cem\u003e\u0026ldquo;Wer den Pfennig nicht ehrt, ist den Taler nicht wert\u0026rdquo;\u003c/em\u003e teaches us the value of small, consistent actions. In software development, this wisdom is crucial for managing technical debt. By respecting the pennies—addressing small issues promptly and intentionally—we can avoid the compound interest that turns minor debts into major crises.\u003c/p\u003e\n\u003cp\u003eAs stewards of our systems, let us commit to honoring the pennies of our craft, ensuring that our codebases remain worthy of the dollars they aim to generate.\u003c/p\u003e\n","date_modified":"2026-05-25T23:10:21+02:00","date_published":"2024-11-22T16:45:00+01:00","id":"https://daily-devops.net/posts/tale-of-forgotten-pennies-and-lost-dollars/","language":"en","summary":"Discover how small technical debts accumulate into major project costs and learn strategies to manage them effectively in software development.","tags":["technicaldebt","bestpractices","dependency-management","rcda","softwareengineering"],"title":"A Tale of Forgotten Pennies and Lost Dollars","url":"https://daily-devops.net/posts/tale-of-forgotten-pennies-and-lost-dollars/"},{"authors":[{"name":"Martin Stühmer","url":"https://daily-devops.net/authors/martin/"}],"content_html":"\u003cp\u003eIn software development, dependencies are inevitable - any project worth its salt relies on various libraries, frameworks, or packages. However, as I found in my own work, managing these dependencies can be an onerous task. Constant updates, new vulnerabilities, and endless manual approvals were draining my time and focus. What if, I thought, these processes could be automated? This thought led to the creation of \u003ccode\u003edependamerge\u003c/code\u003e, a GitHub Action designed to free developers from the drudgery of manual dependency maintenance and let us get back to what we do best: building great software.\u003c/p\u003e\n\n\n\n\n\u003ch2 id=\"the-realities-of-manual-dependency-management-my-journey\"\u003e\u003ca href=\"/posts/dependamerge-action/#the-realities-of-manual-dependency-management-my-journey\" title=\"The realities of manual dependency management: My journey\"\u003eThe realities of manual dependency management: My journey\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eLike many developers, I used to spend a lot of time managing dependencies. Dependabot would helpfully create pull requests for each new release, but I still had to check and merge each one. This quickly became an endless cycle. The hassle of checking every dependency update, even minor ones, pulled me away from critical tasks.\u003c/p\u003e\n\u003cp\u003eThe reality is that as teams grow in size, dependency management becomes increasingly complex. For a while, I was stuck in a manual cycle, balancing the risk of out-of-date dependencies against the time commitment of updates. This tension was a big factor that inspired \u003ccode\u003edependamerge\u003c/code\u003e.\u003c/p\u003e\n\n\n\n\n\u003ch3 id=\"why-automation-why-now\"\u003e\u003ca href=\"/posts/dependamerge-action/#why-automation-why-now\" title=\"Why automation? Why now?\"\u003eWhy automation? Why now?\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003eMy experience echoed the frustrations faced by many developers:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\u003cstrong\u003eUnending maintenance\u003c/strong\u003e: Keeping up with dependency updates is like an unrelenting treadmill. Without automation, it’s all too easy for obsolete packages to slip through the cracks.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eDisrupted flow\u003c/strong\u003e: Each pull request interrupts the flow, forcing us to context-switch and potentially delaying real progress.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eSecurity pressure\u003c/strong\u003e: At a time when vulnerabilities can bring down entire ecosystems, dependency maintenance is non-negotiable, but finding the time to do it can feel impossible.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eProductivity drain\u003c/strong\u003e: Manual dependency management is a time sink, diverting focus from the core work of building and improving software.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eTechnical debt\u003c/strong\u003e: Neglected dependencies can accumulate into a significant technical debt, leading to more problems down the line.\u003c/li\u003e\n\u003c/ol\u003e\n\n\n\n\n\u003ch3 id=\"benefits-of-automation\"\u003e\u003ca href=\"/posts/dependamerge-action/#benefits-of-automation\" title=\"Benefits of automation\"\u003eBenefits of automation\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003eAutomating dependency management with \u003ccode\u003edependamerge\u003c/code\u003e brings a range of significant benefits that streamline development and enhance code quality:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cstrong\u003eTime-Saving\u003c/strong\u003e: By automating dependency updates, \u003ccode\u003edependamerge\u003c/code\u003e saves developers from manually reviewing each pull request. This efficiency frees up hours each week, allowing teams to focus on feature development and innovation rather than getting bogged down by routine maintenance.\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cstrong\u003eEnhanced Security\u003c/strong\u003e: In today’s landscape, where vulnerabilities can have far-reaching impacts, timely updates are essential for maintaining a secure codebase. With \u003ccode\u003edependamerge\u003c/code\u003e, critical updates can be applied promptly and consistently, helping to protect your projects from potential threats. Automation ensures that nothing slips through the cracks, even when time is limited.\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cstrong\u003eImproved Code Quality and Stability\u003c/strong\u003e: Automated dependency updates reduce the risk of errors that can occur when manually merging changes across environments. Consistent updates prevent compatibility issues that might arise from neglected dependencies, contributing to a more stable and reliable codebase.\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cstrong\u003eReduced Technical Debt\u003c/strong\u003e: By keeping dependencies up-to-date, \u003ccode\u003edependamerge\u003c/code\u003e helps prevent the buildup of technical debt that can slow down future development and create unexpected blockers. With fewer outdated dependencies, teams can avoid the last-minute scramble to upgrade critical packages or dependencies right before a major release.\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cstrong\u003eSeamless Integration in CI/CD Workflows\u003c/strong\u003e: \u003ccode\u003edependamerge\u003c/code\u003e is designed to operate smoothly within a CI/CD pipeline, allowing dependency updates to be tested and validated alongside other code changes. This integration reduces interruptions to the workflow and ensures that updates don’t introduce issues at later stages in the development lifecycle.\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eBy automating these repetitive tasks, \u003ccode\u003edependamerge\u003c/code\u003e empowers developers to focus on what matters most: building and improving software. It’s a tool that boosts productivity, enhances security, and ultimately contributes to a more efficient and resilient development process.\u003c/p\u003e\n\n\n\n\n\u003ch2 id=\"the-solution-dependamerge\"\u003e\u003ca href=\"/posts/dependamerge-action/#the-solution-dependamerge\" title=\"The Solution: dependamerge\"\u003eThe Solution: dependamerge\u003c/a\u003e\u003c/h2\u003e\n\n\n\n\n\u003ch3 id=\"introducing-dependamerge-a-solution-built-for-developers\"\u003e\u003ca href=\"/posts/dependamerge-action/#introducing-dependamerge-a-solution-built-for-developers\" title=\"Introducing dependamerge: A solution built for developers\"\u003eIntroducing dependamerge: A solution built for developers\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003eDesigned to take the reins of dependency updates, \u003ccode\u003edependamerge\u003c/code\u003e works with Dependabot to make dependency management truly seamless. This GitHub action doesn\u0026rsquo;t just approve updates—it is adjustable to your project’s specific needs, ensuring that only the right updates are merged at the right time. Even better, \u003ccode\u003edependamerge\u003c/code\u003e can be part of a fully automated CI/CD pipeline, ensuring that dependency updates are tested and validated alongside other code changes.\u003c/p\u003e\n\u003ca href=\"https://github.com/dailydevops/dependamerge-action\" class=\"linked\" target=\"_blank\" rel=\"noopener external noreferrer\" title=\"GitHub action that automatically validates, approves, and merges pull requests for branches created by dependabot[bot]\"\u003e\n  \u003cimg src=\"/images/github-dailydevops-dependamerge-action.png\" class=\"repository\" width=\"1200\" height=\"630\" title=\"GitHub action that automatically validates, approves, and merges pull requests for branches created by dependabot[bot]\" alt=\"GitHub action that automatically validates, approves, and merges pull requests for branches created by dependabot[bot]\" /\u003e\n\u003c/a\u003e\n\u003cp\u003eHighlights of \u003ccode\u003edependamerge\u003c/code\u003e include:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\u003cstrong\u003eFully compatible with Dependabot\u003c/strong\u003e: \u003ccode\u003edependamerge\u003c/code\u003e works seamlessly with Dependabot, extending its capabilities and streamlining the update process. To do this, \u003ccode\u003edependamerge\u003c/code\u003e communicates with Dependabot\u0026rsquo;s comment commands to manage the pull requests.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eAutomated merging\u003c/strong\u003e: With the ability to define specific merge rules, updates are approved without disrupting your day. Regardless of the ecosystem, all current and future Dependabot ecosystems are supported.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eCustomizable conditions\u003c/strong\u003e: Tailor the automation to prioritize critical updates, such as security patches, while handling non-critical updates according to your project’s needs.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eHuman-Free Handling\u003c/strong\u003e: Freeing developers from dependency maintenance not only saves time, but also prevents mental fatigue from routine tasks. \u003ccode\u003edependamerge\u003c/code\u003e ensures that updates are handled consistently and reliably, without manual intervention.\u003c/li\u003e\n\u003c/ol\u003e\n\n\n\n\n\u003ch3 id=\"usage-example-setting-up-dependamerge-in-a-cicd-pipeline\"\u003e\u003ca href=\"/posts/dependamerge-action/#usage-example-setting-up-dependamerge-in-a-cicd-pipeline\" title=\"Usage example: Setting up dependamerge in a CI/CD pipeline\"\u003eUsage example: Setting up dependamerge in a CI/CD pipeline\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003eTo start with \u003ccode\u003edependamerge\u003c/code\u003e, you can use the following example configuration. This GitHub action is highly customizable, allowing you to adjust various parameters to suit your project’s specific requirements.\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003ename\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l\"\u003eDependaMerge\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003eon\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e  \u003c/span\u003e\u003cspan class=\"nt\"\u003epull_request\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003ejobs\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e  \u003c/span\u003e\u003cspan class=\"nt\"\u003edependabot\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"nt\"\u003eruns-on\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l\"\u003eubuntu-latest\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"nt\"\u003esteps\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e      \u003c/span\u003e- \u003cspan class=\"nt\"\u003euses\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l\"\u003eactions/checkout@v2\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e      \u003c/span\u003e- \u003cspan class=\"nt\"\u003ename\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l\"\u003eDependaMerge\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e        \u003c/span\u003e\u003cspan class=\"nt\"\u003euses\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l\"\u003edailydevops/action-dependamerge@v1\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e        \u003c/span\u003e\u003cspan class=\"nt\"\u003ewith\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e          \u003c/span\u003e\u003cspan class=\"nt\"\u003etoken\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l\"\u003e${{ secrets.GITHUB_TOKEN }}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e          \u003c/span\u003e\u003cspan class=\"nt\"\u003ecommand\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"l\"\u003esquash\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"c\"\u003e# Merge all commits into one (default)\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\n\n\n\u003ch3 id=\"key-parameters-and-options\"\u003e\u003ca href=\"/posts/dependamerge-action/#key-parameters-and-options\" title=\"Key Parameters and Options\"\u003eKey Parameters and Options\u003c/a\u003e\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ccode\u003ecommand\u003c/code\u003e: Specifies how the pull request is merged. Options include:\n\u003cul\u003e\n\u003cli\u003e\u003ccode\u003esquash\u003c/code\u003e (default): Combines all commits into one.\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003emerge\u003c/code\u003e: Maintains commit history.\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003erebase\u003c/code\u003e: Rebases the pull request if it’s behind the target branch.\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eapprove-only\u003c/code\u003e: If set to \u003ccode\u003etrue\u003c/code\u003e, the action will only approve, not merge, the pull request.\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003etarget\u003c/code\u003e: Defines the maximum version increment level (\u003ccode\u003emajor\u003c/code\u003e, \u003ccode\u003eminor\u003c/code\u003e, \u003ccode\u003epatch\u003c/code\u003e, or \u003ccode\u003eany\u003c/code\u003e), giving you control over the scope of updates. Default is \u003ccode\u003epatch\u003c/code\u003e.\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003ehandle-dependency-group\u003c/code\u003e: Merges all pull requests in a specified dependency group, allowing related updates to be applied together.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eThese configurable options ensure that \u003ccode\u003edependamerge\u003c/code\u003e aligns precisely with your team’s requirements.\u003c/p\u003e\n\n\n\n\n\u003ch3 id=\"output-parameters-understanding-and-utilizing-results\"\u003e\u003ca href=\"/posts/dependamerge-action/#output-parameters-understanding-and-utilizing-results\" title=\"Output Parameters: Understanding and Utilizing Results\"\u003eOutput Parameters: Understanding and Utilizing Results\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003eThe output parameters in \u003ccode\u003edependamerge\u003c/code\u003e provide a valuable summary of each action’s status and results, allowing you to programmatically react based on outcomes. Two key outputs include:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ccode\u003estate\u003c/code\u003e: Indicates the action’s status, including:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ccode\u003eapproved\u003c/code\u003e: Pull request was successfully approved.\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003emerged\u003c/code\u003e: Pull request was merged.\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eskipped\u003c/code\u003e: Action skipped the pull request, halting further processing.\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003efailed\u003c/code\u003e: Action couldn’t process the pull request due to errors.\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003erebased\u003c/code\u003e: PR was rebased due to behind-branch status.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003cstrong\u003eBenefit\u003c/strong\u003e: By checking the \u003ccode\u003estate\u003c/code\u003e output, your workflow can respond to each action outcome. For example, you could add conditional notifications for failed or skipped updates to ensure immediate attention or skip further testing if the pull request was already merged.\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003ccode\u003emessage\u003c/code\u003e: Contains additional information on the processing state, including error and debug details.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eBenefit\u003c/strong\u003e: The \u003ccode\u003emessage\u003c/code\u003e output parameter can be leveraged for logging purposes or sent in a notification, enabling better tracking and diagnostics without requiring manual review. It’s especially useful for troubleshooting and ensuring full transparency of the automation process.\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eThese output parameters add an essential layer of feedback, enabling automated downstream workflows based on \u003ccode\u003edependamerge\u003c/code\u003e outcomes. The increased control and visibility improve overall workflow reliability and responsiveness.\u003c/p\u003e\n\u003cp\u003eDesigned to take the reins of dependency updates, \u003ccode\u003edependamerge\u003c/code\u003e works with Dependabot to make dependency management truly seamless. This GitHub action doesn\u0026rsquo;t just approve updates—it is adjustable to your project’s specific needs, ensuring that only the right updates are merged at the right time. Even better, \u003ccode\u003edependamerge\u003c/code\u003e can be part of a fully automated CI/CD pipeline, ensuring that dependency updates are tested and validated alongside other code changes.\u003c/p\u003e\n\n\n\n\n\u003ch2 id=\"community-and-contributions\"\u003e\u003ca href=\"/posts/dependamerge-action/#community-and-contributions\" title=\"Community and Contributions\"\u003eCommunity and Contributions\u003c/a\u003e\u003c/h2\u003e\n\n\n\n\n\u003ch3 id=\"open-source-your-contributions-matter\"\u003e\u003ca href=\"/posts/dependamerge-action/#open-source-your-contributions-matter\" title=\"Open-source, your contributions matter\"\u003eOpen-source, your contributions matter\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003e\u003ccode\u003edependamerge\u003c/code\u003e thrives on community input. Whether you’re a developer, or user, your feedback and contributions are invaluable. By sharing your experiences, suggesting improvements, or submitting code, you can help shape the future of \u003ccode\u003edependamerge\u003c/code\u003e. Every contribution, no matter how small, makes a difference in creating a more efficient and effective dependency management solution for all. - \u003ca href=\"https://github.com/dailydevops/action-dependamerge\" target=\"_blank\" rel=\"noopener external noreferrer\"\u003edailydevops/action-dependamerge\u003c/a\u003e\u003c/p\u003e\n\n\n\n\n\u003ch2 id=\"conclusion\"\u003e\u003ca href=\"/posts/dependamerge-action/#conclusion\" title=\"Conclusion\"\u003eConclusion\u003c/a\u003e\u003c/h2\u003e\n\n\n\n\n\u003ch3 id=\"flexibility-under-control-dependamerge-for-all\"\u003e\u003ca href=\"/posts/dependamerge-action/#flexibility-under-control-dependamerge-for-all\" title=\"Flexibility under control: dependamerge for all\"\u003eFlexibility under control: dependamerge for all\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003eWhether you’re working on a private project, an open-source initiative, or a company-driven application, \u003ccode\u003edependamerge\u003c/code\u003e is designed to meet your needs. By automating dependency management, you can focus on building great software without the burden of manual updates. The flexibility and customization options in \u003ccode\u003edependamerge\u003c/code\u003e ensure that you can tailor the automation to your project’s specific requirements, making it a valuable addition to any development workflow.\u003c/p\u003e\n\u003cp\u003eIf you\u0026rsquo;re like me, frustrated by dependency management’s time-consuming nature, \u003ccode\u003edependamerge\u003c/code\u003e is the solution you’ve been waiting for. Try it out, contribute, and help shape the future of dependency management automation. Together, we can build a more efficient, secure, and productive development process for all.\u003c/p\u003e","date_modified":"2026-05-26T10:22:03+02:00","date_published":"2024-11-13T09:00:00+01:00","id":"https://daily-devops.net/posts/dependamerge-action/","language":"en","summary":"Learn how to automate dependency management with the dependamerge GitHub Action for streamlined security updates, maintenance workflows, and automated PRs.","tags":["dependency-management","bestpractices","github","github-actions","nuget","technicaldebt"],"title":"dependamerge-action: Automated Dependency Merging","url":"https://daily-devops.net/posts/dependamerge-action/"},{"authors":[{"name":"Martin Stühmer","url":"https://daily-devops.net/authors/martin/"}],"content_html":"\u003cp\u003eFor over 12 years, NuGet package management has been part of the .NET ecosystem with direct integrations to various IDEs, CLIs and build systems. But a feature took 12 years before it appeared and certainly needs some more maintenance until it is mature!\u003c/p\u003e\n\n\n\n\n\u003ch2 id=\"the-issue\"\u003e\u003ca href=\"/posts/manage-nuget-packages-centrally/#the-issue\" title=\"The issue\"\u003eThe issue\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eRegardless of the code version management strategy, mono-repository vs. poly-repository, there has always been a need to synchronize the individual projects in the versions of NuGet packages used. Reasons for this are compatibility and security, but also new functionalities or bug fixes.\u003c/p\u003e\n\n\n\n\n\u003ch2 id=\"earlier-approaches\"\u003e\u003ca href=\"/posts/manage-nuget-packages-centrally/#earlier-approaches\" title=\"Earlier approaches\"\u003eEarlier approaches\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eOver the years, the requirements in this area have evolved more and more, so that the previous solution approaches increasingly reached their limits. Not only the uniform use of the same package version, but also the general use of a package in all related projects of a solution was taken up and developed further in this context. However, the main shortcoming could never be solved; until now, manual intervention by a developer was always necessary to update the version of the packages used. The existing integrations of IDEs and CLIs produced more errors than they could fix.\u003c/p\u003e\n\n\n\n\n\u003ch2 id=\"central-package-management-cpm\"\u003e\u003ca href=\"/posts/manage-nuget-packages-centrally/#central-package-management-cpm\" title=\"Central Package Management (CPM)\"\u003eCentral Package Management (CPM)\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eNow the request has been fulfilled and in April 2022 the \u003ca href=\"https://learn.microsoft.com/en-us/nuget/consume-packages/Central-Package-Management\" target=\"_blank\" rel=\"noopener external noreferrer\"\u003eCentral Package Management (\u0026ldquo;CPM\u0026rdquo;)\u003c/a\u003e was introduced and released along with NuGet version 6.2 and some complementary features.\u003c/p\u003e\n\u003cp\u003eTo enable central package management, the MSBuild property \u003ccode\u003eManagePackageVersionsCentrally\u003c/code\u003e is set to \u003ccode\u003etrue\u003c/code\u003e in the \u003ccode\u003eDirectory.Packages.props\u003c/code\u003e file.\u003c/p\u003e\n\u003cp\u003eFor version listing and management, \u003ccode\u003ePackageVersion\u003c/code\u003e elements are required, each containing the package name and the version to be used. The next step is to remove the \u003ccode\u003eVersion\u003c/code\u003e attribute from all \u003ccode\u003ePackageReference\u003c/code\u003e elements in the project files. This migrates the solution and it will use the central package management from now on.\u003c/p\u003e\n\n\n\n\n\u003ch3 id=\"additional-feature-transitive-pinning\"\u003e\u003ca href=\"/posts/manage-nuget-packages-centrally/#additional-feature-transitive-pinning\" title=\"Additional feature: Transitive pinning\"\u003eAdditional feature: Transitive pinning\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003eSetting the MSBuild property \u003ccode\u003eCentralPackageTransitivePinningEnabled\u003c/code\u003e to \u003ccode\u003etrue\u003c/code\u003e tells NuGet to update all transitive dependencies from their explicitly defined dependencies. This property can be set in both \u003ca href=\"https://learn.microsoft.com/en-us/visualstudio/msbuild/customize-by-directory?view=vs-2022#directorybuildprops-and-directorybuildtargets\" target=\"_blank\" rel=\"noopener external noreferrer\"\u003e\u003ccode\u003eDirectory.Build.props\u003c/code\u003e\u003c/a\u003e and the aforementioned \u003ccode\u003eDirectory.Packages.props\u003c/code\u003e.\u003c/p\u003e\n\n\n\n\n\u003ch3 id=\"additional-feature-global-package-references\"\u003e\u003ca href=\"/posts/manage-nuget-packages-centrally/#additional-feature-global-package-references\" title=\"Additional feature: Global Package References\"\u003eAdditional feature: Global Package References\u003c/a\u003e\u003c/h3\u003e\n\u003cp\u003eAnother feature is \u003ccode\u003eGlobalPackageReference\u003c/code\u003e, which can be used to reference a package in any project of the solution / repository, such as code analyzer. This kind of package referencing should also be done in \u003ccode\u003eDirectory.Packages.props\u003c/code\u003e.\u003c/p\u003e\n\n\n\n\n\u003ch2 id=\"summary\"\u003e\u003ca href=\"/posts/manage-nuget-packages-centrally/#summary\" title=\"Summary\"\u003eSummary\u003c/a\u003e\u003c/h2\u003e\n\u003cp\u003eAll in all, a great enhancement to the NuGet system. However, there are currently some issues with the Visual Studio or .NET CLI integration.\u003c/p\u003e\n\u003cp\u003eBoth integrations are able to evaluate the package references and recover the packages. However, when updating with Visual Studio, the XML structure of the project is updated incorrectly, so manual rework is required.\u003c/p\u003e\n\u003cp\u003eWhen the .NET CLI wants to add a reference to a project, CPM is ignored and build errors occur again.\u003c/p\u003e\n\u003cp\u003eHowever, this should not deter you, because existing integrations such as \u003ca href=\"https://github.com/dependabot\" target=\"_blank\" rel=\"noopener external noreferrer\"\u003eGitHubs Dependabot\u003c/a\u003e provide excellent results.\u003c/p\u003e","date_modified":"2026-05-26T10:22:03+02:00","date_published":"2023-04-17T08:30:00+02:00","id":"https://daily-devops.net/posts/manage-nuget-packages-centrally/","language":"en","summary":"Learn how to centrally manage NuGet packages in .NET solutions using Directory.Packages.props for better dependency management and version control.","tags":["nuget","bestpractices","csharp","dependency-management","dotnet","hidden-gems","technicaldebt"],"title":"Manage NuGet Packages Centrally","url":"https://daily-devops.net/posts/manage-nuget-packages-centrally/"}],"language":"en","title":"Dependency Management for .NET Projects on Daily DevOps \u0026 .NET","version":"https://jsonfeed.org/version/1.1"}