updated the installer so that it should actually work
Some checks failed
Build / build (push) Failing after 5m23s

This commit is contained in:
tumillanino
2025-11-11 18:57:02 +11:00
parent a7bd4d9457
commit 33dd952ad4
583 changed files with 161651 additions and 67 deletions

View File

View File

@@ -0,0 +1,53 @@
from pathlib import Path
import pytest
@pytest.fixture(scope='session')
def config_fixture() -> Path:
return Path(__file__).parent / 'data' / 'test_config.json'
@pytest.fixture(scope='session')
def btrfs_config_fixture() -> Path:
return Path(__file__).parent / 'data' / 'test_config_btrfs.json'
@pytest.fixture(scope='session')
def creds_fixture() -> Path:
return Path(__file__).parent / 'data' / 'test_creds.json'
@pytest.fixture(scope='session')
def encrypted_creds_fixture() -> Path:
return Path(__file__).parent / 'data' / 'test_encrypted_creds.json'
@pytest.fixture(scope='session')
def deprecated_creds_config() -> Path:
return Path(__file__).parent / 'data' / 'test_deprecated_creds_config.json'
@pytest.fixture(scope='session')
def deprecated_mirror_config() -> Path:
return Path(__file__).parent / 'data' / 'test_deprecated_mirror_config.json'
@pytest.fixture(scope='session')
def deprecated_audio_config() -> Path:
return Path(__file__).parent / 'data' / 'test_deprecated_audio_config.json'
@pytest.fixture(scope='session')
def mirrorlist_no_country_fixture() -> Path:
return Path(__file__).parent / 'data' / 'mirrorlists' / 'test_no_country'
@pytest.fixture(scope='session')
def mirrorlist_with_country_fixture() -> Path:
return Path(__file__).parent / 'data' / 'mirrorlists' / 'test_with_country'
@pytest.fixture(scope='session')
def mirrorlist_multiple_countries_fixture() -> Path:
return Path(__file__).parent / 'data' / 'mirrorlists' / 'test_multiple_countries'

View File

@@ -0,0 +1,16 @@
################################################################################
################# Arch Linux mirrorlist generated by Reflector #################
################################################################################
# With: reflector @/etc/xdg/reflector/reflector.conf
# When: 2025-01-11 05:37:57 UTC
# From: https://archlinux.org/mirrors/status/json/
# Retrieved: 2025-01-11 05:37:17 UTC
# Last Check: 2025-01-11 05:17:17 UTC
## United States
Server = https://geo.mirror.pkgbuild.com/$repo/os/$arch
Server = https://america.mirror.pkgbuild.com/$repo/os/$arch
## Australia
Server = https://au.mirror.pkgbuild.com/$repo/os/$arch

View File

@@ -0,0 +1,12 @@
################################################################################
################# Arch Linux mirrorlist generated by Reflector #################
################################################################################
# With: reflector @/etc/xdg/reflector/reflector.conf
# When: 2025-01-11 05:37:57 UTC
# From: https://archlinux.org/mirrors/status/json/
# Retrieved: 2025-01-11 05:37:17 UTC
# Last Check: 2025-01-11 05:17:17 UTC
Server = https://geo.mirror.pkgbuild.com/$repo/os/$arch
Server = https://america.mirror.pkgbuild.com/$repo/os/$arch

View File

@@ -0,0 +1,13 @@
################################################################################
################# Arch Linux mirrorlist generated by Reflector #################
################################################################################
# With: reflector @/etc/xdg/reflector/reflector.conf
# When: 2025-01-11 05:37:57 UTC
# From: https://archlinux.org/mirrors/status/json/
# Retrieved: 2025-01-11 05:37:17 UTC
# Last Check: 2025-01-11 05:17:17 UTC
## United States
Server = https://geo.mirror.pkgbuild.com/$repo/os/$arch
Server = https://america.mirror.pkgbuild.com/$repo/os/$arch

View File

