Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions content/authors/_index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
title: Authors
description: "Meet the authors behind the sbomify blog: practitioners writing about SBOMs, software supply chain security, and compliance."
---
2 changes: 1 addition & 1 deletion content/faq/what-is-an-sbom.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
title: "What is an SBOM?"
title: "What is an SBOM (Software Bill of Materials)?"
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."
Expand Down
1 change: 1 addition & 0 deletions content/features/why-now.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
---

title: The Growing Importance of SBOMs in Cybersecurity Compliance
description: "Why SBOMs matter now: Executive Order 14028, the EU Cyber Resilience Act, PCI DSS 4.0, and the FDA are turning SBOMs into a baseline compliance requirement across industries."
---

The cybersecurity landscape has evolved rapidly in recent years, driven largely by increased awareness of software supply chain vulnerabilities. A significant milestone in this evolution was the US government's introduction of [Executive Order 14028](https://www.federalregister.gov/documents/2021/05/17/2021-10460/improving-the-nations-cybersecurity) in May 2021. This executive order responded directly to escalating cyber threats targeting critical infrastructure, government agencies, and private enterprises. One of its key components mandated Software Bill of Materials (SBOMs) for all vendors selling software to the federal government.
Expand Down
3 changes: 2 additions & 1 deletion content/posts/_index.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
---
title: "sbomify | the SBOM sharing and collaboration platform"
title: "The sbomify Blog"
description: "Articles, guides, and product updates on SBOMs, software supply chain security, and compliance from the sbomify team."
---
1 change: 1 addition & 0 deletions content/what-is-sbom.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
---
url: /what-is-sbom/
title: What is an SBOM?
description: "A Software Bill of Materials (SBOM) is a machine-readable inventory of every component, library, and dependency in your software. Learn what SBOMs are, why regulations require them, and how to get started."
tldr: "A Software Bill of Materials (SBOM) is a machine-readable inventory of every component, library, and dependency in your software. Think of it as an ingredients list for code. SBOMs are increasingly required by regulations like the EU Cyber Resilience Act and US Executive Order 14028, and are essential for vulnerability management, license compliance, and supply chain security."
---

Expand Down
2 changes: 2 additions & 0 deletions layouts/_default/_markup/render-codeblock.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
{{- $result := transform.HighlightCodeBlock . -}}
<figure class="code-block">{{ $result.Wrapped }}</figure>
8 changes: 4 additions & 4 deletions layouts/_default/single.html
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{{ define "main" }}
<div>
<div class="bg-primaryBG relative overflow-hidden px-5 py-16 lg:py-24 lg:px-24">
<header class="bg-primaryBG relative overflow-hidden px-5 py-16 lg:py-24 lg:px-24">
{{ partial "aurora.html" . }}

<div class="relative max-w-4xl mx-auto text-center">
Expand All @@ -13,15 +13,15 @@ <h1 class="text-white text-[40px] lg:text-[68px] leading-[48px] lg:leading-[78px
</p>
{{ end }}
</div>
</div>
</header>

