Skip to content

Commit 6d7f3dc

Browse files
committed
Merge dev: M9.R.42.3 install drivers
2 parents d7f523f + de6608d commit 6d7f3dc

7 files changed

Lines changed: 348 additions & 14 deletions

File tree

_m9r42_install.sh

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
#!/usr/bin/env bash
2+
# M9.R.42 — install driver running the M9.R.42 ISO.
3+
#
4+
# Boots the M9.R.42 ISO under QEMU OVMF; autorun service drives the
5+
# installer through Phase 2 (disk apply); REPRO_DISK_DIAG=
6+
# /tmp/installer.disk-diag.log lands in the diag-persist tarball
7+
# because the M9.R.42.1 stage-de-rootfs.sh change included it in the
8+
# tar list.
9+
#
10+
# Outputs:
11+
# /tmp/m9r42_install.qcow2 — installed disk image
12+
# /tmp/m9r42_install.log — serial transcript
13+
# /tmp/m9r42_diag/ — extracted launcher diag tarball
14+
# installer.disk-diag.log — M9.R.42.1 kernel-state snapshots
15+
# AROUND each sgdisk + partprobe
16+
set -uo pipefail
17+
ISO="${ISO:-/opt/repro/reprobuild/recipes/reproos-iso/build/reproos.iso}"
18+
DISK="${DISK:-/tmp/m9r42_install.qcow2}"
19+
DIAG_DISK="${DIAG_DISK:-/tmp/m9r42_diag.qcow2}"
20+
INSTALL_LOG="${INSTALL_LOG:-/tmp/m9r42_install.log}"
21+
INSTALL_TIMEOUT="${INSTALL_TIMEOUT:-900}"
22+
DIAG_OUT="${DIAG_OUT:-/tmp/m9r42_diag}"
23+
24+
[ -f "$ISO" ] || { echo "ISO $ISO does not exist" >&2; exit 2; }
25+
26+
OVMF_FW="$(find /nix/store -maxdepth 5 -path '*OVMF*/FV/OVMF_CODE.fd' 2>/dev/null | head -1)"
27+
[ -n "$OVMF_FW" ] || { echo "No OVMF firmware in /nix/store" >&2; exit 2; }
28+
OVMF_DIR="$(dirname "$OVMF_FW")"
29+
OVMF_CODE="$OVMF_DIR/OVMF_CODE.fd"
30+
31+
INSTALL_VARS=/tmp/m9r42_install_ovmf_vars.fd
32+
cp "$OVMF_DIR/OVMF_VARS.fd" "$INSTALL_VARS"
33+
chmod u+w "$INSTALL_VARS"
34+
35+
date
36+
37+
rm -f "$DISK" "$DIAG_DISK"
38+
nix-shell -p qemu --run "qemu-img create -f qcow2 $DISK 32G" >/dev/null
39+
truncate -s 64M "$DIAG_DISK"
40+
41+
ISO_GRUB_HAS_AUTORUN="$(strings "$ISO" 2>/dev/null | grep -c 'repro.installer.autorun=1' || true)"
42+
if [ "${ISO_GRUB_HAS_AUTORUN:-0}" -lt 1 ]; then
43+
echo "[m9r42-install] WARNING: '$ISO' does NOT carry repro.installer.autorun=1"
44+
fi
45+
46+
echo "=== M9.R.42 instrumented install (timeout ${INSTALL_TIMEOUT}s) ===" | tee "$INSTALL_LOG"
47+
nix-shell -p qemu OVMF --run "
48+
tail -f /dev/null | qemu-system-x86_64 -machine q35 -m 4096 -smp 4 \
49+
-drive if=pflash,format=raw,readonly=on,file=$OVMF_CODE \
50+
-drive if=pflash,format=raw,file=$INSTALL_VARS \
51+
-cdrom $ISO \
52+
-drive file=$DISK,if=virtio,format=qcow2 \
53+
-drive file=$DIAG_DISK,if=virtio,format=raw \
54+
-nographic -serial mon:stdio -display none
55+
" >> "$INSTALL_LOG" 2>&1 &
56+
QPID=$!
57+
58+
T=0
59+
while kill -0 $QPID 2>/dev/null && [ $T -lt $INSTALL_TIMEOUT ]; do
60+
sleep 10
61+
T=$((T+10))
62+
done
63+
if kill -0 $QPID 2>/dev/null; then
64+
echo "[m9r42-install] ${INSTALL_TIMEOUT}s timeout, killing QEMU" | tee -a "$INSTALL_LOG"
65+
kill -9 $QPID 2>/dev/null
66+
fi
67+
wait $QPID 2>/dev/null
68+
69+
echo ""
70+
echo "=== M9.R.42 install log (last 200 lines, ANSI stripped) ==="
71+
sed 's/\x1B\[[0-9;]*[mK]//g' "$INSTALL_LOG" | tail -200
72+
73+
echo ""
74+
echo "=== M9.R.42 post-mortem diag extraction ==="
75+
rm -rf "$DIAG_OUT"
76+
mkdir -p "$DIAG_OUT"
77+
HEADER="$(dd if="$DIAG_DISK" bs=512 count=1 status=none 2>/dev/null | tr -d '\0' | head -1)"
78+
echo "diag-header=$HEADER"
79+
DIAG_SIZE="$(echo "$HEADER" | sed -nE 's/^M9R39DIAGv1 SIZE=([0-9]+).*$/\1/p')"
80+
if [ -z "$DIAG_SIZE" ] || [ "$DIAG_SIZE" = "0" ]; then
81+
echo "[m9r42-install] no M9R39DIAGv1 header on /dev/vdb; launcher diag-persist did not fire"
82+
date
83+
exit 0
84+
fi
85+
dd if="$DIAG_DISK" bs=512 skip=1 count=$(( (DIAG_SIZE + 511) / 512 )) \
86+
status=none 2>/dev/null \
87+
| head -c "$DIAG_SIZE" \
88+
> "$DIAG_OUT/installer.diag.tar.gz"
89+
tar -xzf "$DIAG_OUT/installer.diag.tar.gz" -C "$DIAG_OUT" 2>&1
90+
91+
echo ""
92+
echo "=== installer.rc ==="
93+
cat "$DIAG_OUT/installer.rc" 2>&1 || echo MISSING
94+
echo ""
95+
echo "=== installer.log (last 80) ==="
96+
tail -80 "$DIAG_OUT/installer.log" 2>&1
97+
echo ""
98+
echo "=== installer.disk-diag.log (M9.R.42.1 kernel-state snapshots) ==="
99+
if [ -f "$DIAG_OUT/installer.disk-diag.log" ]; then
100+
cat "$DIAG_OUT/installer.disk-diag.log"
101+
else
102+
echo "MISSING — REPRO_DISK_DIAG didn't reach the apply driver"
103+
fi
104+
echo ""
105+
date