@@ -0,0 +1,202 @@
{
"archinstall-language": "English",
"script": "test_script",
"app_config": {
"bluetooth_config": {
"enabled": true
},
"audio_config": {
"audio": "pipewire"
}
},
"auth_config": {
"u2f_config": {
"passwordless_sudo": true,
"u2f_login_method": "passwordless"
}
},
"audio_config": {
"audio": "pipewire"
},
"bootloader": "Systemd-boot",
"services": [
"service_1",
"service_2"
],
"disk_config": {
"config_type": "default_layout",
"btrfs_options": {
"snapshot_config": {
"type": "Snapper"
}
},
"device_modifications": [
{
"device": "/dev/sda",
"partitions": [
{
"btrfs": [],
"dev_path": null,
"flags": [
"boot"
],
"fs_type": "fat32",
"size": {
"sector_size": {
"unit": "B",
"value": 512
},
"unit": "MiB",
"value": 512
},
"mount_options": [],
"mountpoint": "/boot",
"obj_id": "2c3fa2d5-2c79-4fab-86ec-22d0ea1543c0",
"start": {
"sector_size": {
"unit": "B",
"value": 512
},
"unit": "MiB",
"value": 1
},
"status": "create",
"type": "primary"
},
{
"btrfs": [],
"dev_path": null,
"flags": [],
"fs_type": "ext4",
"size": {
"sector_size": {
"unit": "B",
"value": 512
},
"unit": "GiB",
"value": 32
},
"mount_options": [],
"mountpoint": "/",
"obj_id": "3e7018a0-363b-4d05-ab83-8e82d13db208",
"start": {
"sector_size": {
"unit": "B",
"value": 512
},
"unit": "MiB",
"value": 513
},
"status": "create",
"type": "primary"
},
{
"btrfs": [],
"dev_path": null,
"flags": [],
"fs_type": "ext4",
"size": {
"sector_size": {
"unit": "B",
"value": 512
},
"unit": "GiB",
"value": 32
},
"mount_options": [],
"mountpoint": "/home",
"obj_id": "ce58b139-f041-4a06-94da-1f8bad775d3f",
"start": {
"sector_size": {
"unit": "B",
"value": 512
},
"unit": "MiB",
"value": 33281
},
"status": "create",
"type": "primary"
}
],
"wipe": true
}
]
},
"hostname": "archy",
"kernels": [
"linux-zen"
],
"locale_config": {
"kb_layout": "us",
"sys_enc": "UTF-8",
"sys_lang": "en_US"
},
"mirror_config": {
"custom_servers": [
{
"url": "https://mymirror.com/$repo/os/$arch"
}
],
"mirror_regions": {
"Australia": [
"http://archlinux.mirror.digitalpacific.com.au/$repo/os/$arch"
]
},
"optional_repositories": [
"testing"
],
"custom_repositories": [
{
"name": "myrepo",
"url": "https://myrepo.com/$repo/os/$arch",
"sign_check": "Required",
"sign_option": "TrustAll"
}
]
},
"network_config": {
"type": "manual",
"nics": [
{
"iface": "eno1",
"ip": "192.168.1.15/24",
"dhcp": true,
"gateway": "192.168.1.1",
"dns": [
"192.168.1.1",
"9.9.9.9"
]
}
]
},
"ntp": true,
"packages": [
"firefox"
],
"parallel_downloads": 66,
"profile_config": {
"gfx_driver": "All open-source",
"greeter": "lightdm-gtk-greeter",
"profile": {
"custom_settings": {
"Hyprland": {
"seat_access": "polkit"
},
"Sway": {
"seat_access": "seatd"
}
},
"details": [
"Sway",
"Hyprland"
],
"main": "Desktop"
}
},
"custom_commands": [
"echo 'Hello, World!'"
],
"swap": false,
"timezone": "UTC",
"version": "3.0.2"
}

View File

@@ -0,0 +1,11 @@
{
"root_enc_password": "password_hash",
"users": [
{
"enc_password": "password_hash",
"sudo": true,
"username": "user_name",
"groups": ["wheel"]
}
]
}

View File

@@ -0,0 +1,5 @@
{
"audio_config": {
"audio": "pipewire"
}
}

View File

