1
0
Fork 0

Adding debian version 1.0.141.

Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
This commit is contained in:
Daniel Baumann 2025-06-22 09:44:37 +02:00
parent 04ec7bd664
commit 53607d61bf
Signed by: daniel.baumann
GPG key ID: BCC918A2ABD66424
21 changed files with 4622 additions and 0 deletions

3465
debian/changelog vendored Normal file

File diff suppressed because it is too large Load diff

30
debian/control vendored Normal file
View file

@ -0,0 +1,30 @@
Source: debootstrap
Section: admin
Priority: optional
Maintainer: Debian Install System Team <debian-boot@lists.debian.org>
Uploaders: Colin Watson <cjwatson@debian.org>, Steve McIntyre <93sam@debian.org>,
Hideki Yamane <henrich@debian.org>, Luca Boccassi <bluca@debian.org>,
Build-Depends: debhelper-compat (= 13)
Standards-Version: 4.7.0
Rules-Requires-Root: no
Vcs-Browser: https://salsa.debian.org/installer-team/debootstrap
Vcs-Git: https://salsa.debian.org/installer-team/debootstrap.git
Package: debootstrap
Architecture: all
Multi-Arch: foreign
Depends: ${misc:Depends}, wget, distro-info
Recommends: sopv | sqv | gpgv, mount, ${debootstrap:Recommends}
Suggests: squid-deb-proxy-client, ${debootstrap:Suggests}
Description: Bootstrap a basic Debian system
debootstrap is used to create a Debian base system from scratch,
without requiring the availability of dpkg or apt. It does this by
downloading .deb files from a mirror site, and carefully unpacking them
into a directory which can eventually be chrooted into.
Package: debootstrap-udeb
Section: debian-installer
Package-Type: udeb
Architecture: all
Depends: ${misc:Depends}, mounted-partitions
Description: Bootstrap the Debian system

23
debian/copyright vendored Normal file
View file

@ -0,0 +1,23 @@
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Files: *
Copyright: 2001-2007 Anthony Towns <ajt@debian.org>
2007-2024 Debian Install System Team <debian-boot@lists.debian.org>
License: Expat
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
.
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE

1
debian/debootstrap.docs vendored Normal file
View file

@ -0,0 +1 @@
README

1
debian/debootstrap.manpages vendored Normal file
View file

@ -0,0 +1 @@
debootstrap.8

2
debian/gbp.conf vendored Normal file
View file

@ -0,0 +1,2 @@
[DEFAULT]
debian-tag = %(version)s

36
debian/rules vendored Executable file
View file

@ -0,0 +1,36 @@
#! /usr/bin/make -f
ifeq (0,$(shell dpkg-vendor --derives-from Ubuntu; echo $$?))
RECOMMENDS := ubuntu-keyring
SUGGESTS := debian-archive-keyring, arch-test (>= 0.11~),
else ifeq (0,$(shell dpkg-vendor --derives-from Tanglu; echo $$?))
RECOMMENDS := tanglu-archive-keyring, arch-test (>= 0.11~),
SUGGESTS := debian-archive-keyring, ubuntu-archive-keyring, binutils, xz-utils, zstd
else ifeq (0,$(shell dpkg-vendor --derives-from Kali; echo $$?))
RECOMMENDS := kali-archive-keyring, arch-test (>= 0.11~),
SUGGESTS := debian-archive-keyring, ubuntu-archive-keyring, binutils, xz-utils, zstd
else ifeq (0,$(shell dpkg-vendor --derives-from Pardus; echo $$?))
RECOMMENDS := pardus-archive-keyring, arch-test (>= 0.11~),
SUGGESTS := debian-archive-keyring, ubuntu-archive-keyring, binutils, xz-utils, zstd
else ifeq (0,$(shell dpkg-vendor --derives-from eLxr; echo $$?))
RECOMMENDS := elxr-archive-keyring, arch-test (>= 0.11~),
SUGGESTS := debian-archive-keyring, ubuntu-archive-keyring, binutils, xz-utils, zstd
else
RECOMMENDS := debian-archive-keyring, arch-test (>= 0.11~),
SUGGESTS := ubuntu-archive-keyring, binutils, xz-utils, zstd
endif
%:
dh $@
override_dh_auto_install:
$(MAKE) install DESTDIR=$(CURDIR)/debian/debootstrap
$(MAKE) install DESTDIR=$(CURDIR)/debian/debootstrap-udeb
override_dh_gencontrol:
dh_gencontrol -- -Vdebootstrap:Recommends='$(RECOMMENDS)' -Vdebootstrap:Suggests='$(SUGGESTS)'
# Specify gzip to mitigate #770217:
override_dh_builddeb:
dh_builddeb -pdebootstrap -- -Zgzip
dh_builddeb -pdebootstrap-udeb -- -Zxz

76
debian/salsa-ci.yml vendored Normal file
View file

