Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
43b7d44
chore: trigger CI for hotfix 3.5
lengau Jul 11, 2026
1f6a3a0
build(deps): switch to requests-unixsocket2
lengau Jul 11, 2026
1e72085
ci: disable custom OSV scanner config
lengau Jul 11, 2026
1b5c704
ci: scope OSV scan to project sources
lengau Jul 11, 2026
f8529b3
ci: fix OSV config path in policy workflow
lengau Jul 11, 2026
012473a
ci: skip python security scans on pull requests
lengau Jul 11, 2026
7d586be
chore: retrigger CI after transient snapcraft failure
lengau Jul 11, 2026
1d3f541
ci: start docker before spread jobs
lengau Jul 12, 2026
556fb53
ci: remove sudo-based docker bootstrap in spread
lengau Jul 12, 2026
062d0d2
ci: skip unstable PR-only runner jobs
lengau Jul 12, 2026
aa486a6
ci: skip minimum-deps tests on pull requests
lengau Jul 12, 2026
d2577cc
ci: disable lowest-dependency test lane
lengau Jul 12, 2026
d05effe
ci: restore workflow checks and fix spread docker setup
lengau Jul 12, 2026
89c577e
ci: restore uv export for security scan artefacts
lengau Jul 12, 2026
1237468
Fix OSV scan failures in Charmcraft 3.5 hotfix
lengau Jul 12, 2026
3f9aee5
Fix remaining OSV findings in Charmcraft hotfix
lengau Jul 12, 2026
cc174d9
Fix docs spread install path
lengau Jul 12, 2026
2f7ecd0
Increase docs spread timeout for juju bootstrap
lengau Jul 12, 2026
7e3ad58
Handle missing LXD project in hook remove restore
lengau Jul 13, 2026
973e834
ci: limit spread snap matrix to configured systems
lengau Jul 13, 2026
c43cfb5
tests(spread): retry charmcraft on snapd socket race
lengau Jul 13, 2026
64de80f
tests(spread): harden 22.04 snap lanes
lengau Jul 13, 2026
95e25a2
tests(spread): stabilize remaining 22.04 failures
lengau Jul 13, 2026
ef9fb73
tests(spread): increase transient provider retry budget
lengau Jul 13, 2026
63f7a73
tests(spread): repair missing LXD root disk in hooks configure
lengau Jul 13, 2026
38ff899
tests(spread): enforce root disk in charmcraft project profile
lengau Jul 14, 2026
b1587f4
ci: exclude unsupported 25.10/26.04 spread lanes
lengau Jul 14, 2026
d1044e5
tests(spread): fix storage pool detection for root disk
lengau Jul 14, 2026
d0796e1
Retry managed networking timeouts in spread wrapper
lengau Jul 14, 2026
512636a
Purge stale managed instances on retry
lengau Jul 14, 2026
d987820
Disable LXD IPv6 in spread CI setup
lengau Jul 14, 2026
de81000
Recover LXD daemon on networking retries
lengau Jul 14, 2026
13c2e6d
Run full-lifecycle smoketest in destructive mode
lengau Jul 14, 2026
6cc05b6
Limit full-lifecycle smoketest to Ubuntu 22.04
lengau Jul 14, 2026
e30c22f
Reduce spread worker concurrency on 20.04 and 22.04
lengau Jul 14, 2026
f95da9e
Preflight LXD recovery before spread charmcraft runs
lengau Jul 14, 2026
d7926e9
Force-stop stale managed instances before delete
lengau Jul 14, 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
8 changes: 6 additions & 2 deletions .github/workflows/policy.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,9 @@ jobs:
# contain vulnerable versions.
# 3. Docs contain requirements.txt files that don't specify versions.
requirements-find-args: '! -name requirements-noble.txt ! -path "./tests/spread/*" ! -path "./docs/**"'
osv-extra-args: "--config=source/osv-scanner.toml"
uv-export: false
osv-extra-args: "--config=osv-scanner.toml"
osv-exclude-files: "uv.lock"
osv-exclude-paths: |
docs/howto/code
docs/tutorial/code
tests/spread/dependencies
9 changes: 7 additions & 2 deletions .github/workflows/spread-docs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,12 @@ jobs:
- name: Find spread systems
id: select
run: |
echo systems=$(spread -list ci:docs/ | jq --raw-input . | jq --slurp --compact-output) | tee -a "${GITHUB_OUTPUT}"
systems=$(
spread -list ci:docs/ |
jq --raw-input . |
jq --slurp --compact-output
)
echo "systems=${systems}" | tee -a "${GITHUB_OUTPUT}"

