@@ -233,6 +233,82 @@ func TestEvaluateSimplifiedPolicies(t *testing.T) {
233233 })
234234}
235235
236+ // `policy develop eval` selects the policy by material name, as a contract does.
237+ func TestEvaluateMaterialSelection (t * testing.T ) {
238+ const (
239+ anyKindPolicy = "testdata/any-kind-policy.yaml"
240+ evidenceKind = "EVIDENCE"
241+ )
242+
243+ tempDir := t .TempDir ()
244+ logger := zerolog .New (os .Stderr )
245+
246+ passing := filepath .Join (tempDir , "pass.json" )
247+ require .NoError (t , os .WriteFile (passing , []byte (`{}` ), 0600 ))
248+ failing := filepath .Join (tempDir , "fail.json" )
249+ require .NoError (t , os .WriteFile (failing , []byte (`{"fail": true}` ), 0600 ))
250+
251+ testCases := []struct {
252+ name string
253+ policyPath string
254+ kind string
255+ materialPath string
256+ wantViolations []string
257+ wantErr string
258+ }{
259+ {
260+ name : "kind-less spec with explicit kind" ,
261+ policyPath : anyKindPolicy ,
262+ kind : evidenceKind ,
263+ materialPath : passing ,
264+ },
265+ {
266+ name : "kind-less spec reports violations" ,
267+ policyPath : anyKindPolicy ,
268+ kind : evidenceKind ,
269+ materialPath : failing ,
270+ wantViolations : []string {"material asked to fail" },
271+ },
272+ {
273+ name : "kind-less spec with auto-detected kind" ,
274+ policyPath : anyKindPolicy ,
275+ materialPath : "testdata/test-sbom.json" ,
276+ },
277+ {
278+ name : "spec with a matching kind" ,
279+ policyPath : "testdata/sbom-min-components-policy.yaml" ,
280+ kind : "SBOM_CYCLONEDX_JSON" ,
281+ materialPath : "testdata/test-sbom.json" ,
282+ wantViolations : []string {"SBOM must have at least 2 components" },
283+ },
284+ {
285+ name : "spec with a different kind is not applied" ,
286+ policyPath : "testdata/sbom-min-components-policy.yaml" ,
287+ kind : evidenceKind ,
288+ materialPath : passing ,
289+ wantErr : "no execution branch matched" ,
290+ },
291+ }
292+
293+ for _ , tc := range testCases {
294+ t .Run (tc .name , func (t * testing.T ) {
295+ result , err := Evaluate (& EvalOptions {
296+ PolicyPath : tc .policyPath ,
297+ MaterialKind : tc .kind ,
298+ MaterialPath : tc .materialPath ,
299+ }, logger )
300+ if tc .wantErr != "" {
301+ require .ErrorContains (t , err , tc .wantErr )
302+ return
303+ }
304+
305+ require .NoError (t , err )
306+ assert .False (t , result .Result .Skipped )
307+ assert .ElementsMatch (t , tc .wantViolations , result .Result .Violations )
308+ })
309+ }
310+ }
311+
236312// fixtureGitHubPAT is assembled from fragments so that this file does not itself
237313// carry a credential-shaped literal for secret scanners to flag.
238314const fixtureGitHubPAT = "ghp_erOZlZv0B1e3amrQ" + "ugdwZ8Ro2W4kDql9WPTf"
0 commit comments