PageSourceSearch

https://ratify.dev/assets/js/f3c6c9cd.0dd51d0c.js

js ratify.dev collected 2026-09-24 19:29:06 UTC 9,406 bytes, 1 lines download raw bytes

1"use strict";(globalThis.webpackChunkratify=globalThis.webpackChunkratify||[]).push([[3756],{27872(e,n,i){i.r(n),i.d(n,{assets:()=>r,contentTitle:()=>o,default:()=>h,frontMatter:()=>l,metadata:()=>s,toc:()=>c});const s=JSON.parse('{"id":"quickstarts/working-with-spdx","title":"Working with SPDX","description":"SPDX is a popular specification for representing software bill of material (SBoM) information. Once an SBoM has been","source":"@site/versioned_docs/version-1.2/quickstarts/working-with-spdx.md","sourceDirName":"quickstarts","slug":"/quickstarts/working-with-spdx","permalink":"/docs/1.2/quickstarts/working-with-spdx","draft":false,"unlisted":false,"editUrl":"https://github.com/ratify-project/ratify-web/blob/main/versioned_docs/version-1.2/quickstarts/working-with-spdx.md","tags":[],"version":"1.2","frontMatter":{},"sidebar":"tutorialSidebar","previous":{"title":"Ratify on AWS","permalink":"/docs/1.2/quickstarts/ratify-on-aws"},"next":{"title":"Reference","permalink":"/docs/1.2/category/reference"}}');var t=i(74848),a=i(28453);const l={},o="Working with SPDX",r={},c=[{value:"Setup",id:"setup",level:2},{value:"Build the Image",id:"build-the-image",level:2},{value:"Generate the SBoM",id:"generate-the-sbom",level:2},{value:"Push the image and SBoM",id:"push-the-image-and-sbom",level:2},{value:"Validating the SBoM",id:"validating-the-sbom",level:2},{value:"Cleaning Up",id:"cleaning-up",level:2}];function d(e){const n={a:"a",code:"code",h1:"h1",h2:"h2",header:"header",li:"li",p:"p",pre:"pre",ul:"ul",...(0,a.R)(),...e.components};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(n.header,{children:(0,t.jsx)(n.h1,{id:"working-with-spdx",children:"Working with SPDX"})}),"\n",(0,t.jsxs)(n.p,{children:["SPDX is a popular specification for representing software bill of material (SBoM) information. Once an SBoM has been\ngenerated there are a number of ways to validate the contents. This guide will walk through the steps to generate an\nSBoM from a container image and validate some information from the SBoM using the example ",(0,t.jsx)(n.code,{children:"licensechecker"})," plugin. By\nthe end of this guide you will have:"]}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsx)(n.li,{children:"Built a docker image"}),"\n",(0,t.jsx)(n.li,{children:"Generated an SBoM for that image in SPDX tag-value format"}),"\n",(0,t.jsx)(n.li,{children:"Pushed the SBoM to a registry"}),"\n",(0,t.jsx)(n.li,{children:"Configured Ratify to validate the licenses used in the docker image"}),"\n",(0,t.jsx)(n.li,{children:"Run the validation via the CLI"}),"\n"]}),"\n",(0,t.jsxs)(n.p,{children:["For more information on additional metadata that is captured in SPDX visit the ",(0,t.jsx)(n.a,{href:"https://spdx.dev/specifications/",children:"SPDX specification docs"}),"."]}),"\n",(0,t.jsx)(n.h2,{id:"setup",children:"Setup"}),"\n",(0,t.jsx)(n.p,{children:"In order to complete this guide you will need some tools."}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.a,{href:"https://www.docker.com/get-started",children:"docker"}),": This tool will be used to build the container image"]}),"\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.a,{href:"https://github.com/anchore/syft",children:"syft"}),": This tool will be used to generate an SBoM in SPDX tag-value format"]}),"\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.a,{href:"https://github.com/oras-project/oras",children:"oras"}),": This tool will be used to push the generated SBoM to the registry"]}),"\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.a,{href:"https://github.com/ratify-project/ratify",children:"ratify"}),": This tool will be used to validate the SBoM"]}),"\n"]}),"\n",(0,t.jsx)(n.p,{children:"You will also need a registry to push your container image and SBoM to. For this guide deploy a local registry with\noras artifacts support:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-shell",children:"docker run --name sbom_demo -d -p 5000:5000 ghcr.io/oras-project/registry:v0.0.3-alpha\n"})}),"\n",(0,t.jsx)(n.h2,{id:"build-the-image",children:"Build the Image"}),"\n",(0,t.jsx)(n.p,{children:"First we need to build the container image we will be using:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-shell",children:"docker build -t localhost:5000/only-spdx:v1 https://github.com/wabbit-networks/net-monitor.git\\#main\n"})}),"\n",(0,t.jsx)(n.h2,{id:"generate-the-sbom",children:"Generate the SBoM"}),"\n",(0,t.jsx)(n.p,{children:"Generate an SPDX SBoM using syft:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-shell",children:"syft -o spdx --file sbom.spdx localhost:5000/only-spdx:v1\n"})}),"\n",(0,t.jsx)(n.h2,{id:"push-the-image-and-sbom",children:"Push the image and SBoM"}),"\n",(0,t.jsx)(n.p,{children:"After building the image and generating the SBoM pu
1sh them to the registry:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-shell",children:"docker push localhost:5000/only-spdx:v1\n\noras attach localhost:5000/only-spdx:v1 \\\n  --artifact-type application/vnd.ratify.spdx.v0 \\\n  --plain-http \\\n  sbom.spdx:application/text\n"})}),"\n",(0,t.jsx)(n.h2,{id:"validating-the-sbom",children:"Validating the SBoM"}),"\n",(0,t.jsx)(n.p,{children:"If you have not done so already, build and install ratify:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-shell",children:"make build\nmake install\n"})}),"\n",(0,t.jsx)(n.p,{children:"Next we will create the config file we will use for validation:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-shell",children:'cat <<\'EOF\' >> spdxconfig.json\n{\n    "store": {\n        "version": "1.0.0",\n        "plugins": [\n            {\n                "name": "oras",\n                "useHttp": true,\n                "localCachePath": "./local_oras_cache"\n            }\n        ]\n    },\n    "policy": {\n        "version": "1.0.0",\n        "plugin": {\n            "name": "configPolicy",\n            "artifactVerificationPolicies": {\n                "application/vnd.ratify.spdx.v0": "all"\n            }\n        }\n    },\n    "verifier": {\n        "version": "1.0.0",\n        "plugins": [\n            {\n                "name": "licensechecker",\n                "artifactTypes": "application/vnd.ratify.spdx.v0",\n                "allowedLicenses": [\n                    "GPL-2.0-only",\n                    "MIT",\n                    "OpenSSL",\n                    "BSD-2-Clause AND BSD-3-Clause",\n                    "Zlib",\n                    "MPL-2.0 AND MIT",\n                    "ISC"\n                ]\n            }\n\n        ]\n\n    }\n}\nEOF\n'})}),"\n",(0,t.jsxs)(n.p,{children:["This config file will only enable the ",(0,t.jsx)(n.code,{children:"licensechecker"})," verifier and configure it to check that only the licenses in the\n",(0,t.jsx)(n.code,{children:"allowedLicenses"})," list are used. Note here that the ",(0,t.jsx)(n.code,{children:"artifactType"})," of the SBoM is arbitrary and can be whatever you\nwant to specify it as so long as you are consistently use it when pushing and validating."]}),"\n",(0,t.jsx)(n.p,{children:"We are now ready to validate our image:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-shell",children:'ratify verify -c spdxconfig.json -s localhost:5000/only-spdx:v1\n\n{\n  "isSuccess": true,\n  "verifierReports": [\n    {\n      "subject": "localhost:5000/only-spdx:v1",\n      "isSuccess": true,\n      "name": "licensechecker",\n      "results": [\n        "License Check: SUCCESS",\n        "All packages have allowed licenses"\n      ]\n    }\n  ]\n}\n'})}),"\n",(0,t.jsxs)(n.p,{children:["Now remove one of the license lines from the config file, for example ",(0,t.jsx)(n.code,{children:"MIT"}),", and run the validation again:"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-shell",children:'ratify verify -c spdxconfig.json -s localhost:5000/only-spdx:v1\n\n{\n  "isSuccess": false,\n  "verifierReports": [\n    {\n      "subject": "localhost:5000/only-spdx:v1",\n      "name": "licensechecker",\n      "results": [\n        "License Check: FAILED",\n        "package \'alpine-keys\' has unpermitted license \'MIT\'",\n        "package \'musl-utils\' has unpermitted license \'MIT\'",\n        "package \'musl\' has unpermitted license \'MIT\'"\n      ]\n    }\n  ]\n}\n'})}),"\n",(0,t.jsx)(n.p,{children:"We have successfully used Ratify to validate the contents of an SPDX SBoM!"}),"\n",(0,t.jsx)(n.h2,{id:"cleaning-up",children:"Cleaning Up"}),"\n",(0,t.jsx)(n.p,{children:"Remove the registry container, the guide sbom, and the guide config:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-shell",children:"docker container stop sbom_demo\ndocker container rm sbom_demo\n\nrm sbom.spdx\nrm spdxconfig.json\n"})})]})}function h(e={}){const{wrapper:n}={...(0,a.R)(),...e.components};return n?(0,t.jsx)(n,{...e,children:(0,t.jsx)(d,{...e})}):d(e)}},28453(e,n,i){i.d(n,{R:()=>l,x:()=>o});var s=i(96540);const t={},a=s.createContext(t);function l(e){const n=s.useContext(a);return s.useMemo(function(){return"function"==typeof e?e(n):{...n,...e}},[n,e])}function o(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(t):e.components||t:l(e.components),s.createElement(a.Provider,{value:n},e.children)}}}]);

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.