Skip to content
Merged
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
44 changes: 30 additions & 14 deletions generated/routes.json
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@
},
"/getting-started/advanced-config/sandboxing": {
"relPath": "/getting-started/advanced-config/sandboxing.md",
"lastmod": "2026-01-26T19:35:11.000Z"
"lastmod": "2026-02-19T20:33:28.000Z"
},
"/getting-started/advanced-config/network-configuration": {
"relPath": "/getting-started/advanced-config/network-configuration.md",
Expand All @@ -97,31 +97,31 @@
},
"/api-reference": {
"relPath": "/api-reference/index.md",
"lastmod": "2026-02-03T20:04:53.000Z"
"lastmod": "2026-02-03T22:03:47.000Z"
},
"/api-reference/kubernetes": {
"relPath": "/api-reference/kubernetes/index.md",
"lastmod": "2026-02-03T20:04:53.000Z"
"lastmod": "2026-02-03T22:03:47.000Z"
},
"/api-reference/kubernetes/management-api-reference": {
"relPath": "/api-reference/kubernetes/management-api-reference.md",
"lastmod": "2026-02-03T20:04:53.000Z"
"lastmod": "2026-02-20T17:28:22.000Z"
},
"/api-reference/kubernetes/agent-api-reference": {
"relPath": "/api-reference/kubernetes/agent-api-reference.md",
"lastmod": "2026-02-03T20:04:53.000Z"
"lastmod": "2026-02-16T17:54:34.000Z"
},
"/api-reference/graphql": {
"relPath": "/api-reference/graphql.md",
"lastmod": "2026-02-03T20:04:53.000Z"
"lastmod": "2026-02-03T22:03:47.000Z"
},
"/api-reference/rest": {
"relPath": "/api-reference/rest.md",
"lastmod": "2026-02-03T20:04:53.000Z"
"lastmod": "2026-02-11T23:42:02.000Z"
},
"/api-reference/terraform": {
"relPath": "/api-reference/terraform.md",
"lastmod": "2026-02-03T20:04:53.000Z"
"lastmod": "2026-02-03T22:03:47.000Z"
},
"/plural-features": {
"relPath": "/plural-features/index.md",
Expand Down Expand Up @@ -149,11 +149,11 @@
},
"/plural-features/continuous-deployment/service-templating": {
"relPath": "/plural-features/continuous-deployment/service-templating/index.md",
"lastmod": "2026-02-03T20:13:57.978Z"
"lastmod": "2026-02-23T00:01:21.673Z"
},
"/plural-features/continuous-deployment/service-templating/supporting-liquid-filters": {
"relPath": "/plural-features/continuous-deployment/service-templating/supporting-liquid-filters.md",
"lastmod": "2026-02-03T20:13:57.997Z"
"lastmod": "2026-02-23T00:01:21.700Z"
},
"/plural-features/continuous-deployment/lua": {
"relPath": "/plural-features/continuous-deployment/lua.md",
Expand Down Expand Up @@ -289,7 +289,7 @@
},
"/plural-features/flows/preview-environments": {
"relPath": "/plural-features/flows/preview-environments.md",
"lastmod": "2025-05-14T21:43:40.000Z"
"lastmod": "2026-02-22T23:55:41.000Z"
},
"/plural-features/flows/mcp": {
"relPath": "/plural-features/flows/mcp.md",
Expand Down Expand Up @@ -339,6 +339,22 @@
"relPath": "/plural-features/pr-automation/crds.md",
"lastmod": "2025-06-05T13:01:10.000Z"
},
"/plural-features/pr-automation/governance": {
"relPath": "/plural-features/pr-automation/governance/index.md",
"lastmod": "2026-02-22T23:55:41.000Z"
},
"/plural-features/pr-automation/governance/servicenow": {
"relPath": "/plural-features/pr-automation/governance/servicenow.md",
"lastmod": "2026-02-22T23:55:41.000Z"
},
"/plural-features/pr-automation/governance/webhook": {
"relPath": "/plural-features/pr-automation/governance/webhook.md",
"lastmod": "2026-02-22T23:55:41.000Z"
},
"/plural-features/pr-automation/description-patterns": {
"relPath": "/plural-features/pr-automation/description-patterns.md",
"lastmod": "2026-02-22T23:55:41.000Z"
},
"/plural-features/pr-automation/testing": {
"relPath": "/plural-features/pr-automation/testing.md",
"lastmod": "2025-03-12T14:59:41.000Z"
Expand Down Expand Up @@ -461,7 +477,7 @@
},
"/deployments/sandboxing": {
"relPath": "/getting-started/advanced-config/sandboxing.md",
"lastmod": "2026-01-26T19:35:11.000Z"
"lastmod": "2026-02-19T20:33:28.000Z"
},
"/deployments/network-configuration": {
"relPath": "/getting-started/advanced-config/network-configuration.md",
Expand Down Expand Up @@ -597,10 +613,10 @@
},
"/management-api-reference": {
"relPath": "/api-reference/kubernetes/management-api-reference.md",
"lastmod": "2026-02-03T20:04:53.000Z"
"lastmod": "2026-02-20T17:28:22.000Z"
},
"/agent-api-reference": {
"relPath": "/api-reference/kubernetes/agent-api-reference.md",
"lastmod": "2026-02-03T20:04:53.000Z"
"lastmod": "2026-02-16T17:54:34.000Z"
}
}
4 changes: 4 additions & 0 deletions pages/plural-features/flows/preview-environments.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ spec:
template:
namespace: "flow-test-pr-{{ pr.number }}"
name: "flow-test-pr-{{ pr.number }}"

