Skip to content
Draft
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
1 change: 1 addition & 0 deletions cmd/inspect/inspect.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ func init() {
InspectCmd = NewInspectCmd()
InspectCmd.AddCommand(inspectPolicyCmd())
InspectCmd.AddCommand(inspectPolicyDataCmd())
InspectCmd.AddCommand(inspectECPCmd())
}

func NewInspectCmd() *cobra.Command {
Expand Down
116 changes: 116 additions & 0 deletions cmd/inspect/inspect_ecp.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
// Copyright The Conforma Contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// SPDX-License-Identifier: Apache-2.0

// Define the `ec inspect ecp` command
package inspect

import (
"fmt"

hd "github.com/MakeNowJust/heredoc"
"github.com/spf13/cobra"

validate_utils "github.com/conforma/cli/internal/validate"
)

func inspectECPCmd() *cobra.Command {
var (
policyConfiguration string
policyOverlays []string
)

cmd := &cobra.Command{
Use: "ecp --policy <policy>",
Short: "Inspect and display the effective EnterpriseContractPolicy configuration",

Long: hd.Doc(`
Load a base EnterpriseContractPolicy configuration and optionally merge it with
overlay files, then display the resulting effective configuration.

This is useful for debugging and understanding how policy overlays are merged
with the base policy. The output shows the final configuration that would be
used during validation.
`),

Example: hd.Doc(`
Display a single policy configuration:

ec inspect ecp --policy policy.yaml

Display the merged result of a base policy and overlays:

ec inspect ecp --policy standard.yaml --policy-overlay team.yaml

Display the result of multiple overlays (applied in order):

ec inspect ecp --policy standard.yaml \
--policy-overlay team.yaml \
--policy-overlay hotfix.yaml
`),

Args: cobra.NoArgs,

RunE: func(cmd *cobra.Command, args []string) error {
ctx := cmd.Context()

// Load base policy configuration
policyConfig, err := validate_utils.GetPolicyConfig(ctx, policyConfiguration)
if err != nil {
return fmt.Errorf("failed to load policy: %w", err)
}

// Merge overlays if provided
if len(policyOverlays) > 0 {
var overlays []string
for _, overlayFile := range policyOverlays {
overlay, err := validate_utils.GetPolicyConfig(ctx, overlayFile)
if err != nil {
return fmt.Errorf("failed to load policy overlay %s: %w", overlayFile, err)
}
overlays = append(overlays, overlay)
}

mergedConfig, err := validate_utils.MergePolicyConfigs(ctx, policyConfig, overlays)
if err != nil {
return fmt.Errorf("failed to merge policy configs: %w", err)
}
policyConfig = mergedConfig
}

// Output the effective configuration
fmt.Println(policyConfig)
return nil
},
}

cmd.Flags().StringVarP(&policyConfiguration, "policy", "p", policyConfiguration, hd.Doc(`
Policy configuration as:
* Kubernetes reference ([<namespace>/]<name>)
* file (policy.yaml)
* git reference (github.com/user/repo//default?ref=main), or
* inline JSON ('{sources: {...}, identity: {...}}')`))

cmd.Flags().StringSliceVar(&policyOverlays, "policy-overlay", policyOverlays, hd.Doc(`
Policy overlay files to merge with the base policy. Can be specified multiple times.
Overlays are applied in order. Maps are deeply merged, arrays are concatenated.
Supports the same formats as --policy (files, git references, inline JSON/YAML).`))

if err := cmd.MarkFlagRequired("policy"); err != nil {
panic(err)
}

return cmd
}
27 changes: 27 additions & 0 deletions cmd/validate/image.go
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,27 @@ func validateImageCmd(validate imageValidationFunc) *cobra.Command {
}
data.policyConfiguration = policyConfiguration

// Merge policy overlays if provided
if len(data.policyOverlays) > 0 {
var overlays []string
for _, overlayFile := range data.policyOverlays {
overlay, err := validate_utils.GetPolicyConfig(ctx, overlayFile)
if err != nil {
allErrors = errors.Join(allErrors, fmt.Errorf("failed to load policy overlay %s: %w", overlayFile, err))
return
}
overlays = append(overlays, overlay)
}

mergedConfig, err := validate_utils.MergePolicyConfigs(ctx, data.policyConfiguration, overlays)
if err != nil {
allErrors = errors.Join(allErrors, fmt.Errorf("failed to merge policy configs: %w", err))
return
}
data.policyConfiguration = mergedConfig
log.Debugf("Merged base policy with %d overlay(s)", len(overlays))
}

policyOptions := policy.Options{
EffectiveTime: data.effectiveTime,
Identity: cosign.Identity{
Expand Down Expand Up @@ -484,6 +505,11 @@ func validateImageCmd(validate imageValidationFunc) *cobra.Command {
* git reference (github.com/user/repo//default?ref=main), or
* inline JSON ('{sources: {...}, identity: {...}}')")`))

cmd.Flags().StringSliceVar(&data.policyOverlays, "policy-overlay", data.policyOverlays, hd.Doc(`
Policy overlay files to merge with the base policy. Can be specified multiple times.
Overlays are applied in order. Maps are deeply merged, arrays are concatenated.
Supports the same formats as --policy (files, git references, inline JSON/YAML).`))

cmd.Flags().StringVarP(&data.imageRef, "image", "i", data.imageRef, "OCI image reference")

cmd.Flags().StringVarP(&data.publicKey, "public-key", "k", data.publicKey,
Expand Down Expand Up @@ -640,6 +666,7 @@ type imageData struct {
outputFile string
policy policy.Policy
policyConfiguration string
policyOverlays []string
policySource string
publicKey string
rekorURL string
Expand Down
63 changes: 63 additions & 0 deletions docs/modules/ROOT/pages/ec_inspect_ecp.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
= ec inspect ecp

Inspect and display the effective EnterpriseContractPolicy configuration

== Synopsis

Load a base EnterpriseContractPolicy configuration and optionally merge it with
overlay files, then display the resulting effective configuration.

This is useful for debugging and understanding how policy overlays are merged
with the base policy. The output shows the final configuration that would be
used during validation.

[source,shell]
----
ec inspect ecp --policy <policy> [flags]
----

== Examples
Display a single policy configuration:

ec inspect ecp --policy policy.yaml

Display the merged result of a base policy and overlays:

ec inspect ecp --policy standard.yaml --policy-overlay team.yaml

Display the result of multiple overlays (applied in order):

ec inspect ecp --policy standard.yaml \
--policy-overlay team.yaml \
--policy-overlay hotfix.yaml

== Options

-h, --help:: help for ecp (Default: false)
-p, --policy:: Policy configuration as:
* Kubernetes reference ([<namespace>/]<name>)
* file (policy.yaml)
* git reference (github.com/user/repo//default?ref=main), or
* inline JSON ('{sources: {...}, identity: {...}}')
--policy-overlay:: Policy overlay files to merge with the base policy. Can be specified multiple times.
Overlays are applied in order. Maps are deeply merged, arrays are concatenated.
Supports the same formats as --policy (files, git references, inline JSON/YAML). (Default: [])

== Options inherited from parent commands

--debug:: same as verbose but also show function names and line numbers (Default: false)
--kubeconfig:: path to the Kubernetes config file to use
--logfile:: file to write the logging output. If not specified logging output will be written to stderr
--quiet:: less verbose output (Default: false)
--retry-duration:: base duration for exponential backoff calculation (Default: 1s)
--retry-factor:: exponential backoff multiplier (Default: 2)
--retry-jitter:: randomness factor for backoff calculation (0.0-1.0) (Default: 0.1)
--retry-max-retry:: maximum number of retry attempts (Default: 3)
--retry-max-wait:: maximum wait time between retries (Default: 3s)
--timeout:: max overall execution duration (Default: 5m0s)
--trace:: enable trace logging, set one or more comma separated values: none,all,perf,cpu,mem,opa,log (Default: none)
--verbose:: more verbose output (Default: false)

== See also

* xref:ec_inspect.adoc[ec inspect - Inspect policy rules]
3 changes: 3 additions & 0 deletions docs/modules/ROOT/pages/ec_validate_image.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,9 @@ mark (?) sign, for example: --output text=output.txt?show-successes=false
* file (policy.yaml)
* git reference (github.com/user/repo//default?ref=main), or
* inline JSON ('{sources: {...}, identity: {...}}')")
--policy-overlay:: Policy overlay files to merge with the base policy. Can be specified multiple times.
Overlays are applied in order. Maps are deeply merged, arrays are concatenated.
Supports the same formats as --policy (files, git references, inline JSON/YAML). (Default: [])
-k, --public-key:: path to the public key. Overrides publicKey from EnterpriseContractPolicy
-r, --rekor-url:: Rekor URL. Overrides rekorURL from EnterpriseContractPolicy
--skip-image-sig-check:: Skip image signature validation checks. (Default: false)
Expand Down
1 change: 1 addition & 0 deletions docs/modules/ROOT/partials/cli_nav.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
** xref:ec_init.adoc[ec init]
** xref:ec_init_policies.adoc[ec init policies]
** xref:ec_inspect.adoc[ec inspect]
** xref:ec_inspect_ecp.adoc[ec inspect ecp]
** xref:ec_inspect_policy.adoc[ec inspect policy]
** xref:ec_inspect_policy-data.adoc[ec inspect policy-data]
** xref:ec_opa.adoc[ec opa]
Expand Down
104 changes: 104 additions & 0 deletions features/__snapshots__/inspect_ecp.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@

[inspect policy with multiple overlays:stdout - 1]
exclude:
- overlay1_exclude
- overlay2_exclude
publicKey: k8s://openshift-pipelines/public-key
ruleData:
key1: value1
key2: value2
sources:
- name: Default
policy:
- oci::quay.io/enterprise-contract/ec-release-policy:latest


---

[overlay values override base values:stdout - 1]
ruleData:
baseKey: baseValue
overlayKey: overlayValue
sharedKey: fromOverlay
sources:
- name: Default
policy:
- oci::quay.io/example/policy:v1


---

[inspect policy with multiple overlays:stderr - 1]

---

[overlay values override base values:stderr - 1]

---

[inspect policy with single overlay:stdout - 1]
exclude:
- test.rule_data_provided
- attestation_task_bundle.disallowed_task_reference
publicKey: k8s://openshift-pipelines/public-key
ruleData:
customThreshold: 0.95
teamName: platform-team
sources:
- name: Default
policy:
- oci::quay.io/enterprise-contract/ec-release-policy:latest


---

[inspect policy with single overlay:stderr - 1]

---

[deep merge of nested ruleData:stdout - 1]
ruleData:
baseKey: baseValue
overlayKey: overlayValue
sharedKey: fromOverlay
sources:
- name: Default
policy:
- oci::quay.io/example/policy:v1


---

[deep merge of nested ruleData:stderr - 1]

---

[arrays are concatenated in overlays:stdout - 1]
ruleData:
baseKey: baseValue
overlayKey: overlayValue
sharedKey: fromOverlay
sources:
- name: Default
policy:
- oci::quay.io/example/policy:v1


---

[arrays are concatenated in overlays:stderr - 1]

---

[inspect single policy file:stdout - 1]
sources:
- name: Default
policy:
- "oci::quay.io/enterprise-contract/ec-release-policy:latest"
publicKey: "k8s://openshift-pipelines/public-key"

---

[inspect single policy file:stderr - 1]

---
Loading
Loading