From 0dd8af22a0eecc839f7920009a9c8ae9a564eb47 Mon Sep 17 00:00:00 2001 From: swetha1654 Date: Mon, 9 Feb 2026 12:23:39 +0530 Subject: [PATCH 1/4] Update issue and enhancement templates --- .github/ISSUE_TEMPLATE/bug_report.yml | 24 ++++++++++++++++--- .../ISSUE_TEMPLATE/enhancement_proposal.yml | 21 +++++++++++++++- 2 files changed, 41 insertions(+), 4 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 466be6c..3372cdf 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -1,6 +1,6 @@ name: Bug Report description: File a bug report -labels: ["Type: Bug", "Status: Triage"] +labels: ["bug"] body: - type: markdown attributes: @@ -16,6 +16,25 @@ body: If applicable, add screenshots to help explain the problem you are facing. validations: required: true + - type: dropdown + id: impact + attributes: + label: Impact + description: How severe is the business impact of this bug? + options: + - Low (minor issue or cosmetic problem) + - Medium (functionality degraded, workaround exists) + - High (major functionality broken, no workaround) + - Critical (system down, data loss, affecting deployment in production) + validations: + required: true + - type: textarea + id: impact-rationale + attributes: + label: Impact Rationale + description: > + If impact is high or critical, please provide the rationale behind your assessment, impacted + project reference and any relevant project deadline dates which will be affected by this bug. - type: textarea id: reproduction attributes: @@ -46,7 +65,7 @@ body: description: > Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks. Fetch the logs using `juju debug-log --replay` and `kubectl logs ...`. Additional details available in the juju docs - at https://juju.is/docs/olm/juju-logs + at https://documentation.ubuntu.com/juju/3.6/howto/manage-logs/#manage-logs render: shell validations: required: true @@ -54,4 +73,3 @@ body: id: additional-context attributes: label: Additional context - diff --git a/.github/ISSUE_TEMPLATE/enhancement_proposal.yml b/.github/ISSUE_TEMPLATE/enhancement_proposal.yml index b2348b9..df54155 100644 --- a/.github/ISSUE_TEMPLATE/enhancement_proposal.yml +++ b/.github/ISSUE_TEMPLATE/enhancement_proposal.yml @@ -1,6 +1,6 @@ name: Enhancement Proposal description: File an enhancement proposal -labels: ["Type: Enhancement", "Status: Triage"] +labels: ["enhancement"] body: - type: markdown attributes: @@ -15,3 +15,22 @@ body: Describe the enhancement you would like to see in as much detail as needed. validations: required: true + - type: dropdown + id: impact + attributes: + label: Impact + description: What is the impact of this feature? + options: + - Low (The feature is nice to have) + - Medium (The feature may be helpful in the future) + - High (The feature has short-term technical value) + - Critical (The feature has big short-term business value) + validations: + required: true + - type: textarea + id: impact-rationale + attributes: + label: Impact Rationale + description: > + If impact is high or critical, please provide the rationale behind your assessment with as + much context as possible. From 989b7b2aee1ca107e238af4ea1a561c8a967c9cb Mon Sep 17 00:00:00 2001 From: swetha1654 Date: Tue, 10 Feb 2026 10:35:53 +0530 Subject: [PATCH 2/4] fix lint and unit errors --- http-proxy-policy-operator/src/relay.py | 1 + .../tests/integration/any_charm.py | 4 +- .../tests/integration/conftest.py | 1 + .../tests/unit/test_charm.py | 29 ++++++++----- squid-forward-proxy-operator/src/squid.py | 24 ++++------- .../tests/integration/conftest.py | 1 + .../tests/unit/test_charm.py | 6 +-- .../tests/unit/test_http_proxy.py | 43 ++++++++++++------- 8 files changed, 61 insertions(+), 48 deletions(-) diff --git a/http-proxy-policy-operator/src/relay.py b/http-proxy-policy-operator/src/relay.py index f686c86..dc5152e 100644 --- a/http-proxy-policy-operator/src/relay.py +++ b/http-proxy-policy-operator/src/relay.py @@ -2,6 +2,7 @@ # See LICENSE file for licensing details. """HTTP proxy request relay.""" + import dataclasses import logging diff --git a/http-proxy-policy-operator/tests/integration/any_charm.py b/http-proxy-policy-operator/tests/integration/any_charm.py index 77c7eb3..8310f2c 100644 --- a/http-proxy-policy-operator/tests/integration/any_charm.py +++ b/http-proxy-policy-operator/tests/integration/any_charm.py @@ -5,6 +5,8 @@ """Integration test charm.""" +import secrets + import http_proxy from any_charm_base import AnyCharmBase @@ -36,7 +38,7 @@ def provide_proxy(self, _) -> None: request = proxy_requests.get(requirer) auth = request.auth[0] if http_proxy.AUTH_METHOD_USERPASS in auth: - user = {"username": "test", "password": "test"} + user = {"username": "test", "password": secrets.token_hex()} else: user = None responses.add_or_replace( diff --git a/http-proxy-policy-operator/tests/integration/conftest.py b/http-proxy-policy-operator/tests/integration/conftest.py index 1d5d752..744b82d 100644 --- a/http-proxy-policy-operator/tests/integration/conftest.py +++ b/http-proxy-policy-operator/tests/integration/conftest.py @@ -2,6 +2,7 @@ # See LICENSE file for licensing details. """Integration test charm fixtures.""" + import asyncio import json import os.path diff --git a/http-proxy-policy-operator/tests/unit/test_charm.py b/http-proxy-policy-operator/tests/unit/test_charm.py index 4c1c152..cf390ff 100644 --- a/http-proxy-policy-operator/tests/unit/test_charm.py +++ b/http-proxy-policy-operator/tests/unit/test_charm.py @@ -6,6 +6,7 @@ # pylint: disable=protected-access,line-too-long import json +import secrets import unittest.mock import uuid from typing import cast @@ -121,7 +122,7 @@ def test_reply_requests(mock_policy): "database": "http-proxy-policy", "endpoints": "postgresql.test:5432", "username": "postgres", - "password": "postgres", + "password": secrets.token_hex(), }, ) mock_policy.HttpProxyPolicyClient.refresh.return_value = EXAMPLE_EVALUATED_REQUESTS @@ -192,7 +193,9 @@ def test_relay_responses(mock_policy): }, ) mock_policy.HttpProxyPolicyClient.refresh.return_value = [EXAMPLE_EVALUATED_REQUESTS[0]] - backend_secret = ops.testing.Secret(tracked_content={"username": "test", "password": "test"}) + backend_secret = ops.testing.Secret( + tracked_content={"username": "test", "password": secrets.token_hex()} + ) backend_relation = ops.testing.Relation( endpoint="http-proxy-backend", remote_app_data={ @@ -216,7 +219,7 @@ def test_relay_responses(mock_policy): "database": "http-proxy-policy", "endpoints": "postgresql.test:5432", "username": "postgres", - "password": "postgres", + "password": secrets.token_hex(), }, ) state_in = ops.testing.State( @@ -277,7 +280,7 @@ def test_invalid_requests(mock_policy): "database": "http-proxy-policy", "endpoints": "postgresql.test:5432", "username": "postgres", - "password": "postgres", + "password": secrets.token_hex(), }, ) backend_relation = ops.testing.Relation( @@ -363,7 +366,7 @@ def test_unsupported_requests(mock_policy): # pylint: disable=unused-argument "database": "http-proxy-policy", "endpoints": "postgresql.test:5432", "username": "postgres", - "password": "postgres", + "password": secrets.token_hex(), }, ) backend_relation = ops.testing.Relation( @@ -422,7 +425,7 @@ def test_ignore_duplicate_requests(mock_policy): "database": "http-proxy-policy", "endpoints": "postgresql.test:5432", "username": "postgres", - "password": "postgres", + "password": secrets.token_hex(), }, ) backend_relation = ops.testing.Relation( @@ -469,7 +472,9 @@ def test_cleanup_responses(mock_policy): }, ) mock_policy.HttpProxyPolicyClient.refresh.return_value = [EXAMPLE_EVALUATED_REQUESTS[0]] - backend_secret = ops.testing.Secret(tracked_content={"username": "test", "password": "test"}) + backend_secret = ops.testing.Secret( + tracked_content={"username": "test", "password": secrets.token_hex()} + ) backend_relation = ops.testing.Relation( endpoint="http-proxy-backend", local_app_data={ @@ -504,7 +509,7 @@ def test_cleanup_responses(mock_policy): "database": "http-proxy-policy", "endpoints": "postgresql.test:5432", "username": "postgres", - "password": "postgres", + "password": secrets.token_hex(), }, ) state_in = ops.testing.State( @@ -547,7 +552,9 @@ def test_invalid_backend_response(mock_policy): }, ) mock_policy.HttpProxyPolicyClient.refresh.return_value = [EXAMPLE_EVALUATED_REQUESTS[0]] - backend_secret = ops.testing.Secret(tracked_content={"username": "test", "password": "test"}) + backend_secret = ops.testing.Secret( + tracked_content={"username": "test", "password": secrets.token_hex()} + ) backend_relation = ops.testing.Relation( endpoint="http-proxy-backend", remote_app_data={ @@ -560,7 +567,7 @@ def test_invalid_backend_response(mock_policy): "database": "http-proxy-policy", "endpoints": "postgresql.test:5432", "username": "postgres", - "password": "postgres", + "password": secrets.token_hex(), }, ) state_in = ops.testing.State( @@ -611,7 +618,7 @@ def test_missing_backend_relation(mock_policy): "database": "http-proxy-policy", "endpoints": "postgresql.test:5432", "username": "postgres", - "password": "postgres", + "password": secrets.token_hex(), }, ) state_in = ops.testing.State( diff --git a/squid-forward-proxy-operator/src/squid.py b/squid-forward-proxy-operator/src/squid.py index 500ff40..bdf170c 100644 --- a/squid-forward-proxy-operator/src/squid.py +++ b/squid-forward-proxy-operator/src/squid.py @@ -122,8 +122,7 @@ def generate_config(specs: list[HttpProxySpec], http_port: int = 3128) -> str: Squid configuration. """ buffer = [ - textwrap.dedent( - f"""\ + textwrap.dedent(f"""\ http_port {http_port} logfile_rotate 10000 @@ -131,8 +130,7 @@ def generate_config(specs: list[HttpProxySpec], http_port: int = 3128) -> str: auth_param basic credentialsttl 60 seconds cache deny all - """ - ), + """), *sorted( [ _generate_http_access_snippet( @@ -141,15 +139,13 @@ def generate_config(specs: list[HttpProxySpec], http_port: int = 3128) -> str: for spec in specs ] ), - textwrap.dedent( - """\ + textwrap.dedent("""\ access_log /var/log/squid/access.log squid http_access allow localhost manager http_access deny manager http_access deny all - """ - ), + """), ] return "\n".join(buffer) @@ -236,8 +232,7 @@ def install() -> None: # pragma: nocover apt.add_package( ["squid", "libcrypt1", "prometheus-squid-exporter", "logrotate"], update_cache=True ) - logrotate_config = textwrap.dedent( - """ + logrotate_config = textwrap.dedent(""" /var/log/squid/*.log { daily rotate 180 @@ -251,8 +246,7 @@ def install() -> None: # pragma: nocover test ! -e /run/squid.pid || test ! -x /usr/sbin/squid || /usr/sbin/squid -k rotate endscript } - """ - ) + """) _SQUID_LOGROTATE_CONFIG_PATH.write_text(logrotate_config, encoding="utf-8") @@ -354,11 +348,9 @@ def update_config_and_passwd( if old_passwd != new_passwd: write_passwd(new_passwd) reload() - exporter_config = textwrap.dedent( - f""" + exporter_config = textwrap.dedent(f""" ARGS="-squid-port {http_port} -listen 127.0.0.1:9301" - """ - ) + """) if exporter_config != read_exporter_config(): write_exporter_config(exporter_config) restart_exporter() diff --git a/squid-forward-proxy-operator/tests/integration/conftest.py b/squid-forward-proxy-operator/tests/integration/conftest.py index 799909c..ef171ab 100644 --- a/squid-forward-proxy-operator/tests/integration/conftest.py +++ b/squid-forward-proxy-operator/tests/integration/conftest.py @@ -2,6 +2,7 @@ # See LICENSE file for licensing details. """Integration test charm fixtures.""" + import asyncio import json import os.path diff --git a/squid-forward-proxy-operator/tests/unit/test_charm.py b/squid-forward-proxy-operator/tests/unit/test_charm.py index 03abe9c..e7e322d 100644 --- a/squid-forward-proxy-operator/tests/unit/test_charm.py +++ b/squid-forward-proxy-operator/tests/unit/test_charm.py @@ -44,8 +44,7 @@ def test_squid_charm_basic(mock_squid): relations=[integration, ops.testing.PeerRelation(endpoint="squid-peer")], ) state_out = ctx.run(ctx.on.config_changed(), state_in) - assert mock_squid.read_config() == textwrap.dedent( - """\ + assert mock_squid.read_config() == textwrap.dedent("""\ http_port 3128 logfile_rotate 10000 @@ -71,8 +70,7 @@ def test_squid_charm_basic(mock_squid): http_access allow localhost manager http_access deny manager http_access deny all - """ # noqa: E501 (line too long) - ) + """) # noqa: E501 (line too long) assert len(list(state_out.secrets)) == 1 secret = [ secret diff --git a/squid-forward-proxy-operator/tests/unit/test_http_proxy.py b/squid-forward-proxy-operator/tests/unit/test_http_proxy.py index 421f267..c5e6ac9 100644 --- a/squid-forward-proxy-operator/tests/unit/test_http_proxy.py +++ b/squid-forward-proxy-operator/tests/unit/test_http_proxy.py @@ -6,6 +6,7 @@ # pylint: disable=protected-access import json +import secrets import uuid import pydantic @@ -64,16 +65,16 @@ class PureHttpProxyResponseListReader(http_proxy._HttpProxyResponseListReader): # for test purpose only # pylint: disable=super-init-not-called - def __init__(self, data: dict | None = None, secrets: dict | None = None) -> None: + def __init__(self, data: dict | None = None, secrets_dict: dict | None = None) -> None: """Initialize the object. Args: data: integration data - secrets: juju secrets + secrets_dict: juju secrets """ self._integration_id = 123 self._integration_data = data or {} - self._test_secrets = secrets or {} + self._test_secrets = secrets_dict or {} self._responses: dict[str, dict] = {} self._load() @@ -87,16 +88,16 @@ class PureHttpProxyResponseListReadWriter(http_proxy._HttpProxyResponseListReadW # for test purpose only # pylint: disable=super-init-not-called - def __init__(self, data: dict | None = None, secrets: dict | None = None) -> None: + def __init__(self, data: dict | None = None, secrets_dict: dict | None = None) -> None: """Initialize the object. Args: data: integration data - secrets: juju secrets + secrets_dict: juju secrets """ self._integration_id = 123 self._integration_data = data or {} - self._test_secrets = secrets or {} + self._test_secrets = secrets_dict or {} self._responses: dict[str, dict] = {} self._load() @@ -628,7 +629,7 @@ def test_http_proxy_response_list_reader_validate_response(proxy_response): @pytest.mark.parametrize( - "proxy_response, parsed_response, secrets", + "proxy_response, parsed_response, secrets_dict", [ pytest.param( { @@ -680,19 +681,26 @@ def test_http_proxy_response_list_reader_validate_response(proxy_response): http_proxy="http://squid.internal:3128", user=http_proxy.HttpProxyUser(username="foo", password=pydantic.SecretStr("bar")), ), - {"secret:foobar": {"username": "foo", "password": "bar"}}, + { + "secret:foobar": { + "username": "foo", + "password": "bar", # nosec: hardcoded_password_string + } + }, id="ready with user", ), ], ) -def test_http_proxy_response_list_reader_get_response(proxy_response, parsed_response, secrets): +def test_http_proxy_response_list_reader_get_response( + proxy_response, parsed_response, secrets_dict +): """ arrange: none act: provide a http-proxy integration with HTTP proxy responses assert: the charm should get HTTP proxy responses from the integration """ reader = PureHttpProxyResponseListReader( - data={"responses": json.dumps([proxy_response])}, secrets=secrets + data={"responses": json.dumps([proxy_response])}, secrets_dict=secrets_dict ) assert reader.get("00000000-0000-4000-8000-000000000000") == parsed_response @@ -703,6 +711,7 @@ def test_http_proxy_response_list_reader_add_delete_response(): act: add an HTTP proxy response to the integration then delete it assert: data in the integration should reflect the change """ + test_password = secrets.token_hex() writer = PureHttpProxyResponseListReadWriter() writer.add( @@ -718,11 +727,11 @@ def test_http_proxy_response_list_reader_add_delete_response(): auth=http_proxy.AUTH_METHOD_USERPASS, https_proxy="http://squid.internal:3128", http_proxy="http://squid.internal:3128", - user={"username": "foo", "password": "bar"}, + user={"username": "foo", "password": test_password}, ) assert len(writer._test_secrets) == 1 secret_id = list(writer._test_secrets)[0] - assert writer._test_secrets[secret_id] == {"username": "foo", "password": "bar"} + assert writer._test_secrets[secret_id] == {"username": "foo", "password": test_password} assert json.loads(writer._integration_data["responses"]) == [ {"requirer": "00000000-0000-4000-8000-000000000000", "status": "pending"}, { @@ -759,6 +768,8 @@ def test_http_proxy_response_list_reader_update(): act: update an HTTP proxy response in the integration assert: data in the integration should reflect the change """ + test_password1 = secrets.token_hex() + test_password2 = secrets.token_hex() writer = PureHttpProxyResponseListReadWriter() writer.add( @@ -815,11 +826,11 @@ def test_http_proxy_response_list_reader_update(): writer.update( requirer_id="00000000-0000-4000-8000-000000000000", auth=http_proxy.AUTH_METHOD_USERPASS, - user={"username": "foo", "password": "bar"}, + user={"username": "foo", "password": test_password1}, ) assert len(writer._test_secrets) == 1 secret_id = list(writer._test_secrets)[0] - assert writer._test_secrets[secret_id] == {"username": "foo", "password": "bar"} + assert writer._test_secrets[secret_id] == {"username": "foo", "password": test_password1} assert json.loads(writer._integration_data["responses"]) == [ { "requirer": "00000000-0000-4000-8000-000000000000", @@ -833,9 +844,9 @@ def test_http_proxy_response_list_reader_update(): writer.update( requirer_id="00000000-0000-4000-8000-000000000000", - user={"username": "foobar", "password": "foobar"}, + user={"username": "foobar", "password": test_password2}, ) - assert writer._test_secrets[secret_id] == {"username": "foobar", "password": "foobar"} + assert writer._test_secrets[secret_id] == {"username": "foobar", "password": test_password2} assert json.loads(writer._integration_data["responses"]) == [ { "requirer": "00000000-0000-4000-8000-000000000000", From 75b3cd901b5700e9d3a2e3addb9f94f47934e322 Mon Sep 17 00:00:00 2001 From: swetha1654 Date: Tue, 10 Feb 2026 12:02:17 +0530 Subject: [PATCH 3/4] fix integration test --- http-proxy-policy-operator/tests/integration/any_charm.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/http-proxy-policy-operator/tests/integration/any_charm.py b/http-proxy-policy-operator/tests/integration/any_charm.py index 8310f2c..81963cd 100644 --- a/http-proxy-policy-operator/tests/integration/any_charm.py +++ b/http-proxy-policy-operator/tests/integration/any_charm.py @@ -38,7 +38,7 @@ def provide_proxy(self, _) -> None: request = proxy_requests.get(requirer) auth = request.auth[0] if http_proxy.AUTH_METHOD_USERPASS in auth: - user = {"username": "test", "password": secrets.token_hex()} + user = {"username": "test", "password": "test"} # nosec: hardcoded_password_string else: user = None responses.add_or_replace( From cad6a2f841dc2cd0aa29e287fb5d8a8aa18ab1d3 Mon Sep 17 00:00:00 2001 From: swetha1654 Date: Tue, 10 Feb 2026 12:02:30 +0530 Subject: [PATCH 4/4] fix integration test --- http-proxy-policy-operator/tests/integration/any_charm.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/http-proxy-policy-operator/tests/integration/any_charm.py b/http-proxy-policy-operator/tests/integration/any_charm.py index 81963cd..91a6721 100644 --- a/http-proxy-policy-operator/tests/integration/any_charm.py +++ b/http-proxy-policy-operator/tests/integration/any_charm.py @@ -5,8 +5,6 @@ """Integration test charm.""" -import secrets - import http_proxy from any_charm_base import AnyCharmBase