# Copy our opa executable from build stage
COPY --from=build /tmp/opa /app/opa
-RUN chmod +x /app/opa-pdp && chmod 755 /app/opa
+RUN chmod +x /app/opa-pdp && chmod 755 /app/opa && chmod 777 /app/bundles
# Switch to the non-root user and 1000 is for ubuntu
import (
"net/http"
"policy-opa-pdp/cfg"
- "policy-opa-pdp/pkg/bundleserver"
"policy-opa-pdp/pkg/data"
"policy-opa-pdp/pkg/decision"
"policy-opa-pdp/pkg/healthcheck"
opaDecisionHandler := http.HandlerFunc(decision.OpaDecision)
http.Handle("/policy/pdpo/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)
// -
// ========================LICENSE_START=================================
-// Copyright (C) 2024: Deutsche Telekom
+// Copyright (C) 2024-2025: Deutsche Telekom
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
"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"
statusCode int
}{
{"/policy/pdpo/v1/decision", decision.OpaDecision, http.StatusUnauthorized},
- {"/opa/bundles/", bundleserver.GetBundle, http.StatusInternalServerError},
{"/ready", readinessProbe, http.StatusOK},
{"/policy/pdpo/v1/healthcheck", healthcheck.HealthCheckHandler, http.StatusUnauthorized},
}
"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"
// Declare function variables for dependency injection makes it more testable
var (
initializeHandlersFunc = initializeHandlers
- initializeBundleFunc = initializeBundle
startHTTPServerFunc = startHTTPServer
shutdownHTTPServerFunc = shutdownHTTPServer
waitForServerFunc = waitForServer
// Initialize Handlers and Build Bundle
initializeHandlersFunc()
- if output, err := initializeBundleFunc(exec.Command); err != nil {
- log.Warnf("Output %s", string(output))
- log.Warnf("Failed to initialize bundle: %s", err)
- }
// Start HTTP Server
server := startHTTPServerFunc()
h.RegisterHandlers()
}
-// build bundle tar file
-func initializeBundle(execCmd func(string, ...string) *exec.Cmd) (string, error) {
- return bundleserver.BuildBundle(execCmd)
-}
-
func startHTTPServer() *http.Server {
//Configures the HTTP server to wait a maximum of 5 seconds for the headers of incoming requests
server := &http.Server{Addr: consts.ServerPort, ReadHeaderTimeout: 5 * time.Second}
"errors"
"net/http"
"os"
- "os/exec"
"policy-opa-pdp/consts"
"policy-opa-pdp/pkg/kafkacomm"
"policy-opa-pdp/pkg/kafkacomm/mocks"
log.Debug("Handlers initialized")
}
- // Mock initializeBundle
- initializeBundleFunc = func(cmdFn func(string, ...string) *exec.Cmd) (string, error) {
- return "", nil // no error expected
- }
-
// Use an actual *http.Server instance for testing
testServer := &http.Server{}
assert.True(t, true, "main function executed successfully")
}
-
-// Test to validate that the OPA bundle initialization process works as expected.
-func TestInitializeBundle(t *testing.T) {
- mockExecCmd := func(name string, arg ...string) *exec.Cmd {
- return exec.Command("echo")
- }
- output,err := initializeBundle(mockExecCmd)
- assert.NoError(t, err, output)
-}
-
// Test to verify that the HTTP server starts successfully.
func TestStartHTTPServer(t *testing.T) {
server := startHTTPServer()
}
-
-// Test to simulate a failure during OPA bundle initialization in the main function.
-func TestMain_InitializeBundleFailure(t *testing.T) {
- initializeBundleFunc = func(cmdFn func(string, ...string) *exec.Cmd) (string, error) {
- return "Bundle Initialization Error", errors.New("bundle initialization error") // Simulate error
- }
-
- done := make(chan struct{})
- go func() {
- main()
- close(done)
- }()
-
- select {
- case <-done:
- case <-time.After(1 * time.Second):
- t.Error("main function timed out on initializeBundleFunc failure")
- }
-}
-
// Test to simulate a Kafka initialization failure in the main function.
func TestMain_KafkaInitializationFailure(t *testing.T) {
startKafkaConsAndProdFunc = func() (*kafkacomm.KafkaConsumer, *kafkacomm.KafkaProducer, error) {
+++ /dev/null
-// -
-// ========================LICENSE_START=================================
-// Copyright (C) 2024-2025: 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.
-// SPDX-License-Identifier: Apache-2.0
-// ========================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) (string, 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 string(output), err
- }
- log.Debug("Bundle Built Sucessfully....")
- return string(output), nil
-}
+++ /dev/null
-// -
-// ========================LICENSE_START=================================
-// Copyright (C) 2024-2025: Deutsche Telekom
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-// SPDX-License-Identifier: Apache-2.0
-// ========================LICENSE_END===================================
-//
-
-package 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) {
- output, err := BuildBundle(mockCmd)
- if err != nil {
- t.Errorf("BuildBundle() error = %v, wantErr %v", err, output)
- }
-}
-
-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
- }
-
- output, err := BuildBundle(mockCmdFail)
- if err == nil {
- t.Errorf("BuildBundle() error = nil, wantErr %v", output)
- }
-}
"fmt"
"os/exec"
"policy-opa-pdp/consts"
- "policy-opa-pdp/pkg/bundleserver"
"policy-opa-pdp/pkg/kafkacomm/publisher"
"policy-opa-pdp/pkg/log"
"policy-opa-pdp/pkg/model"
// build bundle tar file
func createBundleFunc(execCmd func(string, ...string) *exec.Cmd, toscaPolicy model.ToscaPolicy) (string, error) {
- return bundleserver.BuildBundle(execCmd)
+ return utils.BuildBundle(execCmd)
}
func sendSuccessResponse(p publisher.PdpStatusSender, pdpUpdate *model.PdpUpdate, respMessage string) error {
"github.com/go-playground/validator/v10"
"github.com/google/uuid"
"os"
+ "os/exec"
"path/filepath"
+ "policy-opa-pdp/consts"
"policy-opa-pdp/pkg/log"
"policy-opa-pdp/pkg/model"
"regexp"
return true
}
}
+
+func BuildBundle(cmdFunc func(string, ...string) *exec.Cmd) (string, 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 string(output), err
+ }
+ log.Debug("Bundle Built Sucessfully....")
+ return string(output), nil
+}
"github.com/google/uuid"
"github.com/stretchr/testify/assert"
"os"
+ "os/exec"
"path/filepath"
"policy-opa-pdp/pkg/model"
"testing"
"time"
)
+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)
+}
+
// Positive Test Case: Valid UUIDs
func TestIsValidUUIDPositive(t *testing.T) {
// Define valid UUID strings
}
}
}
+
+func TestBuildBundle(t *testing.T) {
+ output, err := BuildBundle(mockCmd)
+ if err != nil {
+ t.Errorf("BuildBundle() error = %v, wantErr %v", err, output)
+ }
+}
+
+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
+ }
+
+ output, err := BuildBundle(mockCmdFail)
+ if err == nil {
+ t.Errorf("BuildBundle() error = nil, wantErr %v", output)
+ }
+}
"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
}
"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
}