@ -0,0 +1,76 @@
---
include:
- https://salsa.debian.org/installer-team/branch2repo/-/raw/main/trigger_b2r.yml
variables:
SALSA_CI_DISABLE_BUILD_PACKAGE_ANY: 1
# undo some of branch2repo's defaults, which are tuned for udebs
SALSA_CI_DISABLE_LINTIAN: 0
SALSA_CI_DISABLE_PIUPARTS: 0
# This tests running debootstrap inside an unshared user namespace.
# Inside that namespace, mknod is not available.
# In such an environment "mount -t proc proc /proc" will not work (see
# #1031222) so this also tests whether the fallback to bind-mounting
# proc works as systemd-tmpfiles will otherwise not create several files.
test-unshare:
stage: test
image: $SALSA_CI_IMAGES_BASE
needs:
- job: build
artifacts: true
variables:
DEBOOTSTRAP_SCRIPT: $CI_PROJECT_DIR/debootstrap
DEBOOTSTRAP_DIR: $CI_PROJECT_DIR
AUTOPKGTEST_TMP: /tmp
script:
- apt-get update
- apt-get install --no-install-recommends -y libdistro-info-perl libdpkg-perl libipc-run-perl perl systemd systemd-container ca-certificates mmdebstrap uidmap wget distro-info
- mmdebstrap --variant=custom --mode=unshare --setup-hook="./debian/tests/debian-testing minbase" --skip=update,setup,cleanup - "$AUTOPKGTEST_TMP/chroot.d"
test-buildd:
stage: test
image: $SALSA_CI_IMAGES_BASE
needs:
- job: build
artifacts: true
script:
- |
set -x
apt-get update
apt-get install --no-install-recommends -y wget distro-info
for SUITE in bullseye bookworm trixie; do
env DEBOOTSTRAP_DIR="$CI_PROJECT_DIR" ./debootstrap --variant=buildd "$SUITE" ./chroot
# check if chroots before trixie are unmerged and chroots of trixie
# or later are using merged-/usr
case "$SUITE" in
bullseye|bookworm)
for f in bin sbin lib; do
[ ! -d "./chroot/$f" ] && echo "E: /$f is not a directory" && exit 1
[ -L "./chroot/$f" ] && echo "E: /$f is a symlink" && exit 1
done
;;
trixie)
for f in bin sbin lib; do
[ ! -L "./chroot/$f" ] && echo "E: /$f is not a symlink" && exit 1
done
;;
esac
# check if trixie buildd chroots do not contain Priority:required
# packages like tzdata
case "$SUITE" in
bullseye|bookworm)
if [ "$(chroot ./chroot dpkg-query --no-pager --showformat '${db:Status-Status}' --show tzdata)" != "installed" ]; then
echo "E: tzdata should be installed in the buildd variant for bullseye and bookworm"
exit 1
fi
;;
trixie)
if [ "$(chroot ./chroot dpkg-query --no-pager --showformat '${db:Status-Status}' --show tzdata)" = "installed" ]; then
echo "E: tzdata should not be installed in the buildd variant for trixie"
exit 1
fi
;;
esac
rm -rf ./chroot
done

1
debian/source/format vendored Normal file
View file

@ -0,0 +1 @@
3.0 (native)

3
debian/source/lintian-overrides vendored Normal file
View file

@ -0,0 +1,3 @@
debootstrap source: custom-compression-in-debian-source-options compression = gzip [debian/source/options:*]
debootstrap source: custom-compression-in-debian-rules dh_builddeb -pdebootstrap * -- -Zgzip [debian/rules:*]
debootstrap source: custom-compression-in-debian-rules dh_builddeb -pdebootstrap-udeb -- -Zxz [debian/rules:*]

1
debian/source/options vendored Normal file
View file

@ -0,0 +1 @@
compression = gzip

120
debian/tests/arch-all-mitm.py vendored Normal file
View file

@ -0,0 +1,120 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2023 Debian Install System Team <debian-boot@lists.debian.org>
# Copyright (C) 2023 Matthias Klumpp <matthias@tenstral.net>
#
# SPDX-License-Identifier: MIT
"""
Flask app which MITM's a legacy-compatibility archive to make it arch:all-only.
"""
import functools
import gzip
import hashlib
import os
import requests
import tempfile
from apt_pkg import TagFile, TagSection
from flask import Flask, redirect
app = Flask(__name__)
ARCH = os.environ.get("FLASK_ARCH", "amd64")
DIST = os.environ.get("FLASK_DIST", "trixie")
DISTRO = os.environ.get("FLASK_DISTRO", "debian")
MIRROR = os.environ.get("FLASK_MIRROR", "http://deb.debian.org")
if DISTRO in ("debian", "pureos"):
hash_funcs = [hashlib.md5, hashlib.sha256]
else:
# Ubuntu includes SHA1 still
hash_funcs = [hashlib.md5, hashlib.sha1, hashlib.sha256]
def _munge_release_file(url: str) -> bytes:
"""Given a Release file URL, rewrite it for our modified Packages content."""
original = requests.get(MIRROR + "/" + url).content.decode('utf-8')
packages_content = _packages_arch_content(
f"{DISTRO}/dists/{DIST}/main/binary-{ARCH}/Packages"
)
size = str(len(packages_content))
sums = [
hash_func(packages_content).hexdigest()
for hash_func in hash_funcs
]
new_lines = []
filename = f"main/binary-{ARCH}/Packages"
for line in original.splitlines():
if line.startswith('No-Support-for-Architecture-all:'):
continue
if line.startswith('Architectures:'):
if ' all' not in line:
line += ' all'
new_lines.append(line)
continue
if line.startswith('Acquire-By-Hash:'):
new_lines.append('Acquire-By-Hash: no')
continue
if not line.endswith(filename):
new_lines.append(line)
continue
new_lines.append(" ".join(["", sums.pop(0), size, filename]))
result = "\n".join(new_lines)
return result.encode('utf-8')
@functools.lru_cache
def _packages_arch_content(url: str) -> bytes:
"""Given an arch-specific Packages URL, fetch it and filter out arch:all."""
resp = requests.get(MIRROR + "/" + url + ".gz")
upstream_content = gzip.decompress(resp.content)
filtered_sections = []
with tempfile.NamedTemporaryFile() as tmp_f:
tmp_f.write(upstream_content)
tmp_f.flush()
with TagFile(tmp_f.name) as tf:
for section in tf:
if section.get('Architecture') == 'all':
continue
filtered_sections.append(section)
result = '\n'.join([str(s) for s in filtered_sections])
return result.encode('utf-8')
@functools.lru_cache
def _packages_indep_content(url: str) -> bytes:
"""Given an arch:all Packages URL, just return its uncompressed contents."""
resp = requests.get(MIRROR + "/" + url + ".gz")
upstream_content = gzip.decompress(resp.content)
return upstream_content
@app.route("/<path:url>", methods=["GET", "POST"])
def root(url):
"""Handler for all requests."""
if (
url == f"{DISTRO}/dists/{DIST}/InRelease"
or "by-hash" in url
or "Packages.xz" in url
or "Packages.gz" in url
):
# 404 these URLs to force clients to fetch by path and without compression, to
# make MITM easier
return "", 404
if url == f"{DISTRO}/dists/{DIST}/Release":
# If Release is being fetched, return our modified version
return _munge_release_file(url)
if url == f"{DISTRO}/dists/{DIST}/main/binary-all/Packages":
return _packages_indep_content(url)
if url == f"{DISTRO}/dists/{DIST}/main/binary-{ARCH}/Packages":
# If Packages is being fetched, return our modified version
return _packages_arch_content(url)
# For anything we don't need to modify, redirect clients to upstream mirror
return redirect(f"{MIRROR}/{url}")

