Alanxtl commented on code in PR #822:
URL: https://github.com/apache/dubbo-go-pixiu/pull/822#discussion_r2576252157


##########
pkg/filter/opa/opa.go:
##########
@@ -127,15 +186,165 @@ func (f *Filter) Decode(c *http.HttpContext) 
filter.FilterStatus {
                "params":      c.Params,
        }
 
+       // Server mode (priority)
+       if f.httpClient != nil {
+               return f.evaluateServer(c, input)
+       }
+
+       // Embedded mode (backward compatibility)
+       if f.preparedQuery != nil {
+               return f.evaluateEmbedded(c, input)
+       }
+
+       logger.Error("OPA filter not initialized properly")
+       errResp := contextHttp.InternalError.WithError(fmt.Errorf("OPA filter 
not initialized"))
+       c.SendLocalReply(errResp.Status, errResp.ToJSON())
+       return filter.Stop
+}
+
+// evaluateEmbedded evaluates the policy using embedded OPA engine
+func (f *Filter) evaluateEmbedded(c *contextHttp.HttpContext, input 
map[string]any) filter.FilterStatus {
        results, err := f.preparedQuery.Eval(c.Ctx, rego.EvalInput(input))
        if err != nil {
-               logger.Error("OPA evaluation error: %v\n", err)
+               logger.Errorf("OPA embedded evaluation error: %v", err)
+               errResp := contextHttp.InternalError.WithError(err)
+               c.SendLocalReply(errResp.Status, errResp.ToJSON())
                return filter.Stop
        }
 
-       if len(results) == 0 || results[0].Expressions[0].Value != true {
+       if len(results) == 0 {
+               logger.Debugf("OPA embedded policy returned empty result for 
request: %s %s", input["method"], input["path"])
+               errResp := contextHttp.Forbidden.New()
+               c.SendLocalReply(errResp.Status, errResp.ToJSON())
+               return filter.Stop
+       }
+
+       // Extract decision from result (supports both boolean and object 
formats)
+       allow := extractDecision(results[0].Expressions[0].Value)
+       if !allow {
+               logger.Debugf("OPA embedded policy denied request: %s %s", 
input["method"], input["path"])
+               errResp := contextHttp.Forbidden.New()
+               c.SendLocalReply(errResp.Status, errResp.ToJSON())
                return filter.Stop
        }
 
        return filter.Continue
 }
+
+// evaluateServer evaluates the policy by calling OPA server REST API
+func (f *Filter) evaluateServer(c *contextHttp.HttpContext, input 
map[string]any) filter.FilterStatus {
+       // Construct request body according to OPA REST API specification
+       requestBody := map[string]any{
+               "input": input,
+       }
+
+       jsonData, err := json.Marshal(requestBody)
+       if err != nil {
+               logger.Errorf("Failed to marshal OPA request: %v", err)
+               errResp := contextHttp.InternalError.WithError(err)
+               c.SendLocalReply(errResp.Status, errResp.ToJSON())
+               return filter.Stop
+       }
+
+       // Construct HTTP request
+       url := f.cfg.ServerURL + f.cfg.DecisionPath
+       req, err := http.NewRequestWithContext(c.Ctx, "POST", url, 
bytes.NewBuffer(jsonData))
+       if err != nil {
+               logger.Errorf("Failed to create OPA request: %v", err)
+               errResp := contextHttp.InternalError.WithError(err)
+               c.SendLocalReply(errResp.Status, errResp.ToJSON())
+               return filter.Stop
+       }
+
+       req.Header.Set("Content-Type", "application/json")
+       if f.cfg.BearerToken != "" {
+               req.Header.Set("Authorization", "Bearer "+f.cfg.BearerToken)
+       }
+
+       // Send request to OPA server
+       resp, err := f.httpClient.Do(req)
+       if err != nil {
+               logger.Errorf("OPA server request failed: %v", err)
+               // Check if it's a timeout error using net.Error interface
+               if netErr, ok := err.(interface{ Timeout() bool }); ok && 
netErr.Timeout() {
+                       errResp := contextHttp.GatewayTimeout.WithError(err)
+                       c.SendLocalReply(errResp.Status, errResp.ToJSON())
+               } else {
+                       errResp := contextHttp.ServiceUnavailable.WithError(err)
+                       c.SendLocalReply(errResp.Status, errResp.ToJSON())
+               }
+               return filter.Stop
+       }
+       defer resp.Body.Close()
+
+       // Check HTTP status code
+       if resp.StatusCode != 200 {
+               body, err := io.ReadAll(resp.Body)
+               if err != nil {
+                       logger.Errorf("Failed to read OPA server response body: 
%v", err)
+                       body = []byte("") 

Review Comment:
   ```suggestion
                        body = []byte("")
   ```



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to