@@ -0,0 +1,11 @@
{
"!root-password": "rootPwd",
"!users": [
{
"!password": "userPwd",
"sudo": true,
"username": "user_name",
"groups": ["wheel"]
}
]
}

View File

@@ -0,0 +1,18 @@
{
"additional-repositories": ["testing"],
"mirror_config": {
"custom_mirrors": [
{
"name": "my_mirror",
"sign_check": "Optional",
"sign_option": "TrustedOnly",
"url": "example.com"
}
],
"mirror_regions": {
"Australia": [
"http://archlinux.mirror.digitalpacific.com.au/$repo/os/$arch"
]
}
}
}

View File

@@ -0,0 +1 @@
$argon2id$9lv5DTin0wusAc0tFPxbkw==$Z0FBQUFBQm4temxTbzJnd09OQmVCbU1DTGg0akNBMXNoeFI1UTlHVGRiVzF0UUFDRW9rVDRpeDVaVENVb1NGMzhZc0RReEZ4MmNtdkc3dHctU3BlNXdXb01UVWJibnYwZmVYRXZkbk9TQlUxUTVkN3Z6NWRfUTNVYlVUS3lzckhpNERJeW5mOUcxdnJqU2loVl95dlRBdWdEZXlCOVZyRHZRaEk2NURUWGRROGpEeExpdWtGU3ZTQ0FqTFFEMEozMmJEQkxabW1Wcjg2cXdEVllfYXYzN0p0eE9PRHVkZnFNcWZnY2h3cVJhVjA3S1Q2MER5RWZrb0FUTnJobW5icERzYUNVZE5iT3VLLWFtLTFDZVdoMUFub3FGQzBHcGFFNVRVbTBZM2ZqXzRERGlvSEJndWFma25hYlpvOHllUEVOZUVmc3dCN215NjlrdHVYNElfWGl5Ny1xTVlRWWw3V0VTSGRONENWbTdPalMxY1BnUGs3eFZoRERnOXNGSW9zRGZub2xQSEZSODFKVGxtdzNyZlpfeHdMSkJZUUNPQUZUWHNEd25KVWpwZTV2LVNyb1pzSFF6SGg3c3RldEpwLUVnQ0w1US1mN2l6MmdVLTZSSHpvNVdtcWhTaHVXMGJUczBFN2s0VXctUEo1OUdzNUs4bW9sbnpfcmJmQzNxSVNPM2NVeWktek5QaFU=

View File