<div class="bg-[#F6F9FA]">
<section class="bg-[#F6F9FA]">
<div class="max-w-4xl mx-auto px-6 lg:px-8 py-16 lg:py-24">
<article class="page bg-white p-8 md:p-12 rounded-2xl shadow-sm border border-gray-100">
{{ partial "tldr.html" . }}
{{ .Content }}
</article>
</div>
</div>
</section>
</div>
{{ end }}
137 changes: 84 additions & 53 deletions layouts/partials/head.html
Original file line number Diff line number Diff line change
@@ -1,22 +1,58 @@
<head>
{{- /* Paginated pages (/blog/page/2/ etc.) need their own canonical URL,
title, and description so they don't count as duplicates of page 1. */ -}}
{{- $paginator := partial "paginator.html" . -}}
{{- $pageSuffix := "" -}}
{{- $canonical := .Permalink -}}
{{- with $paginator -}}
{{- if gt .PageNumber 1 -}}
{{- $pageSuffix = printf " - Page %d of %d" .PageNumber .TotalPages -}}
{{- $canonical = .URL | absURL -}}
{{- end -}}
{{- end -}}
{{- $desc := or .Params.description "" -}}
{{- if not $desc -}}
{{- if eq .Kind "term" -}}
{{- if eq .Data.Plural "categories" -}}
{{- $desc = printf "All sbomify blog posts in the %s category: articles on SBOMs, software supply chain security, and compliance." (.Title | lower) -}}
{{- else -}}
{{- $desc = printf "All sbomify blog posts tagged %s: articles on SBOMs, software supply chain security, and compliance." (.Title | lower) -}}
{{- end -}}
{{- else if eq .Kind "taxonomy" -}}
{{- $desc = printf "Browse the sbomify blog by %s to find articles on SBOMs, software supply chain security, and compliance." (.Title | lower) -}}
{{- else -}}
{{- $desc = site.Params.description -}}
{{- end -}}
{{- end -}}
{{- $desc = printf "%s%s" $desc $pageSuffix -}}
{{- /* Distinguish term page titles from same-named content pages
(e.g. /tags/integrations/ vs /features/integrations/). */ -}}
{{- $title := .Title -}}
{{- if eq .Kind "term" -}}
{{- if eq .Data.Plural "categories" -}}
{{- $title = printf "%s Category" .Title -}}
{{- else -}}
{{- $title = printf "%s Articles" .Title -}}
{{- end -}}
{{- end -}}
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ if eq .RelPermalink "/" }}{{ .Title | default site.Title }}{{ else }}{{ .Title }} | {{ site.Title }}{{ end }}</title>
<meta name="description" content="{{ .Params.description | default site.Params.description }}">
<title>{{ if eq .RelPermalink "/" }}{{ $title | default site.Title }}{{ else }}{{ $title }}{{ $pageSuffix }} | {{ site.Title }}{{ end }}</title>
<meta name="description" content="{{ $desc }}">
<meta name="keywords" content="{{ with .Params.keywords }}{{ delimit . ", " }}{{ else }}{{ delimit site.Params.keywords ", " }}{{ end }}">

<!-- Canonical URL -->
<link rel="canonical" href="{{ .Permalink }}">
<link rel="canonical" href="{{ $canonical }}">

<!-- Robots meta -->
<meta name="robots" content="index, follow">
<meta name="googlebot" content="index, follow">

<!-- Open Graph Meta Tags -->
<meta property="og:title" content="{{ .Title | default site.Title }}">
<meta property="og:description" content="{{ .Params.description | default site.Params.description }}">
<meta property="og:title" content="{{ $title | default site.Title }}{{ $pageSuffix }}">
<meta property="og:description" content="{{ $desc }}">
<meta property="og:type" content="{{ if eq .Type "posts" }}article{{ else }}website{{ end }}">
<meta property="og:url" content="{{ .Permalink }}">
<meta property="og:url" content="{{ $canonical }}">
{{- $ogImage := .Params.image | default site.Params.social.image -}}
<meta property="og:image" content="{{ $ogImage | absURL }}">
<meta property="og:image:width" content="1200">
Expand All @@ -38,8 +74,8 @@

<!-- Twitter Card Meta Tags -->
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="{{ .Title | default site.Title }}">
<meta name="twitter:description" content="{{ .Params.description | default site.Params.description }}">
<meta name="twitter:title" content="{{ $title | default site.Title }}{{ $pageSuffix }}">
<meta name="twitter:description" content="{{ $desc }}">
<meta name="twitter:image" content="{{ $ogImage | absURL }}">
<meta name="twitter:image:alt" content="{{ .Title | default site.Title }}">
{{- $twitterHandle := "" -}}
Expand All @@ -51,8 +87,8 @@

<!-- LinkedIn Card Meta Tags -->
<meta property="linkedin:card" content="summary_large_image">
<meta property="linkedin:title" content="{{ .Title | default site.Title }}">
<meta property="linkedin:description" content="{{ .Params.description | default site.Params.description }}">
<meta property="linkedin:title" content="{{ $title | default site.Title }}{{ $pageSuffix }}">
<meta property="linkedin:description" content="{{ $desc }}">
<meta property="linkedin:image" content="{{ $ogImage | absURL }}">
<meta property="linkedin:author" content="{{ $linkedinUrl }}">

Expand Down Expand Up @@ -88,27 +124,36 @@
"sameAs": [
{{ range $i, $p := site.Params.social.profiles }}{{ if $i }},{{ end }}"{{ $p.url }}"{{ end }}
],
"description": {{ site.Params.description | jsonify }}
"description": {{ site.Params.description | jsonify | safeJS }}
}
</script>

