From 5770ef6cb14cd1abbc66090bdc510737c208c306 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kara=20=F0=9F=90=95?= <45862012+kara-kiss@users.noreply.github.com> Date: Wed, 22 Oct 2025 09:59:31 +0100 Subject: [PATCH 1/6] Updated Github Actions to run on staging branches (#56) --- .github/workflows/python-app.yml | 4 ++-- SECURITY.md | 17 +++++++++++++++++ 2 files changed, 19 insertions(+), 2 deletions(-) create mode 100644 SECURITY.md diff --git a/.github/workflows/python-app.yml b/.github/workflows/python-app.yml index d2c9b20..15e739a 100644 --- a/.github/workflows/python-app.yml +++ b/.github/workflows/python-app.yml @@ -2,9 +2,9 @@ name: Pylint and Pytest on: push: - branches: [ "main", "mtls-staging" ] + branches: [ "main", "*-staging" ] pull_request: - branches: [ "main", "mtls-staging" ] + branches: [ "main", "*-staging" ] permissions: contents: read diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..ed28bfb --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,17 @@ +# Security Policy + +## Supported Versions + +Only the latest release version of _python-sample-app_ is supported by security +updates. + +| Version | Supported | +| ---------------- | ------------------ | +| Latest Release | :white_check_mark: | +| Earlier Releases | :x: | + +## Reporting a Vulnerability + +If you find a vulnerability in _python-sample-app_, please report it as a security +vulnerability on GitHub: + From c004b8eb1572c14393943d538c4b2adb0b2443ed Mon Sep 17 00:00:00 2001 From: surendarraju Date: Wed, 22 Oct 2025 14:21:26 +0100 Subject: [PATCH 2/6] Added changes for independent namespace (#55) * Added changes for independent namespace * Modified the values for namespace field * Updated the default values of helm variables * Added a comment in values.yaml for user --- .../templates/network-policy/network-policy.yaml | 3 +++ charts/eric-oss-hello-world-python-app/values.yaml | 9 +++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/charts/eric-oss-hello-world-python-app/templates/network-policy/network-policy.yaml b/charts/eric-oss-hello-world-python-app/templates/network-policy/network-policy.yaml index 6dc9da5..6b6fa2e 100644 --- a/charts/eric-oss-hello-world-python-app/templates/network-policy/network-policy.yaml +++ b/charts/eric-oss-hello-world-python-app/templates/network-policy/network-policy.yaml @@ -24,6 +24,9 @@ spec: - podSelector: matchLabels: app: eric-pm-server + - namespaceSelector: + matchLabels: + kubernetes.io/metadata.name: {{ .Values.eic.namespace }} ports: - protocol: TCP port: {{ index .Values.service "http-port" }} diff --git a/charts/eric-oss-hello-world-python-app/values.yaml b/charts/eric-oss-hello-world-python-app/values.yaml index 112f0a7..81fe1fe 100644 --- a/charts/eric-oss-hello-world-python-app/values.yaml +++ b/charts/eric-oss-hello-world-python-app/values.yaml @@ -130,8 +130,13 @@ instantiationDefaults: proxyCaCertMountPath: "/etc/certs/ca" proxyAppCertMountPath: "/etc/certs/app" +# Below variables values are populated by App Manager automatically + global: clientCredentials: secret: - clientIdKey: "clientId" - name: "-cc" + clientIdKey: + name: + +eic: + namespace: From 997e5cfae116b2a1f47415b6975821e09be76161 Mon Sep 17 00:00:00 2001 From: surendarraju Date: Fri, 14 Nov 2025 14:01:37 +0000 Subject: [PATCH 3/6] Added changes to support mTLS metrics from pre-created namespace (#58) --- .../templates/configmap/envoy-configmap.yaml | 8 ++++---- .../templates/deployment/deployment.yaml | 5 +++-- .../templates/network-policy/network-policy.yaml | 1 - 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/charts/eric-oss-hello-world-python-app/templates/configmap/envoy-configmap.yaml b/charts/eric-oss-hello-world-python-app/templates/configmap/envoy-configmap.yaml index ead96c9..422deac 100644 --- a/charts/eric-oss-hello-world-python-app/templates/configmap/envoy-configmap.yaml +++ b/charts/eric-oss-hello-world-python-app/templates/configmap/envoy-configmap.yaml @@ -35,6 +35,10 @@ data: path: "/sample-app/python/hello" route: cluster: eric-oss-hello-world-python-app-cluster + - match: + path: "/sample-app/python/metrics" + route: + cluster: eric-oss-hello-world-python-app-cluster http_filters: - name: envoy.filters.http.router typed_config: @@ -74,10 +78,6 @@ data: path: "/sample-app/python/health" route: cluster: eric-oss-hello-world-python-app-cluster - - match: - path: "/sample-app/python/metrics" - route: - cluster: eric-oss-hello-world-python-app-cluster http_filters: - name: envoy.filters.http.router typed_config: diff --git a/charts/eric-oss-hello-world-python-app/templates/deployment/deployment.yaml b/charts/eric-oss-hello-world-python-app/templates/deployment/deployment.yaml index e4523a8..6dc21cd 100644 --- a/charts/eric-oss-hello-world-python-app/templates/deployment/deployment.yaml +++ b/charts/eric-oss-hello-world-python-app/templates/deployment/deployment.yaml @@ -29,17 +29,18 @@ spec: template: metadata: labels: + rapp-name: {{ include "eric-oss-hello-world-python-app.name" . }} app: {{ include "eric-oss-hello-world-python-app.name" . }} app.kubernetes.io/name: {{ include "eric-oss-hello-world-python-app.name" . }} app.kubernetes.io/version: {{ include "eric-oss-hello-world-python-app.version" . }} helm.sh/chart: {{ template "eric-oss-hello-world-python-app.chart" . }} app.kubernetes.io/instance: {{ .Release.Name }} - service.cleartext/scraping: "true" + rapp.metrics/scraping: "true" annotations: {{- if not (semverCompare ">=1.30.0" .Capabilities.KubeVersion.GitVersion) }} container.apparmor.security.beta.kubernetes.io/eric-oss-hello-world-python-app: {{ include "eric-oss-hello-world-python-app.appArmorProfileAnnotation" . | default "runtime/default" }} {{- end }} - prometheus.io/port: '{{ index .Values.service "http-port" }}' + prometheus.io/port: '{{ index .Values.service "https-port" }}' prometheus.io/scrape: "{{ .Values.prometheus.scrape }}" prometheus.io/path: "{{ .Values.prometheus.path }}" {{- include "eric-oss-hello-world-python-app.product-info" . | indent 8 }} diff --git a/charts/eric-oss-hello-world-python-app/templates/network-policy/network-policy.yaml b/charts/eric-oss-hello-world-python-app/templates/network-policy/network-policy.yaml index 6b6fa2e..6a38f6a 100644 --- a/charts/eric-oss-hello-world-python-app/templates/network-policy/network-policy.yaml +++ b/charts/eric-oss-hello-world-python-app/templates/network-policy/network-policy.yaml @@ -32,4 +32,3 @@ spec: port: {{ index .Values.service "http-port" }} - protocol: TCP port: {{ index .Values.service "https-port" }} - From 5801b61f6a372d47a5e8113ddc4c18ae2f5c1588 Mon Sep 17 00:00:00 2001 From: Darren O'Neill Date: Fri, 21 Nov 2025 10:19:15 +0000 Subject: [PATCH 4/6] Merge main into independent-ns-staging (#62) * Added SECURITY.md - how to report vulns. (#50) Added SECURITY.md following examples of other Ericsson repositories on Github. Co-authored-by: Neil Grogan * Removed eric-eo-api-gateway from network-policy.yaml * Renamed IAM_BASE_URL to EIC_HOST_URL (#59) Renaming all instances of Iam Base Url to Eic Host Url. * Removed unused environmental variables (#61) * Removed unused environmental variables * Modified testcases and the config file * Reverted test files * Removed unused testcase Signed-off-by: erjxsrn * Removed unused code --------- Signed-off-by: erjxsrn --------- Signed-off-by: erjxsrn Co-authored-by: Neil Grogan Co-authored-by: Neil Grogan Co-authored-by: ekievin Co-authored-by: surendarraju --- .../templates/deployment/deployment.yaml | 8 ++------ .../network-policy/network-policy.yaml | 3 --- eric-oss-hello-world-python-app/config.py | 8 ++------ eric-oss-hello-world-python-app/login.py | 2 +- .../tests/conftest.py | 19 +++---------------- .../tests/test_login.py | 2 +- 6 files changed, 9 insertions(+), 33 deletions(-) diff --git a/charts/eric-oss-hello-world-python-app/templates/deployment/deployment.yaml b/charts/eric-oss-hello-world-python-app/templates/deployment/deployment.yaml index 6dc21cd..3c12629 100644 --- a/charts/eric-oss-hello-world-python-app/templates/deployment/deployment.yaml +++ b/charts/eric-oss-hello-world-python-app/templates/deployment/deployment.yaml @@ -112,12 +112,8 @@ spec: mountPath: {{ index .Values "clientCredsMountPath" | default .Values.instantiationDefaults.clientCredsMountPath | quote }} readOnly: true env: - - name: IAM_CLIENT_ID - value: {{ index .Values "clientId" | quote }} - - name: IAM_CLIENT_SECRET - value: {{ index .Values "clientSecret" | quote }} - - name: IAM_BASE_URL - value: {{ index .Values "iamBaseUrl" | quote }} + - name: EIC_HOST_URL + value: {{ index .Values "eicHostUrl" | quote }} - name: LOG_ENDPOINT value: {{ index .Values "logEndpoint" | quote }} - name: CA_CERT_FILE_PATH diff --git a/charts/eric-oss-hello-world-python-app/templates/network-policy/network-policy.yaml b/charts/eric-oss-hello-world-python-app/templates/network-policy/network-policy.yaml index 6a38f6a..aff7150 100644 --- a/charts/eric-oss-hello-world-python-app/templates/network-policy/network-policy.yaml +++ b/charts/eric-oss-hello-world-python-app/templates/network-policy/network-policy.yaml @@ -15,9 +15,6 @@ spec: app: eric-oss-hello-world-python-app ingress: - from: - - podSelector: - matchLabels: - app: eric-eo-api-gateway - podSelector: matchLabels: app: eric-sef-exposure-api-gateway diff --git a/eric-oss-hello-world-python-app/config.py b/eric-oss-hello-world-python-app/config.py index 28266c4..39a7e9a 100644 --- a/eric-oss-hello-world-python-app/config.py +++ b/eric-oss-hello-world-python-app/config.py @@ -5,9 +5,7 @@ def get_config(): """get env and return config with all env vals required""" - iam_client_id = get_os_env_string("IAM_CLIENT_ID", "") - iam_client_secret = get_os_env_string("IAM_CLIENT_SECRET", "") - iam_base_url = get_os_env_string("IAM_BASE_URL", "") + eic_host_url = get_os_env_string("EIC_HOST_URL", "") ca_cert_file_name = get_os_env_string("CA_CERT_FILE_NAME", "") ca_cert_file_path = get_os_env_string("CA_CERT_FILE_PATH", "") log_ctrl_file = get_os_env_string("LOG_CTRL_FILE", "") @@ -19,9 +17,7 @@ def get_config(): client_id_file_name = get_os_env_string("CLIENT_ID_FILE_NAME", "") config = { - "iam_client_id": iam_client_id, - "iam_client_secret": iam_client_secret, - "iam_base_url": iam_base_url, + "eic_host_url": eic_host_url, "ca_cert_file_name": ca_cert_file_name, "ca_cert_file_path": ca_cert_file_path, "log_ctrl_file": log_ctrl_file, diff --git a/eric-oss-hello-world-python-app/login.py b/eric-oss-hello-world-python-app/login.py index 9e100a7..4cbfe07 100644 --- a/eric-oss-hello-world-python-app/login.py +++ b/eric-oss-hello-world-python-app/login.py @@ -22,7 +22,7 @@ def login(): """ config = get_config() login_path = "/auth/realms/master/protocol/openid-connect/token" - login_url = urljoin(config.get("iam_base_url"), login_path) + login_url = urljoin(config.get("eic_host_url"), login_path) headers = {"Content-Type": "application/x-www-form-urlencoded"} resp = tls_login(login_url, headers) resp = json.loads(resp.decode("utf-8")) diff --git a/eric-oss-hello-world-python-app/tests/conftest.py b/eric-oss-hello-world-python-app/tests/conftest.py index 28eb8fb..d0b60bb 100644 --- a/eric-oss-hello-world-python-app/tests/conftest.py +++ b/eric-oss-hello-world-python-app/tests/conftest.py @@ -31,24 +31,13 @@ def match_request_data(request): ] ] ) - uses_legacy = all( - [ - parameter in request.text - for parameter in [ - "grant_type=client_credentials", - "tenant_id=master", - "client_id=IAM_CLIENT_ID", - "client_secret=IAM_CLIENT_SECRET", - ] - ] - ) - return uses_x509 or uses_legacy + return uses_x509 @pytest.fixture(name="mock_login_api") def fixture_mock_login_api(config): login_endpoint = urljoin( - config.get("iam_base_url"), "/auth/realms/master/protocol/openid-connect/token" + config.get("eic_host_url"), "/auth/realms/master/protocol/openid-connect/token" ) with requests_mock.Mocker() as request_mocker: request_mocker.post( @@ -109,9 +98,7 @@ def no_log_certs(): def populate_environment_variables(): - os.environ["IAM_CLIENT_ID"] = "IAM_CLIENT_ID" - os.environ["IAM_CLIENT_SECRET"] = "IAM_CLIENT_SECRET" - os.environ["IAM_BASE_URL"] = "https://www.iam-base-url.com" + os.environ["EIC_HOST_URL"] = "https://www.eic-host-url.com" os.environ["CA_CERT_FILE_NAME"] = "CA_CERT_FILE_NAME" os.environ["CA_CERT_FILE_PATH"] = "CA_CERT_MOUNT_PATH" os.environ["LOG_ENDPOINT"] = "LOG_ENDPOINT" diff --git a/eric-oss-hello-world-python-app/tests/test_login.py b/eric-oss-hello-world-python-app/tests/test_login.py index be0a91d..7f23bee 100644 --- a/eric-oss-hello-world-python-app/tests/test_login.py +++ b/eric-oss-hello-world-python-app/tests/test_login.py @@ -15,7 +15,7 @@ def test_login_receives_token_x509(mock_login_api, config): def test_login_bad_credentials(requests_mock, config): """Ensure we get an error if credentials are bad""" login_url = urljoin( - config.get("iam_base_url"), "/auth/realms/master/protocol/openid-connect/token" + config.get("eic_host_url"), "/auth/realms/master/protocol/openid-connect/token" ) requests_mock.post( login_url, status_code=400, json={"error": "invalid_request"} From ba8ee95e1e7cf106c57d16b1768cbcb734a8fa92 Mon Sep 17 00:00:00 2001 From: surendarraju Date: Fri, 21 Nov 2025 15:10:41 +0000 Subject: [PATCH 5/6] Updated the variable name of helm parameters (#64) --- .../templates/network-policy/network-policy.yaml | 2 +- charts/eric-oss-hello-world-python-app/values.yaml | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/charts/eric-oss-hello-world-python-app/templates/network-policy/network-policy.yaml b/charts/eric-oss-hello-world-python-app/templates/network-policy/network-policy.yaml index aff7150..1f85c57 100644 --- a/charts/eric-oss-hello-world-python-app/templates/network-policy/network-policy.yaml +++ b/charts/eric-oss-hello-world-python-app/templates/network-policy/network-policy.yaml @@ -23,7 +23,7 @@ spec: app: eric-pm-server - namespaceSelector: matchLabels: - kubernetes.io/metadata.name: {{ .Values.eic.namespace }} + kubernetes.io/metadata.name: {{ .Values.global.platform.namespace }} ports: - protocol: TCP port: {{ index .Values.service "http-port" }} diff --git a/charts/eric-oss-hello-world-python-app/values.yaml b/charts/eric-oss-hello-world-python-app/values.yaml index 81fe1fe..56577ee 100644 --- a/charts/eric-oss-hello-world-python-app/values.yaml +++ b/charts/eric-oss-hello-world-python-app/values.yaml @@ -137,6 +137,5 @@ global: secret: clientIdKey: name: - -eic: - namespace: + platform: + namespace: From 52b4e15246f11eb77f420cdbcfc99157bd31f4cb Mon Sep 17 00:00:00 2001 From: Darren O'Neill Date: Mon, 24 Nov 2025 12:40:51 +0000 Subject: [PATCH 6/6] Include metadata.namespace as field in logging payload (#63) * Include metadata.namespace as field in logging payload Update NAMESPACE in deployment.yaml to be more explicit as APP_NAMESPACE Signed-off-by: don2112e * removed unnecessary comment Signed-off-by: don2112e * consolidated mock config into conftest.py --------- Signed-off-by: don2112e --- .../templates/deployment/deployment.yaml | 2 +- eric-oss-hello-world-python-app/config.py | 2 ++ .../mtls_logging.py | 1 + .../tests/conftest.py | 7 +++++ .../tests/test_mtls_logging.py | 30 ++++++++++--------- 5 files changed, 27 insertions(+), 15 deletions(-) diff --git a/charts/eric-oss-hello-world-python-app/templates/deployment/deployment.yaml b/charts/eric-oss-hello-world-python-app/templates/deployment/deployment.yaml index 3c12629..1f19933 100644 --- a/charts/eric-oss-hello-world-python-app/templates/deployment/deployment.yaml +++ b/charts/eric-oss-hello-world-python-app/templates/deployment/deployment.yaml @@ -146,7 +146,7 @@ spec: valueFrom: fieldRef: fieldPath: metadata.uid - - name: NAMESPACE + - name: APP_NAMESPACE valueFrom: fieldRef: fieldPath: metadata.namespace diff --git a/eric-oss-hello-world-python-app/config.py b/eric-oss-hello-world-python-app/config.py index 39a7e9a..149f477 100644 --- a/eric-oss-hello-world-python-app/config.py +++ b/eric-oss-hello-world-python-app/config.py @@ -15,6 +15,7 @@ def get_config(): app_cert_file_path = get_os_env_string("APP_CERT_FILE_PATH", "") client_creds_file_path = get_os_env_string("CLIENT_CREDS_FILE_PATH", "") client_id_file_name = get_os_env_string("CLIENT_ID_FILE_NAME", "") + app_namespace = get_os_env_string("APP_NAMESPACE", "") config = { "eic_host_url": eic_host_url, @@ -28,6 +29,7 @@ def get_config(): "client_creds_file_path": client_creds_file_path, "client_id_file_name": client_id_file_name, "chosen_unique_name": "eric-oss-hello-world-python-app", + "app_namespace": app_namespace, } return config diff --git a/eric-oss-hello-world-python-app/mtls_logging.py b/eric-oss-hello-world-python-app/mtls_logging.py index 36cc3a6..cdd7755 100644 --- a/eric-oss-hello-world-python-app/mtls_logging.py +++ b/eric-oss-hello-world-python-app/mtls_logging.py @@ -76,6 +76,7 @@ def log(self, message, severity): "message": message, "service_id": "rapp-" + self.config.get("chosen_unique_name"), "severity": severity.name.lower(), + "metadata": {"namespace": self.config.get("app_namespace")}, } # print to console diff --git a/eric-oss-hello-world-python-app/tests/conftest.py b/eric-oss-hello-world-python-app/tests/conftest.py index d0b60bb..3f82471 100644 --- a/eric-oss-hello-world-python-app/tests/conftest.py +++ b/eric-oss-hello-world-python-app/tests/conftest.py @@ -96,6 +96,12 @@ def no_log_certs(): populate_environment_variables() +@pytest.fixture(name="with_log_ctrl_file") +def with_log_ctrl_file(): + log_ctrl_config = get_config() + log_ctrl_config["log_ctrl_file"] = "/dummy/path/logcontrol.json" + return log_ctrl_config + def populate_environment_variables(): os.environ["EIC_HOST_URL"] = "https://www.eic-host-url.com" @@ -107,3 +113,4 @@ def populate_environment_variables(): os.environ["APP_CERT_FILE_PATH"] = "APP_CERT_FILE_PATH" os.environ["CLIENT_CREDS_FILE_PATH"] = os.path.relpath(os.path.dirname(__file__), "/") os.environ["CLIENT_ID_FILE_NAME"] = "client_id_example" + os.environ["APP_NAMESPACE"] = "test-namespace" \ No newline at end of file diff --git a/eric-oss-hello-world-python-app/tests/test_mtls_logging.py b/eric-oss-hello-world-python-app/tests/test_mtls_logging.py index 4b9b623..fcb5e2d 100644 --- a/eric-oss-hello-world-python-app/tests/test_mtls_logging.py +++ b/eric-oss-hello-world-python-app/tests/test_mtls_logging.py @@ -6,6 +6,7 @@ from mtls_logging import MtlsLogging, Severity + def test_log_stdout_and_mtls(caplog): """Ensure any log is sent both to STDOUT and through HTTPS""" message = "Message which should appear in both STDOUT and sent as a POST request" @@ -80,7 +81,7 @@ def test_log_handles_missing_schema(caplog): assert "Request failed for mTLS logging: Missing schema" in caplog.text -def test_init_sets_log_level_from_log_ctrl_file(): +def test_init_sets_log_level_from_log_ctrl_file(with_log_ctrl_file): # Sample log control file contents with container mapping log_ctrl_data = [ {"container": "test-container", "severity": "critical"}, @@ -88,22 +89,23 @@ def test_init_sets_log_level_from_log_ctrl_file(): ] log_ctrl_json = json.dumps(log_ctrl_data) - # Mocked config dict including the log_ctrl_file path - mock_config = { - "log_ctrl_file": "/dummy/path/logcontrol.json", - "ca_cert_file_name": "ca.pem", - "ca_cert_file_path": "certs", - "app_cert": "appcert.pem", - "app_key": "appkey.pem", - "app_cert_file_path": "certs", - "log_endpoint": "log.endpoint", - "chosen_unique_name": "eric-oss-hello-world-python-app" - } - # Patch config and environment variable - with mock.patch("mtls_logging.get_config", return_value=mock_config), \ + with mock.patch("mtls_logging.get_config", return_value=with_log_ctrl_file), \ mock.patch("mtls_logging.get_os_env_string", return_value="test-container"), \ mock.patch("builtins.open", mock.mock_open(read_data=log_ctrl_json)): logger = MtlsLogging(level=None) assert logger.logger.level == Severity.CRITICAL + + +def test_namespace_is_set_in_mtls_log(config): + """Ensure the namespace is set in the mTLS log""" + message = "Message that should be included in a request payload that includes the namespace" + + with mock.patch("mtls_logging.get_config", return_value=config): + mock_post = with_mocked_post(send_log, message, Severity.INFO, Severity.INFO) + mock_post.assert_called() + + request_body_object = mock_post.call_args.kwargs.get('json') + + assert request_body_object['metadata']['namespace'] == 'test-namespace'