30
debian/tests/arch-all-support vendored Executable file
View file

@ -0,0 +1,30 @@
#!/bin/sh
# This test runs the arch-all-mitm.py Flask app which debootstrap is then
# pointed at.
# It is used to pretend an archive in legacy-compatibility mode is only
# supporting the split-arch-all mode, to test if debootstrap will handle
# that situation correctly.
export FLASK_ARCH="$(dpkg --print-architecture)"
export FLASK_DIST=testing
export FLASK_DISTRO=debian
export FLASK_MIRROR=http://deb.debian.org
export PATH=$PATH:/usr/sbin
# Launch our MitM "mirror" server, ensure that request logging is sent to stdout
PYTHONDONTWRITEBYTECODE=true FLASK_APP=debian/tests/arch-all-mitm.py flask run 2>&1 &
flask_pid=$!
# Give Flask time to come up
sleep 2
tempdir=$(mktemp -d)
# Run debootstrap against our MitM "mirror", ignoring the inevitable GPG errors
./debootstrap --download-only --variant minbase --no-check-sig ${FLASK_DIST} $tempdir http://127.0.0.1:5000/${FLASK_DISTRO}/
rc=$?
rm -rf $tempdir
kill $flask_pid
exit $rc

57
debian/tests/control vendored Normal file
View file

@ -0,0 +1,57 @@
Features: test-name=debian-testing-minbase
Test-Command: ./debian/tests/debian-testing minbase
Depends:
debootstrap,
libdistro-info-perl,
libdpkg-perl,
libipc-run-perl,
perl,
systemd [linux-any],
systemd-container [linux-any],
ca-certificates,
distro-info,
Restrictions: allow-stderr, needs-root
Features: test-name=debian-testing-buildd
Test-Command: ./debian/tests/debian-testing buildd
Depends:
debootstrap,
libdistro-info-perl,
libdpkg-perl,
libipc-run-perl,
perl,
systemd [linux-any],
systemd-container [linux-any],
ca-certificates,
distro-info,
Restrictions: allow-stderr, needs-root
Features: test-name=debian-testing-default
Test-Command: ./debian/tests/debian-testing -
Depends:
debootstrap,
libdistro-info-perl,
libdpkg-perl,
libipc-run-perl,
perl,
systemd [linux-any],
systemd-container [linux-any],
ca-certificates,
distro-info,
Restrictions: allow-stderr, needs-root
Tests: unsorted-packages-files
Depends:
debootstrap,
python3-debian,
python3-flask,
python3-requests,
Restrictions: allow-stderr
Tests: arch-all-support
Depends:
debootstrap,
python3-apt,
python3-flask,
python3-requests,
Restrictions: allow-stderr

398
debian/tests/debian-testing vendored Executable file
View file

