Make the apply tests fit the checker's isolated step: accept any who in the refused line, skip aloud where no group can be set (issue 1919, R4g)
mesh/delivery delivered
mesh/delivery-group group feat/r4g failed: a member failed
mesh/check checking 4b4bb09a05a0 on 48c3e3834c69 | novox/mesh-host#132 in group feat/r4g

This commit is contained in:
2026-10-23 18:54:53 +02:00
parent 11b0a1fb29
commit 4b4bb09a05
2 changed files with 31 additions and 2 deletions
+5 -2
View File
@@ -11,7 +11,9 @@ import (
// The read-only judgement of a node's directories (novox/hq issue 358): one line each — placed, would be refused // The read-only judgement of a node's directories (novox/hq issue 358): one line each — placed, would be refused
// naming the link and who could replace it, or not there yet (placed: an apply makes it) — and nothing made or // naming the link and who could replace it, or not there yet (placed: an apply makes it) — and nothing made or
// changed. // changed. Who could replace the link is "every account", "the account X" or "the group X", by the account and the
// directories the test runs as: the checker's isolated step runs as the account nobody, which owns / there (issue 1919,
// R4g), so the test demands a who in any of the forms couldReplace and linkReplacer produce, not "every account" alone.
func TestJudgeDirectoriesSaysWhatTheWalkWouldRefuseAndChangesNothing(t *testing.T) { func TestJudgeDirectoriesSaysWhatTheWalkWouldRefuseAndChangesNothing(t *testing.T) {
base := t.TempDir() base := t.TempDir()
plain := filepath.Join(base, "plain") plain := filepath.Join(base, "plain")
@@ -39,7 +41,8 @@ func TestJudgeDirectoriesSaysWhatTheWalkWouldRefuseAndChangesNothing(t *testing.
t.Errorf("a directory the walk reaches is not said placed: %q", said) t.Errorf("a directory the walk reaches is not said placed: %q", said)
} }
if !strings.Contains(lines[2], "would be refused") || !strings.Contains(lines[2], filepath.Join(base, "linked")) || if !strings.Contains(lines[2], "would be refused") || !strings.Contains(lines[2], filepath.Join(base, "linked")) ||
!strings.Contains(lines[2], "every account") { !(strings.Contains(lines[2], "every account (") || strings.Contains(lines[2], "the account ") ||
strings.Contains(lines[2], "the group ")) {
t.Errorf("the linked directory is not said refused naming the link and who: %q", lines[2]) t.Errorf("the linked directory is not said refused naming the link and who: %q", lines[2])
} }
if _, err := os.Stat(filepath.Join(base, "missing")); !os.IsNotExist(err) { if _, err := os.Stat(filepath.Join(base, "missing")); !os.IsNotExist(err) {
+26
View File
@@ -11,6 +11,7 @@ import (
"path/filepath" "path/filepath"
"strconv" "strconv"
"strings" "strings"
"syscall"
"testing" "testing"
"time" "time"
@@ -23,6 +24,23 @@ import (
// The engine's half of ADR 0328's checks (novox/hq ADR 0328, "How it is checked", issue 567). The engine runs as // The engine's half of ADR 0328's checks (novox/hq ADR 0328, "How it is checked", issue 567). The engine runs as
// root; a test may not, and a non-root test gives its folders a group it is in itself. // root; a test may not, and a non-root test gives its folders a group it is in itself.
// canSetGroups skips aloud a test that gives a folder a group when this step cannot. **A step that cannot set a folder's
// group judges nothing here** (issue 1919, R4g): the checker runs the tests in the build module's isolation, a user
// namespace that maps no group but the step's own, so a chown to any other group is refused (EINVAL or EPERM). A test that
// sets a group calls it first: the probe gives a file of the test's own that group, and when it is refused the test skips
// aloud; outside such an isolation it runs and is judged.
func canSetGroups(t *testing.T, gid int) {
t.Helper()
probe := filepath.Join(t.TempDir(), "probe")
if err := os.WriteFile(probe, nil, 0o600); err != nil {
t.Fatal(err)
}
if err := os.Chown(probe, -1, gid); errors.Is(err, syscall.EINVAL) || errors.Is(err, syscall.EPERM) {
t.Skipf("NOT JUDGED: this step cannot set a folder's group (a user namespace maps only its own account, as the "+
"checker's isolated step does): %v; issue 1919", err)
}
}
// testGID is a group the test may give its folders: any number as root, else one of its own added groups that is // testGID is a group the test may give its folders: any number as root, else one of its own added groups that is
// no root group's. // no root group's.
func testGID(t *testing.T) int { func testGID(t *testing.T) int {
@@ -121,6 +139,7 @@ func statOf(t *testing.T, path string) unix.Stat_t {
// those folders alone, never what is in them; owner, owner's and others' bits unchanged. // those folders alone, never what is in them; owner, owner's and others' bits unchanged.
func TestALibraryIsKeptInItsGroup(t *testing.T) { func TestALibraryIsKeptInItsGroup(t *testing.T) {
gid := testGID(t) gid := testGID(t)
canSetGroups(t, gid)
libraries(t, nil, nil) libraries(t, nil, nil)
root := filepath.Join(t.TempDir(), "media") root := filepath.Join(t.TempDir(), "media")
if err := os.Mkdir(root, 0o755); err != nil { if err := os.Mkdir(root, 0o755); err != nil {
@@ -170,6 +189,7 @@ func TestALibraryIsKeptInItsGroup(t *testing.T) {
// Row 9: a missing sub-path is made with the root's owner, the library's group, group rwx and setgid. // Row 9: a missing sub-path is made with the root's owner, the library's group, group rwx and setgid.
func TestAMissingSubPathIsMadeAsTheRootIs(t *testing.T) { func TestAMissingSubPathIsMadeAsTheRootIs(t *testing.T) {
gid := testGID(t) gid := testGID(t)
canSetGroups(t, gid)
libraries(t, nil, nil) libraries(t, nil, nil)
root := filepath.Join(t.TempDir(), "media") root := filepath.Join(t.TempDir(), "media")
if err := os.Mkdir(root, 0o751); err != nil { if err := os.Mkdir(root, 0o751); err != nil {
@@ -226,6 +246,7 @@ func TestARootThatHoldsDataWaitsForTheOperatorsWord(t *testing.T) {
// (the act's ask, internal/link); an undeclared library refused; a walk over its bound goes on from its cursor. // (the act's ask, internal/link); an undeclared library refused; a walk over its bound goes on from its cursor.
func TestTheTakeActSetsTheGroupUnderTheRoot(t *testing.T) { func TestTheTakeActSetsTheGroupUnderTheRoot(t *testing.T) {
gid := testGID(t) gid := testGID(t)
canSetGroups(t, gid)
libraries(t, nil, nil) libraries(t, nil, nil)
base := t.TempDir() base := t.TempDir()
root := filepath.Join(base, "media") root := filepath.Join(base, "media")
@@ -512,6 +533,7 @@ func TestNoLibraryGroupIsRoot(t *testing.T) {
// A library's filesystem that cannot be named this time is unknown, never a move; another filesystem at the root is. // A library's filesystem that cannot be named this time is unknown, never a move; another filesystem at the root is.
func TestALibraryNotNamedIsUnknownAndAnotherFilesystemIsAMove(t *testing.T) { func TestALibraryNotNamedIsUnknownAndAnotherFilesystemIsAMove(t *testing.T) {
gid := testGID(t) gid := testGID(t)
canSetGroups(t, gid)
base := t.TempDir() base := t.TempDir()
pool := filepath.Join(base, "pool") pool := filepath.Join(base, "pool")
root := filepath.Join(pool, "media") root := filepath.Join(pool, "media")
@@ -650,6 +672,7 @@ func TestALibraryIsNeverTheMachinesOwnTree(t *testing.T) {
// and sample all in shape are kept; once taken, never asked again on that filesystem. // and sample all in shape are kept; once taken, never asked again on that filesystem.
func TestARootInShapeWithDataBelowNotInTheGroupWaits(t *testing.T) { func TestARootInShapeWithDataBelowNotInTheGroupWaits(t *testing.T) {
gid := testGID(t) gid := testGID(t)
canSetGroups(t, gid)
libraries(t, nil, nil) libraries(t, nil, nil)
root := filepath.Join(t.TempDir(), "media") root := filepath.Join(t.TempDir(), "media")
movies := filepath.Join(root, "movies") movies := filepath.Join(root, "movies")
@@ -699,6 +722,7 @@ func TestARootInShapeWithDataBelowNotInTheGroupWaits(t *testing.T) {
// file never keeps its setgid bit once regrouped. // file never keeps its setgid bit once regrouped.
func TestRootsLinkedFilesAreLeftAndSetgidIsNeverKept(t *testing.T) { func TestRootsLinkedFilesAreLeftAndSetgidIsNeverKept(t *testing.T) {
gid := testGID(t) gid := testGID(t)
canSetGroups(t, gid)
f, err := os.CreateTemp(t.TempDir(), "file") f, err := os.CreateTemp(t.TempDir(), "file")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
@@ -729,6 +753,7 @@ func TestRootsLinkedFilesAreLeftAndSetgidIsNeverKept(t *testing.T) {
// waits for the operator's word as the root would, and nothing of it is changed; an empty one is kept. // waits for the operator's word as the root would, and nothing of it is changed; an empty one is kept.
func TestASubPathHoldingOldDataWaitsForTheOperatorsWord(t *testing.T) { func TestASubPathHoldingOldDataWaitsForTheOperatorsWord(t *testing.T) {
gid := testGID(t) gid := testGID(t)
canSetGroups(t, gid)
libraries(t, nil, nil) libraries(t, nil, nil)
root := filepath.Join(t.TempDir(), "media") root := filepath.Join(t.TempDir(), "media")
if err := os.Mkdir(root, 0o755); err != nil { if err := os.Mkdir(root, 0o755); err != nil {
@@ -795,6 +820,7 @@ func TestAnApplyDoesNotWaitForATakeWalk(t *testing.T) {
// the root alone, says whether the data is the library's already (§7). // the root alone, says whether the data is the library's already (§7).
func TestTheSampleBeneathARootInShapeIsJudged(t *testing.T) { func TestTheSampleBeneathARootInShapeIsJudged(t *testing.T) {
gid := testGID(t) gid := testGID(t)
canSetGroups(t, gid)
libraries(t, nil, nil) libraries(t, nil, nil)
root := filepath.Join(t.TempDir(), "media") root := filepath.Join(t.TempDir(), "media")
if err := os.MkdirAll(filepath.Join(root, "old"), 0o755); err != nil { if err := os.MkdirAll(filepath.Join(root, "old"), 0o755); err != nil {