-
Notifications
You must be signed in to change notification settings - Fork 344
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add announcements section to the website
Signed-off-by: Adam Talbot <[email protected]>
- Loading branch information
1 parent
6726fd3
commit f54a952
Showing
7 changed files
with
338 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
24 changes: 24 additions & 0 deletions
24
content/announcements/2024-03-04-cert-manager-security-audit.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
--- | ||
slug: cert-manager-security-audit | ||
title: cert-manager completes it security audit! | ||
description: As part of our graduation processes cert-manager has completed a security audit of the project | ||
date: 03-04-2024 | ||
--- | ||
|
||
Between late 2023 and early 2024 the cert-manager project has undergone a security audit by the team at [Ada Logics](https://adalogics.com/). This is part of the ongoing [graduation of cert-manager](https://github.com/cncf/toc/pull/1212). | ||
|
||
The goal of the engagement was to assess cert-managers code quality, its development and its release practices. The thread model was determined along with potential threat actors, the codebase was reviewed, dependencies were evaluated and the project was integrated into OSS-Fuzz. | ||
|
||
The threat model of cert-manager is built upon the existing threat model for acquiring certificates from issuers. However, the specific procedures for acquiring certificates as documented by external entities were not scrutinized in this audit. | ||
|
||
Threat actors include contributors to cert-manager or any of its dependencies, users on the clusters where cert-manager is deployed and external users in cases where cert-manager is deployed in use cases that process input from untrusted internet users. | ||
|
||
For a full breakdown of the threat model and actors, see the [full report](TODO). | ||
|
||
A total of 8 issues were raised as part of the audit, of which 5 were low severity, 2 were moderate severity and 1 was informational. All issues have been resolved as of cert-manager 1.12.8, v1.13.4 and 1.14.3. | ||
|
||
Dependencies of the cert-manager project were assessed using [OpenSSF Scorecard](https://github.com/ossf/scorecard). This is a process that scores repositories using several factors to build a picture of their maintenance status and suitability. Based on the results, three dependencies have been removed from cert-manager. The full findings and scoring for dependencies can be found on the [full report](TODO). | ||
|
||
On top of assessing existing dependencies, the cert-manager team have [opened an issue](TODO) to investigate how we can implement a strategy for evaluating new dependencies as they arise. | ||
|
||
Thanks to to team at [Ada Logics](https://adalogics.com/), in particular Adam Korczynski and David Korczynski for completing this audit, it was an all-round pleasant experience with no real hiccups. Also thanks to CNCF who facilitated this audit and are key to the ongoing support of cert-manager. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
export const meta = { | ||
pageTitle: '- cert-manager Announcement', | ||
title: 'cert-manager Announcements', | ||
description: '' | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,152 @@ | ||
import { getRawFile } from 'lib/files' | ||
import { join } from 'path' | ||
import { readdir } from 'fs/promises' | ||
import { VFile } from 'vfile' | ||
import { serialize } from 'next-mdx-remote/serialize' | ||
import matter from 'gray-matter' | ||
import { marked } from 'marked' | ||
import GithubSlugger from 'github-slugger' | ||
import rehypeSlug from 'rehype-slug' | ||
import rehypeAutolink from 'rehype-autolink-headings' | ||
|
||
import { codeImport as remarkCodeImport } from 'remark-code-import' | ||
import remarkInlineLinks from 'remark-inline-links' | ||
import remarkGfm from 'remark-gfm' | ||
import remarkHeadingId from 'lib/remark-plugins/heading-ids' | ||
import remarkExternalLinks from 'remark-external-links' | ||
import remarkRewriteImages from 'lib/remark-plugins/images' | ||
|
||
|
||
export async function getArticles() { | ||
const files = await readdir(join(process.cwd(), 'content', 'announcements')) | ||
const paths = await Promise.all( | ||
files.map(async (file) => { | ||
const rawFileContents = await getRawFile(join('announcements', file)); | ||
const { data } = matter(rawFileContents); | ||
const date = new Date(data.date); | ||
const slug = getSlug(date, data.slug) | ||
|
||
return { | ||
title: data.title, | ||
description: data.description, | ||
date: date, | ||
path: slug.join("/"), | ||
slug: slug, | ||
file: file, | ||
} | ||
} | ||
)) | ||
|
||
paths.sort((a, b) => new Date(b.date) - new Date(a.date)) | ||
|
||
return paths | ||
} | ||
|
||
export async function pageProps({params}) { | ||
const articles = await getArticles() | ||
const article = articles.find((article) => article.path == params.article.join("/")) | ||
if (!article) return { | ||
notFound: true | ||
} | ||
|
||
const path = join('announcements', article.file) | ||
const mdxPathAbsolute = join(process.cwd(), 'content', path) | ||
const mdxRawContent = await getRawFile(path) | ||
const { content, data } = matter(mdxRawContent) | ||
if (!data.title) { | ||
data.title = '' | ||
} | ||
|
||
const slugger = new GithubSlugger() | ||
const mdxSource = await serialize( | ||
new VFile({ | ||
value: content, | ||
path: mdxPathAbsolute | ||
}), | ||
{ | ||
parseFrontmatter: false, | ||
scope: { data }, | ||
mdxOptions: { | ||
mdExtensions: [], | ||
mdxExtensions: ['.md', '.mdx'], | ||
rehypePlugins: [ | ||
rehypeSlug, | ||
[ | ||
rehypeAutolink, | ||
{ | ||
behavior: 'append', | ||
properties: { | ||
className: ['btn-copy-link', 'invisible'] | ||
}, | ||
content: { | ||
type: 'element', | ||
tagName: 'svg', | ||
properties: { | ||
className: ['h-6', 'w-6', 'ml-2', 'docs-copy-btn'], | ||
xmlns: 'http://www.w3.org/2000/svg', | ||
fill: 'none', | ||
viewBox: '0 0 24 24', | ||
stroke: 'currentColor' | ||
}, | ||
children: [ | ||
{ | ||
type: 'element', | ||
tagName: 'path', | ||
properties: { | ||
strokeLinecap: 'round', | ||
strokeLinejoin: 'round', | ||
strokeWidth: 2, | ||
d: 'M13.828 10.172a4 4 0 00-5.656 0l-4 4a4 4 0 105.656 5.656l1.102-1.101m-.758-4.899a4 4 0 005.656 0l4-4a4 4 0 00-5.656-5.656l-1.1 1.1' | ||
}, | ||
children: [] | ||
} | ||
] | ||
} | ||
} | ||
] | ||
], | ||
remarkPlugins: [ | ||
remarkHeadingId, | ||
remarkGfm, | ||
remarkCodeImport, | ||
[ | ||
remarkRewriteImages, | ||
{ destination: process.env.ASSETS_DESTINATION } | ||
], | ||
remarkInlineLinks, | ||
[remarkExternalLinks, { target: false, rel: ['nofollow'] }], | ||
] | ||
}, | ||
target: ['esnext'] | ||
} | ||
) | ||
|
||
const markdownTokens = marked.lexer(content) | ||
const headings = markdownTokens | ||
.filter((t) => t.type === 'heading') | ||
.map((heading) => { | ||
heading.slug = slugger.slug(heading.text) | ||
return heading | ||
}) | ||
|
||
const firstHeadingText = | ||
headings && headings.length > 0 ? headings[0].text : '' | ||
const title = data.title.length > 0 ? data.title : firstHeadingText | ||
|
||
return { | ||
title, | ||
date: article.date.toDateString(), | ||
frontmatter: data, | ||
source: mdxSource, | ||
tocHeadings: headings, | ||
} | ||
} | ||
|
||
function getSlug(date, slug) { | ||
return [ | ||
'' + date.getFullYear(), | ||
('0' + date.getMonth()+1).slice(-2), | ||
('0' + date.getDate()).slice(-2), | ||
slug, | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,144 @@ | ||
// You probably wonder why this file, [...docs].jsx, contains square brackets and | ||
// dots. The reason is that the only way to do "dynamic routes" in Next.js is to | ||
// use a file name containing square brackets and dots. You can learn more at: | ||
// https://nextjs.org/docs/routing/dynamic-routes. | ||
|
||
import { MDXRemote } from 'next-mdx-remote' | ||
import { NextSeo } from 'next-seo' | ||
import { withRouter } from 'next/router' | ||
import { Element } from 'react-scroll' | ||
|
||
import CodeBlock from 'components/docs/CodeBlock.jsx' | ||
import InlineCode from 'components/docs/InlineCode.jsx' | ||
import Toc from 'components/docs/Toc' | ||
|
||
import getCurrentUrl from 'lib/currentUrl' | ||
import theme from 'lib/github.js' | ||
import { getArticles, pageProps } from 'lib/announcements' | ||
|
||
import { meta as page } from 'content/pages/article.mdx' | ||
|
||
const AnnouncementPage = ({ | ||
router, | ||
title, | ||
source, | ||
tocHeadings, | ||
frontmatter, | ||
date, | ||
isIndex, | ||
articles | ||
}) => { | ||
const currentUrl = getCurrentUrl(router) | ||
|
||
if (isIndex) { | ||
return <AnnouncementIndex articles={articles} /> | ||
} | ||
|
||
if (!source) return null | ||
return ( | ||
<> | ||
<NextSeo | ||
title={`${title} ${page.pageTitle}`} | ||
description={page.description} | ||
canonical={currentUrl} | ||
openGraph={{ | ||
url: currentUrl, | ||
title: frontmatter.title, | ||
description: frontmatter.description | ||
}} | ||
/> | ||
<div className="container mt-6 pb-48"> | ||
<div className="w-full md:grid grid-cols-12 gap-12 xl:gap-16"> | ||
<div className="col-span-4 lg:col-span-3 xl:col-span-3 md:border-r border-gray-2/50 pr-5"></div> | ||
<main className="col-span-8 lg:col-span-9 xl:col-span-7 docs"> | ||
<div className="mx-auto md:mx-0 prose max-w-full main-docs-section"> | ||
<h1>{title}</h1> | ||
<i>{date}</i> | ||
<Announcement source={source} theme={theme} /> | ||
</div> | ||
</main> | ||
<div className="hidden xl:block col-span-2 border-l border-gray-2/50 pl-5"> | ||
<Toc contents={tocHeadings} maxHeadingLevel={2} /> | ||
</div> | ||
</div> | ||
</div> | ||
</> | ||
) | ||
} | ||
|
||
function AnnouncementIndex({articles}) { | ||
return ( | ||
<> | ||
<NextSeo | ||
title={page.title} | ||
description={page.description} | ||
canonical={'/announcements'} | ||
openGraph={{ | ||
url: '/announcements', | ||
title: page.title, | ||
description: page.description | ||
}} | ||
/> | ||
<div className="container mt-6 pb-48"> | ||
<div className="w-full md:grid grid-cols-12 gap-12 xl:gap-16"> | ||
<div className="col-span-4 lg:col-span-3 xl:col-span-3 md:border-r border-gray-2/50 pr-5"></div> | ||
<main className="col-span-8 lg:col-span-9 xl:col-span-7 docs"> | ||
<div className="mx-auto md:mx-0 prose max-w-full main-docs-section"> | ||
<h1>Announcements</h1> | ||
{articles.map((article) => ( | ||
<a key={article.path} href={article.path} className="block my-2 !no-underline p-6 bg-white border border-gray-200 rounded-lg shadow-md hover:bg-gray-100 dark:bg-gray-800 dark:border-gray-700 dark:hover:bg-gray-700"> | ||
<h5 className="mb-2 text-2xl font-bold tracking-tight text-gray-900 dark:text-white">{article.title}</h5> | ||
<p className="font-normal text-gray-700 dark:text-gray-400">{article.description}</p> | ||
<p className="font-thin text-gray-700 dark:text-gray-400 italic">{article.date}</p> | ||
</a> | ||
))} | ||
</div> | ||
</main> | ||
<div className="hidden xl:block col-span-2 border-l border-gray-2/50 pl-5"></div> | ||
</div> | ||
</div> | ||
</> | ||
) | ||
} | ||
|
||
export default withRouter(AnnouncementPage) | ||
|
||
function Announcement({ source, theme }) { | ||
const components = { | ||
Element: ({ name, ...props }) => { | ||
return ( | ||
<Element | ||
// remove name from parent div | ||
name={props.children[0]?.props?.id === name ? null : name} | ||
{...props} | ||
/> | ||
) | ||
}, | ||
pre: (props) => <CodeBlock {...props} theme={theme} />, | ||
code: (props) => <InlineCode {...props} theme={theme} /> | ||
} | ||
|
||
return <MDXRemote {...source} components={components} theme={theme} /> | ||
} | ||
|
||
export async function getStaticPaths() { | ||
const articles = await getArticles() | ||
const paths = articles.map((article) => ({params: {article: article.slug}})).concat([{params: {article: []}}]) | ||
return { paths, fallback: false } | ||
} | ||
|
||
export async function getStaticProps(ctx) { | ||
const isIndex = !ctx.params.article | ||
if (isIndex) { | ||
const articles = await getArticles() | ||
return {props: { | ||
isIndex: true, | ||
articles: articles.map(({title, description, path, date}) => ({title, description, path, date: date.toDateString()})) | ||
}} | ||
} | ||
|
||
const props = await pageProps(ctx) | ||
return { props } | ||
} | ||
|
||
|