diff --git a/_assets/css/tailwind.css b/_assets/css/tailwind.css index fa560f1..3dc518c 100644 --- a/_assets/css/tailwind.css +++ b/_assets/css/tailwind.css @@ -221,14 +221,15 @@ } } -/* Blog Post & Page Styles */ -.blog-post, .page { +/* Blog Post, Page & FAQ Styles */ +.blog-post, .page, .faq-content { font-family: "Inter Variable", "Inter", ui-sans-serif, system-ui, sans-serif; } /* Headings */ .blog-post h1, .blog-post h2, .blog-post h3, .blog-post h4, .blog-post h5, .blog-post h6, -.page h1, .page h2, .page h3, .page h4, .page h5, .page h6 { +.page h1, .page h2, .page h3, .page h4, .page h5, .page h6, +.faq-content h1, .faq-content h2, .faq-content h3, .faq-content h4, .faq-content h5, .faq-content h6 { color: #141035; font-weight: 600; line-height: 1.3; @@ -236,7 +237,7 @@ margin-bottom: 1rem; /* 16px */ } -.blog-post h1, .page h1 { +.blog-post h1, .page h1, .faq-content h1 { font-size: 2.25rem; /* 36px */ font-weight: 700; line-height: 1.2; @@ -245,74 +246,74 @@ } @media (min-width: 768px) { - .blog-post h1, .page h1 { + .blog-post h1, .page h1, .faq-content h1 { font-size: 3rem; /* 48px */ } } @media (min-width: 1024px) { - .blog-post h1, .page h1 { + .blog-post h1, .page h1, .faq-content h1 { font-size: 3.5rem; /* 56px */ } } -.blog-post h2, .page h2 { +.blog-post h2, .page h2, .faq-content h2 { font-size: 1.75rem; /* 28px */ margin-top: 3rem; /* 48px */ } @media (min-width: 768px) { - .blog-post h2, .page h2 { + .blog-post h2, .page h2, .faq-content h2 { font-size: 2.25rem; /* 36px */ } } -.blog-post h3, .page h3 { +.blog-post h3, .page h3, .faq-content h3 { font-size: 1.5rem; /* 24px */ margin-top: 2.5rem; /* 40px */ } @media (min-width: 768px) { - .blog-post h3, .page h3 { + .blog-post h3, .page h3, .faq-content h3 { font-size: 1.75rem; /* 28px */ } } -.blog-post h4, .page h4 { +.blog-post h4, .page h4, .faq-content h4 { font-size: 1.25rem; /* 20px */ margin-top: 2rem; /* 32px */ } @media (min-width: 768px) { - .blog-post h4, .page h4 { + .blog-post h4, .page h4, .faq-content h4 { font-size: 1.375rem; /* 22px */ } } -.blog-post h5, .page h5 { +.blog-post h5, .page h5, .faq-content h5 { font-size: 1.125rem; /* 18px */ margin-top: 1.5rem; /* 24px */ } @media (min-width: 768px) { - .blog-post h5, .page h5 { + .blog-post h5, .page h5, .faq-content h5 { font-size: 1.25rem; /* 20px */ } } -.blog-post h6, .page h6 { +.blog-post h6, .page h6, .faq-content h6 { font-size: 1rem; /* 16px */ margin-top: 1.25rem; /* 20px */ } @media (min-width: 768px) { - .blog-post h6, .page h6 { + .blog-post h6, .page h6, .faq-content h6 { font-size: 1.125rem; /* 18px */ } } /* Paragraphs */ -.blog-post p, .page p { +.blog-post p, .page p, .faq-content p { color: #5E5E5E; font-size: 1.125rem; /* 18px */ line-height: 1.7; @@ -320,52 +321,55 @@ } @media (min-width: 768px) { - .blog-post p, .page p { + .blog-post p, .page p, .faq-content p { font-size: 1.25rem; /* 20px */ line-height: 1.8; } } /* First paragraph styling */ -.blog-post > p:first-of-type, .page > p:first-of-type { +.blog-post > p:first-of-type, .page > p:first-of-type, .faq-content > p:first-of-type { font-size: 1.25rem; /* 20px */ color: #141035; } @media (min-width: 768px) { - .blog-post > p:first-of-type, .page > p:first-of-type { + .blog-post > p:first-of-type, .page > p:first-of-type, .faq-content > p:first-of-type { font-size: 1.375rem; /* 22px */ line-height: 1.8; } } /* Links */ -.blog-post a, .page a { +.blog-post a, .page a, .faq-content a { color: #8A7DFF; text-decoration: underline; text-underline-offset: 3px; transition: all 0.2s ease; } -.blog-post a:hover, .page a:hover { +.blog-post a:hover, .page a:hover, .faq-content a:hover { color: #7A6DE5; text-decoration-thickness: 2px; } .blog-post strong, .blog-post b, -.page strong, .page b { +.page strong, .page b, +.faq-content strong, .faq-content b { color: #141035; font-weight: 600; } .blog-post em, .blog-post i, -.page em, .page i { +.page em, .page i, +.faq-content em, .faq-content i { font-style: italic; } /* Lists */ .blog-post ul, .blog-post ol, -.page ul, .page ol { +.page ul, .page ol, +.faq-content ul, .faq-content ol { font-size: 1.125rem; /* 18px */ line-height: 1.7; margin-bottom: 1.5rem; /* 24px */ @@ -375,34 +379,35 @@ @media (min-width: 768px) { .blog-post ul, .blog-post ol, - .page ul, .page ol { + .page ul, .page ol, + .faq-content ul, .faq-content ol { font-size: 1.25rem; /* 20px */ line-height: 1.8; } } -.blog-post li, .page li { +.blog-post li, .page li, .faq-content li { margin-bottom: 0.75rem; /* 12px */ padding-left: 0.5rem; /* 8px */ } -.blog-post li:last-child, .page li:last-child { +.blog-post li:last-child, .page li:last-child, .faq-content li:last-child { margin-bottom: 0; } -.blog-post ul, .page ul { +.blog-post ul, .page ul, .faq-content ul { list-style: disc; } -.blog-post ul li::marker, .page ul li::marker { +.blog-post ul li::marker, .page ul li::marker, .faq-content ul li::marker { color: #8A7DFF; } -.blog-post ol, .page ol { +.blog-post ol, .page ol, .faq-content ol { list-style: decimal; } -.blog-post ol li::marker, .page ol li::marker { +.blog-post ol li::marker, .page ol li::marker, .faq-content ol li::marker { color: #8A7DFF; font-weight: 600; } @@ -455,7 +460,7 @@ } /* Blockquotes */ -.blog-post blockquote, .page blockquote { +.blog-post blockquote, .page blockquote, .faq-content blockquote { position: relative; margin: 2rem 0; /* 32px */ padding: 1.5rem 1.5rem 1.5rem 3rem; /* 24px 24px 24px 48px */ @@ -468,24 +473,24 @@ } @media (min-width: 768px) { - .blog-post blockquote, .page blockquote { + .blog-post blockquote, .page blockquote, .faq-content blockquote { margin: 2.5rem 0; /* 40px */ padding: 2rem 2rem 2rem 3.5rem; /* 32px 32px 32px 56px */ font-size: 1.25rem; /* 20px */ } } -.blog-post blockquote p, .page blockquote p { +.blog-post blockquote p, .page blockquote p, .faq-content blockquote p { margin: 0; color: #141035; } -.blog-post blockquote p:not(:last-child), .page blockquote p:not(:last-child) { +.blog-post blockquote p:not(:last-child), .page blockquote p:not(:last-child), .faq-content blockquote p:not(:last-child) { margin-bottom: 1rem; /* 16px */ } /* TL;DR blocks */ -.blog-post .tldr, .page .tldr { +.blog-post .tldr, .page .tldr, .faq-content .tldr { margin: 0 0 2rem 0; /* 32px */ padding: 1.25rem 1.5rem; /* 20px 24px */ background: linear-gradient(135deg, rgba(138, 125, 255, 0.08) 0%, rgba(138, 125, 255, 0.03) 100%); @@ -494,12 +499,12 @@ } @media (min-width: 768px) { - .blog-post .tldr, .page .tldr { + .blog-post .tldr, .page .tldr, .faq-content .tldr { padding: 1.5rem 2rem; /* 24px 32px */ } } -.blog-post .tldr .tldr-label, .page .tldr .tldr-label { +.blog-post .tldr .tldr-label, .page .tldr .tldr-label, .faq-content .tldr .tldr-label { display: block; font-size: 0.75rem; /* 12px */ font-weight: 700; @@ -509,7 +514,7 @@ margin-bottom: 0.5rem; /* 8px */ } -.blog-post .tldr p, .page .tldr p { +.blog-post .tldr p, .page .tldr p, .faq-content .tldr p { margin: 0; font-size: 1rem; /* 16px */ line-height: 1.7; @@ -517,13 +522,13 @@ } @media (min-width: 768px) { - .blog-post .tldr p, .page .tldr p { + .blog-post .tldr p, .page .tldr p, .faq-content .tldr p { font-size: 1.125rem; /* 18px */ } } /* Code */ -.blog-post code, .page code { +.blog-post code, .page code, .faq-content code { background: #f1f5f9; color: #334155; padding: 0.1875rem 0.5rem; /* 3px 8px */ @@ -533,7 +538,7 @@ border: 1px solid #e2e8f0; } -.blog-post pre, .page pre { +.blog-post pre, .page pre, .faq-content pre { background: #1e293b; color: #e2e8f0; padding: 1.5rem; /* 24px */ @@ -544,7 +549,7 @@ box-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1); } -.blog-post pre code, .page pre code { +.blog-post pre code, .page pre code, .faq-content pre code { background: transparent; padding: 0; border: none; @@ -553,13 +558,13 @@ } @media (min-width: 768px) { - .blog-post pre code, .page pre code { + .blog-post pre code, .page pre code, .faq-content pre code { font-size: 1rem; /* 16px */ } } /* Tables */ -.blog-post table, .page table { +.blog-post table, .page table, .faq-content table { display: block; width: 100%; overflow-x: auto; @@ -570,19 +575,20 @@ } @media (min-width: 768px) { - .blog-post table, .page table { + .blog-post table, .page table, .faq-content table { font-size: 1.125rem; /* 18px */ } } .blog-post th, .blog-post td, -.page th, .page td { +.page th, .page td, +.faq-content th, .faq-content td { border: 1px solid #e5e7eb; padding: 0.75rem 1rem; /* 12px 16px */ text-align: left; } -.blog-post th, .page th { +.blog-post th, .page th, .faq-content th { background-color: #f9fafb; color: #141035; font-weight: 600; @@ -591,21 +597,21 @@ letter-spacing: 0.05em; } -.blog-post tbody tr, .page tbody tr { +.blog-post tbody tr, .page tbody tr, .faq-content tbody tr { background: #FFF; transition: background-color 0.2s ease; } -.blog-post tbody tr:hover, .page tbody tr:hover { +.blog-post tbody tr:hover, .page tbody tr:hover, .faq-content tbody tr:hover { background: #f9fafb; } -.blog-post td, .page td { +.blog-post td, .page td, .faq-content td { color: #5E5E5E; } /* Horizontal rules */ -.blog-post hr, .page hr { +.blog-post hr, .page hr, .faq-content hr { margin: 3rem 0; /* 48px */ border: none; height: 2px; @@ -613,7 +619,7 @@ } @media (min-width: 768px) { - .blog-post hr, .page hr { + .blog-post hr, .page hr, .faq-content hr { margin: 4rem 0; /* 64px */ } } diff --git a/assets/css/styles.css b/assets/css/styles.css index bed4009..b1ea31c 100644 --- a/assets/css/styles.css +++ b/assets/css/styles.css @@ -816,6 +816,10 @@ a.button:hover { margin-bottom: 0px !important; } +.\!mb-2 { + margin-bottom: 0.5rem !important; +} + .\!mb-4 { margin-bottom: 1rem !important; } @@ -920,6 +924,10 @@ a.button:hover { margin-top: 6rem; } +.mt-3 { + margin-top: 0.75rem; +} + .mt-4 { margin-top: 1rem; } @@ -928,6 +936,10 @@ a.button:hover { margin-top: 1.5rem; } +.mt-8 { + margin-top: 2rem; +} + .mt-auto { margin-top: auto; } @@ -1238,6 +1250,10 @@ a.button:hover { justify-content: flex-start; } +.justify-end { + justify-content: flex-end; +} + .justify-center { justify-content: center; } @@ -1307,6 +1323,12 @@ a.button:hover { margin-bottom: calc(6rem * var(--tw-space-y-reverse)); } +.space-y-3 > :not([hidden]) ~ :not([hidden]) { + --tw-space-y-reverse: 0; + margin-top: calc(0.75rem * calc(1 - var(--tw-space-y-reverse))); + margin-bottom: calc(0.75rem * var(--tw-space-y-reverse)); +} + .space-y-4 > :not([hidden]) ~ :not([hidden]) { --tw-space-y-reverse: 0; margin-top: calc(1rem * calc(1 - var(--tw-space-y-reverse))); @@ -1546,6 +1568,10 @@ a.button:hover { background-color: rgb(34 197 94 / var(--tw-bg-opacity, 1)); } +.bg-green-500\/10 { + background-color: rgb(34 197 94 / 0.1); +} + .bg-pink-50 { --tw-bg-opacity: 1; background-color: rgb(253 242 248 / var(--tw-bg-opacity, 1)); @@ -1681,6 +1707,10 @@ a.button:hover { padding: 1rem; } +.p-5 { + padding: 1.25rem; +} + .p-6 { padding: 1.5rem; } @@ -2037,6 +2067,11 @@ a.button:hover { color: rgb(31 41 55 / var(--tw-text-opacity, 1)); } +.text-green-400 { + --tw-text-opacity: 1; + color: rgb(74 222 128 / var(--tw-text-opacity, 1)); +} + .text-green-600 { --tw-text-opacity: 1; color: rgb(22 163 74 / var(--tw-text-opacity, 1)); @@ -2092,6 +2127,16 @@ a.button:hover { text-underline-offset: 2px; } +.placeholder-gray-400::-moz-placeholder { + --tw-placeholder-opacity: 1; + color: rgb(156 163 175 / var(--tw-placeholder-opacity, 1)); +} + +.placeholder-gray-400::placeholder { + --tw-placeholder-opacity: 1; + color: rgb(156 163 175 / var(--tw-placeholder-opacity, 1)); +} + .opacity-0 { opacity: 0; } @@ -2214,14 +2259,15 @@ a.button:hover { } } -/* Blog Post & Page Styles */ -.blog-post, .page { +/* Blog Post, Page & FAQ Styles */ +.blog-post, .page, .faq-content { font-family: "Inter Variable", "Inter", ui-sans-serif, system-ui, sans-serif; } /* Headings */ .blog-post h1, .blog-post h2, .blog-post h3, .blog-post h4, .blog-post h5, .blog-post h6, -.page h1, .page h2, .page h3, .page h4, .page h5, .page h6 { +.page h1, .page h2, .page h3, .page h4, .page h5, .page h6, +.faq-content h1, .faq-content h2, .faq-content h3, .faq-content h4, .faq-content h5, .faq-content h6 { color: #141035; font-weight: 600; line-height: 1.3; @@ -2229,7 +2275,7 @@ a.button:hover { margin-bottom: 1rem; /* 16px */ } -.blog-post h1, .page h1 { +.blog-post h1, .page h1, .faq-content h1 { font-size: 2.25rem; /* 36px */ font-weight: 700; line-height: 1.2; @@ -2238,74 +2284,74 @@ a.button:hover { } @media (min-width: 768px) { - .blog-post h1, .page h1 { + .blog-post h1, .page h1, .faq-content h1 { font-size: 3rem; /* 48px */ } } @media (min-width: 1024px) { - .blog-post h1, .page h1 { + .blog-post h1, .page h1, .faq-content h1 { font-size: 3.5rem; /* 56px */ } } -.blog-post h2, .page h2 { +.blog-post h2, .page h2, .faq-content h2 { font-size: 1.75rem; /* 28px */ margin-top: 3rem; /* 48px */ } @media (min-width: 768px) { - .blog-post h2, .page h2 { + .blog-post h2, .page h2, .faq-content h2 { font-size: 2.25rem; /* 36px */ } } -.blog-post h3, .page h3 { +.blog-post h3, .page h3, .faq-content h3 { font-size: 1.5rem; /* 24px */ margin-top: 2.5rem; /* 40px */ } @media (min-width: 768px) { - .blog-post h3, .page h3 { + .blog-post h3, .page h3, .faq-content h3 { font-size: 1.75rem; /* 28px */ } } -.blog-post h4, .page h4 { +.blog-post h4, .page h4, .faq-content h4 { font-size: 1.25rem; /* 20px */ margin-top: 2rem; /* 32px */ } @media (min-width: 768px) { - .blog-post h4, .page h4 { + .blog-post h4, .page h4, .faq-content h4 { font-size: 1.375rem; /* 22px */ } } -.blog-post h5, .page h5 { +.blog-post h5, .page h5, .faq-content h5 { font-size: 1.125rem; /* 18px */ margin-top: 1.5rem; /* 24px */ } @media (min-width: 768px) { - .blog-post h5, .page h5 { + .blog-post h5, .page h5, .faq-content h5 { font-size: 1.25rem; /* 20px */ } } -.blog-post h6, .page h6 { +.blog-post h6, .page h6, .faq-content h6 { font-size: 1rem; /* 16px */ margin-top: 1.25rem; /* 20px */ } @media (min-width: 768px) { - .blog-post h6, .page h6 { + .blog-post h6, .page h6, .faq-content h6 { font-size: 1.125rem; /* 18px */ } } /* Paragraphs */ -.blog-post p, .page p { +.blog-post p, .page p, .faq-content p { color: #5E5E5E; font-size: 1.125rem; /* 18px */ line-height: 1.7; @@ -2313,52 +2359,55 @@ a.button:hover { } @media (min-width: 768px) { - .blog-post p, .page p { + .blog-post p, .page p, .faq-content p { font-size: 1.25rem; /* 20px */ line-height: 1.8; } } /* First paragraph styling */ -.blog-post > p:first-of-type, .page > p:first-of-type { +.blog-post > p:first-of-type, .page > p:first-of-type, .faq-content > p:first-of-type { font-size: 1.25rem; /* 20px */ color: #141035; } @media (min-width: 768px) { - .blog-post > p:first-of-type, .page > p:first-of-type { + .blog-post > p:first-of-type, .page > p:first-of-type, .faq-content > p:first-of-type { font-size: 1.375rem; /* 22px */ line-height: 1.8; } } /* Links */ -.blog-post a, .page a { +.blog-post a, .page a, .faq-content a { color: #8A7DFF; text-decoration: underline; text-underline-offset: 3px; transition: all 0.2s ease; } -.blog-post a:hover, .page a:hover { +.blog-post a:hover, .page a:hover, .faq-content a:hover { color: #7A6DE5; text-decoration-thickness: 2px; } .blog-post strong, .blog-post b, -.page strong, .page b { +.page strong, .page b, +.faq-content strong, .faq-content b { color: #141035; font-weight: 600; } .blog-post em, .blog-post i, -.page em, .page i { +.page em, .page i, +.faq-content em, .faq-content i { font-style: italic; } /* Lists */ .blog-post ul, .blog-post ol, -.page ul, .page ol { +.page ul, .page ol, +.faq-content ul, .faq-content ol { font-size: 1.125rem; /* 18px */ line-height: 1.7; margin-bottom: 1.5rem; /* 24px */ @@ -2368,34 +2417,35 @@ a.button:hover { @media (min-width: 768px) { .blog-post ul, .blog-post ol, - .page ul, .page ol { + .page ul, .page ol, + .faq-content ul, .faq-content ol { font-size: 1.25rem; /* 20px */ line-height: 1.8; } } -.blog-post li, .page li { +.blog-post li, .page li, .faq-content li { margin-bottom: 0.75rem; /* 12px */ padding-left: 0.5rem; /* 8px */ } -.blog-post li:last-child, .page li:last-child { +.blog-post li:last-child, .page li:last-child, .faq-content li:last-child { margin-bottom: 0; } -.blog-post ul, .page ul { +.blog-post ul, .page ul, .faq-content ul { list-style: disc; } -.blog-post ul li::marker, .page ul li::marker { +.blog-post ul li::marker, .page ul li::marker, .faq-content ul li::marker { color: #8A7DFF; } -.blog-post ol, .page ol { +.blog-post ol, .page ol, .faq-content ol { list-style: decimal; } -.blog-post ol li::marker, .page ol li::marker { +.blog-post ol li::marker, .page ol li::marker, .faq-content ol li::marker { color: #8A7DFF; font-weight: 600; } @@ -2448,7 +2498,7 @@ a.button:hover { } /* Blockquotes */ -.blog-post blockquote, .page blockquote { +.blog-post blockquote, .page blockquote, .faq-content blockquote { position: relative; margin: 2rem 0; /* 32px */ padding: 1.5rem 1.5rem 1.5rem 3rem; /* 24px 24px 24px 48px */ @@ -2461,24 +2511,24 @@ a.button:hover { } @media (min-width: 768px) { - .blog-post blockquote, .page blockquote { + .blog-post blockquote, .page blockquote, .faq-content blockquote { margin: 2.5rem 0; /* 40px */ padding: 2rem 2rem 2rem 3.5rem; /* 32px 32px 32px 56px */ font-size: 1.25rem; /* 20px */ } } -.blog-post blockquote p, .page blockquote p { +.blog-post blockquote p, .page blockquote p, .faq-content blockquote p { margin: 0; color: #141035; } -.blog-post blockquote p:not(:last-child), .page blockquote p:not(:last-child) { +.blog-post blockquote p:not(:last-child), .page blockquote p:not(:last-child), .faq-content blockquote p:not(:last-child) { margin-bottom: 1rem; /* 16px */ } /* TL;DR blocks */ -.blog-post .tldr, .page .tldr { +.blog-post .tldr, .page .tldr, .faq-content .tldr { margin: 0 0 2rem 0; /* 32px */ padding: 1.25rem 1.5rem; /* 20px 24px */ background: linear-gradient(135deg, rgba(138, 125, 255, 0.08) 0%, rgba(138, 125, 255, 0.03) 100%); @@ -2487,12 +2537,12 @@ a.button:hover { } @media (min-width: 768px) { - .blog-post .tldr, .page .tldr { + .blog-post .tldr, .page .tldr, .faq-content .tldr { padding: 1.5rem 2rem; /* 24px 32px */ } } -.blog-post .tldr .tldr-label, .page .tldr .tldr-label { +.blog-post .tldr .tldr-label, .page .tldr .tldr-label, .faq-content .tldr .tldr-label { display: block; font-size: 0.75rem; /* 12px */ font-weight: 700; @@ -2502,7 +2552,7 @@ a.button:hover { margin-bottom: 0.5rem; /* 8px */ } -.blog-post .tldr p, .page .tldr p { +.blog-post .tldr p, .page .tldr p, .faq-content .tldr p { margin: 0; font-size: 1rem; /* 16px */ line-height: 1.7; @@ -2510,13 +2560,13 @@ a.button:hover { } @media (min-width: 768px) { - .blog-post .tldr p, .page .tldr p { + .blog-post .tldr p, .page .tldr p, .faq-content .tldr p { font-size: 1.125rem; /* 18px */ } } /* Code */ -.blog-post code, .page code { +.blog-post code, .page code, .faq-content code { background: #f1f5f9; color: #334155; padding: 0.1875rem 0.5rem; /* 3px 8px */ @@ -2526,7 +2576,7 @@ a.button:hover { border: 1px solid #e2e8f0; } -.blog-post pre, .page pre { +.blog-post pre, .page pre, .faq-content pre { background: #1e293b; color: #e2e8f0; padding: 1.5rem; /* 24px */ @@ -2537,7 +2587,7 @@ a.button:hover { box-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1); } -.blog-post pre code, .page pre code { +.blog-post pre code, .page pre code, .faq-content pre code { background: transparent; padding: 0; border: none; @@ -2546,13 +2596,13 @@ a.button:hover { } @media (min-width: 768px) { - .blog-post pre code, .page pre code { + .blog-post pre code, .page pre code, .faq-content pre code { font-size: 1rem; /* 16px */ } } /* Tables */ -.blog-post table, .page table { +.blog-post table, .page table, .faq-content table { display: block; width: 100%; overflow-x: auto; @@ -2563,19 +2613,20 @@ a.button:hover { } @media (min-width: 768px) { - .blog-post table, .page table { + .blog-post table, .page table, .faq-content table { font-size: 1.125rem; /* 18px */ } } .blog-post th, .blog-post td, -.page th, .page td { +.page th, .page td, +.faq-content th, .faq-content td { border: 1px solid #e5e7eb; padding: 0.75rem 1rem; /* 12px 16px */ text-align: left; } -.blog-post th, .page th { +.blog-post th, .page th, .faq-content th { background-color: #f9fafb; color: #141035; font-weight: 600; @@ -2584,21 +2635,21 @@ a.button:hover { letter-spacing: 0.05em; } -.blog-post tbody tr, .page tbody tr { +.blog-post tbody tr, .page tbody tr, .faq-content tbody tr { background: #FFF; transition: background-color 0.2s ease; } -.blog-post tbody tr:hover, .page tbody tr:hover { +.blog-post tbody tr:hover, .page tbody tr:hover, .faq-content tbody tr:hover { background: #f9fafb; } -.blog-post td, .page td { +.blog-post td, .page td, .faq-content td { color: #5E5E5E; } /* Horizontal rules */ -.blog-post hr, .page hr { +.blog-post hr, .page hr, .faq-content hr { margin: 3rem 0; /* 48px */ border: none; height: 2px; @@ -2606,7 +2657,7 @@ a.button:hover { } @media (min-width: 768px) { - .blog-post hr, .page hr { + .blog-post hr, .page hr, .faq-content hr { margin: 4rem 0; /* 64px */ } } @@ -2856,6 +2907,10 @@ a.button:hover { background-color: rgb(138 125 255 / 0.2); } +.hover\:bg-\[\#8A7DFF\]\/30:hover { + background-color: rgb(138 125 255 / 0.3); +} + .hover\:bg-gray-800:hover { --tw-bg-opacity: 1; background-color: rgb(31 41 55 / var(--tw-bg-opacity, 1)); @@ -2948,6 +3003,26 @@ a.button:hover { filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); } +.focus\:border-\[\#8A7DFF\]:focus { + --tw-border-opacity: 1; + border-color: rgb(138 125 255 / var(--tw-border-opacity, 1)); +} + +.focus\:outline-none:focus { + outline: 2px solid transparent; + outline-offset: 2px; +} + +.focus\:ring-2:focus { + --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color); + --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color); + box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); +} + +.focus\:ring-\[\#8A7DFF\]\/20:focus { + --tw-ring-color: rgb(138 125 255 / 0.2); +} + .group:hover .group-hover\:translate-x-1 { --tw-translate-x: 0.25rem; transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); @@ -3081,9 +3156,6 @@ a.button:hover { .lg\:grid-cols-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); } - .lg\:grid-cols-4 { - grid-template-columns: repeat(4, minmax(0, 1fr)); - } .lg\:flex-row { flex-direction: row; } @@ -3168,3 +3240,9 @@ a.button:hover { line-height: 78px; } } + +@media (min-width: 1280px) { + .xl\:grid-cols-5 { + grid-template-columns: repeat(5, minmax(0, 1fr)); + } +} diff --git a/content/_index.html b/content/_index.html index 5becb79..27f4454 100644 --- a/content/_index.html +++ b/content/_index.html @@ -29,17 +29,17 @@

Integrates With
- - GitHub + + {{< icon "github" "w-6 h-6" >}} GitHub - - GitLab + + {{< icon "gitlab" "w-6 h-6" >}} GitLab - - Bitbucket + + {{< icon "bitbucket" "w-6 h-6" >}} Bitbucket - - Docker + + {{< icon "docker" "w-6 h-6" >}} Docker Google OSV diff --git a/content/faq/_index.md b/content/faq/_index.md new file mode 100644 index 0000000..e55e705 --- /dev/null +++ b/content/faq/_index.md @@ -0,0 +1,7 @@ +--- +url: /faq/ +title: Frequently Asked Questions +description: "Common questions about SBOMs, software supply chain security, and the sbomify platform. Get answers about SBOM formats, compliance requirements, and getting started." +keywords: [SBOM FAQ, Software Bill of Materials questions, sbomify help, SBOM compliance, supply chain security FAQ] +outputs: [HTML, JSON] +--- diff --git a/content/faq/can-i-combine-multiple-sboms-into-one.md b/content/faq/can-i-combine-multiple-sboms-into-one.md new file mode 100644 index 0000000..4a87313 --- /dev/null +++ b/content/faq/can-i-combine-multiple-sboms-into-one.md @@ -0,0 +1,42 @@ +--- +title: "Can I combine multiple SBOMs into one?" +description: "Why merging multiple SBOMs into a single file loses context, and how to link them together instead using sbomify's hierarchy." +answer: "You can technically merge SBOMs, but it should generally be avoided because you lose the ability to tell where a particular component comes from. Use sbomify's hierarchy to link multiple SBOMs together instead." +tldr: "You can technically merge SBOMs, but it should generally be avoided because you lose the ability to tell where a particular component comes from. Use sbomify's hierarchy to link multiple SBOMs together instead." +weight: 36 +keywords: [merge SBOMs, combine SBOMs, SBOM merging, multiple SBOMs, SBOM hierarchy, SBOM deduplication] +url: /faq/can-i-combine-multiple-sboms-into-one/ +--- + +## The short answer + +You can, but you probably shouldn't. Merging multiple SBOMs into a single flat file loses important context about where components come from. + +## Why merging is problematic + +Consider a product with a Python backend and a Node frontend, each with its own SBOM. If you merge them into one file: + +- **Origin is lost** - you can no longer tell whether a dependency belongs to the backend or the frontend +- **Deduplication destroys information** - if both SBOMs contain `pkg:pypi/requests@2.31.0`, a naive merge deduplicates it into one entry, but maybe only the backend actually uses it +- **Vulnerability triage becomes harder** - when a CVE hits a component, you need to know which service is affected, not just that the component exists somewhere in your product +- **Versioning breaks down** - your backend and frontend ship on different release cadences, but a merged SBOM has a single version + +## What about SPDX 3 and CycloneDX 2? + +The latest versions of both formats (SPDX 3.0, which is the current version, and the upcoming CycloneDX 2.0) do support linking multiple documents together without losing context. They allow referencing external SBOM documents while preserving the relationship between components and their source. However, this is significantly more complex than simply concatenating files, and tooling support is still maturing. + +## Our recommendation: link, don't merge + +Instead of merging SBOMs, use sbomify's [hierarchy](/faq/how-do-products-work-in-sbomify/) to link them together: + +- Each repository gets its own **component** with its own SBOM +- Components are grouped into **projects** (e.g. "Backend", "Frontend") +- Projects roll up into **products** (e.g. "My App") +- **Releases** snapshot specific SBOM versions across the product + +This preserves full context - you always know which component a dependency belongs to, which project it's part of, and which product release it shipped in. Customers and auditors can drill down to any level of detail, and you can share the full product SBOM or individual component SBOMs as needed. + +## Further reading + +- [How do products work in sbomify?](/faq/how-do-products-work-in-sbomify/) - the full hierarchy explained +- [SBOM Hierarchy feature page](/features/sbom-hierarchy/) diff --git a/content/faq/can-i-convert-between-cyclonedx-and-spdx.md b/content/faq/can-i-convert-between-cyclonedx-and-spdx.md new file mode 100644 index 0000000..20841f4 --- /dev/null +++ b/content/faq/can-i-convert-between-cyclonedx-and-spdx.md @@ -0,0 +1,51 @@ +--- +title: "Can I convert between CycloneDX and SPDX?" +description: "Why converting between CycloneDX and SPDX SBOM formats is problematic and what to do instead." +answer: "Not reliably. CycloneDX and SPDX have different data models, so converting between them inevitably loses context. The best approach is to generate natively in the format you need." +tldr: "Not reliably. CycloneDX and SPDX have different data models, so converting between them inevitably loses context. The best approach is to generate natively in the format you need." +weight: 35 +keywords: [CycloneDX, SPDX, SBOM conversion, SBOM format, convert SBOM, CycloneDX to SPDX, SPDX to CycloneDX] +url: /faq/can-i-convert-between-cyclonedx-and-spdx/ +--- + +## The short answer + +You can technically run a conversion tool, but you will almost certainly lose data in the process. CycloneDX and SPDX are not different encodings of the same information - they are fundamentally different data models with different concepts, fields, and relationships. + +## Why conversion loses context + +Each format has fields and structures the other does not: + +- **CycloneDX** has concepts like services, vulnerabilities (VEX), formulation, licensing expressions on components, lifecycle phases, and attestations that have no direct SPDX equivalent +- **SPDX** has concepts like document-level relationships, file-level analysis, snippet tracking, and annotation types that have no direct CycloneDX equivalent +- Even fields that look similar (like licensing) use different structures and semantics between the two formats + +A round-trip conversion (CycloneDX -> SPDX -> CycloneDX) will not give you back what you started with. Data that doesn't map cleanly is either dropped silently or shoehorned into fields where it doesn't belong. + +## What to do instead + +Generate natively in the format you need. [sbomify-action](https://github.com/sbomify/sbomify-action) supports both formats out of the box: + +```yaml +# CycloneDX (default) +- uses: sbomify/sbomify-action@master + env: + LOCK_FILE: requirements.txt + OUTPUT_FILE: sbom.cdx.json + ENRICH: true + +# SPDX +- uses: sbomify/sbomify-action@master + env: + LOCK_FILE: requirements.txt + OUTPUT_FILE: sbom.spdx.json + SBOM_FORMAT: spdx + ENRICH: true +``` + +If a customer or regulation requires a specific format, generate in that format from the start rather than converting after the fact. + +## Further reading + +- [What SBOM formats does sbomify support?](/faq/what-sbom-formats-does-sbomify-support/) +- [Schema Crosswalk](/compliance/schema-crosswalk/) - how fields map (and don't map) across CycloneDX and SPDX diff --git a/content/faq/how-do-i-achieve-ntia-cisa-compliance.md b/content/faq/how-do-i-achieve-ntia-cisa-compliance.md new file mode 100644 index 0000000..e3ef382 --- /dev/null +++ b/content/faq/how-do-i-achieve-ntia-cisa-compliance.md @@ -0,0 +1,108 @@ +--- +title: "How do I achieve NTIA/CISA minimum elements compliance?" +description: "Guide to meeting NTIA and CISA SBOM minimum elements requirements using sbomify-action's augmentation feature and sbomify's central profile management." +answer: "Use sbomify-action's augmentation feature to automatically add required metadata like supplier info, authors, licenses, and lifecycle phase to your SBOMs - either via a local config file or centrally managed profiles in sbomify." +tldr: "Use sbomify-action's augmentation feature to automatically add required metadata like supplier info, authors, licenses, and lifecycle phase to your SBOMs - either via a local config file or centrally managed profiles in sbomify." +weight: 85 +keywords: [NTIA compliance, CISA minimum elements, SBOM compliance, SBOM augmentation, supplier metadata, sbomify-action] +url: /faq/how-do-i-achieve-ntia-cisa-compliance/ +--- + +## The problem + +Most SBOM generation tools produce SBOMs that are missing key fields required by the [NTIA Minimum Elements](/compliance/ntia-minimum-elements/) and [CISA 2025 Minimum Elements](/compliance/cisa-minimum-elements/). Specifically, generated SBOMs typically lack: + +- **Supplier name** - the organization that supplies the component +- **Authors** - who created the SBOM data +- **Licenses** - per-component license information +- **Lifecycle phase** - the SDLC phase where the SBOM was generated (CISA 2025) + +It is possible to achieve NTIA/CISA compliance using other tools, but it typically requires chaining together multiple tools and manually injecting data into the generated SBOM. sbomify-action is a toolkit that automates this process and provides best-effort quality improvements to your SBOMs in a single step. + +## Option 1: Local config file + +You can provide augmentation metadata via a `sbomify.json` file in your project root. This works without a sbomify account: + +```json +{ + "lifecycle_phase": "build", + "supplier": { + "name": "Your Company", + "url": "https://yourcompany.com" + }, + "authors": [ + { + "name": "Your Team", + "email": "engineering@yourcompany.com" + } + ], + "licenses": ["Apache-2.0"] +} +``` + +Then enable augmentation in your CI pipeline: + +```yaml +- uses: sbomify/sbomify-action@master + env: + LOCK_FILE: requirements.txt + OUTPUT_FILE: sbom.cdx.json + AUGMENT: true + ENRICH: true + UPLOAD: false +``` + +This is ideal for individual projects or teams that want to manage metadata per-repository. + +## Option 2: Central profile management in sbomify + +For organizations managing many components, sbomify provides centrally managed augmentation profiles. Instead of maintaining `sbomify.json` files in every repository, you configure the metadata once in sbomify and it gets applied automatically during augmentation. + +### Creating a profile + +Navigate to your workspace settings to create an augmentation profile with your organization's supplier info, authors, licenses, and other metadata: + +{{< video-embed-native video_url="https://marketing-assets.sbomify.com/profile_editing.webm" title="Creating an augmentation profile in sbomify" description="Walkthrough of creating a centrally managed augmentation profile in sbomify for NTIA/CISA compliance." >}} + +### Using profiles + +Once you have a profile, there are two ways to apply it: + +- **Default profile** - Set a profile as the workspace default, and it will be used for all components in that workspace during augmentation +- **Per-component profile** - Manually select a specific profile on individual components for cases where different components need different metadata + +Then in your CI pipeline, simply enable augmentation with a sbomify account: + +```yaml +- uses: sbomify/sbomify-action@master + env: + TOKEN: ${{ secrets.SBOMIFY_TOKEN }} + COMPONENT_ID: your-component-id + LOCK_FILE: requirements.txt + AUGMENT: true + ENRICH: true +``` + +sbomify-action will fetch the profile metadata from sbomify and apply it to the generated SBOM automatically. + +## What gets added + +Augmentation addresses specific NTIA and CISA minimum element fields: + +| Field | NTIA 2021 | CISA 2025 | +| ------------------- | --------- | -------------- | +| Supplier Name | Required | Required | +| Author of SBOM Data | Required | Required | +| License | - | Required (new) | +| Generation Context | - | Required (new) | + +For the full list of supported augmentation fields, see the [sbomify-action documentation](https://github.com/sbomify/sbomify-action#augmentation-vs-enrichment). + +## Further reading + +- [Compliance overview](/compliance/) - all frameworks and standards sbomify supports +- [NTIA Minimum Elements guide](/compliance/ntia-minimum-elements/) +- [CISA 2025 Minimum Elements guide](/compliance/cisa-minimum-elements/) +- [EU Cyber Resilience Act guide](/compliance/eu-cra/) +- [Schema Crosswalk](/compliance/schema-crosswalk/) - how fields map across CycloneDX and SPDX +- [sbomify-action augmentation reference](https://github.com/sbomify/sbomify-action#augmentation-config-file) diff --git a/content/faq/how-do-i-create-a-software-release.md b/content/faq/how-do-i-create-a-software-release.md new file mode 100644 index 0000000..738c32d --- /dev/null +++ b/content/faq/how-do-i-create-a-software-release.md @@ -0,0 +1,36 @@ +--- +title: "How do I create a software release in sbomify?" +description: "Step-by-step guide to creating a product release in sbomify by linking existing component SBOMs to a versioned release." +answer: "Upload your component SBOMs first, then create a product release that points to specific SBOMs. Each SBOM can have its own version and be shared across multiple releases." +tldr: "Upload your component SBOMs first, then create a product release that points to specific SBOMs. Each SBOM can have its own version and be shared across multiple releases." +weight: 77 +keywords: [product release, software release, sbomify release, create release, SBOM versioning, release management] +url: /faq/how-do-i-create-a-software-release/ +--- + +## Walkthrough + +{{< video-embed-native video_url="https://marketing-assets.sbomify.com/release_creation.webm" title="How to create a software release in sbomify" description="Step-by-step screencast showing how to create a product release in sbomify by linking component SBOMs." >}} + +## Creating a product release + +A product release in sbomify ties together one or more component SBOMs under a single version tag. This is how you represent a shipped version of your software. + +### Prerequisites + +Before creating a release, you need: + +- A **product** set up in sbomify (see [How do products work?](/faq/how-do-products-work-in-sbomify/)) +- One or more **components** with uploaded SBOMs + +### Steps + +1. Navigate to your **Product** +2. Click **Create Release** +3. Enter the **release version** (e.g. `v2.1.0`) +4. Select which **SBOMs** to include in this release +5. Click **Save** + +### How versioning works + +Component SBOMs and product releases are versioned independently. For example, your product `v2.1.0` might include a backend component at `v1.8.3` and a frontend at `v3.0.1`. The same component SBOM can also be shared across multiple product releases - if two products ship the same library version, there's no need to upload it twice. diff --git a/content/faq/how-do-i-delete-a-workspace.md b/content/faq/how-do-i-delete-a-workspace.md new file mode 100644 index 0000000..c4232dc --- /dev/null +++ b/content/faq/how-do-i-delete-a-workspace.md @@ -0,0 +1,25 @@ +--- +title: "How do I delete a workspace?" +description: "Step-by-step guide to deleting a workspace in sbomify, including what happens to your data." +answer: "You can delete a workspace from the workspace settings page. This permanently removes the workspace and all its data, including components, SBOMs, and documents." +tldr: "You can delete a workspace from the workspace settings page. This permanently removes the workspace and all its data, including components, SBOMs, and documents." +weight: 80 +keywords: [delete workspace, remove workspace, sbomify workspace, workspace settings] +url: /faq/how-do-i-delete-a-workspace/ +--- + +## Walkthrough + +{{< video-embed-native video_url="https://marketing-assets.sbomify.com/workspace_deletion.webm" title="How to delete a workspace in sbomify" description="Step-by-step screencast showing how to delete a workspace in sbomify." >}} + +## Deleting a workspace + +To delete a workspace in sbomify: + +1. Navigate to your workspace **Settings** +2. Go to the **General** tab +3. Scroll down to the **Danger Zone** section +4. Click **Delete Workspace** +5. Confirm the deletion when prompted + +This action is **permanent** and cannot be undone. All data associated with the workspace will be deleted, including products, projects, components, SBOMs, and documents. diff --git a/content/faq/how-do-i-delete-my-account.md b/content/faq/how-do-i-delete-my-account.md new file mode 100644 index 0000000..1aeab23 --- /dev/null +++ b/content/faq/how-do-i-delete-my-account.md @@ -0,0 +1,24 @@ +--- +title: "How do I delete my account?" +description: "Step-by-step guide to deleting your account in sbomify, including what happens to your data." +answer: "You can delete your account from Settings > Account > Delete Your Account. This permanently removes your account and all associated data." +tldr: "You can delete your account from Settings > Account > Delete Your Account. This permanently removes your account and all associated data." +weight: 81 +keywords: [delete account, remove account, sbomify account, account settings, account deletion] +url: /faq/how-do-i-delete-my-account/ +--- + +## Walkthrough + +{{< video-embed-native video_url="https://marketing-assets.sbomify.com/account_deletion.webm" title="How to delete your account in sbomify" description="Step-by-step screencast showing how to delete your account in sbomify." >}} + +## Deleting your account + +To delete your account in sbomify: + +1. Navigate to **Settings** +2. Go to the **Account** tab +3. Click **Delete Your Account** +4. Confirm the deletion when prompted + +This action is **permanent** and cannot be undone. All data associated with your account will be deleted. diff --git a/content/faq/how-do-i-enable-tea-in-sbomify.md b/content/faq/how-do-i-enable-tea-in-sbomify.md new file mode 100644 index 0000000..90e74f3 --- /dev/null +++ b/content/faq/how-do-i-enable-tea-in-sbomify.md @@ -0,0 +1,41 @@ +--- +title: "How do I enable the Transparency Exchange API (TEA) in sbomify?" +description: "Step-by-step guide to enabling the Transparency Exchange API (TEA) in sbomify for automated SBOM discovery and distribution." +answer: "You can enable TEA from your workspace settings. TEA requires a Business plan or higher." +tldr: "You can enable TEA from your workspace settings. TEA requires a Business plan or higher." +plan: "Business+" +weight: 72 +keywords: [TEA, Transparency Exchange API, SBOM distribution, SBOM discovery, sbomify TEA, enable TEA] +url: /faq/how-do-i-enable-tea-in-sbomify/ +--- + +## Walkthrough + +{{< video-embed-native video_url="https://marketing-assets.sbomify.com/tea_enabling.webm" title="How to enable TEA in sbomify" description="Step-by-step screencast showing how to enable the Transparency Exchange API (TEA) in sbomify." >}} + +## What is TEA? + +The [Transparency Exchange API (TEA)](https://github.com/CycloneDX/transparency-exchange-api) is a standardized, format-agnostic API for automating software supply chain transparency. Developed within ECMA TC54, it provides a standard way for vendors and open-source projects to share transparency artifacts with downstream consumers. + +TEA goes beyond just SBOMs. It supports sharing a range of artifact types: + +- **SBOMs** - Software Bill of Materials +- **VEX/VDR** - Vulnerability exploitability and disclosure reports +- **CLE** - Common Lifecycle Enumeration (ECMA-428) +- **CDXA** - CycloneDX Attestations for standards compliance +- **HBOM, AI/ML-BOM, SaaSBOM, CBOM** - Hardware, AI/ML, SaaS, and Cryptography BOMs + +Instead of manually exchanging files via email or portals, TEA lets consumers programmatically discover and retrieve artifacts for any product release using a standard API. + +## Enabling TEA + +TEA is available on the **Business** plan and above. + +To enable it: + +1. Navigate to your workspace **Settings** +2. Go to the **TEA** section +3. Toggle TEA on +4. Configure your TEA endpoint settings + +Once enabled, your published SBOMs become discoverable via the TEA protocol, making it easy for customers and partners to access your transparency data automatically. diff --git a/content/faq/how-do-i-generate-an-sbom.md b/content/faq/how-do-i-generate-an-sbom.md new file mode 100644 index 0000000..fe30693 --- /dev/null +++ b/content/faq/how-do-i-generate-an-sbom.md @@ -0,0 +1,74 @@ +--- +title: "How do I generate an SBOM?" +description: "Step-by-step guide to generating your first SBOM using sbomify-action, open-source tools, and CI/CD integration." +answer: "The easiest way is with sbomify-action, which generates, enriches, and uploads SBOMs from your lockfiles or Docker images in CI/CD. You can also use standalone tools like Syft or Trivy." +tldr: "The easiest way is with sbomify-action, which generates, enriches, and uploads SBOMs from your lockfiles or Docker images in CI/CD. You can also use standalone tools like Syft or Trivy." +weight: 60 +keywords: [generate SBOM, create SBOM, SBOM tools, SBOM generation, how to SBOM, sbomify-action] +url: /faq/how-do-i-generate-an-sbom/ +--- + +## Recommended: sbomify-action + +The [sbomify-action](https://github.com/sbomify/sbomify-action) is a CI/CD tool that generates, augments, enriches, and uploads SBOMs from your lockfiles or Docker images. It works as a GitHub Action, Docker image, or pip package, and includes SBOM generators (Trivy, Syft, cdxgen) pre-installed. + +```yaml +- uses: sbomify/sbomify-action@master + env: + LOCK_FILE: requirements.txt + OUTPUT_FILE: sbom.cdx.json + ENRICH: true +``` + +sbomify-action supports Python, Node, Rust, Go, Ruby, Dart, C++, Docker images, and Yocto/OpenEmbedded builds. It outputs both CycloneDX and SPDX formats. + +Beyond basic generation, sbomify-action can: + +- **Enrich** SBOMs with metadata from package registries (PyPI, npm, crates.io, etc.) +- **Augment** with business metadata (supplier, authors, licenses, lifecycle phase) +- **Inject** additional packages not in lockfiles (vendored code, system libraries) +- **Upload** to sbomify for collaboration and vulnerability management +- **Attest** with GitHub's build provenance + +It also works with [GitLab CI and Bitbucket Pipelines](https://github.com/sbomify/sbomify-action#other-cicd-platforms). See our [CI/CD integration guide](/guides/ci-cd/) for details. + +### Using Docker directly + +The sbomify-action Docker image can be used standalone, without any CI platform: + +```bash +docker run --rm \ + -v $(pwd):/github/workspace \ + -w /github/workspace \ + -e LOCK_FILE=/github/workspace/requirements.txt \ + -e OUTPUT_FILE=/github/workspace/sbom.cdx.json \ + -e UPLOAD=false \ + -e ENRICH=true \ + sbomifyhub/sbomify-action +``` + +This is useful for local development, scripted workflows, or CI systems that don't have a native sbomify-action integration. + +## Standalone tools + +If you prefer standalone tools outside of CI/CD, **Syft** and **Trivy** are popular options: + +```bash +# Using Syft +syft . -o cyclonedx-json > sbom.cdx.json + +# Using Trivy +trivy fs . --format cyclonedx --output sbom.cdx.json +``` + +For language-specific generators, see our [language guides](/guides/) covering Python, JavaScript, Java, Go, Rust, Docker, and more. + +## See it in action + +Watch our FOSDEM 2026 talk for a real-world walkthrough of CRA-ready SBOM generation using sbomify-action: + +{{< video-embed-native video_url="https://video.fosdem.org/2026/ud2208/UYTGWA-sbom-generation.av1.webm" title="CRA-Ready SBOMs: A Practical Blueprint for High-Quality Generation" description="A four-phase SBOM generation model addressing the EU's Cyber Resilience Act requirements, covering authoring, augmenting, enriching, and signing SBOMs to exceed minimal compliance standards." >}} + +## Next steps + +Once you have your SBOM, [upload it to sbomify](https://app.sbomify.com) to monitor for vulnerabilities, track compliance, and share it with customers through your [Trust Center](https://trust.sbomify.com/). diff --git a/content/faq/how-do-i-set-up-a-trust-center.md b/content/faq/how-do-i-set-up-a-trust-center.md new file mode 100644 index 0000000..9e0c02f --- /dev/null +++ b/content/faq/how-do-i-set-up-a-trust-center.md @@ -0,0 +1,39 @@ +--- +title: "How do I set up a Trust Center in sbomify?" +description: "Step-by-step guide to enabling and configuring a Trust Center in sbomify, including custom domain setup." +answer: "Go to Settings > Trust Center, enable it, and set your custom domain. Trust Center requires a Business plan or higher." +tldr: "Go to Settings > Trust Center, enable it, and set your custom domain. Trust Center requires a Business plan or higher." +plan: "Business+" +weight: 71 +keywords: [Trust Center, set up Trust Center, enable Trust Center, custom domain, sbomify Trust Center, trust.sbomify.com] +url: /faq/how-do-i-set-up-a-trust-center/ +--- + +## Walkthrough + +{{< video-embed-native video_url="https://marketing-assets.sbomify.com/trust_center_setup.webm" title="How to set up a Trust Center in sbomify" description="Step-by-step screencast showing how to enable and configure a Trust Center in sbomify." >}} + +## Setting up a Trust Center + +The Trust Center is available on the **Business** plan and above. For background on what a Trust Center is and why it matters, see [What is a Trust Center?](/faq/what-is-a-trust-center/). + +To set up your Trust Center: + +1. Navigate to **Settings** +2. Go to the **Trust Center** section +3. **Enable** your Trust Center +4. Set your **custom domain** (e.g. `trust.yourcompany.com`) +5. Configure a CNAME record with your DNS provider pointing to sbomify + +Once enabled, your uploaded SBOMs and compliance documents are automatically published to your Trust Center. You can see a live example at [trust.sbomify.com](https://trust.sbomify.com/). + +## Gated content + +Not everything needs to be public. sbomify lets you mark components as **gated**, meaning visitors must request access before they can view or download the artifacts. This is useful for sensitive documents like penetration test reports or detailed SBOMs that you only want to share under certain conditions. + +Gated content supports two modes: + +- **With NDA** -the visitor must accept your NDA before access is granted +- **Without NDA** -the visitor requests access and you approve or deny it manually + +Either way, you stay in control of who sees what. Approval requests show up in your sbomify dashboard so you can review them. diff --git a/content/faq/how-do-i-upload-compliance-documents.md b/content/faq/how-do-i-upload-compliance-documents.md new file mode 100644 index 0000000..cd7dab4 --- /dev/null +++ b/content/faq/how-do-i-upload-compliance-documents.md @@ -0,0 +1,27 @@ +--- +title: "How do I upload compliance documents?" +description: "Step-by-step guide to uploading compliance documents like SOC 2, ISO 27001, and CE certificates in sbomify." +answer: "You can upload compliance documents (SOC 2, ISO 27001, CE certificates, etc.) to any project in sbomify by navigating to the project and using the Documents section." +tldr: "You can upload compliance documents (SOC 2, ISO 27001, CE certificates, etc.) to any project in sbomify by navigating to the project and using the Documents section." +weight: 76 +keywords: [compliance documents, SOC 2, ISO 27001, CE certificate, upload documents, sbomify documents] +url: /faq/how-do-i-upload-compliance-documents/ +--- + +## Walkthrough + +{{< video-embed-native video_url="https://marketing-assets.sbomify.com/document_upload.webm" title="How to upload compliance documents in sbomify" description="Step-by-step screencast showing how to upload compliance documents like SOC 2 and ISO 27001 in sbomify." >}} + +## Uploading compliance documents + +sbomify lets you attach compliance documents -such as SOC 2 Type II reports, ISO 27001 certificates, CE certificates, and other attestations -directly to your projects. This keeps your compliance artifacts alongside your SBOMs in one place. + +To upload a compliance document: + +1. Navigate to your **Project** +2. Go to the **Documents** section +3. Click **Upload Document** +4. Select the file and fill in the document details +5. Click **Save** + +Uploaded documents are visible to anyone with access to the project and can be shared via your [Trust Center](/faq/what-is-a-trust-center/). diff --git a/content/faq/is-sbomify-free.md b/content/faq/is-sbomify-free.md new file mode 100644 index 0000000..0324c4c --- /dev/null +++ b/content/faq/is-sbomify-free.md @@ -0,0 +1,51 @@ +--- +title: "Is sbomify free?" +description: "Learn about sbomify's pricing tiers including the free Community plan for open-source projects, the Business plan for teams, and Enterprise options." +answer: "Yes - sbomify offers a free Community tier for open-source maintainers and hobby projects. Paid Business and Enterprise plans are available for teams that need private SBOMs and advanced features." +tldr: "Yes - sbomify offers a free Community tier for open-source maintainers and hobby projects. Paid Business and Enterprise plans are available for teams that need private SBOMs and advanced features." +weight: 40 +keywords: [sbomify pricing, sbomify free, SBOM tool free, sbomify plans] +url: /faq/is-sbomify-free/ +--- + +## Pricing tiers + +sbomify offers three plans to fit different needs: + +### Community (Free) + +The Community tier is **completely free** and designed for: + +- Open-source maintainers who want to publish SBOMs for their projects +- Hobby projects and personal use +- Developers evaluating sbomify before upgrading + +It includes core SBOM management features and the ability to share SBOMs publicly. + +### Business ($199/month) + +The Business tier is built for mid-size teams that need: + +- Private SBOM repositories +- Team collaboration features +- Compliance reporting +- Priority support + +### Enterprise (Custom pricing) + +For large organizations with advanced security and compliance needs: + +- SSO/SAML integration +- Custom roles and permissions +- Dedicated support +- SLA guarantees + +Visit our [Pricing page](/pricing/) for the full feature comparison, or [sign up for a free account](https://app.sbomify.com) to get started immediately. + +## Self-hosting + +sbomify is also available as a self-hosted solution. If you prefer to run sbomify on your own infrastructure, you can deploy it using Docker. Visit our [GitHub repository](https://github.com/sbomify/sbomify) for setup instructions. + +## No credit card required + +You can create a Community account and start uploading SBOMs right away - no credit card or commitment needed. Upgrade to a paid plan whenever your needs grow. diff --git a/content/faq/what-is-a-trust-center.md b/content/faq/what-is-a-trust-center.md new file mode 100644 index 0000000..fe34128 --- /dev/null +++ b/content/faq/what-is-a-trust-center.md @@ -0,0 +1,50 @@ +--- +title: "What is a Trust Center?" +description: "Learn what a Trust Center is, how it helps you share security artifacts transparently, and how sbomify makes it easy to create one." +answer: "A Trust Center is a public-facing page where organizations share security artifacts like SBOMs, compliance documents, and attestations with customers and partners - building transparency and trust." +tldr: "A Trust Center is a public-facing page where organizations share security artifacts like SBOMs, compliance documents, and attestations with customers and partners - building transparency and trust." +weight: 70 +keywords: [Trust Center, security artifacts, SBOM sharing, sbomify Trust Center, software transparency] +url: /faq/what-is-a-trust-center/ +--- + +## What is a Trust Center? + +A Trust Center is a dedicated page where your organization publicly shares security and compliance information about your products. Instead of handling security questionnaires and SBOM requests ad-hoc via email, you provide a single URL where customers and partners can find everything they need. + +A Trust Center typically includes: + +- **SBOMs** - Current Software Bill of Materials for your products +- **Compliance status** - Which frameworks and standards you meet +- **Security attestations** - Signed statements about your security practices +- **Vulnerability disclosures** - How you handle and communicate security issues + +## Why does it matter? + +Enterprise buyers and regulated industries increasingly require evidence of security practices during procurement. A Trust Center: + +- **Reduces friction** - Customers self-serve instead of sending questionnaires +- **Scales trust** - One page serves all customers, partners, and auditors +- **Demonstrates maturity** - Shows you take supply chain security seriously +- **Meets compliance requirements** - CRA and other regulations require transparency about software composition + +## sbomify's Trust Center + +sbomify includes a built-in Trust Center on the Business and Enterprise plans that automatically publishes your uploaded SBOMs and compliance artifacts. You can see a live example at [trust.sbomify.com](https://trust.sbomify.com/) - that's sbomify's own Trust Center, built with the same feature available to Business and Enterprise users. + +Key features: + +- **Automatic updates** - When you upload a new SBOM, your Trust Center reflects it immediately +- **Custom domain** - Map your Trust Center to your own domain (e.g., trust.yourcompany.com) +- **Granular access** - Choose which artifacts are public vs. private +- **Compliance badges** - Show which standards your products meet + +## Getting started + +1. [Sign up for sbomify](https://app.sbomify.com) on a Business or Enterprise plan +2. Upload your SBOMs +3. Configure your Trust Center settings +4. Optionally map it to your own domain +5. Share the URL with customers + +No additional hosting is required - sbomify handles everything. diff --git a/content/faq/what-is-an-sbom.md b/content/faq/what-is-an-sbom.md new file mode 100644 index 0000000..23a5318 --- /dev/null +++ b/content/faq/what-is-an-sbom.md @@ -0,0 +1,41 @@ +--- +title: "What is an SBOM?" +description: "Learn what a Software Bill of Materials (SBOM) is, why it matters for supply chain security, and how it lists every component in your software." +answer: "An SBOM (Software Bill of Materials) is a machine-readable inventory of all components, libraries, and dependencies that make up a piece of software - like an ingredients list for your code." +tldr: "An SBOM (Software Bill of Materials) is a machine-readable inventory of all components, libraries, and dependencies that make up a piece of software - like an ingredients list for your code." +weight: 10 +keywords: [SBOM, Software Bill of Materials, what is SBOM, SBOM definition] +url: /faq/what-is-an-sbom/ +--- + +## What does SBOM stand for? + +SBOM stands for **Software Bill of Materials**. It is a formal, machine-readable document that lists every component included in a software product - open-source libraries, third-party packages, and their transitive dependencies. + +Think of it like a nutrition label for software. Just as food labels tell you exactly what ingredients are inside, an SBOM tells you exactly what code is inside your application. + +## Why do SBOMs matter? + +Modern software is built from hundreds or thousands of open-source and third-party components. When a vulnerability is discovered in one of those components (like [Log4Shell](https://en.wikipedia.org/wiki/Log4Shell) in 2021), organizations need to quickly determine whether they are affected. Without an SBOM, this is a slow and error-prone process. + +SBOMs help you: + +- **Identify vulnerabilities** - Know immediately if a vulnerable component is in your software +- **Meet compliance requirements** - Regulations like the [EU Cyber Resilience Act](/compliance/eu-cra/) and [NTIA minimum elements](/compliance/ntia/) now require SBOMs +- **Build customer trust** - Share your software composition transparently via a [Trust Center](https://trust.sbomify.com/) +- **Manage license risk** - Understand which open-source licenses apply to your codebase + +## What formats are SBOMs available in? + +The two most widely adopted SBOM formats are: + +- **[CycloneDX](https://cyclonedx.org/)** - A lightweight, security-focused format maintained by OWASP +- **[SPDX](https://spdx.dev/)** - An ISO/IEC standard (ISO/IEC 5962:2021) originally focused on license compliance + +Both formats support JSON and XML representations. sbomify supports both CycloneDX and SPDX. + +## How do I get started? + +Generating your first SBOM is straightforward. Check out our [language-specific guides](/guides/) for step-by-step instructions covering Python, JavaScript, Java, Go, Rust, and more. Once you have an SBOM, you can upload it to [sbomify](https://app.sbomify.com) to manage, monitor, and share it. + +For a deeper introduction, read our full [What is an SBOM?](/what-is-sbom/) page. diff --git a/content/faq/what-is-the-eu-cyber-resilience-act.md b/content/faq/what-is-the-eu-cyber-resilience-act.md new file mode 100644 index 0000000..59f12f6 --- /dev/null +++ b/content/faq/what-is-the-eu-cyber-resilience-act.md @@ -0,0 +1,62 @@ +--- +title: "What is the EU Cyber Resilience Act (CRA)?" +description: "Understand the EU Cyber Resilience Act, its SBOM requirements, timeline, and how sbomify helps you achieve CRA compliance." +answer: "The EU Cyber Resilience Act (CRA) is a binding EU regulation requiring manufacturers of products with digital elements to provide SBOMs, handle vulnerabilities, and meet cybersecurity requirements throughout the product lifecycle." +tldr: "The EU Cyber Resilience Act (CRA) is a binding EU regulation requiring manufacturers of products with digital elements to provide SBOMs, handle vulnerabilities, and meet cybersecurity requirements throughout the product lifecycle." +weight: 50 +keywords: [EU CRA, Cyber Resilience Act, CRA SBOM, EU SBOM compliance, CRA requirements] +url: /faq/what-is-the-eu-cyber-resilience-act/ +--- + +## Overview + +The **EU Cyber Resilience Act** (Regulation 2024/2847) is a binding EU regulation that establishes cybersecurity requirements for products with digital elements - essentially any hardware or software product sold in the EU market. + +It was published in the Official Journal of the EU in November 2024, with a phased enforcement timeline through 2027. + +## Key SBOM requirements + +The CRA explicitly requires manufacturers to: + +- **Produce a machine-readable SBOM** in a commonly used format (e.g., CycloneDX, SPDX) identifying components and dependencies in their products +- **Cover at least top-level dependencies** of the product +- **Document vulnerabilities** and provide timely security updates +- **Report actively exploited vulnerabilities** to ENISA within 24 hours +- **Maintain cybersecurity** throughout the product's expected lifetime + +Germany's BSI has published [TR-03183-2](https://bsi.bund.de/dok/TR-03183-en), which provides concrete technical specifications for CRA-compliant SBOMs, including: + +- **Format:** CycloneDX 1.6+ or SPDX 3.0.1+ in JSON or XML +- **Depth:** Recursive dependency resolution down to and including the first component outside the scope of delivery +- **Required fields per component:** Creator, name, version, filename, dependencies, licences (as SPDX identifiers), SHA-512 hash, and executable/archive/structured properties +- **No vulnerability data in SBOMs** - use CSAF or VEX instead + +## Who does it apply to? + +The CRA applies to: + +- Software vendors selling products in the EU (including SaaS with on-premise components) +- Hardware manufacturers with embedded software +- Open-source projects distributed commercially (non-commercial open source has exemptions) + +## Timeline + +- **September 2026** - Vulnerability reporting obligations begin +- **September 2027** - Full compliance required for all products + +## How sbomify helps + +sbomify provides tooling to help you prepare for CRA compliance: + +- Manage and monitor SBOMs across your product portfolio +- Track vulnerability status with automated scanning +- Share compliance artifacts through your [Trust Center](https://trust.sbomify.com/) +- CRA compliance plugin to assess your SBOM against CRA requirements + +For the complete breakdown of CRA requirements and field mappings, see our detailed [EU CRA Compliance Guide](/compliance/eu-cra/). + +## FOSDEM 2026: CRA-Ready SBOMs + +For a practical walkthrough of CRA-ready SBOM generation, watch our FOSDEM 2026 talk: + +{{< video-embed-native video_url="https://video.fosdem.org/2026/ud2208/UYTGWA-sbom-generation.av1.webm" title="CRA-Ready SBOMs: A Practical Blueprint for High-Quality Generation" description="A four-phase SBOM generation model addressing the EU's Cyber Resilience Act requirements, covering authoring, augmenting, enriching, and signing SBOMs to exceed minimal compliance standards." >}} diff --git a/content/faq/what-sbom-formats-does-sbomify-support.md b/content/faq/what-sbom-formats-does-sbomify-support.md new file mode 100644 index 0000000..9ed6e99 --- /dev/null +++ b/content/faq/what-sbom-formats-does-sbomify-support.md @@ -0,0 +1,48 @@ +--- +title: "What SBOM formats does sbomify support?" +description: "sbomify supports CycloneDX and SPDX SBOM formats in JSON, with automatic validation and schema compliance checking." +answer: "sbomify supports both CycloneDX and SPDX - the two industry-standard SBOM formats - in JSON representation, with automatic validation against official schemas." +tldr: "sbomify supports both CycloneDX and SPDX - the two industry-standard SBOM formats - in JSON representation, with automatic validation against official schemas." +weight: 30 +keywords: [SBOM formats, CycloneDX, SPDX, sbomify formats, SBOM standard] +url: /faq/what-sbom-formats-does-sbomify-support/ +--- + +## Supported formats + +sbomify supports the two major SBOM standards: + +### CycloneDX + +[CycloneDX](https://cyclonedx.org/) is an OWASP project designed specifically for security use cases. It is lightweight, easy to generate, and widely supported by tooling. + +- **Versions supported:** CycloneDX 1.6, 1.7 +- **Representations:** JSON +- **Strengths:** Security-focused, supports VEX (Vulnerability Exploitability eXchange), extensive tooling ecosystem + +### SPDX + +[SPDX](https://spdx.dev/) (Software Package Data Exchange) is an ISO/IEC international standard (5962:2021) with deep roots in license compliance. + +- **Versions supported:** SPDX 2.3, 3.0 +- **Representations:** JSON +- **Strengths:** ISO standard, strong license compliance support, widely used in automotive and enterprise + +## Automatic validation + +When you upload an SBOM to sbomify, it is automatically validated against the official schema for its format and version. This helps catch malformed documents before they enter your pipeline. + +## Which format should I choose? + +Both formats are well supported and meet regulatory requirements. Some considerations: + +- **CycloneDX** is generally easier to get started with and has stronger security tooling (VEX, VDR) +- **SPDX** may be preferred if your industry or customers specifically require an ISO standard + +Most SBOM generation tools support both formats. See our [language guides](/guides/) for tool-specific instructions. + +## Can I convert between formats? + +We strongly recommend against converting between CycloneDX and SPDX. The two formats have different data models, and conversion is inherently lossy - fields, relationships, and metadata will be dropped or misrepresented in the process. The resulting SBOM may look valid but will be incomplete or inaccurate. + +Instead, generate your SBOMs natively in the format you need. Some tools like Syft and Trivy support both formats, but many generators only output one. Check our [Resources page](/resources/) for a list of SBOM generation tools and their supported formats. diff --git a/content/faq/why-do-i-need-an-sbom.md b/content/faq/why-do-i-need-an-sbom.md new file mode 100644 index 0000000..93791fb --- /dev/null +++ b/content/faq/why-do-i-need-an-sbom.md @@ -0,0 +1,43 @@ +--- +title: "Why do I need an SBOM?" +description: "Discover why your organization needs a Software Bill of Materials for vulnerability management, regulatory compliance, and customer trust." +answer: "You need an SBOM to track what's inside your software, respond quickly to vulnerabilities, meet regulatory requirements like the EU CRA, and build trust with customers and partners." +tldr: "You need an SBOM to track what's inside your software, respond quickly to vulnerabilities, meet regulatory requirements like the EU CRA, and build trust with customers and partners." +weight: 20 +keywords: [why SBOM, SBOM benefits, SBOM requirements, software supply chain] +url: /faq/why-do-i-need-an-sbom/ +--- + +## The software supply chain problem + +Over 90% of modern applications contain open-source components. When a critical vulnerability is disclosed, the first question every security team asks is: _"Are we affected?"_ Without an SBOM, answering that question requires manually auditing codebases across every product and service - a process that can take days or weeks. + +## Key reasons to adopt SBOMs + +### Vulnerability response + +When a new CVE drops, an SBOM lets you search your entire software portfolio in seconds. Instead of scrambling to check repos manually, you can query your SBOMs and know immediately which products contain the affected component. + +### Regulatory compliance + +SBOMs are increasingly required by law and industry standards: + +- **[EU Cyber Resilience Act (CRA)](/compliance/eu-cra/)** - Requires SBOMs for all products with digital elements sold in the EU +- **[NTIA Minimum Elements](/compliance/ntia/)** - US government baseline for SBOM content +- **[NIST 800-171](/compliance/nist-800-171/)** - Supply chain risk management requirements +- **[FDA guidance](/compliance/fda/)** - Medical device manufacturers must submit SBOMs +- **[PCI DSS 4.0](/compliance/pci-dss/)** - Payment industry now references software composition analysis + +See our full [Compliance guide](/compliance/) for details on each framework. + +### Customer trust and procurement + +Enterprise buyers increasingly ask for SBOMs during procurement. Having your SBOMs ready and accessible through a [Trust Center](https://trust.sbomify.com/) demonstrates transparency and security maturity, giving you a competitive advantage. + +### License management + +SBOMs catalog the licenses of every dependency, helping legal teams identify copyleft or restrictive licenses before they become a problem. + +## Getting started + +You don't need to overhaul your development process. Start by generating an SBOM for one project using our [language guides](/guides/), then gradually expand coverage. [sbomify's free Community tier](https://app.sbomify.com) lets you manage SBOMs for open-source projects at no cost. diff --git a/content/features/integrations.html b/content/features/integrations.html index bbaa544..e39817b 100644 --- a/content/features/integrations.html +++ b/content/features/integrations.html @@ -18,7 +18,7 @@

CI/CD & Generation

- GitHub + {{< icon "github" "w-8 h-8" >}} GitHub
View on Marketplace → @@ -45,28 +45,30 @@

CI/CD & Generation

- GitLab - View Pipeline → + {{< icon "gitlab" "w-8 h-8" >}} GitLab + View on GitHub →

- For GitLab users, we provide a dedicated pipeline template. + Use our Docker image directly in GitLab CI with built-in caching support.

generate-sbom:
   image: sbomifyhub/sbomify-action
+  cache:
+    key: sbomify-cache
+    paths:
+      - .sbomify-cache/
   variables:
-    TOKEN: $SBOMIFY_TOKEN
-    COMPONENT_ID: 'Your Component ID'
-    UPLOAD: "true"
-    AUGMENT: "true"
+    SBOMIFY_CACHE_DIR: "${CI_PROJECT_DIR}/.sbomify-cache/sbomify"
+    TRIVY_CACHE_DIR: "${CI_PROJECT_DIR}/.sbomify-cache/trivy"
+    SYFT_CACHE_DIR: "${CI_PROJECT_DIR}/.sbomify-cache/syft"
+    LOCK_FILE: poetry.lock
+    OUTPUT_FILE: sbom.cdx.json
+    UPLOAD: "false"
     ENRICH: "true"
-    COMPONENT_NAME: 'my-python-app'
-    COMPONENT_VERSION: $CI_COMMIT_SHA
-    LOCK_FILE: 'poetry.lock'
-    OUTPUT_FILE: 'sbom.cdx.json'
   script:
-    - /sbomify.sh
+ - sbomify-action
@@ -74,28 +76,33 @@

CI/CD & Generation

- Bitbucket - View Pipe → + {{< icon "bitbucket" "w-8 h-8" >}} Bitbucket + View on GitHub →

- Seamlessly integrate with Bitbucket Pipelines using our official pipe. + Seamlessly integrate with Bitbucket Pipelines using our Docker image with built-in caching.

-
- step:
-    name: Build SBOM
-    script:
-      - pipe: docker://sbomifyhub/sbomify-action:latest
-        variables:
-          TOKEN: $SBOMIFY_TOKEN
-          COMPONENT_ID: "Your Component ID"
-          UPLOAD: "true"
-          AUGMENT: "true"
-          ENRICH: "true"
-          COMPONENT_NAME: "my-python-app"
-          COMPONENT_VERSION: $BITBUCKET_COMMIT
-          LOCK_FILE: "poetry.lock"
-          OUTPUT_FILE: "bitbucket-sbom.cdx.json"
+
pipelines:
+  default:
+    - step:
+        caches:
+          - sbomify
+        script:
+          - pipe: docker://sbomifyhub/sbomify-action:latest
+            variables:
+              SBOMIFY_CACHE_DIR: "${BITBUCKET_CLONE_DIR}/.sbomify-cache/sbomify"
+              TRIVY_CACHE_DIR: "${BITBUCKET_CLONE_DIR}/.sbomify-cache/trivy"
+              SYFT_CACHE_DIR: "${BITBUCKET_CLONE_DIR}/.sbomify-cache/syft"
+              LOCK_FILE: poetry.lock
+              OUTPUT_FILE: sbom.cdx.json
+              UPLOAD: "false"
+              ENRICH: "true"
+
+definitions:
+  caches:
+    sbomify: .sbomify-cache
@@ -103,26 +110,271 @@

CI/CD & Generation

- Docker - Universal Support + {{< icon "docker" "w-8 h-8" >}} Docker + View on Docker Hub →

- For any other CI/CD system, you can use our Docker image directly. + For any other CI/CD system, use our Docker image directly. All generators are pre-installed.

-
docker run --rm \
-  -v $(pwd):/code \
-  -e TOKEN=<my token> \
-  -e COMPONENT_ID=<my component id> \
-  -e LOCK_FILE=/code/requirements.txt \
-  -e OUTPUT_FILE=/code/sbom.cdx.json \
-  -e COMPONENT_NAME=my-app \
+
# Create persistent cache volume
+docker volume create sbomify-cache
+
+docker run --rm \
+  -v $(pwd):/github/workspace \
+  -v sbomify-cache:/cache \
+  -w /github/workspace \
+  -e SBOMIFY_CACHE_DIR=/cache/sbomify \
+  -e TRIVY_CACHE_DIR=/cache/trivy \
+  -e SYFT_CACHE_DIR=/cache/syft \
+  -e LOCK_FILE=/github/workspace/requirements.txt \
+  -e OUTPUT_FILE=/github/workspace/sbom.cdx.json \
+  -e UPLOAD=false \
   -e ENRICH=true \
   sbomifyhub/sbomify-action
+ + +
+
+ {{< icon "python" "w-8 h-8" >}} pip / CLI + View on PyPI → +
+

+ Install via pip for local development or non-Docker environments. Requires external generators (Trivy, Syft, or cdxgen) to be installed separately. +

+
+ +
pip install sbomify-action
+
+# CLI usage
+sbomify-action --lock-file requirements.txt \
+  --enrich --no-upload -o sbom.cdx.json
+
+# Or use environment variables
+export LOCK_FILE=requirements.txt
+export ENRICH=true
+export UPLOAD=false
+sbomify-action
+ +
+
+
+ + + + +
+
+

Supported Ecosystems

+

Generate SBOMs from lockfiles across 14 languages, plus Docker images and Yocto/OpenEmbedded builds.

+
+ +
+
+

{{< icon "python" "w-5 h-5" >}} Python

+
+ requirements.txt + poetry.lock + Pipfile.lock + uv.lock + pyproject.toml +
+
+
+

{{< icon "javascript" "w-5 h-5" >}} JavaScript

+
+ package.json + package-lock.json + yarn.lock + pnpm-lock.yaml + bun.lock +
+
+
+

{{< icon "java" "w-5 h-5" >}} Java

+
+ pom.xml + build.gradle + build.gradle.kts + gradle.lockfile +
+
+
+

{{< icon "golang" "w-5 h-5" >}} Go

+
+ go.mod + go.sum +
+
+
+

{{< icon "rust" "w-5 h-5" >}} Rust

+
+ Cargo.lock +
+
+
+

Ruby

+
+ Gemfile.lock +
+
+
+

{{< icon "php" "w-5 h-5" >}} PHP

+
+ composer.json + composer.lock +
+
+
+

.NET / C#

+
+ packages.lock.json +
+
+
+

{{< icon "swift" "w-5 h-5" >}} Swift

+
+ Package.swift + Package.resolved +
+
+
+

{{< icon "dart" "w-5 h-5" >}} Dart

+
+ pubspec.lock +
+
+
+

Elixir

+
+ mix.lock +
+
+
+

Scala

+
+ build.sbt +
+
+
+

{{< icon "cpp" "w-5 h-5" >}} C++

+
+ conan.lock +
+
+
+

{{< icon "terraform" "w-5 h-5" >}} Terraform

+
+ .terraform.lock.hcl +
+
+
+ +
+
+

Docker Images

+

Generate SBOMs directly from container images using DOCKER_IMAGE instead of a lockfile. Scans all layers and installed packages.

+
+
+

Yocto / OpenEmbedded

+

Batch process SPDX SBOMs from Yocto builds. Extracts .spdx.tar.zst archives, uploads package SBOMs, and tags them with a product release.

+
+
+ +
+ + +
+
+

SBOM Generators

+

Five generators with automatic fallback. The best tool for each ecosystem is selected automatically.

+
+ +
+
+
+

cyclonedx-py

+ Priority 10 +
+

Native Python generator. Most accurate for Python ecosystems.

+
+ Python +
+
+
+
+

cargo-cyclonedx

+ Priority 10 +
+

Native Rust generator. Most accurate for Rust ecosystems.

+
+ Rust +
+
+
+
+

cdxgen

+ Priority 20 +
+

Broadest ecosystem support. Best choice for Java/Gradle and multi-language projects.

+
+ Python + JS + Java + Go + Rust + Ruby + +8 more +
+
+
+
+

Trivy

+ Priority 30 +
+

Security-focused scanner by Aqua Security. Supports CycloneDX and SPDX output.

+
+ Python + JS + Java + Go + Docker + +5 more +
+
+
+
+

Syft

+ Priority 35 +
+

Comprehensive scanner by Anchore. Supports CycloneDX and SPDX output including Terraform.

+
+ Python + JS + Go + Terraform + Docker + +7 more +
+
+
+ + +
+
+

CycloneDX

+

Default format. Versions 1.3 through 1.7 supported depending on generator.

+ SBOM_FORMAT=cyclonedx +
+
+

SPDX

+

Versions 2.2 and 2.3 via Trivy or Syft, plus 3.0 via Yocto/OpenEmbedded. Validated against JSON schemas.

+ SBOM_FORMAT=spdx +
@@ -149,9 +401,15 @@

Google OSV

Dependency Track

Dependency Track

- Leverage the power of OWASP Dependency-Track for continuous component analysis. + Leverage the power of OWASP Dependency-Track for continuous component analysis. Upload SBOMs directly from CI/CD with UPLOAD_DESTINATIONS=dependency-track.

-
+
+
+ CI/CD +

+ Direct Upload: sbomify-action can upload SBOMs directly to your Dependency Track instance from any CI pipeline. +

+
Enterprise

@@ -168,7 +426,7 @@

Dependency Track

Enrichment Data Sources

-

We integrate with 11 data sources to add metadata to your SBOM components: descriptions, licenses, supplier information, and more.

+

We integrate with 12 data sources to add metadata to your SBOM components: descriptions, licenses, supplier information, and more.

@@ -205,7 +463,7 @@

Lifecycle Database

Native Package Registries

Authoritative data direct from the ecosystem's official source.

-
+

PyPI

Python Package Index

@@ -226,6 +484,11 @@

Debian Sources

Debian Package Archive

pkg:deb/debian/*
+
+

Conan Center

+

C/C++ (Conan)

+ pkg:conan/* +
diff --git a/layouts/faq/list.html b/layouts/faq/list.html new file mode 100644 index 0000000..0f6e698 --- /dev/null +++ b/layouts/faq/list.html @@ -0,0 +1,171 @@ +{{ define "main" }} +
+
+ +
+ + +
+

+ {{ .Title }} +

+ {{ with .Params.description }} +

+ {{ . }} +

+ {{ end }} +
+
+ +
+
+ {{ with .Content }} +
+ {{ . }} +
+ {{ end }} + + +
+ + +
+ + + + + +
+ {{ range .Pages.ByWeight }} +
+

+ + {{ .Title }} + + {{ with .Params.plan }} + {{ . }} + {{ end }} +

+ {{ with .Params.answer }} +

{{ . }}

+ {{ end }} + + Read full answer → + +
+ {{ end }} +
+ + + + + +
+

Still have questions?

+

Our team is here to help you get started with SBOMs and supply chain security.

+ +
+
+
+
+ + +{{ end }} diff --git a/layouts/faq/list.json b/layouts/faq/list.json new file mode 100644 index 0000000..191fcbc --- /dev/null +++ b/layouts/faq/list.json @@ -0,0 +1,11 @@ +{{- $entries := slice -}} +{{- range .Pages.ByWeight -}} + {{- $entry := dict + "title" .Title + "answer" .Params.answer + "url" .RelPermalink + "keywords" .Params.keywords + -}} + {{- $entries = $entries | append $entry -}} +{{- end -}} +{{- $entries | jsonify -}} diff --git a/layouts/faq/single.html b/layouts/faq/single.html new file mode 100644 index 0000000..47c428a --- /dev/null +++ b/layouts/faq/single.html @@ -0,0 +1,48 @@ +{{ define "main" }} +
+
+ +
+ + +
+

+ {{ .Title }} +

+ {{ with .Params.plan }} + {{ . }} plan + {{ end }} +
+
+ +
+
+ + + +
+ {{ partial "tldr.html" . }} + {{ .Content }} +
+ + + +
+
+
+{{ end }} diff --git a/layouts/partials/footer.html b/layouts/partials/footer.html index 29b2347..c02982b 100644 --- a/layouts/partials/footer.html +++ b/layouts/partials/footer.html @@ -21,6 +21,7 @@