<!-- Schema.org structured data: SoftwareApplication -->
{{ if .IsHome }}
<!-- Schema.org structured data: Product (Google requires aggregateRating or
review on SoftwareApplication; Product validates with offers alone) -->
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "SoftwareApplication",
"@type": "Product",
"additionalType": "https://schema.org/SoftwareApplication",
"name": "sbomify",
"applicationCategory": "BusinessApplication",
"applicationSubCategory": "Supply Chain Security",
"operatingSystem": "Cloud",
"description": {{ site.Params.description | jsonify | safeJS }},
"url": "{{ site.BaseURL }}",
"image": "{{ site.BaseURL }}android-chrome-512x512.png",
"brand": {
"@type": "Organization",
"name": "sbomify"
},
"category": "Supply Chain Security Software",
"offers": [
{
"@type": "Offer",
"name": "Community",
"price": "0",
"priceCurrency": "USD",
"description": "For OSS maintainers and hobby projects",
"availability": "https://schema.org/InStock"
"availability": "https://schema.org/InStock",
"url": "{{ site.BaseURL }}pricing/"
},
{
"@type": "Offer",
Expand All @@ -117,27 +162,13 @@
"priceCurrency": "USD",
"description": "For mid-size teams needing private SBOMs",
"availability": "https://schema.org/InStock",
"priceValidUntil": "{{ now.AddDate 0 1 0 | time.Format "2006-01-02" }}"
},
{
"@type": "Offer",
"name": "Enterprise",
"description": "For large orgs with advanced security & compliance needs. Contact for pricing.",
"availability": "https://schema.org/InStock"
"priceValidUntil": "{{ now.AddDate 0 1 0 | time.Format "2006-01-02" }}",
"url": "{{ site.BaseURL }}pricing/"
}
],
"description": {{ site.Params.description | jsonify }},
"url": "{{ site.BaseURL }}",
"featureList": [
"SBOM Generation",
"SBOM Management",
"Supply Chain Security",
"Compliance Management",
"Vulnerability Tracking"
],
"softwareVersion": "1.0"
]
}
</script>
{{ end }}

