aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDeena Mukundan <dm00536893@techmahindra.com>2024-12-23 10:19:53 +0100
committerDeena Mukundan <dm00536893@techmahindra.com>2024-12-23 15:30:03 +0100
commit38b5a22de90e3055d00136fb8b036a692f0a79a7 (patch)
treeed3f029a75771c4208da8bf2b840cbf5d58f60a8
parentbc208ae0a6b0c995f65c26564fb8b06ef270bf67 (diff)
OPA-PDP URL changes and bugfix
Issue-ID: POLICY-5222 Change-Id: Ia3c214b93f3b5fa18e482e100ac8c255544e0ba6 Signed-off-by: Deena Mukundan <dm00536893@techmahindra.com>
-rw-r--r--Makefile2
-rw-r--r--api/openapi.yaml12
-rw-r--r--api/register-handlers.go6
-rw-r--r--api/register-handlers_test.go4
-rw-r--r--pkg/decision/decision-provider.go21
-rw-r--r--pkg/kafkacomm/handler/pdp_state_change_handler_test.go31
-rw-r--r--pkg/kafkacomm/publisher/1148
-rw-r--r--pkg/kafkacomm/publisher/pdp-heartbeat.go8
-rw-r--r--pkg/kafkacomm/publisher/pdp-heartbeat_test.go18
-rw-r--r--test/README.md34
-rw-r--r--test/data/docs/data.json7
-rw-r--r--test/data/vehicle/data.json7
-rw-r--r--test/data/zone/data.json10
-rw-r--r--test/policies/docs/policy.rego22
-rw-r--r--test/policies/vehicle/policy.rego23
-rw-r--r--test/policies/zone/policy.rego23
-rw-r--r--version2
17 files changed, 326 insertions, 52 deletions
diff --git a/Makefile b/Makefile
index 5521995..f6d0ab2 100644
--- 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 ./...
diff --git a/api/openapi.yaml b/api/openapi.yaml
index a9b8191..bd94ec2 100644
--- a/api/openapi.yaml
+++ b/api/openapi.yaml
@@ -27,8 +27,8 @@ info:
name: Deena Mukundan
email: dm00536893@techmahindra.com
servers:
-- url: http://policy-opa-pdp:8282/policy/pdpx/v1
-- url: https://policy-opa-pdp:8282/policy/pdpx/v1
+- url: http://policy-opa-pdp:8282/policy/pdpo/v1
+- url: https://policy-opa-pdp:8282/policy/pdpo/v1
tags:
- name: Decision
- name: Statistics
@@ -110,7 +110,7 @@ paths:
- basicAuth: []
x-interface info:
last-mod-release: Paris
- pdpx-version: 1.0.0
+ pdpo-version: 1.0.0
x-codegen-request-body-name: body
/healthcheck:
get:
@@ -170,13 +170,13 @@ paths:
- basicAuth: []
x-interface info:
last-mod-release: Paris
- pdpx-version: 1.0.0
+ pdpo-version: 1.0.0
/statistics:
get:
tags:
- Statistics
summary: Fetch current statistics
- description: Provides current statistics of the Policy OPA PDP component
+ description: Provides current statistics of the Policy OPA PDP component
operationId: statistics
parameters:
- name: X-ONAP-RequestID
@@ -229,7 +229,7 @@ paths:
- basicAuth: []
x-interface info:
last-mod-release: Paris
- pdpx-version: 1.0.0
+ pdpo-version: 1.0.0
components:
schemas:
ErrorResponse:
diff --git a/api/register-handlers.go b/api/register-handlers.go
index 4b21314..c5eb5df 100644
--- a/api/register-handlers.go
+++ b/api/register-handlers.go
@@ -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))
}
diff --git a/api/register-handlers_test.go b/api/register-handlers_test.go
index 801cb0e..f67c1f5 100644
--- a/api/register-handlers_test.go
+++ b/api/register-handlers_test.go
@@ -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 {
diff --git a/pkg/decision/decision-provider.go b/pkg/decision/decision-provider.go
index 48d6edf..5f45668 100644
--- a/pkg/decision/decision-provider.go
+++ b/pkg/decision/decision-provider.go
@@ -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
}
diff --git a/pkg/kafkacomm/handler/pdp_state_change_handler_test.go b/pkg/kafkacomm/handler/pdp_state_change_handler_test.go
index 67edd6f..da3832b 100644
--- a/pkg/kafkacomm/handler/pdp_state_change_handler_test.go
+++ b/pkg/kafkacomm/handler/pdp_state_change_handler_test.go
@@ -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
index 0000000..bfd5272
--- /dev/null
+++ b/pkg/kafkacomm/publisher/1
@@ -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()
+}
diff --git a/pkg/kafkacomm/publisher/pdp-heartbeat.go b/pkg/kafkacomm/publisher/pdp-heartbeat.go
index fbd07d6..0891add 100644
--- a/pkg/kafkacomm/publisher/pdp-heartbeat.go
+++ b/pkg/kafkacomm/publisher/pdp-heartbeat.go
@@ -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")
}
diff --git a/pkg/kafkacomm/publisher/pdp-heartbeat_test.go b/pkg/kafkacomm/publisher/pdp-heartbeat_test.go
index e95866e..7548177 100644
--- a/pkg/kafkacomm/publisher/pdp-heartbeat_test.go
+++ b/pkg/kafkacomm/publisher/pdp-heartbeat_test.go
@@ -20,12 +20,6 @@
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()
}
diff --git a/test/README.md b/test/README.md
index 1052749..51cdcf0 100644
--- a/test/README.md
+++ b/test/README.md
@@ -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
index 0000000..5d43020
--- /dev/null
+++ b/test/data/docs/data.json
@@ -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
index 0000000..570c677
--- /dev/null
+++ b/test/data/vehicle/data.json
@@ -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
index 0000000..be77176
--- /dev/null
+++ b/test/data/zone/data.json
@@ -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
index 0000000..90ce883
--- /dev/null
+++ b/test/policies/docs/policy.rego
@@ -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
index 0000000..592afee
--- /dev/null
+++ b/test/policies/vehicle/policy.rego
@@ -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
index 0000000..75357a6
--- /dev/null
+++ b/test/policies/zone/policy.rego
@@ -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
--- a/version
+++ b/version
@@ -1 +1 @@
-1.0.5-SNAPSHOT
+1.0.0-SNAPSHOT