diff --git a/content/docs/user-guide/catalog-item-instances.md b/content/docs/user-guide/catalog-item-instances.md index 64b324f..0fa2eaf 100644 --- a/content/docs/user-guide/catalog-item-instances.md +++ b/content/docs/user-guide/catalog-item-instances.md @@ -50,7 +50,11 @@ spec: | `spec.user_values` | Sets of overrides for fields allowed by the catalog item's `fields` array. Only fields with `editable: true` can be customized here. | | `spec.user_values[].path` | Path corresponding to the `path` key in the `catalog_item`'s `fields` item | -> **Note:** Each value provided in `user_values` will be validated against its corresponding item in the catalog item's `fields` list. If the `field` is not editable (`editable=false`) or the `value` does not pass the `validation_schema` the request will be rejected. +> **Note:** Each value provided in `user_values` will be validated against its corresponding item in the catalog item's `fields` list. If the `field` is not editable (`editable=false`) or the `value` does not pass the `validation_schema`, the request will be rejected. + +### Policy Evaluation + +Values set through `user_values` become part of the resource spec that placement [policies](../policies/) evaluate. They are accessible as `input.spec.*` in Rego code — for example, `input.spec.metadata.labels.env` for the label shown above. Only fields declared in the catalog item are included; see [How `input.spec` is Constructed](../policies/#how-inputspec-is-constructed) for details. ### Verifying the Instance diff --git a/content/docs/user-guide/catalog-items.md b/content/docs/user-guide/catalog-items.md index c61e76b..1723923 100644 --- a/content/docs/user-guide/catalog-items.md +++ b/content/docs/user-guide/catalog-items.md @@ -77,6 +77,17 @@ spec: | `spec.fields[].default` | Default value for the field. When `editable` is `false` this becomes the actual value | | `spec.fields[].validation_schema` | JSON Schema rules to validate input. See: https://json-schema.org/ | +### Fields and Policy Evaluation + +Catalog item fields define the governance boundary for placement policies. When DCM builds the resource spec that policies evaluate, it includes **only** two sources: + +1. **Field defaults** declared in the catalog item +2. **user_values** overrides provided at instance creation + +Anything not declared as a catalog item field is invisible to the policy engine, even if set elsewhere on the instance request. This means labels must be exposed through fields with `metadata.labels.*` paths for policies to inspect them. For example, a field with `path: metadata.labels.region` makes the region label available to Rego policies as `input.spec.metadata.labels.region`. + +See [Policies](../policies/) for details on how `input.spec` is constructed and how to write policies that use label values. + ### Verifying the Catalog Item After creating a catalog item, confirm it was registered successfully: diff --git a/content/docs/user-guide/policies.md b/content/docs/user-guide/policies.md index afd9b20..c8ec774 100644 --- a/content/docs/user-guide/policies.md +++ b/content/docs/user-guide/policies.md @@ -82,6 +82,62 @@ The `input` object includes: | `provider` | The currently selected service provider (empty string initially, populated as policies are evaluated). | | `service_provider_constraints` | The accumulated service-provider constraints from prior policies. | +##### How `input.spec` is Constructed + +The `input.spec` object is built from exactly two sources: + +1. **Catalog item field defaults** — the `default` values declared in the catalog item's `fields` array +2. **Instance user_values** — overrides provided when the instance is created + +No other data reaches the policy engine. Arbitrary metadata or fields that are not declared in the [catalog item](../catalog-items/) are **not** included in `input.spec`. The catalog item acts as a governance boundary: if a field is not declared, policies cannot see it. + +This means labels must be declared as catalog item fields (using `metadata.labels.*` paths) for policies to inspect them. See [Fields and Policy Evaluation](../catalog-items/#fields-and-policy-evaluation) for more on declaring fields. + +##### Example: Policy Using Instance Labels + +The following end-to-end example shows how a `region` label flows from a catalog item field declaration through an instance and into a Rego policy. + +**1. Catalog item field** — declares `metadata.labels.region` with allowed values: + +```yaml +fields: + - path: metadata.labels.region + display_name: "Deployment Region" + editable: true + validation_schema: + type: string + enum: + - region-a + - region-b +``` + +**2. Instance user_values** — sets the region at deployment time: + +```yaml +user_values: + - path: metadata.labels.region + value: region-a +``` + +**3. Rego policy** — reads the label from `input.spec` and selects a provider: + +```rego +package region.placement + +import rego.v1 + +main := {"rejected": true, "rejection_reason": "region label is required"} if { + not input.spec.metadata.labels.region +} + +main := {"rejected": false, "selected_provider": provider} if { + region := input.spec.metadata.labels.region + provider := sprintf("provider-%s", [region]) +} +``` + +> **Note:** If `metadata.labels.region` were not declared as a catalog item field, `input.spec.metadata.labels.region` would be undefined and the policy would have no value to evaluate. + #### Output The `main` rule must return an object with the following fields: