Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
c88df24
Support proxy values
swetha1654 Jan 20, 2026
5ca542c
static errors
swetha1654 Jan 20, 2026
209479e
fix static and lint issues
swetha1654 Jan 20, 2026
903ce2f
fix static and lint inside app
swetha1654 Jan 20, 2026
72d8d3f
abort on fail
swetha1654 Jan 20, 2026
26b2965
add changelog
swetha1654 Jan 20, 2026
3f37f58
vale error
swetha1654 Jan 20, 2026
4860270
delete chain and run integ tests
swetha1654 Jan 27, 2026
f74433b
chore(deps): update dependency openstacksdk to v4.9.0 (#184)
renovate[bot] Jan 22, 2026
83fffe4
chore: update charm libraries (#177)
github-actions[bot] Jan 22, 2026
9e8f934
Merge branch 'main' into ISD-3652-aproxy2
swetha1654 Jan 27, 2026
e49a597
Update src/builder.py
swetha1654 Jan 27, 2026
d901d07
remove pyproject update
swetha1654 Jan 27, 2026
ad07dc9
address code review
swetha1654 Feb 5, 2026
7cb4485
remove tesT
swetha1654 Feb 5, 2026
1d7a529
test
swetha1654 Feb 6, 2026
7ef5451
update prerouting chain
swetha1654 Feb 10, 2026
417b9ef
fix script
swetha1654 Feb 10, 2026
08d10b4
fix script
swetha1654 Feb 10, 2026
1e68b2a
update builder initializer
swetha1654 Feb 10, 2026
efbadff
remove all code
swetha1654 Feb 10, 2026
a89fbdb
remove code
swetha1654 Feb 10, 2026
47c6b97
remove code
swetha1654 Feb 10, 2026
b804d34
setup proxy env for all hooks
swetha1654 Feb 10, 2026
b57f7ae
fix lint issues
swetha1654 Feb 10, 2026
2f7a6f2
Merge branch 'main' into ISD-3652-aproxy2
swetha1654 Feb 10, 2026
40db4e1
remove lint
swetha1654 Feb 10, 2026
60cd863
add more logs
swetha1654 Feb 10, 2026
130b7f7
remove randomly added code
swetha1654 Feb 10, 2026
cc9f619
lint issues
swetha1654 Feb 10, 2026
d3befa1
disable noproxy and check
swetha1654 Feb 11, 2026
608545b
experiment with no proxy
swetha1654 Feb 11, 2026
51761f9
debug
swetha1654 Feb 12, 2026
ca7e35e
debug
swetha1654 Feb 12, 2026
210216d
debug
swetha1654 Feb 12, 2026
2cb34b4
remove integration test
swetha1654 Feb 17, 2026
5c7ec25
chore(deps): update all non-major dependencies (#190)
renovate[bot] Feb 13, 2026
960d6b3
feat: otel-collector snap (#195)
swetha1654 Feb 17, 2026
cc5d29b
Merge branch 'main' into ISD-3652-aproxy2
swetha1654 Feb 17, 2026
51782dc
address review comments
swetha1654 Feb 17, 2026
cac7063
fix unit test
swetha1654 Feb 17, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion app/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

[project]
name = "github-runner-image-builder"
version = "0.12.0"
version = "0.12.1"
authors = [
{ name = "Canonical IS DevOps", email = "is-devops-team@canonical.com" },
]
Expand Down
1 change: 0 additions & 1 deletion app/tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@

"""Fixtures for github runner image builder app."""


from pytest import Parser


Expand Down
1 change: 1 addition & 0 deletions app/tests/integration/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
# See LICENSE file for licensing details.

"""Fixtures for github runner image builder integration tests."""

import logging
import os
import secrets
Expand Down
6 changes: 2 additions & 4 deletions app/tests/integration/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -382,8 +382,7 @@ def setup_aproxy(ssh_connection: SSHConnection, proxy: str) -> None:
proxy: The hostname and port in the format of "hostname:port".
"""
ssh_connection.run(f"/usr/bin/sudo snap set aproxy proxy={proxy} listen=:8444")
ssh_connection.run(
"""/usr/bin/sudo nft -f - << EOF
ssh_connection.run("""/usr/bin/sudo nft -f - << EOF
define default-ip = $(ip route get $(ip route show 0.0.0.0/0 | grep -oP 'via \\K\\S+') \
| grep -oP 'src \\K\\S+')
define private-ips = { 10.0.0.0/8, 127.0.0.1/8, 172.16.0.0/12, 192.168.0.0/16 }
Expand All @@ -400,8 +399,7 @@ def setup_aproxy(ssh_connection: SSHConnection, proxy: str) -> None:
}
}
EOF
"""
)
""")
# Wait for aproxy to become active.
for _ in range(6):
time.sleep(5)
Expand Down
4 changes: 2 additions & 2 deletions app/tests/integration/test_openstack_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,8 +120,8 @@ def image_ids_fixture(
script_config=config.ScriptConfig(
script_url=urllib.parse.urlparse(TESTDATA_TEST_SCRIPT_URL),
script_secrets={
"TEST_SECRET": "SHOULD_EXIST",
"TEST_NON_SECRET": "SHOULD_NOT_EXIST",
"TEST_SECRET": "SHOULD_EXIST", # nosec: hardcoded_password_string
"TEST_NON_SECRET": "SHOULD_NOT_EXIST", # nosec: hardcoded_password_string
},
),
),
Expand Down
1 change: 1 addition & 0 deletions app/tests/unit/test_logging.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
# See LICENSE file for licensing details.

"""Unit tests for logging module."""

import logging as logging_module
from pathlib import Path
from unittest.mock import MagicMock
Expand Down
23 changes: 18 additions & 5 deletions app/tests/unit/test_openstack_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,11 @@ def test_run(
if with_external_script
else None
),
script_secrets={"TEST_SECRET_ONE": "HELLO"} if with_external_script else {},
script_secrets=(
({"TEST_SECRET_ONE": "HELLO"}) # nosec: hardcoded_password_string
if with_external_script
else {}
),
Comment thread
swetha1654 marked this conversation as resolved.
),
)

Expand Down Expand Up @@ -694,7 +698,10 @@ def test__generate_cloud_init_script(
name="test-image",
script_config=openstack_builder.config.ScriptConfig(
script_url=urllib.parse.urlparse("https://test-url.com/script.sh"),
script_secrets={"TEST_SECRET_ONE": "HELLO", "TEST_SECRET_TWO": "WORLD"},
script_secrets={
"TEST_SECRET_ONE": "HELLO", # nosec: hardcoded_password_string
"TEST_SECRET_TWO": "WORLD", # nosec: hardcoded_password_string
},
),
),
proxy="test.proxy.internal:3128",
Expand Down Expand Up @@ -948,9 +955,15 @@ def test__wait_for_cloud_init_complete():
@pytest.mark.parametrize(
"script_secrets",
[
pytest.param({"TEST_SECRET_ONE": "HELLO"}, id="single secret"),
pytest.param(
{"TEST_SECRET_ONE": "HELLO", "TEST_SECRET_TWO": "WORLD"}, id="multiple secrets"
{"TEST_SECRET_ONE": "HELLO"}, id="single secret" # nosec: hardcoded_password_string
),
pytest.param(
{
"TEST_SECRET_ONE": "HELLO", # nosec: hardcoded_password_string
"TEST_SECRET_TWO": "WORLD", # nosec: hardcoded_password_string
},
id="multiple secrets",
),
pytest.param({}, id="no secrets"),
],
Expand Down Expand Up @@ -1011,7 +1024,7 @@ def run_side_effect(*_, **__):
with pytest.raises(ExternalScriptError) as exc:
openstack_builder._execute_external_script(
script_url="https://test-url.com/script.sh",
script_secrets={"TEST_SECRET_ONE": "HELLO"},
script_secrets={"TEST_SECRET_ONE": "HELLO"}, # nosec: hardcoded_password_string
ssh_conn=mock_connection,
)
assert "Unexpected exit code" in str(exc)
Expand Down
3 changes: 3 additions & 0 deletions docs/changelog.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@

<!-- vale Canonical.007-Headings-sentence-case = NO -->

## [#185 Remove aproxy installation and add proxy support in workload](https://github.com/canonical/github-runner-image-builder-operator/pull/185) (2026-01-20)
* Remove `aproxy` snap installation in the charm and inject proxy values from the model config into the workload process.

## [#172 feat: apt upgrade](https://github.com/canonical/github-runner-image-builder-operator/pull/172) (2025-11-26)
* Apply apt-update and apt-upgrade to GH runner images by applying them during cloud-init.

Expand Down
49 changes: 45 additions & 4 deletions src/builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@
OPENSTACK_CLOUDS_YAML_PATH = UBUNTU_HOME / "clouds.yaml"

# Bandit thinks this is a hardcoded secret
IMAGE_BUILDER_SECRET_PREFIX = "IMAGE_BUILDER_SECRET_" # nosec: B105
IMAGE_BUILDER_SECRET_PREFIX = "IMAGE_BUILDER_SECRET_" # nosec: hardcoded_password_string


@dataclasses.dataclass
Expand Down Expand Up @@ -348,10 +348,10 @@ class ExternalServiceConfig:
"""Builder run external service dependencies.

Attributes:
proxy: The proxy to use to build the image.
proxy: The proxy configuration to use to build the image.
"""

proxy: str | None
proxy: state.ProxyConfig | None


@dataclasses.dataclass
Expand Down Expand Up @@ -515,7 +515,11 @@ def _run(config: RunConfig) -> list[CloudImage]:
script_secrets=config.image.script_config.script_secrets,
),
service_options=_ServiceOptions(
proxy=config.external_service.proxy,
proxy=(
config.external_service.proxy.http or config.external_service.proxy.https
if config.external_service.proxy
else None
),
),
)
logger.info("Run build command: %s", run_command)
Expand All @@ -528,6 +532,7 @@ def _run(config: RunConfig) -> list[CloudImage]:
env={
"HOME": str(UBUNTU_HOME),
**_transform_secrets(secrets=config.image.script_config.script_secrets),
**_get_proxy_env(proxy=config.external_service.proxy),
},
Comment thread
swetha1654 marked this conversation as resolved.
)
# The return value of the CLI is "Image build success:\n<comma-separated-image-ids>"
Expand Down Expand Up @@ -571,6 +576,42 @@ def _transform_secrets(secrets: dict[str, str] | None) -> dict[str, str]:
)


def _get_proxy_env(proxy: state.ProxyConfig | None) -> dict[str, str]:
"""Transform proxy config to standard environment variables.
Comment thread
swetha1654 marked this conversation as resolved.
Outdated

Args:
proxy: The proxy configuration.

Returns:
Dictionary of proxy environment variables.
"""
if not proxy:
return {}
env_vars = {}
if proxy.http:
env_vars.update(
{
"http_proxy": proxy.http,
"HTTP_PROXY": proxy.http,
}
)
if proxy.https:
env_vars.update(
{
"https_proxy": proxy.https,
"HTTPS_PROXY": proxy.https,
}
)
if proxy.no_proxy:
env_vars.update(
{
"no_proxy": proxy.no_proxy,
"NO_PROXY": proxy.no_proxy,
}
)
return env_vars


@dataclasses.dataclass
class _RunArgs:
"""Builder application run arguments.
Expand Down
13 changes: 4 additions & 9 deletions src/charm.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
# See LICENSE file for licensing details.

"""Entrypoint for GithubRunnerImageBuilder charm."""

import json
import logging

Expand All @@ -21,7 +22,6 @@
import builder
import charm_utils
import image
import proxy
import state

LOG_FILE_DIR = Path("/var/log/github-runner-image-builder")
Expand Down Expand Up @@ -104,7 +104,6 @@ def _on_config_changed(self, _: ops.ConfigChangedEvent) -> None:
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.
proxy.configure_aproxy(proxy=state.ProxyConfig.from_env()) # pragma: no cover
builder.install_clouds_yaml( # pragma: no cover
cloud_config=builder_config_state.cloud_config.openstack_clouds_config
)
Expand All @@ -131,7 +130,6 @@ def _on_image_relation_changed(self, evt: ops.RelationChangedEvent) -> None:
evt.unit.name,
)
return
proxy.configure_aproxy(proxy=state.ProxyConfig.from_env())
builder.install_clouds_yaml(
cloud_config=builder_config_state.cloud_config.openstack_clouds_config
)
Expand Down Expand Up @@ -178,7 +176,6 @@ def _on_run_action(self, event: ops.ActionEvent) -> None:

def _setup_builder(self) -> None:
"""Set up the builder application."""
proxy.setup(proxy=state.ProxyConfig.from_env())
builder_config_state = state.BuilderConfig.from_charm(charm=self)
builder.initialize(
app_init_config=builder.ApplicationInitializationConfig(
Expand All @@ -193,17 +190,15 @@ def _setup_builder(self) -> None:
def _setup_logrotate(self) -> None:
"""Set up the log rotation for image-builder application."""
APP_LOGROTATE_CONFIG_PATH.write_text(
dedent(
f"""\
dedent(f"""\
{str(LOG_FILE_PATH.absolute())} {{
weekly
rotate 3
compress
delaycompress
missingok
}}
"""
),
"""),
encoding="utf-8",
)
try:
Expand Down Expand Up @@ -322,7 +317,7 @@ def _get_static_config(self, builder_config: state.BuilderConfig) -> builder.Sta
runner_version=builder_config.image_config.runner_version,
),
service_config=builder.ExternalServiceConfig(
proxy=(builder_config.proxy.http if builder_config.proxy else None),
proxy=builder_config.proxy,
),
)

Expand Down
4 changes: 0 additions & 4 deletions src/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,6 @@ class BuilderRunError(BuilderBaseError):
"""Represents an error while running the image builder."""


class ProxyInstallError(BuilderBaseError):
"""Represents an error while installing proxy."""


class GetLatestImageError(BuilderBaseError):
"""Represents an error while fetching the latest image."""

Expand Down
1 change: 0 additions & 1 deletion src/pipx.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

"""Module handling interactions with pipx."""


# Code is abstracting process interactions and is currently tested in integration tests.

import logging
Expand Down
83 changes: 0 additions & 83 deletions src/proxy.py

This file was deleted.

Loading
Loading