syncConfig:
deleteNamespace: true # ensure the temp namespace is deleted on cleanup

helm:
values:
image:
Expand Down
91 changes: 91 additions & 0 deletions pages/plural-features/pr-automation/description-patterns.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
---
title: Description Patterns
description: Auto-Correlate Pull Requests with Resources in Plural
---

Plural Supports a number of ways to correlate your Pull Request with resources in Plural, these can serve a variety of purposes:

1. Kick a Plural Service, to minimize GitOps lag on merge.
2. Auto-generate Plural Stack plans for terraform changes, improving the pull request review process.
3. Deferring merges to off-hours to implement service windows.
4. Tie PRs to governance controllers
5. Preview Environment Creation

{% callout severity="info" header="Ensure Webhook Present!" %}
In all of these cases, it's assumed you have an SCM webhook configured to provide Plural with an event stream for pull request/merge requests from you SCM provider. We support all major SCM providers, and they're easy to set up at Self Service -> SCM Management.
{% /callout %}

We'll list these all out one-by-one

## PR <> Service Correlation

To tie a pull request to a service, simply add a tag like this to the pull requests description body:

```
Plural Service: {cluster-handle}/{service-name}
```

to your pull request body. Once there, you'll be able to see the pull request in the service's details view in Plural, and once merged, Plural will automatically resync that service with its source of truth in git, allowing for responsive deployment of the new configuration.

If this isn't implemented, the ordinary GitOps sync window is something like ~2m with some jitter

## PR <> Plural Stack Correlation

Plural Stacks can be tied to pull requests easily with:

```
Plural Stack: {stack-name}
```

This serves two main purposes:

1. Like with services, pr merges will auto-kick the stack, ensuring they sync the new changes with git quickly. Ordinarily these follow a gitops sync window like with services, tuned to ~5m +- jitter by default.
2. Allows for terraform plans to be generated and posted to pull requests as comments, this makes it much easier to safely review terraform code based on the changes it implies against real infrastructure.

The plan will include:

1. The full terraform plan result against the current state of the stack whenever a commit is made to the PR
2. If Plural AI is enabled, an ai explanation of the plan, and any risks it might pose, which is a nice additional review in case engineers are unfamiliar with the APIs involved.

## Plural merge cron

Plural has the ability to auto-merge a PR based on a crontab, assuming the following:

1. The PR is already approved
2. A `default` SCM connection has been registered within Plural to use.

It is activated with the following PR body tag:

```
Plural merge cron: */5 1,2 * * *
```

This will trigger Plural to attempt auto-merge from 1am-2am every 5 minutes. To ensure the PR is defer-merged, approve it before that window and Plural will merge it on your behalf.

## PR <> Plural Governance Correlation

To understand how PR governance works, I recommend reading the [docs themselves](/plural-features/pr-automation/governance). That said, tying a PR to a governance controller is simple:

```
Plural governance: {governance-name}
```

From there, the governance controller will go through its workflow of:

1. create a change on PR open
2. confirm the change is approved while the PR is open, and if so, approve the PR
3. If the PR is closed or merged, close out the change with the appropriate status.

## PR -> Preview Environment Creation/Deletion

Plural Flows supports a full PR-based preview environment controller. You can learn more about it in its [dedicated docs page](/plural-features/flows/preview-environment), but specifying one is simple:

```
Plural Flow: {flow-name}
Plural Preview: {preview-environment-template-name}
```

This will trigger preview environment creation based on the given template, which is unique to a Flow. In particular this will:

1. Clone an existing service on PR creation, and auto-updates that service whenever the PR receives a push event.
2. Delete the service when the PR is deleted.
53 changes: 53 additions & 0 deletions pages/plural-features/pr-automation/governance/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
---
title: PR Governance Controller
description: Unify Change Management Processes within a Git-standard Pull Request Model
---

# Motivation