@@ -0,0 +1,373 @@
import os
from importlib.metadata import version
from pathlib import Path
from pytest import MonkeyPatch
from archinstall.default_profiles.profile import GreeterType
from archinstall.lib.args import ArchConfig, ArchConfigHandler, Arguments
from archinstall.lib.hardware import GfxDriver
from archinstall.lib.models.application import ApplicationConfiguration, Audio, AudioConfiguration, BluetoothConfiguration
from archinstall.lib.models.authentication import AuthenticationConfiguration, U2FLoginConfiguration, U2FLoginMethod
from archinstall.lib.models.bootloader import Bootloader
from archinstall.lib.models.device import DiskLayoutConfiguration, DiskLayoutType
from archinstall.lib.models.locale import LocaleConfiguration
from archinstall.lib.models.mirrors import CustomRepository, CustomServer, MirrorConfiguration, MirrorRegion, SignCheck, SignOption
from archinstall.lib.models.network import NetworkConfiguration, Nic, NicType
from archinstall.lib.models.packages import Repository
from archinstall.lib.models.profile import ProfileConfiguration
from archinstall.lib.models.users import Password, User
from archinstall.lib.profile.profiles_handler import profile_handler
from archinstall.lib.translationhandler import translation_handler
def test_default_args(monkeypatch: MonkeyPatch) -> None:
monkeypatch.setattr('sys.argv', ['archinstall'])
handler = ArchConfigHandler()
args = handler.args
assert args == Arguments(
config=None,
config_url=None,
creds=None,
creds_url=None,
creds_decryption_key=None,
silent=False,
dry_run=False,
script=None,
mountpoint=Path('/mnt'),
skip_ntp=False,
skip_wkd=False,
skip_boot=False,
debug=False,
offline=False,
no_pkg_lookups=False,
plugin=None,
skip_version_check=False,
advanced=False,
)
def test_correct_parsing_args(
monkeypatch: MonkeyPatch,
config_fixture: Path,
creds_fixture: Path,
) -> None:
monkeypatch.setattr(
'sys.argv',
[
'archinstall',
'--config',
str(config_fixture),
'--config-url',
'https://example.com',
'--creds',
str(creds_fixture),
'--script',
'execution_script',
'--mountpoint',
'/tmp',
'--skip-ntp',
'--skip-wkd',
'--skip-boot',
'--debug',
'--offline',
'--no-pkg-lookups',
'--plugin',
'pytest_plugin.py',
'--skip-version-check',
'--advanced',
'--dry-run',
'--silent',
],
)
handler = ArchConfigHandler()
args = handler.args
assert args == Arguments(
config=config_fixture,
config_url='https://example.com',
creds=creds_fixture,
silent=True,
dry_run=True,
script='execution_script',
mountpoint=Path('/tmp'),
skip_ntp=True,
skip_wkd=True,
skip_boot=True,
debug=True,
offline=True,
no_pkg_lookups=True,
plugin='pytest_plugin.py',
skip_version_check=True,
advanced=True,
)
def test_config_file_parsing(
monkeypatch: MonkeyPatch,
config_fixture: Path,
creds_fixture: Path,
) -> None:
monkeypatch.setattr(
'sys.argv',
[
'archinstall',
'--config',
str(config_fixture),
'--creds',
str(creds_fixture),
],
)
handler = ArchConfigHandler()
arch_config = handler.config
# TODO: Use the real values from the test fixture instead of clearing out the entries
arch_config.disk_config.device_modifications = [] # type: ignore[union-attr]
assert arch_config == ArchConfig(
version=version('archinstall'),
script='test_script',
app_config=ApplicationConfiguration(
bluetooth_config=BluetoothConfiguration(enabled=True),
audio_config=AudioConfiguration(audio=Audio.PIPEWIRE),
),
auth_config=AuthenticationConfiguration(
root_enc_password=Password(enc_password='password_hash'),
users=[
User(
username='user_name',
password=Password(enc_password='password_hash'),
sudo=True,
groups=['wheel'],
),
],
u2f_config=U2FLoginConfiguration(
u2f_login_method=U2FLoginMethod.Passwordless,
passwordless_sudo=True,
),
),
locale_config=LocaleConfiguration(
kb_layout='us',
sys_lang='en_US',
sys_enc='UTF-8',
),
archinstall_language=translation_handler.get_language_by_abbr('en'),
disk_config=DiskLayoutConfiguration(
config_type=DiskLayoutType.Default,
device_modifications=[],
lvm_config=None,
mountpoint=None,
),
profile_config=ProfileConfiguration(
profile=profile_handler.parse_profile_config(
{
'custom_settings': {
'Hyprland': {
'seat_access': 'polkit',
},
'Sway': {
'seat_access': 'seatd',
},
},
'details': [
'Sway',
'Hyprland',
],
'main': 'Desktop',
}
),
gfx_driver=GfxDriver.AllOpenSource,
greeter=GreeterType.Lightdm,
),
mirror_config=MirrorConfiguration(
mirror_regions=[
MirrorRegion(
name='Australia',
urls=['http://archlinux.mirror.digitalpacific.com.au/$repo/os/$arch'],
),
],
custom_servers=[CustomServer('https://mymirror.com/$repo/os/$arch')],
optional_repositories=[Repository.Testing],
custom_repositories=[
CustomRepository(
name='myrepo',
url='https://myrepo.com/$repo/os/$arch',
sign_check=SignCheck.Required,
sign_option=SignOption.TrustAll,
),
],
),
network_config=NetworkConfiguration(
type=NicType.MANUAL,
nics=[
Nic(
iface='eno1',
ip='192.168.1.15/24',
dhcp=True,
gateway='192.168.1.1',
dns=[
'192.168.1.1',
'9.9.9.9',
],
),
],
),
bootloader=Bootloader.Systemd,
uki=False,
hostname='archy',
kernels=['linux-zen'],
ntp=True,
packages=['firefox'],
parallel_downloads=66,
swap=False,
timezone='UTC',
services=['service_1', 'service_2'],
custom_commands=["echo 'Hello, World!'"],
)
def test_deprecated_mirror_config_parsing(
monkeypatch: MonkeyPatch,
deprecated_mirror_config: Path,
) -> None:
monkeypatch.setattr(
'sys.argv',
[
'archinstall',
'--config',
str(deprecated_mirror_config),
],
)
handler = ArchConfigHandler()
arch_config = handler.config
assert arch_config.mirror_config == MirrorConfiguration(
mirror_regions=[
MirrorRegion(
name='Australia',
urls=['http://archlinux.mirror.digitalpacific.com.au/$repo/os/$arch'],
),
],
custom_servers=[],
optional_repositories=[Repository.Testing],
custom_repositories=[
CustomRepository(
name='my_mirror',
url='example.com',
sign_check=SignCheck.Optional,
sign_option=SignOption.TrustedOnly,
),
],
)
def test_deprecated_creds_config_parsing(
monkeypatch: MonkeyPatch,
deprecated_creds_config: Path,
) -> None:
monkeypatch.setattr(
'sys.argv',
[
'archinstall',
'--creds',
str(deprecated_creds_config),
],
)
handler = ArchConfigHandler()
arch_config = handler.config
assert arch_config.auth_config is not None
assert arch_config.auth_config.root_enc_password == Password(plaintext='rootPwd')
assert arch_config.auth_config.users == [
User(
username='user_name',
password=Password(plaintext='userPwd'),
sudo=True,
groups=['wheel'],
),
]
def test_deprecated_audio_config_parsing(
monkeypatch: MonkeyPatch,
deprecated_audio_config: Path,
) -> None:
monkeypatch.setattr(
'sys.argv',
[
'archinstall',
'--config',
str(deprecated_audio_config),
],
)
handler = ArchConfigHandler()
arch_config = handler.config
assert arch_config.app_config == ApplicationConfiguration(
audio_config=AudioConfiguration(audio=Audio.PIPEWIRE),
)
def test_encrypted_creds_with_arg(
monkeypatch: MonkeyPatch,
encrypted_creds_fixture: Path,
) -> None:
monkeypatch.setattr(
'sys.argv',
[
'archinstall',
'--creds',
str(encrypted_creds_fixture),
'--creds-decryption-key',
'master',
],
)
handler = ArchConfigHandler()
arch_config = handler.config
assert arch_config.auth_config is not None
assert arch_config.auth_config.root_enc_password == Password(enc_password='$y$j9T$FWCInXmSsS.8KV4i7O50H.$Hb6/g.Sw1ry888iXgkVgc93YNuVk/Rw94knDKdPVQw7')
assert arch_config.auth_config.users == [
User(
username='t',
password=Password(enc_password='$y$j9T$3KxMigAEnjtzbjalhLewE.$gmuoQtc9RNY/PmO/GxHHYvkZNO86Eeftg1Oc7L.QSO/'),
sudo=True,
groups=[],
),
]
def test_encrypted_creds_with_env_var(
monkeypatch: MonkeyPatch,
encrypted_creds_fixture: Path,
) -> None:
os.environ['ARCHINSTALL_CREDS_DECRYPTION_KEY'] = 'master'
monkeypatch.setattr(
'sys.argv',
[
'archinstall',
'--creds',
str(encrypted_creds_fixture),
],
)
handler = ArchConfigHandler()
arch_config = handler.config
assert arch_config.auth_config is not None
assert arch_config.auth_config.root_enc_password == Password(enc_password='$y$j9T$FWCInXmSsS.8KV4i7O50H.$Hb6/g.Sw1ry888iXgkVgc93YNuVk/Rw94knDKdPVQw7')
assert arch_config.auth_config.users == [
User(
username='t',
password=Password(enc_password='$y$j9T$3KxMigAEnjtzbjalhLewE.$gmuoQtc9RNY/PmO/GxHHYvkZNO86Eeftg1Oc7L.QSO/'),
sudo=True,
groups=[],
),
]