_m9r42_iso_rebuild.sh

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
#!/usr/bin/env bash
2+
# M9.R.42 — ISO rebuild that picks up:
3+
# * the M9.R.42.1 disk-apply REPRO_DISK_DIAG hook (the diag file
4+
# lands at /tmp/installer.disk-diag.log; the launcher passes the
5+
# env var through strace + the diag-persist tarball includes it).
6+
# * the M9.R.41 install-root subcommand stays — only the disk_apply
7+
# module gained the kernel-state snapshot instrumentation.
8+
#
9+
# Same shape as _m9r41_iso_rebuild.sh.
10+
set -uo pipefail
11+
cd /opt/repro/reprobuild
12+
13+
LOG=/tmp/m9r42_iso_build.log
14+
date > "$LOG"
15+
echo "=== M9.R.42 ISO rebuild (REPRO_INSTALLER_AUTORUN=1) ===" >> "$LOG"
16+
17+
pkill -KILL -f 'moc$' 2>/dev/null || true
18+
pkill -KILL -9 -f 'cmake.*reproos' 2>/dev/null || true
19+
pkill -KILL -9 -f 'ninja.*reproos' 2>/dev/null || true
20+
21+
# Nuke the staged de-rootfs + ISO so build phase re-fires.
22+
chmod -R u+w recipes/reproos-iso/build/de-rootfs 2>/dev/null || true
23+
rm -rf recipes/reproos-iso/build/de-rootfs
24+
rm -f recipes/reproos-iso/build/reproos.iso
25+
26+
# Force a reproos-installer rebuild only if its sources changed. The
27+
# M9.R.42 milestone touched stage-de-rootfs.sh + the disk_apply +
28+
# disk_tools modules — the installer C++ is unchanged from M9.R.41.
29+
# But because base-rootfs is keyed on apt-pkg-list and stays the same
30+
# as M9.R.41 (no apt-list change in M9.R.42), the cache hit should
31+
# be valid and we re-use it.
32+
chmod -R u+w apps/reproos-installer/.repro 2>/dev/null || true
33+
rm -rf apps/reproos-installer/.repro
34+
35+
CLINGO_DIR="$(dirname "$(find /nix/store -maxdepth 3 -name 'libclingo.so' 2>/dev/null | head -1)")"
36+
export LD_LIBRARY_PATH="${CLINGO_DIR}${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
37+
38+
export REPRO_INSTALLER_AUTORUN=1
39+
export IO_MON_SRC=/opt/repro/io-mon/src
40+
41+
echo "=== step 1: rebuild reproos-installer ===" >> "$LOG"
42+
nix-shell -p openssl patchelf gcc binutils gnumake autoconf automake libtool pkg-config gettext perl python3 bison flex xz gawk kmod cpio squashfsTools libisoburn grub2 mtools dosfstools curl docker rsync --run "PATH=/opt/repro/reprobuild/build/bin:\$PATH LD_LIBRARY_PATH=$LD_LIBRARY_PATH repro build --daemon=off --tool-provisioning=from-source apps/reproos-installer" >> "$LOG" 2>&1
43+
INSTALLER_RC=$?
44+
echo "INSTALLER_RC=$INSTALLER_RC" >> "$LOG"
45+
ls -la apps/reproos-installer/.repro/output/install/usr/bin/reproos-installer 2>&1 | tee -a "$LOG"
46+
if [ "$INSTALLER_RC" -ne 0 ]; then
47+
echo "FAIL: reproos-installer rebuild RC=$INSTALLER_RC; ISO build aborted" >> "$LOG"
48+
exit "$INSTALLER_RC"
49+
fi
50+
51+
echo "=== step 2: rebuild ISO with REPRO_INSTALLER_AUTORUN=1 ===" >> "$LOG"
52+
nix-shell -p openssl patchelf gcc binutils gnumake autoconf automake libtool pkg-config gettext perl python3 bison flex xz gawk kmod cpio squashfsTools libisoburn grub2 mtools dosfstools curl docker rsync --run "PATH=/opt/repro/reprobuild/build/bin:\$PATH LD_LIBRARY_PATH=$LD_LIBRARY_PATH REPRO_INSTALLER_AUTORUN=1 repro build --daemon=off --tool-provisioning=from-source recipes/reproos-iso" >> "$LOG" 2>&1
53+
RC=$?
54+
echo "" >> "$LOG"
55+
echo "RC=$RC" >> "$LOG"
56+
date >> "$LOG"
57+
58+
echo "=== ISO artifact ===" >> "$LOG"
59+
ls -la recipes/reproos-iso/build/reproos.iso 2>&1 | tee -a "$LOG"
60+
61+
echo "=== verify autorun cmdline staged ===" >> "$LOG"
62+
nix-shell -p binutils --run "strings recipes/reproos-iso/build/reproos.iso | grep -c 'repro.installer.autorun=1'" 2>&1 | tee -a "$LOG"
63+
64+
echo "=== verify REPRO_DISK_DIAG passthrough in staged launcher ===" >> "$LOG"
65+
grep -c 'REPRO_DISK_DIAG=/tmp/installer.disk-diag.log' \
66+
recipes/reproos-iso/build/de-rootfs/usr/bin/reproos-installer-launcher.sh \
67+
2>&1 | tee -a "$LOG"
68+
69+
echo "=== verify installer.disk-diag.log entry in diag-persist tarball list ===" >> "$LOG"
70+
grep -c 'installer.disk-diag.log' \
71+
recipes/reproos-iso/build/de-rootfs/usr/bin/reproos-installer-launcher.sh \
72+
2>&1 | tee -a "$LOG"
73+
74+
echo "=== verify install-root subcommand is reachable on the live ISO ===" >> "$LOG"
75+
nix-shell -p binutils --run "strings recipes/reproos-iso/build/de-rootfs/usr/bin/repro 2>/dev/null | grep -c 'install-root'" 2>&1 | tee -a "$LOG"
76+
77+
exit $RC

