Skip to content
Open
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
3 changes: 3 additions & 0 deletions .github/workflows/vale.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ jobs:
with:
node-version: '22'
cache: yarn
- name: Authenticate GitHub Packages
if: steps.changed.outputs.skip == 'false'
run: yarn config set --home npmScopes.tigera.npmAuthToken "${{ secrets.GITHUB_TOKEN }}"
- name: Install dependencies
if: steps.changed.outputs.skip == 'false'
Comment on lines +33 to 37
Copy link

Copilot AI Apr 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This workflow now authenticates to GitHub Packages during yarn install, but it doesn’t declare permissions: packages: read. If the repository’s default GITHUB_TOKEN permissions don’t include packages access, dependency installation from npm.pkg.github.com will fail. Consider adding explicit packages: read permissions (workflow- or job-level).

Copilot uses AI. Check for mistakes.
run: yarn install --immutable
Expand Down
41 changes: 41 additions & 0 deletions calico/networking/ingress-gateway/migrate-from-nginx.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
---
description: Migrate your NGINX Ingress resources to Calico Ingress Gateway (Envoy Gateway) with an automated conversion tool and step-by-step playbook.
title: Migrating from NGINX
---

import { IngressConverter } from '/src/___new___/components';

# Migrating from NGINX Ingress

