1"use strict";(globalThis.webpackChunkratify=globalThis.webpackChunkratify||[]).push([[73],{28453(e,n,i){i.d(n,{R:()=>r,x:()=>l});var s=i(96540);const a={},t=s.createContext(a);function r(e){const n=s.useContext(t);return s.useMemo(function(){return"function"==typeof e?e(n):{...n,...e}},[n,e])}function l(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(a):e.components||a:r(e.components),s.createElement(t.Provider,{value:n},e.children)}},61934(e,n,i){i.r(n),i.d(n,{assets:()=>o,contentTitle:()=>l,default:()=>h,frontMatter:()=>r,metadata:()=>s,toc:()=>c});const s=JSON.parse('{"id":"external plugins/Verifier/sbom","title":"SBOM Validation","description":"This document outlines how Ratify can be used to verify SBOM (Software bill of material). The sbom verifier is added as a plugin to the Ratify verification framework. Currently the SBOM verifier is in 2.0.0-alpha release, and it supports the following SBOM validation:","source":"@site/versioned_docs/version-1.1/external plugins/Verifier/sbom.md","sourceDirName":"external plugins/Verifier","slug":"/external plugins/Verifier/sbom","permalink":"/docs/1.1/external plugins/Verifier/sbom","draft":false,"unlisted":false,"editUrl":"https://github.com/ratify-project/ratify-web/blob/main/versioned_docs/version-1.1/external plugins/Verifier/sbom.md","tags":[],"version":"1.1","frontMatter":{},"sidebar":"tutorialSidebar","previous":{"title":"Cosign","permalink":"/docs/1.1/external plugins/Verifier/cosign"},"next":{"title":"Vulnerability Report","permalink":"/docs/1.1/external plugins/Verifier/vulnerabilityreport"}}');var a=i(74848),t=i(28453);const r={},l="SBOM Validation",o={},c=[{value:"Table of Contents",id:"table-of-contents",level:2},{value:"SBOM with License and Package Validation",id:"sbom-with-license-and-package-validation",level:2},{value:"Walkthrough",id:"walkthrough",level:3},{value:"1. Generate SBOM and attach to your image",id:"1-generate-sbom-and-attach-to-your-image",level:4},{value:"2. Ratfy Installation and configuration",id:"2-ratfy-installation-and-configuration",level:4},{value:"3. Deploying test image",id:"3-deploying-test-image",level:4},{value:"SBOM with Signature Validation",id:"sbom-with-signature-validation",level:2},{value:"Installation",id:"installation",level:3},{value:"1. Generate, sign the SBOM and attach to your image",id:"1-generate-sign-the-sbom-and-attach-to-your-image",level:3},{value:"Configuration",id:"configuration",level:2},{value:"CLI",id:"cli",level:3},{value:"Future Improvements",id:"future-improvements",level:3},{value:"FAQ",id:"faq",level:3},{value:"Why are there multiple external verifiers that can verify SBOMs?",id:"why-are-there-multiple-external-verifiers-that-can-verify-sboms",level:4}];function d(e){const n={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",h4:"h4",header:"header",li:"li",ol:"ol",p:"p",pre:"pre",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,t.R)(),...e.components};return(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)(n.header,{children:(0,a.jsx)(n.h1,{id:"sbom-validation",children:"SBOM Validation"})}),"\n",(0,a.jsxs)(n.p,{children:["This document outlines how Ratify can be used to verify SBOM (Software bill of material). The ",(0,a.jsx)(n.code,{children:"sbom"})," verifier is added as a plugin to the Ratify verification framework. Currently the SBOM verifier is in 2.0.0-alpha release, and it supports the following SBOM validation:"]}),"\n",(0,a.jsxs)(n.ul,{children:["\n",(0,a.jsx)(n.li,{children:"SBOM attached to the subject image as a referrer artifact"}),"\n",(0,a.jsxs)(n.li,{children:["SBOM generated in ",(0,a.jsx)(n.a,{href:"https://spdx.dev/learn/overview/",children:"JSON(.spdx.json)"})," format"]}),"\n"]}),"\n",(0,a.jsx)(n.h2,{id:"table-of-contents",children:"Table of Contents"}),"\n",(0,a.jsxs)(n.ul,{children:["\n",(0,a.jsx)(n.li,{children:(0,a.jsx)(n.a,{href:"#sbom-with-license-and-package-validation",children:"SBOM with License and Package Validation"})}),"\n",(0,a.jsx)(n.li,{children:(0,a.jsx)(n.a,{href:"#sbom-with-signature-validation",children:"SBOM with Signature Validation"})}),"\n",(0,a.jsx)(n.li,{children:(0,a.jsx)(n.a,{href:"#configuration",children:"Configuration"})}),"\n",(0,a.jsx)(n.li,{children:(0,a.jsx)(n.a,{href:"#future-improvements",children:"Future improvement"})}),"\n",(0,a.jsx)(n.li,{children:(0,a.jsx)(n.a,{href:"#faq",children:"FAQ"})}),"\n"]}),"\n",(0,a.jsx)(n.h2,{id:"sbom-with-license-and-package-validation",children:"SBOM with License and Package Validation"}),"\n",(0,a.jsx)(n.p,{children:"Alice has a Kubernetes cluster. The softw
1are she deploys to her cluster depends on many open source components. She wants to make sure container images meet the following criteria:"}),"\n",(0,a.jsxs)(n.ul,{children:["\n",(0,a.jsx)(n.li,{children:"does not contain licenses that could conflict with her business interest"}),"\n",(0,a.jsx)(n.li,{children:"does not contain any vulnerable packages"}),"\n"]}),"\n",(0,a.jsx)(n.h3,{id:"walkthrough",children:"Walkthrough"}),"\n",(0,a.jsx)(n.h4,{id:"1-generate-sbom-and-attach-to-your-image",children:"1. Generate SBOM and attach to your image"}),"\n",(0,a.jsxs)(n.p,{children:["Use a SBOM generator such as syft to generate an SBOM for your iamge ",(0,a.jsx)(n.code,{children:"myregistry.io/sbom/alpine:3.18.2"}),". A reference artifact is generated:"]}),"\n",(0,a.jsxs)(n.ol,{children:["\n",(0,a.jsxs)(n.li,{children:["\n",(0,a.jsxs)(n.p,{children:["Use ",(0,a.jsx)(n.a,{href:"https://github.com/anchore/syft",children:"syft"})," to scan ",(0,a.jsx)(n.code,{children:"myregistry.io/sbom/alpine:3.18.2"})," and save the output file"]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-shell",children:"syft -o spdx-json --file sbom.spdx.json myregistry.io/sbom/alpine:3.18.2\n"})}),"\n"]}),"\n",(0,a.jsxs)(n.li,{children:["\n",(0,a.jsxs)(n.p,{children:["A tool such as ",(0,a.jsx)(n.code,{children:"oras"})," is used to package, attach, and then push the report to registry"]}),"\n",(0,a.jsxs)(n.ul,{children:["\n",(0,a.jsxs)(n.li,{children:[(0,a.jsx)(n.code,{children:"artifact-type"})," MUST be ",(0,a.jsx)(n.code,{children:"application/spdx+json"})]}),"\n"]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-shell",children:"oras attach \\\n --artifact-type application/spdx+json \\\n myregistry.io/sbom/alpine:3.18.2 \\\n sbom.spdx.json\n"})}),"\n"]}),"\n"]}),"\n",(0,a.jsx)(n.p,{children:"The resulting image will have a single SBOM artifact attached:"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-shell",children:"> oras discover myregistry.io/sbom/alpine:3.18.2 -o tree\nmyregistry.io/sbom/alpine@sha256:96f270a2d97f70713ef7bd6c4b80552178bf97fc6bd75ac9af2df4ba06b26f62\n\u2514\u2500\u2500 application/spdx+json\n \u2514\u2500\u2500 sha256:6944ae19f248ed93a494c528a839d3eac4c33df6ca81d6f762a0483af8b2b87f\n"})}),"\n",(0,a.jsx)(n.h4,{id:"2-ratfy-installation-and-configuration",children:"2. Ratfy Installation and configuration"}),"\n",(0,a.jsxs)(n.p,{children:["First, follow the first step of the ",(0,a.jsx)(n.a,{href:"/docs/1.1/quickstarts/quickstart-manual",children:"manual quickstart"})," to installs Gatekeeper on the cluster."]}),"\n",(0,a.jsxs)(n.p,{children:["Second, install Ratify and configure the SBOM verifier with disallowed license and package information. In the configuration below, Alice specifies ",(0,a.jsx)(n.code,{children:"busybox"})," as a disallowed package as it leads arbitrary code execution. ",(0,a.jsx)(n.a,{href:"https://www.gnu.org/licenses/copyleft.en.html",children:"Copy left "})," license such as ",(0,a.jsx)(n.code,{children:"MPL"})," is also disallowed due to license restrictions."]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-bash",children:'helm repo add ratify https://notaryproject.github.io/ratify\nhelm install ratify \\\n ratify/ratify --atomic \\\n --namespace gatekeeper-system \\\n --set featureFlags.RATIFY_CERT_ROTATION=true \\\n --set sbom.enabled=true \\\n --set sbom.disallowedLicenses={"MPL"} \\\n --set sbom.disallowedPackages[0].name="busybox" \\\n --set sbom.disallowedPackages[0].version="1.36.1-r0"\n \n'})}),"\n",(0,a.jsxs)(n.p,{children:["Third, deploy a ",(0,a.jsx)(n.code,{children:"demo"})," constraint."]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{children:"kubectl apply -f https://notaryproject.github.io/ratify/library/default/template.yaml\nkubectl apply -f https://notaryproject.github.io/ratify/library/default/samples/constraint.yaml\n"})}),"\n",(0,a.jsx)(n.h4,{id:"3-deploying-test-image",children:"3. Deploying test image"}),"\n",(0,a.jsxs)(n.p,{children:["Finally we will attempt to deploy our test image ",(0,a.jsx)(n.code,{children:"myregistry.io/sbom/alpine:3.18.2"}
1),". We expect this to FAIL since the SBOM contains disallowed packages busybox:"]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-shell",children:'> kubectl run alpine-image -n default --image=myregistry.io/sbom/alpine:3.18.2, the output\nError from server (Forbidden): admission webhook "validation.gatekeeper.sh" denied the request: Subject failed verification: myregistry.io/sbom/alpine@sha256:96f270a2d97f70713ef7bd6c4b80552178bf97fc6bd75ac9af2df4ba06b26f62\n'})}),"\n",(0,a.jsx)(n.p,{children:"Taking a look at the Ratify logs reveals the failing report:"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-json",children:'> kubectl logs deploy/ratify -n gatekeeper-system\ntime=2023-12-07T20:02:17.238355853Z level=info msg=verify result for subject myregistry.io/sbom/alpine@sha256:96f270a2d97f70713ef7bd6c4b80552178bf97fc6bd75ac9af2df4ba06b26f62: {\n "verifierReports": [\n {\n "subject": "myregistry.io/sbom/alpine@sha256:96f270a2d97f70713ef7bd6c4b80552178bf97fc6bd75ac9af2df4ba06b26f62",\n "isSuccess": false,\n "name": "verifier-sbom",\n "message": "SBOM validation failed.",\n "extensions": {\n "creationInfo": {\n "created": "2023-12-07T19:22:42.448010842Z",\n "creators": [\n "Organization: Anchore, Inc",\n "Tool: syft-0.36.0"\n ],\n "licenseListVersion": "3.15"\n },\n "packageViolations": [\n {\n "License": "GPL-2.0-only",\n "Name": "busybox",\n "Version": "1.36.1-r0"\n },\n {\n "License": "GPL-2.0-only",\n "Name": "busybox-binsh",\n "Version": "1.36.1-r0"\n }\n ]\n },\n "artifactType": "application/spdx+json"\n }\n ]\n} \n'})}),"\n",(0,a.jsx)(n.h2,{id:"sbom-with-signature-validation",children:"SBOM with Signature Validation"}),"\n",(0,a.jsx)(n.p,{children:"Alice has a Kubernetes cluster. The software she deploys to her cluster depends on many open source components. She wants to make sure container images meet the following criteria:"}),"\n",(0,a.jsxs)(n.ul,{children:["\n",(0,a.jsx)(n.li,{children:"does not contain licenses that could conflict with her business interest"}),"\n",(0,a.jsx)(n.li,{children:"does not contain any vulnerable packages"}),"\n"]}),"\n",(0,a.jsx)(n.p,{children:"Furthermore, the most recent report being validated must have a verified Notary Project signature attached to it."}),"\n",(0,a.jsx)(n.h3,{id:"installation",children:"Installation"}),"\n",(0,a.jsxs)(n.p,{children:["First, follow the first step of the ",(0,a.jsx)(n.a,{href:"/docs/1.1/quickstarts/quickstart-manual",children:"manual quickstart"})," to install Gatekeeper."]}),"\n",(0,a.jsx)(n.p,{children:"Second, install Ratify with the SBOM verifier enabled and configured. The SBOM verifier must also be configured and cert provided. Here, we will assume the report is signed using the quickstart image's signing key."}),"\n",(0,a.jsxs)(n.p,{children:["Third, deploy a ",(0,a.jsx)(n.code,{children:"demo"})," constraint."]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{children:"kubectl apply -f https://notaryproject.github.io/ratify/library/default/template.yaml\nkubectl apply -f https://notaryproject.github.io/ratify/library/default/samples/constraint.yaml\n"})}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-bash",children:'helm repo add ratify https://notaryproject.github.io/ratify\n# download the notary verification certificate\ncurl -sSLO https://raw.githubusercontent.com/deislabs/ratify/main/test/testdata/notation.crt\nhelm install ratify \\\n ratify/ratify --atomic \\\n --namespace gatekeeper-system \\\n --set featureFlags.RATIFY_CERT_ROTATION=true \\\n --set-file notationCerts={./notation.crt} \\\n --set sbom.enabled=true \\\n --set sbom.notaryProjectSignatureRequired=true \\\n --set sbom.disallowedLicenses={"MPL"} \\\n --set sbom.disallowedPackages[0].name="busybox" \\\n --set sbom.disallowedPackages[0].version="1.36.1-r0"\n \n'})}),"\n",(0,a.jsx)(n.h3,{id:"1-generate-sign-the-sbom-and-attach-to-your-image",children:"1. Generate, sign the SBOM and attach to your image"}),"\n",(0,a.jsxs)(n.p,{children:["Use a sbom generator such as syft to generate an sbom for your iamge ",(0,a.jsx)(n.code,{children:"myregistry.io/sbom/alpine:3.18.2"}),". A reference artifact is generated:"]}),"\n",(0,a.jsxs)(n.ol,{children:["\n",(0,a.jsxs)(n.li,{children:["\n",(0,a.jsxs)(n.p,{children:["Use syft to scan ",(0,a.jsx)(n.code,{children:"myregistry.io/sbom/alpine:3.18.2"})," and save the output file"]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-shell",children:"syft -o spdx-json --file sbom.spdx.json myregistry.io/sbom/alpine:3.18.2\n"})}),"\n"]}),"\n",(0,a.jsxs)(n.li,{children:["\n",(0,a.jsxs)(n.p,{children:["A tool such as ",(0,a.jsx)(n.code,{children:"oras"})," is used to package, attach, and then push the report to registry"]}),"\n",(0,a.jsxs)(n.ul,{children:["\n",(0,a.jsxs)(n.li,{children:[(0,a.jsx)(n.code,{children:"artifact-type"})," MUST be ",(0,a.jsx)(n.code,{children:"application/spdx+json"})]}),"\n"]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-shell",children:"oras attach \\\n --artifact-type application/spdx+json \\\n myregistry.io/sbom/alpine:3.18.2 \\\n sbom.spdx.json\n"})}),"\n"]}),"\n",(0,a.jsxs)(n.li,{children:["\n",(0,a.jsxs)(n.p,{children:["Use ",(0,a.jsx)(n.a,{href:"https://notaryproject.dev/",children:(0,a.jsx)(n.code,{children:"notation"})})," to sign the report"]}),"\n"]}),"\n"]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-shell",children:'report_digest=$(oras discover myregistry.io/sbom/alpine:3.18.2 -o json | jq .manifests[0].digest | tr -d \\")\nnotation sign myregistry.io/sbom/alpine@$report_digest\n'})}),"\n",(0,a.jsx)(n.p,{children:"The resulting image will have a single sbom artifact attached with Notary Project signature attached:"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-shell",children:"> oras discover myregistry.io/sbom/alpine:3.18.2 -o tree\nmyregistry.io/sbom/alpine@
1sha256:96f270a2d97f70713ef7bd6c4b80552178bf97fc6bd75ac9af2df4ba06b26f62\n\u2514\u2500\u2500 application/spdx+json\n \u2514\u2500\u2500 sha256:6944ae19f248ed93a494c528a839d3eac4c33df6ca81d6f762a0483af8b2b87f\n \u2514\u2500\u2500 application/vnd.cncf.notary.signature\n \u2514\u2500\u2500 sha256:3ed4d26f01c6dc5b410e2370031d2222dd27f1cfa16fca74dff2966f9bac9df9\n"})}),"\n",(0,a.jsxs)(n.p,{children:["Finally we will attempt to deploy our test image ",(0,a.jsx)(n.code,{children:"myregistry.io/sbom/alpine:3.18.2"}),". We expect this to FAIL since our package busybox is not allowed."]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{children:'{\n "isSuccess": true,\n "verifierReports": [\n {\n "subject": "myregistry.io/sbom/alpine@sha256:96f270a2d97f70713ef7bd6c4b80552178bf97fc6bd75ac9af2df4ba06b26f62",\n "isSuccess": false,\n "name": "verifier-sbom",\n "message": "SBOM validation failed.",\n "extensions": {\n "creationInfo": {\n "created": "2023-12-07T19:22:42.448010842Z",\n "creators": [\n "Organization: Anchore, Inc",\n "Tool: syft-0.36.0"\n ],\n "licenseListVersion": "3.15"\n },\n "packageViolations": [\n {\n "License": "GPL-2.0-only",\n "Name": "busybox",\n "Version": "1.36.1-r0"\n },\n {\n "License": "GPL-2.0-only",\n "Name": "busybox-binsh",\n "Version": "1.36.1-r0"\n }\n ]\n },\n "nestedResults": [\n {\n "subject": "myregistry.io/sbom/alpine@sha256:6944ae19f248ed93a494c528a839d3eac4c33df6ca81d6f762a0483af8b2b87f",\n "isSuccess": true,\n "name": "notation",\n "message": "signature verification success",\n "extensions": {\n "Issuer": "CN=wabbit-networks.io,O=Notary,L=Seattle,ST=WA,C=US",\n "SN": "CN=wabbit-networks.io,O=Notary,L=Seattle,ST=WA,C=US"\n },\n "artifactType": "application/vnd.cncf.notary.signature"\n }\n ],\n "artifactType": "application/spdx+json"\n }\n ]\n}\n'})}),"\n",(0,a.jsx)(n.h2,{id:"configuration",children:"Configuration"}),"\n",(0,a.jsx)(n.p,{children:"Sample YAML"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-json",children:"apiVersion: config.ratify.deislabs.io/v1beta1\nkind: Verifier\nmetadata:\n name: verifier-sbom\nspec:\n name: sbom\n artifactTypes: application/spdx+json\n parameters:\n disallowedPackages:\n - name: busybox\n version: 1.36.1-r0\n disallowedLicenses: \n - MPL\n"})}),"\n",(0,a.jsxs)(n.table,{children:[(0,a.jsx)(n.thead,{children:(0,a.jsxs)(n.tr,{children:[(0,a.jsx)(n.th,{children:"Name"}),(0,a.jsx)(n.th,{children:"Required"}),(0,a.jsx)(n.th,{children:"Path"}),(0,a.jsx)(n.th,{children:"Description"}),(0,a.jsx)(n.th,{children:"Default Value"})]})}),(0,a.jsxs)(n.tbody,{children:[(0,a.jsxs)(n.tr,{children:[(0,a.jsx)(n.td,{children:"disallowedPackages"}),(0,a.jsx)(n.td,{children:"No"}),(0,a.jsx)(n.td,{children:"spec.parameters.disallowedPackages"}),(0,a.jsx)(n.td,{children:"Array of disallowed packages. If version is empty, all packages with matching name will be disallowed."}),(0,a.jsx)(n.td,{children:"[]"})]}),(0,a.jsxs)(n.tr,{children:[(0,a.jsx)(n.td,{children:"disallowedLicenses"}),(0,a.jsx)(n.td,{children:"No"}),(0,a.jsx)(n.td,{children:"spec.parameters.disallowedLicenses"}),(0,a.jsx)(n.td,{children:"String array of disallowed licenses."}),(0,a.jsx)(n.td,{children:"[]"})]})]})]}),"\n",(0,a.jsx)(n.h3,{id:"cli",children:"CLI"}),"\n",(0,a.jsx)(n.p,{children:"Sample JSON"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-json",children:'{\n "store": {\n "version": "1.0.0",\n "plugins": [\n {\n "name": "oras",\n "useHttp": true\n }\n ]\n },\n "policy": {\n "version": "1.0.0",\n "plugin": {\n "name": "configPolicy",\n "artifactVerificationPolicies": {\n "application/spdx+json": "all"\n }\n }\n },\n "verifier": {\n "version": "1.0.0",\n "plugins": [\n {\n "name": "sbom",\n "artifactTypes": "application/spdx+json",\n "disallowedLicenses": ["MPL"],\n "disallowedPackages":[{"name":"busybox","version":"1.36.1-r0"}]\n }\n ]\n }\n}\n'})}),"\n",(0,a.jsx)(n.h3,{id:"future-improvements",children:"Future Improvements"}),"\n",(0,a.jsx)(n.p,{children:"Please vote on these issues to help us prioritize:"}),"\n",(0,a.jsxs)(n.ul,{children:["\n",(0,a.jsx)(n.li,{children:(0,a.jsx)(n.a,{href:"https://github.com/ratify-project/ratify/issues/1206",children:"SBOM Verifier to supp
1ort other formats"})}),"\n",(0,a.jsx)(n.li,{children:(0,a.jsx)(n.a,{href:"https://github.com/ratify-project/ratify/issues/1207",children:"SBOM verifier to support license expressions"})}),"\n"]}),"\n",(0,a.jsx)(n.h3,{id:"faq",children:"FAQ"}),"\n",(0,a.jsx)(n.h4,{id:"why-are-there-multiple-external-verifiers-that-can-verify-sboms",children:"Why are there multiple external verifiers that can verify SBOMs?"}),"\n",(0,a.jsx)(n.p,{children:"These verifiers are authored by various contributors to fit their project need. The license checker implements a strict validation against the allowed licenses list, where as the SBOM verifier works against a disallowed license and package list."}),"\n",(0,a.jsx)(n.p,{children:"The licensechecker verifier has been DEPRECATED and will be removed in future releases. Please use the SBOM verifier for license checks moving forward. Package license verification is associated typically with SBOMs. As such, Ratify has decided to incorporate package license filtering in SBOM verification."})]})}function h(e={}){const{wrapper:n}={...(0,t.R)(),...e.components};return n?(0,a.jsx)(n,{...e,children:(0,a.jsx)(d,{...e})}):d(e)}}}]);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.