_m9r42_loopback_smoke.sh

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
#!/usr/bin/env bash
2+
# M9.R.42.1 Phase A loopback smoke — exercise the disk-apply driver
3+
# against a 4 GiB loopback file with REPRO_DISK_DIAG set, so the
4+
# kernel-state snapshots fire on a Linux host that has sgdisk +
5+
# udev + partprobe but is NOT inside the live ISO. This tests
6+
# whether the M9.R.41 sgdisk-exit-4 race reproduces OUTSIDE the
7+
# live-ISO autorun path (i.e. on a fully-booted Debian Trixie or
8+
# a NixOS host) — a critical signal for whether the race is
9+
# inherent to sgdisk/Trixie OR specific to the live-ISO udev/devtmpfs.
10+
set -uo pipefail
11+
12+
IMG="${IMG:-/tmp/m9r42_loop.img}"
13+
DIAG_OUT="${DIAG_OUT:-/tmp/m9r42_loop_diag.log}"
14+
DISKO_NIM="${DISKO_NIM:-/tmp/m9r42_loop_disko.nim}"
15+
REPRO_BIN="${REPRO_BIN:-/opt/repro/reprobuild/build/bin/repro}"
16+
17+
# Reset
18+
sudo umount -lf /tmp/m9r42_mnt 2>/dev/null || true
19+
sudo umount -lf /tmp/m9r42_mnt/boot 2>/dev/null || true
20+
sudo losetup -D 2>/dev/null || true
21+
rm -f "$IMG" "$DIAG_OUT"
22+
23+
# 4 GiB loopback image
24+
truncate -s 4G "$IMG"
25+
LOOPDEV="$(sudo losetup --find --show "$IMG")"
26+
echo "[loop] LOOPDEV=$LOOPDEV"
27+
LOOPBASE="$(basename "$LOOPDEV")"
28+
29+
cat > "$DISKO_NIM" <<NIM
30+
import repro_profile
31+
32+
hardware "01M9R42-LOOP":
33+
cpu:
34+
arch: "x86_64"
35+
disko:
36+
disks:
37+
"main":
38+
device: "$LOOPDEV"
39+
table: gpt
40+
partitions:
41+
"esp":
42+
kind: esp
43+
size: "512M"
44+
bootable: true
45+
content:
46+
filesystem:
47+
format: "vfat"
48+
mountpoint: "/boot"
49+
"root":
50+
kind: linux
51+
size: "100%"
52+
content:
53+
filesystem:
54+
format: "ext4"
55+
mountpoint: "/"
56+
NIM
57+
58+
export REPRO_DISK_DIAG="$DIAG_OUT"
59+
echo "[loop] starting repro disk apply against $LOOPDEV"
60+
echo "[loop] BEFORE state:"
61+
ls -la "/dev/${LOOPBASE}"* 2>&1
62+
cat /proc/partitions 2>&1 | head -20
63+
64+
cd /opt/repro/reprobuild
65+
sudo -E "$REPRO_BIN" disk apply "$DISKO_NIM" --confirm --device "$LOOPDEV" 2>&1
66+
APPLY_RC=$?
67+
echo "[loop] apply RC=$APPLY_RC"
68+
echo "[loop] AFTER state:"
69+
ls -la "/dev/${LOOPBASE}"* 2>&1
70+
cat /proc/partitions 2>&1 | head -20
71+
72+
echo ""
73+
echo "=== M9.R.42.1 diag file ($DIAG_OUT) ==="
74+
if [ -f "$DIAG_OUT" ]; then
75+
cat "$DIAG_OUT"
76+
else
77+
echo "MISSING — diag file not created"
78+
fi
79+
80+
# Cleanup
81+
sudo losetup -d "$LOOPDEV" 2>/dev/null || true
82+
rm -f "$IMG"
83+
84+
exit $APPLY_RC