NGINX Ingress Controller [retired in March 2026](https://kubernetes.io/blog/2025/11/11/ingress-nginx-retirement/) — no more releases, bugfixes, or security patches. Calico Ingress Gateway, powered by Envoy Gateway, is the recommended replacement.

Check failure on line 10 in calico/networking/ingress-gateway/migrate-from-nginx.mdx

View workflow job for this annotation

GitHub Actions / runner / vale

[vale] reported by reviewdog 🐶 [Vale.Spelling] Did you really mean 'bugfixes'? Raw Output: {"message": "[Vale.Spelling] Did you really mean 'bugfixes'?", "location": {"path": "calico/networking/ingress-gateway/migrate-from-nginx.mdx", "range": {"start": {"line": 10, "column": 135}}}, "severity": "ERROR"}

This migration tool converts your NGINX Ingress resources (including annotations) into Gateway API equivalents and generates a personalised migration playbook.

## What it converts

- **Structural Ingress fields** — hosts, paths, TLS, backends → Gateway, HTTPRoute, ReferenceGrant
- **NGINX annotations** — CORS, timeouts, rate limiting, auth, session affinity, rewrites, and 130+ more → SecurityPolicy, BackendTrafficPolicy, ClientTrafficPolicy
- **Supports both NGINX controllers** — community (`nginx.ingress.kubernetes.io/*`) and NGINX Inc/F5 (`nginx.org/*`, `nginx.com/*`)

Annotations that can't be auto-converted are flagged with "think in Envoy terms" guidance explaining how to achieve the same behavior in Envoy Gateway.

## Try it now

Paste your NGINX Ingress YAML below to generate a conversion and migration playbook — everything runs in your browser, nothing is sent to a server.

<IngressConverter />

## Migration playbook

The converter generates a 6-section playbook tailored to your resources:

1. **Pre-Migration Assessment** — what you have, what you'll get, what needs manual attention
2. **Prepare** — install Envoy Gateway, review and apply converted resources
3. **Verify (Parallel Running)** — test routes through Envoy Gateway without disrupting NGINX traffic
4. **Traffic Shift** — DNS-based, weighted, or canary strategies with rollback instructions
5. **Cleanup** — remove Ingress resources and NGINX controller
6. **Post-Migration** — explore Gateway API features, set up observability

## Need help?

For complex migrations (hundreds of Ingress resources, custom NGINX snippets, mTLS, NGINX Plus features), [talk to a Tigera engineer](https://www.tigera.io/contact/).
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
---
description: Migrate your NGINX Ingress resources to Calico Ingress Gateway (Envoy Gateway) with an automated conversion tool and step-by-step playbook.
title: Migrating from NGINX
---

import { IngressConverter } from '/src/___new___/components';

# Migrating from NGINX Ingress

NGINX Ingress Controller [retired in March 2026](https://kubernetes.io/blog/2025/11/11/ingress-nginx-retirement/) — no more releases, bugfixes, or security patches. Calico Ingress Gateway, powered by Envoy Gateway, is the recommended replacement.

Check failure on line 10 in calico_versioned_docs/version-3.31/networking/ingress-gateway/migrate-from-nginx.mdx

View workflow job for this annotation

GitHub Actions / runner / vale

[vale] reported by reviewdog 🐶 [Vale.Spelling] Did you really mean 'bugfixes'? Raw Output: {"message": "[Vale.Spelling] Did you really mean 'bugfixes'?", "location": {"path": "calico_versioned_docs/version-3.31/networking/ingress-gateway/migrate-from-nginx.mdx", "range": {"start": {"line": 10, "column": 135}}}, "severity": "ERROR"}

This migration tool converts your NGINX Ingress resources (including annotations) into Gateway API equivalents and generates a personalised migration playbook.

## What it converts

- **Structural Ingress fields** — hosts, paths, TLS, backends → Gateway, HTTPRoute, ReferenceGrant
- **NGINX annotations** — CORS, timeouts, rate limiting, auth, session affinity, rewrites, and 130+ more → SecurityPolicy, BackendTrafficPolicy, ClientTrafficPolicy
- **Supports both NGINX controllers** — community (`nginx.ingress.kubernetes.io/*`) and NGINX Inc/F5 (`nginx.org/*`, `nginx.com/*`)

Annotations that can't be auto-converted are flagged with "think in Envoy terms" guidance explaining how to achieve the same behavior in Envoy Gateway.

## Try it now

Paste your NGINX Ingress YAML below to generate a conversion and migration playbook — everything runs in your browser, nothing is sent to a server.

<IngressConverter />

## Migration playbook

The converter generates a 6-section playbook tailored to your resources:

1. **Pre-Migration Assessment** — what you have, what you'll get, what needs manual attention
2. **Prepare** — install Envoy Gateway, review and apply converted resources
3. **Verify (Parallel Running)** — test routes through Envoy Gateway without disrupting NGINX traffic
4. **Traffic Shift** — DNS-based, weighted, or canary strategies with rollback instructions
5. **Cleanup** — remove Ingress resources and NGINX controller
6. **Post-Migration** — explore Gateway API features, set up observability

## Need help?

For complex migrations (hundreds of Ingress resources, custom NGINX snippets, mTLS, NGINX Plus features), [talk to a Tigera engineer](https://www.tigera.io/contact/).
3 changes: 2 additions & 1 deletion calico_versioned_sidebars/version-3.31-sidebars.json
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,8 @@
"networking/ingress-gateway/about-calico-ingress-gateway",
"networking/ingress-gateway/create-ingress-gateway",
"networking/ingress-gateway/customize-ingress-gateway",
"networking/ingress-gateway/tutorial-ingress-gateway-canary"
"networking/ingress-gateway/tutorial-ingress-gateway-canary",
"networking/ingress-gateway/migrate-from-nginx"
]
},
{
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
"cheerio": "^1.1.0",
"clsx": "^2.1.1",
"framer-motion": "^4.1.17",
"marked": "^17.0.5",
"prism-react-renderer": "^2.1.0",
"react": "19.2.3",
"react-dom": "19.2.3",
Expand Down
3 changes: 2 additions & 1 deletion sidebars-calico.js
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,8 @@ module.exports = {
'networking/ingress-gateway/about-calico-ingress-gateway',
'networking/ingress-gateway/create-ingress-gateway',
'networking/ingress-gateway/customize-ingress-gateway',
'networking/ingress-gateway/tutorial-ingress-gateway-canary'
'networking/ingress-gateway/tutorial-ingress-gateway-canary',
'networking/ingress-gateway/migrate-from-nginx'
],
},
{
Expand Down
74 changes: 74 additions & 0 deletions src/___new___/components/IngressConverter/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// Vendored from @tigera/ingress-to-gateway-web@0.7.0
// Source: https://github.com/tigera/ing2gw (private)
// To update: copy packages/web/dist/{index.js,styles.css} → vendor/
import { IngressInput, PlaybookOutput, YamlOutput, useConversion } from './vendor/ing2gw-web';
import './vendor/ing2gw-web.css';
import { marked } from 'marked';
import React, { useCallback, useState } from 'react';

function MarkdownRenderer({ children }: { children: string }) {
const html = marked.parse(children, { async: false }) as string;
// biome-ignore lint/security/noDangerouslySetInnerHtml: markdown is generated by our own report engine, not user input
Comment on lines +8 to +11
Copy link

Copilot AI Apr 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

marked will render raw HTML by default, and conversion.output.report is derived (directly/indirectly) from user-pasted YAML. Rendering it via dangerouslySetInnerHTML without sanitization creates an XSS risk. Consider sanitizing the generated HTML (e.g., reuse the repo’s existing sanitize-html dependency) or configure the markdown pipeline to disallow embedded HTML before injecting it.

Suggested change
function MarkdownRenderer({ children }: { children: string }) {
const html = marked.parse(children, { async: false }) as string;
// biome-ignore lint/security/noDangerouslySetInnerHtml: markdown is generated by our own report engine, not user input
import sanitizeHtml from 'sanitize-html';
function MarkdownRenderer({ children }: { children: string }) {
const rawHtml = marked.parse(children, { async: false }) as string;
const html = sanitizeHtml(rawHtml, {
allowedTags: sanitizeHtml.defaults.allowedTags,
allowedAttributes: sanitizeHtml.defaults.allowedAttributes,
});

Copilot uses AI. Check for mistakes.
return <div dangerouslySetInnerHTML={{ __html: html }} />;
}

type Step = 'input' | 'playbook';

export default function IngressConverter() {
const conversion = useConversion();
const [step, setStep] = useState<Step>('input');

const handleConvert = useCallback(() => {
const result = conversion.handleConvert();
Comment on lines +17 to +22
Copy link

Copilot AI Apr 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This new React component doesn’t appear to have a Jest test alongside it, while other components under src/___new___/components/* commonly have snapshot tests in __test__/ (e.g., src/___new___/components/Explore/__test__/index.test.tsx). Adding at least a basic render/snapshot test would help prevent regressions when updating @tigera/ingress-to-gateway-web or the wrapper logic.

Copilot generated this review using guidance from repository custom instructions.
if (result) {
setStep('playbook');
}
}, [conversion.handleConvert]);

const handleReset = useCallback(() => {
conversion.reset();
setStep('input');
}, [conversion.reset]);

if (step === 'playbook' && conversion.output) {
return (
<div style={{ display: 'flex', flexDirection: 'column', gap: '1.5rem' }}>
<div>
<button
type='button'
onClick={handleReset}
style={{
padding: '0.375rem 0.75rem',
fontSize: '0.75rem',
fontWeight: 500,
cursor: 'pointer',
border: '1px solid var(--ifm-color-emphasis-300)',
borderRadius: '0.25rem',
background: 'transparent',
color: 'var(--ifm-color-emphasis-700)',
}}
>
Start over
</button>
</div>
<PlaybookOutput
markdown={conversion.output.report}
markdownRenderer={MarkdownRenderer}
/>
<YamlOutput yaml={conversion.output.yaml} />
</div>
);
}

return (
<IngressInput
value={conversion.input}
onChange={conversion.setInput}
onConvert={handleConvert}
provider={conversion.provider}
onProviderChange={conversion.setProvider}
errors={conversion.errors}
showHeader={false}
/>
);
}

Large diffs are not rendered by default.

419 changes: 419 additions & 0 deletions src/___new___/components/IngressConverter/vendor/ing2gw-web.js

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion src/___new___/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import CalicoProducts from './CalicoProducts';
import AskAIButton from './AskAIButton';
import DocCardLink, { PaidProductDocCardLink } from './DocCardLink';
import DocCardLinkLayout from './DocCardLinkLayout';
import IngressConverter from './IngressConverter';
import SearchModalAskAI from './SearchModalAskAI';

export { DocCardLink, DocCardLinkLayout, PaidProductDocCardLink, CalicoProducts, AskAIButton, SearchModalAskAI };
export { DocCardLink, DocCardLinkLayout, PaidProductDocCardLink, CalicoProducts, AskAIButton, IngressConverter, SearchModalAskAI };
10 changes: 10 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -14066,6 +14066,15 @@ __metadata:
languageName: node
linkType: hard

"marked@npm:^17.0.5":
version: 17.0.5
resolution: "marked@npm:17.0.5"
bin:
marked: bin/marked.js
checksum: 10c0/a044c59cfa14662fefa37bc840200c1f0899214fb677da779112284d49cd5b277806f9a28398195b2031b1e2c80d8daef218e8ad588d7bfa9bc8041cac777ee6
languageName: node
linkType: hard

"math-intrinsics@npm:^1.1.0":
version: 1.1.0
resolution: "math-intrinsics@npm:1.1.0"
Expand Down Expand Up @@ -19680,6 +19689,7 @@ __metadata:
jest-environment-jsdom: "npm:^30.0.5"
jest-junit: "npm:^15.0.0"
limiter: "npm:^2.1.0"
marked: "npm:^17.0.5"
needle: "npm:^3.2.0"
playwright: "npm:1.47.2"
prism-react-renderer: "npm:^2.1.0"
Expand Down
Loading