1616package policies
1717
1818import (
19+ "bytes"
1920 "encoding/json"
2021 "fmt"
2122 "io"
@@ -31,6 +32,7 @@ import (
3132
3233const (
3334 policiesEndpoint = "policies"
35+ validateAction = "validate"
3436 groupsEndpoint = "groups"
3537
3638 digestParam = "digest"
@@ -50,6 +52,15 @@ type ProviderResponse struct {
5052 Raw * RawMessage `json:"raw"`
5153}
5254
55+ type ValidateRequest struct {
56+ PolicyAttachment string `json:"policy_attachment"`
57+ }
58+
59+ type ValidateResponse struct {
60+ Valid bool `json:"valid"`
61+ ValidationErrors []string `json:"validationErrors"`
62+ }
63+
5364type RawMessage struct {
5465 Body []byte `json:"body"`
5566 Format string `json:"format"`
@@ -88,6 +99,73 @@ func (p *PolicyProvider) Resolve(policyName, orgName, token string) (*schemaapi.
8899 return & policy , createRef (url , policyName , providerDigest , orgName ), nil
89100}
90101
102+ func (p * PolicyProvider ) ValidateAttachment (att * schemaapi.PolicyAttachment , token string ) error {
103+ endpoint , err := url .JoinPath (p .url , policiesEndpoint , validateAction )
104+ if err != nil {
105+ return fmt .Errorf ("invalid url: %w" , err )
106+ }
107+ url , err := url .Parse (endpoint )
108+ if err != nil {
109+ return fmt .Errorf ("error parsing policy provider URL: %w" , err )
110+ }
111+
112+ attBody , err := protojson .Marshal (att )
113+ if err != nil {
114+ return fmt .Errorf ("error serializing policy attachment: %w" , err )
115+ }
116+
117+ validateReq := & ValidateRequest {
118+ PolicyAttachment : string (attBody ),
119+ }
120+
121+ reqBody , err := json .Marshal (validateReq )
122+ if err != nil {
123+ return fmt .Errorf ("error serializing policy validation request: %w" , err )
124+ }
125+
126+ req , err := http .NewRequest ("POST" , url .String (), bytes .NewReader (reqBody ))
127+ if err != nil {
128+ return fmt .Errorf ("error creating policy request: %w" , err )
129+ }
130+
131+ req .Header .Set ("Authorization" , fmt .Sprintf ("Bearer %s" , token ))
132+ req .Header .Set ("Content-Type" , "application/json" )
133+
134+ // make the request
135+ resp , err := http .DefaultClient .Do (req )
136+ if err != nil {
137+ return fmt .Errorf ("error executing policy request: %w" , err )
138+ }
139+
140+ if resp .StatusCode != http .StatusOK {
141+ if resp .StatusCode == http .StatusNotFound {
142+ // Ignore endpoint not found as it might not be implemented by the provider
143+ return nil
144+ }
145+
146+ return fmt .Errorf ("expected status code 200 but got %d" , resp .StatusCode )
147+ }
148+
149+ resBytes , err := io .ReadAll (resp .Body )
150+ if err != nil {
151+ return fmt .Errorf ("error reading validation response: %w" , err )
152+ }
153+
154+ defer resp .Body .Close ()
155+
156+ // unmarshall response
157+ var response ValidateResponse
158+ if err := json .Unmarshal (resBytes , & response ); err != nil {
159+ return fmt .Errorf ("error unmarshalling validation response: %w" , err )
160+ }
161+
162+ if ! response .Valid {
163+ return fmt .Errorf ("validation failures: %v" , response .ValidationErrors )
164+ }
165+
166+ return nil
167+ }
168+
91169// ResolveGroup calls remote provider for retrieving a policy group definition
92170func (p * PolicyProvider ) ResolveGroup (groupName , orgName , token string ) (* schemaapi.PolicyGroup , * PolicyReference , error ) {
93171 if groupName == "" || token == "" {
0 commit comments