OPA-PDP URL changes and bugfix 85/139785/5
authorDeena Mukundan <dm00536893@techmahindra.com>
Mon, 23 Dec 2024 09:19:53 +0000 (10:19 +0100)
committerDeena Mukundan <dm00536893@techmahindra.com>
Mon, 23 Dec 2024 14:30:03 +0000 (15:30 +0100)
Issue-ID: POLICY-5222
Change-Id: Ia3c214b93f3b5fa18e482e100ac8c255544e0ba6
Signed-off-by: Deena Mukundan <dm00536893@techmahindra.com>
17 files changed:
Makefile
api/openapi.yaml
api/register-handlers.go
api/register-handlers_test.go
pkg/decision/decision-provider.go
pkg/kafkacomm/handler/pdp_state_change_handler_test.go
pkg/kafkacomm/publisher/1 [new file with mode: 0644]
pkg/kafkacomm/publisher/pdp-heartbeat.go
pkg/kafkacomm/publisher/pdp-heartbeat_test.go
test/README.md
test/data/docs/data.json [new file with mode: 0644]
test/data/vehicle/data.json [new file with mode: 0644]
test/data/zone/data.json [new file with mode: 0644]
test/policies/docs/policy.rego [new file with mode: 0644]
test/policies/vehicle/policy.rego [new file with mode: 0644]
test/policies/zone/policy.rego [new file with mode: 0644]
version

index 5521995..f6d0ab2 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -14,7 +14,7 @@ deploy: build_image
 
 .PHONY: test
 test:
-       @go test -v ./...
+       @go test -v -p 1 ./...
 
 format:
        @go fmt ./...
index a9b8191..bd94ec2 100644 (file)
@@ -27,8 +27,8 @@ info:
       name: Deena Mukundan\r
       email: dm00536893@techmahindra.com\r
 servers:\r
-- url: http://policy-opa-pdp:8282/policy/pdpx/v1\r
-- url: https://policy-opa-pdp:8282/policy/pdpx/v1\r
+- url: http://policy-opa-pdp:8282/policy/pdpo/v1\r
+- url: https://policy-opa-pdp:8282/policy/pdpo/v1\r
 tags:\r
 - name: Decision\r
 - name: Statistics\r
@@ -110,7 +110,7 @@ paths:
       - basicAuth: []\r
       x-interface info:\r
         last-mod-release: Paris\r
-        pdpx-version: 1.0.0\r
+        pdpo-version: 1.0.0\r
       x-codegen-request-body-name: body\r
   /healthcheck:\r
     get:\r
@@ -170,13 +170,13 @@ paths:
       - basicAuth: []\r
       x-interface info:\r
         last-mod-release: Paris\r
-        pdpx-version: 1.0.0\r
+        pdpo-version: 1.0.0\r
   /statistics:\r
     get:\r
       tags:\r
       - Statistics\r
       summary: Fetch current statistics\r
-      description: Provides current statistics of the Policy OPA PDP component\r
+      description: Provides current statistics of the Policy OPA PDP component \r
       operationId: statistics\r
       parameters:\r
       - name: X-ONAP-RequestID\r
@@ -229,7 +229,7 @@ paths:
       - basicAuth: []\r
       x-interface info:\r
         last-mod-release: Paris\r
-        pdpx-version: 1.0.0\r
+        pdpo-version: 1.0.0\r
 components:\r
   schemas:\r
     ErrorResponse:\r