{{ if eq .Type "posts" }}
<!-- Schema.org structured data: BlogPosting / TechArticle -->
Expand All @@ -156,8 +187,8 @@
"@type": "WebPage",
"@id": "{{ .Permalink }}"
},
"headline": {{ .Title | jsonify }},
"description": {{ (.Params.description | default site.Params.description) | jsonify }},
"headline": {{ .Title | jsonify | safeJS }},
"description": {{ (.Params.description | default site.Params.description) | jsonify | safeJS }},
"image": "{{ $ogImage | absURL }}",
"author": {
"@type": "Person",
Expand Down Expand Up @@ -210,7 +241,7 @@
{
"@type": "ListItem",
"position": 3,
"name": {{ .Title | jsonify }},
"name": {{ .Title | jsonify | safeJS }},
"item": "{{ .Permalink }}"
}
]
Expand All @@ -224,8 +255,8 @@
{
"@context": "https://schema.org",
"@type": "Article",
"headline": {{ .Title | jsonify }},
"description": {{ (.Params.description | default site.Params.description) | jsonify }},
"headline": {{ .Title | jsonify | safeJS }},
"description": {{ (.Params.description | default site.Params.description) | jsonify | safeJS }},
"image": "{{ (.Params.logo | default site.Params.social.image) | absURL }}",
"publisher": {
"@type": "Organization",
Expand Down Expand Up @@ -265,7 +296,7 @@
{
"@type": "ListItem",
"position": 3,
"name": {{ .Title | jsonify }},
"name": {{ .Title | jsonify | safeJS }},
"item": "{{ .Permalink }}"
}
]
Expand All @@ -283,10 +314,10 @@
{{ range $i, $qa := .Params.faq }}
{{ if $i }},{{ end }}{
"@type": "Question",
"name": {{ $qa.question | jsonify }},
"name": {{ $qa.question | jsonify | safeJS }},
"acceptedAnswer": {
"@type": "Answer",
"text": {{ $qa.answer | jsonify }}
"text": {{ $qa.answer | jsonify | safeJS }}
}
}
{{ end }}
Expand All @@ -311,8 +342,8 @@
{
"@context": "https://schema.org",
"@type": "TechArticle",
"name": {{ .Title | jsonify }},
"description": {{ (.Params.description | default site.Params.description) | jsonify }},
"name": {{ .Title | jsonify | safeJS }},
"description": {{ (.Params.description | default site.Params.description) | jsonify | safeJS }},
"image": "{{ $ogImage | absURL }}",
"proficiencyLevel": "Beginner",
"inLanguage": "en-US"
Expand Down Expand Up @@ -411,10 +442,10 @@
{{ range $i, $faq := .Pages.ByWeight }}
{{ if $i }},{{ end }}{
"@type": "Question",
"name": {{ $faq.Title | jsonify }},
"name": {{ $faq.Title | jsonify | safeJS }},
"acceptedAnswer": {
"@type": "Answer",
"text": {{ $faq.Params.answer | jsonify }}
"text": {{ $faq.Params.answer | jsonify | safeJS }}
}
}
{{ end }}
Expand All @@ -438,7 +469,7 @@
"@type": "ListItem",
"position": {{ add $i 1 }},
"url": "{{ $faq.Permalink }}",
"name": {{ $faq.Title | jsonify }}
"name": {{ $faq.Title | jsonify | safeJS }}
}
{{ end }}
]
Expand Down Expand Up @@ -478,10 +509,10 @@
"mainEntity": [
{
"@type": "Question",
"name": {{ .Title | jsonify }},
"name": {{ .Title | jsonify | safeJS }},
"acceptedAnswer": {
"@type": "Answer",
"text": {{ .Params.answer | jsonify }}
"text": {{ .Params.answer | jsonify | safeJS }}
}
}
]
Expand All @@ -493,8 +524,8 @@
{
"@context": "https://schema.org",
"@type": "WebPage",
"name": {{ .Title | jsonify }},
"description": {{ (.Params.description | default site.Params.description) | jsonify }},
"name": {{ .Title | jsonify | safeJS }},
"description": {{ (.Params.description | default site.Params.description) | jsonify | safeJS }},
"url": "{{ .Permalink }}",
"dateModified": "{{ .Lastmod.Format "2006-01-02T15:04:05Z07:00" }}",
"isPartOf": {
Expand Down Expand Up @@ -534,7 +565,7 @@
{
"@type": "ListItem",
"position": 3,
"name": {{ .Title | jsonify }},
"name": {{ .Title | jsonify | safeJS }},
"item": "{{ .Permalink }}"
}
]
Expand Down
4 changes: 2 additions & 2 deletions layouts/partials/pagination.html
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{{ $paginator := .Paginator }}

<div class="flex justify-center items-center gap-4">
<nav class="flex justify-center items-center gap-4" aria-label="Pagination">
{{ if $paginator.HasPrev }}
<a href="{{ $paginator.Prev.URL }}" class="px-8 py-3 bg-white border border-gray-200 hover:border-[#8A7DFF] text-primaryText hover:text-[#8A7DFF] rounded-full font-medium transition-all duration-200">&larr; Previous</a>
{{ else }}
Expand All @@ -14,4 +14,4 @@
{{ else }}
<span class="px-8 py-3 bg-gray-100 border border-gray-200 text-gray-400 rounded-full font-medium cursor-not-allowed">Next &rarr;</span>
{{ end }}
</div>
</nav>
15 changes: 15 additions & 0 deletions layouts/partials/paginator.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{{- /* Returns the page's paginator for paginated list pages, or "" otherwise.
Mirrors the .Paginate calls in posts.html (via posts/list.html and
authors/list.html) and term.html: Hugo errors if .Paginate is invoked
with different arguments for the same page, so keep these in sync. */ -}}
{{- $paginator := "" -}}
{{- if eq .Kind "term" -}}
{{- $paginator = .Paginate .Pages -}}
{{- else if and (eq .Kind "section") (eq .Section "posts") -}}
{{- $paginator = .Paginate (where site.RegularPages "Section" "posts") -}}
{{- else if and (eq .Kind "section") .Params.author_key -}}
{{- with index site.Data.authors .Params.author_key -}}
{{- $paginator = $.Paginate (where (where site.RegularPages "Section" "posts") ".Params.author.display_name" .display_name) -}}
{{- end -}}
{{- end -}}
{{- return $paginator -}}
4 changes: 2 additions & 2 deletions layouts/partials/tldr.html
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{{ if .Params.tldr }}
<div class="tldr">
<aside class="tldr">
<span class="tldr-label">TL;DR</span>
<p>{{ .Params.tldr }}</p>
</div>
</aside>
{{ end }}
Loading
Loading