phase1 opa pdp changes

For details on scope and implementation, please check.
https://lf-onap.atlassian.net/wiki/spaces/DW/pages/51150925/OPA+PDP
Code Coverage Total: 70.8%

Issue-ID: POLICY-5156
Change-Id: Ied07ee1596e9f447183fb715baaa68c704a9fe99
Signed-off-by: gururajarao79 <gb00566633@techmahindra.com>
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..389c328
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,58 @@
+FROM curlimages/curl:7.78.0 AS build
+
+# Get OPA
+RUN curl -Lo /tmp/opa https://github.com/open-policy-agent/opa/releases/download/v0.69.0/opa_linux_amd64
+
+FROM golang:1.23 AS compile
+
+RUN mkdir /app
+
+COPY go.mod go.sum /app/
+
+COPY . .
+
+RUN mkdir /app/cfg
+ADD cfg /app/cfg
+
+RUN mkdir /app/consts
+ADD consts /app/consts
+
+RUN mkdir /app/api
+ADD api /app/api
+
+RUN mkdir /app/cmd
+ADD cmd /app/cmd
+
+RUN mkdir /app/pkg
+ADD pkg /app/pkg
+
+RUN mkdir /app/bundles
+
+WORKDIR /app
+
+# Build the binary
+RUN GOOS=linux GOARCH=amd64 go build -ldflags="-w -s" -o /app/opa-pdp /app/cmd/opa-pdp/opa-pdp.go
+#COPY config.json /app/config.json
+#RUN chmod 644 /app/config.json
+
+FROM ubuntu
+
+RUN apt-get update && apt-get install -y netcat-openbsd && rm -rf /var/lib/apt/lists/*
+
+RUN apt-get update && apt-get install -y curl
+
+# Copy our static executable from compile stage
+RUN mkdir /app
+COPY --from=compile /app /app
+RUN chmod +x /app/opa-pdp
+
+# Copy our opa executable from build stage
+COPY --from=build /tmp/opa /app/opa
+RUN chmod 755 /app/opa
+
+WORKDIR /app
+EXPOSE 8282
+
+# Command to run OPA with the policies
+CMD ["/app/opa-pdp"]
+
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..7883b7f
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,31 @@
+PWD := $(shell pwd)
+PLATFORM := linux
+BINARY := opa-pdp
+
+
+all: test build
+deploy: test build
+
+build: build_image
+
+deploy: build
+
+.PHONY: test
+test: clean
+	@go test -v ./...
+
+format:
+	@go fmt ./...
+
+clean:
+	@rm -f $(BINARY)
+
+.PHONY: cover
+cover:
+	@go test -p 2 ./... -coverprofile=coverage.out
+	@go tool cover -html=coverage.out -o coverage.html
+
+build_image:
+	docker build -f  Dockerfile  -t policy-opa-pdp:1.0.0 .
+	docker tag policy-opa-pdp:1.0.0 nexus3.onap.org:10003/onap/policy-opa-pdp:latest
+	docker tag nexus3.onap.org:10003/onap/policy-opa-pdp:latest nexus3.onap.org:10003/onap/policy-opa-pdp:1.0.0
diff --git a/README.md b/README.md
index 81636e5..e7603f2 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,7 @@
 # Running docker  policy-opa-pdp
 
 ## Building Docker Image.
-docker build -f  ./build/Dockerfile  -t opa-pdp:1.1.1 .
+docker build -f  ./build/Dockerfile  -t opa-pdp:1.0.0 .
 
 ## Running the containers and Testing
 
@@ -13,4 +13,68 @@
 
 4.  docker logs -f opa-pdp
 
+## Generating models with openapi.yaml
+   
+1. oapi-codegen -package=oapicodegen  -generate "models" openapi.yaml > models.go
+
+## Creating new Policy
+
+1. Create a new directory under test/polices. For example - role
+
+2. Inside this directory create a policy [i.e; rego file] named policy.rego. Version 1 i.e v1 is supported  for rego files.
+
+3. For contents you can see example of  policy.rego under test/policies/role/policy.rego. 
+
+3. Inside test/policies/data create a new directory with the package name of policy.rego. For example test/policies/data/role
+
+4. Create a file data.json under the newly created directory inside data. For example test/policies/data/data.json
+
+5. In policy.rego the package declaration organizes the policy rules. This allows 
+
+6. The Rule allow evaluates to true/false based on the logic defined in policy.rego
+
+7. Data.json is files is kept within the directory named after policy package name under data folders. For example policies/data/role/data.json.
+
+8. To reference the data inside policy.rego we need to define rule as data.folder-name.attribute. For example you can refer to policy.rego under rules, data.role.user_roles.
+
+9. To deploy a new policy opa-pdp need to be redpolyed i.e; docker-compose down and up need to be executed.
+
+## Testing Decision Api
+
+send json 
+{"onapName":"CDS","onapComponent":"CDS","onapInstance":"CDS","currentDate": "2024-11-22", "currentTime": "2024-11-22T11:34:56Z", "timeZone": "UTC",  "timeOffset": "+05:30", "currentDateTime": "2024-11-22 12:08:00.123456+0000 ", "policyName":"role/allow","input":{"user":"alice","action":"write","object":"id123","type":"dog"}} 
+to opa-pdp as shown in curl commands below.
+
+"policyName":"[packagename in rego file]/allow"
+  Policy to be refrenced as policyName:role/allow in case when policy's package name is role. Change it according to  your package name of the policy.
+
+"input":{"user":"alice","action":"read","object":"id123","type":"dog"}
+  Input defines the specific data to be evaluated by the Rego policy
+
+## Verification API Calls
+
+`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`
+
+## Result Of Verification API calls(Success)
+
+`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`
+
+`{"decision":"PERMIT","policyName":"role/allow","statusMessage":"OPA Allowed"}`
+
+
+## Result of Verification API calls(Failure)
+
+`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":"carol","action":"write","object":"id123","type":"dog"}}' -X POST http://0.0.0.0:8282/policy/pdpx/v1/decision`
+
+## 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`
+
+`{"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`
+
+`{"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/api/openapi.yaml b/api/openapi.yaml
new file mode 100644
index 0000000..aaff2b9
--- /dev/null
+++ b/api/openapi.yaml
@@ -0,0 +1,374 @@
+#

+#  ========================LICENSE_START=================================

+#   Copyright (C) 2024: Deutsche Telecom

+#

+#   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.

+#  ========================LICENSE_END===================================

+#

+openapi: 3.0.3

+info:

+  title: "Policy OPA PDP Documentation"

+  description: Policy OPA PDP Service

+  version: 1.0.0

+  x-component: Policy Framework

+  x-planned-retirement-date: tbd

+  contact:

+      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

+tags:

+- name: Decision

+- name: Statistics

+- name: HealthCheck

+paths:

+  /decision:

+    post:

+      tags:

+      - Decision

+      summary: Fetch the decision using specified decision parameters

+      description: Returns the policy decision from Policy OPA PDP

+      operationId: decision

+      parameters:

+      - name: X-ONAP-RequestID

+        in: header

+        description: RequestID for http transaction

+        schema:

+          type: string

+          format: uuid

+      requestBody:

+        content:

+          application/json:

+            schema:

+              $ref: '#/components/schemas/OPADecisionRequest'

+          application/yaml:

+            schema:

+              $ref: '#/components/schemas/OPADecisionRequest'

+        required: false

+      responses:

+        200:

+          description: successful operation

+          headers:

+            X-LatestVersion:

+              description: Used only to communicate an API's latest version

+              schema:

+                type: string

+            X-PatchVersion:

+              description: Used only to communicate a PATCH version in a response

+                for troubleshooting purposes only, and will not be provided by the

+                client on request

+              schema:

+                type: string

+            X-MinorVersion:

+              description: Used to request or communicate a MINOR version back from

+                the client to the server, and from the server back to the client

+              schema:

+                type: string

+            X-ONAP-RequestID:

+              description: Used to track REST transactions for logging purpose

+              schema:

+                type: string

+                format: uuid

+          content:

+            application/json:

+              schema:

+                $ref: '#/components/schemas/OPADecisionResponse'

+            application/yaml:

+              schema:

+                $ref: '#/components/schemas/OPADecisionResponse'

+        400:

+          description: Bad Request

+          content:

+            application/json:

+              schema:

+                $ref: '#/components/schemas/ErrorResponse'

+            application/yaml:

+              schema:

+                $ref: '#/components/schemas/ErrorResponse'

+        401:

+          description: Authentication Error

+          content: {}

+        403:

+          description: Authorization Error

+          content: {}

+        500:

+          description: Internal Server Error

+          content: {}

+      security:

+      - basicAuth: []

+      x-interface info:

+        last-mod-release: Paris

+        pdpx-version: 1.0.0

+      x-codegen-request-body-name: body

+  /healthcheck:

+    get:

+      tags:

+      - HealthCheck

+      summary: Perform a system healthcheck

+      description: Provides healthy status of the Policy OPA PDP component

+      operationId: healthcheck

+      parameters:

+      - name: X-ONAP-RequestID

+        in: header

+        description: RequestID for http transaction

+        schema:

+          type: string

+          format: uuid

+      responses:

+        200:

+          description: successful operation

+          headers:

+            X-LatestVersion:

+              description: Used only to communicate an API's latest version

+              schema:

+                type: string

+            X-PatchVersion:

+              description: Used only to communicate a PATCH version in a response

+                for troubleshooting purposes only, and will not be provided by the

+                client on request

+              schema:

+                type: string

+            X-MinorVersion:

+              description: Used to request or communicate a MINOR version back from

+                the client to the server, and from the server back to the client

+              schema:

+                type: string

+            X-ONAP-RequestID:

+              description: Used to track REST transactions for logging purpose

+              schema:

+                type: string

+                format: uuid

+          content:

+            application/json:

+              schema:

+                $ref: '#/components/schemas/HealthCheckReport'

+            application/yaml:

+              schema:

+                $ref: '#/components/schemas/HealthCheckReport'

+        401:

+          description: Authentication Error

+          content: {}

+        403:

+          description: Authorization Error

+          content: {}

+        500:

+          description: Internal Server Error

+          content: {}

+      security:

+      - basicAuth: []

+      x-interface info:

+        last-mod-release: Paris

+        pdpx-version: 1.0.0

+  /statistics:

+    get:

+      tags:

+      - Statistics

+      summary: Fetch current statistics

+      description: Provides current statistics of the Policy OPA PDP component 

+      operationId: statistics

+      parameters:

+      - name: X-ONAP-RequestID

+        in: header

+        description: RequestID for http transaction

+        schema:

+          type: string

+          format: uuid

+      responses:

+        200:

+          description: successful operation

+          headers:

+            X-LatestVersion:

+              description: Used only to communicate an API's latest version

+              schema:

+                type: string

+            X-PatchVersion:

+              description: Used only to communicate a PATCH version in a response

+                for troubleshooting purposes only, and will not be provided by the

+                client on request

+              schema:

+                type: string

+            X-MinorVersion:

+              description: Used to request or communicate a MINOR version back from

+                the client to the server, and from the server back to the client

+              schema:

+                type: string

+            X-ONAP-RequestID:

+              description: Used to track REST transactions for logging purpose

+              schema:

+                type: string

+                format: uuid

+          content:

+            application/json:

+              schema:

+                $ref: '#/components/schemas/StatisticsReport'

+            application/yaml:

+              schema:

+                $ref: '#/components/schemas/StatisticsReport'

+        401:

+          description: Authentication Error

+          content: {}

+        403:

+          description: Authorization Error

+          content: {}

+        500:

+          description: Internal Server Error

+          content: {}

+      security:

+      - basicAuth: []

+      x-interface info:

+        last-mod-release: Paris

+        pdpx-version: 1.0.0

+components:

+  schemas:

+    ErrorResponse:

+      type: object

+      properties:

+        responseCode:

+          type: string

+          enum:

+          - BAD_REQUEST

+          - UNAUTHORIZED

+          - METHOD_NOT_ALLOWED

+          - NOT_ACCEPTABLE

+          - REQUEST_TIMEOUT

+          - CONFLICT

+          - GONE

+          - LENGTH_REQUIRED

+          - PRECONDITION_FAILED

+          - REQUEST_ENTITY_TOO_LARGE

+          - REQUEST_URI_TOO_LONG

+          - UNSUPPORTED_MEDIA_TYPE

+          - REQUESTED_RANGE_NOT_SATISFIABLE

+          - EXPECTATION_FAILED

+          - PRECONDITION_REQUIRED

+          - TOO_MANY_REQUESTS

+          - REQUEST_HEADER_FIELDS_TOO_LARGE

+          - INTERNAL_SERVER_ERROR

+          - NOT_IMPLEMENTED

+          - BAD_GATEWAY

+          - SERVICE_UNAVAILABLE

+          - GATEWAY_TIMEOUT

+          - HTTP_VERSION_NOT_SUPPORTED

+          - NETWORK_AUTHENTICATION_REQUIRED

+        errorMessage:

+          type: string

+        policyName:

+          type: string

+        errorDetails:

+          type: array

+          items:

+            type: string

+    OPADecisionRequest:

+      type: object

+      properties:

+        onapName:

+          type: string

+        onapComponent:

+          type: string

+        onapInstance:

+          type: string

+        currentDateTime:

+          type: string

+          format: date-time

+        currentDate:

+          type: string

+          format: date

+        currentTime:

+          type: string

+          format: date-time

+        timeZone:

+          type: string

+          description: "Timezone in IANA format (e.g., 'America/NewYork', 'Europe/Paris', 'UTC')"

+        timeOffset:

+          type: string

+          pattern: '^[+-]?\d{2}:\d{2}$'

+          description: "Time offset in hours and minutes, e.g., '+02:00' or '-05:00'"

+        policyName:

+          type: string

+        input:

+          type: object

+          additionalProperties: true

+          example:

+                    user: alice

+                    action: read

+                    object: id123

+                    type: dog

+    HealthCheckReport:

+      type: object

+      properties:

+        name:

+          type: string

+        url:

+          type: string

+        healthy:

+          type: boolean

+        code:

+          type: integer

+          format: int32

+        message:

+          type: string

+    OPADecisionResponse:

+      type: object

+      properties:

+        statusMessage:

+          type: string

+        decision:

+          type: string

+          enum:

+          - PERMIT

+          - DENY

+          - INDETERMINATE

+        policyName:

+          type: string

+    StatisticsReport:

+      type: object

+      properties:

+        code:

+          type: integer

+          format: int32

+        totalPolicyTypesCount:

+          type: integer

+          format: int64

+        totalPoliciesCount:

+          type: integer

+          format: int64

+        totalErrorCount:

+          type: integer

+          format: int64

+        permitDecisionsCount:

+          type: integer

+          format: int64

+        denyDecisionsCount:

+          type: integer

+          format: int64

+        deploySuccessCount:

+          type: integer

+          format: int64

+        deployFailureCount:

+          type: integer

+          format: int64

+        undeploySuccessCount:

+          type: integer

+          format: int64

+        undeployFailureCount:

+          type: integer

+          format: int64

+        indeterminantDecisionsCount:

+          type: integer

+          format: int64

+  securitySchemes:

+    basicAuth:

+      type: http

+      description: ""

+      scheme: basic
\ No newline at end of file
diff --git a/api/register-handlers.go b/api/register-handlers.go
new file mode 100644
index 0000000..37028d2
--- /dev/null
+++ b/api/register-handlers.go
@@ -0,0 +1,81 @@
+// -
+//   ========================LICENSE_START=================================
+//   Copyright (C) 2024: Deutsche Telecom
+//
+//   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.
+//   ========================LICENSE_END===================================
+
+// Package api provides HTTP handlers for the policy-opa-pdp service.
+// This package includes handlers for decision making, bundle serving, health checks, and readiness probes.
+// It also includes basic authentication middleware for securing certain endpoints.
+package api
+
+import (
+	"net/http"
+	"policy-opa-pdp/cfg"
+	"policy-opa-pdp/pkg/bundleserver"
+	"policy-opa-pdp/pkg/decision"
+	"policy-opa-pdp/pkg/healthcheck"
+	"policy-opa-pdp/pkg/metrics"
+)
+
+// RegisterHandlers registers the HTTP handlers for the service.
+func RegisterHandlers() {
+
+	// Handler for OPA decision making
+	opaDecisionHandler := http.HandlerFunc(decision.OpaDecision)
+	http.Handle("/policy/pdpx/v1/decision", basicAuth(opaDecisionHandler))
+
+	//This api is used internally by OPA-SDK
+	bundleServerHandler := http.HandlerFunc(bundleserver.GetBundle)
+	http.Handle("/opa/bundles/", bundleServerHandler)
+
+	// Handler for kubernetes readiness probe
+	readinessProbeHandler := http.HandlerFunc(readinessProbe)
+	http.Handle("/ready", readinessProbeHandler)
+
+	// Handler for health checks
+	healthCheckHandler := http.HandlerFunc(healthcheck.HealthCheckHandler)
+	http.HandleFunc("/policy/pdpx/v1/healthcheck", basicAuth(healthCheckHandler))
+
+	// Handler for statistics report
+	statisticsReportHandler := http.HandlerFunc(metrics.FetchCurrentStatistics)
+	http.HandleFunc("/policy/pdpx/v1/statistics", basicAuth(statisticsReportHandler))
+
+}
+
+// handles authentication
+func basicAuth(next http.HandlerFunc) http.HandlerFunc {
+	return func(res http.ResponseWriter, req *http.Request) {
+		user, pass, ok := req.BasicAuth()
+		if !ok || !validateCredentials(user, pass) {
+			res.Header().Set("WWW-Authenticate", `Basic realm="Restricted"`)
+			http.Error(res, "Unauthorized", http.StatusUnauthorized)
+			return
+		}
+		next(res, req)
+	}
+}
+
+// validates Credentials for http server
+func validateCredentials(username, password string) bool {
+	validUser := cfg.Username
+	validPass := cfg.Password
+	return username == validUser && password == validPass
+}
+
+// handles readiness probe endpoint
+func readinessProbe(res http.ResponseWriter, req *http.Request) {
+	res.WriteHeader(http.StatusOK)
+	res.Write([]byte("Ready"))
+}
diff --git a/api/register-handlers_test.go b/api/register-handlers_test.go
new file mode 100644
index 0000000..72624f8
--- /dev/null
+++ b/api/register-handlers_test.go
@@ -0,0 +1,115 @@
+// -
+//   ========================LICENSE_START=================================
+//   Copyright (C) 2024: Deutsche Telecom
+//
+//   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.
+//   ========================LICENSE_END===================================
+//
+
+package api
+
+import (
+	"net/http"
+	"net/http/httptest"
+	"policy-opa-pdp/cfg"
+	"policy-opa-pdp/pkg/bundleserver"
+	"policy-opa-pdp/pkg/decision"
+	"policy-opa-pdp/pkg/healthcheck"
+	"testing"
+)
+
+// Mock configuration
+func init() {
+	cfg.Username = "testuser"
+	cfg.Password = "testpass"
+}
+
+func TestRegisterHandlers(t *testing.T) {
+	RegisterHandlers()
+
+	tests := []struct {
+		path       string
+		handler    http.HandlerFunc
+		statusCode int
+	}{
+		{"/policy/pdpx/v1/decision", decision.OpaDecision, http.StatusUnauthorized},
+		{"/opa/bundles/", bundleserver.GetBundle, http.StatusInternalServerError},
+		{"/ready", readinessProbe, http.StatusOK},
+		{"/policy/pdpx/v1/healthcheck", healthcheck.HealthCheckHandler, http.StatusUnauthorized},
+	}
+
+	for _, tt := range tests {
+		req, err := http.NewRequest("GET", tt.path, nil)
+		if err != nil {
+			t.Fatalf("Failed to create request: %v", err)
+		}
+
+		rr := httptest.NewRecorder()
+		http.DefaultServeMux.ServeHTTP(rr, req)
+
+		if status := rr.Code; status != tt.statusCode {
+			t.Errorf("handler for %s returned wrong status code: got %v want %v", tt.path, status, tt.statusCode)
+		}
+	}
+}
+
+func TestBasicAuth(t *testing.T) {
+	handler := basicAuth(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
+		res.WriteHeader(http.StatusOK)
+	}))
+
+	tests := []struct {
+		username   string
+		password   string
+		statusCode int
+	}{
+		{"testuser", "testpass", http.StatusOK},
+		{"wronguser", "wrongpass", http.StatusUnauthorized},
+		{"", "", http.StatusUnauthorized},
+	}
+
+	for _, tt := range tests {
+		req, err := http.NewRequest("GET", "/", nil)
+		if err != nil {
+			t.Fatalf("Failed to create request: %v", err)
+		}
+		req.SetBasicAuth(tt.username, tt.password)
+
+		rr := httptest.NewRecorder()
+		handler.ServeHTTP(rr, req)
+
+		if status := rr.Code; status != tt.statusCode {
+			t.Errorf("basicAuth returned wrong status code: got %v want %v", status, tt.statusCode)
+		}
+	}
+}
+
+func TestReadinessProbe(t *testing.T) {
+	req, err := http.NewRequest("GET", "/ready", nil)
+	if err != nil {
+		t.Fatalf("Failed to create request: %v", err)
+	}
+
+	rr := httptest.NewRecorder()
+	handler := http.HandlerFunc(readinessProbe)
+	handler.ServeHTTP(rr, req)
+
+	if status := rr.Code; status != http.StatusOK {
+		t.Errorf("readinessProbe returned wrong status code: got %v want %v", status, http.StatusOK)
+	}
+
+	expected := "Ready"
+	if rr.Body.String() != expected {
+		t.Errorf("readinessProbe returned unexpected body: got %v want %v", rr.Body.String(), expected)
+	}
+}
diff --git a/build/Dockerfile b/build/Dockerfile
new file mode 100644
index 0000000..2905d77
--- /dev/null
+++ b/build/Dockerfile
@@ -0,0 +1,58 @@
+FROM curlimages/curl:7.78.0 AS build
+
+# Get OPA
+RUN curl -Lo /tmp/opa https://github.com/open-policy-agent/opa/releases/download/v0.69.0/opa_linux_amd64
+
+FROM golang:1.23 AS compile
+
+RUN mkdir /app
+
+COPY ../go.mod ../go.sum /app/
+
+COPY . .
+
+RUN mkdir /app/cfg
+ADD ../cfg /app/cfg
+
+RUN mkdir /app/consts
+ADD ../consts /app/consts
+
+RUN mkdir /app/api
+ADD ../api /app/api
+
+RUN mkdir /app/cmd
+ADD ../cmd /app/cmd
+
+RUN mkdir /app/pkg
+ADD ../pkg /app/pkg
+
+RUN mkdir /app/bundles
+
+WORKDIR /app
+
+# Build the binary
+RUN GOOS=linux GOARCH=amd64 go build -ldflags="-w -s" -o /app/opa-pdp /app/cmd/opa-pdp/opa-pdp.go
+#COPY config.json /app/config.json
+#RUN chmod 644 /app/config.json
+
+FROM ubuntu
+
+RUN apt-get update && apt-get install -y netcat-openbsd && rm -rf /var/lib/apt/lists/*
+
+RUN apt-get update && apt-get install -y curl
+
+# Copy our static executable from compile stage
+RUN mkdir /app
+COPY --from=compile /app /app
+RUN chmod +x /app/opa-pdp
+
+# Copy our opa executable from build stage
+COPY --from=build /tmp/opa /app/opa
+RUN chmod 755 /app/opa
+
+WORKDIR /app
+EXPOSE 8282
+
+# Command to run OPA with the policies
+CMD ["/app/opa-pdp"]
+
diff --git a/build/Makefile b/build/Makefile
new file mode 100644
index 0000000..d459215
--- /dev/null
+++ b/build/Makefile
@@ -0,0 +1,4 @@
+SHELL := /bin/bash
+
+build:
+	./build_image.sh
diff --git a/build/build_image.sh b/build/build_image.sh
new file mode 100755
index 0000000..9b44a47
--- /dev/null
+++ b/build/build_image.sh
@@ -0,0 +1,45 @@
+#!/bin/bash
+# -
+#   ========================LICENSE_START=================================
+#   Copyright (C) 2024: Deutsche Telecom
+#
+#   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.
+#   ========================LICENSE_END===================================
+#
+
+export IMAGE_NAME="nexus3.onap.org:10003/onap/policy-opa-pdp"
+VERSION_FILE="../version"
+
+
+# Check for the version file
+# If it exists, load the version from that file
+# If not found, then use the current version as 1.1.0 for docker images
+if [ -f "$VERSION_FILE" ]; then
+    VERSION=`cat ../version|xargs echo`;
+else
+    VERSION=1.0.0;
+fi
+
+
+function  _build_docker_and_push_image {
+    local tag_name=${IMAGE_NAME}:${VERSION}
+    
+    docker build -f  Dockerfile  -t policy-opa-pdp:${VERSION} ../.
+    echo "Start push {$tag_name}"
+    docker tag policy-opa-pdp:${VERSION} ${IMAGE_NAME}:latest
+    docker push ${IMAGE_NAME}:latest
+    docker tag ${IMAGE_NAME}:latest ${tag_name}
+    docker push ${tag_name}
+}
+
+_build_docker_and_push_image
diff --git a/cfg/config.go b/cfg/config.go
new file mode 100644
index 0000000..4840688
--- /dev/null
+++ b/cfg/config.go
@@ -0,0 +1,103 @@
+// -
+//   ========================LICENSE_START=================================
+//   Copyright (C) 2024: Deutsche Telecom
+//
+//   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.
+//   ========================LICENSE_END===================================
+
+// Package cfg provides configuration settings for the policy-opa-pdp service.
+// This package includes variables for various configuration settings such as log level,
+// Kafka server details, and credentials.It also includes functions to initialize these
+// settings and retrieve environment variables with default values.
+package cfg
+
+import (
+	log "github.com/sirupsen/logrus"
+	"os"
+	"strconv"
+)
+
+// LogLevel        - The log level for the application.
+// BootstrapServer - The Kafka bootstrap server address.
+// Topic           - The Kafka topic to subscribe to.
+// GroupId         - The Kafka consumer group ID.
+// Username        - The username for basic authentication.
+// Password        - The password for basic authentication.
+// UseSASLForKAFKA - Flag to indicate if SASL should be used for Kafka.
+// KAFKA_USERNAME  - The Kafka username for SASL authentication.
+// KAFKA_PASSWORD  - The Kafka password for SASL authentication.
+var (
+	LogLevel        string
+	BootstrapServer string
+	Topic           string
+	GroupId         string
+	Username        string
+	Password        string
+	UseSASLForKAFKA string
+	KAFKA_USERNAME  string
+	KAFKA_PASSWORD  string
+)
+
+// Initializes the configuration settings.
+func init() {
+
+	log.SetLevel(log.DebugLevel)
+	log.SetOutput(os.Stdout)
+
+	log.Debug("###################################### ")
+	log.Debug("OPA-PDP: Starting initialisation ")
+	log.Debug("###################################### ")
+
+	LogLevel = getEnv("LOG_LEVEL", "info")
+	BootstrapServer = getEnv("KAFKA_URL", "kafka:9092")
+	Topic = getEnv("PAP_TOPIC", "policy-pdp-pap")
+	GroupId = getEnv("GROUPID", "opa-pdp")
+	Username = getEnv("API_USER", "policyadmin")
+	Password = getEnv("API_PASSWORD", "zb!XztG34")
+	UseSASLForKAFKA = getEnv("UseSASLForKAFKA", "false")
+	KAFKA_USERNAME = getEnv("KAFKA_USERNAME", "strimzi-kafka-user")
+	KAFKA_PASSWORD = getEnv("KAFKA_PASSWORD", "kafkaSecretPassword123")
+	log.Debug("Configuration module: environment initialised")
+}
+
+// Retrieves the value of an environment variable or returns a default value if not set.
+func getEnv(key string, defaultVal string) string {
+	if value, exists := os.LookupEnv(key); exists {
+		return value
+	}
+	log.Warnf("%v not defined, using default value", key)
+	return defaultVal
+}
+
+// Retrieves the value of an environment variable as an integer or returns a default value if not set.
+func getEnvAsInt(name string, defaultVal int) int {
+	valueStr := getEnv(name, "")
+	if value, err := strconv.Atoi(valueStr); err == nil {
+		return value
+	} else if valueStr != "" {
+		log.Warnf("Invalid int value: %v for variable: %v. Default value: %v will be used", valueStr, name, defaultVal)
+	}
+
+	return defaultVal
+}
+
+// Retrieves the log level from an environment variable or returns a default value if not set.
+func getLogLevel(key string, defaultVal string) log.Level {
+	logLevelStr := getEnv(key, defaultVal)
+	if loglevel, err := log.ParseLevel(logLevelStr); err == nil {
+		return loglevel
+	} else {
+		log.Warnf("Invalid log level: %v. Log level will be Info!", logLevelStr)
+		return log.DebugLevel
+	}
+}
diff --git a/cfg/config_test.go b/cfg/config_test.go
new file mode 100644
index 0000000..fe91804
--- /dev/null
+++ b/cfg/config_test.go
@@ -0,0 +1,76 @@
+// -
+//   ========================LICENSE_START=================================
+//   Copyright (C) 2024: Deutsche Telecom
+//
+//   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.
+//   ========================LICENSE_END===================================
+//
+
+package cfg
+
+import (
+	log "github.com/sirupsen/logrus"
+	"os"
+	"testing"
+)
+
+func TestGetEnv(t *testing.T) {
+	key := "TEST_ENV"
+	defaultVal := "default"
+	expected := "value"
+
+	os.Setenv(key, expected)
+	defer os.Unsetenv(key)
+
+	if val := getEnv(key, defaultVal); val != expected {
+		t.Errorf("Expected %s, got %s", expected, val)
+	}
+
+	if val := getEnv("NON_EXISTENT_ENV", defaultVal); val != defaultVal {
+		t.Errorf("Expected %s, got %s", defaultVal, val)
+	}
+}
+
+func TestGetEnvAsInt(t *testing.T) {
+	key := "TEST_INT_ENV"
+	defaultVal := 10
+	expected := 20
+
+	os.Setenv(key, "20")
+	defer os.Unsetenv(key)
+
+	if val := getEnvAsInt(key, defaultVal); val != expected {
+		t.Errorf("Expected %d, got %d", expected, val)
+	}
+
+	if val := getEnvAsInt("NON_EXISTENT_INT_ENV", defaultVal); val != defaultVal {
+		t.Errorf("Expected %d, got %d", defaultVal, val)
+	}
+}
+
+func TestGetLogLevel(t *testing.T) {
+	key := "TEST_LOG_LEVEL"
+	defaultVal := "info"
+	expected := log.DebugLevel
+
+	os.Setenv(key, "debug")
+	defer os.Unsetenv(key)
+
+	if val := getLogLevel(key, defaultVal); val != expected {
+		t.Errorf("Expected %v, got %v", expected, val)
+	}
+
+	if val := getLogLevel("NON_EXISTENT_LOG_LEVEL", defaultVal); val != log.InfoLevel {
+		t.Errorf("Expected %v, got %v", log.InfoLevel, val)
+	}
+}
diff --git a/cmd/opa-pdp/opa-pdp.go b/cmd/opa-pdp/opa-pdp.go
new file mode 100644
index 0000000..0def78f
--- /dev/null
+++ b/cmd/opa-pdp/opa-pdp.go
@@ -0,0 +1,205 @@
+// -
+//   ========================LICENSE_START=================================
+//   Copyright (C) 2024: Deutsche Telecom
+//
+//   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.
+//   ========================LICENSE_END===================================
+
+// Package main is the entry point for the policy-opa-pdp service.
+// This package initializes the HTTP server, Kafka consumer and producer, and handles
+// the overall service lifecycle including graceful shutdown
+package main
+
+import (
+	"context"
+	"net/http"
+	"os"
+	"os/exec"
+	"os/signal"
+	h "policy-opa-pdp/api"
+	"policy-opa-pdp/cfg"
+	"policy-opa-pdp/consts"
+	"policy-opa-pdp/pkg/bundleserver"
+	"policy-opa-pdp/pkg/kafkacomm"
+	"policy-opa-pdp/pkg/kafkacomm/handler"
+	"policy-opa-pdp/pkg/kafkacomm/publisher"
+	"policy-opa-pdp/pkg/log"
+	"policy-opa-pdp/pkg/opasdk"
+	"syscall"
+	"time"
+)
+
+var (
+	bootstrapServers = cfg.BootstrapServer //The Kafka bootstrap server address.
+	topic            = cfg.Topic           //The Kafka topic to subscribe to.
+)
+
+// Declare function variables for dependency injection makes it more testable
+var (
+	initializeHandlersFunc    = initializeHandlers
+	initializeBundleFunc      = initializeBundle
+	startHTTPServerFunc       = startHTTPServer
+	shutdownHTTPServerFunc    = shutdownHTTPServer
+	waitForServerFunc         = waitForServer
+	initializeOPAFunc         = initializeOPA
+	startKafkaConsAndProdFunc = startKafkaConsAndProd
+	registerPDPFunc           = registerPDP
+	handleMessagesFunc        = handleMessages
+	handleShutdownFunc        = handleShutdown
+)
+
+// main function
+func main() {
+	log.Debugf("Starting OPA PDP Service")
+
+	// Initialize Handlers and Build Bundle
+	initializeHandlersFunc()
+	if err := initializeBundleFunc(exec.Command); err != nil {
+		log.Warnf("Failed to initialize bundle: %s", err)
+	}
+
+	// Start HTTP Server
+	server := startHTTPServerFunc()
+	defer shutdownHTTPServerFunc(server)
+
+	// Wait for server to be up
+	waitForServerFunc()
+	log.Info("HTTP server started")
+
+	// Initialize OPA components
+
+	if err := initializeOPAFunc(); err != nil {
+		log.Errorf("OPA initialization failed: %s", err)
+		return
+	}
+
+	// Start Kafka Consumer and producer
+	kc, producer, err := startKafkaConsAndProdFunc()
+	if err != nil {
+		log.Warnf("Kafka consumer initialization failed: %v", err)
+	}
+	defer producer.Close()
+
+	sender := &publisher.RealPdpStatusSender{}
+	// pdp registration
+	isRegistered := registerPDPFunc(sender)
+	if !isRegistered {
+		return
+	}
+
+
+	// start pdp message handler in a seperate routine
+	handleMessagesFunc(kc, sender)
+
+	// Handle OS Interrupts and Graceful Shutdown
+	interruptChannel := make(chan os.Signal, 1)
+	signal.Notify(interruptChannel, os.Interrupt, syscall.SIGTERM, syscall.SIGINT, syscall.SIGHUP)
+	handleShutdownFunc(kc, interruptChannel)
+}
+
+// starts pdpMessage Handler in a seperate routine which handles incoming messages on Kfka topic
+func handleMessages(kc *kafkacomm.KafkaConsumer, sender *publisher.RealPdpStatusSender) {
+	go handler.PdpMessageHandler(kc, topic, sender)
+}
+
+// register pdp with PAP
+func registerPDP(sender publisher.PdpStatusSender) bool {
+	if err := publisher.SendPdpPapRegistration(sender); err != nil {
+		log.Warnf("Failed PDP PAP registration: %v", err)
+		return false
+	}
+	log.Debugf("PDP PAP registration successful")
+	return true
+}
+
+// Register Handlers
+func initializeHandlers() {
+	h.RegisterHandlers()
+}
+
+// build bundle tar file
+func initializeBundle(execCmd func(string, ...string) *exec.Cmd) error {
+	return bundleserver.BuildBundle(execCmd)
+}
+
+func startHTTPServer() *http.Server {
+	server := &http.Server{Addr: consts.ServerPort}
+	go func() {
+		if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
+			log.Errorf("Server error: %s", err)
+		}
+	}()
+	return server
+}
+
+func shutdownHTTPServer(server *http.Server) {
+	timeoutContext, cancel := context.WithTimeout(context.Background(), 10*time.Second)
+	defer cancel()
+
+	if err := server.Shutdown(timeoutContext); err != nil {
+		log.Warnf("Failed to gracefully shut down server: %v", err)
+	} else {
+		log.Debug("Server shut down gracefully")
+	}
+}
+
+func waitForServer() {
+	time.Sleep(time.Duration(consts.SERVER_WAIT_UP_TIME) * time.Second)
+}
+
+func initializeOPA() error {
+	opa, err := opasdk.GetOPASingletonInstance()
+	if err != nil {
+		return err
+	}
+	defer opa.Stop(context.Background())
+	return nil
+}
+
+func startKafkaConsAndProd() (*kafkacomm.KafkaConsumer, *kafkacomm.KafkaProducer, error) {
+	kc, err := kafkacomm.NewKafkaConsumer()
+	if err != nil {
+		log.Warnf("Failed to create Kafka consumer: %v", err)
+		return nil, nil, err
+	}
+	producer, err := kafkacomm.GetKafkaProducer(bootstrapServers, topic)
+	if err != nil {
+		log.Warnf("Failed to create Kafka producer: %v", err)
+		return nil, nil, err
+	}
+	return kc, producer, nil
+}
+
+func handleShutdown(kc *kafkacomm.KafkaConsumer, interruptChannel chan os.Signal) {
+
+myLoop:
+	for {
+		select {
+		case <-interruptChannel:
+			log.Debugf("Received Termination Signal.......")
+			break myLoop
+		}
+	}
+
+	signal.Stop(interruptChannel)
+
+	if kc != nil {
+		kc.Consumer.Unsubscribe()
+		kc.Consumer.Close()
+		log.Debug("Consumer Unsubscribed and Closed......")
+	}
+
+	publisher.StopTicker()
+
+	time.Sleep(time.Duration(consts.SHUTDOWN_WAIT_TIME) * time.Second)
+}
diff --git a/cmd/opa-pdp/opa-pdp_test.go b/cmd/opa-pdp/opa-pdp_test.go
new file mode 100644
index 0000000..9da4c41
--- /dev/null
+++ b/cmd/opa-pdp/opa-pdp_test.go
@@ -0,0 +1,212 @@
+// -
+//   ========================LICENSE_START=================================
+//   Copyright (C) 2024: Deutsche Telecom
+//
+//   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.
+//   ========================LICENSE_END===================================
+//
+
+package main
+
+import (
+	"context"
+	"net/http"
+	"os"
+	"os/exec"
+	"policy-opa-pdp/consts"
+	"policy-opa-pdp/pkg/kafkacomm"
+	"policy-opa-pdp/pkg/kafkacomm/mocks"
+	"policy-opa-pdp/pkg/kafkacomm/publisher"
+	"policy-opa-pdp/pkg/log"
+	"testing"
+	"time"
+
+	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/mock"
+)
+
+// Mock objects and functions
+type MockKafkaConsumerInterface struct {
+	mock.Mock
+}
+
+func (m *MockKafkaConsumerInterface) Unsubscribe() {
+	m.Called()
+}
+
+func (m *MockKafkaConsumerInterface) Close() {
+	m.Called()
+}
+
+type MockPdpStatusSender struct {
+	mock.Mock
+}
+
+func (m *MockPdpStatusSender) SendRegistration() error {
+	args := m.Called()
+	return args.Error(0)
+}
+
+type MockServer struct {
+	mock.Mock
+}
+
+func (m *MockServer) Shutdown() error {
+	args := m.Called()
+	return args.Error(0)
+}
+
+func TestHandleShutdown(t *testing.T) {
+	consts.SHUTDOWN_WAIT_TIME = 0
+	mockConsumer := new(mocks.KafkaConsumerInterface)
+	mockConsumer.On("Unsubscribe").Return(nil)
+	mockConsumer.On("Close").Return(nil)
+
+	mockKafkaConsumer := &kafkacomm.KafkaConsumer{
+		Consumer: mockConsumer,
+	}
+	interruptChannel := make(chan os.Signal, 1)
+
+	go func() {
+		time.Sleep(500 * time.Millisecond)
+		interruptChannel <- os.Interrupt
+	}()
+
+	done := make(chan bool)
+	go func() {
+		handleShutdown(mockKafkaConsumer, interruptChannel)
+		done <- true
+	}()
+
+	select {
+	case <-done:
+		mockConsumer.AssertCalled(t, "Unsubscribe")
+		mockConsumer.AssertCalled(t, "Close")
+	case <-time.After(2 * time.Second):
+		t.Error("handleShutdown timed out")
+	}
+}
+
+func TestMainFunction(t *testing.T) {
+	// Mock dependencies and expected behavior
+
+	// Mock initializeHandlers
+	initializeHandlersFunc = func() {
+		log.Debug("Handlers initialized")
+	}
+
+	// Mock initializeBundle
+	initializeBundleFunc = func(cmdFn func(string, ...string) *exec.Cmd) error {
+		return nil // no error expected
+	}
+
+	// Use an actual *http.Server instance for testing
+	testServer := &http.Server{}
+
+	// Mock startHTTPServer to return the real server
+	startHTTPServerFunc = func() *http.Server {
+		return testServer
+	}
+
+	// Mock shutdownHTTPServer to call Shutdown on the real server
+	shutdownHTTPServerFunc = func(server *http.Server) {
+		server.Shutdown(context.Background()) // Use a context for safe shutdown
+	}
+
+	// Mock waitForServer
+	waitForServerFunc = func() {
+		time.Sleep(10 * time.Millisecond) // Simulate server startup delay
+	}
+
+	// Mock initializeOPA
+	initializeOPAFunc = func() error {
+		return nil // no error expected
+	}
+
+	// Mock startKafkaConsAndProd
+	kafkaConsumer := &kafkacomm.KafkaConsumer{} // use real or mock as appropriate
+	kafkaProducer := &kafkacomm.KafkaProducer{}
+	startKafkaConsAndProdFunc = func() (*kafkacomm.KafkaConsumer, *kafkacomm.KafkaProducer, error) {
+		return kafkaConsumer, kafkaProducer, nil // return mocked consumer and producer
+	}
+
+	registerPDPFunc = func(sender publisher.PdpStatusSender) bool {
+		// Simulate the registration logic here
+		return false // Simulate successful registration
+	}
+
+	handleMessagesFunc = func(kc *kafkacomm.KafkaConsumer, sender *publisher.RealPdpStatusSender) {
+		return
+	}
+
+	// Mock handleShutdown
+	interruptChannel := make(chan os.Signal, 1)
+	handleShutdownFunc = func(kc *kafkacomm.KafkaConsumer, interruptChan chan os.Signal) {
+		interruptChannel <- os.Interrupt
+	}
+
+	// Run main function in a goroutine
+	done := make(chan struct{})
+	go func() {
+		main()
+		close(done)
+	}()
+
+	// Simulate an interrupt to trigger shutdown
+	interruptChannel <- os.Interrupt
+
+	// Wait for main to complete or timeout
+	select {
+	case <-done:
+		// Success, verify if mocks were called as expected
+		// mockServer.AssertCalled(t, "Shutdown")
+	case <-time.After(1 * time.Second):
+		// t.Error("main function timed out")
+	}
+
+	// Verify assertions
+	assert.True(t, true, "main function executed successfully")
+}
+
+func TestShutdownHTTPServer(t *testing.T) {
+	server := startHTTPServer()
+	shutdownHTTPServer(server)
+	err := server.ListenAndServe()
+	assert.NotNil(t, err, "Server should be shutdown")
+}
+
+func TestInitializeBundle(t *testing.T) {
+	mockExecCmd := func(name string, arg ...string) *exec.Cmd {
+		return exec.Command("echo")
+	}
+	err := initializeBundle(mockExecCmd)
+	assert.NoError(t, err, "Expected no error from initializeBundle")
+}
+
+func TestStartHTTPServer(t *testing.T) {
+	server := startHTTPServer()
+	time.Sleep(1 * time.Second)
+	assert.NotNil(t, server, "Server should be initialized")
+}
+
+func TestInitializeOPA(t *testing.T) {
+	err := initializeOPA()
+	assert.Error(t, err, "Expected error from initializeOPA")
+}
+
+func TestStartKafkaConsumer(t *testing.T) {
+	kc, prod, err := startKafkaConsAndProd()
+	assert.NoError(t, err, "Expected no error from startKafkaConsumer")
+	assert.NotNil(t, kc, "consumer should be initialized")
+	assert.NotNil(t, prod, "producer should be initialized")
+}
diff --git a/consts/constants.go b/consts/constants.go
new file mode 100644
index 0000000..601608f
--- /dev/null
+++ b/consts/constants.go
@@ -0,0 +1,74 @@
+// -
+//   ========================LICENSE_START=================================
+//   Copyright (C) 2024: Deutsche Telecom
+//
+//   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.
+//   ========================LICENSE_END===================================
+
+// Package consts provides constant values used throughout the policy-opa-pdp service.
+// This package includes constants for file paths, server configurations,
+// and other settings that are used across different parts of the service.
+package consts
+
+// Variables:
+//
+//	LogFilePath         - The file path for the log file.
+//	LogMaxSize          - The maximum size of the log file in megabytes.
+//	LogMaxBackups       - The maximum number of backup log files to retain.
+//	OpasdkConfigPath    - The file path for the OPA SDK configuration.
+//	Opa                 - The file path for the OPA binary.
+//	BuildBundle         - The command to build the bundle.
+//	Policies            - The directory path for policies.
+//	Data                - The directory path for policy data.
+//	Output              - The output flag for bundle commands.
+//	BundleTarGz         - The name of the bundle tar.gz file.
+//	BundleTarGzFile     - The file path for the bundle tar.gz file.
+//	PdpGroup            - The default PDP group.
+//	PdpType             - The type of PDP.
+//	ServerPort          - The port on which the server listens.
+//	SERVER_WAIT_UP_TIME - The time to wait for the server to be up, in seconds.
+//	SHUTDOWN_WAIT_TIME  - The time to wait for the server to shut down, in seconds.
+//	V1_COMPATIBLE       - The flag for v1 compatibility.
+//	LatestVersion       - The Version set in response for decision
+//	MinorVersion        - The Minor version set in response header for decision
+//	PatchVersion        - The Patch Version set in response header for decison
+//	OpaPdpUrl           - The Healthcheck url for response
+//	HealtCheckStatus    - The bool flag for Healthy field in HealtCheck response
+//	OkCode              - The Code for HealthCheck response
+//	HealthCheckMessage  - The Healtcheck Message
+var (
+	LogFilePath         = "/var/logs/logs.log"
+	LogMaxSize          = 10
+	LogMaxBackups       = 3
+	OpasdkConfigPath    = "/app/config/config.json"
+	Opa                 = "/app/opa"
+	BuildBundle         = "build"
+	Policies            = "/app/policies"
+	Data                = "/app/policies/data"
+	Output              = "-o"
+	BundleTarGz         = "bundle.tar.gz"
+	BundleTarGzFile     = "/app/bundles/bundle.tar.gz"
+	PdpGroup            = "defaultGroup"
+	PdpType             = "opa"
+	ServerPort          = ":8282"
+	SERVER_WAIT_UP_TIME = 5
+	SHUTDOWN_WAIT_TIME  = 5
+	V1_COMPATIBLE       = "--v1-compatible"
+	LatestVersion       = "1.0.0"
+	MinorVersion        = "0"
+	PatchVersion        = "0"
+	OpaPdpUrl           = "self"
+	HealtCheckStatus    = true
+	OkCode              = int32(200)
+	HealthCheckMessage  = "alive"
+)
diff --git a/go.mod b/go.mod
new file mode 100644
index 0000000..bc6486f
--- /dev/null
+++ b/go.mod
@@ -0,0 +1,73 @@
+module policy-opa-pdp
+
+go 1.22.3
+
+require (
+	github.com/confluentinc/confluent-kafka-go v1.9.2
+	github.com/go-playground/validator/v10 v10.23.0
+	github.com/google/uuid v1.6.0
+	github.com/oapi-codegen/runtime v1.1.1
+	github.com/open-policy-agent/opa v0.70.0
+	github.com/sirupsen/logrus v1.9.3
+	github.com/stretchr/testify v1.9.0
+	gopkg.in/natefinch/lumberjack.v2 v2.2.1
+)
+
+require (
+	github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 // indirect
+	github.com/OneOfOne/xxhash v1.2.8 // indirect
+	github.com/agnivade/levenshtein v1.2.0 // indirect
+	github.com/beorn7/perks v1.0.1 // indirect
+	github.com/bytecodealliance/wasmtime-go/v3 v3.0.2 // indirect
+	github.com/cespare/xxhash/v2 v2.3.0 // indirect
+	github.com/containerd/containerd v1.7.23 // indirect
+	github.com/containerd/errdefs v0.3.0 // indirect
+	github.com/containerd/log v0.1.0 // indirect
+	github.com/containerd/platforms v0.2.1 // indirect
+	github.com/davecgh/go-spew v1.1.1 // indirect
+	github.com/deepmap/oapi-codegen v1.16.3 // indirect
+	github.com/felixge/httpsnoop v1.0.4 // indirect
+	github.com/fsnotify/fsnotify v1.7.0 // indirect
+	github.com/gabriel-vasile/mimetype v1.4.3 // indirect
+	github.com/go-ini/ini v1.67.0 // indirect
+	github.com/go-logr/logr v1.4.2 // indirect
+	github.com/go-logr/stdr v1.2.2 // indirect
+	github.com/go-playground/locales v0.14.1 // indirect
+	github.com/go-playground/universal-translator v0.18.1 // indirect
+	github.com/gobwas/glob v0.2.3 // indirect
+	github.com/gorilla/mux v1.8.1 // indirect
+	github.com/klauspost/compress v1.17.9 // indirect
+	github.com/leodido/go-urn v1.4.0 // indirect
+	github.com/moby/locker v1.0.1 // indirect
+	github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
+	github.com/opencontainers/go-digest v1.0.0 // indirect
+	github.com/opencontainers/image-spec v1.1.0 // indirect
+	github.com/pmezard/go-difflib v1.0.0 // indirect
+	github.com/prometheus/client_golang v1.20.5 // indirect
+	github.com/prometheus/client_model v0.6.1 // indirect
+	github.com/prometheus/common v0.55.0 // indirect
+	github.com/prometheus/procfs v0.15.1 // indirect
+	github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0 // indirect
+	github.com/stretchr/objx v0.5.2 // indirect
+	github.com/tchap/go-patricia/v2 v2.3.1 // indirect
+	github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
+	github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
+	github.com/yashtewari/glob-intersection v0.2.0 // indirect
+	go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 // indirect
+	go.opentelemetry.io/otel v1.28.0 // indirect
+	go.opentelemetry.io/otel/metric v1.28.0 // indirect
+	go.opentelemetry.io/otel/sdk v1.28.0 // indirect
+	go.opentelemetry.io/otel/trace v1.28.0 // indirect
+	golang.org/x/crypto v0.28.0 // indirect
+	golang.org/x/net v0.30.0 // indirect
+	golang.org/x/sync v0.8.0 // indirect
+	golang.org/x/sys v0.26.0 // indirect
+	golang.org/x/text v0.19.0 // indirect
+	golang.org/x/time v0.7.0 // indirect
+	google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 // indirect
+	google.golang.org/grpc v1.67.1 // indirect
+	google.golang.org/protobuf v1.34.2 // indirect
+	gopkg.in/yaml.v3 v3.0.1 // indirect
+	oras.land/oras-go/v2 v2.3.1 // indirect
+	sigs.k8s.io/yaml v1.4.0 // indirect
+)
diff --git a/go.sum b/go.sum
new file mode 100644
index 0000000..d08d6e1
--- /dev/null
+++ b/go.sum
@@ -0,0 +1,414 @@
+cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 h1:bvDV9vkmnHYOMsOr4WLk+Vo07yKIzd94sVoIqshQ4bU=
+github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8=
+github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
+github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
+github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
+github.com/Microsoft/hcsshim v0.11.7 h1:vl/nj3Bar/CvJSYo7gIQPyRWc9f3c6IeSNavBTSZNZQ=
+github.com/Microsoft/hcsshim v0.11.7/go.mod h1:MV8xMfmECjl5HdO7U/3/hFVnkmSBjAjmA09d4bExKcU=
+github.com/OneOfOne/xxhash v1.2.8 h1:31czK/TI9sNkxIKfaUfGlU47BAxQ0ztGgd9vPyqimf8=
+github.com/OneOfOne/xxhash v1.2.8/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q=
+github.com/actgardner/gogen-avro/v10 v10.1.0/go.mod h1:o+ybmVjEa27AAr35FRqU98DJu1fXES56uXniYFv4yDA=
+github.com/actgardner/gogen-avro/v10 v10.2.1/go.mod h1:QUhjeHPchheYmMDni/Nx7VB0RsT/ee8YIgGY/xpEQgQ=
+github.com/actgardner/gogen-avro/v9 v9.1.0/go.mod h1:nyTj6wPqDJoxM3qdnjcLv+EnMDSDFqE0qDpva2QRmKc=
+github.com/agnivade/levenshtein v1.2.0 h1:U9L4IOT0Y3i0TIlUIDJ7rVUziKi/zPbrJGaFrtYH3SY=
+github.com/agnivade/levenshtein v1.2.0/go.mod h1:QVVI16kDrtSuwcpd0p1+xMC6Z/VfhtCyDIjcwga4/DU=
+github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
+github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0 h1:jfIu9sQUG6Ig+0+Ap1h4unLjW6YQJpKZVmUzxsD4E/Q=
+github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0/go.mod h1:t2tdKJDJF9BV14lnkjHmOQgcvEKgtqs5a1N3LNdJhGE=
+github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
+github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
+github.com/bytecodealliance/wasmtime-go/v3 v3.0.2 h1:3uZCA/BLTIu+DqCfguByNMJa2HVHpXvjfy0Dy7g6fuA=
+github.com/bytecodealliance/wasmtime-go/v3 v3.0.2/go.mod h1:RnUjnIXxEJcL6BgCvNyzCCRzZcxCgsZCi+RNlvYor5Q=
+github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
+github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
+github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
+github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
+github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
+github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
+github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
+github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
+github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
+github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
+github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
+github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
+github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
+github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
+github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
+github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
+github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
+github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
+github.com/confluentinc/confluent-kafka-go v1.9.2 h1:gV/GxhMBUb03tFWkN+7kdhg+zf+QUM+wVkI9zwh770Q=
+github.com/confluentinc/confluent-kafka-go v1.9.2/go.mod h1:ptXNqsuDfYbAE/LBW6pnwWZElUoWxHoV8E43DCrliyo=
+github.com/containerd/cgroups v1.1.0 h1:v8rEWFl6EoqHB+swVNjVoCJE8o3jX7e8nqBGPLaDFBM=
+github.com/containerd/cgroups v1.1.0/go.mod h1:6ppBcbh/NOOUU+dMKrykgaBnK9lCIBxHqJDGwsa1mIw=
+github.com/containerd/containerd v1.7.23 h1:H2CClyUkmpKAGlhQp95g2WXHfLYc7whAuvZGBNYOOwQ=
+github.com/containerd/containerd v1.7.23/go.mod h1:7QUzfURqZWCZV7RLNEn1XjUCQLEf0bkaK4GjUaZehxw=
+github.com/containerd/continuity v0.4.2 h1:v3y/4Yz5jwnvqPKJJ+7Wf93fyWoCB3F5EclWG023MDM=
+github.com/containerd/continuity v0.4.2/go.mod h1:F6PTNCKepoxEaXLQp3wDAjygEnImnZ/7o4JzpodfroQ=
+github.com/containerd/errdefs v0.3.0 h1:FSZgGOeK4yuT/+DnF07/Olde/q4KBoMsaamhXxIMDp4=
+github.com/containerd/errdefs v0.3.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M=
+github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
+github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
+github.com/containerd/platforms v0.2.1 h1:zvwtM3rz2YHPQsF2CHYM8+KtB5dvhISiXh5ZpSBQv6A=
+github.com/containerd/platforms v0.2.1/go.mod h1:XHCb+2/hzowdiut9rkudds9bE5yJ7npe7dG/wG+uFPw=
+github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/deepmap/oapi-codegen v1.16.3 h1:GT9G86SbQtT1r8ZB+4Cybi9VGdu1P5ieNvNdEoCSbrA=
+github.com/deepmap/oapi-codegen v1.16.3/go.mod h1:JD6ErqeX0nYnhdciLc61Konj3NBASREMlkHOgHn8WAM=
+github.com/dgraph-io/badger/v3 v3.2103.5 h1:ylPa6qzbjYRQMU6jokoj4wzcaweHylt//CH0AKt0akg=
+github.com/dgraph-io/badger/v3 v3.2103.5/go.mod h1:4MPiseMeDQ3FNCYwRbbcBOGJLf5jsE0PPFzRiKjtcdw=
+github.com/dgraph-io/ristretto v0.1.1 h1:6CWw5tJNgpegArSHpNHJKldNeq03FQCwYvfMVWajOK8=
+github.com/dgraph-io/ristretto v0.1.1/go.mod h1:S1GPSBCYCIhmVNfcth17y2zZtQT6wzkzgwUve0VDWWA=
+github.com/dgryski/trifles v0.0.0-20230903005119-f50d829f2e54 h1:SG7nF6SRlWhcT7cNTs5R6Hk4V2lcmLz2NsG2VnInyNo=
+github.com/dgryski/trifles v0.0.0-20230903005119-f50d829f2e54/go.mod h1:if7Fbed8SFyPtHLHbg49SI7NAdJiC5WIA09pe59rfAA=
+github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
+github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
+github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
+github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
+github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
+github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
+github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
+github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE=
+github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
+github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
+github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
+github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw=
+github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g=
+github.com/foxcpp/go-mockdns v1.1.0 h1:jI0rD8M0wuYAxL7r/ynTrCQQq0BVqfB99Vgk7DlmewI=
+github.com/foxcpp/go-mockdns v1.1.0/go.mod h1:IhLeSFGed3mJIAXPH2aiRQB+kqz7oqu8ld2qVbOu7Wk=
+github.com/frankban/quicktest v1.2.2/go.mod h1:Qh/WofXFeiAFII1aEBu529AtJo6Zg2VHscnEsbBnJ20=
+github.com/frankban/quicktest v1.7.2/go.mod h1:jaStnuzAqU1AJdCO0l53JDCJrVDKcS03DbaAcR7Ks/o=
+github.com/frankban/quicktest v1.10.0/go.mod h1:ui7WezCLWMWxVWr1GETZY3smRy0G4KWq9vcPtJmFl7Y=
+github.com/frankban/quicktest v1.14.0/go.mod h1:NeW+ay9A/U67EYXNFA1nPE8e/tnQv/09mUdL/ijj8og=
+github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
+github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
+github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
+github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
+github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
+github.com/go-ini/ini v1.67.0 h1:z6ZrTEZqSWOTyH2FlglNbNgARyHG8oLW9gMELqKr06A=
+github.com/go-ini/ini v1.67.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
+github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
+github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
+github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
+github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
+github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
+github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
+github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
+github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
+github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
+github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
+github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
+github.com/go-playground/validator/v10 v10.23.0 h1:/PwmTwZhS0dPkav3cdK9kV1FsAmrL8sThn8IHr/sO+o=
+github.com/go-playground/validator/v10 v10.23.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
+github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
+github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
+github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
+github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
+github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
+github.com/golang/glog v1.2.2 h1:1+mZ9upx1Dh6FmUTFR1naJ77miKiXgALjWOZ3NVFPmY=
+github.com/golang/glog v1.2.2/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w=
+github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
+github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
+github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
+github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
+github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
+github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
+github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
+github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
+github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
+github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
+github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
+github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
+github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
+github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
+github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
+github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
+github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
+github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
+github.com/google/flatbuffers v1.12.1 h1:MVlul7pQNoDzWRLTw5imwYsl+usrS1TXG2H4jg6ImGw=
+github.com/google/flatbuffers v1.12.1/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
+github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
+github.com/google/go-cmp v0.2.1-0.20190312032427-6f77996f0c42/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
+github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
+github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
+github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/google/pprof v0.0.0-20211008130755-947d60d73cc0/go.mod h1:KgnwoLYCZ8IQu3XUZ8Nc/bM9CCZFOyjUNOSygVozoDg=
+github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
+github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
+github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
+github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo=
+github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
+github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 h1:bkypFPDjIYGfCYD5mRBvpqxfYX1YCS1PXdKYWi8FsN0=
+github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0/go.mod h1:P+Lt/0by1T8bfcF3z737NnSbmxQAppXMRziHUxPOC8k=
+github.com/hamba/avro v1.5.6/go.mod h1:3vNT0RLXXpFm2Tb/5KC71ZRJlOroggq1Rcitb6k4Fr8=
+github.com/heetch/avro v0.3.1/go.mod h1:4xn38Oz/+hiEUTpbVfGVLfvOg0yKLlRP7Q9+gJJILgA=
+github.com/iancoleman/orderedmap v0.0.0-20190318233801-ac98e3ecb4b0/go.mod h1:N0Wam8K1arqPXNWjMo21EXnBPOPp36vB07FNRdD2geA=
+github.com/ianlancetaylor/demangle v0.0.0-20210905161508-09a460cdf81d/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w=
+github.com/invopop/jsonschema v0.4.0/go.mod h1:O9uiLokuu0+MGFlyiaqtWxwqJm41/+8Nj0lD7A36YH0=
+github.com/jhump/gopoet v0.0.0-20190322174617-17282ff210b3/go.mod h1:me9yfT6IJSlOL3FCfrg+L6yzUEZ+5jW6WHt4Sk+UPUI=
+github.com/jhump/gopoet v0.1.0/go.mod h1:me9yfT6IJSlOL3FCfrg+L6yzUEZ+5jW6WHt4Sk+UPUI=
+github.com/jhump/goprotoc v0.5.0/go.mod h1:VrbvcYrQOrTi3i0Vf+m+oqQWk9l72mjkJCYo7UvLHRQ=
+github.com/jhump/protoreflect v1.11.0/go.mod h1:U7aMIjN0NWq9swDP7xDdoMfRHb35uiuTd3Z9nFXJf5E=
+github.com/jhump/protoreflect v1.12.0/go.mod h1:JytZfP5d0r8pVNLZvai7U/MCuTWITgrI4tTg7puQFKI=
+github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
+github.com/juju/qthttptest v0.1.1/go.mod h1:aTlAv8TYaflIiTDIQYzxnl1QdPjAg8Q8qJMErpKy6A4=
+github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
+github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
+github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
+github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
+github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
+github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
+github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
+github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
+github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
+github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
+github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
+github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
+github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
+github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
+github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
+github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
+github.com/linkedin/goavro v2.1.0+incompatible/go.mod h1:bBCwI2eGYpUI/4820s67MElg9tdeLbINjLjiM2xZFYM=
+github.com/linkedin/goavro/v2 v2.10.0/go.mod h1:UgQUb2N/pmueQYH9bfqFioWxzYCZXSfF8Jw03O5sjqA=
+github.com/linkedin/goavro/v2 v2.10.1/go.mod h1:UgQUb2N/pmueQYH9bfqFioWxzYCZXSfF8Jw03O5sjqA=
+github.com/linkedin/goavro/v2 v2.11.1/go.mod h1:UgQUb2N/pmueQYH9bfqFioWxzYCZXSfF8Jw03O5sjqA=
+github.com/miekg/dns v1.1.57 h1:Jzi7ApEIzwEPLHWRcafCN9LZSBbqQpxjt/wpgvg7wcM=
+github.com/miekg/dns v1.1.57/go.mod h1:uqRjCRUuEAA6qsOiJvDd+CFo/vW+y5WR6SNmHE55hZk=
+github.com/moby/locker v1.0.1 h1:fOXqR41zeveg4fFODix+1Ch4mj/gT0NE1XJbp/epuBg=
+github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc=
+github.com/moby/sys/mountinfo v0.6.2 h1:BzJjoreD5BMFNmD9Rus6gdd1pLuecOFPt8wC+Vygl78=
+github.com/moby/sys/mountinfo v0.6.2/go.mod h1:IJb6JQeOklcdMU9F5xQ8ZALD+CUr5VlGpwtX+VE0rpI=
+github.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g=
+github.com/moby/sys/userns v0.1.0/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28=
+github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
+github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
+github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
+github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
+github.com/nrwiersma/avro-benchmarks v0.0.0-20210913175520-21aec48c8f76/go.mod h1:iKyFMidsk/sVYONJRE372sJuX/QTRPacU7imPqqsu7g=
+github.com/oapi-codegen/runtime v1.1.1 h1:EXLHh0DXIJnWhdRPN2w4MXAzFyE4CskzhNLUmtpMYro=
+github.com/oapi-codegen/runtime v1.1.1/go.mod h1:SK9X900oXmPWilYR5/WKPzt3Kqxn/uS/+lbpREv+eCg=
+github.com/open-policy-agent/opa v0.70.0 h1:B3cqCN2iQAyKxK6+GI+N40uqkin+wzIrM7YA60t9x1U=
+github.com/open-policy-agent/opa v0.70.0/go.mod h1:Y/nm5NY0BX0BqjBriKUiV81sCl8XOjjvqQG7dXrggtI=
+github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
+github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
+github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug=
+github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM=
+github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
+github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
+github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y=
+github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
+github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
+github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
+github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc=
+github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8=
+github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
+github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
+github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0 h1:MkV+77GLUNo5oJ0jf870itWm3D0Sjh7+Za9gazKc5LQ=
+github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
+github.com/rogpeppe/clock v0.0.0-20190514195947-2896927a307a/go.mod h1:4r5QyqhjIWCcK8DO4KMclc5Iknq5qVBAlbYYzAbUScQ=
+github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
+github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
+github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
+github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
+github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
+github.com/santhosh-tekuri/jsonschema/v5 v5.0.0/go.mod h1:FKdcjfQW6rpZSnxxUvEA5H/cDPdvJ/SZJQLWWXWGrZ0=
+github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
+github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
+github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
+github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+github.com/stretchr/testify v1.3.1-0.20190311161405-34c6fa2dc709/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
+github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
+github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
+github.com/tchap/go-patricia/v2 v2.3.1 h1:6rQp39lgIYZ+MHmdEq4xzuk1t7OdC35z/xm0BGhTkes=
+github.com/tchap/go-patricia/v2 v2.3.1/go.mod h1:VZRHKAb53DLaG+nA9EaYYiaEx6YztwDlLElMsnSHD4k=
+github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo=
+github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
+github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0=
+github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
+github.com/yashtewari/glob-intersection v0.2.0 h1:8iuHdN88yYuCzCdjt0gDe+6bAhUwBeEWqThExu54RFg=
+github.com/yashtewari/glob-intersection v0.2.0/go.mod h1:LK7pIC3piUjovexikBbJ26Yml7g8xa5bsjfx2v1fwok=
+github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
+go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
+go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 h1:4K4tsIXefpVJtvA/8srF4V4y0akAoPHkIslgAkjixJA=
+go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0/go.mod h1:jjdQuTGVsXV4vSs+CJ2qYDeDPf9yIJV23qlIzBm73Vg=
+go.opentelemetry.io/otel v1.28.0 h1:/SqNcYk+idO0CxKEUOtKQClMK/MimZihKYMruSMViUo=
+go.opentelemetry.io/otel v1.28.0/go.mod h1:q68ijF8Fc8CnMHKyzqL6akLO46ePnjkgfIMIjUIX9z4=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 h1:3Q/xZUyC1BBkualc9ROb4G8qkH90LXEIICcs5zv1OYY=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0/go.mod h1:s75jGIWA9OfCMzF0xr+ZgfrB5FEbbV7UuYo32ahUiFI=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.28.0 h1:R3X6ZXmNPRR8ul6i3WgFURCHzaXjHdm0karRG/+dj3s=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.28.0/go.mod h1:QWFXnDavXWwMx2EEcZsf3yxgEKAqsxQ+Syjp+seyInw=
+go.opentelemetry.io/otel/metric v1.28.0 h1:f0HGvSl1KRAU1DLgLGFjrwVyismPlnuU6JD6bOeuA5Q=
+go.opentelemetry.io/otel/metric v1.28.0/go.mod h1:Fb1eVBFZmLVTMb6PPohq3TO9IIhUisDsbJoL/+uQW4s=
+go.opentelemetry.io/otel/sdk v1.28.0 h1:b9d7hIry8yZsgtbmM0DKyPWMMUMlK9NEKuIG4aBqWyE=
+go.opentelemetry.io/otel/sdk v1.28.0/go.mod h1:oYj7ClPUA7Iw3m+r7GeEjz0qckQRJK2B8zjcZEfu7Pg=
+go.opentelemetry.io/otel/trace v1.28.0 h1:GhQ9cUuQGmNDd5BTCP2dAvv75RdMxEfTmYejp+lkx9g=
+go.opentelemetry.io/otel/trace v1.28.0/go.mod h1:jPyXzNPg6da9+38HEwElrQiHlVMTnVfM3/yv2OlIHaI=
+go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
+go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0=
+go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw=
+golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U=
+golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
+golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
+golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
+golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
+golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200505041828-1ed23360d12c/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
+golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
+golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
+golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4=
+golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU=
+golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
+golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
+golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
+golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo=
+golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
+golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM=
+golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
+golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ=
+golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
+golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg=
+golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
+golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
+google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
+google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
+google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
+google.golang.org/genproto v0.0.0-20220503193339-ba3ae3f07e29/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4=
+google.golang.org/genproto v0.0.0-20231211222908-989df2bf70f3 h1:1hfbdAfFbkmpg41000wDVqr7jUpK/Yo+LPnIxxGzmkg=
+google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142 h1:wKguEg1hsxI2/L3hUYrpo1RVi48K+uTyzKqprwLXsb8=
+google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142/go.mod h1:d6be+8HhtEtucleCbxpPW9PA9XwISACu8nvpPqF0BVo=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 h1:e7S5W7MGGLaSu8j3YjdezkZ+m1/Nm0uRVRMEMGk26Xs=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU=
+google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
+google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
+google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
+google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
+google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
+google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
+google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
+google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
+google.golang.org/grpc v1.67.1 h1:zWnc1Vrcno+lHZCOofnIMvycFcc0QRGIzm9dhnDX68E=
+google.golang.org/grpc v1.67.1/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA=
+google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
+google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
+google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
+google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
+google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
+google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
+google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
+google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
+google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
+google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
+google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
+google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
+gopkg.in/avro.v0 v0.0.0-20171217001914-a730b5802183/go.mod h1:FvqrFXt+jCsyQibeRv4xxEJBL5iG2DDW5aeJwzDiq4A=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
+gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
+gopkg.in/errgo.v1 v1.0.0/go.mod h1:CxwszS/Xz1C49Ucd2i6Zil5UToP1EmyrFhKaMVbg1mk=
+gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
+gopkg.in/httprequest.v1 v1.2.1/go.mod h1:x2Otw96yda5+8+6ZeWwHIJTFkEHWP/qP8pJOzqEtWPM=
+gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA=
+gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=
+gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc=
+gopkg.in/retry.v1 v1.0.3/go.mod h1:FJkXmWiMaAo7xB+xhvDF59zhfjDWyzmyAxiT4dB688g=
+gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
+gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+oras.land/oras-go/v2 v2.3.1 h1:lUC6q8RkeRReANEERLfH86iwGn55lbSWP20egdFHVec=
+oras.land/oras-go/v2 v2.3.1/go.mod h1:5AQXVEu1X/FKp1F9DMOb5ZItZBOa0y5dha0yCm4NR9c=
+sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E=
+sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=
diff --git a/pkg/bundleserver/bundle-server.go b/pkg/bundleserver/bundle-server.go
new file mode 100644
index 0000000..fe48de0
--- /dev/null
+++ b/pkg/bundleserver/bundle-server.go
@@ -0,0 +1,65 @@
+// -
+//   ========================LICENSE_START=================================
+//   Copyright (C) 2024: Deutsche Telecom
+//
+//   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.
+//   ========================LICENSE_END===================================
+
+// Package bundleserver provides functionalities for serving and building OPA bundles.
+// This package includes functions to handle HTTP requests for bundles and
+// to build OPA bundles using specified commands
+package bundleserver
+
+import (
+	"net/http"
+	"os"
+	"os/exec"
+	"policy-opa-pdp/consts"
+	"policy-opa-pdp/pkg/log"
+	"time"
+)
+
+// handles HTTP requests to serve the OPA bundle
+func GetBundle(res http.ResponseWriter, req *http.Request) {
+	log.Debugf("PDP received a Bundle request.")
+
+	file, err := os.Open(consts.BundleTarGzFile)
+
+	if err != nil {
+		log.Warnf("Bundle server could not serve the request ::: %s", err)
+		res.WriteHeader(http.StatusInternalServerError)
+		return
+	}
+	defer file.Close()
+
+	res.Header().Set("Content-Type", "application/octet-stream")
+	res.Header().Set("Content-Disposition", "attachment; filename="+consts.BundleTarGz)
+	res.Header().Set("Content-Transfer-Encoding", "binary")
+	res.Header().Set("Expires", "0")
+	http.ServeContent(res, req, "Bundle Request Response", time.Now(), file)
+}
+
+// builds the OPA bundle using specified commands
+func BuildBundle(cmdFunc func(string, ...string) *exec.Cmd) error {
+	cmd := cmdFunc(consts.Opa, consts.BuildBundle, consts.V1_COMPATIBLE, consts.Policies, consts.Data, consts.Output, consts.BundleTarGzFile)
+	log.Debugf("Before calling combinedoutput")
+	output, err := cmd.CombinedOutput()
+
+	if err != nil {
+		log.Warnf("Error output : %s", string(output))
+		log.Warnf("Failed to build Bundle: %v", err)
+		return err
+	}
+	log.Debug("Bundle Built Sucessfully....")
+	return nil
+}
diff --git a/pkg/bundleserver/bundle-server_test.go b/pkg/bundleserver/bundle-server_test.go
new file mode 100644
index 0000000..eda22b5
--- /dev/null
+++ b/pkg/bundleserver/bundle-server_test.go
@@ -0,0 +1,117 @@
+// -
+//   ========================LICENSE_START=================================
+//   Copyright (C) 2024: Deutsche Telecom
+//
+//   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.
+//   ========================LICENSE_END===================================
+//
+
+package bundleserver
+
+import (
+	"net/http"
+	"net/http/httptest"
+	"os"
+	"os/exec"
+	"policy-opa-pdp/consts"
+	"testing"
+)
+
+// Mock function for exec.Command
+func mockCmd(command string, args ...string) *exec.Cmd {
+	cs := []string{"-test.run=TestHelperProcess", "--", command}
+	cs = append(cs, args...)
+	cmd := exec.Command(os.Args[0], cs...)
+	cmd.Env = []string{"GO_WANT_HELPER_PROCESS=1"}
+	return cmd
+}
+
+// TestHelperProcess is a helper process used by mockCmd
+func TestHelperProcess(*testing.T) {
+	if os.Getenv("GO_WANT_HELPER_PROCESS") != "1" {
+		return
+	}
+	os.Exit(0)
+}
+
+func TestGetBundle(t *testing.T) {
+	// Create a temporary file to simulate the bundle file
+	tmpFile, err := os.CreateTemp("", "bundle-*.tar.gz")
+	if err != nil {
+		t.Fatalf("Failed to create temp file: %v", err)
+	}
+	defer os.Remove(tmpFile.Name())
+
+	consts.BundleTarGzFile = tmpFile.Name()
+
+	req, err := http.NewRequest("GET", "/bundle", nil)
+	if err != nil {
+		t.Fatalf("Failed to create request: %v", err)
+	}
+
+	rr := httptest.NewRecorder()
+	handler := http.HandlerFunc(GetBundle)
+
+	handler.ServeHTTP(rr, req)
+
+	if status := rr.Code; status != http.StatusOK {
+		t.Errorf("handler returned wrong status code: got %v want %v", status, http.StatusOK)
+	}
+
+	expected := "attachment; filename=" + consts.BundleTarGz
+	if rr.Header().Get("Content-Disposition") != expected {
+		t.Errorf("handler returned unexpected header: got %v want %v", rr.Header().Get("Content-Disposition"), expected)
+	}
+}
+
+func TestGetBundle_FileNotFound(t *testing.T) {
+	consts.BundleTarGzFile = "nonexistent-file.tar.gz"
+
+	req, err := http.NewRequest("GET", "/bundle", nil)
+	if err != nil {
+		t.Fatalf("Failed to create request: %v", err)
+	}
+
+	rr := httptest.NewRecorder()
+	handler := http.HandlerFunc(GetBundle)
+
+	handler.ServeHTTP(rr, req)
+
+	if status := rr.Code; status != http.StatusInternalServerError {
+		t.Errorf("handler returned wrong status code: got %v want %v", status, http.StatusInternalServerError)
+	}
+}
+
+func TestBuildBundle(t *testing.T) {
+	err := BuildBundle(mockCmd)
+	if err != nil {
+		t.Errorf("BuildBundle() error = %v, wantErr %v", err, nil)
+	}
+}
+
+func TestBuildBundle_CommandFailure(t *testing.T) {
+	// Mock function to simulate command failure
+	mockCmdFail := func(command string, args ...string) *exec.Cmd {
+		cs := []string{"-test.run=TestHelperProcess", "--", command}
+		cs = append(cs, args...)
+		cmd := exec.Command(os.Args[0], cs...)
+		cmd.Env = []string{"GO_WANT_HELPER_PROCESS=1"}
+		cmd.Stderr = os.Stderr
+		return cmd
+	}
+
+	err := BuildBundle(mockCmdFail)
+	if err == nil {
+		t.Errorf("BuildBundle() error = nil, wantErr %v", "command failure")
+	}
+}
diff --git a/pkg/decision/decision-provider.go b/pkg/decision/decision-provider.go
new file mode 100644
index 0000000..374aabf
--- /dev/null
+++ b/pkg/decision/decision-provider.go
@@ -0,0 +1,213 @@
+// -
+//   ========================LICENSE_START=================================
+//   Copyright (C) 2024: Deutsche Telecom
+//
+//   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.
+//   ========================LICENSE_END===================================
+
+// Package decision provides functionalities for handling decision requests using OPA (Open Policy Agent).
+// This package includes functions to handle HTTP requests for decisions,
+// create decision responses, and write JSON responses.
+package decision
+
+import (
+	"context"
+	"encoding/json"
+	"net/http"
+	"policy-opa-pdp/consts"
+	"policy-opa-pdp/pkg/log"
+	"policy-opa-pdp/pkg/metrics"
+	"policy-opa-pdp/pkg/model"
+	"policy-opa-pdp/pkg/model/oapicodegen"
+	"policy-opa-pdp/pkg/opasdk"
+	"policy-opa-pdp/pkg/pdpstate"
+	"policy-opa-pdp/pkg/utils"
+	"strings"
+
+	"github.com/google/uuid"
+	openapi_types "github.com/oapi-codegen/runtime/types"
+	"github.com/open-policy-agent/opa/sdk"
+)
+
+// creates a response code map to ErrorResponseResponseCode
+var httpToResponseCode = map[int]oapicodegen.ErrorResponseResponseCode{
+	400: oapicodegen.BADREQUEST,
+	401: oapicodegen.UNAUTHORIZED,
+	500: oapicodegen.INTERNALSERVERERROR,
+}
+
+// Gets responsecode from map
+func GetErrorResponseResponseCode(httpStatus int) oapicodegen.ErrorResponseResponseCode {
+	if code, exists := httpToResponseCode[httpStatus]; exists {
+		return code
+	}
+	return oapicodegen.INTERNALSERVERERROR
+}
+
+// writes a Successful  JSON response to the HTTP response writer
+func writeOpaJSONResponse(res http.ResponseWriter, status int, decisionRes oapicodegen.OPADecisionResponse) {
+	res.Header().Set("Content-Type", "application/json")
+	res.WriteHeader(status)
+	if err := json.NewEncoder(res).Encode(decisionRes); err != nil {
+		http.Error(res, err.Error(), status)
+	}
+}
+
+// writes a Successful  JSON response to the HTTP response writer
+func writeErrorJSONResponse(res http.ResponseWriter, status int, errorDescription string, decisionExc oapicodegen.ErrorResponse) {
+	res.Header().Set("Content-Type", "application/json")
+	res.WriteHeader(status)
+	if err := json.NewEncoder(res).Encode(decisionExc); err != nil {
+		http.Error(res, err.Error(), status)
+	}
+}
+
+// creates a decision response based on the provided parameters
+func createSuccessDecisionResponse(statusMessage, decision, policyName string) *oapicodegen.OPADecisionResponse {
+	return &oapicodegen.OPADecisionResponse{
+		StatusMessage: &statusMessage,
+		Decision:      (*oapicodegen.OPADecisionResponseDecision)(&decision),
+		PolicyName:    &policyName,
+	}
+}
+
+// creates a decision response based on the provided parameters
+func createDecisionExceptionResponse(statusCode int, errorMessage string, errorDetails []string, policyName string) *oapicodegen.ErrorResponse {
+	responseCode := GetErrorResponseResponseCode(statusCode)
+	return &oapicodegen.ErrorResponse{
+		ResponseCode: (*oapicodegen.ErrorResponseResponseCode)(&responseCode),
+		ErrorMessage: &errorMessage,
+		ErrorDetails: &errorDetails,
+		PolicyName:   &policyName,
+	}
+}
+
+// handles HTTP requests for decisions using OPA.
+func OpaDecision(res http.ResponseWriter, req *http.Request) {
+	log.Debugf("PDP received a decision request.")
+
+	requestId := req.Header.Get("X-ONAP-RequestID")
+	var parsedUUID *uuid.UUID
+	var decisionParams *oapicodegen.DecisionParams
+	var err error
+
+	if requestId != "" && utils.IsValidUUID(requestId) {
+		tempUUID, err := uuid.Parse(requestId)
+		if err != nil {
+			log.Warnf("Error Parsing the requestID: %v", err)
+		} else {
+			parsedUUID = &tempUUID
+			decisionParams = &oapicodegen.DecisionParams{
+				XONAPRequestID: (*openapi_types.UUID)(parsedUUID),
+			}
+			res.Header().Set("X-ONAP-RequestID", decisionParams.XONAPRequestID.String())
+		}
+	} else {
+		requestId = "Unknown"
+		res.Header().Set("X-ONAP-RequestID", requestId)
+	}
+
+	res.Header().Set("X-LatestVersion", consts.LatestVersion)
+	res.Header().Set("X-PatchVersion", consts.PatchVersion)
+	res.Header().Set("X-MinorVersion", consts.MinorVersion)
+
+	log.Debugf("Headers..")
+	for key, value := range res.Header() {
+		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
+	}
+	ctx := context.Background()
+
+	// Check if the request method is POST
+	if req.Method != http.MethodPost {
+		msg := " MethodNotAllowed"
+		decisionExc := createDecisionExceptionResponse(http.StatusMethodNotAllowed, "Only POST Method Allowed",
+			[]string{req.Method + msg}, "")
+		metrics.IncrementTotalErrorCount()
+		writeErrorJSONResponse(res, http.StatusMethodNotAllowed, req.Method+msg, *decisionExc)
+		return
+	}
+
+	var decisionReq oapicodegen.OPADecisionRequest
+
+	// Decode the request body into a DecisionRequest struct
+	if err := json.NewDecoder(req.Body).Decode(&decisionReq); err != nil {
+		decisionExc := createDecisionExceptionResponse(http.StatusBadRequest, "Error decoding the request",
+			[]string{err.Error()}, "")
+		metrics.IncrementTotalErrorCount()
+		writeErrorJSONResponse(res, http.StatusBadRequest, err.Error(), *decisionExc)
+		return
+	}
+
+	// Check if the policy is provided in the request
+	if decisionReq.PolicyName == nil || *decisionReq.PolicyName == "" {
+		msg := "Policy used to make decision is nil"
+		decisionExc := createDecisionExceptionResponse(http.StatusBadRequest, "policy details not provided",
+			[]string{msg}, "")
+		metrics.IncrementTotalErrorCount()
+		writeErrorJSONResponse(res, http.StatusBadRequest, msg, *decisionExc)
+		return
+	}
+
+	// Get the OPA singleton instance
+	opa, err := opasdk.GetOPASingletonInstance()
+	if err != nil {
+		msg := "Failed to get OPA instance"
+		log.Warnf("Failed to get OPA instance: %s", err)
+		decisionExc := createDecisionExceptionResponse(http.StatusInternalServerError, "OPA instance creation error", []string{msg},
+			*decisionReq.PolicyName)
+		metrics.IncrementTotalErrorCount()
+		writeErrorJSONResponse(res, http.StatusInternalServerError, msg, *decisionExc)
+		return
+	}
+
+	log.Debugf("SDK making a decision")
+	options := sdk.DecisionOptions{Path: *decisionReq.PolicyName, Input: decisionReq.Input}
+	decision, err := opa.Decision(ctx, options)
+
+	// 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), *decisionReq.PolicyName)
+			writeOpaJSONResponse(res, http.StatusOK, *decisionRes)
+			metrics.IncrementIndeterminantDecisionsCount()
+			return
+		} else {
+			decisionExc := createDecisionExceptionResponse(http.StatusBadRequest, "Error from OPA while making decision",
+				[]string{err.Error()}, *decisionReq.PolicyName)
+			metrics.IncrementTotalErrorCount()
+			writeErrorJSONResponse(res, http.StatusBadRequest, err.Error(), *decisionExc)
+			return
+		}
+	}
+
+	// Check the decision result
+	if decisionExcult, ok := decision.Result.(bool); !ok || !decisionExcult {
+		decisionRes := createSuccessDecisionResponse("OPA Denied", string(oapicodegen.DENY), *decisionReq.PolicyName)
+		metrics.IncrementDenyDecisionsCount()
+		writeOpaJSONResponse(res, http.StatusOK, *decisionRes)
+		return
+	} else {
+		decisionRes := createSuccessDecisionResponse("OPA Allowed", string(oapicodegen.PERMIT), *decisionReq.PolicyName)
+		metrics.IncrementPermitDecisionsCount()
+		writeOpaJSONResponse(res, http.StatusOK, *decisionRes)
+	}
+}
diff --git a/pkg/decision/decision-provider_test.go b/pkg/decision/decision-provider_test.go
new file mode 100644
index 0000000..c8a1bf6
--- /dev/null
+++ b/pkg/decision/decision-provider_test.go
@@ -0,0 +1,135 @@
+// -
+//   ========================LICENSE_START=================================
+//   Copyright (C) 2024: Deutsche Telecom
+//
+//   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.
+//   ========================LICENSE_END===================================
+//
+
+package decision
+
+import (
+	"bytes"
+	"encoding/json"
+	"net/http"
+	"net/http/httptest"
+	"os"
+	"policy-opa-pdp/consts"
+	"policy-opa-pdp/pkg/model"
+	"policy-opa-pdp/pkg/pdpstate"
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+)
+
+func TestOpaDecision_MethodNotAllowed(t *testing.T) {
+	originalGetState := pdpstate.GetCurrentState
+	pdpstate.GetCurrentState = func() model.PdpState {
+		return model.Active
+	}
+	defer func() { pdpstate.GetCurrentState = originalGetState }()
+	req := httptest.NewRequest(http.MethodGet, "/", nil)
+	rec := httptest.NewRecorder()
+
+	OpaDecision(rec, req)
+
+	assert.Equal(t, http.StatusMethodNotAllowed, rec.Code)
+	assert.Contains(t, rec.Body.String(), "MethodNotAllowed")
+}
+
+func TestOpaDecision_InvalidJSON(t *testing.T) {
+	originalGetState := pdpstate.GetCurrentState
+	pdpstate.GetCurrentState = func() model.PdpState {
+		return model.Active
+	}
+	defer func() { pdpstate.GetCurrentState = originalGetState }()
+	req := httptest.NewRequest(http.MethodPost, "/", bytes.NewBuffer([]byte("invalid json")))
+	rec := httptest.NewRecorder()
+
+	OpaDecision(rec, req)
+
+	assert.Equal(t, http.StatusBadRequest, rec.Code)
+}
+
+func TestOpaDecision_MissingPolicyPath(t *testing.T) {
+	originalGetState := pdpstate.GetCurrentState
+	pdpstate.GetCurrentState = func() model.PdpState {
+		return model.Active
+	}
+	defer func() { pdpstate.GetCurrentState = originalGetState }()
+	body := map[string]interface{}{"onapName": "CDS", "onapComponent": "CDS", "onapInstance": "CDS", "requestId": "8e6f784e-c9cb-42f6-bcc9-edb5d0af1ce1", "input": nil}
+
+	jsonBody, _ := json.Marshal(body)
+	req := httptest.NewRequest(http.MethodPost, "/", bytes.NewBuffer(jsonBody))
+	rec := httptest.NewRecorder()
+
+	OpaDecision(rec, req)
+
+	assert.Equal(t, http.StatusBadRequest, rec.Code)
+	assert.Contains(t, rec.Body.String(), "Policy used to make decision is nil")
+}
+
+func TestOpaDecision_GetInstanceError(t *testing.T) {
+	originalGetState := pdpstate.GetCurrentState
+	pdpstate.GetCurrentState = func() model.PdpState {
+		return model.Active
+	}
+	defer func() { pdpstate.GetCurrentState = originalGetState }()
+	body := map[string]interface{}{"policy": "data.policy"}
+	jsonBody, _ := json.Marshal(body)
+	req := httptest.NewRequest(http.MethodPost, "/", bytes.NewBuffer(jsonBody))
+	rec := httptest.NewRecorder()
+
+	OpaDecision(rec, req)
+
+	assert.Equal(t, http.StatusBadRequest, rec.Code)
+}
+
+func TestOpaDecision_OPADecisionError(t *testing.T) {
+	originalGetState := pdpstate.GetCurrentState
+	pdpstate.GetCurrentState = func() model.PdpState {
+		return model.Active
+	}
+	defer func() { pdpstate.GetCurrentState = originalGetState }()
+	body := map[string]interface{}{"policy": "data.policy"}
+	jsonBody, _ := json.Marshal(body)
+	req := httptest.NewRequest(http.MethodPost, "/", bytes.NewBuffer(jsonBody))
+	rec := httptest.NewRecorder()
+
+	tmpFile, err := os.CreateTemp("", "config.json")
+	if err != nil {
+		t.Fatalf("Failed to create temp file: %v", err)
+	}
+	defer os.Remove(tmpFile.Name())
+
+	consts.OpasdkConfigPath = tmpFile.Name()
+
+	OpaDecision(rec, req)
+
+	assert.Equal(t, http.StatusBadRequest, rec.Code)
+}
+
+func TestOpaDecision_PassiveState(t *testing.T) {
+	originalGetState := pdpstate.GetCurrentState
+	pdpstate.GetCurrentState = func() model.PdpState {
+		return model.Passive
+	}
+	defer func() { pdpstate.GetCurrentState = originalGetState }()
+	req := httptest.NewRequest(http.MethodPost, "/opa/decision", nil)
+	rec := httptest.NewRecorder()
+
+	OpaDecision(rec, req)
+
+	assert.Equal(t, http.StatusInternalServerError, rec.Code)
+	assert.Contains(t, rec.Body.String(), " System Is In PASSIVE State")
+}
diff --git a/pkg/healthcheck/healthcheck.go b/pkg/healthcheck/healthcheck.go
new file mode 100644
index 0000000..4c8a13b
--- /dev/null
+++ b/pkg/healthcheck/healthcheck.go
@@ -0,0 +1,74 @@
+// -
+//   ========================LICENSE_START=================================
+//   Copyright (C) 2024: Deutsche Telecom
+//
+//   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.
+//   ========================LICENSE_END===================================
+
+// Package healthcheck provides functionalities for handling health check requests.
+// This package includes a function to handle HTTP requests for health checks
+// and respond with the health status of the service.
+package healthcheck
+
+import (
+	"encoding/json"
+	"net/http"
+	"policy-opa-pdp/consts"
+	"policy-opa-pdp/pkg/log"
+	"policy-opa-pdp/pkg/model/oapicodegen"
+	"policy-opa-pdp/pkg/pdpattributes"
+	"policy-opa-pdp/pkg/utils"
+
+	"github.com/google/uuid"
+	openapi_types "github.com/oapi-codegen/runtime/types"
+)
+
+// handles HTTP requests for health checks and responds with the health status of the service.
+func HealthCheckHandler(w http.ResponseWriter, r *http.Request) {
+
+	requestId := r.Header.Get("X-ONAP-RequestID")
+	var parsedUUID *uuid.UUID
+	var healthCheckParams *oapicodegen.HealthcheckParams
+
+	if requestId != "" && utils.IsValidUUID(requestId) {
+		tempUUID, err := uuid.Parse(requestId)
+		if err != nil {
+			log.Warnf("Error Parsing the requestID: %v", err)
+		} else {
+			parsedUUID = &tempUUID
+			healthCheckParams = &oapicodegen.HealthcheckParams{
+				XONAPRequestID: (*openapi_types.UUID)(parsedUUID),
+			}
+			w.Header().Set("X-ONAP-RequestID", healthCheckParams.XONAPRequestID.String())
+		}
+	} else {
+		log.Warnf("Invalid or Missing  Request ID")
+		requestId = "000000000000"
+		w.Header().Set("X-ONAP-RequestID", requestId)
+	}
+	w.Header().Set("X-LatestVersion", consts.LatestVersion)
+	w.Header().Set("X-PatchVersion", consts.PatchVersion)
+	w.Header().Set("X-MinorVersion", consts.MinorVersion)
+
+	response := &oapicodegen.HealthCheckReport{
+		Name:    &pdpattributes.PdpName,
+		Url:     &consts.OpaPdpUrl,
+		Healthy: &consts.HealtCheckStatus,
+		Code:    &consts.OkCode,
+		Message: &consts.HealthCheckMessage,
+	}
+	log.Debug("Received Health Check message")
+	w.Header().Set("Content-Type", "application/json")
+	w.WriteHeader(http.StatusOK)
+	json.NewEncoder(w).Encode(response)
+}
diff --git a/pkg/healthcheck/healthcheck_test.go b/pkg/healthcheck/healthcheck_test.go
new file mode 100644
index 0000000..3e1876f
--- /dev/null
+++ b/pkg/healthcheck/healthcheck_test.go
@@ -0,0 +1,85 @@
+package healthcheck
+
+import (
+	"encoding/json"
+	"github.com/stretchr/testify/assert"
+	"net/http"
+	"net/http/httptest"
+	"policy-opa-pdp/pkg/model/oapicodegen"
+	"policy-opa-pdp/pkg/pdpattributes"
+	"testing"
+)
+
+// Success Test Case for HealthCheckHandler
+func TestHealthCheckHandler_Success(t *testing.T) {
+	// Prepare a request to the health check endpoint
+	req := httptest.NewRequest(http.MethodGet, "/healthcheck", nil)
+	w := httptest.NewRecorder()
+
+	// Call the HealthCheckHandler with the test request and response recorder
+	HealthCheckHandler(w, req)
+
+	// Check if the status code is OK (200)
+	assert.Equal(t, http.StatusOK, w.Code)
+
+	// Check if the response is a valid JSON and contains the expected fields
+	var response oapicodegen.HealthCheckReport
+	err := json.NewDecoder(w.Body).Decode(&response)
+	assert.NoError(t, err)
+	assert.Equal(t, pdpattributes.PdpName, *response.Name)
+	assert.Equal(t, "self", *response.Url)
+	assert.True(t, *response.Healthy)
+	assert.Equal(t,int32(200), *response.Code)
+	assert.Equal(t, "alive", *response.Message)
+}
+
+// Failure Test Case for HealthCheckHandler (Simulate failure by forcing an error)
+func TestHealthCheckHandler_Failure(t *testing.T) {
+	// Simulate an error by modifying the handler or the response
+	// For the sake of testing, we'll modify the handler to return a failure message
+	// You could also simulate a failure by forcing an error within the handler code itself
+	HealthCheckFailureHandler := func(w http.ResponseWriter, r *http.Request) {
+		// Modify response to simulate failure
+		response := oapicodegen.HealthCheckReport{
+			Name:    strPtr("Unknown"),
+			Url:     strPtr("self"),
+			Healthy: boolPtr(false),
+			Code:    int32Ptr(500),
+			Message: strPtr("error"),
+		}
+		w.Header().Set("Content-Type", "application/json")
+		w.WriteHeader(http.StatusInternalServerError)
+		json.NewEncoder(w).Encode(response)
+	}
+
+	// Prepare a request to the health check endpoint
+	req := httptest.NewRequest(http.MethodGet, "/healthcheck", nil)
+	w := httptest.NewRecorder()
+
+	// Call the HealthCheckHandler with the test request and response recorder
+	HealthCheckFailureHandler(w, req)
+
+	// Check if the status code is InternalServerError (500)
+	assert.Equal(t, http.StatusInternalServerError, w.Code)
+
+	// Check if the response is a valid JSON and contains the expected failure fields
+	var response oapicodegen.HealthCheckReport
+	err := json.NewDecoder(w.Body).Decode(&response)
+	assert.NoError(t, err)
+	assert.False(t, *response.Healthy)
+	assert.Equal(t, int32(500), *response.Code)
+	assert.Equal(t, "error", *response.Message)
+
+}
+
+func strPtr(s string) *string {
+    return &s
+}
+
+func boolPtr(b bool) *bool {
+    return &b
+}
+
+func int32Ptr(i int32) *int32 {
+    return &i
+}
diff --git a/pkg/kafkacomm/handler/pdp_message_handler.go b/pkg/kafkacomm/handler/pdp_message_handler.go
new file mode 100644
index 0000000..8d7da92
--- /dev/null
+++ b/pkg/kafkacomm/handler/pdp_message_handler.go
@@ -0,0 +1,132 @@
+// -
+//   ========================LICENSE_START=================================
+//   Copyright (C) 2024: Deutsche Telecom
+//
+//   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.
+//   ========================LICENSE_END===================================
+
+// The handler package is responsible for processing messages from Kafka, specifically targeting the OPA
+// (Open Policy Agent) PDP (Policy Decision Point). It validates the message type,
+//
+//	ensures it is relevant to the current PDP, and dispatches the message for appropriate processing.
+package handler
+
+import (
+	"encoding/json"
+	"policy-opa-pdp/consts"
+	"policy-opa-pdp/pkg/kafkacomm"
+	"policy-opa-pdp/pkg/kafkacomm/publisher"
+	"policy-opa-pdp/pkg/log"
+	"policy-opa-pdp/pkg/pdpattributes"
+)
+
+type OpaPdpMessage struct {
+	Name        string `json:"name"`        // Name of the PDP (optional for broadcast messages).
+	MessageType string `json:"MessageName"` // Type of the message (e.g., PDP_UPDATE, PDP_STATE_CHANGE, etc.)
+	PdpGroup    string `json:"pdpGroup"`    // Group to which the PDP belongs.
+	PdpSubgroup string `json:"pdpSubgroup"` // Subgroup within the PDP group.
+}
+
+// Checks if the incoming Kafka message belongs to the current PDP instance.
+func checkIfMessageIsForOpaPdp(message OpaPdpMessage) bool {
+
+	if message.Name != "" {
+		// message included a PDP name, check if matches
+		//log.Infof(" Message Name is not empty")
+		return message.Name == pdpattributes.PdpName
+	}
+
+	// message does not provide a PDP name - must be a broadcast
+	if message.PdpGroup == "" {
+		//log.Infof(" Message PDP Group is empty")
+		return false
+	}
+
+	if pdpattributes.PdpSubgroup == "" {
+		// this PDP has no assignment yet, thus should ignore broadcast messages
+		//log.Infof(" pdpstate PDP subgroup is empty")
+		return false
+	}
+
+	if message.PdpGroup != consts.PdpGroup {
+		//log.Infof(" message pdp group is not equal to cons pdp group")
+		return false
+	}
+
+	if message.PdpSubgroup == "" {
+		//message was broadcast to entire group
+		//log.Infof(" message pdp subgroup is empty")
+		return true
+	}
+
+	return message.PdpSubgroup == pdpattributes.PdpSubgroup
+}
+
+// Handles incoming Kafka messages, validates their relevance to the current PDP,
+// and dispatches them for further processing based on their type.
+func PdpMessageHandler(kc *kafkacomm.KafkaConsumer, topic string, p publisher.PdpStatusSender) error {
+
+	log.Debug("Starting PDP Message Listener.....")
+	var stopConsuming bool
+	for !stopConsuming {
+		message, err := kafkacomm.ReadKafkaMessages(kc)
+		if err != nil {
+			log.Warnf("Failed to Read Kafka Messages: %v\n", err)
+			continue
+		}
+		log.Debugf("[IN|KAFKA|%s]\n%s", topic, string(message))
+
+		if message != nil {
+
+			var opaPdpMessage OpaPdpMessage
+
+			err = json.Unmarshal(message, &opaPdpMessage)
+			if err != nil {
+				log.Warnf("Failed to UnMarshal Messages: %v\n", err)
+				continue
+			}
+
+			if !checkIfMessageIsForOpaPdp(opaPdpMessage) {
+
+				log.Warnf("Not a valid Opa Pdp Message")
+				continue
+			}
+
+			switch opaPdpMessage.MessageType {
+
+			case "PDP_UPDATE":
+				err = PdpUpdateMessageHandler(message, p)
+				if err != nil {
+					log.Warnf("Error processing Update Message: %v", err)
+				}
+
+			case "PDP_STATE_CHANGE":
+				err = PdpStateChangeMessageHandler(message, p)
+				if err != nil {
+					log.Warnf("Error processing Update Message: %v", err)
+				}
+
+			case "PDP_STATUS":
+				log.Debugf("discarding event of type PDP_STATUS")
+				continue
+			default:
+				log.Errorf("This is not a valid Message Type: %s", opaPdpMessage.MessageType)
+				continue
+
+			}
+
+		}
+	}
+	return nil
+
+}
diff --git a/pkg/kafkacomm/handler/pdp_message_handler_test.go b/pkg/kafkacomm/handler/pdp_message_handler_test.go
new file mode 100644
index 0000000..3764c9e
--- /dev/null
+++ b/pkg/kafkacomm/handler/pdp_message_handler_test.go
@@ -0,0 +1,142 @@
+// -
+//   ========================LICENSE_START=================================
+//   Copyright (C) 2024: Deutsche Telecom
+//
+//   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.
+//   ========================LICENSE_END===================================
+//
+
+package handler
+
+import (
+	"github.com/stretchr/testify/assert"
+	"policy-opa-pdp/pkg/pdpattributes"
+	"testing"
+)
+
+/*
+checkIfMessageIsForOpaPdp_Check
+Description: Validating Message Attributes
+Input: PDP message
+Expected Output: Returning true stating all the values are validated successfully
+*/
+func TestCheckIfMessageIsForOpaPdp_Check(t *testing.T) {
+
+	var opapdpMessage OpaPdpMessage
+
+	opapdpMessage.Name = "opa-3a318049-813f-4172-b4d3-7d4f466e5b80"
+	opapdpMessage.MessageType = "PDP_STATUS"
+	opapdpMessage.PdpGroup = "defaultGroup"
+	opapdpMessage.PdpSubgroup = "opa"
+
+	assert.False(t, checkIfMessageIsForOpaPdp(opapdpMessage), "Its a valid Opa Pdp Message")
+
+}
+
+/*
+checkIfMessageIsForOpaPdp_Check_Message_Name
+Description: Validating Message Attributes
+Input: PDP message with name as empty
+Expected Output: Returning Error since it is not valid message
+*/
+func TestCheckIfMessageIsForOpaPdp_Check_Message_Name(t *testing.T) {
+
+	var opapdpMessage OpaPdpMessage
+
+	opapdpMessage.Name = ""
+	opapdpMessage.MessageType = "PDP_STATUS"
+	opapdpMessage.PdpGroup = "defaultGroup"
+	opapdpMessage.PdpSubgroup = "opa"
+
+	assert.False(t, checkIfMessageIsForOpaPdp(opapdpMessage), "Not a valid Opa Pdp Message")
+
+}
+
+/*
+checkIfMessageIsForOpaPdp_Check_PdpGroup
+Description: Validating Message Attributes
+Input: PDP message with invalid PdpGroup
+Expected Output: Returning Error since it is not valid message
+*/
+func TestCheckIfMessageIsForOpaPdp_Check_PdpGroup(t *testing.T) {
+
+	var opapdpMessage OpaPdpMessage
+
+	opapdpMessage.Name = ""
+	opapdpMessage.MessageType = "PDP_STATUS"
+	opapdpMessage.PdpGroup = "defaultGroup"
+	opapdpMessage.PdpSubgroup = "opa"
+
+	pdpattributes.PdpSubgroup = "opa"
+	assert.True(t, checkIfMessageIsForOpaPdp(opapdpMessage), "Its a valid Opa Pdp Message")
+
+}
+
+/*
+checkIfMessageIsForOpaPdp_Check_EmptyPdpGroup
+Description: Validating Message Attributes
+Input: PDP Group Empty
+Expected Output: Returning Error since it is not valid message
+*/
+func TestCheckIfMessageIsForOpaPdp_Check_EmptyPdpGroup(t *testing.T) {
+
+	var opapdpMessage OpaPdpMessage
+
+	opapdpMessage.Name = ""
+	opapdpMessage.MessageType = "PDP_STATUS"
+	opapdpMessage.PdpGroup = ""
+	opapdpMessage.PdpSubgroup = "opa"
+
+	assert.False(t, checkIfMessageIsForOpaPdp(opapdpMessage), "Not a valid Opa Pdp Message")
+
+}
+
+/*
+checkIfMessageIsForOpaPdp_Check_PdpSubgroup
+Description: Validating Message Attributes
+Input: PDP message with invalid PdpSubgroup
+Expected Output: Returning Error since it is not valid message
+*/
+func TestCheckIfMessageIsForOpaPdp_Check_PdpSubgroup(t *testing.T) {
+
+	var opapdpMessage OpaPdpMessage
+
+	opapdpMessage.Name = ""
+	opapdpMessage.MessageType = "PDP_STATUS"
+	opapdpMessage.PdpGroup = "defaultGroup"
+	opapdpMessage.PdpSubgroup = "opa"
+
+	pdpattributes.PdpSubgroup = "opa"
+	assert.True(t, checkIfMessageIsForOpaPdp(opapdpMessage), "It's a valid Opa Pdp Message")
+
+}
+
+/*
+checkIfMessageIsForOpaPdp_Check_IncorrectPdpSubgroup
+Description: Validating Message Attributes
+Input: PDP message with empty  PdpSubgroup
+Expected Output: Returning Error since it is not valid message
+*/
+func TestCheckIfMessageIsForOpaPdp_Check_IncorrectPdpSubgroup(t *testing.T) {
+
+	var opapdpMessage OpaPdpMessage
+
+	opapdpMessage.Name = ""
+	opapdpMessage.MessageType = "PDP_STATUS"
+	opapdpMessage.PdpGroup = "defaultGroup"
+	opapdpMessage.PdpSubgroup = "o"
+
+	pdpattributes.PdpSubgroup = "opa"
+	assert.False(t, checkIfMessageIsForOpaPdp(opapdpMessage), "Not a valid Opa Pdp Message")
+
+}
diff --git a/pkg/kafkacomm/handler/pdp_state_change_handler.go b/pkg/kafkacomm/handler/pdp_state_change_handler.go
new file mode 100644
index 0000000..32d998f
--- /dev/null
+++ b/pkg/kafkacomm/handler/pdp_state_change_handler.go
@@ -0,0 +1,57 @@
+// -
+//   ========================LICENSE_START=================================
+//   Copyright (C) 2024: Deutsche Telecom
+//
+//   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.
+//   ========================LICENSE_END===================================
+
+// will process the state change message from pap and send the pdp status response.
+package handler
+
+import (
+	"encoding/json"
+	"policy-opa-pdp/pkg/kafkacomm/publisher"
+	"policy-opa-pdp/pkg/log"
+	"policy-opa-pdp/pkg/model"
+	"policy-opa-pdp/pkg/pdpstate"
+)
+
+// Processes incoming messages indicating a PDP state change.
+// This includes updating the PDP state and sending a status response when the state transitions.
+func PdpStateChangeMessageHandler(message []byte, p publisher.PdpStatusSender) error {
+
+	var pdpStateChange model.PdpStateChange
+
+	err := json.Unmarshal(message, &pdpStateChange)
+	if err != nil {
+		log.Debugf("Failed to UnMarshal Messages: %v\n", err)
+		return err
+	}
+
+	log.Debugf("PDP STATE CHANGE message received: %s", string(message))
+
+	if pdpStateChange.State != "" {
+		pdpstate.SetState(pdpStateChange.State)
+
+	}
+
+	log.Debugf("State change from PASSIVE To : %s", pdpstate.GetState())
+	err = publisher.SendStateChangeResponse(p, &pdpStateChange)
+	if err != nil {
+		log.Debugf("Failed to Send State Change Response Message: %v\n", err)
+		return err
+	}
+	log.Infof("PDP_STATUS With State Change Message Sent Successfully")
+
+	return nil
+}
diff --git a/pkg/kafkacomm/handler/pdp_state_change_handler_test.go b/pkg/kafkacomm/handler/pdp_state_change_handler_test.go
new file mode 100644
index 0000000..f7e8f84
--- /dev/null
+++ b/pkg/kafkacomm/handler/pdp_state_change_handler_test.go
@@ -0,0 +1,93 @@
+// -
+//   ========================LICENSE_START=================================
+//   Copyright (C) 2024: Deutsche Telecom
+//
+//   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.
+//   ========================LICENSE_END===================================
+//
+
+package handler
+
+import (
+	"policy-opa-pdp/pkg/kafkacomm/publisher"
+	"policy-opa-pdp/pkg/model"
+	"policy-opa-pdp/pkg/pdpstate"
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/mock"
+)
+
+// MockPdpStatusSender is a mock implementation of the PdpStatusSender interface
+type MockPdpStatusSender struct {
+	mock.Mock
+}
+
+func (m *MockPdpStatusSender) SendStateChangeResponse(p *publisher.PdpStatusSender, pdpStateChange *model.PdpStateChange) error {
+	args := m.Called(p, pdpStateChange)
+	return args.Error(0)
+}
+
+func (m *MockPdpStatusSender) SendPdpStatus(status model.PdpStatus) error {
+	args := m.Called(status)
+	return args.Error(0)
+}
+
+func TestPdpStateChangeMessageHandler(t *testing.T) {
+
+	// Create a mock PdpStatusSender
+	mockSender := new(MockPdpStatusSender)
+
+	// Define test cases
+	tests := []struct {
+		name          string
+		message       []byte
+		expectedState string
+		mockError     error
+		expectError   bool
+	}{
+		{
+			name:          "Valid state change",
+			message:       []byte(`{"state":"ACTIVE"}`),
+			expectedState: "ACTIVE",
+			mockError:     nil,
+			expectError:   false,
+		},
+		{
+			name:        "Invalid JSON",
+			message:     []byte(`{"state":}`),
+			mockError:   nil,
+			expectError: true,
+		},
+	}
+
+	for _, 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)
+
+			// Call the handler
+			err := PdpStateChangeMessageHandler(tt.message, mockSender)
+
+			// Check the results
+			if tt.expectError {
+				assert.Error(t, err)
+			} else {
+				assert.NoError(t, err)
+				assert.Equal(t, tt.expectedState, pdpstate.GetState().String())
+			}
+
+		})
+	}
+}
diff --git a/pkg/kafkacomm/handler/pdp_update_message_handler.go b/pkg/kafkacomm/handler/pdp_update_message_handler.go
new file mode 100644
index 0000000..632bcc8
--- /dev/null
+++ b/pkg/kafkacomm/handler/pdp_update_message_handler.go
@@ -0,0 +1,64 @@
+// -
+//   ========================LICENSE_START=================================
+//   Copyright (C) 2024: Deutsche Telecom
+//
+//   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.
+//   ========================LICENSE_END===================================
+
+// will process the update message from pap and send the pdp status response.
+package handler
+
+import (
+	"encoding/json"
+	"github.com/go-playground/validator/v10"
+	"policy-opa-pdp/pkg/kafkacomm/publisher"
+	"policy-opa-pdp/pkg/log"
+	"policy-opa-pdp/pkg/model"
+	"policy-opa-pdp/pkg/pdpattributes"
+)
+
+// Handles messages of type PDP_UPDATE sent from the Policy Administration Point (PAP).
+// It validates the incoming data, updates PDP attributes, and sends a response back to the sender.
+func PdpUpdateMessageHandler(message []byte, p publisher.PdpStatusSender) error {
+
+	var pdpUpdate model.PdpUpdate
+	err := json.Unmarshal(message, &pdpUpdate)
+	if err != nil {
+		log.Debugf("Failed to UnMarshal Messages: %v\n", err)
+		return err
+	}
+	//Initialize Validator and validate Struct after unmarshalling
+	validate := validator.New()
+
+	err = validate.Struct(pdpUpdate)
+	if err != nil {
+		for _, err := range err.(validator.ValidationErrors) {
+			log.Infof("Field %s failed on the %s tag\n", err.Field(), err.Tag())
+		}
+		return err
+	}
+
+	log.Debugf("PDP_UPDATE Message received: %s", string(message))
+
+	pdpattributes.SetPdpSubgroup(pdpUpdate.PdpSubgroup)
+	pdpattributes.SetPdpHeartbeatInterval(pdpUpdate.PdpHeartbeatIntervalMs)
+
+	err = publisher.SendPdpUpdateResponse(p, &pdpUpdate)
+	if err != nil {
+		log.Debugf("Failed to Send Update Response Message: %v\n", err)
+		return err
+	}
+	log.Infof("PDP_STATUS Message Sent Successfully")
+	go publisher.StartHeartbeatIntervalTimer(pdpattributes.PdpHeartbeatInterval, p)
+	return nil
+}
diff --git a/pkg/kafkacomm/handler/pdp_update_message_handler_test.go b/pkg/kafkacomm/handler/pdp_update_message_handler_test.go
new file mode 100644
index 0000000..061f1ce
--- /dev/null
+++ b/pkg/kafkacomm/handler/pdp_update_message_handler_test.go
@@ -0,0 +1,196 @@
+// -
+//   ========================LICENSE_START=================================
+//   Copyright (C) 2024: Deutsche Telecom
+//
+//   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.
+//   ========================LICENSE_END===================================
+//
+
+package handler
+
+import (
+	"errors"
+	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/mock"
+	"policy-opa-pdp/pkg/kafkacomm/publisher/mocks"
+	"testing"
+)
+
+/*
+PdpUpdateMessageHandler_success
+Description: Test by sending a valid input message for pdp update
+Input: valid input
+Expected Output: PDP Update Message should be sent sucessfully.
+*/
+func TestPdpUpdateMessageHandler_Success(t *testing.T) {
+
+	messageString := `{
+		"source":"pap-c17b4dbc-3278-483a-ace9-98f3157245c0",
+		"pdpHeartbeatIntervalMs":120000,
+		"policiesToBeDeployed":[],
+		"policiesToBeUndeployed":[],
+		"messageName":"PDP_UPDATE",
+		"requestId":"41c117db-49a0-40b0-8586-5580d042d0a1",
+		"timestampMs":1730722305297,
+		"name":"opa-21cabb3e-f652-4ca6-b498-a77e62fcd059",
+		"pdpGroup":"defaultGroup",
+		"pdpSubgroup":"opa"
+	         }`
+
+	mockSender := new(mocks.PdpStatusSender)
+	mockSender.On("SendPdpStatus", mock.Anything).Return(nil)
+
+	err := PdpUpdateMessageHandler([]byte(messageString), mockSender)
+	assert.NoError(t, err)
+
+}
+
+/*
+PdpUpdateMessageHandler_Message_Unmarshal_Failure1
+Description: Test by sending a invalid input message which should result in a Json unmarhsal error
+Input: invalid input Message by renaming params or removing certain params
+Expected Output: Message Handler should exit gracefully stating the error.
+*/
+func TestPdpUpdateMessageHandler_Message_Unmarshal_Failure1(t *testing.T) {
+
+	// sending only source parameter in the message string
+	messageString := `{
+		"source":"pap-c17b4dbc-3278-483a-ace9-98f3157245c0"}`
+
+	mockSender := new(mocks.PdpStatusSender)
+	mockSender.On("SendPdpStatus", mock.Anything).Return(errors.New("Jsonunmarshal Error"))
+
+	err := PdpUpdateMessageHandler([]byte(messageString), mockSender)
+	assert.Error(t, err)
+
+}
+
+/*
+PdpUpdateMessageHandler_Message_Unmarshal_Failure2
+Description: Test by sending a invalid input message which should result in a Json unmarhsal error
+Input: invalid input Message by renaming params or removing certain params
+Expected Output: Message Handler should exit gracefully stating the error.
+*/
+func TestPdpUpdateMessageHandler_Message_Unmarshal_Failure2(t *testing.T) {
+
+	// invlaid params by mispelling a param  "source"
+
+	messageString := `{
+		"soce":"pap-c17b4dbc-3278-483a-ace9-98f3157245c0",
+		"pdpHeartbeatIntervalMs":120000}`
+	mockSender := new(mocks.PdpStatusSender)
+	mockSender.On("SendPdpStatus", mock.Anything).Return(errors.New("Jsonunmarshal Error"))
+
+	err := PdpUpdateMessageHandler([]byte(messageString), mockSender)
+	assert.Error(t, err)
+
+}
+
+/*
+PdpUpdateMessageHandler_Message_Unmarshal_Failure3
+Description: Test by sending a invalid input message which should result in a Json unmarhsal error
+Input: {}
+Expected Output: Message Handler should exit gracefully stating the error.
+*/
+func TestPdpUpdateMessageHandler_Message_Unmarshal_Failure3(t *testing.T) {
+
+	// invlaid params by mispelling a param  "source"
+
+	messageString := `{
+                "soce:"pap-c17b4dbc-3278-483a-ace9-98f3157245c0",
+                "pdpHeartbeatIntervalMs":120000}`
+	mockSender := new(mocks.PdpStatusSender)
+	mockSender.On("SendPdpStatus", mock.Anything).Return(errors.New("Jsonunmarshal Error"))
+
+	err := PdpUpdateMessageHandler([]byte(messageString), mockSender)
+	assert.Error(t, err)
+
+}
+
+/*
+PdpUpdateMessageHandler_Message_Unmarshal_Failure4
+Description: Test by sending a invalid input message which should result in a Json unmarhsal error
+Input: empty
+Expected Output: Message Handler should exit gracefully stating the error.
+*/
+func TestPdpUpdateMessageHandler_Message_Unmarshal_Failure4(t *testing.T) {
+
+	// invlaid params by mispelling a param  "source"
+
+	messageString := `""`
+	mockSender := new(mocks.PdpStatusSender)
+	mockSender.On("SendPdpStatus", mock.Anything).Return(errors.New("Jsonunmarshal Error"))
+
+	err := PdpUpdateMessageHandler([]byte(messageString), mockSender)
+	assert.Error(t, err)
+
+}
+
+/*
+PdpUpdateMessageHandler_Fails_Sending_PdpUpdateResponse
+Description: Test by sending a invalid attribute for pdpstate which should result in a failure in sending pdp update response
+Input: invalid input config set for pdpstate
+Expected Output: Message Handler should exit gracefully stating the error.
+*/
+func TestPdpUpdateMessageHandler_Fails_Sending_UpdateResponse(t *testing.T) {
+
+	// invalid value set to pdpSubgroup -->empty ""
+	messageString := `{
+		"source":"pap-c17b4dbc-3278-483a-ace9-98f3157245c0",
+		"pdpHeartbeatIntervalMs":120000,
+		"policiesToBeDeployed":[],
+		"policiesToBeUndeployed":[],
+		"messageName":"PDP_UPDATE",
+		"requestId":"41c117db-49a0-40b0-8586-5580d042d0a1",
+		"timestampMs":1730722305297,
+		"name":"opa-21cabb3e-f652-4ca6-b498-a77e62fcd059",
+		"pdpGroup":"defaultGroup"
+	         }`
+
+	mockSender := new(mocks.PdpStatusSender)
+	mockSender.On("SendPdpStatus", mock.Anything).Return(errors.New("Error in Sending PDP Update Response"))
+
+	err := PdpUpdateMessageHandler([]byte(messageString), mockSender)
+	assert.Error(t, err)
+
+}
+
+/*
+PdpUpdateMessageHandler_Invalid_Starttimeinterval
+Description: Test by sending a invalid time value attribute for pdpstate which should result in a failure in starting heartbeat interval
+Input: invalid input message for pdpstate heartbeat interval
+Expected Output: Message Handler should exit gracefully stating the error.
+*/
+func TestPdpUpdateMessageHandler_Invalid_Starttimeinterval(t *testing.T) {
+
+	//invalid interval set to negative -1000
+	messageString := `{
+		"source":"pap-c17b4dbc-3278-483a-ace9-98f3157245c0",
+		"pdpHeartbeatIntervalMs":-1000,
+		"policiesToBeDeployed":[],
+		"policiesToBeUndeployed":[],
+		"messageName":"PDP_UPDATE",
+		"requestId":"41c117db-49a0-40b0-8586-5580d042d0a1",
+		"timestampMs":1730722305297,
+		"name":"opa-21cabb3e-f652-4ca6-b498-a77e62fcd059",
+		"pdpGroup":"defaultGroup",
+		"pdpSubgroup":"opa"
+	         }`
+
+	mockSender := new(mocks.PdpStatusSender)
+	mockSender.On("SendPdpStatus", mock.Anything).Return(errors.New("Invalid Interval Time for Heartbeat"))
+
+	err := PdpUpdateMessageHandler([]byte(messageString), mockSender)
+	assert.Error(t, err)
+
+}
diff --git a/pkg/kafkacomm/mocks/kafkaconsumerinterface.go b/pkg/kafkacomm/mocks/kafkaconsumerinterface.go
new file mode 100644
index 0000000..ca5140e
--- /dev/null
+++ b/pkg/kafkacomm/mocks/kafkaconsumerinterface.go
@@ -0,0 +1,96 @@
+// Code generated by mockery v2.46.3. DO NOT EDIT.
+
+package mocks
+
+import (
+	kafka "github.com/confluentinc/confluent-kafka-go/kafka"
+
+	mock "github.com/stretchr/testify/mock"
+
+	time "time"
+)
+
+// KafkaConsumerInterface is an autogenerated mock type for the KafkaConsumerInterface type
+type KafkaConsumerInterface struct {
+	mock.Mock
+}
+
+// Close provides a mock function with given fields:
+func (_m *KafkaConsumerInterface) Close() error {
+	ret := _m.Called()
+
+	if len(ret) == 0 {
+		panic("no return value specified for Close")
+	}
+
+	var r0 error
+	if rf, ok := ret.Get(0).(func() error); ok {
+		r0 = rf()
+	} else {
+		r0 = ret.Error(0)
+	}
+
+	return r0
+}
+
+// ReadMessage provides a mock function with given fields: timeout
+func (_m *KafkaConsumerInterface) ReadMessage(timeout time.Duration) (*kafka.Message, error) {
+	ret := _m.Called(timeout)
+
+	if len(ret) == 0 {
+		panic("no return value specified for ReadMessage")
+	}
+
+	var r0 *kafka.Message
+	var r1 error
+	if rf, ok := ret.Get(0).(func(time.Duration) (*kafka.Message, error)); ok {
+		return rf(timeout)
+	}
+	if rf, ok := ret.Get(0).(func(time.Duration) *kafka.Message); ok {
+		r0 = rf(timeout)
+	} else {
+		if ret.Get(0) != nil {
+			r0 = ret.Get(0).(*kafka.Message)
+		}
+	}
+
+	if rf, ok := ret.Get(1).(func(time.Duration) error); ok {
+		r1 = rf(timeout)
+	} else {
+		r1 = ret.Error(1)
+	}
+
+	return r0, r1
+}
+
+// Unsubscribe provides a mock function with given fields:
+func (_m *KafkaConsumerInterface) Unsubscribe() error {
+	ret := _m.Called()
+
+	if len(ret) == 0 {
+		panic("no return value specified for Unsubscribe")
+	}
+
+	var r0 error
+	if rf, ok := ret.Get(0).(func() error); ok {
+		r0 = rf()
+	} else {
+		r0 = ret.Error(0)
+	}
+
+	return r0
+}
+
+// NewKafkaConsumerInterface creates a new instance of KafkaConsumerInterface. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
+// The first argument is typically a *testing.T value.
+func NewKafkaConsumerInterface(t interface {
+	mock.TestingT
+	Cleanup(func())
+}) *KafkaConsumerInterface {
+	mock := &KafkaConsumerInterface{}
+	mock.Mock.Test(t)
+
+	t.Cleanup(func() { mock.AssertExpectations(t) })
+
+	return mock
+}
diff --git a/pkg/kafkacomm/mocks/kafkaproducerinterface.go b/pkg/kafkacomm/mocks/kafkaproducerinterface.go
new file mode 100644
index 0000000..97b6f53
--- /dev/null
+++ b/pkg/kafkacomm/mocks/kafkaproducerinterface.go
@@ -0,0 +1,51 @@
+// Code generated by mockery v2.46.3. DO NOT EDIT.
+
+package mocks
+
+import (
+	kafka "github.com/confluentinc/confluent-kafka-go/kafka"
+
+	mock "github.com/stretchr/testify/mock"
+)
+
+// KafkaProducerInterface is an autogenerated mock type for the KafkaProducerInterface type
+type KafkaProducerInterface struct {
+	mock.Mock
+}
+
+// Close provides a mock function with given fields:
+func (_m *KafkaProducerInterface) Close() {
+	_m.Called()
+}
+
+// Produce provides a mock function with given fields: _a0, _a1
+func (_m *KafkaProducerInterface) Produce(_a0 *kafka.Message, _a1 chan kafka.Event) error {
+	ret := _m.Called(_a0, _a1)
+
+	if len(ret) == 0 {
+		panic("no return value specified for Produce")
+	}
+
+	var r0 error
+	if rf, ok := ret.Get(0).(func(*kafka.Message, chan kafka.Event) error); ok {
+		r0 = rf(_a0, _a1)
+	} else {
+		r0 = ret.Error(0)
+	}
+
+	return r0
+}
+
+// NewKafkaProducerInterface creates a new instance of KafkaProducerInterface. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
+// The first argument is typically a *testing.T value.
+func NewKafkaProducerInterface(t interface {
+	mock.TestingT
+	Cleanup(func())
+}) *KafkaProducerInterface {
+	mock := &KafkaProducerInterface{}
+	mock.Mock.Test(t)
+
+	t.Cleanup(func() { mock.AssertExpectations(t) })
+
+	return mock
+}
diff --git a/pkg/kafkacomm/pdp_topic_consumer.go b/pkg/kafkacomm/pdp_topic_consumer.go
new file mode 100644
index 0000000..4858bdf
--- /dev/null
+++ b/pkg/kafkacomm/pdp_topic_consumer.go
@@ -0,0 +1,103 @@
+// -
+//   ========================LICENSE_START=================================
+//   Copyright (C) 2024: Deutsche Telecom
+//
+//   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.
+//   ========================LICENSE_END===================================
+
+// kafkacomm package provides a structured way to create and manage Kafka consumers,
+// handle subscriptions, and read messages from Kafka topics
+package kafkacomm
+
+import (
+	"github.com/confluentinc/confluent-kafka-go/kafka"
+	"policy-opa-pdp/cfg"
+	"policy-opa-pdp/pkg/log"
+	"time"
+)
+
+// KafkaConsumerInterface defines the interface for a Kafka consumer.
+type KafkaConsumerInterface interface {
+	Close() error
+	Unsubscribe() error
+	ReadMessage(timeout time.Duration) (*kafka.Message, error)
+}
+
+// KafkaConsumer is a wrapper around the Kafka consumer.
+type KafkaConsumer struct {
+	Consumer KafkaConsumerInterface
+}
+
+// Close closes the KafkaConsumer
+func (kc *KafkaConsumer) Close() {
+	kc.Consumer.Close()
+}
+
+// Unsubscribe unsubscribes the KafkaConsumer
+func (kc *KafkaConsumer) Unsubscribe() error {
+	if err := kc.Consumer.Unsubscribe(); err != nil {
+		log.Warnf("Error Unsubscribing :%v", err)
+		return err
+	}
+	log.Debug("Unsubscribe From Topic")
+	return nil
+}
+
+// creates a new Kafka consumer and returns it
+func NewKafkaConsumer() (*KafkaConsumer, error) {
+	brokers := cfg.BootstrapServer
+	groupid := cfg.GroupId
+	topic := cfg.Topic
+	useSASL := cfg.UseSASLForKAFKA
+	username := cfg.KAFKA_USERNAME
+	password := cfg.KAFKA_PASSWORD
+
+	// Add Kafka Connection Properties ....
+	configMap := &kafka.ConfigMap{
+		"bootstrap.servers": brokers,
+		"group.id":          groupid,
+		"auto.offset.reset": "earliest",
+	}
+	//for STRIMZI-KAFKA in case sasl is enabled
+	if useSASL == "true" {
+		configMap.SetKey("sasl.mechanism", "SCRAM-SHA-512")
+		configMap.SetKey("sasl.username", username)
+		configMap.SetKey("sasl.password", password)
+		configMap.SetKey("security.protocol", "SASL_PLAINTEXT")
+	}
+
+	// create new Kafka Consumer
+	consumer, err := kafka.NewConsumer(configMap)
+	if err != nil {
+		log.Warnf("Error creating consumer: %v\n", err)
+		return nil, err
+	}
+	//subscribe to topic
+	err = consumer.SubscribeTopics([]string{topic}, nil)
+	if err != nil {
+		log.Warnf("Error subcribing to topic: %v\n", err)
+		return nil, err
+	}
+	log.Debugf("Topic Subscribed... : %v", topic)
+	return &KafkaConsumer{Consumer: consumer}, nil
+}
+
+// gets the Kafka messages on the subscribed topic
+func ReadKafkaMessages(kc *KafkaConsumer) ([]byte, error) {
+	msg, err := kc.Consumer.ReadMessage(-1)
+	if err != nil {
+		log.Warnf("Error reading Kafka message: %v", err)
+		return nil, err
+	}
+	return msg.Value, nil
+}
diff --git a/pkg/kafkacomm/pdp_topic_consumer_test.go b/pkg/kafkacomm/pdp_topic_consumer_test.go
new file mode 100644
index 0000000..2fdfa90
--- /dev/null
+++ b/pkg/kafkacomm/pdp_topic_consumer_test.go
@@ -0,0 +1,129 @@
+// -
+//   ========================LICENSE_START=================================
+//   Copyright (C) 2024: Deutsche Telecom
+//
+//   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.
+//   ========================LICENSE_END===================================
+//
+
+package kafkacomm
+
+import (
+	"errors"
+	"policy-opa-pdp/pkg/kafkacomm/mocks"
+	"testing"
+
+	"github.com/confluentinc/confluent-kafka-go/kafka"
+	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/mock"
+)
+
+func TestNewKafkaConsumer(t *testing.T) {
+	// Assuming configuration is correctly loaded from cfg package
+	// You can mock or override cfg values here if needed
+
+	consumer, err := NewKafkaConsumer()
+	assert.NoError(t, err, "Expected no error when creating Kafka consumer")
+	assert.NotNil(t, consumer, "Expected a non-nil KafkaConsumer")
+
+	// Clean up
+	if consumer != nil {
+		consumer.Close()
+	}
+}
+
+func TestReadKafkaMessages_Success(t *testing.T) {
+	// Create a new mock for ConsumerInterface
+	mockConsumer := new(mocks.KafkaConsumerInterface)
+
+	// Create a KafkaConsumer with the mock
+	kc := &KafkaConsumer{Consumer: mockConsumer}
+
+	// Define the expected message
+	expectedMsg := &kafka.Message{Value: []byte("test message")}
+
+	// Set up the mock to return the expected message
+	mockConsumer.On("ReadMessage", mock.Anything).Return(expectedMsg, nil)
+
+	// Test ReadKafkaMessages
+	msg, err := ReadKafkaMessages(kc)
+	assert.NoError(t, err, "Expected no error when reading message")
+	assert.Equal(t, expectedMsg.Value, msg, "Expected message content to match")
+
+	// Assert expectations
+	mockConsumer.AssertExpectations(t)
+}
+
+func TestReadKafkaMessages_Error(t *testing.T) {
+	mockConsumer := new(mocks.KafkaConsumerInterface)
+
+	kc := &KafkaConsumer{Consumer: mockConsumer}
+
+	// Set up the mock to return an error
+	expectedErr := errors.New("read error")
+	mockConsumer.On("ReadMessage", mock.Anything).Return(nil, expectedErr)
+
+	msg, err := ReadKafkaMessages(kc)
+	assert.Error(t, err, "Expected an error when reading message")
+	assert.Nil(t, msg, "Expected message to be nil on error")
+
+	mockConsumer.AssertExpectations(t)
+}
+
+func TestKafkaConsumer_Close(t *testing.T) {
+	mockConsumer := new(mocks.KafkaConsumerInterface)
+
+	kc := &KafkaConsumer{Consumer: mockConsumer}
+
+	// Set up the mock for Close
+	mockConsumer.On("Close").Return(nil)
+
+	// Test Close method
+	kc.Close()
+
+	// Verify that Close was called
+	mockConsumer.AssertExpectations(t)
+}
+
+func TestKafkaConsumer_Unsubscribe(t *testing.T) {
+	mockConsumer := new(mocks.KafkaConsumerInterface)
+
+	kc := &KafkaConsumer{Consumer: mockConsumer}
+
+	// Set up the mock for Unsubscribe
+	mockConsumer.On("Unsubscribe").Return(nil)
+
+	// Test Unsubscribe method
+	err := kc.Unsubscribe()
+	assert.NoError(t, err)
+
+	// Verify that Unsubscribe was called
+	mockConsumer.AssertExpectations(t)
+}
+
+func TestKafkaConsumer_Unsubscribe_Error(t *testing.T) {
+	mockConsumer := new(mocks.KafkaConsumerInterface)
+	mockError := errors.New("Unsubscribe error")
+	kc := &KafkaConsumer{Consumer: mockConsumer}
+
+	// Set up the mock for Unsubscribe
+	mockConsumer.On("Unsubscribe").Return(mockError)
+
+	// Test Unsubscribe method
+	err := kc.Unsubscribe()
+	assert.Error(t, err)
+	assert.Equal(t, mockError, err)
+
+	// Verify that Unsubscribe was called
+	mockConsumer.AssertExpectations(t)
+}
diff --git a/pkg/kafkacomm/pdp_topic_producer.go b/pkg/kafkacomm/pdp_topic_producer.go
new file mode 100644
index 0000000..1b11b35
--- /dev/null
+++ b/pkg/kafkacomm/pdp_topic_producer.go
@@ -0,0 +1,107 @@
+// -
+//   ========================LICENSE_START=================================
+//   Copyright (C) 2024: Deutsche Telecom
+//
+//   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.
+//   ========================LICENSE_END===================================
+
+// Package kafkacomm provides utilities for producing messages to a Kafka topic
+// using a configurable Kafka producer. It supports SASL authentication and
+// dynamic topic configuration.
+package kafkacomm
+
+import (
+	"github.com/confluentinc/confluent-kafka-go/kafka"
+	"policy-opa-pdp/cfg"
+	"sync"
+	"log"
+)
+
+type KafkaProducerInterface interface {
+	Produce(*kafka.Message, chan kafka.Event) error
+	Close()
+}
+
+// KafkaProducer wraps a Kafka producer instance and a topic to provide
+// a simple interface for producing messages.
+type KafkaProducer struct {
+	producer KafkaProducerInterface
+	topic    string
+}
+
+var (
+	instance *KafkaProducer
+	once     sync.Once
+)
+
+// GetKafkaProducer initializes and returns a KafkaProducer instance which is a singleton.
+// It configures the Kafka producer with the given bootstrap servers and topic.
+// If SASL authentication is enabled via the configuration, the necessary credentials
+// are set in the producer configuration.
+func GetKafkaProducer(bootstrapServers, topic string) (*KafkaProducer, error) {
+	var err error
+	once.Do(func() {
+		brokers := cfg.BootstrapServer
+		useSASL := cfg.UseSASLForKAFKA
+		username := cfg.KAFKA_USERNAME
+		password := cfg.KAFKA_PASSWORD
+
+		// Add Kafka Connection Properties ....
+		configMap := &kafka.ConfigMap{
+			"bootstrap.servers": brokers,
+		}
+
+		if useSASL == "true" {
+			configMap.SetKey("sasl.mechanism", "SCRAM-SHA-512")
+			configMap.SetKey("sasl.username", username)
+			configMap.SetKey("sasl.password", password)
+			configMap.SetKey("security.protocol", "SASL_PLAINTEXT")
+		}
+
+		p, err := kafka.NewProducer(configMap)
+		if err != nil {
+			return
+		}
+		instance = &KafkaProducer{
+			producer: p,
+			topic:    topic,
+		}
+
+	})
+	return instance, err
+}
+
+// Produce sends a message to the configured Kafka topic.
+// It takes the message payload as a byte slice and returns any errors
+func (kp *KafkaProducer) Produce(message []byte) error {
+	kafkaMessage := &kafka.Message{
+		TopicPartition: kafka.TopicPartition{Topic: &kp.topic, Partition: kafka.PartitionAny},
+		Value:          []byte(message),
+	}
+	err := kp.producer.Produce(kafkaMessage, nil)
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
+// Close shuts down the Kafka producer, releasing all resources.
+func (kp *KafkaProducer) Close() {
+
+	if kp == nil || kp.producer == nil {
+		log.Println("KafkaProducer or producer is nil, skipping Close.")
+		return
+	}
+	kp.producer.Close()
+	log.Println("KafkaProducer closed successfully.")
+}
diff --git a/pkg/kafkacomm/pdp_topic_producer_test.go b/pkg/kafkacomm/pdp_topic_producer_test.go
new file mode 100644
index 0000000..55f3bc8
--- /dev/null
+++ b/pkg/kafkacomm/pdp_topic_producer_test.go
@@ -0,0 +1,117 @@
+// -
+//   ========================LICENSE_START=================================
+//   Copyright (C) 2024: Deutsche Telecom
+//
+//   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.
+//   ========================LICENSE_END===================================
+//
+
+package kafkacomm
+
+import (
+	"errors"
+	"testing"
+	"time"
+	//	"github.com/confluentinc/confluent-kafka-go/kafka"
+	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/mock"
+
+	"policy-opa-pdp/pkg/kafkacomm/mocks" // Adjust to your actual mock path
+)
+
+func TestKafkaProducer_Produce_Success(t *testing.T) {
+	done := make(chan struct{})
+
+	go func() {
+		defer close(done)
+		// Arrange
+		mockProducer := new(mocks.KafkaProducerInterface)
+		topic := "test-topic"
+		kp := &KafkaProducer{
+			producer: mockProducer,
+			topic:    topic,
+		}
+
+		message := []byte("test message")
+
+		// Mock Produce method to simulate successful delivery
+		mockProducer.On("Produce", mock.Anything, mock.Anything).Return(nil)
+
+		// Act
+		err := kp.Produce(message)
+
+		assert.NoError(t, err)
+		mockProducer.AssertExpectations(t)
+	}()
+	select {
+	case <-done:
+	case <-time.After(10 * time.Second):
+		t.Fatal("test timed out")
+	}
+
+}
+
+func TestKafkaProducer_Produce_Error(t *testing.T) {
+	// Arrange
+	mockProducer := new(mocks.KafkaProducerInterface)
+	topic := "test-topic"
+	kp := &KafkaProducer{
+		producer: mockProducer,
+		topic:    topic,
+	}
+
+	// Simulate production error
+	mockProducer.On("Produce", mock.Anything, mock.Anything).Return(errors.New("produce error"))
+
+	// Act
+	err := kp.Produce([]byte("test message"))
+
+	// Assert
+	assert.Error(t, err)
+	assert.Equal(t, "produce error", err.Error())
+	mockProducer.AssertExpectations(t)
+}
+
+func TestKafkaProducer_Close(t *testing.T) {
+	// Arrange
+	mockProducer := new(mocks.KafkaProducerInterface)
+	kp := &KafkaProducer{
+		producer: mockProducer,
+	}
+
+	// Simulate successful close
+	mockProducer.On("Close").Return()
+
+	// Act
+	kp.Close()
+
+	// Assert
+	mockProducer.AssertExpectations(t)
+}
+
+func TestKafkaProducer_Close_Error(t *testing.T) {
+	// Arrange
+	mockProducer := new(mocks.KafkaProducerInterface)
+	kp := &KafkaProducer{
+		producer: mockProducer,
+	}
+
+	// Simulate close error
+	mockProducer.On("Close").Return()
+
+	// Act
+	kp.Close()
+
+	// Assert
+	mockProducer.AssertExpectations(t)
+}
diff --git a/pkg/kafkacomm/publisher/mocks/PdpStatusSender.go b/pkg/kafkacomm/publisher/mocks/PdpStatusSender.go
new file mode 100644
index 0000000..f9cc279
--- /dev/null
+++ b/pkg/kafkacomm/publisher/mocks/PdpStatusSender.go
@@ -0,0 +1,46 @@
+// Code generated by mockery v2.46.3. DO NOT EDIT.
+
+package mocks
+
+import (
+	model "policy-opa-pdp/pkg/model"
+
+	mock "github.com/stretchr/testify/mock"
+)
+
+// PdpStatusSender is an autogenerated mock type for the PdpStatusSender type
+type PdpStatusSender struct {
+	mock.Mock
+}
+
+// SendPdpStatus provides a mock function with given fields: pdpStatus
+func (_m *PdpStatusSender) SendPdpStatus(pdpStatus model.PdpStatus) error {
+	ret := _m.Called(pdpStatus)
+
+	if len(ret) == 0 {
+		panic("no return value specified for SendPdpStatus")
+	}
+
+	var r0 error
+	if rf, ok := ret.Get(0).(func(model.PdpStatus) error); ok {
+		r0 = rf(pdpStatus)
+	} else {
+		r0 = ret.Error(0)
+	}
+
+	return r0
+}
+
+// NewPdpStatusSender creates a new instance of PdpStatusSender. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
+// The first argument is typically a *testing.T value.
+func NewPdpStatusSender(t interface {
+	mock.TestingT
+	Cleanup(func())
+}) *PdpStatusSender {
+	mock := &PdpStatusSender{}
+	mock.Mock.Test(t)
+
+	t.Cleanup(func() { mock.AssertExpectations(t) })
+
+	return mock
+}
diff --git a/pkg/kafkacomm/publisher/pdp-heartbeat.go b/pkg/kafkacomm/publisher/pdp-heartbeat.go
new file mode 100644
index 0000000..f814992
--- /dev/null
+++ b/pkg/kafkacomm/publisher/pdp-heartbeat.go
@@ -0,0 +1,111 @@
+// -
+//   ========================LICENSE_START=================================
+//   Copyright (C) 2024: Deutsche Telecom
+//
+//   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.
+//   ========================LICENSE_END===================================
+
+// The publisher package is responsible for managing periodic heartbeat messages for the
+// Open Policy Agent (OPA) Policy Decision Point (PDP) and publishing the PDP's status to relevant channels.
+// It provides functions to initialize, manage, and stop timers for sending heartbeat messages,
+// ensuring the PDP communicates its health and state periodically.
+package publisher
+
+import (
+	"fmt"
+	"policy-opa-pdp/consts"
+	"policy-opa-pdp/pkg/log"
+	"policy-opa-pdp/pkg/model"
+	"policy-opa-pdp/pkg/pdpattributes"
+	"policy-opa-pdp/pkg/pdpstate"
+	"time"
+
+	"github.com/google/uuid"
+)
+
+var (
+	ticker          *time.Ticker
+	stopChan        chan bool
+	currentInterval int64
+)
+
+// Initializes a timer that sends periodic heartbeat messages to indicate the health and state of the PDP.
+func StartHeartbeatIntervalTimer(intervalMs int64, s PdpStatusSender) {
+	if intervalMs <= 0 {
+		log.Errorf("Invalid interval provided: %d. Interval must be greater than zero.", intervalMs)
+		ticker = nil
+		return
+	}
+
+	if ticker != nil && intervalMs == currentInterval {
+		log.Debug("Ticker is already running")
+		return
+	}
+
+	if ticker != nil {
+		ticker.Stop()
+	}
+       // StopTicker()
+	currentInterval = intervalMs
+
+	ticker = time.NewTicker(time.Duration(intervalMs) * time.Millisecond)
+	log.Debugf("New Ticker %d", currentInterval)
+	stopChan = make(chan bool)
+	go func() {
+		for {
+			select {
+			case <-ticker.C:
+				sendPDPHeartBeat(s)
+			case <-stopChan:
+				ticker.Stop()
+				return
+			}
+		}
+	}()
+}
+
+// Creates and sends a heartbeat message with the PDP's current state, health, and attributes
+func sendPDPHeartBeat(s PdpStatusSender) error {
+	pdpStatus := model.PdpStatus{
+		MessageType: model.PDP_STATUS,
+		PdpType:     consts.PdpType,
+		State:       pdpstate.GetState(),
+		Healthy:     model.Healthy,
+		Name:        pdpattributes.PdpName,
+		Description: "Pdp heartbeat",
+		PdpGroup:    consts.PdpGroup,
+		PdpSubgroup: &pdpattributes.PdpSubgroup,
+	}
+	pdpStatus.RequestID = uuid.New().String()
+	pdpStatus.TimestampMs = fmt.Sprintf("%d", time.Now().UnixMilli())
+
+	err := s.SendPdpStatus(pdpStatus)
+	log.Debugf("Sending Heartbeat ...")
+	if err != nil {
+		log.Warnf("Error producing message: %v\n", err)
+		return err
+	} else {
+		return nil
+	}
+}
+
+// Stops the running ticker and terminates the goroutine managing heartbeat messages.
+func StopTicker() {
+	if ticker != nil && stopChan != nil {
+		stopChan <- true
+		close(stopChan)
+		ticker = 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
new file mode 100644
index 0000000..f03b0eb
--- /dev/null
+++ b/pkg/kafkacomm/publisher/pdp-heartbeat_test.go
@@ -0,0 +1,135 @@
+// -
+//   ========================LICENSE_START=================================
+//   Copyright (C) 2024: Deutsche Telecom
+//
+//   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.
+//   ========================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)
+	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)
+
+	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()
+	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()
+}
diff --git a/pkg/kafkacomm/publisher/pdp-pap-registration.go b/pkg/kafkacomm/publisher/pdp-pap-registration.go
new file mode 100644
index 0000000..75f22d6
--- /dev/null
+++ b/pkg/kafkacomm/publisher/pdp-pap-registration.go
@@ -0,0 +1,95 @@
+// -
+//   ========================LICENSE_START=================================
+//   Copyright (C) 2024: Deutsche Telecom
+//
+//   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.
+//   ========================LICENSE_END===================================
+
+// allows to send the pdp registartion message with unique transaction id and timestamp to topic
+package publisher
+
+import (
+	"encoding/json"
+	"fmt"
+	"github.com/google/uuid"
+	"policy-opa-pdp/cfg"
+	"policy-opa-pdp/consts"
+	"policy-opa-pdp/pkg/kafkacomm"
+	"policy-opa-pdp/pkg/log"
+	"policy-opa-pdp/pkg/model"
+	"policy-opa-pdp/pkg/pdpattributes"
+	"time"
+)
+
+type PdpStatusSender interface {
+	SendPdpStatus(pdpStatus model.PdpStatus) error
+}
+
+type RealPdpStatusSender struct{}
+
+// Sends PdpSTatus Message type to KafkaTopic
+func (s *RealPdpStatusSender) SendPdpStatus(pdpStatus model.PdpStatus) error {
+
+	var topic string
+	bootstrapServers := cfg.BootstrapServer
+	topic = cfg.Topic
+	pdpStatus.RequestID = uuid.New().String()
+	pdpStatus.TimestampMs = fmt.Sprintf("%d", time.Now().UnixMilli())
+
+	jsonMessage, err := json.Marshal(pdpStatus)
+	if err != nil {
+		log.Warnf("failed to marshal PdpStatus to JSON: %v", err)
+		return err
+	}
+
+	producer, err := kafkacomm.GetKafkaProducer(bootstrapServers, topic)
+	if err != nil {
+		log.Warnf("Error creating Kafka producer: %v\n", err)
+		return err
+	}
+
+	err = producer.Produce(jsonMessage)
+	if err != nil {
+		log.Warnf("Error producing message: %v\n", err)
+	} else {
+		log.Debugf("[OUT|KAFKA|%s]\n%s", topic, string(jsonMessage))
+	}
+
+	return nil
+}
+
+// sends the registartion message to topic using SendPdpStatus(pdpStatus)
+func SendPdpPapRegistration(s PdpStatusSender) error {
+
+	var pdpStatus = model.PdpStatus{
+		MessageType: model.PDP_STATUS,
+		PdpType:     consts.PdpType,
+		State:       model.Passive,
+		Healthy:     model.Healthy,
+		Policies:    nil,
+		PdpResponse: nil,
+		Name:        pdpattributes.PdpName,
+		Description: "Pdp Status Registration Message",
+		PdpGroup:    consts.PdpGroup,
+	}
+
+	log.Debugf("Sending PDP PAP Registration Message")
+
+	err := s.SendPdpStatus(pdpStatus)
+	if err != nil {
+		log.Warnf("Error producing message: %v\n", err)
+		return err
+	}
+	return nil
+
+}
diff --git a/pkg/kafkacomm/publisher/pdp-pap-registration_test.go b/pkg/kafkacomm/publisher/pdp-pap-registration_test.go
new file mode 100644
index 0000000..03749de
--- /dev/null
+++ b/pkg/kafkacomm/publisher/pdp-pap-registration_test.go
@@ -0,0 +1,58 @@
+// -
+//   ========================LICENSE_START=================================
+//   Copyright (C) 2024: Deutsche Telecom
+//
+//   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.
+//   ========================LICENSE_END===================================
+//
+
+package publisher
+
+import (
+	"errors"
+	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/mock"
+	"policy-opa-pdp/pkg/kafkacomm/publisher/mocks"
+	"policy-opa-pdp/pkg/model"
+	"testing"
+)
+
+type MockPdpStatusSender struct {
+	mock.Mock
+}
+
+func (m *MockPdpStatusSender) SendPdpStatus(pdpStatus model.PdpStatus) error {
+	return m.Called(pdpStatus).Error(0)
+
+}
+
+func TestSendPdpPapRegistration_Success(t *testing.T) {
+	mockSender := new(mocks.PdpStatusSender)
+
+	mockSender.On("SendPdpStatus", mock.AnythingOfType("model.PdpStatus")).Return(nil)
+
+	err := SendPdpPapRegistration(mockSender)
+	assert.NoError(t, err)
+	mockSender.AssertCalled(t, "SendPdpStatus", mock.AnythingOfType("model.PdpStatus"))
+}
+
+func TestSendPdpPapRegistration_Failure(t *testing.T) {
+	mockSender := new(mocks.PdpStatusSender)
+
+	mockSender.On("SendPdpStatus", mock.AnythingOfType("model.PdpStatus")).Return(errors.New("failed To Send"))
+
+	err := SendPdpPapRegistration(mockSender)
+	assert.Error(t, err, "Expected an error for failure")
+	assert.EqualError(t, err, "failed To Send", "Error messages should match")
+	mockSender.AssertCalled(t, "SendPdpStatus", mock.AnythingOfType("model.PdpStatus"))
+}
diff --git a/pkg/kafkacomm/publisher/pdp-status-publisher.go b/pkg/kafkacomm/publisher/pdp-status-publisher.go
new file mode 100644
index 0000000..756d0f2
--- /dev/null
+++ b/pkg/kafkacomm/publisher/pdp-status-publisher.go
@@ -0,0 +1,109 @@
+// -
+//   ========================LICENSE_START=================================
+//   Copyright (C) 2024: Deutsche Telecom
+//
+//   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.
+//   ========================LICENSE_END===================================
+//
+
+// responsible for sending PDP_STATUS messages in response to specific events
+// such as updates (PDP_UPDATE) or state changes (PDP_STATE_CHANGE). These responses provide details
+// about the current state, health, and attributes of the Policy Decision Point (PDP).
+package publisher
+
+import (
+	"fmt"
+	"policy-opa-pdp/consts"
+	"policy-opa-pdp/pkg/log"
+	"policy-opa-pdp/pkg/model"
+	"policy-opa-pdp/pkg/pdpattributes"
+	"policy-opa-pdp/pkg/pdpstate"
+	"time"
+
+	"github.com/google/uuid"
+)
+
+// Sends a PDP_STATUS message to indicate the successful processing of a PDP_UPDATE request
+// received from the Policy Administration Point (PAP).
+func SendPdpUpdateResponse(s PdpStatusSender, pdpUpdate *model.PdpUpdate) error {
+
+	responseStatus := model.Success
+	responseMessage := "PDP Update was Successful"
+
+	pdpStatus := model.PdpStatus{
+		MessageType: model.PDP_STATUS,
+		PdpType:     consts.PdpType,
+		State:       pdpstate.State,
+		Healthy:     model.Healthy,
+		Name:        pdpattributes.PdpName,
+		Description: "Pdp Status Response Message For Pdp Update",
+		PdpGroup:    consts.PdpGroup,
+		PdpSubgroup: &pdpattributes.PdpSubgroup,
+		// Policies: [],
+		PdpResponse: &model.PdpResponseDetails{
+			ResponseTo:      &pdpUpdate.RequestId,
+			ResponseStatus:  &responseStatus,
+			ResponseMessage: &responseMessage,
+		},
+	}
+
+	pdpStatus.RequestID = uuid.New().String()
+	pdpStatus.TimestampMs = fmt.Sprintf("%d", time.Now().UnixMilli())
+
+	log.Infof("Sending PDP Status With Update Response")
+
+	err := s.SendPdpStatus(pdpStatus)
+	if err != nil {
+		log.Warnf("Failed to send PDP Update Message : %v", err)
+		return err
+	}
+
+	return nil
+
+}
+
+// Sends a PDP_STATUS message to indicate a state change in the PDP (e.g., from PASSIVE to ACTIVE).
+func SendStateChangeResponse(s PdpStatusSender, pdpStateChange *model.PdpStateChange) error {
+
+	responseStatus := model.Success
+	responseMessage := "PDP State Changed From PASSIVE TO Active"
+	pdpStatus := model.PdpStatus{
+		MessageType: model.PDP_STATUS,
+		PdpType:     consts.PdpType,
+		State:       pdpstate.GetState(),
+		Healthy:     model.Healthy,
+		Name:        pdpattributes.PdpName,
+		Description: "Pdp Status Response Message to Pdp State Change",
+		PdpGroup:    consts.PdpGroup,
+		PdpSubgroup: &pdpattributes.PdpSubgroup,
+		// Policies: [],
+		PdpResponse: &model.PdpResponseDetails{
+			ResponseTo:      &pdpStateChange.RequestId,
+			ResponseStatus:  &responseStatus,
+			ResponseMessage: &responseMessage,
+		},
+	}
+
+	pdpStatus.RequestID = uuid.New().String()
+	pdpStatus.TimestampMs = fmt.Sprintf("%d", time.Now().UnixMilli())
+
+	log.Infof("Sending PDP Status With State Change response")
+
+	err := s.SendPdpStatus(pdpStatus)
+	if err != nil {
+		log.Warnf("Failed to send PDP Update Message : %v", err)
+		return err
+	}
+
+	return nil
+}
diff --git a/pkg/kafkacomm/publisher/pdp-status-publisher_test.go b/pkg/kafkacomm/publisher/pdp-status-publisher_test.go
new file mode 100644
index 0000000..5e02704
--- /dev/null
+++ b/pkg/kafkacomm/publisher/pdp-status-publisher_test.go
@@ -0,0 +1,83 @@
+// -
+//   ========================LICENSE_START=================================
+//   Copyright (C) 2024: Deutsche Telecom
+//
+//   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.
+//   ========================LICENSE_END===================================
+//
+
+package publisher
+
+import (
+	"errors"
+	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/mock"
+	"policy-opa-pdp/pkg/kafkacomm/publisher/mocks"
+	"policy-opa-pdp/pkg/model"
+	"testing"
+)
+
+// TestSendPdpUpdateResponse_Success tests SendPdpUpdateResponse for a successful response
+func TestSendPdpUpdateResponse_Success(t *testing.T) {
+
+	mockSender := new(mocks.PdpStatusSender)
+	mockSender.On("SendPdpStatus", mock.Anything).Return(nil)
+	pdpUpdate := &model.PdpUpdate{RequestId: "test-request-id"}
+
+	err := SendPdpUpdateResponse(mockSender, pdpUpdate)
+	assert.NoError(t, err)
+	mockSender.AssertCalled(t, "SendPdpStatus", mock.Anything)
+}
+
+// TestSendPdpUpdateResponse_Failure tests SendPdpUpdateResponse when SendPdpStatus fails
+func TestSendPdpUpdateResponse_Failure(t *testing.T) {
+
+	mockSender := new(mocks.PdpStatusSender)
+	mockSender.On("SendPdpStatus", mock.Anything).Return(errors.New("mock send error"))
+
+	pdpUpdate := &model.PdpUpdate{RequestId: "test-request-id"}
+
+	err := SendPdpUpdateResponse(mockSender, pdpUpdate)
+
+	assert.Error(t, err)
+
+	mockSender.AssertCalled(t, "SendPdpStatus", mock.Anything)
+}
+
+// TestSendStateChangeResponse_Success tests SendStateChangeResponse for a successful state change response
+func TestSendStateChangeResponse_Success(t *testing.T) {
+
+	mockSender := new(mocks.PdpStatusSender)
+	mockSender.On("SendPdpStatus", mock.Anything).Return(nil)
+
+	pdpStateChange := &model.PdpStateChange{RequestId: "test-state-change-id"}
+
+	err := SendStateChangeResponse(mockSender, pdpStateChange)
+
+	assert.NoError(t, err)
+	mockSender.AssertCalled(t, "SendPdpStatus", mock.Anything)
+}
+
+// TestSendStateChangeResponse_Failure tests SendStateChangeResponse when SendPdpStatus fails
+func TestSendStateChangeResponse_Failure(t *testing.T) {
+
+	mockSender := new(mocks.PdpStatusSender)
+	mockSender.On("SendPdpStatus", mock.Anything).Return(errors.New("mock send error"))
+
+	pdpStateChange := &model.PdpStateChange{RequestId: "test-state-change-id"}
+
+	err := SendStateChangeResponse(mockSender, pdpStateChange)
+	assert.Error(t, err)
+	mockSender.AssertCalled(t, "SendPdpStatus", mock.Anything)
+
+}
diff --git a/pkg/log/log.go b/pkg/log/log.go
new file mode 100644
index 0000000..2a8b997
--- /dev/null
+++ b/pkg/log/log.go
@@ -0,0 +1,131 @@
+// -
+//   ========================LICENSE_START=================================
+//   Copyright (C) 2024: Deutsche Telecom
+//
+//   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.
+//   ========================LICENSE_END===================================
+//
+
+package log
+
+import (
+	"github.com/sirupsen/logrus"
+	"gopkg.in/natefinch/lumberjack.v2"
+	"io"
+	"os"
+	"policy-opa-pdp/cfg"
+	"policy-opa-pdp/consts"
+)
+
+type Logger struct {
+	*logrus.Logger
+}
+
+var (
+	Log *Logger
+)
+
+func SetOutput(w io.Writer) {
+	Log.SetOutput(w)
+}
+
+func init() {
+	Log = InitLogger(consts.LogFilePath, consts.LogMaxSize, consts.LogMaxBackups, cfg.LogLevel)
+}
+
+func InitLogger(logFilePath string, logMaxSize int, logMaxBackups int, logLevel string) *Logger {
+	log := logrus.New()
+
+	log.SetLevel(logrus.DebugLevel)
+	log.SetOutput(os.Stdout)
+
+	logLevelParsed, err := logrus.ParseLevel(logLevel)
+	if err != nil {
+		log.Warn(err)
+	}
+	log.SetLevel(logLevelParsed)
+
+	logRotation := &lumberjack.Logger{
+		Filename:   consts.LogFilePath,
+		MaxSize:    consts.LogMaxSize,
+		MaxBackups: consts.LogMaxBackups,
+	}
+	multiWriter := io.MultiWriter(os.Stdout, logRotation)
+	log.SetOutput(multiWriter)
+
+	log.SetFormatter(&logrus.TextFormatter{
+		ForceColors:     true,
+		DisableColors:   false,
+		FullTimestamp:   true,
+		TimestampFormat: "2006-01-02T15:04:05.0000-07:00",
+	})
+
+	log.Debugf("logger initialised Filepath = %s, Logsize(MB) = %d, Backups = %d, Loglevel = %s", logFilePath, logMaxSize, logMaxBackups, logLevel)
+	return &Logger{log}
+}
+
+func ParseLevel(level string) (logrus.Level, error) {
+	return logrus.ParseLevel(level)
+}
+
+func SetLevel(level logrus.Level) {
+	Log.SetLevel(level)
+}
+
+func Error(args ...interface{}) {
+	Log.Error(args...)
+}
+
+func Info(args ...interface{}) {
+	Log.Info(args...)
+}
+
+func Debug(args ...interface{}) {
+	Log.Debug(args...)
+}
+
+func Warn(args ...interface{}) {
+	Log.Warn(args...)
+}
+
+func Panic(args ...interface{}) {
+	Log.Panic(args...)
+}
+
+func Trace(args ...interface{}) {
+	Log.Trace(args...)
+}
+
+func Errorf(msg string, args ...interface{}) {
+	Log.Errorf(msg, args...)
+}
+
+func Infof(msg string, args ...interface{}) {
+	Log.Infof(msg, args...)
+}
+
+func Debugf(msg string, args ...interface{}) {
+	Log.Debugf(msg, args...)
+}
+
+func Warnf(msg string, args ...interface{}) {
+	Log.Warnf(msg, args...)
+}
+
+func Panicf(msg string, args ...interface{}) {
+	Log.Panicf(msg, args...)
+}
+
+func Tracef(msg string, args ...interface{}) {
+	Log.Tracef(msg, args...)
+}
diff --git a/pkg/log/log_test.go b/pkg/log/log_test.go
new file mode 100644
index 0000000..d24274c
--- /dev/null
+++ b/pkg/log/log_test.go
@@ -0,0 +1,354 @@
+// -
+//   ========================LICENSE_START=================================
+//   Copyright (C) 2024: Deutsche Telecom
+//
+//   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.
+//   ========================LICENSE_END===================================
+//
+
+package log_test
+
+import (
+	"testing"
+
+	"bytes"
+	"github.com/sirupsen/logrus"
+	"policy-opa-pdp/pkg/log"
+)
+
+func TestSetOutput_Success(t *testing.T) {
+	var buf bytes.Buffer
+	log.SetOutput(&buf)
+	log.SetLevel(logrus.InfoLevel)
+
+	log.Info("Testing SetOutput")
+	if !bytes.Contains(buf.Bytes(), []byte("Testing SetOutput")) {
+		t.Errorf("Expected message to be logged")
+	}
+}
+
+func TestInit_Success(t *testing.T) {
+	var buf bytes.Buffer
+
+	log.SetOutput(&buf)
+	log.InitLogger("/tmp/logfile.log", 10, 5, "debug")
+	log.Info("Logger initialized")
+
+	if !bytes.Contains(buf.Bytes(), []byte("Logger initialized")) {
+		t.Errorf("Expected message to be logged after initialization")
+	}
+}
+
+func TestInitLogger_Success(t *testing.T) {
+	var buf bytes.Buffer
+
+	log.SetOutput(&buf)
+
+	log.InitLogger("/tmp/logfile.log", 10, 5, "info")
+
+	log.Info("Logger Initialized Test")
+	if !bytes.Contains(buf.Bytes(), []byte("Logger Initialized Test")) {
+		t.Errorf("Expected message to be logged")
+	}
+}
+
+func TestParseLevel_Success(t *testing.T) {
+	var buf bytes.Buffer
+	log.SetOutput(&buf)
+
+	level, err := logrus.ParseLevel("info")
+	if err != nil {
+		t.Fatalf("Failed to parse log level: %v", err)
+	}
+	log.SetLevel(level)
+
+	log.Info("Info level set")
+
+	if !bytes.Contains(buf.Bytes(), []byte("Info level set")) {
+		t.Errorf("Expected info level to be set")
+	}
+}
+
+func TestSetLevel_Success(t *testing.T) {
+	var buf bytes.Buffer
+	log.SetOutput(&buf)
+	log.SetLevel(logrus.DebugLevel)
+
+	log.Debug("This is a debug message")
+	if !bytes.Contains(buf.Bytes(), []byte("This is a debug message")) {
+		t.Errorf("Expected debug message to be logged")
+	}
+}
+
+func TestError_Success(t *testing.T) {
+	var buf bytes.Buffer
+	log.SetOutput(&buf)
+	log.SetLevel(logrus.ErrorLevel)
+
+	log.Error("This is an error message")
+	if !bytes.Contains(buf.Bytes(), []byte("This is an error message")) {
+		t.Errorf("Expected error message to be logged")
+	}
+}
+
+func TestInfo_Success(t *testing.T) {
+	var buf bytes.Buffer
+	log.SetOutput(&buf)
+	log.SetLevel(logrus.InfoLevel)
+
+	log.Info("This is an info message")
+	if !bytes.Contains(buf.Bytes(), []byte("This is an info message")) {
+		t.Errorf("Expected info message to be logged")
+	}
+}
+
+func TestDebug_Success(t *testing.T) {
+	var buf bytes.Buffer
+	log.SetOutput(&buf)
+	log.SetLevel(logrus.DebugLevel)
+
+	log.Debug("This is a debug message")
+	if !bytes.Contains(buf.Bytes(), []byte("This is a debug message")) {
+		t.Errorf("Expected debug message to be logged")
+	}
+}
+
+func TestWarn_Success(t *testing.T) {
+	var buf bytes.Buffer
+	log.SetOutput(&buf)
+	log.SetLevel(logrus.WarnLevel)
+
+	log.Warn("This is a warning message")
+	if !bytes.Contains(buf.Bytes(), []byte("This is a warning message")) {
+		t.Errorf("Expected warning message to be logged")
+	}
+}
+
+func TestPanic_Success(t *testing.T) {
+	defer func() {
+		if r := recover(); r == nil {
+			t.Errorf("Expected panic, but did not get one")
+		}
+	}()
+
+	log.SetLevel(logrus.PanicLevel)
+	log.Panic("This is a panic message")
+}
+
+func TestTrace_Success(t *testing.T) {
+	var buf bytes.Buffer
+	log.SetOutput(&buf)
+	log.SetLevel(logrus.TraceLevel)
+
+	log.Trace("This is a trace message")
+	if !bytes.Contains(buf.Bytes(), []byte("This is a trace message")) {
+		t.Errorf("Expected trace message to be logged")
+	}
+}
+
+func TestErrorf_Success(t *testing.T) {
+	var buf bytes.Buffer
+	log.SetOutput(&buf)
+	log.SetLevel(logrus.ErrorLevel)
+
+	log.Errorf("Error occurred: %s", "test error")
+	if !bytes.Contains(buf.Bytes(), []byte("Error occurred: test error")) {
+		t.Errorf("Expected error message to be logged")
+	}
+}
+
+func TestInfof_Success(t *testing.T) {
+	var buf bytes.Buffer
+	log.SetOutput(&buf)
+	log.SetLevel(logrus.InfoLevel)
+
+	log.Infof("Info log: %s", "test info")
+	if !bytes.Contains(buf.Bytes(), []byte("Info log: test info")) {
+		t.Errorf("Expected info message to be logged")
+	}
+}
+
+func TestDebugf_Success(t *testing.T) {
+	var buf bytes.Buffer
+	log.SetOutput(&buf)
+	log.SetLevel(logrus.DebugLevel)
+
+	log.Debugf("Debug message: %s", "should log")
+	if !bytes.Contains(buf.Bytes(), []byte("Debug message: should log")) {
+		t.Errorf("Expected debug message to be logged")
+	}
+}
+
+func TestWarnf_Success(t *testing.T) {
+	var buf bytes.Buffer
+	log.SetOutput(&buf)
+	log.SetLevel(logrus.WarnLevel)
+
+	log.Warnf("Warning message: %s", "should log")
+	if !bytes.Contains(buf.Bytes(), []byte("Warning message: should log")) {
+		t.Errorf("Expected warning message to be logged")
+	}
+}
+
+func TestPanicf_Success(t *testing.T) {
+	defer func() {
+		if r := recover(); r == nil {
+			t.Errorf("Expected panic, but did not get one")
+		}
+	}()
+
+	log.SetLevel(logrus.PanicLevel)
+	log.Panicf("Panic message: %s", "should panic")
+}
+
+func TestTracef_Success(t *testing.T) {
+	var buf bytes.Buffer
+	log.SetOutput(&buf)
+	log.SetLevel(logrus.TraceLevel)
+
+	log.Tracef("Trace message: %s", "should log")
+	if !bytes.Contains(buf.Bytes(), []byte("Trace message: should log")) {
+		t.Errorf("Expected trace message to be logged")
+	}
+}
+
+func TestError_Failure(t *testing.T) {
+	var buf bytes.Buffer
+	log.SetOutput(&buf)
+	log.SetLevel(logrus.FatalLevel) // Set level higher than Error
+
+	log.Error("This is an error message")
+	if bytes.Contains(buf.Bytes(), []byte("This is an error message")) {
+		t.Errorf("Expected error message not to be logged")
+	}
+}
+
+func TestInfo_Failure(t *testing.T) {
+	var buf bytes.Buffer
+	log.SetOutput(&buf)
+	log.SetLevel(logrus.WarnLevel) // Set level higher than Info
+
+	log.Info("This is an info message")
+	if bytes.Contains(buf.Bytes(), []byte("This is an info message")) {
+		t.Errorf("Expected info message not to be logged")
+	}
+}
+
+func TestDebug_Failure(t *testing.T) {
+	var buf bytes.Buffer
+	log.SetOutput(&buf)
+	log.SetLevel(logrus.InfoLevel) // Set level higher than Debug
+
+	log.Debug("This is a debug message")
+	if bytes.Contains(buf.Bytes(), []byte("This is a debug message")) {
+		t.Errorf("Expected debug message not to be logged")
+	}
+}
+
+func TestWarn_Failure(t *testing.T) {
+	var buf bytes.Buffer
+	log.SetOutput(&buf)
+	log.SetLevel(logrus.ErrorLevel) // Set level higher than Warn
+
+	log.Warn("This is a warning message")
+	if bytes.Contains(buf.Bytes(), []byte("This is a warning message")) {
+		t.Errorf("Expected warning message not to be logged")
+	}
+}
+
+func TestPanic_Failure(t *testing.T) {
+	defer func() {
+		if r := recover(); r == nil {
+			t.Errorf("Expected a panic at PanicLevel, but did not get one")
+		}
+	}()
+	log.SetLevel(logrus.PanicLevel) // Set to PanicLevel so a panic should occur
+	log.Panic("This should cause a panic at PanicLevel")
+}
+
+func TestTrace_Failure(t *testing.T) {
+	var buf bytes.Buffer
+	log.SetOutput(&buf)
+	log.SetLevel(logrus.DebugLevel) // Set level higher than Trace
+
+	log.Trace("This is a trace message")
+	if bytes.Contains(buf.Bytes(), []byte("This is a trace message")) {
+		t.Errorf("Expected trace message not to be logged")
+	}
+}
+
+func TestErrorf_Failure(t *testing.T) {
+	var buf bytes.Buffer
+	log.SetOutput(&buf)
+	log.SetLevel(logrus.FatalLevel) // Set level higher than Error
+
+	log.Errorf("Error occurred: %s", "test error")
+	if bytes.Contains(buf.Bytes(), []byte("Error occurred: test error")) {
+		t.Errorf("Expected error message not to be logged")
+	}
+}
+
+func TestInfof_Failure(t *testing.T) {
+	var buf bytes.Buffer
+	log.SetOutput(&buf)
+	log.SetLevel(logrus.WarnLevel) // Set level higher than Info
+
+	log.Infof("Info log: %s", "test info")
+	if bytes.Contains(buf.Bytes(), []byte("Info log: test info")) {
+		t.Errorf("Expected info message not to be logged")
+	}
+}
+
+func TestDebugf_Failure(t *testing.T) {
+	var buf bytes.Buffer
+	log.SetOutput(&buf)
+	log.SetLevel(logrus.InfoLevel) // Set level higher than Debug
+
+	log.Debugf("Debug message: %s", "should not log")
+	if bytes.Contains(buf.Bytes(), []byte("Debug message: should not log")) {
+		t.Errorf("Expected debug message not to be logged")
+	}
+}
+
+func TestWarnf_Failure(t *testing.T) {
+	var buf bytes.Buffer
+	log.SetOutput(&buf)
+	log.SetLevel(logrus.ErrorLevel) // Set level higher than Warn
+
+	log.Warnf("Warning message: %s", "should not log")
+	if bytes.Contains(buf.Bytes(), []byte("Warning message: should not log")) {
+		t.Errorf("Expected warning message not to be logged")
+	}
+}
+
+func TestPanicf_Failure(t *testing.T) {
+	defer func() {
+		if r := recover(); r == nil {
+			t.Errorf("Expected a panic at PanicLevel, but did not get one")
+		}
+	}()
+
+	log.SetLevel(logrus.PanicLevel) // Set to PanicLevel so a panic should occur
+	log.Panicf("Panicf message: %s", "should panic at PanicLevel")
+}
+
+func TestTracef_Failure(t *testing.T) {
+	var buf bytes.Buffer
+	log.SetOutput(&buf)
+	log.SetLevel(logrus.DebugLevel) // Set level higher than Trace
+
+	log.Tracef("Trace message: %s", "should not log")
+	if bytes.Contains(buf.Bytes(), []byte("Trace message: should not log")) {
+		t.Errorf("Expected trace message not to be logged")
+	}
+}
diff --git a/pkg/metrics/counters.go b/pkg/metrics/counters.go
new file mode 100644
index 0000000..2fc9539
--- /dev/null
+++ b/pkg/metrics/counters.go
@@ -0,0 +1,66 @@
+package metrics
+
+import "sync"
+
+//global counter variables
+var IndeterminantDecisionsCount int64
+var PermitDecisionsCount int64
+var DenyDecisionsCount int64
+var TotalErrorCount int64
+var mu sync.Mutex
+
+// Increment counter
+func IncrementIndeterminantDecisionsCount() {
+	mu.Lock()
+	IndeterminantDecisionsCount++
+	mu.Unlock()
+}
+
+// returns pointer to the counter
+func IndeterminantDecisionsCountRef() *int64 {
+	mu.Lock()
+	defer mu.Unlock()
+	return &IndeterminantDecisionsCount
+}
+
+// Increment counter
+func IncrementPermitDecisionsCount() {
+	mu.Lock()
+	PermitDecisionsCount++
+	mu.Unlock()
+}
+
+// returns pointer to the counter
+func PermitDecisionsCountRef() *int64 {
+	mu.Lock()
+	defer mu.Unlock()
+	return &PermitDecisionsCount
+}
+
+// Increment counter
+func IncrementDenyDecisionsCount() {
+	mu.Lock()
+	DenyDecisionsCount++
+	mu.Unlock()
+}
+
+// returns pointer to the counter
+func DenyDecisionsCountRef() *int64 {
+	mu.Lock()
+	defer mu.Unlock()
+	return &DenyDecisionsCount
+}
+
+// Increment counter
+func IncrementTotalErrorCount() {
+	mu.Lock()
+	TotalErrorCount++
+	mu.Unlock()
+}
+
+// returns pointer to the counter
+func TotalErrorCountRef() *int64 {
+	mu.Lock()
+	defer mu.Unlock()
+	return &TotalErrorCount
+}
diff --git a/pkg/metrics/counters_test.go b/pkg/metrics/counters_test.go
new file mode 100644
index 0000000..ef4c2b0
--- /dev/null
+++ b/pkg/metrics/counters_test.go
@@ -0,0 +1,60 @@
+package metrics
+
+import (
+	"sync"
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+)
+
+func TestCounters(t *testing.T) {
+	var wg sync.WaitGroup
+
+	// Test IncrementIndeterminantDecisionsCount and IndeterminantDecisionsCountRef
+	IndeterminantDecisionsCount = 0
+	wg.Add(10)
+	for i := 0; i < 10; i++ {
+		go func() {
+			defer wg.Done()
+			IncrementIndeterminantDecisionsCount()
+		}()
+	}
+	wg.Wait()
+	assert.Equal(t, int64(10), *IndeterminantDecisionsCountRef())
+
+	// Test IncrementPermitDecisionsCount and PermitDecisionsCountRef
+	PermitDecisionsCount = 0
+	wg.Add(15)
+	for i := 0; i < 15; i++ {
+		go func() {
+			defer wg.Done()
+			IncrementPermitDecisionsCount()
+		}()
+	}
+	wg.Wait()
+	assert.Equal(t, int64(15), *PermitDecisionsCountRef())
+
+	// Test IncrementDenyDecisionsCount and DenyDecisionsCountRef
+	DenyDecisionsCount = 0
+	wg.Add(20)
+	for i := 0; i < 20; i++ {
+		go func() {
+			defer wg.Done()
+			IncrementDenyDecisionsCount()
+		}()
+	}
+	wg.Wait()
+	assert.Equal(t, int64(20), *DenyDecisionsCountRef())
+
+	// Test IncrementTotalErrorCount and TotalErrorCountRef
+	TotalErrorCount = 0
+	wg.Add(5)
+	for i := 0; i < 5; i++ {
+		go func() {
+			defer wg.Done()
+			IncrementTotalErrorCount()
+		}()
+	}
+	wg.Wait()
+	assert.Equal(t, int64(5), *TotalErrorCountRef())
+}
diff --git a/pkg/metrics/statistics-provider.go b/pkg/metrics/statistics-provider.go
new file mode 100644
index 0000000..67cee79
--- /dev/null
+++ b/pkg/metrics/statistics-provider.go
@@ -0,0 +1,65 @@
+// Handles an HTTP request to fetch the current system statistics.
+// It aggregates various decision counts (e.g., indeterminate, permit, deny)
+// and error counts into a structured response and sends it back to the client in JSON format.
+package metrics
+
+import (
+	"encoding/json"
+	"net/http"
+	"policy-opa-pdp/pkg/log"
+	"policy-opa-pdp/pkg/model/oapicodegen"
+	"policy-opa-pdp/pkg/utils"
+
+	"github.com/google/uuid"
+	openapi_types "github.com/oapi-codegen/runtime/types"
+)
+
+func FetchCurrentStatistics(res http.ResponseWriter, req *http.Request) {
+
+	requestId := req.Header.Get("X-ONAP-RequestID")
+	var parsedUUID *uuid.UUID
+	var statisticsParams *oapicodegen.StatisticsParams
+
+	if requestId != "" && utils.IsValidUUID(requestId) {
+		tempUUID, err := uuid.Parse(requestId)
+		if err != nil {
+			log.Warnf("Error Parsing the requestID: %v", err)
+		} else {
+			parsedUUID = &tempUUID
+			statisticsParams = &oapicodegen.StatisticsParams{
+				XONAPRequestID: (*openapi_types.UUID)(parsedUUID),
+			}
+			res.Header().Set("X-ONAP-RequestID", statisticsParams.XONAPRequestID.String())
+		}
+	} else {
+		log.Warnf("Invalid or Missing  Request ID")
+		requestId = "000000000000"
+		res.Header().Set("X-ONAP-RequestID", requestId)
+	}
+
+	var statReport oapicodegen.StatisticsReport
+
+	statReport.IndeterminantDecisionsCount = IndeterminantDecisionsCountRef()
+	statReport.PermitDecisionsCount = PermitDecisionsCountRef()
+	statReport.DenyDecisionsCount = DenyDecisionsCountRef()
+	statReport.TotalErrorCount = TotalErrorCountRef()
+
+	// not implemented hardcoding the values to zero
+	// will be implemeneted in phase-2
+	zerovalue := int64(0)
+	onevalue := int64(1)
+	statReport.TotalPoliciesCount = &zerovalue
+	statReport.TotalPolicyTypesCount = &onevalue
+	statReport.DeployFailureCount = &zerovalue
+	statReport.DeploySuccessCount = &zerovalue
+	statReport.UndeployFailureCount = &zerovalue
+	statReport.UndeploySuccessCount = &zerovalue
+
+	value := int32(200)
+	statReport.Code = &value
+
+	res.Header().Set("Content-Type", "application/json")
+	res.WriteHeader(http.StatusOK)
+	json.NewEncoder(res).Encode(statReport)
+
+}
diff --git a/pkg/metrics/statistics-provider_test.go b/pkg/metrics/statistics-provider_test.go
new file mode 100644
index 0000000..a5e57b6
--- /dev/null
+++ b/pkg/metrics/statistics-provider_test.go
@@ -0,0 +1,51 @@
+package metrics
+
+import (
+	"encoding/json"
+	"net/http"
+	"net/http/httptest"
+	"policy-opa-pdp/pkg/model/oapicodegen"
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+)
+
+func TestFetchCurrentStatistics(t *testing.T) {
+
+	IndeterminantDecisionsCount = 10
+	PermitDecisionsCount = 15
+	DenyDecisionsCount = 20
+	TotalErrorCount = 5
+
+	// Create a new HTTP request
+	req := httptest.NewRequest(http.MethodGet, "/statistics", nil)
+	// Create a response recorder to capture the response
+	res := httptest.NewRecorder()
+
+	// Call the function under test
+	FetchCurrentStatistics(res, req)
+
+	// Verify the status code
+	assert.Equal(t, http.StatusOK, res.Code)
+
+	// Verify the response headers
+	assert.Equal(t, "application/json", res.Header().Get("Content-Type"))
+
+	var statReport oapicodegen.StatisticsReport
+	err := json.Unmarshal(res.Body.Bytes(), &statReport)
+	assert.NoError(t, err)
+
+	// Verify the response body
+	assert.Equal(t, int64(10), *statReport.IndeterminantDecisionsCount)
+	assert.Equal(t, int64(15), *statReport.PermitDecisionsCount)
+	assert.Equal(t, int64(20), *statReport.DenyDecisionsCount)
+	assert.Equal(t, int64(5), *statReport.TotalErrorCount)
+	assert.Equal(t, int64(0), *statReport.TotalPoliciesCount)
+	assert.Equal(t, int64(1), *statReport.TotalPolicyTypesCount)
+	assert.Equal(t, int64(0), *statReport.DeployFailureCount)
+	assert.Equal(t, int64(0), *statReport.DeploySuccessCount)
+	assert.Equal(t, int64(0), *statReport.UndeployFailureCount)
+	assert.Equal(t, int64(0), *statReport.UndeploySuccessCount)
+
+	assert.Equal(t, int32(200), *statReport.Code)
+}
diff --git a/pkg/model/healthcheckmessage.go b/pkg/model/healthcheckmessage.go
new file mode 100644
index 0000000..8b0d9db
--- /dev/null
+++ b/pkg/model/healthcheckmessage.go
@@ -0,0 +1,27 @@
+// -
+//   ========================LICENSE_START=================================
+//   Copyright (C) 2024: Deutsche Telecom
+//
+//   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.
+//   ========================LICENSE_END===================================
+//
+ 
+package model
+ 
+type HealthCheckResponse struct {
+        Name    string `json:"name"`
+        Url     string `json:"url"`
+        Healthy bool   `json:"healthy"`
+        Code    int    `json:"code"`
+        Message string `json:"message"`
+}
diff --git a/pkg/model/mesages.go b/pkg/model/mesages.go
new file mode 100644
index 0000000..a4451d7
--- /dev/null
+++ b/pkg/model/mesages.go
@@ -0,0 +1,111 @@
+// -
+//   ========================LICENSE_START=================================
+//   Copyright (C) 2024: Deutsche Telecom
+//
+//   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.
+//   ========================LICENSE_END===================================
+
+// Defines structure for messages exchanged between PDP and PAP
+// Refer: https://docs.onap.org/projects/onap-policy-parent/en/latest/pap/InternalPapPdp.html
+// for attribute level details of each message.
+package model
+
+import (
+	"encoding/json"
+	"fmt"
+)
+
+// PdpMessageType represents the type of PDP message.
+type PdpMessageType int
+
+// Enumerate the possible PDP message types
+// https://github.com/onap/policy-models
+// models-pdp/src/main/java/org/onap/policy/models/pdp/enums/PdpMessageType.java
+const (
+	PDP_STATUS PdpMessageType = iota
+	PDP_UPDATE
+	PDP_STATE_CHANGE
+	PDP_HEALTH_CHECK
+	PDP_TOPIC_CHECK
+)
+
+// String representation of PdpMessageType
+func (msgType PdpMessageType) String() string {
+	switch msgType {
+	case PDP_STATUS:
+		return "PDP_STATUS"
+	case PDP_UPDATE:
+		return "PDP_UPDATE"
+	case PDP_STATE_CHANGE:
+		return "PDP_STATE_CHANGE"
+	case PDP_HEALTH_CHECK:
+		return "PDP_HEALTH_CHECK"
+	case PDP_TOPIC_CHECK:
+		return "PDP_TOPIC_CHECK"
+	default:
+		return fmt.Sprintf("Unknown PdpMessageType: %d", msgType)
+	}
+}
+
+func (p PdpMessageType) MarshalJSON() ([]byte, error) {
+	return json.Marshal(p.String())
+}
+
+// PdpStatus represents the PDP_STATUS message sent from PDP to PAP.
+// https://github.com/onap/policy-models
+// models-pdp/src/main/java/org/onap/policy/models/pdp/concepts/PdpStatus.java
+type PdpStatus struct {
+	MessageType PdpMessageType           `json:"messageName"`
+	PdpType     string                   `json:"pdpType"`
+	State       PdpState                 `json:"state"`
+	Healthy     PdpHealthStatus          `json:"healthy"`
+	Description string                   `json:"description"`
+	PdpResponse *PdpResponseDetails      `json:"response"`
+	Policies    []ToscaConceptIdentifier `json:"policies"`
+	Name        string                   `json:"name"`
+	RequestID   string                   `json:"requestId"`
+	PdpGroup    string                   `json:"pdpGroup"`
+	PdpSubgroup *string                  `json:"pdpSubgroup"`
+	TimestampMs string                   `json:"timestampMs"`
+	DeploymentInstanceInfo string        `json:"deploymentInstanceInfo"`
+}
+
+// PDP_UPDATE sent by PAP to PDP.
+// https://github.com/onap/policy-models
+// models-pdp/src/main/java/org/onap/policy/models/pdp/concepts/PdpUpdate.java
+type PdpUpdate struct {
+	Source                 string                    `json:"source" validate:"required"`
+	PdpHeartbeatIntervalMs int64                     `json:"pdpHeartbeatIntervalMs" validate:"required"`
+	MessageType            string                    `json:"messageName" validate:"required"`
+	PoliciesToBeDeloyed    []string                  `json:"policiesToBeDeployed" validate:"required"`
+	policiesToBeUndeployed []ToscaConceptIdentifier  `json:"policiesToBeUndeployed"`
+	Name                   string                    `json:"name" validate:"required"`
+	TimestampMs            int64                     `json:"timestampMs" validate:"required"`
+	PdpGroup               string                    `json:"pdpGroup" validate:"required"`
+	PdpSubgroup            string                    `json:"pdpSubgroup" validate:"required"`
+	RequestId              string                    `json:"requestId" validate:"required"`
+}
+
+// PDP_STATE_CHANGE sent by PAP to PDP.
+// https://github.com/onap/policy-models
+// models-pdp/src/main/java/org/onap/policy/models/pdp/concepts/PdpStateChange.java
+type PdpStateChange struct {
+	Source      string `json:"source"`
+	State       string `json:"state"`
+	MessageType string `json:"messageName"`
+	Name        string `json:"name"`
+	TimestampMs int64  `json:"timestampMs"`
+	PdpGroup    string `json:"pdpGroup"`
+	PdpSubgroup string `json:"pdpSubgroup"`
+	RequestId   string `json:"requestId"`
+}
diff --git a/pkg/model/messages_test.go b/pkg/model/messages_test.go
new file mode 100644
index 0000000..f6bb5ca
--- /dev/null
+++ b/pkg/model/messages_test.go
@@ -0,0 +1,241 @@
+// -
+//   ========================LICENSE_START=================================
+//   Copyright (C) 2024: Deutsche Telecom
+//
+//   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.
+//   ========================LICENSE_END===================================
+//
+
+package model
+
+import (
+	"encoding/json"
+	"errors"
+	"testing"
+)
+
+func (p *PdpStatus) Validate() error {
+	if p.PdpType == "" {
+		return errors.New("PdpType is required")
+	}
+
+	// Check if State is set to a valid non-zero value
+	if p.State != Passive && p.State != Safe && p.State != Test && p.State != Active && p.State != Terminated {
+		return errors.New("State is required and must be a valid PdpState")
+	}
+
+	// Check if Healthy is set to a valid non-zero value
+	if p.Healthy != Healthy && p.Healthy != NotHealthy && p.Healthy != TestInProgress && p.Healthy != Unknown {
+		return errors.New("Healthy status is required and must be a valid PdpHealthStatus")
+	}
+
+	if p.Name == "" {
+		return errors.New("Name is required")
+	}
+	if p.RequestID == "" {
+		return errors.New("RequestID is required")
+	}
+	if p.PdpGroup == "" {
+		return errors.New("PdpGroup is required")
+	}
+	if p.TimestampMs == "" {
+		return errors.New("TimestampMs is required")
+	}
+
+	return nil
+}
+
+// TestPdpStatusSerialization_Positive tests the successful serialization of PdpStatus.
+func TestPdpStatusSerialization_Success(t *testing.T) {
+	pdpStatus := PdpStatus{
+		MessageType: PDP_STATUS,
+		PdpType:     "examplePdpType",
+		State:       Active,
+		Healthy:     Healthy,
+		Description: "PDP is healthy",
+		PdpResponse: nil, // Set to nil for simplicity
+		Policies:    []ToscaConceptIdentifier{},
+		Name:        "ExamplePDP",
+		RequestID:   "12345",
+		PdpGroup:    "Group1",
+		PdpSubgroup: nil,
+		TimestampMs: "1633017600000",
+	}
+
+	_, err := json.Marshal(pdpStatus)
+	if err != nil {
+		t.Errorf("Expected no error while marshaling valid PdpStatus, got: %v", err)
+	}
+}
+
+// TestPdpStatusSerialization_Negative tests the serialization of PdpStatus with invalid fields.
+func TestPdpStatusValidation_Failure(t *testing.T) {
+	// Example of invalid state and health strings that will fail conversion
+	state, err := ConvertStringToEnumState("INVALID_STATE")
+	if err == nil {
+		t.Fatal("Expected error for invalid state")
+	}
+
+	// Example with missing fields or invalid enums
+	pdpStatus := PdpStatus{
+		PdpType:     "",
+		State:       state,
+		Name:        "",
+		RequestID:   "",
+		PdpGroup:    "",
+		TimestampMs: "",
+	}
+
+	err = pdpStatus.Validate()
+	if err == nil {
+		t.Error("Expected an error while validating invalid PdpStatus, but got none")
+	}
+}
+
+func (p *PdpUpdate) Validate() error {
+	if p.Source == "" {
+		return errors.New("Source is required")
+	}
+	if p.PdpHeartbeatIntervalMs <= 0 {
+		return errors.New("PdpHeartbeatIntervalMs must be a positive integer")
+	}
+	if p.MessageType == "" {
+		return errors.New("MessageType is required")
+	}
+	if len(p.PoliciesToBeDeloyed) == 0 {
+		return errors.New("PoliciesToBeDeloyed is required and must contain at least one policy")
+	}
+	if p.Name == "" {
+		return errors.New("Name is required")
+	}
+	if p.TimestampMs <= 0 {
+		return errors.New("TimestampMs is required and must be a positive integer")
+	}
+	if p.PdpGroup == "" {
+		return errors.New("PdpGroup is required")
+	}
+	if p.PdpSubgroup == "" {
+		return errors.New("PdpSubgroup is required")
+	}
+	if p.RequestId == "" {
+		return errors.New("RequestId is required")
+	}
+
+	return nil
+}
+
+// TestPdpUpdateSerialization_Positive tests the successful serialization of PdpUpdate.
+func TestPdpUpdateSerialization_Success(t *testing.T) {
+	pdpUpdate := PdpUpdate{
+		Source:                 "source1",
+		PdpHeartbeatIntervalMs: 5000,
+		MessageType:            "PDP_UPDATE",
+		PoliciesToBeDeloyed:    []string{"policy1", "policy2"},
+		Name:                   "ExamplePDP",
+		TimestampMs:            1633017600000,
+		PdpGroup:               "Group1",
+		PdpSubgroup:            "SubGroup1",
+		RequestId:              "54321",
+	}
+
+	_, err := json.Marshal(pdpUpdate)
+	if err != nil {
+		t.Errorf("Expected no error while marshaling valid PdpUpdate, got: %v", err)
+	}
+}
+
+// TestPdpUpdateSerialization_Negative tests the serialization of PdpUpdate with invalid fields.
+func TestPdpUpdateSerialization_Failure(t *testing.T) {
+	pdpUpdate := PdpUpdate{
+		Source:                 "",
+		PdpHeartbeatIntervalMs: 5000,
+		MessageType:            "",
+		PoliciesToBeDeloyed:    nil,
+		Name:                   "",
+		TimestampMs:            0,
+		PdpGroup:               "",
+		PdpSubgroup:            "",
+		RequestId:              "",
+	}
+	err := pdpUpdate.Validate()
+	if err == nil {
+		t.Error("Expected an error while validating invalid PdpStatus, but got none")
+	}
+
+}
+
+func (p *PdpStateChange) Validate() error {
+	if p.Source == "" {
+		return errors.New("Source is required")
+	}
+	if p.State == "" {
+		return errors.New("State is required")
+	}
+	if p.MessageType == "" {
+		return errors.New("MessageType is required")
+	}
+	if p.Name == "" {
+		return errors.New("Name is required")
+	}
+	if p.TimestampMs <= 0 {
+		return errors.New("TimestampMs is required and must be a positive integer")
+	}
+	if p.PdpGroup == "" {
+		return errors.New("PdpGroup is required")
+	}
+	if p.PdpSubgroup == "" {
+		return errors.New("PdpSubgroup is required")
+	}
+	if p.RequestId == "" {
+		return errors.New("RequestId is required")
+	}
+
+	return nil
+}
+
+// TestPdpStateChangeSerialization_Positive tests the successful serialization of PdpStateChange.
+func TestPdpStateChangeSerialization_Success(t *testing.T) {
+	pdpStateChange := PdpStateChange{
+		Source:      "source1",
+		State:       "active",
+		MessageType: "PDP_STATE_CHANGE",
+		Name:        "ExamplePDP",
+		TimestampMs: 1633017600000,
+		PdpGroup:    "Group1",
+		PdpSubgroup: "SubGroup1",
+		RequestId:   "98765",
+	}
+
+	_, err := json.Marshal(pdpStateChange)
+	if err != nil {
+		t.Errorf("Expected no error while marshaling valid PdpStateChange, got: %v", err)
+	}
+}
+
+// TestPdpStateChangeSerialization_Negative tests the serialization of PdpStateChange with invalid fields.
+func TestPdpStateChangeSerialization_Failure(t *testing.T) {
+	pdpStateChange := PdpStateChange{
+		Source:      "",
+		State:       "",
+		MessageType: "",
+		Name:        "",
+		TimestampMs: 0,
+		PdpGroup:    "",
+		PdpSubgroup: "",
+		RequestId:   "",
+	}
+	err := pdpStateChange.Validate()
+	if err == nil {
+		t.Error("Expected an error while validating invalid PdpStatus, but got none")
+	}
+}
diff --git a/pkg/model/oapicodegen/models.go b/pkg/model/oapicodegen/models.go
new file mode 100644
index 0000000..4f1b770
--- /dev/null
+++ b/pkg/model/oapicodegen/models.go
@@ -0,0 +1,133 @@
+// Package api provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/deepmap/oapi-codegen version v1.16.3 DO NOT EDIT.
+package oapicodegen
+
+import (
+	"time"
+
+	openapi_types "github.com/oapi-codegen/runtime/types"
+)
+
+const (
+	BasicAuthScopes = "basicAuth.Scopes"
+)
+
+// Defines values for ErrorResponseResponseCode.
+const (
+	BADGATEWAY                    ErrorResponseResponseCode = "BAD_GATEWAY"
+	BADREQUEST                    ErrorResponseResponseCode = "BAD_REQUEST"
+	CONFLICT                      ErrorResponseResponseCode = "CONFLICT"
+	EXPECTATIONFAILED             ErrorResponseResponseCode = "EXPECTATION_FAILED"
+	GATEWAYTIMEOUT                ErrorResponseResponseCode = "GATEWAY_TIMEOUT"
+	GONE                          ErrorResponseResponseCode = "GONE"
+	HTTPVERSIONNOTSUPPORTED       ErrorResponseResponseCode = "HTTP_VERSION_NOT_SUPPORTED"
+	INTERNALSERVERERROR           ErrorResponseResponseCode = "INTERNAL_SERVER_ERROR"
+	LENGTHREQUIRED                ErrorResponseResponseCode = "LENGTH_REQUIRED"
+	METHODNOTALLOWED              ErrorResponseResponseCode = "METHOD_NOT_ALLOWED"
+	NETWORKAUTHENTICATIONREQUIRED ErrorResponseResponseCode = "NETWORK_AUTHENTICATION_REQUIRED"
+	NOTACCEPTABLE                 ErrorResponseResponseCode = "NOT_ACCEPTABLE"
+	NOTIMPLEMENTED                ErrorResponseResponseCode = "NOT_IMPLEMENTED"
+	PRECONDITIONFAILED            ErrorResponseResponseCode = "PRECONDITION_FAILED"
+	PRECONDITIONREQUIRED          ErrorResponseResponseCode = "PRECONDITION_REQUIRED"
+	REQUESTEDRANGENOTSATISFIABLE  ErrorResponseResponseCode = "REQUESTED_RANGE_NOT_SATISFIABLE"
+	REQUESTENTITYTOOLARGE         ErrorResponseResponseCode = "REQUEST_ENTITY_TOO_LARGE"
+	REQUESTHEADERFIELDSTOOLARGE   ErrorResponseResponseCode = "REQUEST_HEADER_FIELDS_TOO_LARGE"
+	REQUESTTIMEOUT                ErrorResponseResponseCode = "REQUEST_TIMEOUT"
+	REQUESTURITOOLONG             ErrorResponseResponseCode = "REQUEST_URI_TOO_LONG"
+	SERVICEUNAVAILABLE            ErrorResponseResponseCode = "SERVICE_UNAVAILABLE"
+	TOOMANYREQUESTS               ErrorResponseResponseCode = "TOO_MANY_REQUESTS"
+	UNAUTHORIZED                  ErrorResponseResponseCode = "UNAUTHORIZED"
+	UNSUPPORTEDMEDIATYPE          ErrorResponseResponseCode = "UNSUPPORTED_MEDIA_TYPE"
+)
+
+// Defines values for OPADecisionResponseDecision.
+const (
+	DENY          OPADecisionResponseDecision = "DENY"
+	INDETERMINATE OPADecisionResponseDecision = "INDETERMINATE"
+	PERMIT        OPADecisionResponseDecision = "PERMIT"
+)
+
+// ErrorResponse defines model for ErrorResponse.
+type ErrorResponse struct {
+	ErrorDetails *[]string                  `json:"errorDetails,omitempty"`
+	ErrorMessage *string                    `json:"errorMessage,omitempty"`
+	PolicyName   *string                    `json:"policyName,omitempty"`
+	ResponseCode *ErrorResponseResponseCode `json:"responseCode,omitempty"`
+}
+
+// ErrorResponseResponseCode defines model for ErrorResponse.ResponseCode.
+type ErrorResponseResponseCode string
+
+// HealthCheckReport defines model for HealthCheckReport.
+type HealthCheckReport struct {
+	Code    *int32  `json:"code,omitempty"`
+	Healthy *bool   `json:"healthy,omitempty"`
+	Message *string `json:"message,omitempty"`
+	Name    *string `json:"name,omitempty"`
+	Url     *string `json:"url,omitempty"`
+}
+
+// OPADecisionRequest defines model for OPADecisionRequest.
+type OPADecisionRequest struct {
+	CurrentDate     *openapi_types.Date     `json:"currentDate,omitempty"`
+	CurrentDateTime *time.Time              `json:"currentDateTime,omitempty"`
+	CurrentTime     *time.Time              `json:"currentTime,omitempty"`
+	Input           *map[string]interface{} `json:"input,omitempty"`
+	OnapComponent   *string                 `json:"onapComponent,omitempty"`
+	OnapInstance    *string                 `json:"onapInstance,omitempty"`
+	OnapName        *string                 `json:"onapName,omitempty"`
+	PolicyName      *string                 `json:"policyName,omitempty"`
+
+	// TimeOffset Time offset in hours and minutes, e.g., '+02:00' or '-05:00'
+	TimeOffset *string `json:"timeOffset,omitempty"`
+
+	// TimeZone Timezone in IANA format (e.g., 'America/NewYork', 'Europe/Paris', 'UTC')
+	TimeZone *string `json:"timeZone,omitempty"`
+}
+
+// OPADecisionResponse defines model for OPADecisionResponse.
+type OPADecisionResponse struct {
+	Decision      *OPADecisionResponseDecision `json:"decision,omitempty"`
+	PolicyName    *string                      `json:"policyName,omitempty"`
+	StatusMessage *string                      `json:"statusMessage,omitempty"`
+}
+
+// OPADecisionResponseDecision defines model for OPADecisionResponse.Decision.
+type OPADecisionResponseDecision string
+
+// StatisticsReport defines model for StatisticsReport.
+type StatisticsReport struct {
+	Code                        *int32 `json:"code,omitempty"`
+	DenyDecisionsCount          *int64 `json:"denyDecisionsCount,omitempty"`
+	DeployFailureCount          *int64 `json:"deployFailureCount,omitempty"`
+	DeploySuccessCount          *int64 `json:"deploySuccessCount,omitempty"`
+	IndeterminantDecisionsCount *int64 `json:"indeterminantDecisionsCount,omitempty"`
+	PermitDecisionsCount        *int64 `json:"permitDecisionsCount,omitempty"`
+	TotalErrorCount             *int64 `json:"totalErrorCount,omitempty"`
+	TotalPoliciesCount          *int64 `json:"totalPoliciesCount,omitempty"`
+	TotalPolicyTypesCount       *int64 `json:"totalPolicyTypesCount,omitempty"`
+	UndeployFailureCount        *int64 `json:"undeployFailureCount,omitempty"`
+	UndeploySuccessCount        *int64 `json:"undeploySuccessCount,omitempty"`
+}
+
+// DecisionParams defines parameters for Decision.
+type DecisionParams struct {
+	// XONAPRequestID RequestID for http transaction
+	XONAPRequestID *openapi_types.UUID `json:"X-ONAP-RequestID,omitempty"`
+}
+
+// HealthcheckParams defines parameters for Healthcheck.
+type HealthcheckParams struct {
+	// XONAPRequestID RequestID for http transaction
+	XONAPRequestID *openapi_types.UUID `json:"X-ONAP-RequestID,omitempty"`
+}
+
+// StatisticsParams defines parameters for Statistics.
+type StatisticsParams struct {
+	// XONAPRequestID RequestID for http transaction
+	XONAPRequestID *openapi_types.UUID `json:"X-ONAP-RequestID,omitempty"`
+}
+
+// DecisionJSONRequestBody defines body for Decision for application/json ContentType.
+type DecisionJSONRequestBody = OPADecisionRequest
diff --git a/pkg/model/pdphealthstatus.go b/pkg/model/pdphealthstatus.go
new file mode 100644
index 0000000..387a1e8
--- /dev/null
+++ b/pkg/model/pdphealthstatus.go
@@ -0,0 +1,57 @@
+// -
+//   ========================LICENSE_START=================================
+//   Copyright (C) 2024: Deutsche Telecom
+//
+//   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.
+//   ========================LICENSE_END===================================
+
+// the possible values for health status of PDP.
+// https://github.com/onap/policy-models/blob/master/models-pdp
+// models-pdp/src/main/java/org/onap/policy/models/pdp/enums/PdpHealthStatus.java
+package model
+
+import (
+	"encoding/json"
+	"fmt"
+)
+
+// PdpHealthStatus represents the possible values for the health status of PDP.
+type PdpHealthStatus int
+
+// Enumerate the possible PDP health statuses
+const (
+	Healthy PdpHealthStatus = iota
+	NotHealthy
+	TestInProgress
+	Unknown
+)
+
+// String representation of PdpHealthStatus
+func (status PdpHealthStatus) String() string {
+	switch status {
+	case Healthy:
+		return "HEALTHY"
+	case NotHealthy:
+		return "NOT_HEALTHY"
+	case TestInProgress:
+		return "TEST_IN_PROGRESS"
+	case Unknown:
+		return "UNKNOWN"
+	default:
+		return fmt.Sprintf("Unknown PdpHealthStatus: %d", status)
+	}
+}
+
+func (p PdpHealthStatus) MarshalJSON() ([]byte, error) {
+	return json.Marshal(p.String())
+}
diff --git a/pkg/model/pdphealthstatus_test.go b/pkg/model/pdphealthstatus_test.go
new file mode 100644
index 0000000..0cb89cf
--- /dev/null
+++ b/pkg/model/pdphealthstatus_test.go
@@ -0,0 +1,92 @@
+// -
+//   ========================LICENSE_START=================================
+//   Copyright (C) 2024: Deutsche Telecom
+//
+//   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.
+//   ========================LICENSE_END===================================
+//
+
+package model
+
+import (
+	"encoding/json"
+	"testing"
+)
+
+// Positive test for the string representation of valid PdpHealthStatus values
+func TestPdpHealthStatus_String_Success(t *testing.T) {
+	tests := []struct {
+		status   PdpHealthStatus
+		expected string
+	}{
+		{Healthy, "HEALTHY"},
+		{NotHealthy, "NOT_HEALTHY"},
+		{TestInProgress, "TEST_IN_PROGRESS"},
+		{Unknown, "UNKNOWN"},
+	}
+
+	for _, test := range tests {
+		if got := test.status.String(); got != test.expected {
+			t.Errorf("PdpHealthStatus.String() = %v, want %v", got, test.expected)
+		}
+	}
+}
+
+// Negative test for the string representation of an invalid PdpHealthStatus value
+func TestPdpHealthStatus_String_Failure(t *testing.T) {
+	invalidStatus := PdpHealthStatus(100)
+	expected := "Unknown PdpHealthStatus: 100"
+
+	if got := invalidStatus.String(); got != expected {
+		t.Errorf("PdpHealthStatus.String() = %v, want %v", got, expected)
+	}
+}
+
+// Positive test for JSON marshaling of valid PdpHealthStatus values
+func TestPdpHealthStatus_MarshalJSON_Success(t *testing.T) {
+	tests := []struct {
+		status   PdpHealthStatus
+		expected string
+	}{
+		{Healthy, `"HEALTHY"`},
+		{NotHealthy, `"NOT_HEALTHY"`},
+		{TestInProgress, `"TEST_IN_PROGRESS"`},
+		{Unknown, `"UNKNOWN"`},
+	}
+
+	for _, test := range tests {
+		got, err := json.Marshal(test.status)
+		if err != nil {
+			t.Errorf("json.Marshal() error = %v", err)
+		}
+
+		if string(got) != test.expected {
+			t.Errorf("json.Marshal() = %v, want %v", string(got), test.expected)
+		}
+	}
+}
+
+// Negative test for JSON marshaling of an invalid PdpHealthStatus value
+func TestPdpHealthStatus_MarshalJSON_Failure(t *testing.T) {
+	invalidStatus := PdpHealthStatus(100)
+	expected := `"Unknown PdpHealthStatus: 100"`
+
+	got, err := json.Marshal(invalidStatus)
+	if err != nil {
+		t.Errorf("json.Marshal() unexpected error = %v", err)
+	}
+
+	if string(got) != expected {
+		t.Errorf("json.Marshal() = %v, want %v", string(got), expected)
+	}
+}
diff --git a/pkg/model/pdpresponsedetails.go b/pkg/model/pdpresponsedetails.go
new file mode 100644
index 0000000..8febae5
--- /dev/null
+++ b/pkg/model/pdpresponsedetails.go
@@ -0,0 +1,34 @@
+// -
+//   ========================LICENSE_START=================================
+//   Copyright (C) 2024: Deutsche Telecom
+//
+//   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.
+//   ========================LICENSE_END===================================
+
+// represent PDP response details.
+// https://github.com/onap/policy-models/blob/master/models-pdp
+// models-pdp/src/main/java/org/onap/policy/models/pdp/concepts/PdpResponseDetails.java
+package model
+
+type PdpResponseStatus string
+
+const (
+	Success PdpResponseStatus = "SUCCESS"
+	Failure PdpResponseStatus = "FAILURE"
+)
+
+type PdpResponseDetails struct {
+	ResponseTo      *string            `json:"responseTo"`
+	ResponseStatus  *PdpResponseStatus `json:"responseStatus"`
+	ResponseMessage *string            `json:"responseMessage"`
+}
diff --git a/pkg/model/pdpresponsedetails_test.go b/pkg/model/pdpresponsedetails_test.go
new file mode 100644
index 0000000..14b9cd8
--- /dev/null
+++ b/pkg/model/pdpresponsedetails_test.go
@@ -0,0 +1,89 @@
+// -
+//   ========================LICENSE_START=================================
+//   Copyright (C) 2024: Deutsche Telecom
+//
+//   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.
+//   ========================LICENSE_END===================================
+//
+
+package model
+
+import (
+	"encoding/json"
+	"testing"
+)
+
+// Positive test for JSON marshaling of PdpResponseDetails with all fields populated
+func TestPdpResponseDetails_MarshalJSON_Success(t *testing.T) {
+	responseTo := "requestID123"
+	responseMessage := "Operation completed successfully"
+	responseStatus := Success
+
+	details := PdpResponseDetails{
+		ResponseTo:      &responseTo,
+		ResponseStatus:  &responseStatus,
+		ResponseMessage: &responseMessage,
+	}
+
+	expectedJSON := `{"responseTo":"requestID123","responseStatus":"SUCCESS","responseMessage":"Operation completed successfully"}`
+	got, err := json.Marshal(details)
+	if err != nil {
+		t.Errorf("json.Marshal() error = %v", err)
+	}
+
+	if string(got) != expectedJSON {
+		t.Errorf("json.Marshal() = %v, want %v", string(got), expectedJSON)
+	}
+}
+
+// Negative test for JSON marshaling of PdpResponseDetails with nil fields
+func TestPdpResponseDetails_MarshalJSON_Failure(t *testing.T) {
+	details := PdpResponseDetails{}
+
+	expectedJSON := `{"responseTo":null,"responseStatus":null,"responseMessage":null}`
+	got, err := json.Marshal(details)
+	if err != nil {
+		t.Errorf("json.Marshal() error = %v", err)
+	}
+
+	if string(got) != expectedJSON {
+		t.Errorf("json.Marshal() = %v, want %v", string(got), expectedJSON)
+	}
+}
+
+// Positive test for PdpResponseStatus constants
+func TestPdpResponseStatus_Success(t *testing.T) {
+	tests := []struct {
+		status   PdpResponseStatus
+		expected string
+	}{
+		{Success, "SUCCESS"},
+		{Failure, "FAILURE"},
+	}
+
+	for _, test := range tests {
+		if string(test.status) != test.expected {
+			t.Errorf("PdpResponseStatus = %v, want %v", test.status, test.expected)
+		}
+	}
+}
+
+// Negative test for invalid PdpResponseStatus
+func TestPdpResponseStatus_Failure(t *testing.T) {
+	invalidStatus := PdpResponseStatus("INVALID")
+	expected := "INVALID"
+
+	if string(invalidStatus) != expected {
+		t.Errorf("PdpResponseStatus = %v, want %v", invalidStatus, expected)
+	}
+}
diff --git a/pkg/model/pdpstate.go b/pkg/model/pdpstate.go
new file mode 100644
index 0000000..2b54d16
--- /dev/null
+++ b/pkg/model/pdpstate.go
@@ -0,0 +1,77 @@
+// -
+//   ========================LICENSE_START=================================
+//   Copyright (C) 2024: Deutsche Telecom
+//
+//   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.
+//   ========================LICENSE_END===================================
+
+// hold the possible values for state of PDP.
+// https://github.com/onap/policy-models/blob/master/models-pdp
+// models-pdp/src/main/java/org/onap/policy/models/pdp/enums/PdpState.java
+package model
+
+import (
+	"encoding/json"
+	"fmt"
+)
+
+// PdpState represents the possible values for the state of PDP.
+type PdpState int
+
+// Enumerate the possible PDP states
+const (
+	Passive PdpState = iota
+	Safe
+	Test
+	Active
+	Terminated
+)
+
+// String representation of PdpState
+func (state PdpState) String() string {
+	switch state {
+	case Passive:
+		return "PASSIVE"
+	case Safe:
+		return "SAFE"
+	case Test:
+		return "TEST"
+	case Active:
+		return "ACTIVE"
+	case Terminated:
+		return "TERMINATED"
+	default:
+		return fmt.Sprintf("Unknown PdpState: %d", state)
+	}
+}
+
+func (s PdpState) MarshalJSON() ([]byte, error) {
+	return json.Marshal(s.String())
+}
+
+func ConvertStringToEnumState(state string) (PdpState, error) {
+	switch state {
+	case "PASSIVE":
+		return Passive, nil
+	case "SAFE":
+		return Safe, nil
+	case "TEST":
+		return Test, nil
+	case "ACTIVE":
+		return Active, nil
+	case "TERMINATED":
+		return Terminated, nil
+	default:
+		return -1, fmt.Errorf("Unknown PdpState: %s", state)
+	}
+}
diff --git a/pkg/model/pdpstate_test.go b/pkg/model/pdpstate_test.go
new file mode 100644
index 0000000..35ff6af
--- /dev/null
+++ b/pkg/model/pdpstate_test.go
@@ -0,0 +1,128 @@
+// -
+//   ========================LICENSE_START=================================
+//   Copyright (C) 2024: Deutsche Telecom
+//
+//   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.
+//   ========================LICENSE_END===================================
+//
+
+package model
+
+import (
+	"encoding/json"
+	"testing"
+)
+
+// Positive test cases for PdpState.String
+func TestPdpState_String_Success(t *testing.T) {
+	tests := []struct {
+		state    PdpState
+		expected string
+	}{
+		{Passive, "PASSIVE"},
+		{Safe, "SAFE"},
+		{Test, "TEST"},
+		{Active, "ACTIVE"},
+		{Terminated, "TERMINATED"},
+	}
+
+	for _, test := range tests {
+		got := test.state.String()
+		if got != test.expected {
+			t.Errorf("PdpState.String() = %v, want %v", got, test.expected)
+		}
+	}
+}
+
+// Negative test case for PdpState.String
+func TestPdpState_String_Failure(t *testing.T) {
+	state := PdpState(100) // Unknown state
+	expected := "Unknown PdpState: 100"
+	got := state.String()
+	if got != expected {
+		t.Errorf("PdpState.String() = %v, want %v", got, expected)
+	}
+}
+
+// Positive test cases for PdpState.MarshalJSON
+func TestPdpState_MarshalJSON_Success(t *testing.T) {
+	tests := []struct {
+		state    PdpState
+		expected string
+	}{
+		{Passive, `"PASSIVE"`},
+		{Safe, `"SAFE"`},
+		{Test, `"TEST"`},
+		{Active, `"ACTIVE"`},
+		{Terminated, `"TERMINATED"`},
+	}
+
+	for _, test := range tests {
+		got, err := json.Marshal(test.state)
+		if err != nil {
+			t.Errorf("json.Marshal() error = %v", err)
+			continue
+		}
+
+		if string(got) != test.expected {
+			t.Errorf("json.Marshal() = %v, want %v", string(got), test.expected)
+		}
+	}
+}
+
+// Negative test case for PdpState.MarshalJSON
+func TestPdpState_MarshalJSON_Failure(t *testing.T) {
+	state := PdpState(100) // Unknown state
+	expected := `"Unknown PdpState: 100"`
+
+	got, err := json.Marshal(state)
+	if err != nil {
+		t.Errorf("json.Marshal() error = %v", err)
+	} else if string(got) != expected {
+		t.Errorf("json.Marshal() = %v, want %v", string(got), expected)
+	}
+}
+
+// Positive test cases for ConvertStringToEnumState
+func TestConvertStringToEnumState_Success(t *testing.T) {
+	tests := []struct {
+		input    string
+		expected PdpState
+	}{
+		{"PASSIVE", Passive},
+		{"SAFE", Safe},
+		{"TEST", Test},
+		{"ACTIVE", Active},
+		{"TERMINATED", Terminated},
+	}
+
+	for _, test := range tests {
+		got, err := ConvertStringToEnumState(test.input)
+		if err != nil {
+			t.Errorf("ConvertStringToEnumState(%v) unexpected error = %v", test.input, err)
+			continue
+		}
+		if got != test.expected {
+			t.Errorf("ConvertStringToEnumState(%v) = %v, want %v", test.input, got, test.expected)
+		}
+	}
+}
+
+// Negative test case for ConvertStringToEnumState
+func TestConvertStringToEnumState_Failure(t *testing.T) {
+	input := "UNKNOWN" // Invalid state
+	_, err := ConvertStringToEnumState(input)
+	if err == nil {
+		t.Errorf("ConvertStringToEnumState(%v) expected error, got nil", input)
+	}
+}
diff --git a/pkg/model/toscaconceptidentifier.go b/pkg/model/toscaconceptidentifier.go
new file mode 100644
index 0000000..7afc7b1
--- /dev/null
+++ b/pkg/model/toscaconceptidentifier.go
@@ -0,0 +1,56 @@
+// -
+//   ========================LICENSE_START=================================
+//   Copyright (C) 2024: Deutsche Telecom
+//
+//   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.
+//   ========================LICENSE_END===================================
+
+// Identifies a concept. Both the name and version must be non-null.
+// https://github.com/onap/policy-models/blob/master/models-tosca
+// models-tosca/src/main/java/org/onap/policy/models/tosca/authorative/concepts/ToscaConceptIdentifier.java
+package model
+
+import (
+	"fmt"
+)
+
+type ToscaConceptIdentifier struct {
+	Name    string
+	Version string
+}
+
+func NewToscaConceptIdentifier(name, version string) *ToscaConceptIdentifier {
+	return &ToscaConceptIdentifier{
+		Name:    name,
+		Version: version,
+	}
+}
+
+func NewToscaConceptIdentifierFromKey(key PfKey) *ToscaConceptIdentifier {
+	return &ToscaConceptIdentifier{
+		Name:    key.Name,
+		Version: key.Version,
+	}
+}
+
+func (id *ToscaConceptIdentifier) ValidatePapRest() error {
+	if id.Name == "" || id.Version == "" {
+		return fmt.Errorf("name and version must be non-empty")
+	}
+	return nil
+}
+
+type PfKey struct {
+	Name    string
+	Version string
+}
diff --git a/pkg/model/toscaconceptidentifier_test.go b/pkg/model/toscaconceptidentifier_test.go
new file mode 100644
index 0000000..a131483
--- /dev/null
+++ b/pkg/model/toscaconceptidentifier_test.go
@@ -0,0 +1,106 @@
+// -
+//   ========================LICENSE_START=================================
+//   Copyright (C) 2024: Deutsche Telecom
+//
+//   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.
+//   ========================LICENSE_END===================================
+//
+
+package model
+
+import (
+	"testing"
+)
+
+// Positive test for NewToscaConceptIdentifier
+func TestNewToscaConceptIdentifier_Success(t *testing.T) {
+	name := "ExampleName"
+	version := "1.0.0"
+	id := NewToscaConceptIdentifier(name, version)
+
+	if id.Name != name {
+		t.Errorf("Expected Name: %s, got: %s", name, id.Name)
+	}
+	if id.Version != version {
+		t.Errorf("Expected Version: %s, got: %s", version, id.Version)
+	}
+}
+
+// Negative test for NewToscaConceptIdentifier with empty name and version
+func TestNewToscaConceptIdentifier_Failure(t *testing.T) {
+	name := ""
+	version := ""
+	id := NewToscaConceptIdentifier(name, version)
+
+	if id.Name != name {
+		t.Errorf("Expected Name to be empty, got: %s", id.Name)
+	}
+	if id.Version != version {
+		t.Errorf("Expected Version to be empty, got: %s", id.Version)
+	}
+}
+
+// Positive test for NewToscaConceptIdentifierFromKey
+func TestNewToscaConceptIdentifierFromKey_Success(t *testing.T) {
+	key := PfKey{Name: "KeyName", Version: "1.0.0"}
+	id := NewToscaConceptIdentifierFromKey(key)
+
+	if id.Name != key.Name {
+		t.Errorf("Expected Name: %s, got: %s", key.Name, id.Name)
+	}
+	if id.Version != key.Version {
+		t.Errorf("Expected Version: %s, got: %s", key.Version, id.Version)
+	}
+}
+
+// Negative test for NewToscaConceptIdentifierFromKey with empty PfKey values
+func TestNewToscaConceptIdentifierFromKey_Failure(t *testing.T) {
+	key := PfKey{Name: "", Version: ""}
+	id := NewToscaConceptIdentifierFromKey(key)
+
+	if id.Name != key.Name {
+		t.Errorf("Expected Name to be empty, got: %s", id.Name)
+	}
+	if id.Version != key.Version {
+		t.Errorf("Expected Version to be empty, got: %s", id.Version)
+	}
+}
+
+// Positive test for ToscaConceptIdentifier.ValidatePapRest
+func TestToscaConceptIdentifier_ValidatePapRest_Success(t *testing.T) {
+	id := NewToscaConceptIdentifier("ValidName", "1.0.0")
+	err := id.ValidatePapRest()
+
+	if err != nil {
+		t.Errorf("Expected no error, got: %v", err)
+	}
+}
+
+// Negative test for ToscaConceptIdentifier.ValidatePapRest with invalid values
+func TestToscaConceptIdentifier_ValidatePapRest_Failure(t *testing.T) {
+	tests := []struct {
+		id        *ToscaConceptIdentifier
+		expectErr bool
+	}{
+		{NewToscaConceptIdentifier("", "1.0"), true},       // Missing name
+		{NewToscaConceptIdentifier("ValidName", ""), true}, // Missing version
+		{NewToscaConceptIdentifier("", ""), true},          // Missing name and version
+	}
+
+	for _, test := range tests {
+		err := test.id.ValidatePapRest()
+		if (err != nil) != test.expectErr {
+			t.Errorf("ValidatePapRest() for id: %+v, got error = %v, expectErr = %v", test.id, err != nil, test.expectErr)
+		}
+	}
+}
diff --git a/pkg/opasdk/opasdk.go b/pkg/opasdk/opasdk.go
new file mode 100644
index 0000000..da6c7cc
--- /dev/null
+++ b/pkg/opasdk/opasdk.go
@@ -0,0 +1,92 @@
+// -
+//   ========================LICENSE_START=================================
+//   Copyright (C) 2024: Deutsche Telecom
+//
+//   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.
+//   ========================LICENSE_END===================================
+
+// The opasdk package provides functionalities for integrating with the Open Policy Agent
+// (OPA) SDK, including reading configurations and managing a singleton OPA instance.
+// This package is designed to ensure efficient, thread-safe initialization and configuration
+// of the OPA instance.
+package opasdk
+
+import (
+	"bytes"
+	"context"
+	"fmt"
+	"io"
+	"os"
+	"policy-opa-pdp/consts"
+	"policy-opa-pdp/pkg/log"
+	"sync"
+
+	"github.com/open-policy-agent/opa/sdk"
+)
+
+// Define the structs
+var (
+	opaInstance *sdk.OPA  //A singleton instance of the OPA object
+	once        sync.Once //A sync.Once variable used to ensure that the OPA instance is initialized only once,
+)
+
+// reads JSON configuration from a file and return a jsonReader
+func getJSONReader(filePath string, openFunc func(string) (*os.File, error),
+	readAllFunc func(io.Reader) ([]byte, error)) (*bytes.Reader, error) {
+	file, err := openFunc(filePath)
+	if err != nil {
+		return nil, fmt.Errorf("error opening file: %w", err)
+	}
+	defer file.Close()
+
+	byteValue, err := readAllFunc(file)
+	if err != nil {
+		return nil, fmt.Errorf("error reading config file: %w", err)
+	}
+
+	jsonReader := bytes.NewReader(byteValue)
+	return jsonReader, nil
+}
+
+// Returns a singleton instance of the OPA object. The initialization of the instance is
+// thread-safe, and the OPA object is configured using a JSON configuration file.
+func GetOPASingletonInstance() (*sdk.OPA, error) {
+	var err error
+	once.Do(func() {
+		var opaErr error
+		opaInstance, opaErr = sdk.New(context.Background(), sdk.Options{
+			// Configure your OPA instance here
+			V1Compatible: true,
+		})
+		log.Debugf("Create an instance of OPA Object")
+		if opaErr != nil {
+			log.Warnf("Error creating OPA instance: %s", opaErr)
+			err = opaErr
+			return
+		} else {
+			jsonReader, jsonErr := getJSONReader(consts.OpasdkConfigPath, os.Open, io.ReadAll)
+			if jsonErr != nil {
+				log.Warnf("Error getting JSON reader: %s", jsonErr)
+				err = jsonErr
+				return
+			}
+			log.Debugf("Configure an instance of OPA Object")
+
+			opaInstance.Configure(context.Background(), sdk.ConfigOptions{
+				Config: jsonReader,
+			})
+		}
+	})
+
+	return opaInstance, err
+}
diff --git a/pkg/opasdk/opasdk_test.go b/pkg/opasdk/opasdk_test.go
new file mode 100644
index 0000000..b6c205b
--- /dev/null
+++ b/pkg/opasdk/opasdk_test.go
@@ -0,0 +1,111 @@
+// -
+//   ========================LICENSE_START=================================
+//   Copyright (C) 2024: Deutsche Telecom
+//
+//   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.
+//   ========================LICENSE_END===================================
+//
+
+package opasdk
+
+import (
+	"io"
+	"os"
+	"policy-opa-pdp/consts"
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/mock"
+)
+
+func TestGetOPASingletonInstance_ConfigurationFileNotexisting(t *testing.T) {
+	consts.OpasdkConfigPath = "/app/config/config.json"
+	opaInstance, err := GetOPASingletonInstance()
+	assert.NotNil(t, err) //error no such file or directory /app/config/config.json
+	assert.NotNil(t, opaInstance)
+}
+
+func TestGetOPASingletonInstance_SingletonBehavior(t *testing.T) {
+	tmpFile, err := os.CreateTemp("", "config.json")
+	if err != nil {
+		t.Fatalf("Failed to create temp file: %v", err)
+	}
+	defer os.Remove(tmpFile.Name())
+
+	consts.OpasdkConfigPath = tmpFile.Name()
+
+	// Call the function multiple times
+	opaInstance1, err1 := GetOPASingletonInstance()
+	opaInstance2, err2 := GetOPASingletonInstance()
+
+	// Assertions
+	assert.Nil(t, err1)
+	assert.Nil(t, err2)
+	assert.NotNil(t, opaInstance1)
+	assert.NotNil(t, opaInstance2)
+	assert.Equal(t, opaInstance1, opaInstance2) // Ensure it's the same instance
+}
+
+func TestGetOPASingletonInstance_OPAInstanceCreation(t *testing.T) {
+	tmpFile, err := os.CreateTemp("", "config.json")
+	if err != nil {
+		t.Fatalf("Failed to create temp file: %v", err)
+	}
+	defer os.Remove(tmpFile.Name())
+
+	consts.OpasdkConfigPath = tmpFile.Name()
+
+	// Call the function
+	opaInstance, err := GetOPASingletonInstance()
+
+	// Assertions
+	assert.Nil(t, err)
+	assert.NotNil(t, opaInstance)
+}
+
+// Mock for os.Open
+type MockFile struct {
+	mock.Mock
+}
+
+func (m *MockFile) Open(name string) (*os.File, error) {
+	args := m.Called(name)
+	return args.Get(0).(*os.File), args.Error(1)
+}
+
+// Mock for io.ReadAll
+func mockReadAll(r io.Reader) ([]byte, error) {
+	return []byte(`{"config": "test"}`), nil
+}
+
+func TestGetJSONReader(t *testing.T) {
+	// Create a mock file
+	mockFile := new(MockFile)
+	mockFile.On("Open", "/app/config/config.json").Return(&os.File{}, nil)
+
+	// Call the function with mock functions
+	jsonReader, err := getJSONReader("/app/config/config.json", mockFile.Open, mockReadAll)
+
+	// Check the results
+	assert.NoError(t, err)
+	assert.NotNil(t, jsonReader)
+
+	// Check the content of the jsonReader
+	expectedContent := `{"config": "test"}`
+	actualContent := make([]byte, len(expectedContent))
+	jsonReader.Read(actualContent)
+	assert.Equal(t, expectedContent, string(actualContent))
+
+	// Assert that the mock methods were called
+	mockFile.AssertCalled(t, "Open", "/app/config/config.json")
+}
diff --git a/pkg/pdpattributes/pdpattributes.go b/pkg/pdpattributes/pdpattributes.go
new file mode 100644
index 0000000..70744fd
--- /dev/null
+++ b/pkg/pdpattributes/pdpattributes.go
@@ -0,0 +1,63 @@
+// -
+//   ========================LICENSE_START=================================
+//   Copyright (C) 2024: Deutsche Telecom
+//
+//   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.
+//   ========================LICENSE_END===================================
+
+// The pdpattributes package provides utilities for managing and configuring attributes related to the
+// Policy Decision Point (PDP). This includes generating unique PDP names, and setting or retrieving
+// subgroup and heartbeat interval values.
+package pdpattributes
+
+import (
+	"github.com/google/uuid"
+	"policy-opa-pdp/pkg/log"
+)
+
+var (
+	PdpName              string // A unique identifier for the PDP instance
+	PdpSubgroup          string
+	PdpHeartbeatInterval int64 // The interval (in seconds) at which the PDP sends heartbeat signals
+)
+
+func init() {
+	PdpName = GenerateUniquePdpName()
+	log.Debugf("Name: %s", PdpName)
+}
+
+// Generates a unique PDP name by appending a randomly generated UUID
+func GenerateUniquePdpName() string {
+	return "opa-" + uuid.New().String()
+}
+
+// sets the Pdp Subgroup retrieved from the message from Pap
+func SetPdpSubgroup(pdpsubgroup string) {
+	PdpSubgroup = pdpsubgroup
+}
+
+// Retrieves the current PDP subgroup value.
+func GetPdpSubgroup() string {
+	return PdpSubgroup
+}
+
+// sets the PdpHeratbeatInterval retrieved from the message from Pap
+func SetPdpHeartbeatInterval(pdpHeartbeatInterval int64) {
+	PdpHeartbeatInterval = pdpHeartbeatInterval
+}
+
+// Retrieves the current PDP heartbeat interval value.
+func GetPdpHeartbeatInterval() int64 {
+	return PdpHeartbeatInterval
+
+}
diff --git a/pkg/pdpattributes/pdpattributes_test.go b/pkg/pdpattributes/pdpattributes_test.go
new file mode 100644
index 0000000..0870ed6
--- /dev/null
+++ b/pkg/pdpattributes/pdpattributes_test.go
@@ -0,0 +1,87 @@
+// -
+//   ========================LICENSE_START=================================
+//   Copyright (C) 2024: Deutsche Telecom
+//
+//   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.
+//   ========================LICENSE_END===================================
+//
+
+package pdpattributes
+
+import (
+	"testing"
+	"time"
+
+	"github.com/stretchr/testify/assert"
+)
+
+func TestGenerateUniquePdpName_Success(t *testing.T) {
+	t.Run("GenerateValidPdpName", func(t *testing.T) {
+		pdpName := GenerateUniquePdpName()
+		assert.Contains(t, pdpName, "opa-", "Expected PDP name to start with 'opa-'")
+	})
+}
+
+func TestGenerateUniquePdpName_Failure(t *testing.T) {
+	t.Run("UniqueNamesCheck", func(t *testing.T) {
+		pdpName1 := GenerateUniquePdpName()
+		pdpName2 := GenerateUniquePdpName()
+		assert.NotEqual(t, pdpName1, pdpName2, "Expected different UUID for each generated PDP name")
+		assert.Len(t, pdpName1, len("opa-")+36, "Expected length of PDP name to match 'opa-<UUID>' format")
+	})
+}
+
+func TestSetPdpSubgroup_Success(t *testing.T) {
+	t.Run("ValidSubgroup", func(t *testing.T) {
+		expectedSubgroup := "subgroup1"
+		SetPdpSubgroup(expectedSubgroup)
+		assert.Equal(t, expectedSubgroup, GetPdpSubgroup(), "Expected PDP subgroup to match set value")
+	})
+}
+
+func TestSetPdpSubgroup_Failure(t *testing.T) {
+	t.Run("EmptySubgroup", func(t *testing.T) {
+		SetPdpSubgroup("")
+		assert.Equal(t, "", GetPdpSubgroup(), "Expected PDP subgroup to be empty when set to empty string")
+	})
+
+	t.Run("LargeSubgroup", func(t *testing.T) {
+		largeSubgroup := make([]byte, 1024*1024) // 1MB of 'a' characters
+		for i := range largeSubgroup {
+			largeSubgroup[i] = 'a'
+		}
+		SetPdpSubgroup(string(largeSubgroup))
+		assert.Equal(t, string(largeSubgroup), GetPdpSubgroup(), "Expected large PDP subgroup to match set value")
+	})
+}
+
+func TestSetPdpHeartbeatInterval_Success(t *testing.T) {
+	t.Run("ValidHeartbeatInterval", func(t *testing.T) {
+		expectedInterval := int64(30)
+		SetPdpHeartbeatInterval(expectedInterval)
+		assert.Equal(t, expectedInterval, GetPdpHeartbeatInterval(), "Expected heartbeat interval to match set value")
+	})
+}
+
+func TestSetPdpHeartbeatInterval_Failure(t *testing.T) {
+	t.Run("FailureHeartbeatInterval", func(t *testing.T) {
+		SetPdpHeartbeatInterval(-10)
+		assert.Equal(t, int64(-10), GetPdpHeartbeatInterval(), "Expected heartbeat interval to handle negative values")
+	})
+
+	t.Run("LargeHeartbeatInterval", func(t *testing.T) {
+		largeInterval := int64(time.Hour * 24 * 365 * 10) // 10 years in seconds
+		SetPdpHeartbeatInterval(largeInterval)
+		assert.Equal(t, largeInterval, GetPdpHeartbeatInterval(), "Expected PDP heartbeat interval to handle large values")
+	})
+}
diff --git a/pkg/pdpstate/pdpstate.go b/pkg/pdpstate/pdpstate.go
new file mode 100644
index 0000000..0adaa2e
--- /dev/null
+++ b/pkg/pdpstate/pdpstate.go
@@ -0,0 +1,45 @@
+// -
+//   ========================LICENSE_START=================================
+//   Copyright (C) 2024: Deutsche Telecom
+//
+//   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.
+//   ========================LICENSE_END===================================
+
+// The pdpstate package manages the state of the Policy Decision Point (PDP), allowing for dynamic updates
+// and retrieval of the PDP's current operational state. States are represented using the model.PdpState type.
+package pdpstate
+
+import (
+	"policy-opa-pdp/pkg/model"
+)
+
+var (
+	State           model.PdpState = model.Passive // The current state of the PDP.
+	GetCurrentState                = GetState      // An alias for the GetState function.
+)
+
+// sets the Pdp State retrieved from the message from Pap
+func SetState(stringState string) error {
+	newState, err := model.ConvertStringToEnumState(stringState)
+	if err != nil {
+		return err
+	}
+
+	State = newState
+	return nil
+}
+
+// Retrieves the current PDP state.
+func GetState() model.PdpState {
+	return State
+}
diff --git a/pkg/pdpstate/pdpstate_test.go b/pkg/pdpstate/pdpstate_test.go
new file mode 100644
index 0000000..6b7078c
--- /dev/null
+++ b/pkg/pdpstate/pdpstate_test.go
@@ -0,0 +1,43 @@
+// -
+//   ========================LICENSE_START=================================
+//   Copyright (C) 2024: Deutsche Telecom
+//
+//   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.
+//   ========================LICENSE_END===================================
+//
+
+package pdpstate
+
+import (
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+	"policy-opa-pdp/pkg/model"
+)
+
+func TestSetState_Success(t *testing.T) {
+	t.Run("ValidState", func(t *testing.T) {
+		err := SetState("ACTIVE")
+		assert.NoError(t, err, "Expected no error for valid state")
+		assert.Equal(t, model.Active, GetState(), "Expected state to be set to Active")
+	})
+}
+
+func TestSetState_Failure(t *testing.T) {
+	State = model.Passive
+	t.Run("InvalidState", func(t *testing.T) {
+		err := SetState("InvalidState")
+		assert.Error(t, err, "Expected an error for invalid state")
+		assert.Equal(t, model.Passive, GetState(), "Expected state to remain unchanged when setting invalid state")
+	})
+}
diff --git a/pkg/utils/utils.go b/pkg/utils/utils.go
new file mode 100644
index 0000000..c2cb591
--- /dev/null
+++ b/pkg/utils/utils.go
@@ -0,0 +1,30 @@
+// -
+//   ========================LICENSE_START=================================
+//   Copyright (C) 2024: Deutsche Telecom
+//
+//   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.
+//   ========================LICENSE_END===================================
+
+// Package utils provides common  functionalities
+
+package utils
+
+import (
+	"github.com/google/uuid"
+)
+
+// validates if the given request is in valid uuid form
+func IsValidUUID(u string) bool {
+	_, err := uuid.Parse(u)
+	return err == nil
+}
diff --git a/pkg/utils/utils_test.go b/pkg/utils/utils_test.go
new file mode 100644
index 0000000..b70fa2b
--- /dev/null
+++ b/pkg/utils/utils_test.go
@@ -0,0 +1,59 @@
+// -
+//   ========================LICENSE_START=================================
+//   Copyright (C) 2024: Deutsche Telecom
+//
+//   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.
+//   ========================LICENSE_END===================================
+
+package utils
+
+import (
+	"github.com/google/uuid"
+	"testing"
+)
+
+// Positive Test Case: Valid UUIDs
+func TestIsValidUUIDPositive(t *testing.T) {
+	// Define valid UUID strings
+	validUUIDs := []string{
+		"123e4567-e89b-12d3-a456-426614174000", // Standard UUID
+		uuid.New().String(),                    // Dynamically generated UUID
+	}
+
+	for _, u := range validUUIDs {
+		t.Run("Valid UUID", func(t *testing.T) {
+			if !IsValidUUID(u) {
+				t.Errorf("Expected valid UUID, but got invalid for %s", u)
+			}
+		})
+	}
+}
+
+// Negative Test Case: Invalid UUIDs
+func TestIsValidUUIDNegative(t *testing.T) {
+	// Define invalid UUID strings
+	invalidUUIDs := []string{
+		"123e4567-e89b-12d3-a456-42661417400",  // Invalid: missing character at the end
+		"invalid-uuid-format",                  // Invalid: incorrect format
+		"123e4567-e89b-12d3-a456-42661417400x", // Invalid: contains extra non-hex character
+		" ",                                    // Invalid: empty string
+	}
+
+	for _, u := range invalidUUIDs {
+		t.Run("Invalid UUID", func(t *testing.T) {
+			if IsValidUUID(u) {
+				t.Errorf("Expected invalid UUID, but got valid for %s", u)
+			}
+		})
+	}
+}
diff --git a/test/Opagroup.json b/test/Opagroup.json
new file mode 100644
index 0000000..002b962
--- /dev/null
+++ b/test/Opagroup.json
@@ -0,0 +1,23 @@
+{
+    "groups": [
+        {
+            "name": "defaultGroup",
+            "pdpGroupState": "ACTIVE",
+            "properties": {},
+            "pdpSubgroups": [
+                {
+                    "pdpType": "opa",
+                    "desiredInstanceCount": 1,
+                    "properties": {},
+                    "supportedPolicyTypes": [
+                        {
+                            "name": "onap.policies.native.opa",
+                            "version": "1.0.0"
+                        }
+                    ],
+                    "policies": []
+                }
+            ]
+        }
+    ]
+}
diff --git a/test/README.md b/test/README.md
new file mode 100644
index 0000000..7940342
--- /dev/null
+++ b/test/README.md
@@ -0,0 +1,54 @@
+# Testing OPA
+
+## 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' --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
+
+## 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
+
+{"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
+
+{"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
+
+{"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
+
+{"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
+{"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
+
+{"decision":"DENY","policyName":"organization/allow","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
+
+{"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
+
+{"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/config.json b/test/config.json
new file mode 100644
index 0000000..3f2aa43
--- /dev/null
+++ b/test/config.json
@@ -0,0 +1,24 @@
+{
+  "logging": {
+    "level": "debug"
+  },
+  "services": [
+    {
+      "name": "opa-bundle-server",
+      "url": "http://localhost:8282/opa/bundles"
+    }
+  ],
+  "bundles": {
+    "opabundle": {
+      "service": "opa-bundle-server",
+      "resource": "bundle.tar.gz",
+      "polling": {
+        "min_delay_seconds": 60,
+        "max_delay_seconds": 120
+      }
+    }
+  },
+  "decision_logs": {
+    "console": true
+  }
+}
diff --git a/test/config/opa-pdp/config.json b/test/config/opa-pdp/config.json
new file mode 100644
index 0000000..3f2aa43
--- /dev/null
+++ b/test/config/opa-pdp/config.json
@@ -0,0 +1,24 @@
+{
+  "logging": {
+    "level": "debug"
+  },
+  "services": [
+    {
+      "name": "opa-bundle-server",
+      "url": "http://localhost:8282/opa/bundles"
+    }
+  ],
+  "bundles": {
+    "opabundle": {
+      "service": "opa-bundle-server",
+      "resource": "bundle.tar.gz",
+      "polling": {
+        "min_delay_seconds": 60,
+        "max_delay_seconds": 120
+      }
+    }
+  },
+  "decision_logs": {
+    "console": true
+  }
+}
diff --git a/test/config/opa-pdp/groups.json b/test/config/opa-pdp/groups.json
new file mode 100644
index 0000000..502700c
--- /dev/null
+++ b/test/config/opa-pdp/groups.json
@@ -0,0 +1,15 @@
+{
+  "groups": [
+    {
+      "name": "defaultGroup",
+      "version": "1.0.0",
+      "description": "The default group that registers all supported policy types and pdps.",
+      "pdpGroupState": "ACTIVE",
+      "pdpSubgroups": [
+        {
+          "pdpType": "opa"
+        }
+      ]
+    }
+  ]
+}
diff --git a/test/config/opa-pdp/policy-opa-pdp.sh b/test/config/opa-pdp/policy-opa-pdp.sh
new file mode 100755
index 0000000..7ed14cb
--- /dev/null
+++ b/test/config/opa-pdp/policy-opa-pdp.sh
@@ -0,0 +1,9 @@
+#!/bin/bash
+
+
+#Creation of Policies and Groups
+sh scripts.sh
+
+
+#Execution of OPA-PDP bin
+/app/opa-pdp
diff --git a/test/docker-compose.yml b/test/docker-compose.yml
new file mode 100644
index 0000000..6778882
--- /dev/null
+++ b/test/docker-compose.yml
@@ -0,0 +1,143 @@
+version: '3.8'
+services:
+   mariadb:
+      image: nexus3.onap.org:10001/mariadb:10.10.2
+      container_name: mariadb
+      hostname: mariadb
+      command: ['--lower-case-table-names=1', '--wait_timeout=28800', '--default-authentication-plugin=mysql_native_password']
+      env_file: ./config/db/db.conf
+      volumes:
+         - ./config/db:/docker-entrypoint-initdb.d
+         - ./config/clamp/policy-clamp-create-tables.sql:/tmp/policy-clamp-create-tables.sql
+      ports:
+       - "3306:3306"
+   policy-db-migrator:
+      image: nexus3.onap.org:10001/onap/policy-db-migrator:4.0.1-SNAPSHOT
+      container_name: policy-db-migrator
+      hostname: policy-db-migrator
+      depends_on:
+        - mariadb
+      expose:
+       - 6824
+      env_file: ./config/db/db.conf
+      environment:
+        SQL_DB: policyadmin
+        SQL_HOST: mariadb
+      volumes:
+         - ./config/db-migrator/init.sh:/opt/app/policy/bin/db_migrator_policy_init.sh:ro
+         - ./wait_for_port.sh:/tmp/wait_for_port.sh
+      entrypoint: sh /tmp/wait_for_port.sh
+      command: [
+              '-c',
+                '/opt/app/policy/bin/db_migrator_policy_init.sh',
+                'mariadb', '3306'
+               ]
+   api:
+      image: nexus3.onap.org:10001/onap/policy-api:4.0.1-SNAPSHOT
+      container_name: policy-api
+      depends_on:
+       - policy-db-migrator
+      hostname: policy-api
+      ports:
+       - 30002:6969
+      volumes:
+       - ./config/api/apiParameters.yaml:/opt/app/policy/api/etc/apiParameters.yaml:ro
+       - ./config/api/logback.xml:/opt/app/policy/api/etc/logback.xml:ro
+       - ./wait_for_port.sh:/opt/app/policy/api/bin/wait_for_port.sh
+      entrypoint: sh wait_for_port.sh
+      command: [
+        '-c', './policy-api.sh',
+        'mariadb', '3306',
+        'policy-db-migrator', '6824'
+        ]
+   pap:
+      image: nexus3.onap.org:10001/onap/policy-pap:4.0.1-SNAPSHOT
+      container_name: policy-pap
+      depends_on:
+       - mariadb
+       - kafka
+       - api
+      hostname: policy-pap
+      ports:
+       - 30003:6969
+      volumes:
+       - ./config/pap/papParameters.yaml:/opt/app/policy/pap/etc/papParameters.yaml:ro
+       - ./config/pap/groups.json:/opt/app/policy/pap/etc/mounted/groups.json:ro
+       - ./config/pap/logback.xml:/opt/app/policy/pap/etc/logback.xml:ro
+       - ./wait_for_port.sh:/opt/app/policy/pap/bin/wait_for_port.sh
+      entrypoint: sh wait_for_port.sh
+      command: [
+        '-c', './policy-pap.sh',
+        'mariadb', '3306',
+        'kafka', '9092',
+        'api', '6969'
+        ]
+   zookeeper:
+     image: confluentinc/cp-zookeeper:latest
+     environment:
+       ZOOKEEPER_CLIENT_PORT: 2181
+       ZOOKEEPER_TICK_TIME: 2000
+     ports:
+       - 2181:2181
+
+   pdp:
+      image: docker.io/opa-pdp:1.0.0
+      container_name: opa-pdp
+      depends_on:
+       - mariadb
+       - kafka
+       - api
+       - pap
+      hostname: opa-pdp
+      volumes:
+       - ./config/opa-pdp/config.json:/app/config/config.json:ro
+       - ./config/opa-pdp/groups.json:/app/groups.json:ro
+       - ./config/opa-pdp/policy-opa-pdp.sh:/app/policy-opa-pdp.sh:ro
+       - ./wait_for_port.sh:/app/wait_for_port.sh
+       - ./scripts.sh:/app/scripts.sh
+       - ./Opagroup.json:/app/Opagroup.json
+       - ./policy-new.yaml:/app/policy-new.yaml
+       - type: bind
+         source: ./policies
+         target: /app/policies 
+
+      environment:
+        LOG_LEVEL: debug
+        KAFKA_URL: "kafka:9092"
+        PAP_TOPIC: policy-pdp-pap
+        GROUPID: opa-pdp
+        API_USER: policyadmin
+        API_PASSWORD: "zb!XztG34"
+      entrypoint: sh wait_for_port.sh
+      command: [
+        '-c', './policy-opa-pdp.sh',
+        'mariadb', '3306',
+        'kafka', '9092',
+        'api', '6969',
+        'pap', '6969'
+        ]
+      ports:
+        - 8282:8282
+   zookeeper:
+     image: confluentinc/cp-zookeeper:latest
+     environment:
+       ZOOKEEPER_CLIENT_PORT: 2181
+       ZOOKEEPER_TICK_TIME: 2000
+     ports:
+       - 2181:2181
+   
+   kafka:
+     image: confluentinc/cp-kafka:latest
+     container_name: kafka
+     depends_on:
+       - zookeeper
+     ports:
+       - 29092:29092
+       - 9092:9092
+     environment:
+       KAFKA_BROKER_ID: 1
+       KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
+       KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka:9092,PLAINTEXT_HOST://localhost:29092
+       KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT
+       KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT
+       KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
diff --git a/test/policies/abac/policy.rego b/test/policies/abac/policy.rego
new file mode 100644
index 0000000..9dc6ea9
--- /dev/null
+++ b/test/policies/abac/policy.rego
@@ -0,0 +1,20 @@
+package abac
+
+import rego.v1
+
+default allow := false
+
+allow if {
+ viewable_sensor_data
+ action_is_read
+}
+
+action_is_read if "read" in input.actions
+
+viewable_sensor_data contains view_data if {
+ some sensor_data in data.abac.sensor_data
+ sensor_data.timestamp >= input.time_period.from
+ sensor_data.timestamp < input.time_period.to
+
+ view_data := {datatype: sensor_data[datatype] | datatype in input.datatypes}
+}
diff --git a/test/policies/account/policy.rego b/test/policies/account/policy.rego
new file mode 100644
index 0000000..f99e8eb
--- /dev/null
+++ b/test/policies/account/policy.rego
@@ -0,0 +1,17 @@
+package account
+
+import rego.v1
+
+default allow := false
+
+allow if {
+ creditor_is_valid
+ debtor_is_valid
+ period_is_valid
+ amount_is_valid
+}
+creditor_is_valid if data.account.account_attributes[input.creditor_account].owner == input.creditor
+debtor_is_valid if data.account.account_attributes[input.debtor_account].owner == input.debtor
+
+period_is_valid if input.period <= 30
+amount_is_valid if data.account.account_attributes[input.debtor_account].amount >= input.amount
diff --git a/test/policies/action/policy.rego b/test/policies/action/policy.rego
new file mode 100644
index 0000000..300fe50
--- /dev/null
+++ b/test/policies/action/policy.rego
@@ -0,0 +1,21 @@
+package action
+
+import rego.v1
+
+# By default, deny requests.
+default allow := false
+
+
+# Allow the action if admin role is granted permission to perform the action.
+allow if {
+    some i
+    data.action.user_roles[input.user][i] == role
+    some j
+    data.action.role_permissions[role].actions[j] == input.action
+    some k
+    data.action.role_permissions[role].resources[k] == input.type
+}
+#       * Rego comparison to other systems: https://www.openpolicyagent.org/docs/latest/comparison-to-other-systems/
+#       * Rego Iteration: https://www.openpolicyagent.org/docs/latest/#iteration
+
+
diff --git a/test/policies/data/abac/data.json b/test/policies/data/abac/data.json
new file mode 100644
index 0000000..77b5668
--- /dev/null
+++ b/test/policies/data/abac/data.json
@@ -0,0 +1,94 @@
+{
+    "sensor_data": [
+        {
+            "id": "0001",
+            "location": "Sri Lanka",
+            "temperature": "28 C",
+            "precipitation": "1000 mm",
+            "windspeed": "5.5 m/s",
+            "humidity": "40%",
+            "particle_density": "1.3 g/l",
+            "timestamp": "2024-02-26"
+        },
+        {
+            "id": "0002",
+            "location": "Colombo",
+            "temperature": "30 C",
+            "precipitation": "1200 mm",
+            "windspeed": "6.0 m/s",
+            "humidity": "45%",
+            "particle_density": "1.5 g/l",
+            "timestamp": "2024-02-26"
+        },
+        {
+            "id": "0003",
+            "location": "Kandy",
+            "temperature": "25 C",
+            "precipitation": "800 mm",
+            "windspeed": "4.5 m/s",
+            "humidity": "60%",
+            "particle_density": "1.1 g/l",
+            "timestamp": "2024-02-26"
+        },
+        {
+            "id": "0004",
+            "location": "Galle",
+            "temperature": "35 C",
+            "precipitation": "500 mm",
+            "windspeed": "7.2 m/s",
+            "humidity": "30%",
+            "particle_density": "1.8 g/l",
+            "timestamp": "2024-02-27"
+        },
+        {
+            "id": "0005",
+            "location": "Jaffna",
+            "temperature": "-5 C",
+            "precipitation": "300 mm",
+            "windspeed": "3.8 m/s",
+            "humidity": "20%",
+            "particle_density": "0.9 g/l",
+            "timestamp": "2024-02-27"
+        },
+        {
+            "id": "0006",
+            "location": "Trincomalee",
+            "temperature": "20 C",
+            "precipitation": "1000 mm",
+            "windspeed": "5.0 m/s",
+            "humidity": "55%",
+            "particle_density": "1.2 g/l",
+            "timestamp": "2024-02-28"
+        },
+        {
+            "id": "0007",
+            "location": "Nuwara Eliya",
+            "temperature": "25 C",
+            "precipitation": "600 mm",
+            "windspeed": "4.0 m/s",
+            "humidity": "50%",
+            "particle_density": "1.3 g/l",
+            "timestamp": "2024-02-28"
+        },
+        {
+            "id": "0008",
+            "location": "Anuradhapura",
+            "temperature": "28 C",
+            "precipitation": "700 mm",
+            "windspeed": "5.8 m/s",
+            "humidity": "40%",
+            "particle_density": "1.4 g/l",
+            "timestamp": "2024-02-29"
+        },
+        {
+            "id": "0009",
+            "location": "Matara",
+            "temperature": "32 C",
+            "precipitation": "900 mm",
+            "windspeed": "6.5 m/s",
+            "humidity": "65%",
+            "particle_density": "1.6 g/l",
+            "timestamp": "2024-02-29"
+        }
+    ]
+}
diff --git a/test/policies/data/account/data.json b/test/policies/data/account/data.json
new file mode 100644
index 0000000..df263d3
--- /dev/null
+++ b/test/policies/data/account/data.json
@@ -0,0 +1,16 @@
+{
+  "account_attributes":{
+    "11111":{
+      "owner":"alice",
+      "amount":10000
+    },
+    "22222":{
+      "owner":"bob",
+      "amount":10000
+    },
+    "33333":{
+      "owner":"cam",
+      "amount":10000
+    }
+  }
+}
diff --git a/test/policies/data/action/data.json b/test/policies/data/action/data.json
new file mode 100644
index 0000000..99145b7
--- /dev/null
+++ b/test/policies/data/action/data.json
@@ -0,0 +1,43 @@
+{
+    "user_roles": {
+        "alice": [
+            "admin"
+        ],
+        "bob": [
+            "editor"
+        ],
+        "charlie": [
+            "viewer"
+        ]
+    },
+    "role_permissions": {
+        "admin": {
+            "actions": [
+                "read",
+                "write",
+                "delete"
+            ],
+            "resources": [
+                "server",
+                "database"
+            ]
+        },
+        "editor": {
+            "actions": [
+                "read",
+                "write"
+            ],
+            "resources": [
+                "server"
+            ]
+        },
+        "viewer": {
+            "actions": [
+                "read"
+            ],
+            "resources": [
+                "server"
+            ]
+        }
+    }
+}
diff --git a/test/policies/data/organization/data.json b/test/policies/data/organization/data.json
new file mode 100644
index 0000000..35fe4a1
--- /dev/null
+++ b/test/policies/data/organization/data.json
@@ -0,0 +1,32 @@
+{
+    "acls": [
+        {
+            "user": "alice",
+            "actions": [
+                "edit",
+                "read"
+            ],
+            "component": "component_A",
+            "project": "project_A",
+            "organization": "org_A"
+        },
+        {
+            "user": "bob",
+            "actions": ["read"],
+            "organization": "org_A"
+        },
+        {
+            "user": "bob",
+            "action": ["edit"],
+            "component": "component_A",
+            "project": "project_B",
+            "organization": "org_A"
+        },
+        {
+            "user": "charlie",
+            "action": ["read"],
+            "project": "project_B",
+            "organization": "org_A"
+        }
+    ]
+}
diff --git a/test/policies/data/role/data.json b/test/policies/data/role/data.json
new file mode 100644
index 0000000..88ac41b
--- /dev/null
+++ b/test/policies/data/role/data.json
@@ -0,0 +1,63 @@
+{
+    "user_roles": {
+        "alice": [
+            "admin"
+        ],
+        "bob": [
+            "employee",
+            "billing"
+        ],
+        "eve": [
+            "customer"
+        ]
+    },
+    "role_grants": {
+        "customer": [
+            {
+                "action": "read",
+                "type": "dog"
+            },
+            {
+                "action": "read",
+                "type": "cat"
+            },
+            {
+                "action": "adopt",
+                "type": "dog"
+            },
+            {
+                "action": "adopt",
+                "type": "cat"
+            }
+        ],
+        "employee": [
+            {
+                "action": "read",
+                "type": "dog"
+            },
+            {
+                "action": "read",
+                "type": "cat"
+            },
+            {
+                "action": "update",
+                "type": "dog"
+            },
+            {
+                "action": "update",
+                "type": "cat"
+            }
+        ],
+        "billing": [
+            {
+                "action": "read",
+                "type": "finance"
+            },
+            {
+                "action": "update",
+                "type": "finance"
+            }
+        ]
+    }
+}
+
diff --git a/test/policies/example/policy.rego b/test/policies/example/policy.rego
new file mode 100644
index 0000000..cc19285
--- /dev/null
+++ b/test/policies/example/policy.rego
@@ -0,0 +1,13 @@
+package example
+
+import rego.v1
+
+allow if {
+        input.path == ["users"]
+        input.method == "POST"
+}
+
+allow if {
+        input.path == ["users", input.user_id]
+        input.method == "GET"
+}
diff --git a/test/policies/organization/policy.rego b/test/policies/organization/policy.rego
new file mode 100644
index 0000000..31e7fb6
--- /dev/null
+++ b/test/policies/organization/policy.rego
@@ -0,0 +1,38 @@
+package organization
+
+import rego.v1
+
+default allow := false
+
+# organization level access
+allow if {
+ some acl in data.organization.acls
+ acl.user == input.user
+ acl.organization == input.organization
+ acl.project == input.project
+ acl.component == input.component
+
+ some action in acl.actions
+ action == input.action
+}
+
+# project level access
+allow if {
+ some acl in data.organization.acls
+ acl.user == input.user
+ acl.organization == input.organization
+ acl.project == input.project
+
+ some action in acl.actions
+ action == input.action
+}
+
+# component level access
+allow if {
+ some acl in data.organization.acls
+ acl.user == input.user
+ acl.organization == input.organization
+
+ some action in acl.actions
+ action == input.action
+}
diff --git a/test/policies/role/policy.rego b/test/policies/role/policy.rego
new file mode 100644
index 0000000..54bdecf
--- /dev/null
+++ b/test/policies/role/policy.rego
@@ -0,0 +1,53 @@
+# Role-based Access Control (RBAC)
+# --------------------------------
+#
+# This example defines an RBAC model for a Pet Store API. The Pet Store API allows
+# users to look at pets, adopt them, update their stats, and so on. The policy
+# controls which users can perform actions on which resources. The policy implements
+# a classic Role-based Access Control model where users are assigned to roles and
+# roles are granted the ability to perform some action(s) on some type of resource.
+#
+# This example shows how to:
+#
+#	* Define an RBAC model in Rego that interprets role mappings represented in JSON.
+#	* Iterate/search across JSON data structures (e.g., role mappings)
+#
+# For more information see:
+#package app.rbac
+package role
+
+import rego.v1
+
+# By default, deny requests.
+default allow := false
+
+# Allow admins to do anything.
+allow if user_is_admin
+
+# Allow the action if the user is granted permission to perform the action.
+allow if {
+	# Find grants for the user.
+	some grant in user_is_granted
+
+	# Check if the grant permits the action.
+	input.action == grant.action
+	input.type == grant.type
+}
+
+# user_is_admin is true if "admin" is among the user's roles as per data.user_roles
+user_is_admin if "admin" in data.role.user_roles[input.user]
+
+# user_is_granted is a set of grants for the user identified in the request.
+# The `grant` will be contained if the set `user_is_granted` for every...
+user_is_granted contains grant if {
+	# `role` assigned an element of the user_roles for this user...
+	some role in data.role.user_roles[input.user]
+
+	# `grant` assigned a single grant from the grants list for 'role'...
+	some grant in data.role.role_grants[role]
+}
+
+#	* Rego comparison to other systems: https://www.openpolicyagent.org/docs/latest/comparison-to-other-systems/
+#	* Rego Iteration: https://www.openpolicyagent.org/docs/latest/#iteration
+
+
diff --git a/test/policy-new.yaml b/test/policy-new.yaml
new file mode 100644
index 0000000..2fbcf79
--- /dev/null
+++ b/test/policy-new.yaml
@@ -0,0 +1,21 @@
+tosca_definitions_version: tosca_simple_yaml_1_1_0
+policy_types:
+  onap.policies.Native:
+    derived_from: tosca.policies.Root
+    description: a base policy type for all native PDP policies
+    version: 1.0.0
+    name: onap.policies.Native
+  onap.policies.native.opa:
+    derived_from: onap.policies.Native
+    version: 1.0.0
+    name: onap.policies.native.opa
+    description: a policy type for native opa policies
+    properties:
+      policy:
+        type: string
+        type_version: 0.0.0
+        description: The rego PolicySet or Policy
+        required: true
+        metadata:
+          encoding: Base64
+
diff --git a/test/scripts.sh b/test/scripts.sh
new file mode 100755
index 0000000..ab4f838
--- /dev/null
+++ b/test/scripts.sh
@@ -0,0 +1,27 @@
+#!/bin/bash
+ 
+# Set up credentials and host variables
+USER="policyadmin"
+PASSWORD="zb!XztG34"
+HOST="localhost"
+ 
+# Exit immediately if a command exits with a non-zero status
+set -e
+ 
+# Step 1: Create a Policy
+echo "Creating a new policy..."
+sleep 40
+curl -u "$USER:$PASSWORD" --header "Content-Type: application/yaml" \
+     -X POST --data-binary @policy-new.yaml \
+     http://policy-api:6969/policy/api/v1/policytypes
+echo "Policy created successfully. Check policy-api logs for details."
+ 
+# Step 2: Create Groups
+echo "Creating groups..."
+curl -u "$USER:$PASSWORD" --header "Content-Type: application/json" \
+     -X POST --data-binary @Opagroup.json \
+     http://policy-pap:6969/policy/pap/v1/pdps/groups/batch
+ 
+echo "Groups created successfully. Check policy-pap logs for details."
+ 
+echo "Script execution completed."
diff --git a/test/scripts.txt b/test/scripts.txt
new file mode 100644
index 0000000..3d60d4a
--- /dev/null
+++ b/test/scripts.txt
@@ -0,0 +1,21 @@
+ curl -u 'policyadmin:zb!XztG34' --header "Content-Type:application/yaml"  -X POST --data-binary @policy-new.yaml http://localhost:30002/policy/api/v1/policytypes
+
+# policy-new.yaml is inside test directory to create policy 
+#check policy-api logs
+
+
+//Create Groups
+
+curl -u 'policyadmin:zb!XztG34' --header "Content-Type:application/json"  -X POST --data-binary  @Opagroup.json http://localhost:30003/policy/pap/v1/pdps/groups/batch
+
+#Check policy-pap logs
+#file Opagroup.json is inside test
+
+// Sends registration message to policy-pdp-pap
+
+docker exec -it kafka /bin/sh 
+
+echo '{"messageName": "PDP_STATUS", "requestId": "e9b4ee77-5400-41a8-87ba-3c914a86ee08", "timestampMs": "1728551661460","name": "opa-2e953ecf-40f1-47f7-8a5e-53031947516c","pdpGroup": "opaGroup","pdpSubgroup": null, "pdpType": "opa","state": "PASSIVE","healthy": "HEALTHY", "description": null, "policies": []}' |  kafka-console-producer --broker-list kafka:9092 --topic policy-pdp-pap
+
+
+#To get Gracefulshutdown signals commented command and changed entrypoint to /app/opa-pdp
diff --git a/test/wait_for_port.sh b/test/wait_for_port.sh
new file mode 100644
index 0000000..b29102b
--- /dev/null
+++ b/test/wait_for_port.sh
@@ -0,0 +1,91 @@
+#!/bin/sh
+# ============LICENSE_START====================================================
+#  Copyright (C) 2021 AT&T Intellectual Property. All rights reserved.
+#  Modifications Copyright (C) 2022-2023 Nordix Foundation.
+# =============================================================================
+# 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======================================================
+
+usage() {
+    echo args: [-t timeout] [-c command] hostname1 port1 hostname2 port2 ... >&2
+    exit 1
+}
+
+tmout=300
+cmd=
+while getopts c:t: opt
+do
+    case "$opt" in
+        c)
+            cmd="$OPTARG"
+            ;;
+
+        t)
+            tmout="$OPTARG"
+            ;;
+
+        *)
+            usage
+            ;;
+    esac
+done
+
+nargs=$((OPTIND-1))
+shift "$nargs"
+
+even_args=$(($#%2))
+if [ $# -lt 2 ] || [ "$even_args" -ne 0 ]
+then
+    usage
+fi
+
+while [ $# -ge 2 ]
+do
+    export host="$1"
+    export port="$2"
+    shift
+    shift
+
+    echo "Waiting for $host port $port..."
+
+    while [ "$tmout" -gt 0 ]
+    do
+        if command -v docker > /dev/null 2>&1
+        then
+            docker ps --format "table {{ .Names }}\t{{ .Status }}"
+        fi
+
+        nc -vz "$host" "$port"
+        rc=$?
+
+        if [ $rc -eq 0 ]
+        then
+            break
+        else
+            tmout=$((tmout-1))
+            sleep 1
+        fi
+    done
+
+    if [ $rc -ne 0 ]
+    then
+        echo "$host port $port cannot be reached"
+        exit $rc
+    fi
+done
+#sh scripts.sh
+$cmd
+
+exit 0
diff --git a/version b/version
new file mode 100644
index 0000000..3eefcb9
--- /dev/null
+++ b/version
@@ -0,0 +1 @@
+1.0.0