_m9r42_smoke_disko.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"id":"01M9R42-SMOKE","cpuArch":"x86_64","cpuMicrocode":"intel","kernelModules":[],"loaderDevice":"/dev/loop99","filesystems":[],"graphicsDrivers":[],"audioCards":[],"disko":{"disks":{"main":{"device":"/dev/loop99","type":"gpt","partitions":{"esp":{"type":"esp","size":"512M","bootable":true,"content":{"kind":"filesystem","format":"vfat","mountpoint":"/boot","mountOptions":[],"label":"","subvols":[]}},"root":{"type":"linux","size":"100%","bootable":false,"content":{"kind":"filesystem","format":"ext4","mountpoint":"/","mountOptions":[],"label":"","subvols":[]}}}}},"pools":[]}}

libs/repro_elevation/src/repro_elevation/posix_system_parse.nim

Lines changed: 55 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1204,14 +1204,43 @@ proc renderIcaclsGrantCommandArgs*(path, entry: string): seq[string] =
12041204
of icaclsDenyVerb:
12051205
@["icacls", path, "/deny", split.spec]
12061206

1207+
proc canonicalizeAclPrincipal*(p: string): string =
1208+
## Collapse the well-known Windows principal aliases ``icacls``
1209+
## accepts as INPUT to the domain-qualified form it emits as
1210+
## OUTPUT, so a desired entry written ``SYSTEM:(F)`` matches an
1211+
## observed entry written ``NT AUTHORITY\SYSTEM:(F)``.
1212+
## Case-insensitive on the alias side (``System``, ``SYSTEM``,
1213+
## ``system`` are all icacls-equivalent); the canonical form keeps
1214+
## the exact spelling icacls emits (mixed-case on the
1215+
## Network/Local Service family, all-caps on SYSTEM).
1216+
##
1217+
## Without this collapse the post-apply digest of a
1218+
## ``fs.systemDirectory`` recipe declaring
1219+
## ``aclEntry(principal = "SYSTEM", ...)`` disagrees with the
1220+
## observed ACL even when ``icacls`` happily granted exactly that
1221+
## ACE — operators would have to hand-write
1222+
## ``NT AUTHORITY\SYSTEM`` to make the digest converge.
1223+
case p.toLowerAscii
1224+
of "system": "NT AUTHORITY\\SYSTEM"
1225+
of "localservice", "local service": "NT AUTHORITY\\LOCAL SERVICE"
1226+
of "networkservice", "network service": "NT AUTHORITY\\NETWORK SERVICE"
1227+
of "administrators": "BUILTIN\\Administrators"
1228+
of "users": "BUILTIN\\Users"
1229+
of "everyone": "Everyone"
1230+
of "authenticated users": "NT AUTHORITY\\Authenticated Users"
1231+
else: p
1232+
12071233
proc normalizeDirAclEntry*(ace: string): string =
1208-
## Stable rendering of an ACE for digest purposes: trim outer
1209-
## whitespace and collapse all internal whitespace runs to single
1210-
## spaces. icacls permits extra whitespace inside the perm groups;
1211-
## the canonical form collapses these so two visually-equivalent
1212-
## ACE strings hash to the same digest. Mirrors the
1213-
## `normalizeAclEntry` shape in `windows_system_parse.nim` so the
1214-
## two ACL kinds digest equivalent entries identically.
1234+
## Stable rendering of an ACE for digest purposes: collapse
1235+
## internal whitespace and canonicalise the principal alias
1236+
## (``SYSTEM`` ↔ ``NT AUTHORITY\SYSTEM`` etc.). icacls permits
1237+
## extra whitespace inside the perm groups and accepts well-known
1238+
## short names as input but always emits the domain-qualified form
1239+
## on output; the canonical form collapses both axes so two
1240+
## visually-equivalent ACE strings hash to the same digest.
1241+
## Mirrors the ``normalizeAclEntry`` shape in
1242+
## ``windows_system_parse.nim`` so the two ACL kinds digest
1243+
## equivalent entries identically.
12151244
var collapsed = ""
12161245
var prevWasSpace = false
12171246
for ch in ace.strip():
@@ -1222,7 +1251,25 @@ proc normalizeDirAclEntry*(ace: string): string =
12221251
else:
12231252
collapsed.add(ch)
12241253
prevWasSpace = false
1225-
collapsed
1254+
# Split principal:perm-spec at the FIRST ``:`` that is NOT inside a
1255+
# parenthesised group (an ACE shape is ``Principal[\Name]:(perms)``).
1256+
# The principal canonicalisation only rewrites the prefix.
1257+
var depth = 0
1258+
var splitIdx = -1
1259+
for i, ch in collapsed:
1260+
case ch
1261+
of '(': inc depth
1262+
of ')': dec depth
1263+
of ':':
1264+
if depth == 0:
1265+
splitIdx = i
1266+
break
1267+
else: discard
1268+
if splitIdx < 0:
1269+
return collapsed
1270+
let principal = collapsed[0 ..< splitIdx]
1271+
let rest = collapsed[splitIdx .. ^1]
1272+
canonicalizeAclPrincipal(principal) & rest
12261273