@ -0,0 +1,398 @@
#!/usr/bin/perl
# Verify that debootstrap'ing Debian testing produces a usable chroot,
# and in particular that using it with early 2017 versions of schroot and
# pbuilder results in working pseudo-terminals (#817236)
#
# Copyright © 2017 Simon McVittie
# SPDX-License-Identifier: MIT
# (see debian/copyright)
use strict;
use warnings;
use Cwd qw(getcwd);
use Debian::DistroInfo;
use Dpkg::Version;
use IPC::Run qw(run);
use Test::More;
if (scalar @ARGV != 1) {
die "usage: $0 [minbase|-|buildd]"
}
my $variant = $ARGV[0];
my $srcdir = getcwd;
sub verbose_run {
my $argv = shift;
diag("Running: @{$argv}");
return run($argv, @_);
}
sub capture {
my $output;
my $argv = shift;
ok(verbose_run($argv, '>', \$output), "@{$argv}");
chomp $output;
return $output;
}
my $check_non_docker_env;
if (run([qw(grep docker.*cgroup /proc/1/mountinfo)], '&>', '/dev/null')) {
diag("it seems docker environment");
$check_non_docker_env = 0;
}
else {
diag("okay, it's not docker environment");
$check_non_docker_env = 1;
}
my @maybe_unshare_mount_ns;
if (verbose_run(['unshare', '-m', 'true'])) {
diag('can unshare mount namespace');
@maybe_unshare_mount_ns = ('unshare', '-m');
}
else {
diag('cannot unshare mount namespace, are we in a container?');
}
sub check_fake_schroot {
my %params = @_;
my $reference = $params{reference};
my $version = $params{version} || '1.6.10-3';
my $extra_argv = $params{extra_argv} || [];
# Use unshare -m to make sure the /dev mount gets cleaned up on exit, even
# on failures
my $response = capture([@maybe_unshare_mount_ns,
"$srcdir/debian/tests/fake/schroot-$version", @{$extra_argv},
$params{chroot},
qw(runuser -u nobody --),
qw(script -q -c), 'cat /etc/debian_version', '/dev/null']);
$response =~ s/\r//g;
is($response, $reference, 'script(1) should work under (fake) schroot');
}
sub check_fake_pbuilder {
my %params = @_;
my $reference = $params{reference};
my $version = $params{version} || '0.228.4-1';
my $response = capture([@maybe_unshare_mount_ns,
"$srcdir/debian/tests/fake/pbuilder-$version", $params{chroot},
qw(runuser -u nobody --),
qw(script -q -c), 'cat /etc/debian_version', '/dev/null']);
$response =~ s/\r//g;
is($response, $reference,
'script(1) should work under (fake) pbuilder');
}
sub check_chroot {
my %params = @_;
my $chroot = $params{chroot};
my $response;
ok(-f "$chroot/etc/debian_version",
'chroot should have /etc/debian_version');
ok(-x "$chroot/usr/bin/env",
'chroot should have /usr/bin/env which is Essential');
if ($params{has_systemd}) {
for my $p (
"root/.ssh", "run/lock/subsys",
"var/cache/private", "var/lib/private",
"var/lib/systemd/coredump", "var/lib/systemd/pstore",
"var/log/README", "var/log/private"
)
{
ok( -e "$chroot/$p",
"chroot should have /$p created by systemd-tmpfiles" );
}
}
ok(-x "$chroot/usr/bin/hello", 'chroot should have /usr/bin/hello due to --include');
ok(-d "$chroot/usr/share/doc", 'chroot should have /usr/share/doc');
if (!defined $ENV{container} || $ENV{container} ne "mmdebstrap-unshare") {
diag("not running with container=mmdebstrap-unshare");
ok(-c "$chroot/dev/full", '/dev/full should be a character device');
is(capture(['/usr/bin/stat', '--printf=%t %T %a', "$chroot/dev/full"]),
'1 7 666', '/dev/full should be device 1,7 with 0666 permissions');
ok(-c "$chroot/dev/null");
is(capture(['/usr/bin/stat', '--printf=%t %T %a', "$chroot/dev/null"]),
'1 3 666', '/dev/null should be device 1,3 with 0666 permissions');
}
my $did_mknod_ptmx;
my $output;
if (verbose_run([qw(ls -l), "$chroot/dev/ptmx"], '>', \$output)) {
diag("$chroot/dev/ptmx: $output");
}
else {
diag("Unable to list $chroot/dev/ptmx");
}
if (verbose_run([qw(ls -l), "$chroot/dev/pts/ptmx"], '>', \$output)) {
diag("$chroot/dev/pts/ptmx: $output");
}
else {
diag("Unable to list $chroot/dev/pts/ptmx");
}
if (-l "$chroot/dev/ptmx") {
# Necessary if debootstrap is run inside some containers, see
# https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=817236#77
diag("/dev/ptmx is a symbolic link");
like(readlink("$chroot/dev/ptmx"), qr{(?:/dev/)?pts/ptmx},
'if /dev/ptmx is a symlink it should be to /dev/pts/ptmx');
$did_mknod_ptmx = 0;
}
else {
diag("/dev/ptmx is not a symbolic link");
ok(-c "$chroot/dev/ptmx",
'if /dev/ptmx is not a symlink it should be a character device');
is(capture(['/usr/bin/stat', '--printf=%t %T %a',
"$chroot/dev/ptmx"]), '5 2 666',
'if /dev/ptmx is a device node it should be 5,2 with 0666 permissions');
$did_mknod_ptmx = 1;
}
if ($params{can_mknod_ptmx}) {
ok($did_mknod_ptmx, 'able to mknod ptmx so should have done so');
}
my $reference = capture(['cat', "$chroot/etc/debian_version"]);
is(capture([qw(chroot chroot.d runuser -u nobody --
cat /etc/debian_version)]),
$reference);
# The remaining tests rely on device nodes to either exist or already
# being bind-mounted. Their setups are not prepared to deal with the
# conditions in an environment with an unshared user namespace as
# used in mmdebstrap.
if (defined $ENV{container} && $ENV{container} eq "mmdebstrap-unshare") {
return;
}
# The schroot behaviour proposed to fix #856877 and #983423 works,
# even inside (privileged) lxc.
check_fake_schroot(%params, reference => $reference, version => 'proposed');
check_fake_schroot(%params, reference => $reference, version => 'proposed',
extra_argv => ['--sbuild']);
# As of 1.6.10-3, or equivalently 1.6.10-11, the default profile
# certainly doesn't work in lxc >= 3 or in Docker:
# https://bugs.debian.org/983423
# It probably won't work in other container managers either, for
# similar reasons.
if (defined $params{container}) {
TODO: {
local $TODO = "schroot default profile doesn't work in lxc >= 3 or Docker";
check_fake_schroot(%params, reference => $reference,
version => '1.6.10-3');
}
}
else {
check_fake_schroot(%params, reference => $reference,
version => '1.6.10-3');
}
# schroot 1.6.10-3's sbuild profile does work in lxc, but only on newer
# kernels: https://bugs.debian.org/856877
if (Dpkg::Version->new($params{kernel}) < Dpkg::Version->new('4.7') &&
defined $params{container} && $params{container} eq 'lxc') {
TODO: {
local $TODO = "schroot --sbuild doesn't work in lxc on older ".
"kernels";
check_fake_schroot(%params, reference => $reference,
extra_argv => ['--sbuild']);
}
}
elsif (! $params{can_mknod_ptmx}) {
TODO: {
local $TODO = "schroot --sbuild doesn't work when /dev/ptmx is ".
"a symlink to /dev/pts/ptmx";
check_fake_schroot(%params, reference => $reference,
extra_argv => ['--sbuild']);
}
}
else {
check_fake_schroot(%params, reference => $reference,
extra_argv => ['--sbuild']);
}
# pbuilder >= 0.228.6 works fine
check_fake_pbuilder(%params, reference => $reference,
version => '0.231');
# Older pbuilder doesn't work if we are in a container where we can't
# create the /dev/ptmx device node: https://bugs.debian.org/841935
if (! $params{can_mknod_ptmx}) {
TODO: {
local $TODO = "pbuilder 0.228.4-1 doesn't work when /dev/ptmx is ".
"a symlink to /dev/pts/ptmx";
check_fake_pbuilder(%params, reference => $reference,
version => '0.228.4-1');
}
}
else {
check_fake_pbuilder(%params, reference => $reference,
version => '0.228.4-1');
}
}
# Specify https mirror to check https mirror specific problem
# https://bugs.debian.org/896071
my $mirror = 'https://deb.debian.org/debian';
my $tmp = $ENV{AUTOPKGTEST_TMP};
die "no autopkgtest temporary directory specified" unless $tmp;
chdir $tmp or die "chdir $tmp: $!";
$ENV{LC_ALL} = 'C.UTF-8';
# Try to inherit a Debian mirror from the host
foreach my $file ('/etc/apt/sources.list',
glob('/etc/apt/sources.list.d/*.list')) {
open(my $fh, '<', $file);
while (<$fh>) {
if (m{^deb\s+(http://[-a-zA-Z0-9.:]+/debian)\s}) {
$mirror = $1;
last;
}
}
close $fh;
}
if (run(['ischroot'], '>&2')) {
diag("In a chroot according to ischroot(1)");
}
else {
diag("Not in a chroot according to ischroot(1)");
}
my $virtualization;
if ($^O ne 'linux') {
diag("Cannot use systemd-detect-virt on non-Linux");
}
elsif (run(['systemd-detect-virt', '--vm'], '>', \$virtualization)) {
chomp $virtualization;
diag("Virtualization: $virtualization");
}
else {
$virtualization = undef;
diag("Virtualization: (not in a virtual machine)");
}
my $in_container = 0;
my $container;
if ($^O ne 'linux') {
diag("Cannot use systemd-detect-virt on non-Linux");
}
elsif (run(['systemd-detect-virt', '--container'], '>', \$container)) {
$in_container = 1;
chomp $container;
diag("Container: $container");
}
else {
$container = undef;
diag("Container: (not in a container)");
}
my $kernel = capture([qw(uname -r)]);
chomp $kernel;
open(my $fh, '<', '/proc/self/mountinfo');
while (<$fh>) {
chomp;
diag("mountinfo: $_");
}
close $fh;
my $output;
if (verbose_run([qw(ls -l /dev/ptmx)], '>', \$output)) {
diag("/dev/ptmx: $output");
}
else {
diag("Unable to list /dev/ptmx");
}
if (verbose_run([qw(ls -l /dev/pts/ptmx)], '>', \$output)) {
diag("/dev/pts/ptmx: $output");
}
else {
diag("Unable to list /dev/pts/ptmx");
}
my $can_mknod_ptmx;
if (run([qw(mknod -m000 ptmx c 5 2)], '&>', '/dev/null')) {
diag("mknod ptmx succeeded");
$can_mknod_ptmx = 1;
}
else {
diag("mknod ptmx failed, are we in a container?");
$can_mknod_ptmx = 0;
}
my $distro_info = DebianDistroInfo->new;
my $testing = $distro_info->testing;
# Should specify multiple components for checking (see Bug#898738)
if (!verbose_run([length($ENV{DEBOOTSTRAP_SCRIPT}) ? $ENV{DEBOOTSTRAP_SCRIPT} : 'debootstrap',
'--include=debootstrap,debian-archive-keyring,gnupg,hello,systemd',
"--variant=$variant",
'--components=main,contrib,non-free',
$testing, 'chroot.d', $mirror], '>&2')) {
BAIL_OUT("debootstrap failed: $?");
}
if (!verbose_run([qw(find chroot.d/dev -ls)], '>&2')) {
BAIL_OUT("Unable to list contents of chroot's /dev: $?");
}
if ($check_non_docker_env) {
check_chroot(chroot => 'chroot.d', can_mknod_ptmx => $can_mknod_ptmx,
kernel => $kernel, container => $container, has_systemd => 1);
}
if ($^O ne 'linux') {
diag("Cannot use systemd-nspawn on non-Linux");
}
elsif ($in_container) {
diag('in a container according to systemd-detect-virt, not trying to '.
'use systemd-nspawn');
}
elsif (defined $ENV{container} && length $ENV{container}) {
diag('in a container according to $container, not trying to '.
'use systemd-nspawn');
}
elsif (! -d '/run/systemd/system') {
diag('systemd not booted, not trying to use systemd-nspawn');
}
else {
if (!verbose_run(['systemd-nspawn', '-D', 'chroot.d',
"--bind=$ENV{AUTOPKGTEST_TMP}:/mnt",
'--bind-ro=/usr/sbin/debootstrap',
'--bind-ro=/usr/share/debootstrap',
'--',
'debootstrap', '--include=hello', "--variant=$variant",
$testing, '/mnt/from-nspawn.d', $mirror], '>&2')) {
BAIL_OUT("debootstrap wrapped in systemd-nspawn failed: $?");
}
check_chroot(chroot => "$ENV{AUTOPKGTEST_TMP}/from-nspawn.d", can_mknod_ptmx => 0,
kernel => $kernel, container => "nspawn");
}
if (!defined $ENV{container} || $ENV{container} ne "mmdebstrap-unshare") {
if (!run([qw(rm -fr --one-file-system chroot.d)], '>&2')) {
BAIL_OUT('Unable to remove chroot.d');
}
} else {
if (!run([qw(env --chdir=chroot.d find . -mount -mindepth 1 -delete)], '>&2')) {
BAIL_OUT('Unable to remove contents of chroot.d');
}
}
done_testing;
# vim:set sw=4 sts=4 et:

37
debian/tests/fake/pbuilder-0.228.4-1 vendored Executable file
View file

@ -0,0 +1,37 @@
#!/bin/sh
# fake/pbuilder-0.228.4-1 -- emulate how pbuilder/0.228.4-1 would chroot.
#
# Please do not modify this script without verifying that its behaviour
# is still equivalent to the stated versions of pbuilder.
#
# This version has #841935 unfixed. It mounts /dev/pts, without explicitly
# requesting a new instance or a usable /dev/pts/ptmx.
# (There is of course a lot more that it does, but these are the parts that
# affect pty users like script(1).)
#
# Reference: pbuilder/pbuilder-modules, search for dev/pts.
#
# Copyright © 2017 Simon McVittie
# SPDX-License-Identifier: MIT
# (see debian/copyright)
set -e
chroot="$1"
shift
if test -z "$chroot" || test -z "$1"; then
echo "Usage: $0 CHROOT COMMAND...">&2
exit 2
fi
mkdir -p "$chroot/dev/pts"
mount -t devpts none "$chroot/dev/pts" -onoexec,nosuid,gid=5,mode=620
ls -l "$chroot/dev/ptmx" | sed -e 's/^/# fake-pbuilder: /' >&2
ls -l "$chroot/dev/pts/ptmx" | sed -e 's/^/# fake-pbuilder: /' >&2
e=0
chroot "$chroot" "$@" || e=$?
umount "$chroot/dev/pts"
exit "$e"

64
debian/tests/fake/pbuilder-0.231 vendored Executable file
View file

@ -0,0 +1,64 @@
#!/bin/sh
# fake/pbuilder-0.231 -- emulate how pbuilder >= 0.228.6 sets up its chroot
#
# Please do not modify this script without verifying that its behaviour
# is still equivalent to the stated versions of pbuilder. If a future
# version of pbuilder changes its behaviour, please copy this script and
# modify the copy instead.
#
# This has #841935 fixed (commit 4a4134dd). It was checked for equivalence
# to pbuilder 0.231, which is the version included in Debian 11 and 12,
# but the versions in Debian 10 and 9 have equivalent code here.
#
# Reference: pbuilder/pbuilder-modules, search for dev/pts.
#
# Copyright © 2017-2021 Simon McVittie
# SPDX-License-Identifier: MIT
# (see debian/copyright)
set -e
BUILDPLACE="$1"
shift
if test -z "$BUILDPLACE" || test -z "$1"; then
echo "Usage: $0 CHROOT COMMAND...">&2
exit 2
fi
mkdir -p "$BUILDPLACE/dev/pts"
TTYGRP=5
TTYMODE=620
mount -t devpts devpts "$BUILDPLACE/dev/pts" -o "newinstance,noexec,nosuid,gid=$TTYGRP,mode=$TTYMODE,ptmxmode=0666"
mounted_ptmx=no
if ! [ -L "$BUILDPLACE/dev/ptmx" ]; then
echo "# fake-pbuilder: redirecting /dev/ptmx to /dev/pts/ptmx" >&2
mount --bind "$BUILDPLACE/dev/pts/ptmx" "$BUILDPLACE/dev/ptmx"
mounted_ptmx=yes
fi
mounted_console=no
if stdin_tty="$(tty)"; then
if [ ! -e "$BUILDPLACE/dev/console" ]; then
echo "# fake-pbuilder: creating /dev/console" >&2
mknod -m600 "$BUILDPLACE/dev/console" c 5 1
fi
echo "# fake-pbuilder: mounting $stdin_tty over /dev/console" >&2
mount --bind "$stdin_tty" "$BUILDPLACE/dev/console"
mounted_console=yes
fi
ls -l "$BUILDPLACE/dev/console" | sed -e 's/^/# fake-pbuilder: /' >&2
ls -l "$BUILDPLACE/dev/ptmx" | sed -e 's/^/# fake-pbuilder: /' >&2
ls -l "$BUILDPLACE/dev/pts/ptmx" | sed -e 's/^/# fake-pbuilder: /' >&2
e=0
chroot "$BUILDPLACE" "$@" || e=$?
[ "$mounted_console" = no ] || umount "$BUILDPLACE/dev/console"
[ "$mounted_ptmx" = no ] || umount "$BUILDPLACE/dev/ptmx"
umount "$BUILDPLACE/dev/pts"
exit "$e"

58
debian/tests/fake/schroot-1.6.10-3 vendored Executable file
View file

@ -0,0 +1,58 @@
#!/bin/sh
# fake/schroot-1.6.10-3 -- emulate how schroot/1.6.10-3 would chroot.
#
# Please do not modify this script without verifying that its behaviour
# is still equivalent to the stated versions of schroot. If a future
# version of schroot changes its behaviour, please copy this script and
# modify the copy instead.
#
# This version has #856877 unfixed. It bind-mounts /dev/pts and maybe
# /dev from the host system, rather than creating a new instance of /dev/pts.
# (There is of course a lot more that it does, but these are the parts that
# affect pty users like script(1).)
#
# Copyright © 2017-2023 Simon McVittie
# SPDX-License-Identifier: MIT
# (see debian/copyright)
set -e
# Reference: /etc/schroot/default/fstab
# (in schroot source tree: etc/profile-templates/default/linux/fstab)
bind_dev=yes
while true; do
case "$1" in
(--sbuild)
shift
# Reference: /etc/schroot/sbuild/fstab
# (source: etc/profile-templates/sbuild/linux/fstab)
bind_dev=no
;;
(*)
break
esac
done
chroot="$1"
shift
if test -z "$chroot" || test -z "$1"; then
echo "Usage: $0 CHROOT COMMAND...">&2
exit 2
fi
[ "$bind_dev" = no ] || mount --bind /dev "$chroot/dev"
mount --bind /dev/pts "$chroot/dev/pts"
ls -l "/dev/ptmx" | sed -e 's/^/# fake-schroot: outside chroot: /' >&2
ls -l "/dev/pts/ptmx" | sed -e 's/^/# fake-schroot: outside chroot: /' >&2
ls -l "$chroot/dev/ptmx" | sed -e 's/^/# fake-schroot: /' >&2
ls -l "$chroot/dev/pts/ptmx" | sed -e 's/^/# fake-schroot: /' >&2
e=0
chroot "$chroot" "$@" || e=$?
umount "$chroot/dev/pts"
[ "$bind_dev" = no ] || umount "$chroot/dev"
exit "$e"

87
debian/tests/fake/schroot-proposed vendored Executable file
View file

@ -0,0 +1,87 @@
#!/bin/sh
# fake/schroot-proposed -- emulate proposed mount behaviour for schroot
#
# This version emulates the behaviour proposed on #856877. If it needs
# changing, please update the proposed patch on #856877 too.
#
# Copyright © 2017-2023 Simon McVittie
# SPDX-License-Identifier: MIT
# (see debian/copyright)
set -e
# Reference: /etc/schroot/default/fstab
# (in schroot source tree: etc/profile-templates/default/linux/fstab)
bind_dev=yes
while true; do
case "$1" in
(--sbuild)
shift
# Reference: /etc/schroot/sbuild/fstab
# (source: etc/profile-templates/sbuild/linux/fstab)
bind_dev=no
;;
(*)
break
esac
done
CHROOT_PATH="$1"
shift
if test -z "$CHROOT_PATH" || test -z "$1"; then
echo "Usage: $0 CHROOT COMMAND...">&2
exit 2
fi
[ "$bind_dev" = no ] || mount --bind /dev "$CHROOT_PATH/dev"
mount -t devpts -o rw,newinstance,ptmxmode=666,mode=620,gid=5 /dev/pts "$CHROOT_PATH/dev/pts"
ls -l "/dev/ptmx" | sed -e 's/^/# fake-schroot: outside chroot: /' >&2
ls -l "/dev/pts/ptmx" | sed -e 's/^/# fake-schroot: outside chroot: /' >&2
ls -l "$CHROOT_PATH/dev/ptmx" | sed -e 's/^/# fake-schroot: after first step: /' >&2
ls -l "$CHROOT_PATH/dev/pts/ptmx" | sed -e 's/^/# fake-schroot: after first step: /' >&2
mounted_ptmx=no
# Depending on how /dev was set up, /dev/ptmx might either be
# character device (5,2), or a symbolic link to pts/ptmx.
# Either way we want it to be equivalent to /dev/pts/ptmx, assuming
# both exist.
if [ -e "$CHROOT_PATH/dev/pts/ptmx" ] && \
[ -e "$CHROOT_PATH/dev/ptmx" ] && \
! [ "$CHROOT_PATH/dev/pts/ptmx" -ef "$CHROOT_PATH/dev/ptmx" ]; then
mount --bind "$CHROOT_PATH/dev/pts/ptmx" "$CHROOT_PATH/dev/ptmx"
mounted_ptmx=yes
fi
mounted_console=no
# If schroot was invoked from a terminal, we still want to be able to
# access that terminal. lxc and systemd-nspawn achieve this by
# binding it onto /dev/console; so can we.
if stdin_tty="$(tty)"; then
if [ ! -e "$CHROOT_PATH/dev/console" ]; then
# We need something to mount onto, and it might as well be
# the correctly-numbered device node.
mknod -m700 "$CHROOT_PATH/dev/console" c 5 1
fi
mount --bind "$stdin_tty" "$CHROOT_PATH/dev/console"
mounted_console=yes
fi
ls -l "$CHROOT_PATH/dev/console" | sed -e 's/^/# fake-schroot: after fixing mounts: /' >&2
ls -l "$CHROOT_PATH/dev/ptmx" | sed -e 's/^/# fake-schroot: after fixing mounts: /' >&2
ls -l "$CHROOT_PATH/dev/pts/ptmx" | sed -e 's/^/# fake-schroot: after fixing mounts: /' >&2
e=0
chroot "$CHROOT_PATH" "$@" || e=$?
[ "$mounted_console" = no ] || umount "$CHROOT_PATH/dev/console"
[ "$mounted_ptmx" = no ] || umount "$CHROOT_PATH/dev/ptmx"
umount "$CHROOT_PATH/dev/pts"
[ "$bind_dev" = no ] || umount "$CHROOT_PATH/dev"
exit "$e"

98
debian/tests/out-of-order-mitm.py vendored Normal file
View file

@ -0,0 +1,98 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2023 Debian Install System Team <debian-boot@lists.debian.org>
#
# SPDX-License-Identifier: MIT
"""Flask app which MITM's an archive to generate out-of-order apt lists.
Specifically, it prepends an additional Packages file stanza for a non-existent
lower version of apt: a fixed version of debootstrap will find the second
(correct) apt stanza and succeed; a broken version of debootstrap will find
only the first (non-existent) apt stanza and fail.
"""
import functools
import gzip
import hashlib
import os
import requests
from debian.deb822 import Packages
from flask import Flask, redirect
app = Flask(__name__)
ARCH = os.environ.get("FLASK_ARCH", "amd64")
DIST = os.environ.get("FLASK_DIST", "trixie")
DISTRO = os.environ.get("FLASK_DISTRO", "debian")
MIRROR = os.environ.get("FLASK_MIRROR", "http://deb.debian.org")
if DISTRO in ("debian", "pureos"):
hash_funcs = [hashlib.md5, hashlib.sha256]
else:
# Ubuntu includes SHA1 still
hash_funcs = [hashlib.md5, hashlib.sha1, hashlib.sha256]
def _munge_release_file(url: str) -> bytes:
"""Given a Release file URL, rewrite it for our modified Packages content."""
original = requests.get(MIRROR + "/" + url).content
packages_content = _packages_content(
f"{DISTRO}/dists/{DIST}/main/binary-{ARCH}/Packages"
)
size = bytes(str(len(packages_content)), "ascii")
sums = [
bytes(hash_func(packages_content).hexdigest(), "ascii")
for hash_func in hash_funcs
]
new_lines = []
filename = f"main/binary-{ARCH}/Packages".encode("ascii")
for line in original.splitlines():
if not line.endswith(filename):
new_lines.append(line)
continue
new_lines.append(b" ".join([b"", sums.pop(0), size, filename]))
return b"\n".join(new_lines)
@functools.lru_cache
def _packages_content(url: str) -> bytes:
"""Given a Packages URL, fetch it and prepend a broken apt stanza."""
resp = requests.get(MIRROR + "/" + url + ".gz")
upstream_content = gzip.decompress(resp.content)
# Find the first `apt` stanza
for stanza in Packages.iter_paragraphs(upstream_content):
if stanza["Package"] == "apt":
break
# Generate the broken stanza
new_version = stanza["Version"] + "~test"
stanza["Filename"] = stanza["Filename"].replace(stanza["Version"], new_version)
stanza["Version"] = new_version
# Prepend the stanza to the upstream content
return bytes(stanza) + b"\n" + upstream_content
@app.route("/<path:url>", methods=["GET", "POST"])
def root(url):
"""Handler for all requests."""
if (
url == f"{DISTRO}/dists/{DIST}/InRelease"
or "by-hash" in url
or "Packages.xz" in url
or "Packages.gz" in url
):
# 404 these URLs to force clients to fetch by path and without compression, to
# make MITM easier
return "", 404
if url == f"{DISTRO}/dists/{DIST}/Release":
# If Release is being fetched, return our modified version
return _munge_release_file(url)
if url == f"{DISTRO}/dists/{DIST}/main/binary-{ARCH}/Packages":
# If Packages is being fetched, return our modified version
return _packages_content(url)
# For anything we don't need to modify, redirect clients to upstream mirror
return redirect(f"{MIRROR}/{url}")

34
debian/tests/unsorted-packages-files vendored Executable file
View file

@ -0,0 +1,34 @@
#!/bin/sh
# This test runs the out-of-order-mitm.py Flask app which debootstrap is then
# pointed at.
# out-of-order-mitm.py will return a Packages file which has an additional
# `apt` stanza prepended, with the Version and Filename adjusted to point at
# a lower, non-existent version. Versions of debootstrap which process
# _all_ Packages files entries will find the original stanza later in the file
# (and succesfully fetch the corresponding package file): versions that don't
# will find the prepended stanza and fail (with a 404 of the nonexistent
# package file).
export FLASK_ARCH="$(dpkg --print-architecture)"
export FLASK_DIST=testing
export FLASK_DISTRO=debian
export FLASK_MIRROR=http://deb.debian.org
export PATH=$PATH:/usr/sbin
# Launch our MitM "mirror" server, ensure that request logging is sent to stdout
PYTHONDONTWRITEBYTECODE=true FLASK_APP=debian/tests/out-of-order-mitm.py flask run 2>&1 &
flask_pid=$!
# Give Flask time to come up
sleep 2
tempdir=$(mktemp -d)
# Run debootstrap against our MitM "mirror", ignoring the inevitable GPG errors
debootstrap --download-only --variant minbase --no-check-sig ${FLASK_DIST} $tempdir http://127.0.0.1:5000/${FLASK_DISTRO}/
rc=$?
rm -rf $tempdir
kill $flask_pid
exit $rc