functional2: tidy up some of the NAR handling

Change-Id: Iaa096f7daefa71cad7ac787bce78d91fa4176541
This commit is contained in:
Jade Lovelace
2025-01-24 17:10:44 -08:00
parent c57a99e9c3
commit aa1aacb3e0
3 changed files with 38 additions and 23 deletions
+21 -19
View File
@@ -1,5 +1,7 @@
import pytest
import os
import unicodedata
from pathlib import Path
from ..testlib.nar import *
from ..testlib.fixtures import Nix
from io import BytesIO
@@ -12,59 +14,59 @@ meow_nfd = meow_nfd_.encode('utf-8')
assert meow_nfc != meow_nfd
EVIL_NARS: list[tuple[str, NarItem]] = [
('valid-dir-1', Directory([
(b'a-nested', Directory([
('valid-dir-1', DirectoryUnordered([
(b'a-nested', DirectoryUnordered([
(b'loopy', Symlink(b'../abc-nested'))
])),
(b'b-file', Regular(False, b'meow kbity')),
(b'c-exe', Regular(True, b'#!/usr/bin/env cat\nmeow kbity')),
])),
('invalid-slashes-1', Directory([
('invalid-slashes-1', DirectoryUnordered([
(b'meow', Symlink(b'meowmeow')),
(b'meow/nya', Regular(False, b'eepy')),
])),
('invalid-dot-1', Directory([
('invalid-dot-1', DirectoryUnordered([
(b'.', Symlink(b'meowmeow')),
])),
('invalid-dot-2', Directory([
('invalid-dot-2', DirectoryUnordered([
(b'..', Symlink(b'meowmeow')),
])),
('invalid-nul-1', Directory([
('invalid-nul-1', DirectoryUnordered([
(b'meow\0nya', Symlink(b'meowmeow')),
])),
('invalid-misorder-1', Directory([
('invalid-misorder-1', DirectoryUnordered([
(b'zzz', Regular(False, b'eepy')),
(b'kbity', Regular(False, b'meow')),
])),
('invalid-dupe-1', Directory([
('invalid-dupe-1', DirectoryUnordered([
(b'zzz', Regular(False, b'eepy')),
(b'zzz', Regular(False, b'meow')),
])),
('invalid-dupe-2', Directory([
(b'zzz', Directory([
('invalid-dupe-2', DirectoryUnordered([
(b'zzz', DirectoryUnordered([
(b'meow', Regular(False, b'kbity'))
])),
(b'zzz', Regular(False, b'meow')),
])),
('invalid-dupe-3', Directory([
(b'zzz', Directory([
('invalid-dupe-3', DirectoryUnordered([
(b'zzz', DirectoryUnordered([
(b'meow', Regular(False, b'kbity'))
])),
(b'zzz', Directory([
(b'zzz', DirectoryUnordered([
(b'meow', Regular(False, b'kbityy'))
])),
])),
('invalid-dupe-4', Directory([
('invalid-dupe-4', DirectoryUnordered([
(b'zzz', Symlink(b'../kbity')),
(b'zzz', Directory([
(b'zzz', DirectoryUnordered([
(b'meow', Regular(False, b'kbityy'))
])),
])),
('invalid-casehack-1', Directory([
('invalid-casehack-1', DirectoryUnordered([
(b'ZZZ~nix~case~hack~2', Regular(False, b'meow')),
(b'zzz~nix~case~hack~1', Regular(False, b'eepy')),
])),
('invalid-casehack-2', Directory([
('invalid-casehack-2', DirectoryUnordered([
(b'ZZZ~nix~case~hack~1', Regular(False, b'meow')),
(b'zzz~nix~case~hack~1', Regular(False, b'eepy')),
])),
@@ -106,12 +108,12 @@ def test_unicode_evil_nar(nix: Nix, tmp_path: Path):
# normalization is not applied to this system
pytest.skip('filesystem does not use unicode normalization')
test_evil_nar(nix, 'invalid-unicode-normalization-1', Directory([
test_evil_nar(nix, 'invalid-unicode-normalization-1', DirectoryUnordered([
# méow
(meow_nfd, Regular(False, b'eepy')),
(meow_nfc, Symlink(b'meowmeow')),
]))
test_evil_nar(nix, 'invalid-unicode-normalization-2', Directory([
test_evil_nar(nix, 'invalid-unicode-normalization-2', DirectoryUnordered([
# méow
(meow_nfd, Symlink(b'meowmeow')),
(meow_nfc, Regular(False, b'eepy')),
@@ -20,6 +20,8 @@ class CommandResult:
def ok(self):
if self.rc != 0:
print('stdout:', self.stdout_s)
print('stderr:', self.stderr_s)
raise subprocess.CalledProcessError(returncode=self.rc,
cmd=self.cmd,
stderr=self.stderr,
@@ -28,6 +30,8 @@ class CommandResult:
def expect(self, rc: int):
if self.rc != rc:
print('stdout:', self.stdout_s)
print('stderr:', self.stderr_s)
raise subprocess.CalledProcessError(returncode=self.rc,
cmd=self.cmd,
stderr=self.stderr,
+13 -4
View File
@@ -7,14 +7,14 @@ See "The Purely Functional Software Deployment Model", fig. 5.2 [1].
from abc import ABCMeta, abstractmethod
import dataclasses
import struct
from pathlib import Path
from typing import Protocol
import unicodedata
class Writable(Protocol):
"""Realistically could just be IOBase but this is more constrained"""
def write(self, data: bytes, /) -> int: ...
def write(self, data: bytes, /) -> int:
...
@dataclasses.dataclass
@@ -68,7 +68,7 @@ class Regular(NarItem):
@dataclasses.dataclass
class Directory(NarItem):
class DirectoryUnordered(NarItem):
entries: list[tuple[bytes, NarItem]]
"""Entries in the directory, not required to be in order because this nar is evil"""
type_ = b'directory'
@@ -91,6 +91,15 @@ class Directory(NarItem):
self.entry(out, name, entry)
@dataclasses.dataclass
class Directory(NarItem):
entries: dict[bytes, NarItem]
def serialize_type(self, out: NarListener):
for name, item in sorted(self.entries.items(), key=lambda v: v[0]):
DirectoryUnordered.entry(out, name, item)
@dataclasses.dataclass
class Symlink(NarItem):
target: bytes