Many enterprises require robust governance for all change management. This is oftentimes done within blessed systems-of-record, with ServiceNow being the most frequently common. Plural allows for you to synchronize these processes with the GitOps-friendly pull request workflow offered by your SCM provider, using two main strategies:

1. ServiceNow - dedicated controller implementation to synchronize pull request and ServiceNow change request approvals and status
2. Webhook - custom webhook for any nonstandard systems you might want to implement.

In all cases the flow has three main phases:

1. Open - a pull request is opened and a callback is initiated to the external system to create the change record
2. Confirm - the change record is polled on a jittered interval to determine whether the change record has been approved
3. Approval - Plural will approve the Pull Request itself, using a SCM credential you specify
4. Close - The change record is closed once the Pull Request is merged or closed

## Managing PR Approval

This flow guarantees pull requests cannot be merged unless dictated by the external system if and only if the SCM credential provided is made a required approver. This can be done in a few different ways:

1. Repo level configuration. Many repos have global methods to require approvals from specific users and groups.
2. CODEOWNERS - this is a standard convention within Git providers, which delegates specific file paths within a repo to require approvals within users or groups.

We recomend CODEOWNERS as it's more flexible.

## Tying a Pull Request to PR Governance

Most governance policies will be instantiated via CRD, like so:

```yaml
apiVersion: deployments.plural.sh/v1alpha1
kind: PrGovernance
metadata:
name: example
spec:
type: WEBHOOK
connectionRef:
name: governance # reference to the ScmConnection that is used for Pr approval
configuration:
webhook:
url: https://my.governance.webhook
```

To allow the controller to work on a given pr, you simply need to add the following text to its PR description:

```
Plural governance: example # replace {example} with whatever name you dedicate the governance controller to
```

As long as you have a webhook watching that repo (can be created in the SCM management panel in Plural), we'll dedicate and bind the pr to the controller named `example`.
62 changes: 62 additions & 0 deletions pages/plural-features/pr-automation/governance/servicenow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
---
title: ServiceNow Governance
description: Dedicated Pr <-> Change Request Sync intos ServiceNow
---

The ServiceNow governance controller allows a pull request to be synchronized with a ServiceNow change request, so enterprises can implement GitOps flexibly without sacrificing their auditing and governance posture built around the ServiceNow ecosystem. Before implementing, it's worth just looking through the [docs on PR governance](/plural-features/pr-automation/governance) briefly to familiarize yourself with the model.

{% callout severity="info" header="Ensure Webhook Present!" %}
For this to work, it's assumed you have an SCM webhook configured to provide Plural with an event stream for pull request/merge requests from you SCM provider. We support all major SCM providers, and they're easy to set up at Self Service -> SCM Management. Most SCM providers also have ways to limit the scope of webhook events to individual repository sets in case it cannot be implemented organization-wide.
{% /callout %}

# Defining a PrGovernance CRD

The Governance CRD utilizing SericeNow is relatively straightforward, here's an example:

```yaml
apiVersion: deployments.plural.sh/v1alpha1
kind: PrGovernance
metadata:
name: snow
spec:
type: SERVICE_NOW
connectionRef:
name: governance # reference to the ScmConnection that is used for Pr approval
configuration:
serviceNow:
url: https://instance.service-now.com
username: my-user
passwordSecretKeyRef:
name: snow-creds
key: password
secretNamespace: infra # wherever the `snow-creds` secret lives

# supports the ITIL4 change models, eg Standard, Normal, Emergency
changeModel: Standard

# any specific attributes you want to include in the change request, we'll auto-infer the required fields (description, short description, backout plan, test plan, implementation plan from the pull request itself if not provided)
attributes:
description: some description
```

From there, to tie it to a pull request, you'll need:

1. To ensure there's a SCM webhook for the repository pointing to Plural (this can be created in Self Service -> SCM Management in you Plural Console instance)
2. Add the `Plural governance: snow` tag to your PR description so that we'll identify it as requiring governance.

# ServiceNow Controller Implementation

The ServiceNow controller will do the following once it is tied to a PR:

1. Create a new ServiceNow change request using the REST API, filling in any blank fields by inspecting the PR and generating them with AI if not provided (this is overrideable and meant to minimize required, brittle implementation).
2. Wait for the change to be moved to the 'Scheduled' (or later) state in ServiceNow, and approve the pull request, and move the change to `Implement` state from there.
3. Once the PR is merged, the change is moved to `Close` state, and marked successful with reason that the pull request is merged.
4. If the PR is ever closed, the change request is moved to `Cancelled` state.

# Requiring ServiceNow Approvals before PR Approval

This is acheived in the following way:

1. Mark the `changeModel` as Normal, this requires the ServiceNow change go through CAB approval before being moved to `Scheduled` state.
2. Ensure the governance SCM connection is a required approver on the PR. This will block merges of the PR until the governance controller sees the ServiceNow approval.

Loading
Loading