From 7bbc4232ff8dc51b5c7e562d2e45ba30a81f9e5d Mon Sep 17 00:00:00 2001 From: charlie4284 Date: Tue, 24 Mar 2026 20:53:01 +0800 Subject: [PATCH 01/20] fix: proxy env setup --- src/image.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/image.py b/src/image.py index ba82ccaa..5b387ae1 100644 --- a/src/image.py +++ b/src/image.py @@ -55,6 +55,7 @@ def _on_image_relation_joined(self, event: ops.RelationJoinedEvent) -> None: event: The event emitted when a relation is joined. """ build_config = state.BuilderConfig.from_charm(charm=self.charm) + self.charm._setup_proxy_environment(build_config.proxy) proxy = state.ProxyConfig.from_env() if not build_config.cloud_config.upload_cloud_ids: self.model.unit.status = ops.BlockedStatus( From 405fa53b687d1f5602f5181acd7a1b0091b3f074 Mon Sep 17 00:00:00 2001 From: charlie4284 Date: Tue, 24 Mar 2026 20:54:38 +0800 Subject: [PATCH 02/20] docs: changelog --- app/pyproject.toml | 2 +- docs/changelog.md | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/app/pyproject.toml b/app/pyproject.toml index 1deff3ce..099f9408 100644 --- a/app/pyproject.toml +++ b/app/pyproject.toml @@ -3,7 +3,7 @@ [project] name = "github-runner-image-builder" -version = "0.13.0" +version = "0.13.1" authors = [ { name = "Canonical IS DevOps", email = "is-devops-team@canonical.com" }, ] diff --git a/docs/changelog.md b/docs/changelog.md index d7356b48..4a695e7e 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -1,6 +1,9 @@ +## [#213 Fix proxy setup] +* Fix proxy setup for image-relation joined hook. + ## [#206 Add resolute image support] * Add resolute image support. From c69e40ba869a5a04b00e7ee6d3cf8b2adc221409 Mon Sep 17 00:00:00 2001 From: charlie4284 Date: Mon, 13 Apr 2026 13:35:41 +0800 Subject: [PATCH 03/20] revert: version bump, no app changes made --- app/pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/pyproject.toml b/app/pyproject.toml index 099f9408..1deff3ce 100644 --- a/app/pyproject.toml +++ b/app/pyproject.toml @@ -3,7 +3,7 @@ [project] name = "github-runner-image-builder" -version = "0.13.1" +version = "0.13.0" authors = [ { name = "Canonical IS DevOps", email = "is-devops-team@canonical.com" }, ] From 5ab568e7288b11a2099f84749c7d90f98b11adb4 Mon Sep 17 00:00:00 2001 From: charlie4284 Date: Mon, 13 Apr 2026 13:39:21 +0800 Subject: [PATCH 04/20] fix(logging): remove encoding kwarg from basicConfig to fix mypy type error The typeshed stubs for logging.basicConfig don't include the encoding parameter in the handlers overload. The encoding is already set on the WatchedFileHandler itself (line 22), so passing it again to basicConfig is redundant and causes a mypy call-overload error. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- app/src/github_runner_image_builder/logging.py | 1 - 1 file changed, 1 deletion(-) diff --git a/app/src/github_runner_image_builder/logging.py b/app/src/github_runner_image_builder/logging.py index 771da30e..b3fa134c 100644 --- a/app/src/github_runner_image_builder/logging.py +++ b/app/src/github_runner_image_builder/logging.py @@ -27,5 +27,4 @@ def configure(log_level: str | int) -> None: logging.basicConfig( level=log_level_normalized, handlers=(log_handler,), - encoding="utf-8", ) From ab2830eed5629f03e82e2cade000d49029b35799 Mon Sep 17 00:00:00 2001 From: charlie4284 Date: Mon, 13 Apr 2026 13:55:31 +0800 Subject: [PATCH 05/20] test(image): fix test__on_image_relation_joined mock setup for proxy The PR added _setup_proxy_environment() in _on_image_relation_joined. The test was using a plain MagicMock() for BuilderConfig.from_charm, causing build_config.proxy to be a MagicMock. When passed to _setup_proxy_environment, assigning it to os.environ raises TypeError. Fix: return a mock config with proxy=None so the proxy setup is skipped. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- tests/unit/test_image.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/unit/test_image.py b/tests/unit/test_image.py index b072da07..f91110f4 100644 --- a/tests/unit/test_image.py +++ b/tests/unit/test_image.py @@ -77,7 +77,11 @@ def test__on_image_relation_joined( act: when _on_image_relation_joined hook is fired. assert: update_relation_data is called. """ - monkeypatch.setattr(state.BuilderConfig, "from_charm", MagicMock()) + mock_build_config = MagicMock() + mock_build_config.proxy = None + monkeypatch.setattr( + state.BuilderConfig, "from_charm", MagicMock(return_value=mock_build_config) + ) monkeypatch.setattr(state.CloudsAuthConfig, "from_unit_relation_data", MagicMock()) monkeypatch.setattr(builder, "install_clouds_yaml", MagicMock()) monkeypatch.setattr(builder, "get_latest_images", MagicMock(return_value="test-id")) From 5cf5aee12200fbccf78c67b0e1cd5ba363527665 Mon Sep 17 00:00:00 2001 From: charlie4284 Date: Mon, 13 Apr 2026 14:00:27 +0800 Subject: [PATCH 06/20] fix(image): type-annotate Observer charm as concrete type for mypy The Observer stored self.charm typed as ops.CharmBase, but called _setup_proxy_environment which is defined on GithubRunnerImageBuilderCharm. Use TYPE_CHECKING to import the concrete type and annotate the constructor parameter correctly, resolving the attr-defined mypy error. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/image.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/image.py b/src/image.py index 5b387ae1..85b460e5 100644 --- a/src/image.py +++ b/src/image.py @@ -6,7 +6,7 @@ import json import logging from collections import defaultdict -from typing import Mapping, TypedDict, cast +from typing import TYPE_CHECKING, Mapping, TypedDict, cast import ops @@ -14,6 +14,9 @@ import charm_utils import state +if TYPE_CHECKING: + from charm import GithubRunnerImageBuilderCharm + logger = logging.getLogger(__name__) @@ -34,7 +37,7 @@ class ImageRelationData(TypedDict, total=False): class Observer(ops.Object): """The image relation observer.""" - def __init__(self, charm: ops.CharmBase): + def __init__(self, charm: "GithubRunnerImageBuilderCharm"): """Initialize the observer and register event handlers. Args: From f05badd7d1a6af21e0ce92085cb2c491b9c4b6f5 Mon Sep 17 00:00:00 2001 From: charlie4284 Date: Mon, 13 Apr 2026 14:04:15 +0800 Subject: [PATCH 07/20] refactor(charm): rename _setup_proxy_environment to setup_proxy_environment The method is called from image.Observer (outside the charm class), so it should be public. Renamed from _setup_proxy_environment to setup_proxy_environment to avoid the pylint protected-access warning. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/charm.py | 12 ++++++------ src/image.py | 2 +- tests/unit/test_charm.py | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/charm.py b/src/charm.py index cdecae48..3ecddb83 100755 --- a/src/charm.py +++ b/src/charm.py @@ -102,7 +102,7 @@ def _on_upgrade_charm(self, _: ops.UpgradeCharmEvent) -> None: def _on_config_changed(self, _: ops.ConfigChangedEvent) -> None: """Handle charm configuration change events.""" builder_config_state = state.BuilderConfig.from_charm(charm=self) - self._setup_proxy_environment(builder_config_state.proxy) + self.setup_proxy_environment(builder_config_state.proxy) if not self._is_any_image_relation_ready(cloud_config=builder_config_state.cloud_config): return # The following lines should be covered by integration tests. @@ -119,7 +119,7 @@ def _on_config_changed(self, _: ops.ConfigChangedEvent) -> None: def _on_image_relation_changed(self, evt: ops.RelationChangedEvent) -> None: """Handle charm image relation changed event.""" builder_config_state = state.BuilderConfig.from_charm(charm=self) - self._setup_proxy_environment(builder_config_state.proxy) + self.setup_proxy_environment(builder_config_state.proxy) if not evt.unit: logger.info("No unit in image relation changed event. Skipping image building.") return @@ -158,7 +158,7 @@ def _on_image_relation_changed(self, evt: ops.RelationChangedEvent) -> None: def _on_run(self, _: RunEvent) -> None: """Handle the run event.""" builder_config_state = state.BuilderConfig.from_charm(charm=self) - self._setup_proxy_environment(builder_config_state.proxy) + self.setup_proxy_environment(builder_config_state.proxy) if not self._is_any_image_relation_ready(cloud_config=builder_config_state.cloud_config): return # The following line should be covered by the integration test. @@ -172,14 +172,14 @@ def _on_run_action(self, event: ops.ActionEvent) -> None: event: The run action event. """ builder_config_state = state.BuilderConfig.from_charm(charm=self) - self._setup_proxy_environment(builder_config_state.proxy) + self.setup_proxy_environment(builder_config_state.proxy) if not self._is_any_image_relation_ready(cloud_config=builder_config_state.cloud_config): event.fail("Image relation not yet ready.") return # The following line should be covered by the integration test. self._run() # pragma: nocover - def _setup_proxy_environment(self, proxy_config: state.ProxyConfig | None) -> None: + def setup_proxy_environment(self, proxy_config: state.ProxyConfig | None) -> None: """Set up proxy environment variables. Args: @@ -197,7 +197,7 @@ def _setup_builder(self) -> None: """Set up the builder application.""" builder_config_state = state.BuilderConfig.from_charm(charm=self) - self._setup_proxy_environment(builder_config_state.proxy) + self.setup_proxy_environment(builder_config_state.proxy) builder.initialize( app_init_config=builder.ApplicationInitializationConfig( diff --git a/src/image.py b/src/image.py index 85b460e5..57011999 100644 --- a/src/image.py +++ b/src/image.py @@ -58,7 +58,7 @@ def _on_image_relation_joined(self, event: ops.RelationJoinedEvent) -> None: event: The event emitted when a relation is joined. """ build_config = state.BuilderConfig.from_charm(charm=self.charm) - self.charm._setup_proxy_environment(build_config.proxy) + self.charm.setup_proxy_environment(build_config.proxy) proxy = state.ProxyConfig.from_env() if not build_config.cloud_config.upload_cloud_ids: self.model.unit.status = ops.BlockedStatus( diff --git a/tests/unit/test_charm.py b/tests/unit/test_charm.py index 67117818..18d2a12a 100644 --- a/tests/unit/test_charm.py +++ b/tests/unit/test_charm.py @@ -325,7 +325,7 @@ def test_setup_proxy_environment_with_proxy_config( no_proxy="localhost,127.0.0.1", ) - charm._setup_proxy_environment(proxy_config) + charm.setup_proxy_environment(proxy_config) assert os.environ["http_proxy"] == "http://proxy.example.com:8080" assert os.environ["https_proxy"] == "https://proxy.example.com:8443" From 2765abf526a162fee789e9f420dc6a4d139b3160 Mon Sep 17 00:00:00 2001 From: charlie4284 Date: Mon, 13 Apr 2026 19:18:56 +0800 Subject: [PATCH 08/20] ci: trigger ci From b8a9c94e9a97bbd1688e9cbbfa3a77857001d8ea Mon Sep 17 00:00:00 2001 From: charlie4284 Date: Mon, 13 Apr 2026 19:31:19 +0800 Subject: [PATCH 09/20] ci: integration test to fix branch --- .github/workflows/integration_test.yaml | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/.github/workflows/integration_test.yaml b/.github/workflows/integration_test.yaml index 801904c7..54d58f97 100644 --- a/.github/workflows/integration_test.yaml +++ b/.github/workflows/integration_test.yaml @@ -3,17 +3,16 @@ name: Integration tests on: pull_request: schedule: - - cron: "0 15 * * SAT" + - cron: "0 15 * * SAT" concurrency: - group: ${{ github.workflow }}-${{ github.event.pull_request.number || + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} cancel-in-progress: true jobs: integration-tests: - uses: - canonical/operator-workflows/.github/workflows/integration_test.yaml@main + uses: canonical/operator-workflows/.github/workflows/integration_test.yaml@fix/pipx-deps secrets: inherit with: juju-channel: 3.6/stable @@ -28,5 +27,5 @@ jobs: allure-report: if: ${{ !cancelled() && github.event_name == 'schedule' }} needs: - - integration-tests + - integration-tests uses: canonical/operator-workflows/.github/workflows/allure_report.yaml@main From 79dc7519acec5123b9cd0cd83a64870abee63c19 Mon Sep 17 00:00:00 2001 From: charlie4284 Date: Mon, 13 Apr 2026 19:47:35 +0800 Subject: [PATCH 10/20] ci: debug --- .github/workflows/integration_test.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/integration_test.yaml b/.github/workflows/integration_test.yaml index 54d58f97..d84494ef 100644 --- a/.github/workflows/integration_test.yaml +++ b/.github/workflows/integration_test.yaml @@ -24,6 +24,8 @@ jobs: builder-runner-label: X64 pre-run-script: | -c "./tests/integration/aproxy_prerouting_workaround.sh" + tmate-debug: true + tmate-timeout: 90 allure-report: if: ${{ !cancelled() && github.event_name == 'schedule' }} needs: From 52fb6416f0ee0db4a90735c9ce730434bbd99b2f Mon Sep 17 00:00:00 2001 From: charlie4284 Date: Mon, 13 Apr 2026 23:09:26 +0800 Subject: [PATCH 11/20] test: use forked get-workflow-version-action --- .github/workflows/integration_test.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/integration_test.yaml b/.github/workflows/integration_test.yaml index d84494ef..daaf5c1b 100644 --- a/.github/workflows/integration_test.yaml +++ b/.github/workflows/integration_test.yaml @@ -12,7 +12,7 @@ concurrency: jobs: integration-tests: - uses: canonical/operator-workflows/.github/workflows/integration_test.yaml@fix/pipx-deps + uses: canonical/operator-workflows/.github/workflows/integration_test.yaml@test/get-workflow-version-action secrets: inherit with: juju-channel: 3.6/stable From 1d18aa96e596da2a655245c9d2544c6080a21778 Mon Sep 17 00:00:00 2001 From: charlie4284 Date: Mon, 13 Apr 2026 23:14:31 +0800 Subject: [PATCH 12/20] ci: trigger ci From 266735dccc7e62249ef3ef71250b330c2823d281 Mon Sep 17 00:00:00 2001 From: charlie4284 Date: Mon, 13 Apr 2026 23:16:09 +0800 Subject: [PATCH 13/20] chore: remove debug --- .github/workflows/integration_test.yaml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/integration_test.yaml b/.github/workflows/integration_test.yaml index daaf5c1b..780a93fc 100644 --- a/.github/workflows/integration_test.yaml +++ b/.github/workflows/integration_test.yaml @@ -24,8 +24,6 @@ jobs: builder-runner-label: X64 pre-run-script: | -c "./tests/integration/aproxy_prerouting_workaround.sh" - tmate-debug: true - tmate-timeout: 90 allure-report: if: ${{ !cancelled() && github.event_name == 'schedule' }} needs: From a4337f74251ac261d63451ed46f61c27fb7e60ac Mon Sep 17 00:00:00 2001 From: charlie4284 Date: Mon, 13 Apr 2026 23:20:21 +0800 Subject: [PATCH 14/20] ci: trigger ci From d10e8a8af87dd1ea1bdc9d0378220d3c17804531 Mon Sep 17 00:00:00 2001 From: charlie4284 Date: Mon, 13 Apr 2026 23:53:23 +0800 Subject: [PATCH 15/20] ci: trigger ci From 568960b08930dcb09a74fe7a4f3e3edacc158af9 Mon Sep 17 00:00:00 2001 From: charlie4284 Date: Mon, 13 Apr 2026 23:56:12 +0800 Subject: [PATCH 16/20] trigger From 152b21b22da3001a89cf48c3e1baf40887894da8 Mon Sep 17 00:00:00 2001 From: charlie4284 Date: Tue, 14 Apr 2026 00:13:55 +0800 Subject: [PATCH 17/20] trigger From 58553ed31ec3145f56c9e1fe1af4a4c52522573f Mon Sep 17 00:00:00 2001 From: charlie4284 Date: Tue, 14 Apr 2026 10:57:19 +0800 Subject: [PATCH 18/20] ci: debug --- .github/workflows/integration_test.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/integration_test.yaml b/.github/workflows/integration_test.yaml index 780a93fc..daaf5c1b 100644 --- a/.github/workflows/integration_test.yaml +++ b/.github/workflows/integration_test.yaml @@ -24,6 +24,8 @@ jobs: builder-runner-label: X64 pre-run-script: | -c "./tests/integration/aproxy_prerouting_workaround.sh" + tmate-debug: true + tmate-timeout: 90 allure-report: if: ${{ !cancelled() && github.event_name == 'schedule' }} needs: From f375f13290d7a0118d47fdf8bbf8dec61b495a62 Mon Sep 17 00:00:00 2001 From: charlie4284 Date: Tue, 14 Apr 2026 11:41:00 +0800 Subject: [PATCH 19/20] debug: try juju 4.0/stable (3.6 buggy) --- .github/workflows/integration_test.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/integration_test.yaml b/.github/workflows/integration_test.yaml index daaf5c1b..905dc629 100644 --- a/.github/workflows/integration_test.yaml +++ b/.github/workflows/integration_test.yaml @@ -15,7 +15,7 @@ jobs: uses: canonical/operator-workflows/.github/workflows/integration_test.yaml@test/get-workflow-version-action secrets: inherit with: - juju-channel: 3.6/stable + juju-channel: 4.0/stable provider: lxd modules: '["test_charm", "test_upgrade"]' self-hosted-runner: true From d0284622dba2dc5bfe4a4328349fb8f50ddbe1c1 Mon Sep 17 00:00:00 2001 From: charlie4284 Date: Thu, 16 Apr 2026 10:12:00 +0800 Subject: [PATCH 20/20] chore: revert juju channel & debug --- .github/workflows/integration_test.yaml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/integration_test.yaml b/.github/workflows/integration_test.yaml index 905dc629..780a93fc 100644 --- a/.github/workflows/integration_test.yaml +++ b/.github/workflows/integration_test.yaml @@ -15,7 +15,7 @@ jobs: uses: canonical/operator-workflows/.github/workflows/integration_test.yaml@test/get-workflow-version-action secrets: inherit with: - juju-channel: 4.0/stable + juju-channel: 3.6/stable provider: lxd modules: '["test_charm", "test_upgrade"]' self-hosted-runner: true @@ -24,8 +24,6 @@ jobs: builder-runner-label: X64 pre-run-script: | -c "./tests/integration/aproxy_prerouting_workaround.sh" - tmate-debug: true - tmate-timeout: 90 allure-report: if: ${{ !cancelled() && github.event_name == 'schedule' }} needs: