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
4 changes: 2 additions & 2 deletions app/cli/cmd/policy_develop_eval.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ The command checks if there is a path in the policy for the specified kind and
evaluates the policy against the provided material or attestation.`,
Example: `
# Evaluate policy against a material file
chainloop policy eval --policy policy.yaml --material sbom.json --kind SBOM_CYCLONEDX_JSON --annotation key1=value1,key2=value2 --input key3=value3`,
chainloop policy develop eval --policy policy.yaml --material sbom.json --kind SBOM_CYCLONEDX_JSON --annotation key1=value1,key2=value2 --input key3=value3`,
RunE: func(_ *cobra.Command, _ []string) error {
opts := &action.PolicyEvalOpts{
MaterialPath: materialPath,
Expand Down Expand Up @@ -74,7 +74,7 @@ evaluates the policy against the provided material or attestation.`,
cobra.CheckErr(cmd.MarkFlagRequired("material"))
cmd.Flags().StringVar(&kind, "kind", "", fmt.Sprintf("Kind of the material: %q", schemaapi.ListAvailableMaterialKind()))
cmd.Flags().StringSliceVar(&annotations, "annotation", []string{}, "Key-value pairs of material annotations (key=value)")
cmd.Flags().StringVarP(&policyPath, "policy", "p", "policy.yaml", "Path to custom policy file")
cmd.Flags().StringVarP(&policyPath, "policy", "p", "policy.yaml", "Policy reference (./my-policy.yaml, https://my-domain.com/my-policy.yaml, chainloop://my-stored-policy)")
cmd.Flags().StringArrayVar(&inputs, "input", []string{}, "Key-value pairs of policy inputs (key=value)")
cmd.Flags().StringSliceVar(&allowedHostnames, "allowed-hostnames", []string{}, "Additional hostnames allowed for http.send requests in policies")
cmd.Flags().BoolVarP(&debug, "debug", "", false, "Include detailed evaluation inputs/outputs in JSON output and enable verbose logging")
Expand Down
4 changes: 2 additions & 2 deletions app/cli/documentation/cli-reference.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -2858,7 +2858,7 @@ Examples
```

Evaluate policy against a material file
chainloop policy eval --policy policy.yaml --material sbom.json --kind SBOM_CYCLONEDX_JSON --annotation key1=value1,key2=value2 --input key3=value3
chainloop policy develop eval --policy policy.yaml --material sbom.json --kind SBOM_CYCLONEDX_JSON --annotation key1=value1,key2=value2 --input key3=value3
```

Options
Expand All @@ -2871,7 +2871,7 @@ Options
--input stringArray Key-value pairs of policy inputs (key=value)
--kind string Kind of the material: ["ARTIFACT" "ATTESTATION" "BLACKDUCK_SCA_JSON" "CHAINLOOP_RUNNER_CONTEXT" "CONTAINER_IMAGE" "CSAF_INFORMATIONAL_ADVISORY" "CSAF_SECURITY_ADVISORY" "CSAF_SECURITY_INCIDENT_RESPONSE" "CSAF_VEX" "EVIDENCE" "GHAS_CODE_SCAN" "GHAS_DEPENDENCY_SCAN" "GHAS_SECRET_SCAN" "GITLAB_SECURITY_REPORT" "HELM_CHART" "JACOCO_XML" "JUNIT_XML" "OPENVEX" "SARIF" "SBOM_CYCLONEDX_JSON" "SBOM_SPDX_JSON" "SLSA_PROVENANCE" "STRING" "TWISTCLI_SCAN_JSON" "ZAP_DAST_ZIP"]
--material string Path to material or attestation file
-p, --policy string Path to custom policy file (default "policy.yaml")
-p, --policy string Policy reference (./my-policy.yaml, https://my-domain.com/my-policy.yaml, chainloop://my-stored-policy) (default "policy.yaml")
```

Options inherited from parent commands
Expand Down
32 changes: 21 additions & 11 deletions app/cli/internal/policydevel/eval.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"fmt"
"os"

controlplanev1 "github.com/chainloop-dev/chainloop/app/controlplane/api/controlplane/v1"
v1 "github.com/chainloop-dev/chainloop/app/controlplane/api/workflowcontract/v1"
"github.com/chainloop-dev/chainloop/pkg/casclient"
"github.com/chainloop-dev/chainloop/pkg/policies"
Expand All @@ -34,13 +35,14 @@ const (
)

type EvalOptions struct {
PolicyPath string
MaterialKind string
Annotations map[string]string
MaterialPath string
Inputs map[string]string
AllowedHostnames []string
Debug bool
PolicyPath string
MaterialKind string
Annotations map[string]string
MaterialPath string
Inputs map[string]string
AllowedHostnames []string
Debug bool
AttestationClient controlplanev1.AttestationServiceClient
}

type EvalResult struct {
Expand Down Expand Up @@ -74,7 +76,7 @@ func Evaluate(opts *EvalOptions, logger zerolog.Logger) (*EvalSummary, error) {
material.Annotations = opts.Annotations

// 3. Verify material against policy
summary, err := verifyMaterial(policies, material, opts.MaterialPath, opts.Debug, opts.AllowedHostnames, &logger)
summary, err := verifyMaterial(policies, material, opts.MaterialPath, opts.Debug, opts.AllowedHostnames, opts.AttestationClient, &logger)
if err != nil {
return nil, err
}
Expand All @@ -83,18 +85,26 @@ func Evaluate(opts *EvalOptions, logger zerolog.Logger) (*EvalSummary, error) {
}

func createPolicies(policyPath string, inputs map[string]string) (*v1.Policies, error) {
// Check if the policy path already has a scheme (chainloop://, http://, https://, file://)
ref := policyPath
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

check if there is smth already on the way we parse the policies in the contracts

scheme, _ := policies.RefParts(policyPath)
if scheme == "" {
// Default to file://
ref = fmt.Sprintf("file://%s", policyPath)
}
Comment on lines +90 to +94
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is sweet, but is this a breaking change, in other words, would comments that used to provide a file path work out of the box?
Do you need to provide file:// always now?

It works out of the box, file:// is optional, backwards compatibility is held by this fragment and that's the only reason we have to check for scheme.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

awesome, that makes sense.


return &v1.Policies{
Materials: []*v1.PolicyAttachment{
{
Policy: &v1.PolicyAttachment_Ref{Ref: fmt.Sprintf("file://%s", policyPath)},
Policy: &v1.PolicyAttachment_Ref{Ref: ref},
With: inputs,
},
},
Attestation: nil,
}, nil
}

func verifyMaterial(pol *v1.Policies, material *v12.Attestation_Material, materialPath string, debug bool, allowedHostnames []string, logger *zerolog.Logger) (*EvalSummary, error) {
func verifyMaterial(pol *v1.Policies, material *v12.Attestation_Material, materialPath string, debug bool, allowedHostnames []string, attestationClient controlplanev1.AttestationServiceClient, logger *zerolog.Logger) (*EvalSummary, error) {
var opts []policies.PolicyVerifierOption
if len(allowedHostnames) > 0 {
opts = append(opts, policies.WithAllowedHostnames(allowedHostnames...))
Expand All @@ -103,7 +113,7 @@ func verifyMaterial(pol *v1.Policies, material *v12.Attestation_Material, materi
opts = append(opts, policies.WithIncludeRawData(debug))
opts = append(opts, policies.WithEnablePrint(enablePrint))

v := policies.NewPolicyVerifier(pol, nil, logger, opts...)
v := policies.NewPolicyVerifier(pol, attestationClient, logger, opts...)
policyEvs, err := v.VerifyMaterial(context.Background(), material, materialPath)
if err != nil {
return nil, err
Expand Down
22 changes: 15 additions & 7 deletions app/cli/pkg/action/policy_develop_eval.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
package action

import (
pb "github.com/chainloop-dev/chainloop/app/controlplane/api/controlplane/v1"

"github.com/chainloop-dev/chainloop/app/cli/internal/policydevel"
)

Expand All @@ -42,14 +44,20 @@ func NewPolicyEval(opts *PolicyEvalOpts, actionOpts *ActionsOpts) (*PolicyEval,
}

func (action *PolicyEval) Run() (*policydevel.EvalSummary, error) {
var attClient pb.AttestationServiceClient
if action.CPConnection != nil {
attClient = pb.NewAttestationServiceClient(action.CPConnection)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we might want to make sure this is not mandatory, I mean, if you do not provide a connection, the command should still work with file:// or http://

Copy link
Collaborator Author

@Piskoo Piskoo Nov 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not mandatory, we use it if it's available otherwise it works the same way as before and it will return jwt related error to the user for chainloop:// policies

}

evalOpts := &policydevel.EvalOptions{
PolicyPath: action.opts.PolicyPath,
MaterialKind: action.opts.Kind,
Annotations: action.opts.Annotations,
MaterialPath: action.opts.MaterialPath,
Inputs: action.opts.Inputs,
AllowedHostnames: action.opts.AllowedHostnames,
Debug: action.opts.Debug,
PolicyPath: action.opts.PolicyPath,
MaterialKind: action.opts.Kind,
Annotations: action.opts.Annotations,
MaterialPath: action.opts.MaterialPath,
Inputs: action.opts.Inputs,
AllowedHostnames: action.opts.AllowedHostnames,
Debug: action.opts.Debug,
AttestationClient: attClient,
}

// Evaluate policy
Expand Down
6 changes: 3 additions & 3 deletions pkg/policies/loader.go
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ func unmarshallResource(raw []byte, ref string, digest string, dest proto.Messag

// IsProviderScheme takes a policy reference and returns whether it's referencing to an external provider or not
func IsProviderScheme(ref string) bool {
scheme, _ := refParts(ref)
scheme, _ := RefParts(ref)
return scheme == chainloopScheme || scheme == ""
}

Expand Down Expand Up @@ -306,7 +306,7 @@ func ProviderParts(reference string) *ProviderRef {
}

func ensureScheme(ref string, expected ...string) (string, error) {
scheme, id := refParts(ref)
scheme, id := RefParts(ref)
for _, ex := range expected {
if scheme == ex {
return id, nil
Expand All @@ -316,7 +316,7 @@ func ensureScheme(ref string, expected ...string) (string, error) {
return "", fmt.Errorf("unexpected policy reference scheme: %q", scheme)
}

func refParts(ref string) (string, string) {
func RefParts(ref string) (string, string) {
parts := strings.SplitN(ref, "://", 2)
if len(parts) == 2 {
return parts[0], parts[1]
Expand Down
2 changes: 1 addition & 1 deletion pkg/policies/policies.go
Original file line number Diff line number Diff line change
Expand Up @@ -406,7 +406,7 @@ func (pv *PolicyVerifier) getLoader(attachment *v1.PolicyAttachment) (Loader, er
}

var loader Loader
scheme, _ := refParts(ref)
scheme, _ := RefParts(ref)
switch scheme {
// No scheme means chainloop loader
case chainloopScheme, "":
Expand Down
2 changes: 1 addition & 1 deletion pkg/policies/policy_groups.go
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ func getGroupLoader(attachment *v1.PolicyGroupAttachment, opts *LoadPolicyGroupO
}

var loader GroupLoader
scheme, _ := refParts(ref)
scheme, _ := RefParts(ref)
switch scheme {
// No scheme means chainloop loader
case chainloopScheme, "":
Expand Down
Loading