12271274
proc canonicalDirAclDesired*(present: bool; owner: string;
12281275
entries: seq[string];

libs/repro_elevation/src/repro_elevation/windows_system_driver.nim

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1473,7 +1473,12 @@ when defined(windows):
14731473
" -TaskName " & psQuote(parts.leaf) &
14741474
" -ErrorAction SilentlyContinue; " &
14751475
"if ($null -eq $t) { 'Missing=1' } else { " &
1476-
"'TaskName=' + $t.TaskName; " &
1476+
# Emit the FULL path (``$t.TaskPath`` already ends with ``\``)
1477+
# so the canonical observed-state string matches the desired
1478+
# one (which carries the full ``\Folder\Leaf`` path). Without
1479+
# this the digest disagrees even when Register/Get/Unregister
1480+
# all targeted the same folder.
1481+
"'TaskName=' + $t.TaskPath + $t.TaskName; " &
14771482
"'Executable=' + $t.Actions[0].Execute; " &
14781483
"'Arguments=' + $t.Actions[0].Arguments; " &
14791484
"'WorkingDirectory=' + $t.Actions[0].WorkingDirectory; " &

libs/repro_elevation/tests/t_smoke_repro_elevation.nim

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1175,11 +1175,26 @@ suite "repro_elevation: fs.systemDirectory Phase D — drift digest":
11751175
observedInheritanceDisabled = false,
11761176
desiredInheritance = "enabled")
11771177

