Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
27 changes: 26 additions & 1 deletion .github/workflows/test-linux.yml
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,37 @@ jobs:

- name: "Create container ${{ inputs.container-slug }}"
run: |
/usr/bin/docker create --name ${{ github.run_id }}_salt-test --workdir /_w/ --privileged -e "HOME=/github/home" -e GITHUB_ACTIONS=true -e CI=true -e $GITHUB_ENV -v "/var/run/docker.sock":"/var/run/docker.sock" -v "/home/runner/work":"/__w" -v "/home/runner/work/_temp":"/__w/_temp" -v "/home/runner/work/_actions":"/__w/_actions" -v "/opt/hostedtoolcache":"/__t" -v "/home/runner/work/_temp/_github_home":"/github/home" -v "/home/runner/work/_temp/_github_workflow":"/github/workflow" -v "/home/runner/work/salt-bootstrap/salt-bootstrap":"/_w/btstrap" --entrypoint "/usr/lib/systemd/systemd" ghcr.io/saltstack/salt-ci-containers/testing:${{ inputs.container-slug }} --systemd --unit rescue.target
/usr/bin/docker create --name ${{ github.run_id }}_salt-test --workdir /_w/ --privileged -e "HOME=/github/home" -e GITHUB_ACTIONS=true -e CI=true -e $GITHUB_ENV -v "/var/run/docker.sock":"/var/run/docker.sock" -v "/home/runner/work":"/__w" -v "/home/runner/work/_temp":"/__w/_temp" -v "/home/runner/work/_actions":"/__w/_actions" -v "/opt/hostedtoolcache":"/__t" -v "/home/runner/work/_temp/_github_home":"/github/home" -v "/home/runner/work/_temp/_github_workflow":"/github/workflow" -v "/home/runner/work/salt-bootstrap/salt-bootstrap":"/_w/btstrap" --entrypoint "/usr/lib/systemd/systemd" ghcr.io/saltstack/salt-ci-containers/testing:${{ inputs.container-slug }} --unit=rescue.target

- name: "Start container ${{ inputs.container-slug }}"
run: |
/usr/bin/docker start ${{ github.run_id }}_salt-test

- name: "Wait for container ${{ inputs.container-slug }} to finish booting"
run: |
# systemd's default tmpfiles.d rules wipe /tmp during early boot
# (systemd-tmpfiles-setup.service). Running pip/bootstrap before
# that finishes races the wipe and fails with spurious
# "No such file or directory" errors on /tmp/pip-*-tracker-*.
#
# The container boots into rescue.target (--unit=rescue.target
# above), so "is-system-running" settles on "maintenance", not
# "running"/"degraded" - those are kept as a fallback in case a
# given image's rescue.target ever pulls in extra units.
for i in $(seq 1 30); do
state=$(docker exec ${{ github.run_id }}_salt-test systemctl is-system-running 2>/dev/null || true)
echo "boot state at ${i}s: '$state'"
case "$state" in
maintenance|running|degraded) exit 0 ;;
esac
sleep 1
done
echo "::error::Container did not finish booting within 30 seconds (last state: '$state')"
docker exec ${{ github.run_id }}_salt-test systemctl list-jobs || true
docker exec ${{ github.run_id }}_salt-test systemctl --failed || true
docker exec ${{ github.run_id }}_salt-test journalctl -b --no-pager || true
exit 1

