docs(nx-dev): add enterprise security page (#30852)

Introduce a new enterprise security page highlighting key features like cache poisoning protection, CI access, and personal access control.
This commit is contained in:
Benjamin Cabanes 2025-04-25 15:22:02 -04:00 committed by GitHub
parent 73da211694
commit 3b0c456bbe
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
17 changed files with 1089 additions and 71 deletions

View File

@ -1,6 +1,7 @@
import {
AgentNumberOverTime,
AutomatedAgentsManagement,
EnhancedSecurity,
EnhancedWithAi,
FasterAndCheaper,
Hero,
@ -61,6 +62,9 @@ export default function NxCloudPage(): ReactElement {
<div className="mt-32 lg:mt-56">
<FasterAndCheaper />
</div>
<div className="mt-32 lg:mt-56">
<EnhancedSecurity />
</div>
<div className="mt-32 lg:mt-56">
<UnderstandWorkspace />
</div>

View File

@ -0,0 +1,86 @@
import { useRouter } from 'next/router';
import { NextSeo } from 'next-seo';
import {
ButtonLinkProps,
DefaultLayout,
Footer,
Header,
} from '@nx/nx-dev/ui-common';
import {
BuiltForEnterprise,
CachePoisoningProtection,
CiAccess,
FailingCompliance,
PersonalAccess,
SecurityCallToAction,
SecurityHero,
WhyCiSecurityMatters,
} from '@nx/nx-dev/ui-enterprise';
import { type ReactElement } from 'react';
export function EnterpriseSecurity(): ReactElement {
const router = useRouter();
const headerCTAConfig: ButtonLinkProps[] = [
{
href: '/contact',
variant: 'secondary',
size: 'small',
title: 'Contact us',
children: 'Contact us',
},
];
return (
<>
<NextSeo
title="Enterprise-Grade Security, Built Into the Core"
description="Protect your codebase from artifact poisoning with infrastructure-first security."
canonical="https://nx.dev/enterprise/security"
openGraph={{
url: 'https://nx.dev' + router.asPath,
title: 'Enterprise-Grade Security, Built Into the Core',
description:
'Protect your codebase from artifact poisoning with infrastructure-first security.',
images: [
{
url: 'https://nx.dev/socials/nx-media.png',
width: 800,
height: 421,
alt: 'Nx: Smart Monorepos · Fast CI',
type: 'image/jpeg',
},
],
siteName: 'Nx',
type: 'website',
}}
/>
<DefaultLayout headerCTAConfig={headerCTAConfig}>
<SecurityHero />
<div className="mt-32 scroll-mt-32 lg:mt-56">
<WhyCiSecurityMatters />
</div>
<div className="mt-32 scroll-mt-32 lg:mt-56">
<FailingCompliance />
</div>
<div className="mt-32 scroll-mt-32 lg:mt-56">
<CachePoisoningProtection />
</div>
<div className="mt-32 scroll-mt-32 lg:mt-56">
<PersonalAccess />
</div>
<div className="mt-32 scroll-mt-32 lg:mt-56">
<CiAccess />
</div>
<div className="mt-32 scroll-mt-32 lg:mt-56">
<BuiltForEnterprise />
</div>
<div className="mt-32 scroll-mt-32 lg:mt-56">
<SecurityCallToAction />
</div>
</DefaultLayout>
</>
);
}
export default EnterpriseSecurity;

View File

@ -4,6 +4,7 @@ export * from './lib/trusted-by';
export * from './lib/faster-and-cheaper';
export * from './lib/understand-workspace';
export * from './lib/enhance-with-ai';
export * from './lib/enhanced-security';
export * from './lib/automated-agents-management';
export * from './lib/agent-number-over-time';
export * from './lib/statistics';

View File

@ -0,0 +1,92 @@
import {
CloudArrowDownIcon,
CodeBracketIcon,
FingerPrintIcon,
IdentificationIcon,
LinkSlashIcon,
RectangleGroupIcon,
ServerIcon,
ServerStackIcon,
} from '@heroicons/react/24/outline';
import { SectionHeading } from '@nx/nx-dev/ui-common';
import Link from 'next/link';
import { ReactElement } from 'react';
const features = [
{
name: 'Trusted CI Writes',
description:
'By default, only artifacts produced by verified CI pipelines can enter the shared cache, making cache-poisoning attacks impossible.',
icon: ServerIcon,
},
{
name: 'Artifact Traceability',
description:
'Every build artifact is tied to the identity and permissions of the user or process that created it, ensuring full auditability.',
icon: FingerPrintIcon,
},
{
name: 'Automatic Invalidation',
description:
'Revoke a compromised token and instantly render all artifacts it produced unusable.',
icon: LinkSlashIcon,
},
{
name: 'Real-Time Access Control',
description:
'Provision, audit, and revoke developer and CI access on the fly—integrated with your identity provider for immediate effect.',
icon: IdentificationIcon,
},
];
export function EnhancedSecurity(): ReactElement {
return (
<section id="ai-for-your-ci" className="scroll-mt-24">
<div className="mx-auto max-w-7xl px-6 lg:px-8">
<div className="mx-auto max-w-3xl text-center">
<SectionHeading as="h2" variant="title" id="deep-understanding">
Enterprise-grade CI Security
</SectionHeading>
<SectionHeading as="p" variant="subtitle" className="mt-6">
Protect your codebase from artifact poisoning with
infrastructure-first safeguardsensuring compliance in regulated
industries.
</SectionHeading>
</div>
<dl className="mx-auto mt-16 grid max-w-5xl grid-cols-1 gap-6 sm:mt-20 md:grid-cols-2 lg:mt-24 lg:gap-12">
{features.map((feature) => (
<div key={feature.name} className="relative pl-9">
<dt className="flex items-center gap-4 text-base font-semibold leading-7 text-slate-950 dark:text-white">
<feature.icon
aria-hidden="true"
className="absolute left-1 top-1 size-5 shrink-0"
/>
{feature.name}
</dt>
<dd className="mt-2 text-base leading-7">
{feature.description}
</dd>
</div>
))}
</dl>
<div className="mt-12 text-center">
<Link
href="/enterprise/security"
title="Learn more about Nx Cloud security"
prefetch={false}
className="group mt-4 text-sm font-semibold leading-6 text-slate-950 dark:text-white"
>
See what we do to keep you secure{' '}
<span
aria-hidden="true"
className="inline-block transition group-hover:translate-x-1"
>
</span>
</Link>
</div>
</div>
</section>
);
}

View File

@ -25,7 +25,7 @@ import {
useState,
} from 'react';
import { ButtonLink, ButtonLinkProps } from '../button';
import { resourceMenuItems } from './menu-items';
import { enterpriseItems, resourceMenuItems } from './menu-items';
import { MobileMenuItem } from './mobile-menu-item';
import { SectionsMenu } from './sections-menu';
import { AlgoliaSearch } from '@nx/nx-dev/feature-search';
@ -186,14 +186,49 @@ export function Header({ ctaButtons }: HeaderProps): ReactElement {
Pricing
</Link>
<div className="hidden h-6 w-px bg-slate-200 md:block dark:bg-slate-700" />
<Link
href="/enterprise"
title="Nx Enterprise"
className="hidden gap-2 px-3 py-2 font-medium leading-tight hover:text-blue-500 md:inline-flex dark:text-slate-200 dark:hover:text-sky-500"
prefetch={false}
>
Enterprise
</Link>
<Popover className="relative">
{({ open }) => (
<>
<PopoverButton
className={cx(
open ? 'text-blue-500 dark:text-sky-500' : '',
'group inline-flex items-center px-3 py-2 font-medium leading-tight outline-0 dark:text-slate-200'
)}
>
<span className="transition duration-150 ease-in-out group-hover:text-blue-500 dark:group-hover:text-sky-500">
Enterprise
</span>
<ChevronDownIcon
className={cx(
open
? 'rotate-180 transform text-blue-500 dark:text-sky-500'
: '',
'ml-2 h-3 w-3 transition duration-150 ease-in-out group-hover:text-blue-500 dark:group-hover:text-sky-500'
)}
aria-hidden="true"
/>
</PopoverButton>
<Transition
as={Fragment}
enter="transition ease-out duration-200"
enterFrom="opacity-0 translate-y-1"
enterTo="opacity-100 translate-y-0"
leave="transition ease-in duration-150"
leaveFrom="opacity-100 translate-y-0"
leaveTo="opacity-0 translate-y-1"
>
<Popover.Panel className="absolute left-60 z-30 mt-3 w-max max-w-2xl -translate-x-1/2 transform lg:left-20">
<SectionsMenu
sections={{
'Nx for Enterprises': enterpriseItems,
}}
/>
</Popover.Panel>
</Transition>
</>
)}
</Popover>
<div className="hidden h-6 w-px bg-slate-200 md:block dark:bg-slate-700" />
<div className="px-3 opacity-50 hover:opacity-100">
<AlgoliaSearch tiny={true} />
@ -407,14 +442,44 @@ export function Header({ ctaButtons }: HeaderProps): ReactElement {
>
Remote Cache
</Link>
<Link
href="/enterprise"
title="Enterprise"
className="flex w-full gap-2 py-4 font-medium leading-tight hover:text-blue-500 dark:text-slate-200 dark:hover:text-sky-500"
prefetch={false}
>
Enterprise
</Link>
<Disclosure as="div">
{({ open }) => (
<>
<DisclosureButton
className={cx(
open
? 'text-blue-500 dark:text-sky-500'
: 'tex-slate-800 dark:text-slate-200',
'flex w-full items-center justify-between py-4 text-left text-base font-medium focus:outline-none'
)}
>
<span>Enterprise</span>
<ChevronDownIcon
aria-hidden="true"
className={cx(
open
? 'rotate-180 transform text-blue-500 dark:text-sky-500'
: 'tex-slate-800 dark:text-slate-200',
'h-3 w-3 transition duration-150 ease-in-out group-hover:text-blue-500 dark:group-hover:text-sky-500'
)}
/>
</DisclosureButton>
<Disclosure.Panel
as="ul"
className="space-y-1 pb-2"
>
{Object.values(enterpriseItems)
.flat()
.map((item) => (
<MobileMenuItem
key={item.name}
item={item}
/>
))}
</Disclosure.Panel>
</>
)}
</Disclosure>
<Link
href="/contact"
title="Contact"

View File

@ -18,6 +18,7 @@ import {
CheckBadgeIcon,
LifebuoyIcon,
BookOpenIcon,
ShieldCheckIcon,
} from '@heroicons/react/24/outline';
import { FC, SVGProps } from 'react';
import { DiscordIcon } from '../discord-icon';
@ -147,35 +148,6 @@ export const ossProducts: MenuItem[] = [
},
];
export const enterpriseProducts: MenuItem[] = [
{
name: 'Nx Cloud',
description:
'Nx Cloud is the end-to-end solution for smart, efficient and maintainable CI',
href: '/nx-cloud',
icon: null,
isNew: false,
isHighlight: false,
},
{
name: 'Nx Powerpack',
description:
'A suite of paid extensions for the Nx CLI specifically designed for enterprises.',
href: '/powerpack',
icon: null,
isNew: false,
isHighlight: false,
},
{
name: 'Nx Enterprise',
description:
"Accelerate your organization's journey to tighter collaboration, better developer experience, and speed…lots of speed.",
href: '/enterprise',
icon: null,
isNew: false,
isHighlight: false,
},
];
export const learnItems: MenuItem[] = [
{
name: 'Step by step tutorials',
@ -287,6 +259,26 @@ export const companyItems: MenuItem[] = [
isHighlight: false,
},
];
export const enterpriseItems: MenuItem[] = [
{
name: 'Solutions',
description:
"Accelerate your organization's journey to tighter collaboration, better developer experience, and speed.",
href: '/enterprise',
icon: BuildingOfficeIcon,
isNew: false,
isHighlight: false,
},
{
name: 'Security',
description:
'Protect your codebase from artifact poisoning with infrastructure-first security.',
icon: ShieldCheckIcon,
href: '/enterprise/security',
isNew: false,
isHighlight: false,
},
];
export const resourceMenuItems = {
Learn: learnItems,

View File

@ -11,3 +11,11 @@ export * from './lib/testimonial-carousel';
export * from './lib/download-case-study';
export * from './lib/trial-nx-enterprise';
export * from './lib/enterprise-layout';
export * from './lib/security/cache-poisoning-protection';
export * from './lib/security/why-ci-security-matters';
export * from './lib/security/hero';
export * from './lib/security/personal-access';
export * from './lib/security/ci-access';
export * from './lib/security/build-for-enterprise';
export * from './lib/security/call-to-action';
export * from './lib/security/failing-compliance';

View File

@ -1,10 +1,12 @@
import {
BuildingOfficeIcon,
GlobeAmericasIcon,
ServerStackIcon,
ShieldCheckIcon,
} from '@heroicons/react/24/outline';
import { SectionHeading } from '@nx/nx-dev/ui-common';
import { ReactElement } from 'react';
import Link from 'next/link';
export function Security(): ReactElement {
return (
@ -99,6 +101,31 @@ export function Security(): ReactElement {
</p>
</div>
</div>
<div className="mt-8 flex gap-4">
<BuildingOfficeIcon
aria-hidden="true"
className="size-6 shrink-0"
/>
<div>
<h4 className="relative text-base font-medium leading-6 text-slate-900 dark:text-slate-100">
Enterprise-grade CI security
</h4>
<p className="mt-2">
Protect your codebase from artifact poisoning with
infrastructure-first-safeguards, ensuring compliance in
regulated industries (
<Link
href="/enterprise/security"
title="Enterprise-grade CI security"
className="font-semibold"
>
Learn more
</Link>
)
</p>
</div>
</div>
</div>
</div>
</div>

View File

@ -0,0 +1,95 @@
'use client';
import { SectionHeading } from '@nx/nx-dev/ui-common';
import { ReactElement } from 'react';
import {
AdobeIcon,
AwsIcon,
CapitalOneIcon,
FicoIcon,
ModernaIcon,
PayfitIcon,
RoyalBankOfCanadaIcon,
} from '@nx/nx-dev/ui-icons';
export function BuiltForEnterprise(): ReactElement {
return (
<section
id="built-for-enteprise-section"
className="scroll-mt-24 overflow-hidden"
>
<div className="mx-auto max-w-7xl lg:px-8">
<div className="grid grid-cols-1 gap-x-8 gap-y-16 sm:gap-y-20 lg:grid-cols-3 lg:items-start">
<div className="mt-4 flex flex-col justify-items-stretch gap-4 sm:px-6 lg:px-0">
<div className="mt-12 grid w-full grid-cols-2 place-items-center gap-6">
<CapitalOneIcon
aria-hidden="true"
className="col-span-1 size-28 text-black dark:text-white"
/>
<FicoIcon
aria-hidden="true"
className="col-span-1 size-24 text-[#0A6DE6] dark:text-white"
/>
<AwsIcon
aria-hidden="true"
className="col-span-1 size-14 text-[#FF9900] dark:text-white"
/>
<ModernaIcon
aria-hidden="true"
className="col-span-1 size-24 text-black dark:text-white"
/>
<RoyalBankOfCanadaIcon
aria-hidden="true"
className="col-span-1 size-14 text-black dark:text-white"
/>
<AdobeIcon
aria-hidden="true"
className="col-span-1 size-14 text-[#FF0000] dark:text-white"
/>
</div>
</div>
<div className="col-span-2 px-6 md:px-0 lg:pr-4 lg:pt-4">
<SectionHeading as="h2" variant="title" id="built-for-enteprise">
Built for the Enterprise, Trusted by Leading Teams
</SectionHeading>
<SectionHeading as="p" variant="subtitle" className="mt-6">
Thousands of developers rely on Nx Cloud to move fast and stay
secure.
</SectionHeading>
<figure className="mt-16 rounded-lg bg-slate-100 p-4 pl-8 dark:bg-slate-800">
<blockquote className="text-base/7">
<p>
Nx is the tool that helps gain speed and trust on the overall
system and empowers engineers and product builders to ship
faster to go to market faster.
</p>
</blockquote>
<figcaption className="mt-6 flex items-center gap-x-4 text-sm/6">
<img
alt="avatar"
src="https://avatars.githubusercontent.com/u/7281023?v=4"
className="size-8 flex-none rounded-full"
/>
<div>
<div className="font-semibold">Nicolas Beaussart</div>
<div className="text-slate-500">
Staff Platform Engineer, Payfit
</div>
</div>
<PayfitIcon
aria-hidden="true"
className="ml-auto size-10 rounded text-[#0F6FDE] dark:text-white"
/>
</figcaption>
</figure>
</div>
</div>
</div>
</section>
);
}

View File

@ -0,0 +1,97 @@
'use client';
import {
FingerPrintIcon,
LinkSlashIcon,
ServerIcon,
} from '@heroicons/react/24/outline';
import {
SectionDescription,
SectionHeading,
Strong,
} from '@nx/nx-dev/ui-common';
import { ReactElement } from 'react';
export function CachePoisoningProtection(): ReactElement {
return (
<section
id="cache-poisoning-protection-section"
className="scroll-mt-24 overflow-hidden"
>
<div className="mx-auto max-w-7xl px-6 lg:px-8">
<div className="grid grid-cols-1 gap-x-8 gap-y-16 sm:gap-20 lg:grid-cols-2 lg:items-end">
<div>
<SectionHeading
as="h2"
variant="title"
id="cache-poisoning-protection"
>
Cache Poisoning Protection, By Design
</SectionHeading>
<SectionHeading as="p" variant="subtitle" className="mt-6">
Protect your main branch and your customers from compromised
builds.
</SectionHeading>
<SectionDescription as="p" className="mt-6">
Most teams lock down code merges, but leave their cache wide open.
With other tools, attackers can overwrite artifacts on the main
branch without secrets, without cache access, and without leaving
a trace.
</SectionDescription>
<SectionDescription as="p" className="mt-6">
In other systems, cache poisoning can silently alter frontend
forms, backend APIs, or database access and go undetected. With
Nx Cloud, only trusted builds produce trusted artifacts.
</SectionDescription>
</div>
<div>
<SectionDescription as="p" className="mt-6">
<Strong>
Nx Cloud makes this kind of attack categorically impossible by
implementing:
</Strong>
</SectionDescription>
<ul className="mt-4 space-y-4 text-base leading-7">
<li className="relative pl-9">
<span className="inline font-semibold text-slate-950 dark:text-white">
<ServerIcon
aria-hidden="true"
className="absolute left-1 top-1 h-5 w-5"
/>
Writes only from trusted CI{' '}
</span>
By default, the cache artifacts are reused within each pull
request. Only artifacts from verified CI pipelines can enter the
shared cache used by everyone. PR environments cant poison
main.
</li>
<li className="relative pl-9">
<span className="inline font-semibold text-slate-950 dark:text-white">
<FingerPrintIcon
aria-hidden="true"
className="absolute left-1 top-1 h-5 w-5"
/>
Artifact traceability{' '}
</span>
Artifacts are tied to the identity and permissions of the user
or process that created them.
</li>
<li className="relative pl-9">
<span className="inline font-semibold text-slate-950 dark:text-white">
<LinkSlashIcon
aria-hidden="true"
className="absolute left-1 top-1 h-5 w-5"
/>
Automatic invalidation{' '}
</span>
Revoke a token and every artifact it produced becomes
unusable.
</li>
</ul>
</div>
</div>
</div>
</section>
);
}

View File

@ -0,0 +1,86 @@
import Link from 'next/link';
import { ReactElement } from 'react';
import { sendCustomEvent } from '@nx/nx-dev/feature-analytics';
export function SecurityCallToAction(): ReactElement {
return (
<section
className="relative isolate px-6 py-32 sm:py-40 lg:px-8"
aria-labelledby="section-cta-heading"
>
<svg
className="absolute inset-0 -z-10 h-full w-full rotate-180 stroke-black/10 [mask-image:radial-gradient(100%_100%_at_top_right,white,transparent)] dark:stroke-white/10"
aria-hidden="true"
focusable="false"
>
<defs>
<pattern
id="1d4240dd-898f-445f-932d-e2872fd12de3"
width={200}
height={200}
x="50%"
y={0}
patternUnits="userSpaceOnUse"
>
<path d="M.5 200V.5H200" fill="none" />
</pattern>
</defs>
<svg
x="50%"
y={0}
className="overflow-visible fill-slate-200/20 dark:fill-slate-800/20"
>
<path
d="M-200 0h201v201h-201Z M600 0h201v201h-201Z M-400 600h201v201h-201Z M200 800h201v201h-201Z"
strokeWidth={0}
/>
</svg>
<rect
width="100%"
height="100%"
strokeWidth={0}
fill="url(#1d4240dd-898f-445f-932d-e2872fd12de3)"
/>
</svg>
<div
className="absolute inset-x-0 top-10 -z-10 flex transform-gpu justify-center overflow-hidden blur-3xl"
aria-hidden="true"
>
<div
className="aspect-[1108/632] w-[69.25rem] flex-none bg-gradient-to-r from-[#80caff] to-[#4f46e5] opacity-10"
style={{
clipPath:
'polygon(73.6% 51.7%, 91.7% 11.8%, 100% 46.4%, 97.4% 82.2%, 92.5% 84.9%, 75.7% 64%, 55.3% 47.5%, 46.5% 49.4%, 45% 62.9%, 50.3% 87.2%, 21.3% 64.1%, 0.1% 100%, 5.4% 51.1%, 21.4% 63.9%, 58.9% 0.2%, 73.6% 51.7%)',
}}
/>
</div>
<div className="mx-auto max-w-2xl text-center">
<h2
id="section-cta-heading"
className="text-3xl font-medium tracking-tight text-slate-950 sm:text-5xl dark:text-white"
>
Security that scales <br className="hidden lg:block" /> with your team
</h2>
<div className="mt-10">
<p className="mt-6 italic">
<Link
href="/contact/sales"
title="Talk to an expert"
prefetch={false}
onClick={() =>
sendCustomEvent(
'contact-team',
'enterprise-security-bottom-cta',
'enterprise-security'
)
}
className="rounded-md bg-slate-950 px-3.5 py-2.5 text-sm font-semibold text-slate-100 shadow-sm hover:bg-slate-800 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-white dark:bg-white dark:text-slate-900 dark:hover:bg-slate-100"
>
Talk to an expert
</Link>
</p>
</div>
</div>
</section>
);
}

View File

@ -0,0 +1,86 @@
'use client';
import {
ArrowPathIcon,
ArrowsUpDownIcon,
FingerPrintIcon,
IdentificationIcon,
LinkSlashIcon,
} from '@heroicons/react/24/outline';
import {
SectionDescription,
SectionHeading,
Strong,
} from '@nx/nx-dev/ui-common';
import { ReactElement } from 'react';
import { GitHubIcon } from '@nx/nx-dev/ui-icons';
import Link from 'next/link';
export function CiAccess(): ReactElement {
return (
<section
id="token-rotation-and-revocation-section"
className="scroll-mt-24 overflow-hidden"
>
<div className="mx-auto max-w-7xl px-6 lg:px-8">
<div className="grid grid-cols-1 gap-x-8 gap-y-16 sm:gap-20 lg:grid-cols-2 lg:items-end">
<div>
<SectionHeading
as="h2"
variant="title"
id="token-rotation-and-revocation"
>
CI Access: Token Rotation & Revocation
</SectionHeading>
<SectionHeading as="p" variant="subtitle" className="mt-6">
Secure today, safer tomorrow: automatic token rotation.
</SectionHeading>
<SectionDescription as="p" className="mt-6">
<Strong>
Compromised token? Those artifacts wont touch production.
</Strong>{' '}
All artifacts created with a revoked token are automatically
invalidated so leaked credentials cant poison your builds.
</SectionDescription>
</div>
<div>
<SectionDescription as="p" className="mt-6">
<Strong>Nx Cloud allows you to:</Strong>
</SectionDescription>
<ul className="mt-4 space-y-4 text-base leading-7">
<li className="relative pl-9">
<span className="inline font-semibold text-slate-950 dark:text-white">
<ArrowPathIcon
aria-hidden="true"
className="absolute left-1 top-1 h-5 w-5"
/>
Rotate tokens weekly (or as often as needed)
</span>
</li>
<li className="relative pl-9">
<span className="inline font-semibold text-slate-950 dark:text-white">
<ArrowsUpDownIcon
aria-hidden="true"
className="absolute left-1 top-1 h-5 w-5"
/>
Minimize long-term exposure with read-write token rotations
</span>
</li>
</ul>
<div className="mt-4">
<Link
href="/ci/recipes/security/access-tokens"
title="Learn more about CI Access Tokens"
className="text-sm/6 font-semibold"
>
Learn more about CI Access Tokens{' '}
<span aria-hidden="true"></span>
</Link>
</div>
</div>
</div>
</div>
</section>
);
}

View File

@ -0,0 +1,154 @@
'use client';
import {
BugAntIcon,
DocumentCheckIcon,
ExclamationTriangleIcon,
EyeSlashIcon,
FingerPrintIcon,
LinkSlashIcon,
ServerIcon,
} from '@heroicons/react/24/outline';
import {
ButtonLink,
SectionDescription,
SectionHeading,
Strong,
} from '@nx/nx-dev/ui-common';
import { ReactElement } from 'react';
import Link from 'next/link';
export function FailingCompliance(): ReactElement {
return (
<section id="compliance-section" className="scroll-mt-24">
<div className="mx-auto max-w-7xl px-6 lg:px-8">
<div className="grid grid-cols-1 gap-x-8 gap-y-16 sm:gap-20 lg:grid-cols-2 lg:items-end">
<div>
<SectionHeading as="h2" variant="title" id="compliance">
Rolling Your Own Cache Fails in Regulated Sectors
</SectionHeading>
<SectionHeading as="p" variant="subtitle" className="mt-6">
Unmanaged caching may be convenient nowbut its a liability down
the road.
</SectionHeading>
<SectionDescription as="p" className="mt-6">
If you operate in a regulated sector
<Strong>
finance, healthcare, government, defense, aerospace, or
pharmaceuticals
</Strong>
self-hosting your remote cache may expose you to{' '}
<Strong>serious risks like cache poisoning</Strong>.
</SectionDescription>
<SectionDescription as="p" className="mt-6">
These community-built cache solutions all too often miss essential
safeguardsno integrity validation, no fine-grained access
controls, and no real-time token revocation:
</SectionDescription>
<ul className="mt-4 list-disc space-y-1 pl-6 text-base leading-7">
<li className="">nx-remotecache-azure</li>
<li className="">turborepo-remote-cache</li>
<li className="">nx-cache-server</li>
<li className="">turborepo-remote-cache-cloudflare</li>
<li className="">and others like them</li>
</ul>
<SectionDescription as="p" className="mt-6">
Our{' '}
<Link
href="/remote-cache"
title="official Nx self-hosted plugin"
className="font-semibold underline"
>
official Nx self-hosted plugin
</Link>{' '}
adds enhanced security but follows a similar architecture to the
packages above. It is unable to make guarantees about how cache
artifacts are secured or accessed and cannot meet the security
demands of regulated industries.
</SectionDescription>
</div>
<div>
<SectionDescription as="p" className="mt-6">
<Strong>
Failing to secure your cache can lead to steep breach fines, SLA
breaches, damaged reputation, and costly audit delays.
</Strong>
</SectionDescription>
<ul className="mt-6 space-y-4 text-base leading-7">
<li className="relative pl-9">
<span className="inline font-semibold text-slate-950 dark:text-white">
<ExclamationTriangleIcon
aria-hidden="true"
className="absolute left-1 top-1 h-5 w-5"
/>
SOC 2:{' '}
</span>
Self-hosted caches lack independent audits, continuous
monitoring, and incident response documentation required for SOC
2 compliance.
</li>
<li className="relative pl-9">
<span className="inline font-semibold text-slate-950 dark:text-white">
<ExclamationTriangleIcon
aria-hidden="true"
className="absolute left-1 top-1 h-5 w-5"
/>
HIPAA:{' '}
</span>
No administrative, physical, or technical safeguards to meet
HIPAA mandates for protecting ePHI.
</li>
<li className="relative pl-9">
<span className="inline font-semibold text-slate-950 dark:text-white">
<ExclamationTriangleIcon
aria-hidden="true"
className="absolute left-1 top-1 h-5 w-5"
/>
ISO 27001:{' '}
</span>
Cannot prove a certified ISMS, risk-management processes, or
internal/external audit cycles.
</li>
<li className="relative pl-9">
<span className="inline font-semibold text-slate-950 dark:text-white">
<ExclamationTriangleIcon
aria-hidden="true"
className="absolute left-1 top-1 h-5 w-5"
/>
FedRAMP:{' '}
</span>
Not authorized for federal use; missing mandatory controls for
data classification, monitoring, and secure U.S. hosting.
</li>
<li className="relative pl-9">
<span className="inline font-semibold text-slate-950 dark:text-white">
<ExclamationTriangleIcon
aria-hidden="true"
className="absolute left-1 top-1 h-5 w-5"
/>
PCI-DSS:{' '}
</span>
No encryption, segmentation, or logging controls to safeguard
cardholder data.
</li>
</ul>
<div className="mt-10 text-center">
<ButtonLink
href="/contact/sales"
variant="primary"
size="default"
title="Talk to an expert"
>
Talk to an expert
</ButtonLink>
</div>
</div>
</div>
</div>
</section>
);
}

View File

@ -0,0 +1,21 @@
'use client';
import { ButtonLink, SectionHeading, Strong } from '@nx/nx-dev/ui-common';
import { ReactElement, useState, useEffect } from 'react';
import { Dialog, DialogPanel, Transition } from '@headlessui/react';
import Link from 'next/link';
export function SecurityHero(): ReactElement {
return (
<div className="mx-auto max-w-7xl px-6 lg:px-8">
<div className="mx-auto max-w-2xl text-center xl:max-w-6xl">
<SectionHeading as="h1" variant="display">
Enterprise-Grade Security, Built Into the Core
</SectionHeading>
<SectionHeading as="p" variant="subtitle" className="mt-6 text-center">
Protect your codebase from artifact poisoning with
infrastructure-first security.
</SectionHeading>
</div>
</div>
);
}

View File

@ -0,0 +1,94 @@
'use client';
import {
FingerPrintIcon,
IdentificationIcon,
LinkSlashIcon,
} from '@heroicons/react/24/outline';
import {
SectionDescription,
SectionHeading,
Strong,
} from '@nx/nx-dev/ui-common';
import { ReactElement } from 'react';
import { GitHubIcon } from '@nx/nx-dev/ui-icons';
import Link from 'next/link';
export function PersonalAccess(): ReactElement {
return (
<section
id="control-access-in-real-time-section"
className="scroll-mt-24 overflow-hidden"
>
<div className="mx-auto max-w-7xl px-6 lg:px-8">
<div className="grid grid-cols-1 gap-x-8 gap-y-16 sm:gap-20 lg:grid-cols-2 lg:items-start">
<div>
<SectionHeading
as="h2"
variant="title"
id="control-access-in-real-time"
>
Personal Access: Control Access in Real Time
</SectionHeading>
<SectionHeading as="p" variant="subtitle" className="mt-6">
Provision, audit, and revoke with confidence.
</SectionHeading>
<SectionDescription as="p" className="mt-6">
Easily manage developer access to your Nx Cloud workspace no
waiting, no lingering access for former teammates or contractors.
</SectionDescription>
</div>
<div>
<SectionDescription as="p" className="mt-6">
<Strong>Nx Cloud ensures:</Strong>
</SectionDescription>
<ul className="mt-4 space-y-4 text-base leading-7">
<li className="relative pl-9">
<span className="inline font-semibold text-slate-950 dark:text-white">
<IdentificationIcon
aria-hidden="true"
className="absolute left-1 top-1 h-5 w-5"
/>
Access is tied to individual user authentication
</span>
</li>
<li className="relative pl-9">
<span className="inline font-semibold text-slate-950 dark:text-white">
<GitHubIcon
aria-hidden="true"
className="absolute left-1 top-1 h-5 w-5"
/>
Access is tied to your identity provider{' '}
</span>
when SSO or GitHub access is revoked, cache access is too.
</li>
<li className="relative pl-9">
<span className="inline font-semibold text-slate-950 dark:text-white">
<LinkSlashIcon
aria-hidden="true"
className="absolute left-1 top-1 h-5 w-5"
/>
Token revocation cuts off access in real time
</span>
, and invalidates any artifacts they produced.
</li>
</ul>
<div className="mt-4">
<Link
href="/ci/recipes/security/personal-access-tokens"
title="Learn more about Personal Access Tokens"
className="text-sm/6 font-semibold"
>
Learn more about Personal Access Tokens{' '}
<span aria-hidden="true"></span>
</Link>
</div>
</div>
</div>
</div>
</section>
);
}

View File

@ -0,0 +1,95 @@
'use client';
import {
BugAntIcon,
DocumentCheckIcon,
EyeSlashIcon,
} from '@heroicons/react/24/outline';
import {
ButtonLink,
SectionDescription,
SectionHeading,
Strong,
} from '@nx/nx-dev/ui-common';
import { ReactElement } from 'react';
export function WhyCiSecurityMatters(): ReactElement {
return (
<section
id="why-ci-security-matters-section"
className="scroll-mt-24 overflow-hidden"
>
<div className="mx-auto max-w-7xl px-6 lg:px-8">
<div className="grid grid-cols-1 gap-x-8 gap-y-16 sm:gap-20 lg:grid-cols-2 lg:items-end">
<div>
<SectionHeading
as="h2"
variant="title"
id="why-ci-security-matters"
>
Why CI Security Matters
</SectionHeading>
<SectionHeading as="p" variant="subtitle" className="mt-6">
CI pipelines are a growing target and your cache is a critical
entry point.
</SectionHeading>
<SectionDescription as="p" className="mt-6">
Modern build pipelines involve many contributors and moving parts.
As your team evolves, it's essential to lock down access and
prevent vulnerabilities like cache poisoning or unauthorized reuse
of build data.
</SectionDescription>
<div className="mt-10 text-center">
<ButtonLink
href="/enterprise"
variant="primary"
size="default"
title="Learn about Nx Cloud for Enterprises"
>
Learn about Nx Cloud for Enterprises
</ButtonLink>
</div>
</div>
<div>
<ul className="mt-12 space-y-4 text-base leading-7">
<li className="relative pl-9">
<span className="inline font-semibold text-slate-950 dark:text-white">
<BugAntIcon
aria-hidden="true"
className="absolute left-1 top-1 h-5 w-5"
/>
Build artifacts can be compromised and deployed{' '}
</span>
if left unprotected
</li>
<li className="relative pl-9">
<span className="inline font-semibold text-slate-950 dark:text-white">
<EyeSlashIcon
aria-hidden="true"
className="absolute left-1 top-1 h-5 w-5"
/>
Revoked access must take effect immediately{' '}
</span>
</li>
<li className="relative pl-9">
<span className="inline font-semibold text-slate-950 dark:text-white">
<DocumentCheckIcon
aria-hidden="true"
className="absolute left-1 top-1 h-5 w-5"
/>
Self-hosted caching can't guarantee artifact integrity.{' '}
</span>
Without strict branch isolation, access control, and rebuild
policies, poisoned artifacts can silently reach production.{' '}
<Strong>
For teams in highly regulated industries where undetected
modifications are unacceptable, the risk is too high.
</Strong>
</li>
</ul>
</div>
</div>
</div>
</section>
);
}

View File

@ -1,9 +1,10 @@
'use client';
import { ReactElement } from 'react';
import { CheckCircleIcon } from '@heroicons/react/24/solid';
import { ButtonLink, SectionHeading, Strong } from '@nx/nx-dev/ui-common';
import { ButtonLink, SectionHeading } from '@nx/nx-dev/ui-common';
import { sendCustomEvent } from '@nx/nx-dev/feature-analytics';
import Link from 'next/link';
import { ExclamationCircleIcon } from '@heroicons/react/24/outline';
export function RemoteCacheSolutions(): ReactElement {
return (
@ -59,6 +60,24 @@ export function RemoteCacheSolutions(): ReactElement {
/>
<span>Free plans available, no credit card required</span>
</li>
<li className="flex items-start justify-start gap-x-2 py-2.5">
<CheckCircleIcon
aria-hidden="true"
className="h-6 w-5 flex-none text-blue-600 dark:text-sky-500"
/>
<span>
Secure against cache poisoning (
<Link
href="/enterprise/security"
prefetch={false}
title="Remote caching security"
className="font-semibold underline"
>
Learn more
</Link>
)
</span>
</li>
<li className="flex items-start justify-start gap-x-2 py-2.5">
<CheckCircleIcon
aria-hidden="true"
@ -75,6 +94,7 @@ export function RemoteCacheSolutions(): ReactElement {
Hosted on Nx Cloud servers or on-premise with{' '}
<Link
href="/enterprise"
prefetch={false}
title="Learn about Nx Enterprise"
className="font-semibold underline"
>
@ -91,13 +111,6 @@ export function RemoteCacheSolutions(): ReactElement {
Enterprise grade access management and key revocation
</span>
</li>
<li className="flex items-start justify-start gap-x-2 py-2.5">
<CheckCircleIcon
aria-hidden="true"
className="h-6 w-5 flex-none text-blue-600 dark:text-sky-500"
/>
<span>Secure against cache poisoning</span>
</li>
<li className="flex items-start justify-start gap-x-2 py-2.5">
<CheckCircleIcon
aria-hidden="true"
@ -175,6 +188,25 @@ export function RemoteCacheSolutions(): ReactElement {
/>
<span>Free for all users</span>
</li>
<li className="flex items-start justify-start gap-x-2 py-2.5">
<ExclamationCircleIcon
aria-hidden="true"
className="h-6 w-5 flex-none text-blue-600 dark:text-sky-500"
/>
<span>
Not recommended for organizations requiring HIPAA or SOC-2
compliance (
<Link
href="/enterprise/security"
prefetch={false}
title="Remote caching security"
className="font-semibold underline"
>
Learn more
</Link>
)
</span>
</li>
<li className="flex items-start justify-start gap-x-2 py-2.5">
<CheckCircleIcon
aria-hidden="true"
@ -198,23 +230,6 @@ export function RemoteCacheSolutions(): ReactElement {
Simple migration path from existing 3rd party plugins
</span>
</li>
<li className="flex items-start justify-start gap-x-2 py-2.5">
<CheckCircleIcon
aria-hidden="true"
className="h-6 w-5 flex-none text-blue-600 dark:text-sky-500"
/>
<span>
SOC-2 compliant (
<a
href="https://security.nx.app/"
title="Check our SOC 2 security report"
className="font-semibold underline"
>
view report
</a>
)
</span>
</li>
</ul>
</div>
</div>