[{"data":1,"prerenderedAt":377},["ShallowReactive",2],{"mdc-w790sg-key":3,"mdc--xmgemz-key":24,"mdc-al1ji1-key":48,"mdc--ckta84-key":74,"mdc--l7h28q-key":124,"mdc-wrrcki-key":136,"mdc-qaqwys-key":168,"mdc-r0a8u7-key":181,"mdc-ng947k-key":221,"mdc-ahxj36-key":231,"mdc-cr1g17-key":289,"mdc-vbl330-key":301},{"data":4,"body":5},{},{"type":6,"children":7},"root",[8],{"type":9,"tag":10,"props":11,"children":12},"element","p",{},[13,16,22],{"type":14,"value":15},"text","An SBOM tells you what is in an image. A vulnerability database tells you which of those things has a known problem. ",{"type":9,"tag":17,"props":18,"children":19},"strong",{},[20],{"type":14,"value":21},"Docker Scout",{"type":14,"value":23}," joins the two and — the part that makes it useful rather than merely alarming — tells you what to change.",{"data":25,"body":26},{},{"type":6,"children":27},[28,35],{"type":9,"tag":29,"props":30,"children":32},"h2",{"id":31},"start-with-the-quickview",[33],{"type":14,"value":34},"Start with the quickview",{"type":9,"tag":36,"props":37,"children":41},"pre",{"className":38,"code":40,"language":14},[39],"language-text","docker scout quickview ghcr.io/acme/app:1.0\n",[42],{"type":9,"tag":43,"props":44,"children":46},"code",{"__ignoreMap":45},"",[47],{"type":14,"value":40},{"data":49,"body":50},{},{"type":6,"children":51},[52,57,69],{"type":9,"tag":53,"props":54,"children":56},"terminal-teaser",{":lines":55},"[{\"cmd\":\"docker scout quickview ghcr.io/acme/app:1.0\",\"out\":\"Target             ghcr.io/acme/app:1.0     0C  2H  9M  14L\\nBase image         node:22-alpine           0C  1H  4M  11L\\nRefreshed base     node:22-alpine           0C  0H  1M   3L\"}]",[],{"type":9,"tag":10,"props":58,"children":59},{},[60,62,67],{"type":14,"value":61},"Three rows, and the third is the one that pays for the tool. ",{"type":9,"tag":17,"props":63,"children":64},{},[65],{"type":14,"value":66},"Most of your vulnerabilities are in the base image, and most of those are already fixed",{"type":14,"value":68}," — the base was rebuilt after you pulled it. Repulling and rebuilding fixes them with no code change at all.",{"type":9,"tag":10,"props":70,"children":71},{},[72],{"type":14,"value":73},"The counts are Critical, High, Medium, Low. Read them relative to each other, not as a score.",{"data":75,"body":76},{},{"type":6,"children":77},[78,84,93,104,113],{"type":9,"tag":29,"props":79,"children":81},{"id":80},"the-commands",[82],{"type":14,"value":83},"The commands",{"type":9,"tag":36,"props":85,"children":88},{"className":86,"code":87,"language":14},[39],"docker scout quickview IMAGE          # the summary above\ndocker scout cves IMAGE               # every finding, with package and fix version\ndocker scout recommendations IMAGE    # what to change about the base\ndocker scout compare --to IMAGE-A IMAGE-B    # what a change did\ndocker scout policy IMAGE             # evaluate against configured policy\ndocker scout sbom IMAGE               # the inventory itself\n",[89],{"type":9,"tag":43,"props":90,"children":91},{"__ignoreMap":45},[92],{"type":14,"value":87},{"type":9,"tag":10,"props":94,"children":95},{},[96,102],{"type":9,"tag":43,"props":97,"children":99},{"className":98},[],[100],{"type":14,"value":101},"cves",{"type":14,"value":103}," is the detailed list, and its filters are what make it usable in a pipeline:",{"type":9,"tag":36,"props":105,"children":108},{"className":106,"code":107,"language":14},[39],"docker scout cves --only-severity critical,high ghcr.io/acme/app:1.0\ndocker scout cves --only-fixed ghcr.io/acme/app:1.0\ndocker scout cves --format only-packages --only-severity critical ghcr.io/acme/app:1.0\n",[109],{"type":9,"tag":43,"props":110,"children":111},{"__ignoreMap":45},[112],{"type":14,"value":107},{"type":9,"tag":10,"props":114,"children":115},{},[116,122],{"type":9,"tag":43,"props":117,"children":119},{"className":118},[],[120],{"type":14,"value":121},"--only-fixed",{"type":14,"value":123}," is the filter to reach for first. A finding with no available fix is something to track; a finding with a fix is work you can do this afternoon, and separating the two turns a wall of red into a task list.",{"data":125,"body":126},{},{"type":6,"children":127},[128],{"type":9,"tag":129,"props":130,"children":135},"quiz",{":answer":131,":options":132,"explanation":133,"question":134},"0","[\"Repull the base and rebuild — most of the findings disappear with no application change\",\"Add each CVE to an ignore list\",\"Switch language runtime\"]","A stale base is the most common cause of a long CVE list and the cheapest to fix. That is exactly what the \"Refreshed base image\" row in `quickview` is telling you — and it is why a scheduled rebuild is worth more than most triage.","Scout reports 40 vulnerabilities, of which 31 are in the base image and already fixed upstream. What is the highest-value action?",[],{"data":137,"body":138},{},{"type":6,"children":139},[140,146,159],{"type":9,"tag":29,"props":141,"children":143},{"id":142},"comparing-which-is-what-you-actually-want-in-ci",[144],{"type":14,"value":145},"Comparing, which is what you actually want in CI",{"type":9,"tag":10,"props":147,"children":148},{},[149,151,157],{"type":14,"value":150},"Absolute counts are noisy. What matters at review time is whether ",{"type":9,"tag":152,"props":153,"children":154},"em",{},[155],{"type":14,"value":156},"this change",{"type":14,"value":158}," made things worse:",{"type":9,"tag":36,"props":160,"children":163},{"className":161,"code":162,"language":14},[39],"docker scout compare --to ghcr.io/acme/app:main ghcr.io/acme/app:pr-482\n",[164],{"type":9,"tag":43,"props":165,"children":166},{"__ignoreMap":45},[167],{"type":14,"value":162},{"data":169,"body":170},{},{"type":6,"children":171},[172,176],{"type":9,"tag":53,"props":173,"children":175},{":lines":174},"[{\"cmd\":\"docker scout compare --to ghcr.io/acme/app:main ghcr.io/acme/app:pr-482\",\"out\":\"Packages and Vulnerabilities\\n  +2 packages   +1H +3M\\n  ~  openssl  3.3.2 -> 3.3.1   (downgraded)\\n  +  libxml2  2.13.4           1H 2M\"}]",[],{"type":9,"tag":10,"props":177,"children":178},{},[179],{"type":14,"value":180},"A reviewer can act on that. \"Your branch adds one High by pulling in libxml2, and downgrades openssl\" is a specific, arguable claim. \"There are 40 vulnerabilities\" is not.",{"data":182,"body":183},{},{"type":6,"children":184},[185,191,200],{"type":9,"tag":29,"props":186,"children":188},{"id":187},"recommendations",[189],{"type":14,"value":190},"Recommendations",{"type":9,"tag":36,"props":192,"children":195},{"className":193,"code":194,"language":14},[39],"docker scout recommendations ghcr.io/acme/app:1.0\n",[196],{"type":9,"tag":43,"props":197,"children":198},{"__ignoreMap":45},[199],{"type":14,"value":194},{"type":9,"tag":10,"props":201,"children":202},{},[203,205,211,213,219],{"type":14,"value":204},"This one is about the base image specifically, and it will suggest things like moving ",{"type":9,"tag":43,"props":206,"children":208},{"className":207},[],[209],{"type":14,"value":210},"node:22",{"type":14,"value":212}," to ",{"type":9,"tag":43,"props":214,"children":216},{"className":215},[],[217],{"type":14,"value":218},"node:22-alpine",{"type":14,"value":220},", or to a newer patch tag, with the CVE and size deltas each change would produce. It is opinionated in a useful way — the suggestions are ranked by what they remove.",{"data":222,"body":223},{},{"type":6,"children":224},[225],{"type":9,"tag":129,"props":226,"children":230},{":answer":131,":options":227,"explanation":228,"question":229},"[\"It shows what this change added or removed, instead of restating pre-existing findings\",\"It runs faster\",\"It checks the base image and `cves` does not\"]","Absolute counts on an existing codebase are mostly inherited, so they get ignored after the first week. A delta attributes new findings to the change that introduced them, which is the only form a reviewer can act on.","Why is `docker scout compare` more useful in a pull request than `docker scout cves`?",[],{"data":232,"body":233},{},{"type":6,"children":234},[235,241,246,255,260,271],{"type":9,"tag":29,"props":236,"children":238},{"id":237},"as-a-gate",[239],{"type":14,"value":240},"As a gate",{"type":9,"tag":10,"props":242,"children":243},{},[244],{"type":14,"value":245},"Policies turn findings into pass or fail:",{"type":9,"tag":36,"props":247,"children":250},{"className":248,"code":249,"language":14},[39],"docker scout policy ghcr.io/acme/app:1.0 --org acme\n",[251],{"type":9,"tag":43,"props":252,"children":253},{"__ignoreMap":45},[254],{"type":14,"value":249},{"type":9,"tag":10,"props":256,"children":257},{},[258],{"type":14,"value":259},"Built-in policies cover things like no fixable criticals, no outdated base images, an SBOM being present, no default non-root violation. In GitHub Actions:",{"type":9,"tag":36,"props":261,"children":266},{"className":262,"code":264,"language":265,"meta":45},[263],"language-yaml","      - uses: docker/scout-action@v1\n        with:\n          command: compare\n          image: ghcr.io/acme/app:${{ github.sha }}\n          to: ghcr.io/acme/app:main\n          only-severities: critical,high\n          exit-code: true\n","yaml",[267],{"type":9,"tag":43,"props":268,"children":269},{"__ignoreMap":45},[270],{"type":14,"value":264},{"type":9,"tag":10,"props":272,"children":273},{},[274,280,282,287],{"type":9,"tag":43,"props":275,"children":277},{"className":276},[],[278],{"type":14,"value":279},"exit-code: true",{"type":14,"value":281}," fails the job. Which is a decision to make deliberately: a gate that fires on findings nobody can fix teaches people to bypass it. Start by gating on ",{"type":9,"tag":17,"props":283,"children":284},{},[285],{"type":14,"value":286},"fixable criticals introduced by this change",{"type":14,"value":288}," and widen once the baseline is clean.",{"data":290,"body":291},{},{"type":6,"children":292},[293],{"type":9,"tag":294,"props":295,"children":300},"fill-blank",{":answer":296,"hint":297,"placeholder":298,"prompt":299},"[\"docker scout cves --only-severity critical,high --only-fixed ghcr.io/acme/app:1.0\",\"docker scout cves --only-fixed --only-severity critical,high ghcr.io/acme/app:1.0\",\"docker scout cves --only-severity critical,high --only-fixed -- ghcr.io/acme/app:1.0\"]","The cves subcommand, a severity filter, and the filter that hides findings with no fix.","docker scout cves ...","List only the fixable critical and high vulnerabilities in `ghcr.io/acme/app:1.0`.",[],{"data":302,"body":303},{},{"type":6,"children":304},[305,372],{"type":9,"tag":306,"props":307,"children":309},"deep-dive",{"title":308},"Scanning honestly",[310,315,325,335,352,362,367],{"type":9,"tag":10,"props":311,"children":312},{},[313],{"type":14,"value":314},"A scanner is easy to install and easy to make useless. Four habits separate the two.",{"type":9,"tag":10,"props":316,"children":317},{},[318,323],{"type":9,"tag":17,"props":319,"children":320},{},[321],{"type":14,"value":322},"Scan the image you ship.",{"type":14,"value":324}," Multi-stage builds exist so the compiler is not in production — scanning the build stage reports on software nobody runs and buries the findings that matter.",{"type":9,"tag":10,"props":326,"children":327},{},[328,333],{"type":9,"tag":17,"props":329,"children":330},{},[331],{"type":14,"value":332},"Fix the base first, and on a schedule.",{"type":14,"value":334}," Rebuilding weekly against a refreshed base clears most findings with no code change. This single practice beats any amount of triage, and it is the one people skip because it produces no visible work.",{"type":9,"tag":10,"props":336,"children":337},{},[338,343,345,350],{"type":9,"tag":17,"props":339,"children":340},{},[341],{"type":14,"value":342},"Gate on the delta, not the total.",{"type":14,"value":344}," A gate on absolute counts fails on inherited findings and gets bypassed within a fortnight. A gate on ",{"type":9,"tag":152,"props":346,"children":347},{},[348],{"type":14,"value":349},"newly introduced fixable",{"type":14,"value":351}," criticals stays credible, because every failure is something the author can act on.",{"type":9,"tag":10,"props":353,"children":354},{},[355,360],{"type":9,"tag":17,"props":356,"children":357},{},[358],{"type":14,"value":359},"Record decisions where they are auditable.",{"type":14,"value":361}," Findings you accept need a reason attached to the artifact — a VEX statement — not a rule in a scanner's config that nobody revisits.",{"type":9,"tag":10,"props":363,"children":364},{},[365],{"type":14,"value":366},"And use more than one scanner if it matters to you. Scout, Trivy, Grype and Snyk disagree, because they use different databases and different matching rules, and a CVE that one misses is not thereby absent. Scout's advantage is that it is already in the CLI and reads the attestations from the previous lesson directly; that is convenience, not omniscience.",{"type":9,"tag":10,"props":368,"children":369},{},[370],{"type":14,"value":371},"The failure mode to avoid is the one where a scan runs on every build, nobody reads the output, and everyone believes the images are checked. An unread gate is worse than no gate, because it is load-bearing in exactly one place: the conversation after the incident.",{"type":9,"tag":10,"props":373,"children":374},{},[375],{"type":14,"value":376},"Next up: hardened and minimal base images — removing the packages instead of triaging them.",1787908868439]