- name: "Install Python Dependencies with pip breakage in container ${{ inputs.container-slug }}"
if: ${{ ( inputs.distro-slug == 'debian-12' ) || ( inputs.distro-slug == 'debian-13' ) || ( inputs.distro-slug == 'ubuntu-2404' ) || ( inputs.distro-slug == 'ubuntu-2604' ) }}
run: |
Expand Down
4 changes: 4 additions & 0 deletions bootstrap-salt.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3021,6 +3021,7 @@ __install_saltstack_ubuntu_repository() {
# SaltStack's stable Ubuntu repository:
__fetch_url "/etc/apt/sources.list.d/salt.sources" "https://github.com/saltstack/salt-install-guide/releases/latest/download/salt.sources"
[ -f /etc/apt/sources.list.d/salt.sources ] && sed -i "s#salt-archive-keyring\.pgp#salt-archive-keyring.gpg#" /etc/apt/sources.list.d/salt.sources
[ -f /etc/apt/sources.list.d/salt.sources ] && sed -i "s#packages\.broadcom\.com/artifactory#${_REPO_URL}#" /etc/apt/sources.list.d/salt.sources
__apt_key_fetch "${HTTP_VAL}://${_REPO_URL}/api/security/keypair/SaltProjectKey/public" || return 1
__wait_for_apt apt-get update || return 1

Expand Down Expand Up @@ -3074,6 +3075,7 @@ __install_saltstack_ubuntu_onedir_repository() {
# SaltStack's stable Ubuntu repository:
__fetch_url "/etc/apt/sources.list.d/salt.sources" "https://github.com/saltstack/salt-install-guide/releases/latest/download/salt.sources"
[ -f /etc/apt/sources.list.d/salt.sources ] && sed -i "s#salt-archive-keyring\.pgp#salt-archive-keyring.gpg#" /etc/apt/sources.list.d/salt.sources
[ -f /etc/apt/sources.list.d/salt.sources ] && sed -i "s#packages\.broadcom\.com/artifactory#${_REPO_URL}#" /etc/apt/sources.list.d/salt.sources
__apt_key_fetch "${HTTP_VAL}://${_REPO_URL}/api/security/keypair/SaltProjectKey/public" || return 1
__wait_for_apt apt-get update || return 1

Expand Down Expand Up @@ -3526,6 +3528,7 @@ __install_saltstack_debian_repository() {

__fetch_url "/etc/apt/sources.list.d/salt.sources" "https://github.com/saltstack/salt-install-guide/releases/latest/download/salt.sources"
[ -f /etc/apt/sources.list.d/salt.sources ] && sed -i "s#salt-archive-keyring\.pgp#salt-archive-keyring.gpg#" /etc/apt/sources.list.d/salt.sources
[ -f /etc/apt/sources.list.d/salt.sources ] && sed -i "s#packages\.broadcom\.com/artifactory#${_REPO_URL}#" /etc/apt/sources.list.d/salt.sources
__apt_key_fetch "${HTTP_VAL}://${_REPO_URL}/api/security/keypair/SaltProjectKey/public" || return 1
__wait_for_apt apt-get update || return 1

Expand Down Expand Up @@ -3572,6 +3575,7 @@ __install_saltstack_debian_onedir_repository() {

__fetch_url "/etc/apt/sources.list.d/salt.sources" "https://github.com/saltstack/salt-install-guide/releases/latest/download/salt.sources"
[ -f /etc/apt/sources.list.d/salt.sources ] && sed -i "s#salt-archive-keyring\.pgp#salt-archive-keyring.gpg#" /etc/apt/sources.list.d/salt.sources
[ -f /etc/apt/sources.list.d/salt.sources ] && sed -i "s#packages\.broadcom\.com/artifactory#${_REPO_URL}#" /etc/apt/sources.list.d/salt.sources
__apt_key_fetch "${HTTP_VAL}://${_REPO_URL}/api/security/keypair/SaltProjectKey/public" || return 1
__wait_for_apt apt-get update || return 1

Expand Down
88 changes: 88 additions & 0 deletions tests/integration/test_installation.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import logging
import os
import platform
import re
import shutil
import subprocess

Expand Down Expand Up @@ -120,3 +121,90 @@ def test_apt_keyring_is_trusted():
assert result.returncode == 0, result.stderr
assert "NO_PUBKEY" not in result.stderr, result.stderr
assert "unsupported filetype" not in result.stderr, result.stderr


DEBIAN_REPO_FUNCTIONS = [
"__install_saltstack_ubuntu_repository",
"__install_saltstack_ubuntu_onedir_repository",
"__install_saltstack_debian_repository",
"__install_saltstack_debian_onedir_repository",
]

SAMPLE_SALT_SOURCES = """\
X-Repolib-Name: Salt Project
Types: deb
URIs: https://packages.broadcom.com/artifactory/saltproject-deb
Signed-By: /etc/apt/keyrings/salt-archive-keyring.pgp
Suites: stable
Components: main
"""


def _bash_has_gnu_sed():
# Check through "bash -c", the exact invocation the test below uses, since
# e.g. on GitHub's Windows runners plain "sed" on the host PATH is Git
# Bash's GNU sed, but "bash" on the host PATH resolves to the WSL launcher
# stub instead - a different, often broken, resolution path.
try:
result = subprocess.run(
["bash", "-c", "sed --version"],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
universal_newlines=True,
)
except FileNotFoundError:
return False
return "GNU sed" in result.stdout


def test_debian_repo_functions_rewrite_custom_repo_url(tmp_path):
"""
Regression test for https://github.com/saltstack/salt-bootstrap/issues/2123
The -R/_CUSTOM_REPO_URL option must rewrite the "URIs:" line in
salt.sources for Debian/Ubuntu, not just the GPG key fetch URL.
"""
if not _bash_has_gnu_sed():
# bootstrap-salt.sh's Debian/Ubuntu sed -i syntax targets GNU sed,
# which is what those distros actually ship. BSD sed (e.g. on macOS)
# parses "-i" differently, and isn't representative of the real
# target either way.
pytest.skip("bash with GNU sed not available")

bootstrap_script = os.path.join(
os.path.dirname(__file__), "..", "..", "bootstrap-salt.sh"
)
if not os.path.exists(bootstrap_script):
pytest.skip("bootstrap-salt.sh not found (not running from a repo checkout)")

with open(bootstrap_script) as fp:
script = fp.read()

for func_name in DEBIAN_REPO_FUNCTIONS:
match = re.search(
rf"^{re.escape(func_name)}\(\) {{(.*?)^}}", script, re.M | re.S
)
assert match, f"could not find {func_name}() in bootstrap-salt.sh"

sed_exprs = re.findall(
r'sed -i "([^"]+)" /etc/apt/sources\.list\.d/salt\.sources',
match.group(1),
)
assert sed_exprs, f"{func_name} has no salt.sources sed post-processing"

sources_file = tmp_path / f"{func_name}.sources"
sources_file.write_text(SAMPLE_SALT_SOURCES)

env = dict(os.environ, _REPO_URL="repo.example.com/myrepo", HTTP_VAL="https")
for expr in sed_exprs:
subprocess.run(
["bash", "-c", f'sed -i "{expr}" "$1"', "--", str(sources_file)],
env=env,
check=True,
)

result = sources_file.read_text()
assert "packages.broadcom.com" not in result, (
f"{func_name}: salt.sources still references packages.broadcom.com "
f"after applying its sed commands:\n{result}"
)
assert "repo.example.com/myrepo" in result
Loading