index 4b21314..c5eb5df 100644 (file)
@@ -35,7 +35,7 @@ func RegisterHandlers() {
 
        // Handler for OPA decision making
        opaDecisionHandler := http.HandlerFunc(decision.OpaDecision)
-       http.Handle("/policy/pdpx/v1/decision", basicAuth(opaDecisionHandler))
+       http.Handle("/policy/pdpo/v1/decision", basicAuth(opaDecisionHandler))
 
        //This api is used internally by OPA-SDK
        bundleServerHandler := http.HandlerFunc(bundleserver.GetBundle)
@@ -47,11 +47,11 @@ func RegisterHandlers() {
 
        // Handler for health checks
        healthCheckHandler := http.HandlerFunc(healthcheck.HealthCheckHandler)
-       http.HandleFunc("/policy/pdpx/v1/healthcheck", basicAuth(healthCheckHandler))
+       http.HandleFunc("/policy/pdpo/v1/healthcheck", basicAuth(healthCheckHandler))
 
        // Handler for statistics report
        statisticsReportHandler := http.HandlerFunc(metrics.FetchCurrentStatistics)
-       http.HandleFunc("/policy/pdpx/v1/statistics", basicAuth(statisticsReportHandler))
+       http.HandleFunc("/policy/pdpo/v1/statistics", basicAuth(statisticsReportHandler))
 
 }
 
index 801cb0e..f67c1f5 100644 (file)
@@ -43,10 +43,10 @@ func TestRegisterHandlers(t *testing.T) {
                handler    http.HandlerFunc
                statusCode int
        }{
-               {"/policy/pdpx/v1/decision", decision.OpaDecision, http.StatusUnauthorized},
+               {"/policy/pdpo/v1/decision", decision.OpaDecision, http.StatusUnauthorized},
                {"/opa/bundles/", bundleserver.GetBundle, http.StatusInternalServerError},
                {"/ready", readinessProbe, http.StatusOK},
-               {"/policy/pdpx/v1/healthcheck", healthcheck.HealthCheckHandler, http.StatusUnauthorized},
+               {"/policy/pdpo/v1/healthcheck", healthcheck.HealthCheckHandler, http.StatusUnauthorized},
        }
 
        for _, tt := range tests {
index 48d6edf..5f45668 100644 (file)
@@ -76,7 +76,7 @@ func writeErrorJSONResponse(res http.ResponseWriter, status int, errorDescriptio
 // creates a decision response based on the provided parameters
 func createSuccessDecisionResponse(statusMessage, decision, policyName string, output map[string]interface{}) *oapicodegen.OPADecisionResponse {
        return &oapicodegen.OPADecisionResponse{
-               StatusMessage: &statusMessage,
+                StatusMessage: &statusMessage,
                Decision:      (*oapicodegen.OPADecisionResponseDecision)(&decision),
                PolicyName:    &policyName,
                Output:        &output,
@@ -128,13 +128,14 @@ func OpaDecision(res http.ResponseWriter, req *http.Request) {
                log.Debugf("%s: %s", key, value)
        }
        // Check if the system is in an active state
+
        if pdpstate.GetCurrentState() != model.Active {
                msg := " System Is In PASSIVE State so Unable To Handle Decision wait until it becomes ACTIVE"
                errorMsg := " System Is In PASSIVE State so error Handling the request"
                decisionExc := createDecisionExceptionResponse(http.StatusInternalServerError, msg, []string{errorMsg}, "")
                metrics.IncrementTotalErrorCount()
                writeErrorJSONResponse(res, http.StatusInternalServerError, msg, *decisionExc)
-               return
+               return
        }
        ctx := context.Background()
 
@@ -184,7 +185,7 @@ func OpaDecision(res http.ResponseWriter, req *http.Request) {
        log.Debugf("SDK making a decision")
        options := sdk.DecisionOptions{Path: *decisionReq.PolicyName, Input: decisionReq.Input}
 
-       decision, err := opa.Decision(ctx, options)
+       decision, decision_err := opa.Decision(ctx, options)
 
        jsonOutput, err := json.MarshalIndent(decision, "", "  ")
        if err != nil {
@@ -194,18 +195,18 @@ func OpaDecision(res http.ResponseWriter, req *http.Request) {
        log.Debugf("RAW opa Decision output:\n%s\n", string(jsonOutput))
 
        // Check for errors in the OPA decision
-       if err != nil {
-               if strings.Contains(err.Error(), "opa_undefined_error") {
-                       decisionRes := createSuccessDecisionResponse(err.Error(), string(oapicodegen.INDETERMINATE),
+       if decision_err != nil {
+               if strings.Contains(decision_err.Error(), "opa_undefined_error") {
+                       decisionRes := createSuccessDecisionResponse(decision_err.Error(), string(oapicodegen.INDETERMINATE),
                                *decisionReq.PolicyName, nil)
                        writeOpaJSONResponse(res, http.StatusOK, *decisionRes)
                        metrics.IncrementIndeterminantDecisionsCount()
                        return
                } else {
                        decisionExc := createDecisionExceptionResponse(http.StatusBadRequest, "Error from OPA while making decision",
-                               []string{err.Error()}, *decisionReq.PolicyName)
+                               []string{decision_err.Error()}, *decisionReq.PolicyName)
                        metrics.IncrementTotalErrorCount()
-                       writeErrorJSONResponse(res, http.StatusBadRequest, err.Error(), *decisionExc)
+                       writeErrorJSONResponse(res, http.StatusBadRequest, decision_err.Error(), *decisionExc)
                        return
                }
        }
@@ -310,8 +311,8 @@ func OpaDecision(res http.ResponseWriter, req *http.Request) {
 
        default:
                // Handle unexpected types in decision.Result
-               decisionRes := createSuccessDecisionResponse("Invalid decision result format", string(oapicodegen.DENY), *decisionReq.PolicyName, nil)
-               metrics.IncrementDenyDecisionsCount()
+               decisionRes := createSuccessDecisionResponse("Invalid decision result format", string(oapicodegen.INDETERMINATE), *decisionReq.PolicyName, nil)
+               metrics.IncrementIndeterminantDecisionsCount()
                writeOpaJSONResponse(res, http.StatusOK, *decisionRes)
                return
        }
index 67edd6f..da3832b 100644 (file)
@@ -24,7 +24,7 @@ import (
        "policy-opa-pdp/pkg/model"
        "policy-opa-pdp/pkg/pdpstate"
        "testing"
-
+       "fmt"
        "github.com/stretchr/testify/assert"
        "github.com/stretchr/testify/mock"
 )
@@ -56,6 +56,7 @@ func TestPdpStateChangeMessageHandler(t *testing.T) {
                expectedState string
                mockError     error
                expectError   bool
+               checkNotEqual bool
        }{
                {
                        name:          "Valid state change",
@@ -63,20 +64,36 @@ func TestPdpStateChangeMessageHandler(t *testing.T) {
                        expectedState: "ACTIVE",
                        mockError:     nil,
                        expectError:   false,
+                       checkNotEqual: false,
                },
                {
                        name:        "Invalid JSON",
                        message:     []byte(`{"state":}`),
                        mockError:   nil,
                        expectError: true,
+                       checkNotEqual: true,
                },
+               {
+            name:        "Error in SendStateChangeResponse",
+            message:       []byte(`{"state":"PASSIVE"}`),
+            expectedState: "PASSIVE",
+            mockError:   assert.AnError,
+            expectError: true,
+            checkNotEqual: false,
+        },
        }
 
-       for _, tt := range tests {
+       for i, tt := range tests {
                t.Run(tt.name, func(t *testing.T) {
                        // Set up the mock to return the expected error
-                       mockSender.On("SendStateChangeResponse", mock.Anything, mock.Anything).Return(tt.mockError)
-                       mockSender.On("SendPdpStatus", mock.Anything).Return(nil)
+                       if i == 0 {
+                               mockSender.On("SendStateChangeResponse", mock.Anything, mock.Anything).Return(tt.mockError).Once()
+                               mockSender.On("SendPdpStatus", mock.Anything).Return(nil).Once()
+                       } else if i != 1 {
+                mockSender.On("SendStateChangeResponse", mock.Anything, mock.Anything).Return(fmt.Errorf("failed to send PDP status"))
+                mockSender.On("SendPdpStatus", mock.Anything).Return(fmt.Errorf("failed to send PDP status"))
+            }
+
 
                        // Call the handler
                        err := PdpStateChangeMessageHandler(tt.message, mockSender)
@@ -86,7 +103,11 @@ func TestPdpStateChangeMessageHandler(t *testing.T) {
                                assert.Error(t, err)
                        } else {
                                assert.NoError(t, err)
-                               assert.Equal(t, tt.expectedState, pdpstate.GetState().String())
+                               if tt.checkNotEqual {
+                    assert.NotEqual(t, tt.expectedState, pdpstate.GetState().String())
+                } else {
+                    assert.Equal(t, tt.expectedState, pdpstate.GetState().String())
+                }
                        }
 
                })
diff --git a/pkg/kafkacomm/publisher/1 b/pkg/kafkacomm/publisher/1
new file mode 100644 (file)
index 0000000..bfd5272
--- /dev/null
@@ -0,0 +1,148 @@
+// -
+//   ========================LICENSE_START=================================
+//   Copyright (C) 2024: Deutsche Telekom
+//
+//   Licensed under the Apache License, Version 2.0 (the "License");
+//   you may not use this file except in compliance with the License.
+//   You may obtain a copy of the License at
+//
+//        http://www.apache.org/licenses/LICENSE-2.0
+//
+//   Unless required by applicable law or agreed to in writing, software
+//   distributed under the License is distributed on an "AS IS" BASIS,
+//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//   See the License for the specific language governing permissions and
+//   limitations under the License.
+//   SPDX-License-Identifier: Apache-2.0
+//   ========================LICENSE_END===================================
+//
+
+package publisher
+
+import (
+       /*      "fmt"
+               "policy-opa-pdp/cfg"
+               "policy-opa-pdp/consts"
+               "policy-opa-pdp/pkg/log"
+               "policy-opa-pdp/pkg/model"
+               "policy-opa-pdp/pkg/pdpstate"*/
+       "errors"
+       "github.com/stretchr/testify/assert"
+       "github.com/stretchr/testify/mock"
+       "policy-opa-pdp/pkg/kafkacomm/publisher/mocks"
+       "testing"
+       //      "time"
+       /*      "github.com/google/uuid"*/)
+
+var (
+// ticker          *time.Ticker
+// stopChan        chan bool
+// currentInterval int64
+)
+
+/*
+Success Case 1
+TestStartHeartbeatIntervalTimer_ValidInterval
+Description: Test starting the heartbeat interval timer with a valid interval.
+Input: intervalMs = 1000
+Expected Output: The ticker starts with an interval of 1000 milliseconds, and heartbeat messages are sent at this interval.
+*/
+func TestStartHeartbeatIntervalTimer_ValidInterval(t *testing.T) {
+
+       intervalMs := int64(1000)
+       mockSender := new(mocks.PdpStatusSender)
+       mockSender.On("SendPdpStatus", mock.Anything).Return(nil)
+
+       StartHeartbeatIntervalTimer(intervalMs, mockSender)
+       mu.Lock()
+       defer mu.Unlock()
+       if ticker == nil {
+               t.Errorf("Expected ticker to be initialized")
+       }
+       if currentInterval != intervalMs {
+               t.Errorf("Expected currentInterval to be %d, got %d", intervalMs, currentInterval)
+       }
+}
+
+/*
+Failure Case 1
+TestStartHeartbeatIntervalTimer_InvalidInterval
+Description: Test starting the heartbeat interval timer with an invalid interval.
+Input: intervalMs = -1000
+Expected Output: The function should handle the invalid interval gracefully, possibly by logging an error message and not starting the ticker.
+*/
+func TestStartHeartbeatIntervalTimer_InvalidInterval(t *testing.T) {
+       intervalMs := int64(-1000)
+       mockSender := new(mocks.PdpStatusSender)
+       mockSender.On("SendPdpStatus", mock.Anything).Return(nil)
+
+       StartHeartbeatIntervalTimer(intervalMs, mockSender)
+       mu.Lock()
+       defer mu.Unlock()
+
+       if ticker != nil {
+               t.Log("Expected ticker to be nil for invalid interval")
+       }
+}
+
+/*
+TestSendPDPHeartBeat_Success 2
+Description: Test sending a heartbeat successfully.
+Input: Valid pdpStatus object
+Expected Output: Heartbeat message is sent successfully, and a debug log "Message sent successfully" is generated.
+*/
+/*
+func TestSendPDPHeartBeat_Success(t *testing.T) {
+
+       mockSender := new(mocks.PdpStatusSender)
+       mockSender.On("SendPdpStatus", mock.Anything).Return(nil)
+       err := sendPDPHeartBeat(mockSender)
+       assert.NoError(t, err)
+}
+*/
+/*
+TestSendPDPHeartBeat_Failure 2
+Description: Test failing to send a heartbeat.
+Input: Invalid pdpStatus object or network failure
+Expected Output: An error occurs while sending the heartbeat, and a warning log "Error producing message: ..." is generated.
+*/
+/*
+func TestSendPDPHeartBeat_Failure(t *testing.T) {
+       // Mock SendPdpStatus to return an error
+       mockSender := new(mocks.PdpStatusSender)
+       mockSender.On("SendPdpStatus", mock.Anything).Return(errors.New("Error producing message"))
+       err := sendPDPHeartBeat(mockSender)
+       assert.Error(t, err)
+}
+*/
+
+/*
+TestStopTicker_Success 3
+Description: Test stopping the ticker.
+Input: Ticker is running
+Expected Output: The ticker stops, and the stop channel is closed.
+*/
+func TestStopTicker_Success(t *testing.T) {
+       mockSender := new(mocks.PdpStatusSender)
+       mockSender.On("SendPdpStatus", mock.Anything).Return(nil)
+       StartHeartbeatIntervalTimer(1000, mockSender)
+
+       StopTicker()
+       mu.Lock()
+       defer mu.Unlock()
+       if ticker != nil {
+               t.Errorf("Expected ticker to be nil")
+       }
+}
+
+/*
+TestStopTicker_NotRunning 3
+Description: Test stopping the ticker when it is not running.
+Input: Ticker is not running
+Expected Output: The function should handle this case gracefully, possibly by logging a debug message indicating that the ticker is not running.
+*/
+func TestStopTicker_NotRunning(t *testing.T) {
+       StopTicker()
+       mu.Lock()
+       defer mu.Unlock()
+}
index fbd07d6..0891add 100644 (file)
@@ -30,7 +30,7 @@ import (
        "policy-opa-pdp/pkg/pdpattributes"
        "policy-opa-pdp/pkg/pdpstate"
        "time"
-
+        "sync"
        "github.com/google/uuid"
 )
 
@@ -38,6 +38,7 @@ var (
        ticker          *time.Ticker
        stopChan        chan bool
        currentInterval int64
+       mu              sync.Mutex
 )
 
 // Initializes a timer that sends periodic heartbeat messages to indicate the health and state of the PDP.
@@ -47,6 +48,8 @@ func StartHeartbeatIntervalTimer(intervalMs int64, s PdpStatusSender) {
                ticker = nil
                return
        }
+       mu.Lock()
+       defer mu.Unlock()
 
        if ticker != nil && intervalMs == currentInterval {
                log.Debug("Ticker is already running")
@@ -102,10 +105,13 @@ func sendPDPHeartBeat(s PdpStatusSender) error {
 
 // Stops the running ticker and terminates the goroutine managing heartbeat messages.
 func StopTicker() {
+       mu.Lock()
+       defer mu.Unlock()
        if ticker != nil && stopChan != nil {
                stopChan <- true
                close(stopChan)
                ticker = nil
+               stopChan = nil
        } else {
                log.Debugf("Ticker is not Running")
        }
index e95866e..7548177 100644 (file)
 package publisher
 
 import (
-       /*      "fmt"
-               "policy-opa-pdp/cfg"
-               "policy-opa-pdp/consts"
-               "policy-opa-pdp/pkg/log"
-               "policy-opa-pdp/pkg/model"
-               "policy-opa-pdp/pkg/pdpstate"*/
        "errors"
        "github.com/stretchr/testify/assert"
        "github.com/stretchr/testify/mock"
@@ -54,6 +48,8 @@ func TestStartHeartbeatIntervalTimer_ValidInterval(t *testing.T) {
        mockSender.On("SendPdpStatus", mock.Anything).Return(nil)
 
        StartHeartbeatIntervalTimer(intervalMs, mockSender)
+       mu.Lock()
+       defer mu.Unlock()
        if ticker == nil {
                t.Errorf("Expected ticker to be initialized")
        }
@@ -75,6 +71,8 @@ func TestStartHeartbeatIntervalTimer_InvalidInterval(t *testing.T) {
        mockSender.On("SendPdpStatus", mock.Anything).Return(nil)
 
        StartHeartbeatIntervalTimer(intervalMs, mockSender)
+       mu.Lock()
+       defer mu.Unlock()
 
        if ticker != nil {
                t.Log("Expected ticker to be nil for invalid interval")
@@ -87,6 +85,7 @@ Description: Test sending a heartbeat successfully.
 Input: Valid pdpStatus object
 Expected Output: Heartbeat message is sent successfully, and a debug log "Message sent successfully" is generated.
 */
+
 func TestSendPDPHeartBeat_Success(t *testing.T) {
 
        mockSender := new(mocks.PdpStatusSender)
@@ -101,6 +100,7 @@ Description: Test failing to send a heartbeat.
 Input: Invalid pdpStatus object or network failure
 Expected Output: An error occurs while sending the heartbeat, and a warning log "Error producing message: ..." is generated.
 */
+
 func TestSendPDPHeartBeat_Failure(t *testing.T) {
        // Mock SendPdpStatus to return an error
        mockSender := new(mocks.PdpStatusSender)
@@ -109,6 +109,7 @@ func TestSendPDPHeartBeat_Failure(t *testing.T) {
        assert.Error(t, err)
 }
 
+
 /*
 TestStopTicker_Success 3
 Description: Test stopping the ticker.
@@ -119,7 +120,10 @@ func TestStopTicker_Success(t *testing.T) {
        mockSender := new(mocks.PdpStatusSender)
        mockSender.On("SendPdpStatus", mock.Anything).Return(nil)
        StartHeartbeatIntervalTimer(1000, mockSender)
+
        StopTicker()
+       mu.Lock()
+       defer mu.Unlock()
        if ticker != nil {
                t.Errorf("Expected ticker to be nil")
        }
@@ -133,4 +137,6 @@ Expected Output: The function should handle this case gracefully, possibly by lo
 */
 func TestStopTicker_NotRunning(t *testing.T) {
        StopTicker()
+       mu.Lock()
+       defer mu.Unlock()
 }
index 1052749..51cdcf0 100644 (file)
@@ -2,91 +2,91 @@
 
 ## Verification API Calls
 
-curl -u 'policyadmin:zb!XztG34' -H 'Content-Type: application/json' -H 'Accept: application/json' -d '{"onapName":"CDS","onapComponent":"CDS","onapInstance":"CDS","currentDate": "2024-11-22", "currentTime": "2024-11-22T11:34:56Z", "timeZone": "UTC", "timeOffset": "+05:30", "currentDateTime": "2024-11-22T12:08:00Z","policyName":"example/allow","input":{"method":"POST","path":["users"]}}' -X POST http://0.0.0.0:8282/policy/pdpx/v1/decision
+curl -u 'policyadmin:zb!XztG34' -H 'Content-Type: application/json' -H 'Accept: application/json' -d '{"onapName":"CDS","onapComponent":"CDS","onapInstance":"CDS","currentDate": "2024-11-22", "currentTime": "2024-11-22T11:34:56Z", "timeZone": "UTC", "timeOffset": "+05:30", "currentDateTime": "2024-11-22T12:08:00Z","policyName":"example/allow","input":{"method":"POST","path":["users"]}}' -X POST http://0.0.0.0:8282/policy/pdpo/v1/decision
 
-curl -u 'policyadmin:zb!XztG34' -H 'Content-Type: application/json' -H 'Accept: application/json' --header 'X-ONAP-RequestID:8e6f784e-c9cb-42f6-bcc9-edb5d0af1ce1' -d '{"onapName":"CDS","onapComponent":"CDS","onapInstance":"CDS","currentDate": "2024-11-22", "currentTime": "2024-11-22T11:34:56Z", "timeZone": "UTC", "timeOffset": "+05:30", "currentDateTime": "2024-11-22T12:08:00Z", "policyName":"role/allow","input":{"user":"alice","action":"write","object":"id123","type":"dog"}}' -X POST http://0.0.0.0:8282/policy/pdpx/v1/decision
+curl -u 'policyadmin:zb!XztG34' -H 'Content-Type: application/json' -H 'Accept: application/json' --header 'X-ONAP-RequestID:8e6f784e-c9cb-42f6-bcc9-edb5d0af1ce1' -d '{"onapName":"CDS","onapComponent":"CDS","onapInstance":"CDS","currentDate": "2024-11-22", "currentTime": "2024-11-22T11:34:56Z", "timeZone": "UTC", "timeOffset": "+05:30", "currentDateTime": "2024-11-22T12:08:00Z", "policyName":"role/allow","input":{"user":"alice","action":"write","object":"id123","type":"dog"}}' -X POST http://0.0.0.0:8282/policy/pdpo/v1/decision
 
 ## PERMIT for policy:action
 
-curl -u 'policyadmin:zb!XztG34' -H 'Content-Type: application/json' -H 'Accept: application/json' --header 'X-ONAP-RequestID:8e6f784e-c9cb-42f6-bcc9-edb5d0af1ce1' -d '{"onapName":"CDS","onapComponent":"CDS","onapInstance":"CDS", "currentDate": "2024-11-22", "currentTime": "2024-11-22T11:34:56Z", "timeZone": "UTC", "timeOffset": "+05:30", "currentDateTime": "2024-11-22T12:08:00Z","policyName":"action/allow","input":{"user":"alice","action":"delete","type":"server"}}' -X POST http://0.0.0.0:8282/policy/pdpx/v1/decision
+curl -u 'policyadmin:zb!XztG34' -H 'Content-Type: application/json' -H 'Accept: application/json' --header 'X-ONAP-RequestID:8e6f784e-c9cb-42f6-bcc9-edb5d0af1ce1' -d '{"onapName":"CDS","onapComponent":"CDS","onapInstance":"CDS", "currentDate": "2024-11-22", "currentTime": "2024-11-22T11:34:56Z", "timeZone": "UTC", "timeOffset": "+05:30", "currentDateTime": "2024-11-22T12:08:00Z","policyName":"action/allow","input":{"user":"alice","action":"delete","type":"server"}}' -X POST http://0.0.0.0:8282/policy/pdpo/v1/decision
 
 {"decision":"PERMIT","policyName":"action/allow","statusMessage":"OPA Allowed"}
 
 ## DENY for policy:action
 
-curl -u 'policyadmin:zb!XztG34' -H 'Content-Type: application/json' -H 'Accept: application/json' --header 'X-ONAP-RequestID:8e6f784e-c9cb-42f6-bcc9-edb5d0af1ce1' -d '{"onapName":"CDS","onapComponent":"CDS","onapInstance":"CDS", "currentDate": "2024-11-22", "currentTime": "2024-11-22T11:34:56Z", "timeZone": "UTC", "timeOffset": "+05:30", "currentDateTime": "2024-11-22T12:08:00Z","policyName":"action/allow","input":{"user":"charlie","action":"delete","type":"server"}}' -X POST http://0.0.0.0:8282/policy/pdpx/v1/decision
+curl -u 'policyadmin:zb!XztG34' -H 'Content-Type: application/json' -H 'Accept: application/json' --header 'X-ONAP-RequestID:8e6f784e-c9cb-42f6-bcc9-edb5d0af1ce1' -d '{"onapName":"CDS","onapComponent":"CDS","onapInstance":"CDS", "currentDate": "2024-11-22", "currentTime": "2024-11-22T11:34:56Z", "timeZone": "UTC", "timeOffset": "+05:30", "currentDateTime": "2024-11-22T12:08:00Z","policyName":"action/allow","input":{"user":"charlie","action":"delete","type":"server"}}' -X POST http://0.0.0.0:8282/policy/pdpo/v1/decision
 
 {"decision":"DENY","policyName":"action/allow","statusMessage":"OPA Denied"}
 
 ## PERMIT for policy:account
 
-curl -u 'policyadmin:zb!XztG34' -H 'Content-Type: application/json' -H 'Accept: application/json' --header 'X-ONAP-RequestID:8e6f784e-c9cb-42f6-bcc9-edb5d0af1ce1' -d '{"onapName":"CDS","onapComponent":"CDS","onapInstance":"CDS", "currentDate": "2024-11-22", "currentTime": "2024-11-22T11:34:56Z", "timeZone": "UTC","timeOffset": "+05:30", "currentDateTime": "2024-11-22T12:08:00Z","policyName":"account/allow", "input":{"creditor_account":11111,"creditor":"alice","debtor_account":22222,"debtor":"bob","period":30,"amount":1000}}' -X POST http://0.0.0.0:8282/policy/pdpx/v1/decision
+curl -u 'policyadmin:zb!XztG34' -H 'Content-Type: application/json' -H 'Accept: application/json' --header 'X-ONAP-RequestID:8e6f784e-c9cb-42f6-bcc9-edb5d0af1ce1' -d '{"onapName":"CDS","onapComponent":"CDS","onapInstance":"CDS", "currentDate": "2024-11-22", "currentTime": "2024-11-22T11:34:56Z", "timeZone": "UTC","timeOffset": "+05:30", "currentDateTime": "2024-11-22T12:08:00Z","policyName":"account/allow", "input":{"creditor_account":11111,"creditor":"alice","debtor_account":22222,"debtor":"bob","period":30,"amount":1000}}' -X POST http://0.0.0.0:8282/policy/pdpo/v1/decision
 
 {"decision":"PERMIT","policyName":"account/allow","statusMessage":"OPA Allowed"}
 
 ## DENY for policy:account
 
-curl -u 'policyadmin:zb!XztG34' -H 'Content-Type: application/json' -H 'Accept: application/json' --header 'X-ONAP-RequestID:8e6f784e-c9cb-42f6-bcc9-edb5d0af1ce1' -d '{"onapName":"CDS","onapComponent":"CDS","onapInstance":"CDS", "currentDate": "2024-11-22", "currentTime": "2024-11-22T11:34:56Z", "timeZone": "UTC", "timeOffset": "+05:30", "currentDateTime": "2024-11-22T12:08:00Z","policyName":"account/allow", "input":{"creditor_account":11111,"creditor":"alice","debtor_account":22222,"debtor":"bob","period":31,"amount":1000}}' -X POST http://0.0.0.0:8282/policy/pdpx/v1/decision
+curl -u 'policyadmin:zb!XztG34' -H 'Content-Type: application/json' -H 'Accept: application/json' --header 'X-ONAP-RequestID:8e6f784e-c9cb-42f6-bcc9-edb5d0af1ce1' -d '{"onapName":"CDS","onapComponent":"CDS","onapInstance":"CDS", "currentDate": "2024-11-22", "currentTime": "2024-11-22T11:34:56Z", "timeZone": "UTC", "timeOffset": "+05:30", "currentDateTime": "2024-11-22T12:08:00Z","policyName":"account/allow", "input":{"creditor_account":11111,"creditor":"alice","debtor_account":22222,"debtor":"bob","period":31,"amount":1000}}' -X POST http://0.0.0.0:8282/policy/pdpo/v1/decision
 
 {"decision":"DENY","policyName":"account/allow","statusMessage":"OPA Denied"}
 
 ## PERMIT for policy:organization
 
-curl -u 'policyadmin:zb!XztG34' -H 'Content-Type: application/json' -H 'Accept: application/json' --header 'X-ONAP-RequestID:8e6f784e-c9cb-42f6-bcc9-edb5d0af1ce1' -d '{"onapName":"CDS","onapComponent":"CDS","onapInstance":"CDS", "currentDate": "2024-11-22", "currentTime": "2024-11-22T11:34:56Z", "timeZone": "UTC", "timeOffset": "+05:30", "currentDateTime": "2024-11-22T12:08:00Z","policyName":"organization/allow", "input":{"user":"alice","action": "read","component": "component_A","project": "project_A", "organization": "org_A"}}' -X POST http://0.0.0.0:8282/policy/pdpx/v1/decision
+curl -u 'policyadmin:zb!XztG34' -H 'Content-Type: application/json' -H 'Accept: application/json' --header 'X-ONAP-RequestID:8e6f784e-c9cb-42f6-bcc9-edb5d0af1ce1' -d '{"onapName":"CDS","onapComponent":"CDS","onapInstance":"CDS", "currentDate": "2024-11-22", "currentTime": "2024-11-22T11:34:56Z", "timeZone": "UTC", "timeOffset": "+05:30", "currentDateTime": "2024-11-22T12:08:00Z","policyName":"organization/allow", "input":{"user":"alice","action": "read","component": "component_A","project": "project_A", "organization": "org_A"}}' -X POST http://0.0.0.0:8282/policy/pdpo/v1/decision
 {"decision":"PERMIT","policyName":"organization/allow","statusMessage":"OPA Allowed"}
 
 ## DENY for policy:organization
 
-curl -u 'policyadmin:zb!XztG34' -H 'Content-Type: application/json' -H 'Accept: application/json' --header 'X-ONAP-RequestID:8e6f784e-c9cb-42f6-bcc9-edb5d0af1ce1' -d '{"onapName":"CDS","onapComponent":"CDS","onapInstance":"CDS", "currentDate": "2024-11-22", "currentTime": "2024-11-22T11:34:56Z", "timeZone": "UTC", "timeOffset": "+05:30", "currentDateTime": "2024-11-22T12:08:00Z","policyName":"organization/allow", "input":{"user":"charlie","action": "edit","component": "component_A","project": "project_A", "organization": "org_A"}}' -X POST http://0.0.0.0:8282/policy/pdpx/v1/decision
+curl -u 'policyadmin:zb!XztG34' -H 'Content-Type: application/json' -H 'Accept: application/json' --header 'X-ONAP-RequestID:8e6f784e-c9cb-42f6-bcc9-edb5d0af1ce1' -d '{"onapName":"CDS","onapComponent":"CDS","onapInstance":"CDS", "currentDate": "2024-11-22", "currentTime": "2024-11-22T11:34:56Z", "timeZone": "UTC", "timeOffset": "+05:30", "currentDateTime": "2024-11-22T12:08:00Z","policyName":"organization/allow", "input":{"user":"charlie","action": "edit","component": "component_A","project": "project_A", "organization": "org_A"}}' -X POST http://0.0.0.0:8282/policy/pdpo/v1/decision
 
 {"decision":"DENY","policyName":"organization/allow","statusMessage":"OPA Denied"}
 
 ## DENY for policy:abac(output)
 
-curl -u 'policyadmin:zb!XztG34' -H 'Content-Type: application/json' -H 'Accept: application/json' --header 'X-ONAP-RequestID:8e6f784e-c9cb-42f6-bcc9-edb5d0af1ce1' -d '{"onapName":"CDS","onapComponent":"CDS","onapInstance":"CDS","currentDate": "2024-11-22","policyName":"abac", "policyFilter": ["action_is_read"], "input":{"actions": ["write"],"datatypes": ["location","temperature","precipitation","windspeed"],"time_period": {"from": "2024-03-27","to": "2024-03-31"}}}' -X POST http://0.0.0.0:8282/policy/pdpx/v1/decision
+curl -u 'policyadmin:zb!XztG34' -H 'Content-Type: application/json' -H 'Accept: application/json' --header 'X-ONAP-RequestID:8e6f784e-c9cb-42f6-bcc9-edb5d0af1ce1' -d '{"onapName":"CDS","onapComponent":"CDS","onapInstance":"CDS","currentDate": "2024-11-22","policyName":"abac", "policyFilter": ["action_is_read"], "input":{"actions": ["write"],"datatypes": ["location","temperature","precipitation","windspeed"],"time_period": {"from": "2024-03-27","to": "2024-03-31"}}}' -X POST http://0.0.0.0:8282/policy/pdpo/v1/decision
 {"decision":"DENY","output":{},"policyName":"abac","statusMessage":"OPA Denied"}
 
 ## PERMIT for policy:abac
 
-curl -u 'policyadmin:zb!XztG34' -H 'Content-Type: application/json' -H 'Accept: application/json' --header 'X-ONAP-RequestID:8e6f784e-c9cb-42f6-bcc9-edb5d0af1ce1' -d '{"onapName":"CDS","onapComponent":"CDS","onapInstance":"CDS","currentDate": "2024-11-22","policyName":"abac", "policyFilter": ["viewable_sensor_data"], "input":{"actions": ["read"],"datatypes": ["location","temperature","precipitation","windspeed"],"time_period": {"from": "2024-02-27","to": "2024-02-29"}}}' -X POST http://0.0.0.0:8282/policy/pdpx/v1/decision
+curl -u 'policyadmin:zb!XztG34' -H 'Content-Type: application/json' -H 'Accept: application/json' --header 'X-ONAP-RequestID:8e6f784e-c9cb-42f6-bcc9-edb5d0af1ce1' -d '{"onapName":"CDS","onapComponent":"CDS","onapInstance":"CDS","currentDate": "2024-11-22","policyName":"abac", "policyFilter": ["viewable_sensor_data"], "input":{"actions": ["read"],"datatypes": ["location","temperature","precipitation","windspeed"],"time_period": {"from": "2024-02-27","to": "2024-02-29"}}}' -X POST http://0.0.0.0:8282/policy/pdpo/v1/decision
 {"decision":"PERMIT","output":{"viewable_sensor_data":[{"location":"Galle","precipitation":"500 mm","temperature":"35 C","windspeed":"7.2 m/s"},{"location":"Jaffna","precipitation":"300 mm","temperature":"-5 C","windspeed":"3.8 m/s"},{"location":"Nuwara Eliya","precipitation":"600 mm","temperature":"25 C","windspeed":"4.0 m/s"},{"location":"Trincomalee","precipitation":"1000 mm","temperature":"20 C","windspeed":"5.0 m/s"}]},"policyName":"abac","statusMessage":"OPA Allowed"}
 
 ## PERMIT for policy:zone
-curl -u 'policyadmin:zb!XztG34' -H 'Content-Type: application/json' -H 'Accept: application/json' --header 'X-ONAP-RequestID:8e6f784e-c9cb-42f6-bcc9-edb5d0af1ce1' -d '{"onapName":"CDS","onapComponent":"CDS","onapInstance":"CDS","currentDate": "2024-11-22","policyName":"zone", "policyFilter": ["has_zone_access"], "input":{"actions": ["view"],"log_id": "log1", "datatypes": ["access", "user"],"time_period": {"from": "2024-11-01T09:00:00Z","to": "2024-11-01T10:00:00Z"},"zone_id": "zoneA"}}' -X POST http://0.0.0.0:8282/policy/pdpx/v1/decision
+curl -u 'policyadmin:zb!XztG34' -H 'Content-Type: application/json' -H 'Accept: application/json' --header 'X-ONAP-RequestID:8e6f784e-c9cb-42f6-bcc9-edb5d0af1ce1' -d '{"onapName":"CDS","onapComponent":"CDS","onapInstance":"CDS","currentDate": "2024-11-22","policyName":"zone", "policyFilter": ["has_zone_access"], "input":{"actions": ["view"],"log_id": "log1", "datatypes": ["access", "user"],"time_period": {"from": "2024-11-01T09:00:00Z","to": "2024-11-01T10:00:00Z"},"zone_id": "zoneA"}}' -X POST http://0.0.0.0:8282/policy/pdpo/v1/decision
 {"decision":"PERMIT","output":{"has_zone_access":[{"access":"granted","user":"user1"}]},"policyName":"zone","statusMessage":"OPA Allowed"}
 
 ## DENY for policy: zone
 
-curl -u 'policyadmin:zb!XztG34' -H 'Content-Type: application/json' -H 'Accept: application/json' --header 'X-ONAP-RequestID:8e6f784e-c9cb-42f6-bcc9-edb5d0af1ce1' -d '{"onapName":"CDS","onapComponent":"CDS","onapInstance":"CDS","currentDate": "2024-11-22","policyName":"zone", "policyFilter": ["has_zone_access"], "input":{"actions": ["edit"],"log_id": "log1", "datatypes": ["access", "user"],"time_period": {"from": "2024-11-01T00:00:00Z","to": "2024-11-01T00:00:00Z"},"zone_id": "zoneA"}}' -X POST http://0.0.0.0:8282/policy/pdpx/v1/decision
+curl -u 'policyadmin:zb!XztG34' -H 'Content-Type: application/json' -H 'Accept: application/json' --header 'X-ONAP-RequestID:8e6f784e-c9cb-42f6-bcc9-edb5d0af1ce1' -d '{"onapName":"CDS","onapComponent":"CDS","onapInstance":"CDS","currentDate": "2024-11-22","policyName":"zone", "policyFilter": ["has_zone_access"], "input":{"actions": ["edit"],"log_id": "log1", "datatypes": ["access", "user"],"time_period": {"from": "2024-11-01T00:00:00Z","to": "2024-11-01T00:00:00Z"},"zone_id": "zoneA"}}' -X POST http://0.0.0.0:8282/policy/pdpo/v1/decision
 {"decision":"DENY","output":{"has_zone_access":[]},"policyName":"zone","statusMessage":"OPA Denied"}
 
 ## PERMIT for policy:vehicle
 
-curl -u 'policyadmin:zb!XztG34' -H 'Content-Type: application/json' -H 'Accept: application/json' --header 'X-ONAP-RequestID:8e6f784e-c9cb-42f6-bcc9-edb5d0af1ce1' -d '{"onapName":"CDS","onapComponent":"CDS","onapInstance":"CDS","currentDate": "2024-11-22","policyName":"vehicle", "policyFilter": ["user_has_vehicle_access"], "input":{"actions": ["use"],"user":"user1", "vehicle_id": "v1", "attributes": ["type", "status"]}}' -X POST http://0.0.0.0:8282/policy/pdpx/v1/decision
+curl -u 'policyadmin:zb!XztG34' -H 'Content-Type: application/json' -H 'Accept: application/json' --header 'X-ONAP-RequestID:8e6f784e-c9cb-42f6-bcc9-edb5d0af1ce1' -d '{"onapName":"CDS","onapComponent":"CDS","onapInstance":"CDS","currentDate": "2024-11-22","policyName":"vehicle", "policyFilter": ["user_has_vehicle_access"], "input":{"actions": ["use"],"user":"user1", "vehicle_id": "v1", "attributes": ["type", "status"]}}' -X POST http://0.0.0.0:8282/policy/pdpo/v1/decision
 
 {"decision":"PERMIT","output":{"user_has_vehicle_access":[{"status":"available","type":"car"}]},"policyName":"vehicle","statusMessage":"OPA Allowed"}
 
 ## PERMIT for policy:docs
 
-`curl -u 'policyadmin:zb!XztG34' -H 'Content-Type: application/json' -H 'Accept: application/json' --header 'X-ONAP-RequestID:8e6f784e-c9cb-42f6-bcc9-edb5d0af1ce1' -d '{"onapName":"CDS","onapComponent":"CDS","onapInstance":"CDS","currentDate": "2024-11-22","policyName":"docs", "policyFilter": ["has_access_to_file"], "input":{"action": "read","file_id": "file1","access_level": "admin","attributes": ["owner", "size"]}}' -X POST http://0.0.0.0:8282/policy/pdpx/v1/decision
+`curl -u 'policyadmin:zb!XztG34' -H 'Content-Type: application/json' -H 'Accept: application/json' --header 'X-ONAP-RequestID:8e6f784e-c9cb-42f6-bcc9-edb5d0af1ce1' -d '{"onapName":"CDS","onapComponent":"CDS","onapInstance":"CDS","currentDate": "2024-11-22","policyName":"docs", "policyFilter": ["has_access_to_file"], "input":{"action": "read","file_id": "file1","access_level": "admin","attributes": ["owner", "size"]}}' -X POST http://0.0.0.0:8282/policy/pdpo/v1/decision
 
 {"decision":"PERMIT","output":{"has_access_to_file":[{"owner":"user1","size":"10MB"}]},"policyName":"docs","statusMessage":"OPA Allowed"}`
 
 ## DENY for policy:docs
 
-`curl -u 'policyadmin:zb!XztG34' -H 'Content-Type: application/json' -H 'Accept: application/json' --header 'X-ONAP-RequestID:8e6f784e-c9cb-42f6-bcc9-edb5d0af1ce1' -d '{"onapName":"CDS","onapComponent":"CDS","onapInstance":"CDS","currentDate": "2024-11-22","policyName":"docs", "policyFilter": ["has_access_to_file"], "input":{"action": "view","file_id": "file1","access_level": "employee","attributes": ["owner", "size"]}}' -X POST http://0.0.0.0:8282/policy/pdpx/v1/decision
+`curl -u 'policyadmin:zb!XztG34' -H 'Content-Type: application/json' -H 'Accept: application/json' --header 'X-ONAP-RequestID:8e6f784e-c9cb-42f6-bcc9-edb5d0af1ce1' -d '{"onapName":"CDS","onapComponent":"CDS","onapInstance":"CDS","currentDate": "2024-11-22","policyName":"docs", "policyFilter": ["has_access_to_file"], "input":{"action": "view","file_id": "file1","access_level": "employee","attributes": ["owner", "size"]}}' -X POST http://0.0.0.0:8282/policy/pdpo/v1/decision
 
 {"decision":"DENY","output":{"has_access_to_file":[]},"policyName":"docs","statusMessage":"OPA Denied"}`
 
 
 ## HealthCheck API Call With Response
 
-curl -u 'policyadmin:zb!XztG34' --header 'X-ONAP-RequestID:8e6f784e-c9cb-42f6-bcc9-edb5d0af1ce1' -X GET http://0.0.0.0:8282/policy/pdpx/v1/healthcheck
+curl -u 'policyadmin:zb!XztG34' --header 'X-ONAP-RequestID:8e6f784e-c9cb-42f6-bcc9-edb5d0af1ce1' -X GET http://0.0.0.0:8282/policy/pdpo/v1/healthcheck
 
 {"code":200,"healthy":true,"message":"alive","name":"opa-9f0248ea-807e-45f6-8e0f-935e570b75cc","url":"self"}
 
 ## Statistics API Call With Response
 
-curl -u 'policyadmin:zb!XztG34' --header 'X-ONAP-RequestID:8e6f784e-c9cb-42f6-bcc9-edb5d0af1ce1' -X GET http://0.0.0.0:8282/policy/pdpx/v1/statistics
+curl -u 'policyadmin:zb!XztG34' --header 'X-ONAP-RequestID:8e6f784e-c9cb-42f6-bcc9-edb5d0af1ce1' -X GET http://0.0.0.0:8282/policy/pdpo/v1/statistics
 
 {"code":200,"denyDecisionsCount":10,"deployFailureCount":0,"deploySuccessCount":0,"indeterminantDecisionsCount":0,"permitDecisionsCount":18,"totalErrorCount":4,"totalPoliciesCount":0,"totalPolicyTypesCount":1,"undeployFailureCount":0,"undeploySuccessCount":0}
diff --git a/test/data/docs/data.json b/test/data/docs/data.json
new file mode 100644 (file)
index 0000000..5d43020
--- /dev/null
@@ -0,0 +1,7 @@
+{
+  "files": [
+    { "file_id": "file1", "access_level": "admin", "owner": "user1", "size": "10MB" },
+    { "file_id": "file2", "access_level": "user", "owner": "user2", "size": "5MB" }
+  ]
+}
+
diff --git a/test/data/vehicle/data.json b/test/data/vehicle/data.json
new file mode 100644 (file)
index 0000000..570c677
--- /dev/null
@@ -0,0 +1,7 @@
+{
+  "vehicles": [
+    { "vehicle_id": "v1", "owner": "user1", "type": "car", "status": "available" },
+    { "vehicle_id": "v2", "owner": "user2", "type": "bike", "status": "in use" }
+  ]
+}
+
diff --git a/test/data/zone/data.json b/test/data/zone/data.json
new file mode 100644 (file)
index 0000000..be77176
--- /dev/null
@@ -0,0 +1,10 @@
+{
+  "zone": {
+    "zone_access_logs": [
+      { "log_id": "log1", "timestamp": "2024-11-01T09:00:00Z", "zone_id": "zoneA", "access": "granted", "user": "user1" },
+      { "log_id": "log2", "timestamp": "2024-11-01T10:30:00Z", "zone_id": "zoneA", "access": "denied", "user": "user2" },
+      { "log_id": "log3", "timestamp": "2024-11-01T11:00:00Z", "zone_id": "zoneB", "access": "granted", "user": "user3" }
+    ]
+  }
+}
+
diff --git a/test/policies/docs/policy.rego b/test/policies/docs/policy.rego
new file mode 100644 (file)
index 0000000..90ce883
--- /dev/null
@@ -0,0 +1,22 @@
+package docs
+
+import rego.v1
+
+default allow := false
+
+allow if {
+    has_access_to_file
+    action_is_read_or_write
+}
+
+action_is_read_or_write if {
+    input.action in ["read", "write"]
+}
+
+has_access_to_file contains file_info if {
+    some file in data.docs.files
+    file.file_id == input.file_id
+    file.access_level == input.access_level
+    file_info := {attr: file[attr] | attr in input.attributes}
+}
+
diff --git a/test/policies/vehicle/policy.rego b/test/policies/vehicle/policy.rego
new file mode 100644 (file)
index 0000000..592afee
--- /dev/null
@@ -0,0 +1,23 @@
+package vehicle
+
+import  rego.v1
+
+default allow := false
+
+allow if {
+    user_has_vehicle_access
+    action_is_granted
+}
+
+action_is_granted if {
+    "use" in input.actions
+}
+
+user_has_vehicle_access contains vehicle_data if {
+    some vehicle in data.vehicle.vehicles
+    vehicle.vehicle_id == input.vehicle_id
+    vehicle.owner == input.user
+    vehicle_data := {info: vehicle[info] | info in input.attributes}
+}
+
+
diff --git a/test/policies/zone/policy.rego b/test/policies/zone/policy.rego
new file mode 100644 (file)
index 0000000..75357a6
--- /dev/null
@@ -0,0 +1,23 @@
+package zone
+
+import rego.v1
+
+default allow := false
+
+allow if {
+    has_zone_access
+    action_is_log_view
+}
+
+action_is_log_view if {
+    "view" in input.actions
+}
+
+has_zone_access contains access_data if {
+    some zone_data in data.zone.zone.zone_access_logs
+    zone_data.timestamp >= input.time_period.from
+    zone_data.timestamp < input.time_period.to
+    zone_data.zone_id == input.zone_id
+    access_data := {datatype: zone_data[datatype] | datatype in input.datatypes}
+}
+
diff --git a/version b/version
index 3067557..f755149 100644 (file)
--- a/version
+++ b/version
@@ -1 +1 @@
-1.0.5-SNAPSHOT
+1.0.0-SNAPSHOT