1178-
test "normalizeDirAclEntry collapses internal whitespace":
1179-
check normalizeDirAclEntry("SYSTEM:(F)") == "SYSTEM:(F)"
1180-
check normalizeDirAclEntry(" SYSTEM:(F) ") == "SYSTEM:(F)"
1181-
check normalizeDirAclEntry("SYSTEM:(F) (OI)") == "SYSTEM:(F) (OI)"
1182-
check normalizeDirAclEntry("SYSTEM:(F)\t (CI)") == "SYSTEM:(F) (CI)"
1178+
test "normalizeDirAclEntry collapses internal whitespace + canonicalises principal":
1179+
# The principal-alias collapse (added alongside the whitespace
1180+
# pass) rewrites ``SYSTEM`` to ``NT AUTHORITY\SYSTEM`` so the
1181+
# desired digest matches the icacls-emitted observed digest.
1182+
check normalizeDirAclEntry("SYSTEM:(F)") == "NT AUTHORITY\\SYSTEM:(F)"
1183+
check normalizeDirAclEntry(" SYSTEM:(F) ") ==
1184+
"NT AUTHORITY\\SYSTEM:(F)"
1185+
check normalizeDirAclEntry("SYSTEM:(F) (OI)") ==
1186+
"NT AUTHORITY\\SYSTEM:(F) (OI)"
1187+
check normalizeDirAclEntry("SYSTEM:(F)\t (CI)") ==
1188+
"NT AUTHORITY\\SYSTEM:(F) (CI)"
1189+
# A principal already in domain-qualified form is left alone.
1190+
check normalizeDirAclEntry("NT AUTHORITY\\SYSTEM:(F)") ==
1191+
"NT AUTHORITY\\SYSTEM:(F)"
1192+
# NetworkService -> NT AUTHORITY\NETWORK SERVICE.
1193+
check normalizeDirAclEntry("NetworkService:(RX)") ==
1194+
"NT AUTHORITY\\NETWORK SERVICE:(RX)"
1195+
# An unknown principal is left alone (the canonicaliser only
1196+
# rewrites the documented well-known set).
1197+
check normalizeDirAclEntry("DOMAIN\\Alice:(F)") == "DOMAIN\\Alice:(F)"
11831198

11841199
test "fsSystemDirectoryDigestPayload back-compat for ACL-unmanaged":
11851200
# The aclPresent==false branch MUST produce a string

0 commit comments

Comments
 (0)