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
63 changes: 63 additions & 0 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,69 @@ yarn test:show-report # View test failures
- Configuration in `.vale.ini` and `.github/styles/`
- No direct yarn/make command for local Vale linting

## Feature Lifecycle Notices

Technology preview and deprecation notices are rendered by one component, so the wording is the
same on every page. Do not write the admonition by hand.

### Whole page

When a page is about the feature, declare it in front matter and write nothing in the body:

```yaml
---
description: ...
lifecycle_status: tech-preview
lifecycle_feature: Gateway WAF
lifecycle_id: gateway-waf
---
```

- `lifecycle_status` is `tech-preview` or `deprecated`. There is no value for generally
available: a GA feature says nothing.
- `lifecycle_feature` is the name shown in the notice title. Omit it when the page title already
names the feature unambiguously.
- `lifecycle_id` is the matching `id` in `data/feature-status.yaml`. It is optional, but supply
it when the feature has an entry, because it is what lets CI catch a notice that outlived the
status it describes. Nothing is rendered from it.

`src/remark/lifecycleNoticePlugin.js` places the notice directly after the page's H1. A page
that declares a status but has no H1 fails the build. So does a misspelled key such as
`lifecycle-status`, or a `lifecycle_feature` or `lifecycle_id` without `lifecycle_status`.

Do not use `$[variables]` in these front matter fields. Variable substitution is a remark plugin
that runs over the page body, and front matter never passes through it, so the token would be
published literally. Write the product name out instead.

### Part of a page

When only one section of an otherwise generally available page is affected, or when the notice
needs extra guidance such as what to migrate to, place the component yourself:

```mdx
### Selector-scoped configuration

<LifecycleNotice
status='tech-preview'
feature='Selector-scoped Felix configuration'
id='selector-scoped-felix-config'
/>
```

```mdx
<LifecycleNotice status='deprecated' feature='Application layer policy' id='application-layer-policy-envoy'>
For similar functionality, use [Istio ambient mode](../../compliance/istio/about-istio-ambient.mdx).
</LifecycleNotice>
```

The component is registered globally in `src/theme/MDXComponents.js`, so no import is needed.

### When a feature's status changes

Update `data/feature-status.yaml`, which drives the release notes tables, and update or remove
the notice on the feature's pages in the same change. `yarn test:components` fails when a page
and the data file disagree, so the two cannot drift apart silently.

## Operator API Documentation Updates

### Auto-generation Commands
Expand Down
10 changes: 5 additions & 5 deletions calico-enterprise/reference/resources/felixconfig.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,11 @@ spec:

### Selector-scoped configuration

:::note

This feature is a **tech preview**. The behavior described here may change in future releases.

:::
<LifecycleNotice
status='tech-preview'
feature='Selector-scoped Felix configuration'
id='selector-scoped-felix-config'
/>

FelixConfiguration resources whose name is not `default` and does not start with `node.` can include a `nodeSelector` field to restrict the configuration to nodes whose labels match the selector. This allows you to apply different Felix settings to groups of nodes without creating individual per-node resources.

Expand Down
9 changes: 3 additions & 6 deletions calico-enterprise/threat/gateway-waf/overview.mdx
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
---
description: Protect Calico Ingress Gateway traffic with a per-route and per-namespace web application firewall built on the OWASP Core Rule Set — how the resource families, merge order, and enforcement guardrails fit together.
lifecycle_status: tech-preview
lifecycle_feature: Gateway WAF
lifecycle_id: gateway-waf

Check warning on line 5 in calico-enterprise/threat/gateway-waf/overview.mdx

View workflow job for this annotation

GitHub Actions / runner / vale

[vale] reported by reviewdog 🐶 [Vale.Terms] Use 'WAF' instead of 'waf'. Raw Output: {"message":"[Vale.Terms] Use 'WAF' instead of 'waf'.","location":{"path":"calico-enterprise/threat/gateway-waf/overview.mdx","range":{"start":{"line":5,"column":23},"end":{"line":5,"column":26}}},"severity":"WARNING","code":{"value":"Vale.Terms"}}
---

# Gateway WAF

:::note

This feature is tech preview. Tech preview features may be subject to significant changes before they become GA.

:::

## Big picture

Protect the traffic entering your cluster through $[prodname] Ingress Gateway with a web application firewall (WAF) that you attach per Gateway or per route, and tune per namespace.
Expand Down
7 changes: 4 additions & 3 deletions docusaurus.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ const nextVersion = process.env.BUILD_NEXT === 'true' ? ['current'] : [];

export default async function createAsyncConfig() {
const variablesPlugin = await import('./src/remark/variablesPlugin');
const lifecycleNoticePlugin = await import('./src/remark/lifecycleNoticePlugin');

/** @type {import('@docusaurus/types').Config} */
const config = {
Expand Down Expand Up @@ -452,7 +453,7 @@ export default async function createAsyncConfig() {
},
},
sidebarPath: './sidebars-calico.js',
beforeDefaultRemarkPlugins: [variablesPlugin],
beforeDefaultRemarkPlugins: [lifecycleNoticePlugin, variablesPlugin],
editUrl: generateEditUrl,
},
],
Expand Down Expand Up @@ -499,7 +500,7 @@ export default async function createAsyncConfig() {
},
},
sidebarPath: './sidebars-calico-enterprise.js',
beforeDefaultRemarkPlugins: [variablesPlugin],
beforeDefaultRemarkPlugins: [lifecycleNoticePlugin, variablesPlugin],
editUrl: generateEditUrl,
},
],
Expand All @@ -525,7 +526,7 @@ export default async function createAsyncConfig() {
},
},
sidebarPath: './sidebars-calico-cloud.js',
beforeDefaultRemarkPlugins: [variablesPlugin],
beforeDefaultRemarkPlugins: [lifecycleNoticePlugin, variablesPlugin],
editUrl: generateEditUrl,
},
],
Expand Down
27 changes: 27 additions & 0 deletions src/components/FeatureStatusTable/featureStatus.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,33 @@ function statusAt(changes: ReturnType<typeof statusChanges>, version: string): C
return current;
}

/**
* A feature's status in one product at one release, or `null` if it did not exist yet.
*
* `version` may be null, meaning the unversioned Next tree, which is ahead of every released
* line and so takes the last recorded status. Next has no release number of its own — the
* unversioned trees set `version: 'master'` — so there is nothing to compare against, and
* carrying the final change forward is the only reading consistent with Next being newer than
* everything in the file.
*
* Exported for the lifecycle drift check, which asks the same question one feature at a time
* rather than one table at a time. It shares `statusChanges` and `statusAt` with the tables so
* the two can never answer it differently.
*/
export function resolveStatus(
feature: Feature,
product: string,
version: string | null
): CellStatus {
const history = feature.products?.[product];
if (!history || history.confirmed === false) return null;

const changes = statusChanges(history);
if (!changes.length) return null;

return version === null ? changes[changes.length - 1].status : statusAt(changes, version);
}

/**
* The rows of one table: every feature that held one of the `include` statuses at some
* point in the window.
Expand Down
Loading
Loading