@@ -694,13 +694,16 @@ func (c *Crafter) addMaterial(ctx context.Context, m *schemaapi.CraftingSchema_M
694694 return i .MaterialName == m .Name
695695 })
696696
697+ projectName , projectVersion := c .projectContext ()
698+
697699 pgv := policies .NewPolicyGroupVerifier (
698700 c .CraftingState .GetPolicyGroups (),
699701 c .CraftingState .GetPolicies (),
700702 c .attClient ,
701703 c .Logger ,
702704 policies .WithAllowedHostnames (c .CraftingState .Attestation .PoliciesAllowedHostnames ... ),
703705 policies .WithDefaultGate (c .CraftingState .Attestation .GetBlockOnPolicyViolation ()),
706+ policies .WithProjectContext (projectName , projectVersion ),
704707 )
705708 policyGroupResults , err := pgv .VerifyMaterial (ctx , mt , value )
706709 if err != nil {
@@ -718,6 +721,7 @@ func (c *Crafter) addMaterial(ctx context.Context, m *schemaapi.CraftingSchema_M
718721 c .Logger ,
719722 policies .WithAllowedHostnames (c .CraftingState .Attestation .PoliciesAllowedHostnames ... ),
720723 policies .WithDefaultGate (c .CraftingState .Attestation .GetBlockOnPolicyViolation ()),
724+ policies .WithProjectContext (projectName , projectVersion ),
721725 )
722726 policyResults , err := pv .VerifyMaterial (ctx , mt , value )
723727 if err != nil {
@@ -745,6 +749,21 @@ func (c *Crafter) addMaterial(ctx context.Context, m *schemaapi.CraftingSchema_M
745749 return mt , nil
746750}
747751
752+ // projectContext returns the project name and version from the workflow
753+ // metadata so policy verifiers can pass them to the engine. Either may be
754+ // empty (e.g. dry-run before workflow metadata is populated); built-ins
755+ // must degrade gracefully in that case.
756+ func (c * Crafter ) projectContext () (string , string ) {
757+ wf := c .CraftingState .GetAttestation ().GetWorkflow ()
758+ version := wf .GetVersion ().GetVersion ()
759+ if version == "" {
760+ // Fall back to the deprecated flat field for state written by older clients.
761+ //nolint:staticcheck // intentional fallback for backwards compatibility
762+ version = wf .GetProjectVersion ()
763+ }
764+ return wf .GetProject (), version
765+ }
766+
748767// policyEvalMatches returns true if two policy evaluations refer to the same policy
749768// with the same arguments. It treats nil and empty maps as equivalent to handle
750769// protojson round-trip serialization where empty maps are omitted.
@@ -755,11 +774,14 @@ func policyEvalMatches(a, b *api.PolicyEvaluation) bool {
755774// EvaluateAttestationPolicies evaluates the attestation-level policies and stores them in the attestation state.
756775// The phase parameter controls which policies are evaluated based on their attestation_phases spec field.
757776func (c * Crafter ) EvaluateAttestationPolicies (ctx context.Context , attestationID string , statement * intoto.Statement , phase policies.EvalPhase ) error {
777+ projectName , projectVersion := c .projectContext ()
778+
758779 // evaluate attestation-level policies
759780 pv := policies .NewPolicyVerifier (c .CraftingState .GetPolicies (), c .attClient , c .Logger ,
760781 policies .WithAllowedHostnames (c .CraftingState .Attestation .PoliciesAllowedHostnames ... ),
761782 policies .WithDefaultGate (c .CraftingState .Attestation .GetBlockOnPolicyViolation ()),
762783 policies .WithEvalPhase (phase ),
784+ policies .WithProjectContext (projectName , projectVersion ),
763785 )
764786 policyEvaluations , err := pv .VerifyStatement (ctx , statement )
765787 if err != nil {
@@ -770,6 +792,7 @@ func (c *Crafter) EvaluateAttestationPolicies(ctx context.Context, attestationID
770792 policies .WithAllowedHostnames (c .CraftingState .Attestation .PoliciesAllowedHostnames ... ),
771793 policies .WithDefaultGate (c .CraftingState .Attestation .GetBlockOnPolicyViolation ()),
772794 policies .WithEvalPhase (phase ),
795+ policies .WithProjectContext (projectName , projectVersion ),
773796 )
774797 policyGroupResults , err := pgv .VerifyStatement (ctx , statement )
775798 if err != nil {
0 commit comments