View File

@@ -0,0 +1,68 @@
import json
from pathlib import Path
from pytest import MonkeyPatch
from archinstall.lib.args import ArchConfigHandler
from archinstall.lib.configuration import ConfigurationOutput
def test_user_config_roundtrip(
monkeypatch: MonkeyPatch,
config_fixture: Path,
) -> None:
monkeypatch.setattr('sys.argv', ['archinstall', '--config', str(config_fixture)])
handler = ArchConfigHandler()
arch_config = handler.config
# the version is retrieved dynamically from an installed archinstall package
# as there is no version present in the test environment we'll set it manually
arch_config.version = '3.0.2'
config_output = ConfigurationOutput(arch_config)
test_out_dir = Path('/tmp/')
test_out_file = test_out_dir / config_output.user_configuration_file
config_output.save(test_out_dir)
result = json.loads(test_out_file.read_text())
expected = json.loads(config_fixture.read_text())
# the parsed config will check if the given device exists otherwise
# it will ignore the modification; as this test will run on various local systems
# and the CI pipeline there's no good way specify a real device so we'll simply
# copy the expected result to the actual result
result['disk_config']['config_type'] = expected['disk_config']['config_type']
result['disk_config']['device_modifications'] = expected['disk_config']['device_modifications']
assert json.dumps(
result['mirror_config'],
sort_keys=True,
) == json.dumps(
expected['mirror_config'],
sort_keys=True,
)
def test_creds_roundtrip(
monkeypatch: MonkeyPatch,
creds_fixture: Path,
) -> None:
monkeypatch.setattr('sys.argv', ['archinstall', '--creds', str(creds_fixture)])
handler = ArchConfigHandler()
arch_config = handler.config
config_output = ConfigurationOutput(arch_config)
test_out_dir = Path('/tmp/')
test_out_file = test_out_dir / config_output.user_credentials_file
config_output.save(test_out_dir, creds=True)
result = json.loads(test_out_file.read_text())
expected = json.loads(creds_fixture.read_text())
assert sorted(result.items()) == sorted(expected.items())

