diff --git a/public/docs/i/1000/platform-hub/policies/policies-activation.webp b/public/docs/i/1000/platform-hub/policies/policies-activation.webp new file mode 100644 index 0000000000..391a18f6d3 Binary files /dev/null and b/public/docs/i/1000/platform-hub/policies/policies-activation.webp differ diff --git a/public/docs/i/1000/platform-hub/policies/policies-commit-experience.webp b/public/docs/i/1000/platform-hub/policies/policies-commit-experience.webp new file mode 100644 index 0000000000..77d70b2c01 Binary files /dev/null and b/public/docs/i/1000/platform-hub/policies/policies-commit-experience.webp differ diff --git a/public/docs/i/1000/platform-hub/policies/policies-create-modal.webp b/public/docs/i/1000/platform-hub/policies/policies-create-modal.webp new file mode 100644 index 0000000000..cce09f5ec7 Binary files /dev/null and b/public/docs/i/1000/platform-hub/policies/policies-create-modal.webp differ diff --git a/public/docs/i/1000/platform-hub/policies/policies-edit-getting-started.webp b/public/docs/i/1000/platform-hub/policies/policies-edit-getting-started.webp new file mode 100644 index 0000000000..3eee2d2934 Binary files /dev/null and b/public/docs/i/1000/platform-hub/policies/policies-edit-getting-started.webp differ diff --git a/public/docs/i/1000/platform-hub/policies/policies-getting-started.webp b/public/docs/i/1000/platform-hub/policies/policies-getting-started.webp new file mode 100644 index 0000000000..bff3a19516 Binary files /dev/null and b/public/docs/i/1000/platform-hub/policies/policies-getting-started.webp differ diff --git a/public/docs/i/1000/platform-hub/policies/policies-missing-dependency.webp b/public/docs/i/1000/platform-hub/policies/policies-missing-dependency.webp new file mode 100644 index 0000000000..1643f625a2 Binary files /dev/null and b/public/docs/i/1000/platform-hub/policies/policies-missing-dependency.webp differ diff --git a/public/docs/i/1000/platform-hub/policies/policies-publishing.webp b/public/docs/i/1000/platform-hub/policies/policies-publishing.webp new file mode 100644 index 0000000000..24d7fe337d Binary files /dev/null and b/public/docs/i/1000/platform-hub/policies/policies-publishing.webp differ diff --git a/public/docs/i/2000/platform-hub/policies/policies-activation.webp b/public/docs/i/2000/platform-hub/policies/policies-activation.webp new file mode 100644 index 0000000000..6e7d9f0fab Binary files /dev/null and b/public/docs/i/2000/platform-hub/policies/policies-activation.webp differ diff --git a/public/docs/i/2000/platform-hub/policies/policies-commit-experience.webp b/public/docs/i/2000/platform-hub/policies/policies-commit-experience.webp new file mode 100644 index 0000000000..b4d7fedb19 Binary files /dev/null and b/public/docs/i/2000/platform-hub/policies/policies-commit-experience.webp differ diff --git a/public/docs/i/2000/platform-hub/policies/policies-create-modal.webp b/public/docs/i/2000/platform-hub/policies/policies-create-modal.webp new file mode 100644 index 0000000000..60e5ada462 Binary files /dev/null and b/public/docs/i/2000/platform-hub/policies/policies-create-modal.webp differ diff --git a/public/docs/i/2000/platform-hub/policies/policies-edit-getting-started.webp b/public/docs/i/2000/platform-hub/policies/policies-edit-getting-started.webp new file mode 100644 index 0000000000..b6da83bffc Binary files /dev/null and b/public/docs/i/2000/platform-hub/policies/policies-edit-getting-started.webp differ diff --git a/public/docs/i/2000/platform-hub/policies/policies-getting-started.webp b/public/docs/i/2000/platform-hub/policies/policies-getting-started.webp new file mode 100644 index 0000000000..05be04659f Binary files /dev/null and b/public/docs/i/2000/platform-hub/policies/policies-getting-started.webp differ diff --git a/public/docs/i/2000/platform-hub/policies/policies-missing-dependency.webp b/public/docs/i/2000/platform-hub/policies/policies-missing-dependency.webp new file mode 100644 index 0000000000..59ed6d7470 Binary files /dev/null and b/public/docs/i/2000/platform-hub/policies/policies-missing-dependency.webp differ diff --git a/public/docs/i/2000/platform-hub/policies/policies-publishing.webp b/public/docs/i/2000/platform-hub/policies/policies-publishing.webp new file mode 100644 index 0000000000..f73c1dd5c6 Binary files /dev/null and b/public/docs/i/2000/platform-hub/policies/policies-publishing.webp differ diff --git a/public/docs/i/600/platform-hub/policies/policies-activation.webp b/public/docs/i/600/platform-hub/policies/policies-activation.webp new file mode 100644 index 0000000000..544362ff59 Binary files /dev/null and b/public/docs/i/600/platform-hub/policies/policies-activation.webp differ diff --git a/public/docs/i/600/platform-hub/policies/policies-commit-experience.webp b/public/docs/i/600/platform-hub/policies/policies-commit-experience.webp new file mode 100644 index 0000000000..1eb3d48fe5 Binary files /dev/null and b/public/docs/i/600/platform-hub/policies/policies-commit-experience.webp differ diff --git a/public/docs/i/600/platform-hub/policies/policies-create-modal.webp b/public/docs/i/600/platform-hub/policies/policies-create-modal.webp new file mode 100644 index 0000000000..580365af89 Binary files /dev/null and b/public/docs/i/600/platform-hub/policies/policies-create-modal.webp differ diff --git a/public/docs/i/600/platform-hub/policies/policies-edit-getting-started.webp b/public/docs/i/600/platform-hub/policies/policies-edit-getting-started.webp new file mode 100644 index 0000000000..f309d9e2e5 Binary files /dev/null and b/public/docs/i/600/platform-hub/policies/policies-edit-getting-started.webp differ diff --git a/public/docs/i/600/platform-hub/policies/policies-getting-started.webp b/public/docs/i/600/platform-hub/policies/policies-getting-started.webp new file mode 100644 index 0000000000..62e05cbdba Binary files /dev/null and b/public/docs/i/600/platform-hub/policies/policies-getting-started.webp differ diff --git a/public/docs/i/600/platform-hub/policies/policies-missing-dependency.webp b/public/docs/i/600/platform-hub/policies/policies-missing-dependency.webp new file mode 100644 index 0000000000..6195ecf0ba Binary files /dev/null and b/public/docs/i/600/platform-hub/policies/policies-missing-dependency.webp differ diff --git a/public/docs/i/600/platform-hub/policies/policies-publishing.webp b/public/docs/i/600/platform-hub/policies/policies-publishing.webp new file mode 100644 index 0000000000..1c604fae0c Binary files /dev/null and b/public/docs/i/600/platform-hub/policies/policies-publishing.webp differ diff --git a/public/docs/i/x/platform-hub/policies/policies-activation.png b/public/docs/i/x/platform-hub/policies/policies-activation.png new file mode 100644 index 0000000000..1c17473bc5 Binary files /dev/null and b/public/docs/i/x/platform-hub/policies/policies-activation.png differ diff --git a/public/docs/i/x/platform-hub/policies/policies-commit-experience.png b/public/docs/i/x/platform-hub/policies/policies-commit-experience.png new file mode 100644 index 0000000000..9d33b92931 Binary files /dev/null and b/public/docs/i/x/platform-hub/policies/policies-commit-experience.png differ diff --git a/public/docs/i/x/platform-hub/policies/policies-create-modal.png b/public/docs/i/x/platform-hub/policies/policies-create-modal.png new file mode 100644 index 0000000000..39713ad447 Binary files /dev/null and b/public/docs/i/x/platform-hub/policies/policies-create-modal.png differ diff --git a/public/docs/i/x/platform-hub/policies/policies-edit-getting-started.png b/public/docs/i/x/platform-hub/policies/policies-edit-getting-started.png new file mode 100644 index 0000000000..43fc96ba7e Binary files /dev/null and b/public/docs/i/x/platform-hub/policies/policies-edit-getting-started.png differ diff --git a/public/docs/i/x/platform-hub/policies/policies-getting-started.png b/public/docs/i/x/platform-hub/policies/policies-getting-started.png new file mode 100644 index 0000000000..229f6f3bcf Binary files /dev/null and b/public/docs/i/x/platform-hub/policies/policies-getting-started.png differ diff --git a/public/docs/i/x/platform-hub/policies/policies-missing-dependency.png b/public/docs/i/x/platform-hub/policies/policies-missing-dependency.png new file mode 100644 index 0000000000..1ed671831a Binary files /dev/null and b/public/docs/i/x/platform-hub/policies/policies-missing-dependency.png differ diff --git a/public/docs/i/x/platform-hub/policies/policies-publishing.png b/public/docs/i/x/platform-hub/policies/policies-publishing.png new file mode 100644 index 0000000000..33b511106e Binary files /dev/null and b/public/docs/i/x/platform-hub/policies/policies-publishing.png differ diff --git a/public/docs/img/platform-hub/policies-audit-log.png b/public/docs/img/platform-hub/policies-audit-log.png index 92129fd2cb..1bfd31e458 100644 Binary files a/public/docs/img/platform-hub/policies-audit-log.png and b/public/docs/img/platform-hub/policies-audit-log.png differ diff --git a/public/docs/img/platform-hub/policies/policies-activation.png b/public/docs/img/platform-hub/policies/policies-activation.png new file mode 100644 index 0000000000..d9036bd88d Binary files /dev/null and b/public/docs/img/platform-hub/policies/policies-activation.png differ diff --git a/public/docs/img/platform-hub/policies/policies-activation.png.json b/public/docs/img/platform-hub/policies/policies-activation.png.json new file mode 100644 index 0000000000..bb66d45676 --- /dev/null +++ b/public/docs/img/platform-hub/policies/policies-activation.png.json @@ -0,0 +1 @@ +{"width":2548,"height":1423,"updated":"2025-11-24T05:48:15.540Z"} \ No newline at end of file diff --git a/public/docs/img/platform-hub/policies/policies-commit-experience.png b/public/docs/img/platform-hub/policies/policies-commit-experience.png new file mode 100644 index 0000000000..959e4df3e5 Binary files /dev/null and b/public/docs/img/platform-hub/policies/policies-commit-experience.png differ diff --git a/public/docs/img/platform-hub/policies/policies-commit-experience.png.json b/public/docs/img/platform-hub/policies/policies-commit-experience.png.json new file mode 100644 index 0000000000..132c6d29ce --- /dev/null +++ b/public/docs/img/platform-hub/policies/policies-commit-experience.png.json @@ -0,0 +1 @@ +{"width":2546,"height":1431,"updated":"2025-11-24T05:48:15.629Z"} \ No newline at end of file diff --git a/public/docs/img/platform-hub/policies/policies-create-modal.png b/public/docs/img/platform-hub/policies/policies-create-modal.png new file mode 100644 index 0000000000..e2a38e6dad Binary files /dev/null and b/public/docs/img/platform-hub/policies/policies-create-modal.png differ diff --git a/public/docs/img/platform-hub/policies/policies-create-modal.png.json b/public/docs/img/platform-hub/policies/policies-create-modal.png.json new file mode 100644 index 0000000000..76a029e6d3 --- /dev/null +++ b/public/docs/img/platform-hub/policies/policies-create-modal.png.json @@ -0,0 +1 @@ +{"width":2146,"height":1209,"updated":"2025-11-24T05:48:15.774Z"} \ No newline at end of file diff --git a/public/docs/img/platform-hub/policies/policies-edit-getting-started.png b/public/docs/img/platform-hub/policies/policies-edit-getting-started.png new file mode 100644 index 0000000000..f6db7c56fa Binary files /dev/null and b/public/docs/img/platform-hub/policies/policies-edit-getting-started.png differ diff --git a/public/docs/img/platform-hub/policies/policies-edit-getting-started.png.json b/public/docs/img/platform-hub/policies/policies-edit-getting-started.png.json new file mode 100644 index 0000000000..62dfe60639 --- /dev/null +++ b/public/docs/img/platform-hub/policies/policies-edit-getting-started.png.json @@ -0,0 +1 @@ +{"width":2573,"height":1450,"updated":"2025-11-24T05:48:15.902Z"} \ No newline at end of file diff --git a/public/docs/img/platform-hub/policies/policies-getting-started.png b/public/docs/img/platform-hub/policies/policies-getting-started.png new file mode 100644 index 0000000000..fae74bf831 Binary files /dev/null and b/public/docs/img/platform-hub/policies/policies-getting-started.png differ diff --git a/public/docs/img/platform-hub/policies/policies-getting-started.png.json b/public/docs/img/platform-hub/policies/policies-getting-started.png.json new file mode 100644 index 0000000000..b3bb337c3e --- /dev/null +++ b/public/docs/img/platform-hub/policies/policies-getting-started.png.json @@ -0,0 +1 @@ +{"width":2573,"height":1450,"updated":"2025-11-24T04:12:04.264Z"} \ No newline at end of file diff --git a/public/docs/img/platform-hub/policies/policies-missing-dependency.png b/public/docs/img/platform-hub/policies/policies-missing-dependency.png new file mode 100644 index 0000000000..182010d316 Binary files /dev/null and b/public/docs/img/platform-hub/policies/policies-missing-dependency.png differ diff --git a/public/docs/img/platform-hub/policies/policies-missing-dependency.png.json b/public/docs/img/platform-hub/policies/policies-missing-dependency.png.json new file mode 100644 index 0000000000..5ad11bf358 --- /dev/null +++ b/public/docs/img/platform-hub/policies/policies-missing-dependency.png.json @@ -0,0 +1 @@ +{"width":1968,"height":348,"updated":"2025-11-25T00:18:32.072Z"} \ No newline at end of file diff --git a/public/docs/img/platform-hub/policies/policies-publishing.png b/public/docs/img/platform-hub/policies/policies-publishing.png new file mode 100644 index 0000000000..8d4de9016c Binary files /dev/null and b/public/docs/img/platform-hub/policies/policies-publishing.png differ diff --git a/public/docs/img/platform-hub/policies/policies-publishing.png.json b/public/docs/img/platform-hub/policies/policies-publishing.png.json new file mode 100644 index 0000000000..f7da4315cd --- /dev/null +++ b/public/docs/img/platform-hub/policies/policies-publishing.png.json @@ -0,0 +1 @@ +{"width":2541,"height":1430,"updated":"2025-11-24T05:48:15.999Z"} \ No newline at end of file diff --git a/src/pages/docs/platform-hub/policies/best-practices.md b/src/pages/docs/platform-hub/policies/best-practices.md index 49fe2364b7..e7f4eba8ef 100644 --- a/src/pages/docs/platform-hub/policies/best-practices.md +++ b/src/pages/docs/platform-hub/policies/best-practices.md @@ -1,7 +1,7 @@ --- layout: src/layouts/Default.astro pubDate: 2025-09-11 -modDate: 2025-09-11 +modDate: 2025-09-25 title: Policies best practices subtitle: Best practices for creating policies within Platform Hub icon: fa-solid fa-lock @@ -63,3 +63,14 @@ The resulting policy will have two conditions. :::figure ![An example of a policy that has both the existence and that isn't skipped](/docs/img/platform-hub/policies/example-of-policy-with-two-conditions.png) ::: + +### Check for parallel execution + +Steps can be configured to run in parallel or sequentially. If your organization requires sequential execution for compliance or troubleshooting purposes, create a policy to check the `Execution` array in the input schema. + +Each execution phase has a `StartTrigger` property that indicates when it should run: + +- `StartAfterPrevious` - Steps run sequentially +- `StartWithPrevious` - Steps run in parallel + +To enforce sequential execution, check that no execution phases have `StartTrigger` set to `StartWithPrevious`. See the [examples page](/docs/platform-hub/policies/examples) for a sample policy. diff --git a/src/pages/docs/platform-hub/policies/examples.md b/src/pages/docs/platform-hub/policies/examples.md index e2cded3518..a73b6165f0 100644 --- a/src/pages/docs/platform-hub/policies/examples.md +++ b/src/pages/docs/platform-hub/policies/examples.md @@ -1,7 +1,7 @@ --- layout: src/layouts/Default.astro pubDate: 2025-09-11 -modDate: 2025-09-11 +modDate: 2025-11-25 title: Policies examples subtitle: Examples of policies for different deployment scenarios icon: fa-solid fa-lock @@ -13,6 +13,25 @@ navOrder: 161 There are many different deployment scenarios that you might have that need to be evaluated in order to meet policy conditions. You can use this page as a reference document to help you quickly get started with enforcing policies. +## How to use these examples + +You can create policies using the editor available when editing a policy in the Platform Hub or by writing OCL files directly in your Git repository. The examples below show the Rego code for both the scope and conditions sections that you'll need. + +### Using the policy editor + +When creating a policy using the policy editor in Platform Hub: + +1. Enter the policy name, description, violation action and violation reason in the UI fields +2. Add the package name at the top of both the Scope and Conditions editors - this must match your policy's slug +3. Copy the scope Rego code into the Scope editor (including the package declaration) +4. Copy the conditions Rego code into the Conditions editor (including the package declaration) + +For example, if your policy slug is `manual_intervention_required`, you need to include `package manual_intervention_required` at the top of both editors. + +### Using OCL files + +If you prefer to write policies as OCL files in your Git repository, see the [Writing policies as OCL files](#writing-policies-as-ocl-files) section at the end of this page for the complete format. + ## Scoping examples The following examples will cover various ways that you can scope your policies: @@ -20,881 +39,523 @@ The following examples will cover various ways that you can scope your policies: ### Scope policy to a space or many spaces ```ruby -name = "Block executions" -description = "This policy applies to all Deployments and Runbook runs in one or more space(s) and will block executions." -violation_reason = "Execution are blocked" - -scope { - rego = <<-EOT - package block_executions - - evaluate if { - # input.Space.Name == "" - If you want to use Space Name - # input.Space.Id == "" - If you want to use Space Id - # input.Space.Slug in ["", ""] - If you want to check multiple Spaces - input.Space.Slug == "" +package scope_example - } - EOT -} - -conditions { - rego = <<-EOT - package block_executions +default evaluate := false - default result := {"allowed": false} - EOT +evaluate if { + # input.Space.Name == "" - If you want to use Space Name + # input.Space.Id == "" - If you want to use Space Id + # input.Space.Slug in ["", ""] - If you want to check multiple Spaces + input.Space.Slug == "" } ``` ### Scope policy to an environment or many environments ```ruby -name = "Block executions" -description = "This policy applies to all Deployments and Runbook runs and will block executions, to particular Environment(s)." -violation_reason = "Execution are blocked" - -scope { - rego = <<-EOT - package block_executions +package scope_example - evaluate if { - # input.Environment.Name == "" - If you want to use Environment Name - # input.Environment.Id == "" - If you want to use Environment Id - # input.Environment.Slug in ["", ""] - If you want to check multiple Environments - input.Environment.Slug == "" +default evaluate := false - } - EOT -} - -conditions { - rego = <<-EOT - package block_executions - - default result := {"allowed": false} - EOT +evaluate if { + # input.Environment.Name == "" - If you want to use Environment Name + # input.Environment.Id == "" - If you want to use Environment Id + # input.Environment.Slug in ["", ""] - If you want to check multiple Environments + input.Environment.Slug == "" } ``` ### Scope policy to a project or many projects ```ruby -name = "Block executions" -description = "This policy applies to all Deployments and Runbook runs and will block executions, to particular Project(s)." -violation_reason = "Execution are blocked" - -scope { - rego = <<-EOT - package block_executions +package scope_example - evaluate if { - # input.Project.Name == "" - If you want to use Project Name - # input.Project.Id == "" - If you want to use Project Id - # input.Project.Slug in ["", ""] - If you want to check multiple Projects - input.Project.Slug == "" +default evaluate := false - } - EOT +evaluate if { + # input.Project.Name == "" - If you want to use Project Name + # input.Project.Id == "" - If you want to use Project Id + # input.Project.Slug in ["", ""] - If you want to check multiple Projects + input.Project.Slug == "" } +``` -conditions { - rego = <<-EOT - package block_executions +### Scope policy to all except a particular project - default result := {"allowed": false} - EOT +```ruby +package scope_example + +default evaluate := true + +evaluate := false if { + # input.Project.Slug == "" - If you want to exclude one project + # input.Project.Slug in ["", ""] - If you want to exclude multiple projects + input.Project.Slug == "" } ``` ### Scope policy to runbook runs only ```ruby -name = "Block executions" -description = "This policy applies only to Runbook runs and will block executions to all Runbook runs." -violation_reason = "Execution are blocked" - -scope { - rego = <<-EOT - package block_executions +package scope_example - evaluate if { - input.Runbook - } - EOT -} - -conditions { - rego = <<-EOT - package block_executions +default evaluate := false - default result := {"allowed": false} - EOT +evaluate if { + input.Runbook } ``` ### Scope policy to a runbook and its runs ```ruby -name = "Block executions" -description = "This policy applies only to Runbook runs and will block executions to specific Runbook runs." -violation_reason = "Execution are blocked" - -scope { - rego = <<-EOT - package block_executions - - evaluate if { - # input.Runbook.Name == "" - If you want to use Runbook Name - # input.Runbook.Snapshot == "" - If you want to use Runbook Snapshot - # input.Runbook.Id in ["", ""] - If you want to check multiple Runbooks - input.Runbook.Id == "" - } - EOT -} +package scope_example -conditions { - rego = <<-EOT - package block_executions +default evaluate := false - default result := {"allowed": false} - EOT +evaluate if { + # input.Runbook.Name == "" - If you want to use Runbook Name + # input.Runbook.Snapshot == "" - If you want to use Runbook Snapshot + # input.Runbook.Id in ["", ""] - If you want to check multiple Runbooks + input.Runbook.Id == "" } ``` ### Scope policy to deployments only ```ruby -name = "Block executions" -description = "This policy applies only to Deployments and will block executions to all Deployments." -violation_reason = "Execution are blocked" +package scope_example -scope { - rego = <<-EOT - package block_executions +default evaluate := false - evaluate if { - not input.Runbook - } - EOT -} - -conditions { - rego = <<-EOT - package block_executions - - default result := {"allowed": false} - EOT +evaluate if { + not input.Runbook } ``` -## Policy conditions +## Conditions examples The following examples will cover different deployment scenarios that can be enforced with policies: ### Check that a step isn't skipped in a deployment ```ruby -name = "All steps are not skipped" -description = "This policy applies to all Deployments and Runbook runs and will check that all steps are not skipped" -violation_reason = "No steps can be skipped." +package all_steps_are_not_skipped -scope { - rego = <<-EOT - package all_steps_are_not_skipped +default result := {"allowed": false} - default evaluate := true - EOT -} - -conditions { - rego = <<-EOT - package all_steps_are_not_skipped - - default result := {"allowed": false} - - # Check all steps are not skipped - result := {"allowed": true} if { - count(input.SkippedSteps) == 0 - } - EOT +# Check all steps are not skipped +result := {"allowed": true} if { + count(input.SkippedSteps) == 0 } ``` ### Check that all deployment steps are enabled ```ruby -name = "All steps must be enabled" -description = "This policy applies to all Deployments and Runbook runs and will check that all steps are enabled" -violation_reason = "No steps can be disabled." - -scope { - rego = <<-EOT - package all_steps_must_be_enabled +package all_steps_must_be_enabled - default evaluate := true - EOT -} - -conditions { - rego = <<-EOT - package all_steps_must_be_enabled - - default result := {"allowed": false} +default result := {"allowed": true} - # Check all steps are enabled - result := {"allowed": true} if { - some step in input.Steps - step.Enabled == true - } - EOT +# Check if any steps are disabled +result := {"allowed": false} if { + some step in input.Steps + step.Enabled == false } ``` ### Check that a step exists at the beginning or at the end during execution ```ruby -name = "Check Step location" -description = "This policy applies to all Deployments and Runbook runs and will check that a particular step exists at the start or the end of the execution." -violation_reason = "Step needs to be at the start or end" +package check_step_location -scope { - rego = <<-EOT - package check_step_location +default result := {"allowed": false} - default evaluate := true - EOT +# Step is at the start +result := {"allowed": true} if { + input.Steps[0].Source.SlugOrId == "" } -conditions { - rego = <<-EOT - package check_step_location - - default result := {"allowed": false } - - # Step is at the start - result := {"allowed": true} if { - input.Steps[0].Source.SlugOrId == "" - } - - # Step is at the end - result := {"allowed": true} if { - input.Steps[count(input.Steps)-1].Source.SlugOrId == "" - } - EOT +# Step is at the end +result := {"allowed": true} if { + input.Steps[count(input.Steps)-1].Source.SlugOrId == "" } ``` ### Check that a Step Template isn't skipped or disabled during a deployment ```ruby -name = "Step Template is executed" -description = "This policy applies to all Deployments and Runbook runs and will check that a particular Step Template exists and is not skipped." -violation_reason = "Step Template must be run" +package step_template_is_executed -scope { - rego = <<-EOT - package step_template_is_executed +default result := {"allowed": false} - evaluate if { - input.Space.Slug == "" - } - EOT -} - -conditions { - rego = <<-EOT - package step_template_is_executed - - default result := {"allowed": false} - - result := {"allowed": true} if { - some step in input.Steps - step.Source.Type == "Step Template" - step.Source.SlugOrId == "" - not step.Id in input.SkippedSteps - step.Enabled == true - } - EOT +result := {"allowed": true} if { + some step in input.Steps + step.Source.Type == "Step Template" + step.Source.SlugOrId == "" + not step.Id in input.SkippedSteps + step.Enabled == true } ``` ### Check that a Step Template is of a certain version when deployments occur ```ruby -name = "Step Template with version is executed" -description = "This policy applies to all Deployments and Runbook runs and will check that a particular Step Template with a version exists and is not skipped." -violation_reason = "Step Template with version must be run" +package step_template_with_version_is_executed -scope { - rego = <<-EOT - package step_template_with_version_is_executed +default result := {"allowed": false} - evaluate if { - input.Space.Slug == "" - } - EOT -} - -conditions { - rego = <<-EOT - package step_template_with_version_is_executed - - default result := {"allowed": false} - - result := {"allowed": true} if { - some step in input.Steps - step.Source.Type == "Step Template" - step.Source.SlugOrId == "" - step.Source.Version == "" - not step.Id in input.SkippedSteps - step.Enabled == true - } - EOT +result := {"allowed": true} if { + some step in input.Steps + step.Source.Type == "Step Template" + step.Source.SlugOrId == "" + step.Source.Version == "" + not step.Id in input.SkippedSteps + step.Enabled == true } ``` ### Check that a Process Template is present, and not skipped ```ruby -name = "Process Template is executed" -description = "This policy applies to all Deployments and Runbook runs and will check that a particular Process Template exists and is not skipped." -violation_reason = "Process Template must be run" - -scope { - rego = <<-EOT - package process_template_is_executed - - evaluate if { - input.Space.Slug == "" - } - EOT -} - -conditions { - rego = <<-EOT - package process_template_is_executed +package process_template_is_executed - default result := {"allowed": false} +default result := {"allowed": false} - result := {"allowed": true} if { - some step in input.Steps - step.Source.Type == "Process Template" - step.Source.SlugOrId == "" - not step.Id in input.SkippedSteps - } - EOT +result := {"allowed": true} if { + some step in input.Steps + step.Source.Type == "Process Template" + step.Source.SlugOrId == "" + not step.Id in input.SkippedSteps } ``` ### Check that a Process Template is enabled ```ruby -name = "Process Template is enabled" -description = "This policy applies to all Deployments and Runbook runs and will check that a particular Process Template is enabled." -violation_reason = "Process Template must be enabled" +package process_template_is_enabled -scope { - rego = <<-EOT - package process_template_is_enabled +default result := {"allowed": false} - evaluate if { - input.Space.Slug == "" - } - EOT -} - -conditions { - rego = <<-EOT - package process_template_is_enabled - - default result := {"allowed": false} - - result := {"allowed": true} if { - some step in input.Steps - step.Source.Type == "Process Template" - step.Source.SlugOrId == "" - step.Enabled == true - } - EOT +result := {"allowed": true} if { + some step in input.Steps + step.Source.Type == "Process Template" + step.Source.SlugOrId == "" + step.Enabled == true } ``` ### Check that a Process Template is at the beginning or end of a process ```ruby -name = "Process Template location check" -description = "This policy applies to all Deployments and Runbook runs and will check that a particular Process Template exists at the start or the end of the execution." -violation_reason = "Process Template needs to be at the start or end" +package process_template_location_check -scope { - rego = <<-EOT - package process_template_location_check +default result := {"allowed": false} - evaluate if { - input.Space.Slug == "" - } - EOT +# Process Template is at the start +result := {"allowed": true} if { + input.Steps[0].Source.Type == "Process Template" + input.Steps[0].Source.SlugOrId == "" } -conditions { - rego = <<-EOT - package process_template_location_check - - default result := {"allowed": false} - - # Process Template is at the start - result := {"allowed": true} if { - input.Steps[0].Source.Type == "Process Template" - input.Steps[0].Source.SlugOrId == "" - } - - # Process Template is at the end - result := {"allowed": true} if { - input.Steps[count(input.Steps)-1].Source.Type == "Process Template" - input.Steps[count(input.Steps)-1].Source.SlugOrId == "" - } - EOT +# Process Template is at the end +result := {"allowed": true} if { + input.Steps[count(input.Steps)-1].Source.Type == "Process Template" + input.Steps[count(input.Steps)-1].Source.SlugOrId == "" } ``` ### Check that a Process Template is of a certain version when deployments occur ```ruby -name = "Process Template with version is executed" -description = "This policy applies to all Deployments and Runbook runs and will check that a particular Process Template with a specific version exists and is not skipped." -violation_reason = "Process Template with specific version must be run" +package process_template_with_version_is_executed -scope { - rego = <<-EOT - package process_template_with_version_is_executed - - evaluate if { - input.Space.Slug == "" - } - EOT -} +default result := {"allowed": false} -conditions { - rego = <<-EOT - package process_template_with_version_is_executed - - default result := {"allowed": false} - - result := {"allowed": true} if { - some step in input.Steps - step.Source.Type == "Process Template" - step.Source.SlugOrId == "" - semver.compare(step.Source.Version, "") == 0 - not step.Id in input.SkippedSteps - step.Enabled == true - } - EOT +result := {"allowed": true} if { + some step in input.Steps + step.Source.Type == "Process Template" + step.Source.SlugOrId == "" + semver.compare(step.Source.Version, "") == 0 + not step.Id in input.SkippedSteps + step.Enabled == true } ``` ### Check that a Process Template exists before or after certain steps ```ruby -name = "Process Template step ordering" -description = "This policy applies to all Deployments and Runbook runs and will check that a particular Process Template exists before or after a certain step." -violation_reason = "Process Template must be in correct position relative to other steps" +package process_template_step_ordering -scope { - rego = <<-EOT - package process_template_step_ordering +default result := {"allowed": false} - evaluate if { - input.Space.Slug == "" - } - EOT +# Process Template exists before a specific step +result := {"allowed": true} if { + some i, step in input.Steps + step.Source.Type == "Process Template" + step.Source.SlugOrId == "" + some j, target_step in input.Steps + target_step.Source.SlugOrId == "" + i < j } -conditions { - rego = <<-EOT - package process_template_step_ordering - - default result := {"allowed": false} - - # Process Template exists before a specific step - result := {"allowed": true} if { - some i, step in input.Steps - step.Source.Type == "Process Template" - step.Source.SlugOrId == "" - some j, target_step in input.Steps - target_step.Source.SlugOrId == "" - i < j - } - - # Process Template exists after a specific step - result := {"allowed": true} if { - some i, step in input.Steps - step.Source.Type == "Process Template" - step.Source.SlugOrId == "" - some j, target_step in input.Steps - target_step.Source.SlugOrId == "" - i > j - } - EOT +# Process Template exists after a specific step +result := {"allowed": true} if { + some i, step in input.Steps + step.Source.Type == "Process Template" + step.Source.SlugOrId == "" + some j, target_step in input.Steps + target_step.Source.SlugOrId == "" + i > j } ``` ### Check if a built-in step happens before another built-in step ```ruby -name = "Built-in step ordering - before" -description = "This policy applies to all Deployments and Runbook runs and will check that one built-in step happens before another built-in step." -violation_reason = "Built-in step must occur before the target built-in step" +package builtin_step_before_builtin -scope { - rego = <<-EOT - package builtin_step_before_builtin +default result := {"allowed": false} - evaluate if { - input.Space.Slug == "" - } - EOT -} - -conditions { - rego = <<-EOT - package builtin_step_before_builtin - - default result := {"allowed": false} - - result := {"allowed": true} if { - some i, first_step in input.Steps - first_step.ActionType == "" - some j, second_step in input.Steps - second_step.ActionType == "" - i < j - } - EOT +result := {"allowed": true} if { + some i, first_step in input.Steps + first_step.ActionType == "" + some j, second_step in input.Steps + second_step.ActionType == "" + i < j } ``` ### Check if a built-in step happens after another built-in step ```ruby -name = "Built-in step ordering - after" -description = "This policy applies to all Deployments and Runbook runs and will check that one built-in step happens after another built-in step." -violation_reason = "Built-in step must occur after the target built-in step" - -scope { - rego = <<-EOT - package builtin_step_after_builtin - - evaluate if { - input.Space.Slug == "" - } - EOT -} - -conditions { - rego = <<-EOT - package builtin_step_after_builtin +package builtin_step_after_builtin - default result := {"allowed": false} +default result := {"allowed": false} - result := {"allowed": true} if { - some i, first_step in input.Steps - first_step.ActionType == "" - some j, second_step in input.Steps - second_step.ActionType == "" - i > j - } - EOT +result := {"allowed": true} if { + some i, first_step in input.Steps + first_step.ActionType == "" + some j, second_step in input.Steps + second_step.ActionType == "" + i > j } ``` ### Check if a custom step template happens before a built-in step ```ruby -name = "Step Template before built-in step" -description = "This policy applies to all Deployments and Runbook runs and will check that a custom step template happens before a built-in step." -violation_reason = "Step Template must occur before the built-in step" - -scope { - rego = <<-EOT - package step_template_before_builtin - - evaluate if { - input.Space.Slug == "" - } - EOT -} - -conditions { - rego = <<-EOT - package step_template_before_builtin +package step_template_before_builtin - default result := {"allowed": false} +default result := {"allowed": false} - result := {"allowed": true} if { - some i, template_step in input.Steps - template_step.Source.Type == "Step Template" - template_step.Source.SlugOrId == "" - some j, builtin_step in input.Steps - builtin_step.ActionType == "" - i < j - } - EOT +result := {"allowed": true} if { + some i, template_step in input.Steps + template_step.Source.Type == "Step Template" + template_step.Source.SlugOrId == "" + some j, builtin_step in input.Steps + builtin_step.ActionType == "" + i < j } ``` ### Check if a custom step template happens after a built-in step ```ruby -name = "Step Template after built-in step" -description = "This policy applies to all Deployments and Runbook runs and will check that a custom step template happens after a built-in step." -violation_reason = "Step Template must occur after the built-in step" +package step_template_after_builtin -scope { - rego = <<-EOT - package step_template_after_builtin +default result := {"allowed": false} - evaluate if { - input.Space.Slug == "" - } - EOT -} - -conditions { - rego = <<-EOT - package step_template_after_builtin - - default result := {"allowed": false} - - result := {"allowed": true} if { - some i, template_step in input.Steps - template_step.Source.Type == "Step Template" - template_step.Source.SlugOrId == "" - some j, builtin_step in input.Steps - builtin_step.ActionType == "" - i > j - } - EOT +result := {"allowed": true} if { + some i, template_step in input.Steps + template_step.Source.Type == "Step Template" + template_step.Source.SlugOrId == "" + some j, builtin_step in input.Steps + builtin_step.ActionType == "" + i > j } ``` ### Check that a deployment contains a manual intervention step - ```ruby -name = "Require Manual Intervention step" -description = "Require Manual Intervention step" -violation_reason = "Manual intervention step is required in production environment" +```ruby +package manualintervention -scope { - rego = <<-EOT - package manualintervention +default result := {"allowed": false} - evaluate if { - startswith(input.Space.Name, "Policies") - startswith(input.Project.Name, "Payment") - startswith(input.Environment.Name, "Production") - } - EOT +result := {"allowed": true} if { + some step in input.Steps + step.ActionType == "Octopus.Manual" + not manual_intervention_skipped } -conditions { - rego = <<-EOT - package manualintervention - - default result := {"allowed": false } - - result := {"allowed": true} if { - some step in input.Steps - step.ActionType == "Octopus.Manual" - not manual_intervention_skipped - } - - result := {"allowed": false, "reason": "Manual intervention step cannot be skipped in production environment"} if { - manual_intervention_skipped - } +result := {"allowed": false, "reason": "Manual intervention step cannot be skipped in production environment"} if { + manual_intervention_skipped +} - manual_intervention_skipped if { - some step in input.Steps - step.Id in input.SkippedSteps - step.ActionType == "Octopus.Manual" - } - EOT +manual_intervention_skipped if { + some step in input.Steps + step.Id in input.SkippedSteps + step.ActionType == "Octopus.Manual" } - ``` +``` ### Check that a deployment have packages from main branch only - ```ruby -name = "Require packages from main branch" -violation_reason = "All packages must come from the main branch" +```ruby +package packages_from_main_branch -scope { - rego = <<-EOT - package packages_from_main_branch +default result := {"allowed": true} - evaluate if { - not input.Runbook - } - EOT +all_packages := [pkg | some step in input.Steps; some pkg in step.Packages] + +result := {"allowed": false} if { + count(all_packages) > 0 + some pkg in all_packages + pkg.GitRef != "refs/heads/main" } +``` -conditions { - rego = <<-EOT - package packages_from_main_branch +### Check that no steps run in parallel - default result := {"allowed": true} +```ruby +package no_parallel_steps - all_packages := [pkg | some step in input.Steps; some pkg in step.Packages] +default result := {"allowed": false} - result := {"allowed": false} if { - count(all_packages) > 0 - some pkg in all_packages - pkg.GitRef != "refs/heads/main" - } - EOT +result := {"allowed": true} if { + # All steps should have StartAfterPrevious, not StartWithPrevious + every execution in input.Execution { + execution.StartTrigger != "StartWithPrevious" + } } - ``` +``` ### Check that a release version is greater than required minimum -This policy will block deployments in production environments, but allow deployments with warnings in other environments. - - ```ruby -name = "Require specific release version" -violation_action = "warn" -scope { - rego = <<-EOT - package specific_release_version +This policy will block deployments in production environments, but allow deployments with warnings in other environments. The violation action for this policy has been set to `warn` as a default. - evaluate if { - input.Release - } - EOT -} - -conditions { - rego = <<-EOT - package specific_release_version +```ruby +package specific_release_version - default result := {"allowed": false} +default result := {"allowed": false} - result := {"allowed": false, "action": "block"} if { - production - version_less_than_required - } +result := {"allowed": false, "action": "block"} if { + production + version_less_than_required +} - result := {"allowed": false} if { - not production - version_less_than_required - } +result := {"allowed": false} if { + not production + version_less_than_required +} - result := {"allowed": true} if { - not version_less_than_required - } +result := {"allowed": true} if { + not version_less_than_required +} - production if { - startswith(input.Environment.Slug, "prod") - } +production if { + startswith(input.Environment.Slug, "prod") +} - version_less_than_required if { - semver.compare(input.Release.Version, "1.0.0") < 0 - } - EOT +version_less_than_required if { + semver.compare(input.Release.Version, "1.0.0") < 0 } - ``` +``` ### Check that release is based on the main branch - ```ruby -name = "Release must be from the main branch" +```ruby +package main_branch_release -scope { - rego = <<-EOT - package main_branch_release +default result := {"allowed": false} - evaluate if { - input.Release - } - EOT +result := {"allowed": true} if { + input.Release.GitRef == "refs/heads/main" } +``` -conditions { - rego = <<-EOT - package main_branch_release +### Check that runbook is from the main branch - default result := {"allowed": false} +```ruby +package main_branch_runbook - result := {"allowed": true} if { - input.Release.GitRef == "refs/heads/main" - } - EOT +default result := {"allowed": false} + +result := {"allowed": true} if { + input.Runbook.GitRef == "refs/heads/main" } - ``` +``` -### Check that runbook is from the main branch +### Check that the project and tenant have a tag from the specified tag set - ```ruby -name = "Runbook must be from the main branch" +Example of a policy that checks tags for Environments, Tenants and Projects. -scope { - rego = <<-EOT - package main_branch_runbook +```ruby +package tags - evaluate if { - input.Runbook - } - EOT +default result := {"allowed": false} + +result := {"allowed": true} if { + has_size_tags + has_lang_tags +} + +has_size_tags if { + some tag in input.Tenant.Tags + startswith(tag, "size/") } + +has_lang_tags if { + some tag in input.Project.Tags + startswith(tag, "lang/") +} +``` -conditions { - rego = <<-EOT - package main_branch_runbook +## Writing policies as OCL files - default result := {"allowed": false} +If you prefer to write policies directly as OCL files in your Git repository instead of using the UI editor, you can create `.ocl` files in the `policies` folder of your Platform Hub Git repository. - result := {"allowed": true} if { - input.Runbook.GitRef == "refs/heads/main" - } - EOT -} - ``` +### OCL file format -### Check that the project and tenant have a tag from the specified tag set -Example of a policy that checks tags for Environments, Tenants and Projects +The OCL file format wraps the Rego code with metadata about the policy. Here's the structure: - ```ruby -name = "Specific tag should be set" +```ruby +name = "Policy Name" +description = "Policy description" +violation_reason = "Custom message shown when policy fails" +violation_action = "warn" or "block" scope { rego = <<-EOT - package tags - - evaluate if { - some tag in input.Environment.Tags - tag == "type/production" + package policy_file_name + + default evaluate := false + + evaluate if { + # Your scope conditions here } EOT } conditions { rego = <<-EOT - package tags - + package policy_file_name + default result := {"allowed": false} - + result := {"allowed": true} if { - has_size_tags - has_lang_tags - } - - has_size_tags if { - some tag in input.Tenant.Tags - startswith(tag, "size/") - } - - has_lang_tags if { - some tag in input.Project.Tags - startswith(tag, "lang/") + # Your policy conditions here } EOT } - ``` +``` + +### Important notes for OCL files + +- The file name must match the package name in your Rego code (e.g., `checkformanualintervention.ocl` requires `package checkformanualintervention`) +- You cannot use dashes in your policy file name +- The package name must be identical in both the scope and conditions sections +- You must include the `package` declaration in the Rego code when using OCL files + diff --git a/src/pages/docs/platform-hub/policies/index.md b/src/pages/docs/platform-hub/policies/index.md index 520e1d71b2..e2a28e0bd8 100644 --- a/src/pages/docs/platform-hub/policies/index.md +++ b/src/pages/docs/platform-hub/policies/index.md @@ -1,7 +1,7 @@ --- layout: src/layouts/Default.astro pubDate: 2025-09-11 -modDate: 2025-09-11 +modDate: 2025-11-25 title: Policies subtitle: An overview of Policies icon: fa-solid fa-lock @@ -26,23 +26,24 @@ Consider implementing policies if: While policies may not be necessary in every deployment scenario, they are invaluable if maintaining compliance and security is a priority. By embedding policies into your deployments, you can minimize risks and ensure that all teams are aligned with your organizational standards. -## Enforceable Policies +## What can you enforce with policies? -:::div{.warning} -Policies is currently in Alpha for all Enterprise Tier Cloud Customers. The feature is not finished or fully tested, and may change drastically as we iterate and build more functionality. -::: +Policies give you the flexibility to enforce virtually any standard across your deployments and runbook runs. When an execution starts, Octopus provides detailed information about the deployment or runbook run to the policy engine, allowing you to evaluate it against your requirements. -For the Alpha release of Policies, you can enforce that all deployments to specific environments contain a certain step. A policy will by default, scope to both runbooks and deployment processes. +Common use cases include: -An example use-case you might have is to enforce that all deployments going to production environments must contain a manual intervention step. +- Requiring specific steps (like manual interventions or approvals) in production deployments +- Ensuring all packages come from approved branches +- Validating that certain steps aren't skipped or disabled +- Enforcing step ordering requirements +- Checking that deployments meet environment-specific criteria +- Verifying projects and tenants have required tags -## Getting started +By default, policies scope to both deployment processes and runbook runs unless you specify otherwise. -All policies are written in Rego and saved as an OCL file. For a comprehensive guide to Rego, please visit the official [documentation.](https://www.openpolicyagent.org/docs/policy-language) If you would like to jump straight to examples that are more representative of the deployment scenario you want to enforce, please visit our [examples page](/docs/platform-hub/policies/examples). +## Getting started -:::div{.warning} -Policies can be created on any branch, but will only evaluate deployments from the default branch -::: +All policies are written in Rego and saved as an OCL file under a policies folder in your Platform Hub repository. If you need to setup your Platform Hub repository see [Platform Hub](/docs/platform-hub/). For a comprehensive guide to Rego, please visit the official [documentation.](https://www.openpolicyagent.org/docs/policy-language) If you would like to jump straight to examples that are more representative of the deployment scenario you want to enforce, please visit our [examples page](/docs/platform-hub/policies/examples). In our example below, we are writing a policy that checks for the existence of a manual intervention step whenever deployments go to production. @@ -50,156 +51,174 @@ In our example below, we are writing a policy that checks for the existence of a ### 1. Create your policies file -To get started, you must create a new folder called **policies** in your Git File Storage Directory. In the folder, you will need to create an OCL file for your policy. +To get started, navigate to the Platform Hub inside of your Octopus instance and click on the Policies section. To create your first policy click the `Create Policy` button. -:::div{.warning} -- You cannot use dashes in your policy file name. +:::figure +![A empty policies list in the Platform Hub](/docs/img/platform-hub/policies/policies-getting-started.png) ::: -```json -checkformanualintervention.ocl -``` - ### 2. Give your policy a name -After you’ve done this, open the OCL file in your code editor, and start with a name, an optional description, an optional violation reason, and an optional violation action. A violation reason will show a custom message to users when they fail to meet the conditions of a policy. The violation action determines what happens when a deployment or runbook run doesn't comply with the policy. +You will be presented with the Create Policy modal. You can then set teh Name for you Policy. Octopus will generate a valid slug for your policy based on the name you provide. You can edit this slug before clicking the `Create` button. -
+:::figure +![A modal to create a new policy](/docs/img/platform-hub/policies/policies-create-modal.png) +::: + +:::div{.hint} +- The slug can not be changed once a policy is created. +::: - ```json - name = "Require Manual Intervention step" - description = "This Policy checks that a manual intervention step isn't skipped when deploying to Production" - violation_reason = "Manual intervention step is required to deploy" - violation_action = "warn" or "block" - ``` +### 3. Update your policy details -The ```violation_reason``` can be overridden by the value of the ```reason``` property defined in the output result of the conditions Rego code. Similarly, the ```violation_action``` can be overridden by the value of the ```action``` property defined in the output result of the conditions Rego code. +This will create the Policy file in your Platform Hub repository and then take you to the edit Policy page, where you can update the following details for your policy. -### 3. Define the policy scope +- **Name** - a short, memorable, unique name for this policy. +- **Description** - an optional description. +- **Violation Reason** - a custom message provided to users when they fail to meet the conditions of a policy. +- **Violation Action** - determines what happens when a deployment or runbook run doesn't comply with the policy. +- **Scope Rego** - Rego to scope whether a policy should be evaluated for a particular deployment or runbook run. +- **Conditions Rego** - Rego to determine the rules that a deployment or runbook run will be evaluated against. + +:::figure +![The form used to edit a policy](/docs/img/platform-hub/policies/policies-edit-getting-started.png) +::: + +:::div{.hint} +- ```violation_reason``` can be overridden by the value of the ```reason``` property defined in the output result of the conditions Rego code. +- ```violation_action``` can be overridden by the value of the ```action``` property defined in the output result of the conditions Rego code. + +Full details of output schema is available on the [schema page](/docs/platform-hub/policies/schema). + +See +::: + + +### 4. Define the policy scope You’ll now need to define the policy's scope, as Rego in the OCL file. Octopus will provide data about your deployments to the policy engine to use during evaluation. When you are writing your Rego code for scoping or conditions, this input data is available under the value ```input.VALUE```. This scope section of the policy defines the package name, which must match the underlying .ocl file name the policy is stored in. By default, the policy evaluates to false. The scope will evaluate to true if the deployment is going to the Production environment, for the ACME project, and in the Default space - all three conditions must be true at the same time.
- For example, Octopus provides the environment details that you are deploying to. +For example, Octopus provides the environment details that you are deploying to. - ```json - { - "Environment": { - "Id": "Environments-1", - "Name": "Development", - "Slug": "development" - - } - } - ``` +```json +{ + "Environment": { + "Id": "Environments-1", + "Name": "Development", + "Slug": "development", + "Tags": ["country/australia", "animal/octopus"] + } +} +``` - To use the environment name in your Rego, you would add the following: +To use the environment name in your Rego, you would add the following: - ```json - input.environment.name = "Development" - ``` +```json +input.Environment.Name = "Development" +``` -:::div{.warning} - Full details on the data available for scoping can be found under the [schema page](/docs/platform-hub/policies/schema). -::: +Our example applies only to deployments and runbook runs to the production environment for the ACME project, in the default space. **All Rego code has to have a package defined, which is the policy slug.** +```ruby +package manual_intervention_required - Our example applies only to deployments and runbook runs to the production environment for the ACME project, in the default space. **All Rego code has to have a package defined, which is the name of your ocl file.** +default evaluate := false +evaluate := true if { + input.Environment.Name == "Production" + input.Project.Name == "ACME" + input.Space.Name == "Default" +} +``` + +### 5. Define the policy conditions - ```ruby - scope { - rego = <<-EOT - package checkformanualintervention - default evaluate := false - evaluate := true if { - input.Environment.Name == "Production" - input.Project.Name == "ACME" - input.Space.Name == "Default" - } - EOT - } - ``` +After defining your scope, you must specify the policy rules. These rules are written in Rego. Octopus will check the results of your Rego code to determine if a deployment complies with the policy. The result should contain a composite value with the properties **allowed** and an optional **reason** and **action**. In this example, we will set the default rule result to be non-compliant. Any deployment that does not meet the policy rules will be prevented from executing. This conditions section of the policy defines the package name, which must match the slug for your policy. By default, the policy evaluates to false. The condition will evaluate to true if the deployment contains the required steps. -### 4. Define the policy conditions +:::div{.warning} +- You cannot rename **result**, it must be called **result**. +- The package name must be the same as your policy file name. +::: -After defining your scope, you must specify the policy rules. These rules are written in Rego. Octopus will check the results of your Rego code to determine if a deployment complies with the policy. The result should contain a composite value with the properties **allowed** and an optional **reason.** In this example, we will set the default rule result to be non-compliant. Any deployment that does not meet the policy rules will be prevented from executing. This conditions section of the policy defines the package name, which must match the underlying .ocl file name the policy is stored in. By default, the policy evaluates to false. The condition will evaluate to true if the deployment contains the required steps. +```ruby +package manual_intervention_required - :::div{.warning} - - You cannot rename **result**, it must be called **result**. - - The package name must be the same as your policy file name. - ::: +default result := {"allowed": false} +``` - ```json - conditions { - rego = <<-EOT - package checkformanualintervention - default result := {"allowed": false} - EOT - } - ``` +:::div{.info} +Full details on the data available for policy scoping and conditions can be found under the [schema page](/docs/platform-hub/policies/schema). +:::
-### 5. Check for a deployment step +### 6. Check for a deployment step After you’ve set the default state, you’ll need to define the policy rules that will update the **result** state to be true so the deployment can execute. In this example, the deployment must contain at least one manual intervention step. We can do this by checking the step.ActionType is “Octopus.Manual”
- ```ruby - conditions { - rego = <<-EOT - package checkformanualintervention - default result := {"allowed": false} - result := {"allowed": true} if { - some step in input.Steps - step.ActionType == "Octopus.Manual" - } - EOT - } - ``` +```ruby +package manual_intervention_required + +default result := {"allowed": false} + +result := {"allowed": true} if { + some step in input.Steps + step.ActionType == "Octopus.Manual" +} +```
-### 6. Finalize and test your policy +After your policy details have been finalized you will need to commit, publish and activate your policy for it to be available for evaluation. + +### 7. Saving a Policy + +Once you've finished making changes to your policy you can commit them to save the changes to your Git repository. You can either **Commit** with a description or quick commit without one. + +:::figure +![The commit experience for a policy](/docs/img/platform-hub/policies/policies-commit-experience.png) +::: + +### 8. Publishing a Policy + +Once you've made your changes, you will have to publish the policy to reflect the changes you've made. You will have three options to choose from when publishing changes: -You’ve now defined a basic policy to ensure a manual intervention step is present when deploying to any environment. You can test this policy by customizing the values in the scope block, and then deploying to an environment. If you choose not to include the manual intervention step in your process, you will see errors in the task log and project dashboards when you try to run the deployment. All policy evaluations will appear in the Audit log (**Configuration** → **Audit**) with the “Compliance Policy Evaluated” filter applied. Audit logs and Server Tasks will only appear for deployments within the policy's scope. +- Major changes (breaking) +- Minor changes (non-breaking) +- Patch (bug fixes) + +:::div{.hint} +The first time you publish a policy you can only publish a major version +::: + +:::figure +![Publish experience for a policy](/docs/img/platform-hub/policies/policies-publishing.png) +::: + +### 9. Activating a policy + +You must activate the policy before it can be evaluated. Policies can be deactivated after they are activated to stop a policy from being evaluated. + +:::div{.hint} +Activation settings can be updated anytime, from the Versions tab on the edit policy page +::: + +:::figure +![Activation status for a policy](/docs/img/platform-hub/policies/policies-activation.png) +::: + +### 10. Finalize and test your policy + +You’ve now defined a basic policy to ensure a manual intervention step is present when deploying to any environment. You can test this policy by customizing the values in the scope block, and then deploying to an environment. If you choose not to include the manual intervention step in your process, you will see errors in the task log and project dashboards when you try to run the deployment. All policy evaluations will appear in the Audit log (**Configuration** → **Audit**) with the “Compliance Policy Evaluated” event group filter applied. Audit logs and Server Tasks will only appear for deployments within the policy's scope.
- ```ruby - name = "Require Manual Intervention step" - description = "This Policy checks that a manual intervention step isn't skipped when deploying to Production" - ViolationReason = "Manual intervention step is required to deploy" - - scope { - rego = <<-EOT - package checkformanualintervention - default evaluate := false - evaluate := true if { - input.Environment.Name == "Production" - input.Project.Name == "ACME" - input.Space.Name == "Default" - } - EOT - } - - conditions { - rego = <<-EOT - package checkformanualintervention - default result := {"allowed": false} - result := {"allowed": true} if { - some step in input.Steps - step.ActionType == "Octopus.Manual" - } - EOT - } - ``` - - :::div{.hint} - - If you wish to see more comprehensive examples for other deployment scenarios, please visit the [examples page](/docs/platform-hub/policies/examples). - - If you wish to see the schema of inputs available for policies, please visit the [schemas page](/docs/platform-hub/policies/schema). - ::: +:::div{.hint} +- If you wish to see more comprehensive examples for other deployment scenarios, please visit the [examples page](/docs/platform-hub/policies/examples). +- If you wish to see the schema of inputs available for policies, please visit the [schemas page](/docs/platform-hub/policies/schema). +::: ## Policy evaluation information diff --git a/src/pages/docs/platform-hub/policies/troubleshooting.md b/src/pages/docs/platform-hub/policies/troubleshooting.md new file mode 100644 index 0000000000..7f605bdf73 --- /dev/null +++ b/src/pages/docs/platform-hub/policies/troubleshooting.md @@ -0,0 +1,26 @@ +--- +layout: src/layouts/Default.astro +pubDate: 2025-11-25 +modDate: 2025-11-25 +title: Troubleshooting +subtitle: Known issues that you may run into +icon: fa-solid fa-layer-group +navTitle: Troubleshooting +navSection: Policies +description: Known issues and limitations for policies +navOrder: 175 +--- + +## Troubleshooting common issues + +You may run into known issues when using policies. We've put together this page to help you diagnose and fix common issues. + +### Windows Server missing dependency + +If you try to load or create a policy you might see the following error "The Compliance Policy engine failed to load. There may be missing dependencies on the machine hosting Octopus Server.". + +:::figure +![A error callout trying to load the policies page](/docs/img/platform-hub/policies/policies-missing-dependency.png) +::: + +If your host machine is running Windows Server then you are missing the Visual C++ Redistributable. To resolve this error you need to install the latest redistributable version for your machine, see [Visual C++ dependency](https://learn.microsoft.com/en-us/cpp/windows/latest-supported-vc-redist?view=msvc-170#latest-supported-redistributable-version) for more information.