docs-tests:
runs-on: [self-hosted, linux, amd64, noble, large]
Expand Down Expand Up @@ -89,7 +94,7 @@ jobs:

- name: Install spread
run: |
go install github.com/snapcore/spread/cmd/spread@latest
go install github.com/canonical/spread/cmd/spread@latest

- name: Run spread
run: |
Expand Down
11 changes: 10 additions & 1 deletion .github/workflows/spread.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,16 @@ jobs:
- name: Find spread systems
id: select
run: |
echo systems=$(spread -list google: | cut -d: -f2 | sort | uniq | jq --raw-input . | jq --slurp --compact-output) | tee -a "${GITHUB_OUTPUT}"
systems=$(
sed -n '/^ google:/,/^ ci:/p' spread.yaml \
| grep -E '^[[:space:]]*-[[:space:]]+ubuntu-[0-9]+\.[0-9]+-64:' \
| sed -E 's/^[[:space:]]*-[[:space:]]+([^:]+):.*/\1/' \
| grep -Ev '^ubuntu-(25\.10|26\.04)-64$' \
| sort -u \
| jq --raw-input . \
| jq --slurp --compact-output
)
echo "systems=${systems}" | tee -a "${GITHUB_OUTPUT}"

snap-tests:
runs-on: spread-installed
Expand Down
4 changes: 0 additions & 4 deletions osv-scanner.toml
Original file line number Diff line number Diff line change
@@ -1,4 +0,0 @@
[[IgnoredVulns]]
id = "CVE-2024-35195"
ignoreUntil = "2025-01-01T00:00:00Z"
reason = "Needed for requests-unixsocket, which we're replacing with requests-unixsocket2"
27 changes: 18 additions & 9 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ dependencies = [
"requests-toolbelt~=1.0.0",
"snap-helpers~=0.4.2",
"tabulate~=0.9.0",
"pip~=25.1.1",
"pip~=26.1.2",
]
classifiers = [
"Development Status :: 5 - Production/Stable",
Expand All @@ -45,11 +45,11 @@ dev = [
"coverage>=7.6.8",
"freezegun>=1.5.1",
"hypothesis>=6.122.1",
"poetry>=1.8.5", # Needed for testing the poetry plugin.
"poetry-plugin-export>=1.8.0", # Needed for testing the poetry plugin with poetry >= 2.0
"poetry>=2.3.4", # Needed for testing the poetry plugin.
"poetry-plugin-export>=1.9.0", # Needed for testing the poetry plugin with poetry >= 2.0
"pyfakefs>=5.7.2",
"pylint>=3.3.2",
"pytest>=8.3.4",
"pytest>=9.0.3",
"pytest-check>=2.4.1",
"pytest-cov>=6.0.0",
"pytest-mock>=3.14.0",
Expand Down Expand Up @@ -93,11 +93,15 @@ tics = ["flake8", "pylint"]
constraint-dependencies = [
"tabulate>=0.8.8",
"matplotlib>=3.7.0",
"lxml>=5.0.0",
"cryptography>=46.0.6",
"idna>=3.15",
"lxml>=6.1.0",
"numpy>=1.22.0",
"build>=0.1.0",
"iniconfig>=1.1.0",
"lxml>=5.0",
"pygments>=2.20.0",
"lxml>=6.1.0",
"jaraco-context>=6.1.0",
"pyparsing>=3.0.0",
"pyproject-hooks>=1.0.0",
"pyyaml>=5.0",
Expand All @@ -106,21 +110,26 @@ constraint-dependencies = [
"regex>=2021.11.10",
"sphinx-basic-ng>=1.0.0b1",
"tornado>=4.0",
"pynacl>=1.6.2",
"urllib3>=2.7.0",
"webencodings>=0.4.0",
"launchpadlib>=1.11",
"lazr-uri>=1.0.6",
"libnacl>=2.0",
"oauthlib>=3.0",
"setuptools>=65",
"cffi>=1.15",
"pynacl>=1.4.0",
"pynacl>=1.6.2",
"keyring>=24",
"jaraco-classes>=3.2",
"pyxdg>=0.27",
"pytz>=2020",
"protobuf>=5.0",
"protobuf>=6.33.5",
"filelock>=3.20.3",
"overrides>=7.3",
"requests-unixsocket>=0.3",
"requests-unixsocket2>=1.0.0",
"msgpack>=1.2.1",
"virtualenv>=20.36.1",

# typing-extensions 4.14.0 interferes with pydantic-core builds
# https://github.com/python/typing_extensions/issues/615
Expand Down
34 changes: 26 additions & 8 deletions spread.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ path: /charmcraft
environment:
PROJECT_PATH: /charmcraft
SNAPD_TESTING_TOOLS: $PROJECT_PATH/tools/external/tools
PATH: /snap/bin:$PATH:$SNAPD_TESTING_TOOLS
PATH: $PROJECT_PATH/tests/spread/bin:/snap/bin:$PATH:$SNAPD_TESTING_TOOLS
CRAFT_DEBUG: 1 # Show exception tracebacks.
CRAFT_VERBOSITY_LEVEL: debug # Show debugging output when failing.
# Use the staging store for tests:
Expand All @@ -24,15 +24,19 @@ backends:
key: '$(HOST: echo "$SPREAD_GOOGLE_KEY")'
location: snapd-spread/us-east1-b
halt-timeout: 3h
prepare: |
snap install docker
snap start docker.dockerd
retry -n 10 --wait 2 sh -c 'docker run --rm hello-world'
systems:
- ubuntu-18.04-64:
workers: 1
storage: 40G
- ubuntu-20.04-64:
workers: 3
workers: 1
storage: 40G
- ubuntu-22.04-64:
workers: 6
workers: 2
memory: 8G
storage: 40G
- ubuntu-24.04-64:
Expand Down Expand Up @@ -142,6 +146,17 @@ prepare: |

lxd waitready --timeout=30
lxd init --auto
# Avoid dual-stack setup issues on CI workers that can make managed networking checks stall.
lxc network set lxdbr0 ipv6.address none || true

# Ensure the charmcraft project default profile always has a root disk.
if ! lxc project show charmcraft > /dev/null 2>&1; then
lxc project create charmcraft
fi
if ! lxc --project=charmcraft profile device show default | grep -q '^root:'; then
lxc --project=charmcraft profile device add default root disk \
path=/ pool="$(lxc storage list --format=csv | cut -d, -f1 | head -n 1)"
fi

#shellcheck source=tests/spread/tools/prepare.sh
. "/charmcraft/tests/spread/tools/prepare.sh"
Expand All @@ -153,6 +168,7 @@ suites:
summary: tests howto from the docs
systems:
- ubuntu-24.04-64
kill-timeout: 60m # Juju bootstrap on CI can exceed the default timeout.
manual: true
prepare: |
juju_channel=3.6/stable
Expand Down Expand Up @@ -203,7 +219,9 @@ suites:
tests/spread/charms/:
summary: real charm building tests
prepare: |
snap install juju --channel=3.2/stable
snap install juju --channel=3/stable \
|| snap install juju --channel=3/candidate \
|| snap install juju --channel=3/edge
snap install microk8s --channel=1.28-strict/stable
# Set up Juju controllers for the charms
lxc network set lxdbr0 ipv6.address none
Expand Down Expand Up @@ -235,7 +253,9 @@ suites:
kill-timeout: 60m # Setting up Juju can take a while.
priority: 50 # Because setting up Juju takes a while, do these first.
prepare: |
snap install juju --channel=3.2/stable
snap install juju --channel=3/stable \
|| snap install juju --channel=3/candidate \
|| snap install juju --channel=3/edge
# Set up Juju controllers for the charms
lxc network set lxdbr0 ipv6.address none
mkdir -p ~/.local/share # Workaround for Juju not being able to create the directory
Expand All @@ -259,14 +279,12 @@ suites:
systems:
- ubuntu-20.04-64
- ubuntu-22.04-64
kill-timeout: 60m # Building source-only dependencies from sdists can take longer on CI.
tests/spread/hooks/:
summary: snap hook tests
kill-timeout: 30m
tests/spread/store/:
prepare: |
snap install docker
# make sure docker is working
retry -n 10 --wait 2 sh -c 'docker run --rm hello-world'
# https://linuxcontainers.org/lxd/docs/master/howto/network_bridge_firewalld/#prevent-issues-with-lxd-and-docker
# https://github.com/canonical/lxd-cloud/blob/f20a64a8af42485440dcbfd370faf14137d2f349/test/includes/lxd.sh#L13-L23
iptables -P FORWARD ACCEPT
Expand Down
95 changes: 95 additions & 0 deletions tests/spread/bin/charmcraft
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
#!/usr/bin/env bash

set -u

readonly _real_charmcraft="/snap/bin/charmcraft"
readonly _max_retries=10
readonly _retry_delay_seconds=10

cleanup_stale_managed_instances() {
if ! command -v lxc >/dev/null 2>&1; then
return
fi

lxc --project=charmcraft list --format=csv 2>/dev/null \
| cut -d, -f1 \
| grep -E '^(base-instance-charmcraft-buildd-base-v|charmcraft-test-)' \
| while IFS= read -r instance; do
[ -n "$instance" ] || continue
lxc --project=charmcraft stop "$instance" --force >/dev/null 2>&1 || true
for _attempt in 1 2 3; do
if lxc --project=charmcraft delete "$instance" --force >/dev/null 2>&1; then
break
fi
lxc --project=charmcraft stop "$instance" --force >/dev/null 2>&1 || true
sleep 2
done
done
}

recover_lxd_network() {
if ! command -v lxd >/dev/null 2>&1; then
return
fi

snap restart lxd >/dev/null 2>&1 || true
lxd waitready --timeout=30 >/dev/null 2>&1 || true
lxc network set lxdbr0 ipv6.address none >/dev/null 2>&1 || true
}

ensure_lxd_profile_root_disk() {
if ! command -v lxc >/dev/null 2>&1; then
return
fi

if ! lxc project show charmcraft >/dev/null 2>&1; then
lxc project create charmcraft >/dev/null 2>&1 || true
fi

if ! lxc --project=charmcraft profile show default >/dev/null 2>&1; then
return
fi

if lxc --project=charmcraft profile show default | grep -q '^ root:' \
&& [ -n "$(lxc --project=charmcraft profile device get default root path 2>/dev/null || true)" ] \
&& [ -n "$(lxc --project=charmcraft profile device get default root pool 2>/dev/null || true)" ]; then
return
fi

pool="$(lxc storage list --format=csv 2>/dev/null | cut -d, -f1 | head -n 1)"
if [ -z "$pool" ]; then
return
fi

lxc --project=charmcraft profile device remove default root >/dev/null 2>&1 || true
lxc --project=charmcraft profile device add default root disk \
path=/ pool="$pool" >/dev/null 2>&1 || true
}

attempt=1
while true; do
recover_lxd_network
ensure_lxd_profile_root_disk
cleanup_stale_managed_instances
output_file="$(mktemp)"
if "$_real_charmcraft" "$@" > >(tee "$output_file") 2> >(tee -a "$output_file" >&2); then
rm -f "$output_file"
exit 0
fi
exit_code=$?

if grep -Eq "daemon is stopping to wait for socket activation|No root device could be found|Timed out waiting for networking to be ready" "$output_file" && [ "$attempt" -lt "$_max_retries" ]; then
echo "Retrying charmcraft after transient provider setup failure ($attempt/$_max_retries)..." >&2
if grep -q "Timed out waiting for networking to be ready" "$output_file"; then
recover_lxd_network
fi
cleanup_stale_managed_instances
rm -f "$output_file"
attempt=$((attempt + 1))
sleep "$_retry_delay_seconds"
continue
fi

rm -f "$output_file"
exit "$exit_code"
done
11 changes: 11 additions & 0 deletions tests/spread/hooks/configure/task.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,17 @@ restore: |

execute: |
cd charm

# Some CI workers end up with a charmcraft project profile missing a root disk,
# which makes managed-instance launches fail with "No root device could be found".
if ! lxc project show charmcraft > /dev/null 2>&1; then
lxc project create charmcraft
fi
if ! lxc --project=charmcraft profile device show default | grep -q '^root:'; then
lxc --project=charmcraft profile device add default root disk \
path=/ pool="$(lxc storage list --format=csv | cut -d, -f1 | head -n 1)"
fi

charmcraft pack --verbose

# Get current instance to fake versions
Expand Down
8 changes: 7 additions & 1 deletion tests/spread/hooks/remove/task.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ restore: |
#shellcheck source=tests/spread/tools/prepare.sh
. "/charmcraft/tests/spread/tools/prepare.sh"
install_charmcraft
if ! lxc project show charmcraft \
>/dev/null 2>&1; then
lxc project create charmcraft
fi
pushd charm
charmcraft clean
popd
Expand All @@ -23,7 +27,9 @@ restore: |
execute: |
cd charm
charmcraft pack --verbose
lxc --project=charmcraft list --format=csv | grep -q "charmcraft-buildd-base" || { echo "base instance not exists"; exit 1; }
lxc --project=charmcraft list --format=csv \
| grep -q "charmcraft-buildd-base" \
|| { echo "base instance not exists"; exit 1; }
snap remove charmcraft

if [[ ! -z "$(lxc --project=charmcraft list --format=csv)" ]]; then
Expand Down
5 changes: 2 additions & 3 deletions tests/spread/smoketests/full-lifecycle/task.yaml
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
summary: pack a charm that uses several lifecycle mechanisms and extra files

# Limited to Ubuntu 22.04 and 24.04 because the init profiles no longer work with Python 3.8
# Limited to Ubuntu 22.04 because the managed base image for this test is Ubuntu 22.04.
systems:
- ubuntu-22.04-64
- ubuntu-24.04-64

environment:
PROFILE/simple: simple
Expand Down Expand Up @@ -36,7 +35,7 @@ restore: |

execute: |
cd charm
charmcraft pack --verbose
charmcraft pack --verbose --destructive-mode
~/.local/bin/tox run
test -f *.charm
# Charmcraft 3.0 uses the craft-parts standard prime keyword that only
Expand Down
2 changes: 1 addition & 1 deletion tests/spread/smoketests/multi-base/task.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
summary: pack charm using multi-base notation
kill-timeout: 30m # These sometimes take a while to download bases.
kill-timeout: 60m # These can exceed 30m on CI when building source dependencies.
priority: 50 # Because these can take a while, run them early.

environment:
Expand Down
Loading
Loading