Skip to content

Commit 7e55ad2

Browse files
committed
feat: consolidate marketing site into docs site at netchecks.io
Merge the marketing landing page into the docs site so netchecks.io serves a single unified site. This eliminates the separate stale netchecks.io Next.js marketing site. - Add marketing components: MarketingHero, Features, Pricing, Footer - Convert index.md to index.jsx with getLayout opt-out for docs chrome - Move getting-started content to /docs/getting-started - Add /docs/compliance page with framework info and Stripe link - Update _app.jsx to support per-page getLayout pattern - Update navigation sidebar with new routes - Flesh out development.md and testing.md with actual workflows - Update all docs.netchecks.io references to netchecks.io
1 parent d3bc1cc commit 7e55ad2

18 files changed

Lines changed: 533 additions & 53 deletions

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
![PyPI - Python Version](https://img.shields.io/pypi/pyversions/netcheck?style=flat-square&logo=python)
1919
[![Coverage Status](https://img.shields.io/coverallsCoverage/github/hardbyte/netchecks?branch=main&style=flat-square&logo=coveralls)](https://coveralls.io/github/hardbyte/netcheck?branch=main)
2020
[![CI status](https://img.shields.io/github/actions/workflow/status/hardbyte/netchecks/ci.yaml?branch=main&style=flat-square&logo=github)](https://github.com/hardbyte/netchecks/actions?query=branch%3Amain)
21-
[![Website](https://img.shields.io/website?url=https%3A%2F%2Fdocs.netchecks.io%2F&style=flat-square&label=docs.netchecks.io)](https://docs.netchecks.io/)
21+
[![Website](https://img.shields.io/website?url=https%3A%2F%2Fnetchecks.io%2F&style=flat-square&label=netchecks.io)](https://netchecks.io/)
2222
[![Linting: ruff](https://img.shields.io/badge/linting-ruff-261230.svg?style=flat-square)](https://github.com/astral-sh/ruff)
2323
[![PyPI Downloads](https://static.pepy.tech/badge/netcheck)](https://pypi.org/project/netcheck?style=flat-square)
2424
[![License](https://img.shields.io/github/license/hardbyte/netchecks?style=flat-square)](/LICENSE)
@@ -28,7 +28,7 @@
2828
**Netchecks** is a set of tools for testing network conditions and asserting that they are as expected.
2929

3030
There are two main components:
31-
- **Netchecks Operator** - Kubernetes Operator (Rust/kube-rs) that runs network checks and reports results as `PolicyReport` resources. See the [operator README](https://github.com/hardbyte/netchecks/blob/main/operator/README.md) for more details and the full documentation can be found at [https://docs.netchecks.io](https://docs.netchecks.io)
31+
- **Netchecks Operator** - Kubernetes Operator (Rust/kube-rs) that runs network checks and reports results as `PolicyReport` resources. See the [operator README](https://github.com/hardbyte/netchecks/blob/main/operator/README.md) for more details and the full documentation can be found at [https://netchecks.io](https://netchecks.io)
3232
- **Netcheck CLI and Python Library** - Command line tool for running network checks and asserting that they are as expected. Keep reading for the quickstart guide.
3333

3434

docs/src/components/Container.jsx

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import clsx from 'clsx'
2+
3+
export function Container({ className, ...props }) {
4+
return (
5+
<div
6+
className={clsx('mx-auto max-w-7xl px-4 sm:px-6 lg:px-8', className)}
7+
{...props}
8+
/>
9+
)
10+
}

docs/src/components/Features.jsx

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
import { Container } from '@/components/Container'
2+
3+
const features = [
4+
{
5+
title: 'Proactive Monitoring',
6+
description:
7+
'Periodically probe the network to detect when security assumptions are violated. Continuous validation of live workload environments increases confidence in security controls.',
8+
icon: ShieldIcon,
9+
},
10+
{
11+
title: 'Cloud Native',
12+
description:
13+
'A Kubernetes operator configured by custom resources. Outputs use PolicyReports — an emerging standard used by Kyverno and other security tools.',
14+
icon: CloudIcon,
15+
},
16+
{
17+
title: 'Alerting and Reporting',
18+
description:
19+
'Outputs PolicyReports with Prometheus metrics. Integrate with Grafana, Slack, Discord, email, or MS Teams using Policy Reporter.',
20+
icon: BellIcon,
21+
},
22+
{
23+
title: 'Independent from Controls',
24+
description:
25+
'Verifies whether your cluster can carry out network activity, independent of how controls are implemented — NetworkPolicies, Cilium, or external firewalls.',
26+
icon: LockIcon,
27+
},
28+
]
29+
30+
function ShieldIcon(props) {
31+
return (
32+
<svg viewBox="0 0 24 24" fill="none" strokeWidth={1.5} stroke="currentColor" {...props}>
33+
<path strokeLinecap="round" strokeLinejoin="round" d="M9 12.75 11.25 15 15 9.75m-3-7.036A11.959 11.959 0 0 1 3.598 6 11.99 11.99 0 0 0 3 9.749c0 5.592 3.824 10.29 9 11.623 5.176-1.332 9-6.03 9-11.622 0-1.31-.21-2.571-.598-3.751h-.152c-3.196 0-6.1-1.248-8.25-3.285Z" />
34+
</svg>
35+
)
36+
}
37+
38+
function CloudIcon(props) {
39+
return (
40+
<svg viewBox="0 0 24 24" fill="none" strokeWidth={1.5} stroke="currentColor" {...props}>
41+
<path strokeLinecap="round" strokeLinejoin="round" d="M2.25 15a4.5 4.5 0 0 0 4.5 4.5H18a3.75 3.75 0 0 0 1.332-7.257 3 3 0 0 0-3.758-3.848 5.25 5.25 0 0 0-10.233 2.33A4.502 4.502 0 0 0 2.25 15Z" />
42+
</svg>
43+
)
44+
}
45+
46+
function BellIcon(props) {
47+
return (
48+
<svg viewBox="0 0 24 24" fill="none" strokeWidth={1.5} stroke="currentColor" {...props}>
49+
<path strokeLinecap="round" strokeLinejoin="round" d="M14.857 17.082a23.848 23.848 0 0 0 5.454-1.31A8.967 8.967 0 0 1 18 9.75V9A6 6 0 0 0 6 9v.75a8.967 8.967 0 0 1-2.312 6.022c1.733.64 3.56 1.085 5.455 1.31m5.714 0a24.255 24.255 0 0 1-5.714 0m5.714 0a3 3 0 1 1-5.714 0" />
50+
</svg>
51+
)
52+
}
53+
54+
function LockIcon(props) {
55+
return (
56+
<svg viewBox="0 0 24 24" fill="none" strokeWidth={1.5} stroke="currentColor" {...props}>
57+
<path strokeLinecap="round" strokeLinejoin="round" d="M16.5 10.5V6.75a4.5 4.5 0 1 0-9 0v3.75m-.75 11.25h10.5a2.25 2.25 0 0 0 2.25-2.25v-6.75a2.25 2.25 0 0 0-2.25-2.25H6.75a2.25 2.25 0 0 0-2.25 2.25v6.75a2.25 2.25 0 0 0 2.25 2.25Z" />
58+
</svg>
59+
)
60+
}
61+
62+
export function Features() {
63+
return (
64+
<section id="features" className="bg-slate-50 py-20 dark:bg-slate-800/50 sm:py-28">
65+
<Container>
66+
<div className="text-center">
67+
<h2 className="font-display text-3xl tracking-tight text-slate-900 dark:text-white sm:text-4xl">
68+
Concerned your security controls could be weakened?
69+
</h2>
70+
<p className="mt-4 text-lg text-slate-600 dark:text-slate-400">
71+
Actively test your cloud infrastructure with automated, declarative
72+
network assertions.
73+
</p>
74+
</div>
75+
<div className="mt-16 grid grid-cols-1 gap-8 sm:grid-cols-2 lg:grid-cols-4">
76+
{features.map((feature) => (
77+
<div
78+
key={feature.title}
79+
className="rounded-2xl border border-slate-200 bg-white p-8 dark:border-slate-700 dark:bg-slate-800"
80+
>
81+
<feature.icon className="h-8 w-8 text-sky-500" />
82+
<h3 className="mt-4 font-display text-lg font-medium text-slate-900 dark:text-white">
83+
{feature.title}
84+
</h3>
85+
<p className="mt-2 text-sm text-slate-600 dark:text-slate-400">
86+
{feature.description}
87+
</p>
88+
</div>
89+
))}
90+
</div>
91+
</Container>
92+
</section>
93+
)
94+
}

docs/src/components/Footer.jsx

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import Link from 'next/link'
2+
import { Container } from '@/components/Container'
3+
import { Logomark } from '@/components/Logo'
4+
5+
export function Footer() {
6+
return (
7+
<footer className="border-t border-slate-200 bg-white py-12 dark:border-slate-800 dark:bg-slate-900">
8+
<Container>
9+
<div className="flex flex-col items-center justify-between gap-6 sm:flex-row">
10+
<div className="flex items-center gap-3">
11+
<Logomark className="h-7 w-7" />
12+
<span className="text-sm text-slate-600 dark:text-slate-400">
13+
Netchecks
14+
</span>
15+
</div>
16+
<nav className="flex gap-6 text-sm text-slate-600 dark:text-slate-400">
17+
<Link href="/docs/getting-started" className="hover:text-slate-900 dark:hover:text-white">
18+
Docs
19+
</Link>
20+
<Link href="/docs/compliance" className="hover:text-slate-900 dark:hover:text-white">
21+
Compliance
22+
</Link>
23+
<Link href="https://github.com/hardbyte/netchecks" className="hover:text-slate-900 dark:hover:text-white">
24+
GitHub
25+
</Link>
26+
</nav>
27+
<p className="text-sm text-slate-500 dark:text-slate-500">
28+
&copy; {new Date().getFullYear()} Netchecks
29+
</p>
30+
</div>
31+
</Container>
32+
</footer>
33+
)
34+
}

docs/src/components/Layout.jsx

Lines changed: 4 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import Link from 'next/link'
33
import {useRouter} from 'next/router'
44
import clsx from 'clsx'
55

6-
import {Hero} from '@/components/Hero'
76
import {Logo, Logomark} from '@/components/Logo'
87
import {MobileNavigation} from '@/components/MobileNavigation'
98
import {Navigation} from '@/components/Navigation'
@@ -15,7 +14,7 @@ const navigation = [
1514
{
1615
title: 'Introduction',
1716
links: [
18-
{title: 'Getting started', href: '/'},
17+
{title: 'Getting started', href: '/docs/getting-started'},
1918
{title: 'Validating HTTP Controls', href: '/docs/http'},
2019
{title: 'Validating DNS Controls', href: '/docs/dns'},
2120
{title: 'Validating TCP Connectivity', href: '/docs/tcp'},
@@ -26,24 +25,17 @@ const navigation = [
2625
title: 'User Guide',
2726
links: [
2827
{title: 'Installation', href: '/docs/installation'},
29-
3028
{title: 'Custom Validation Rules', href: '/docs/custom-validation-rules'},
3129
{title: 'External Data', href: '/docs/external-data'},
3230
{title: 'Alerting', href: '/docs/alerting'},
31+
{title: 'Compliance', href: '/docs/compliance'},
3332
],
3433
},
35-
// {
36-
// title: 'Examples',
37-
// links: [
38-
//
39-
// ],
40-
// },
41-
4234
{
4335
title: 'Contributor Guide',
4436
links: [
4537
{title: 'How to contribute', href: '/docs/how-to-contribute'},
46-
{title: 'Development', href: '/docs/development',},
38+
{title: 'Development', href: '/docs/development'},
4739
{title: 'Architecture guide', href: '/docs/architecture-guide'},
4840
{title: 'Testing', href: '/docs/testing'},
4941
{title: 'Design principles', href: '/docs/design-principles'},
@@ -55,13 +47,9 @@ const navigation = [
5547
{
5648
title: 'Reference',
5749
links: [
58-
{title: 'Core concepts', href: '/docs/core-concepts'}
59-
// { title: 'http', href: '/docs/http' },
60-
// { title: 'dns', href: '/docs/dns' },
61-
// { title: 'ping', href: '/docs/ping' },
50+
{title: 'Core concepts', href: '/docs/core-concepts'},
6251
],
6352
},
64-
6553
]
6654

6755
function GitHubIcon(props) {
@@ -167,7 +155,6 @@ function useTableOfContents(tableOfContents) {
167155

168156
export function Layout({children, title, tableOfContents}) {
169157
let router = useRouter()
170-
let isHomePage = router.pathname === '/'
171158
let allLinks = navigation.flatMap((section) => section.links)
172159
let linkIndex = allLinks.findIndex((link) => link.href === router.pathname)
173160
let previousPage = allLinks[linkIndex - 1]
@@ -191,8 +178,6 @@ export function Layout({children, title, tableOfContents}) {
191178
<>
192179
<Header navigation={navigation}/>
193180

194-
{isHomePage && <Hero/>}
195-
196181
<div className="relative mx-auto flex max-w-8xl justify-center sm:px-2 lg:px-8 xl:px-12">
197182
<div className="hidden lg:relative lg:block lg:flex-none">
198183
<div className="absolute inset-y-0 right-0 w-[50vw] bg-slate-50 dark:hidden"/>
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import { Button } from '@/components/Button'
2+
import { HeroBackground } from '@/components/HeroBackground'
3+
import { Container } from '@/components/Container'
4+
5+
export function MarketingHero() {
6+
return (
7+
<div className="overflow-hidden bg-slate-900">
8+
<div className="py-20 sm:px-2 lg:relative lg:py-28 lg:px-0">
9+
<div className="mx-auto max-w-2xl items-center px-4 lg:max-w-8xl lg:px-8 xl:px-12">
10+
<div className="relative z-10 text-center">
11+
<div className="absolute inset-0 -z-10 flex justify-center">
12+
<HeroBackground className="opacity-30 w-full max-w-3xl" />
13+
</div>
14+
<div className="relative">
15+
<h1 className="inline bg-gradient-to-r from-indigo-200 via-sky-400 to-indigo-200 bg-clip-text font-display text-5xl tracking-tight text-transparent sm:text-7xl">
16+
Verify your security controls are working
17+
</h1>
18+
<p className="mx-auto mt-6 max-w-2xl text-lg tracking-tight text-slate-400">
19+
Netchecks proactively tests your Kubernetes network policies and
20+
security controls. Cloud native, policy as code, no assumptions
21+
about your implementation.
22+
</p>
23+
<div className="mt-10 flex justify-center gap-4">
24+
<Button href="/docs/getting-started">Get started</Button>
25+
<Button
26+
href="https://github.com/hardbyte/netchecks"
27+
variant="secondary"
28+
>
29+
View on GitHub
30+
</Button>
31+
</div>
32+
</div>
33+
</div>
34+
</div>
35+
</div>
36+
</div>
37+
)
38+
}

docs/src/components/Pricing.jsx

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
import { Container } from '@/components/Container'
2+
import { Button } from '@/components/Button'
3+
4+
function CheckIcon(props) {
5+
return (
6+
<svg viewBox="0 0 24 24" fill="none" {...props}>
7+
<path
8+
d="M9.307 12.248a.75.75 0 1 0-1.114 1.004l1.114-1.004ZM11 15.25l-.557.502a.75.75 0 0 0 1.15-.043L11 15.25Zm4.844-5.041a.75.75 0 0 0-1.188-.918l1.188.918Zm-7.651 3.043 2.25 2.5 1.114-1.004-2.25-2.5-1.114 1.004Zm3.4 2.457 4.25-5.5-1.187-.918-4.25 5.5 1.188.918Z"
9+
fill="currentColor"
10+
/>
11+
<circle
12+
cx="12"
13+
cy="12"
14+
r="8.25"
15+
stroke="currentColor"
16+
strokeWidth="1.5"
17+
strokeLinecap="round"
18+
strokeLinejoin="round"
19+
/>
20+
</svg>
21+
)
22+
}
23+
24+
const plans = [
25+
{
26+
name: 'Open Source',
27+
price: 'Free',
28+
description:
29+
'For security professionals, small businesses, students, hobbyists, and open source projects.',
30+
href: '/docs/getting-started',
31+
cta: 'Get started',
32+
featured: true,
33+
features: [
34+
'Unlimited operator installs',
35+
'Unlimited NetworkAssertions',
36+
'HTTP, DNS, and TCP probes',
37+
'PolicyReports & Prometheus metrics',
38+
'Community support via GitHub',
39+
],
40+
},
41+
{
42+
name: 'Compliance Pro',
43+
price: 'Contact us',
44+
description:
45+
'Automated compliance reporting for regulated environments.',
46+
href: 'https://buy.stripe.com/cN25or9rA8Ur6xa4gi',
47+
cta: 'Get Compliance Pro',
48+
featured: false,
49+
features: [
50+
'Everything in Open Source',
51+
'CIS Kubernetes Benchmark checks',
52+
'PCI-DSS v4 network controls',
53+
'SOC 2 network monitoring evidence',
54+
'Exportable compliance reports',
55+
'Priority support',
56+
],
57+
},
58+
]
59+
60+
export function Pricing() {
61+
return (
62+
<section id="pricing" className="bg-slate-900 py-20 sm:py-28">
63+
<Container>
64+
<div className="text-center">
65+
<h2 className="font-display text-3xl tracking-tight text-white sm:text-4xl">
66+
Simple pricing, for everyone
67+
</h2>
68+
<p className="mt-4 text-lg text-slate-400">
69+
Open source at its core. Compliance features when you need them.
70+
</p>
71+
</div>
72+
<div className="mx-auto mt-16 grid max-w-4xl grid-cols-1 gap-8 lg:grid-cols-2">
73+
{plans.map((plan) => (
74+
<div
75+
key={plan.name}
76+
className={`rounded-3xl px-6 py-8 sm:px-8 ${
77+
plan.featured
78+
? 'bg-sky-500 ring-1 ring-sky-500'
79+
: 'ring-1 ring-slate-700'
80+
}`}
81+
>
82+
<h3 className="font-display text-2xl text-white">
83+
{plan.name}
84+
</h3>
85+
<p
86+
className={`mt-2 text-sm ${
87+
plan.featured ? 'text-sky-100' : 'text-slate-400'
88+
}`}
89+
>
90+
{plan.description}
91+
</p>
92+
<p className="mt-6 font-display text-4xl font-light tracking-tight text-white">
93+
{plan.price}
94+
</p>
95+
<ul className="mt-8 space-y-3 text-sm text-white">
96+
{plan.features.map((feature) => (
97+
<li key={feature} className="flex">
98+
<CheckIcon
99+
className={`h-6 w-6 flex-none ${
100+
plan.featured ? 'text-white' : 'text-slate-400'
101+
}`}
102+
/>
103+
<span className="ml-3">{feature}</span>
104+
</li>
105+
))}
106+
</ul>
107+
<Button
108+
href={plan.href}
109+
variant={plan.featured ? 'primary' : 'secondary'}
110+
className="mt-8 w-full justify-center"
111+
>
112+
{plan.cta}
113+
</Button>
114+
</div>
115+
))}
116+
</div>
117+
</Container>
118+
</section>
119+
)
120+
}

0 commit comments

Comments
 (0)