View File

@@ -0,0 +1,50 @@
from pathlib import Path
from archinstall.lib.mirrors import MirrorListHandler
def test_mirrorlist_no_country(mirrorlist_no_country_fixture: Path) -> None:
handler = MirrorListHandler(local_mirrorlist=mirrorlist_no_country_fixture)
handler.load_local_mirrors()
regions = handler.get_mirror_regions()
assert len(regions) == 1
assert regions[0].name == 'Local'
assert regions[0].urls == [
'https://geo.mirror.pkgbuild.com/$repo/os/$arch',
'https://america.mirror.pkgbuild.com/$repo/os/$arch',
]
def test_mirrorlist_with_country(mirrorlist_with_country_fixture: Path) -> None:
handler = MirrorListHandler(local_mirrorlist=mirrorlist_with_country_fixture)
handler.load_local_mirrors()
regions = handler.get_mirror_regions()
assert len(regions) == 1
assert regions[0].name == 'United States'
assert regions[0].urls == [
'https://geo.mirror.pkgbuild.com/$repo/os/$arch',
'https://america.mirror.pkgbuild.com/$repo/os/$arch',
]
def test_mirrorlist_multiple_countries(mirrorlist_multiple_countries_fixture: Path) -> None:
handler = MirrorListHandler(local_mirrorlist=mirrorlist_multiple_countries_fixture)
handler.load_local_mirrors()
regions = handler.get_mirror_regions()
assert len(regions) == 2
assert regions[0].name == 'United States'
assert regions[0].urls == [
'https://geo.mirror.pkgbuild.com/$repo/os/$arch',
'https://america.mirror.pkgbuild.com/$repo/os/$arch',
]
assert regions[1].name == 'Australia'
assert regions[1].urls == [
'https://au.mirror.pkgbuild.com/$repo/os/$arch',
]