fix(hostcheck): accept dpkg octal mode and verify bundles in scratch repos (#1816, Vikunja 614). Untested
This commit is contained in:
1 parent
93694c5185
commit
f30c74b128
6 files changed
+114
-4
No files matched your search
@@ -5411,3 +5411,5 @@ Row 299 (573, #1806, Gander, Filbert): before, the P10 band test timed a fault r
|
||||
2026-10-23T17:29:46Z | Gyro Vikunja571 sage-3542 Connections amendment | Branch gyro/editor-connections-design cut exactly from landed PRD1.17 30e6bb680; read REQ-LIB-5 in that PRD. Replaced stale J-b waits in parent and W4. Proposed W8 owns current authorized Markdown/DOCX links/backlinks list, labels, versioned refresh, leakage refusals and fixture tests. Build order under mos-1470/comment961 is W7 closed routing candidate, W8 landing, then W7 human first-real-import opening. No REQ-LIB-8 condition or acceptance change. Q234/mos-1363/S0 M1-M14 and post-10-27/MVP priority fixed. Static diff, twelve brief sections and append-only checks pass. No repo Node, tests, build, browser, queue mutation or live action. Fenton reviews after authorized docs branch push; Sage lands on approval.
|
||||
|
||||
2026-10-23T17:32:37Z | Gyro sage-3544 fenton-0016 N1/N2 delta | Before: W7 Gate/final real-conversion list omit the W8 build-order cross-reference and W8 human-view filtering cites agent settings. After: both locations explicitly put W8 landing before human opening as mos-1470 build order, not acceptance; comment/tracked-deletion links are not current story links and never appear in the human Connections view regardless of agent settings. New commit atop approved 5af060fb5, no amend. Static diff and append-only checks pass. Docs only, no repo Node/tests/live action. Fenton checks only this delta.
|
||||
|
||||
2026-10-23 | Gladstone | Gitea #1816 / Vikunja 614 hostcheck item 5 and bundle verification | Before: dpkg's correct 750 form falsely fails item 5, and two run-sheet bundle verifies require a missing repository. Draft after: exact root/mosaic/path with octal 0750 equivalence; stat/output unchanged; both verifies use cleaned-up bare scratch repos. Three additive-only test blocks, two planned mutants. Untested under Sage-3738; Sage-3740 authorizes untested branch push for static review. Queue row pending; Sage owns gate and landing.
|
||||
@@ -0,0 +1,51 @@
|
||||
# Hostcheck item 5 and bundle verification (Gitea #1816, Vikunja 614)
|
||||
|
||||
Queue row pending from Sage. Owner Gladstone, reviewer Morgana, gate/landing Sage.
|
||||
Base: fetched origin/refactor 93694c5185d0a7f989d2fe78fb620e44599b744e;
|
||||
branch gladstone/hostcheck-item5. Scope: mos-1531 / ops-0256, sage-3738 and sage-3740.
|
||||
|
||||
## Before and after
|
||||
|
||||
Ubuntu 24.04 dpkg 1.22.6ubuntu6.6 prints `root mosaic 750 /usr/bin/bwrap`.
|
||||
Item 5 compared the literal `0750`, falsely refusing a correctly configured host;
|
||||
--enforce would unload the profile, close bwrap and record DRIFT.
|
||||
The candidate accepts exactly four fields, root, mosaic, octal 0750, and $BWRAP.
|
||||
`0*750` represents all octal spellings numerically equal to 0750 without arithmetic
|
||||
conversion/overflow. Horizontal whitespace separates fields; extra fields and
|
||||
embedded newlines refuse. Owner, group and path remain exact. The stat comparison
|
||||
and existing output strings remain unchanged. Only the item 5 comment also changes.
|
||||
|
||||
The two release-transport bundle checks previously ran outside any repository.
|
||||
Each now creates an empty bare scratch repository, verifies with git -C, and removes
|
||||
the scratch directory using an EXIT trap. A failure exits the shell before cloning
|
||||
or fetching. No other run-sheet text changes.
|
||||
|
||||
## Tests and mutants
|
||||
|
||||
Only packages/cli/tests/case1-hostcheck.test.mjs changes among tests, by appending
|
||||
three new test() blocks; the existing passing 0750 fake and failing fake are intact.
|
||||
The pass test exercises 750, 0750 and 000750. The enforce test checks no unload,
|
||||
chown, chmod, DRIFT or hostcheck log for 750. Refusals independently cover 755,
|
||||
0755, 4750, 75, 7500, 075, non-octal strings, other owner/group/path, missing path,
|
||||
extra fields, multiple lines, blank/empty output and a missing fixture file.
|
||||
|
||||
| Mutant | Change | Killer | Result |
|
||||
|---|---|---|---|
|
||||
| M1 | Restore the old literal root mosaic 0750 comparison (drop 750) | new check pass test | Unrun |
|
||||
| M2 | Accept any mode while preserving owner/group/path | new refusal test | Unrun |
|
||||
|
||||
Mutant procedure: preserve script bytes, assert one replacement, run the named
|
||||
killer alone, require failure for its intended assertion, restore in finally and
|
||||
check the original bytes/hash. Run the original targeted file again after restore.
|
||||
|
||||
## Verification status
|
||||
|
||||
Untested. Sage-3738 prohibits all Node until CLEAR because the joint full gate
|
||||
runs alone. Sage-3740 explicitly directs pushing this untested build for Morgana's
|
||||
static review before CLEAR. This supersedes test-first execution for this draft;
|
||||
no Node, tests, node --check, full suites or live-host operations have run.
|
||||
Queue next refused linked-worktree execution; Sage owns queue creation/movement.
|
||||
Push only gladstone/*, with MOSAIC_GITEA_CREDENTIAL_FILE unset; no amend/force.
|
||||
|
||||
Static draft receipt: `git diff --check` passed. Test-file numstat against the
|
||||
base is `46 0 packages/cli/tests/case1-hostcheck.test.mjs` (added/deleted).
|
||||
@@ -1593,3 +1593,4 @@ are never rewritten or removed; corrections are new entries.
|
||||
2026-10-23T17:48:43Z | Scrooge (629b6cd3) | Row 252 Console inbox Approve and Deny (#1753) | Rebased onto 306 landing as 580037105 (range-diff all =), slot run bus 907/0 webui 410/0 cli 943/0, in-review revs 3608/3609, Webby r1 APPROVE, J1-J19 specs to Sage; Sage landed 45ea3fa0d (done rev 3616). Part 1 mutant results were never in BUILD.md; they went to Sage by T3 (scrooge-0252-mutant-specs).
|
||||
2026-10-23 | Sage (1ef1e4f8) | Rows 308 and 252 landings, 571 Connections design amendment, Vikunja 597 | 308 (PRD 1.17, #1815) landed 30e6bb680 and 252 (#1753) landed 45ea3fa0d (replay of 580037105 onto 30e6bb680, range-diff all =), each after a full gate on the landed tree (252 also J1-J19, J11c and J18 equivalent); Gyro's 571 amendment (Fenton APPROVE) landed e8bb13df8; Vikunja 570, 435 and 597 done, canonical webui esbuild 0.28.2; queue revs 3589-3616 committed 59f013247
|
||||
2026-10-23 | Sage (1ef1e4f8) | Vikunja 571 W build rows; rows 13, 42, 257 and 289 check | Filed the design's ten W rows as queue rows 309-318 (revs 3617-3626, owners set to unassigned 3627-3636, queue commit 293b42fee pushed); Vikunja 571 done (comment 994). Row 13's candidate fd72d2689 is on refactor, gate is Monday's row 7 ledger run; 42 paused under mos-1184; 257 post-v1; 289 waits on 214 and 288. Slot released 17:56Z.
|
||||
2026-10-23 | Gladstone (433058fc-9cea-46e3-8554-6ddefb312762, Codex gpt-6.1-sol) | #1816 / Vikunja 614, mos-1531 | Built hostcheck octal-mode fix and two bare-scratch bundle verifies on gladstone/hostcheck-item5 from 93694c518. Three append-only test blocks; Node/tests held by Sage-3738, untested push authorized sage-3740. Queue number pending; Morgana static review, Sage gate/landing.
|
||||
@@ -189,7 +189,12 @@ First install:
|
||||
```sh
|
||||
# Copy the bundle in, then check it before anything reads it.
|
||||
echo "<bundle sha256> /root/<sha>.bundle" | sha256sum -c -
|
||||
git bundle verify /root/<sha>.bundle
|
||||
(
|
||||
bundle_check="$(mktemp -d)" || exit 1
|
||||
trap 'rm -rf "$bundle_check"' EXIT
|
||||
git init -q --bare "$bundle_check" &&
|
||||
git -C "$bundle_check" bundle verify /root/<sha>.bundle
|
||||
) || exit 1
|
||||
|
||||
# Root's checkout. stack-upgrade.sh and case2-unit.sh run from here, never from a copy.
|
||||
git clone -q -b refactor /root/<sha>.bundle /root/mosaic-stack
|
||||
@@ -206,7 +211,12 @@ Each upgrade, before `stack-upgrade.sh upgrade`:
|
||||
|
||||
```sh
|
||||
echo "<bundle sha256> /root/<sha>.bundle" | sha256sum -c -
|
||||
git bundle verify /root/<sha>.bundle
|
||||
(
|
||||
bundle_check="$(mktemp -d)" || exit 1
|
||||
trap 'rm -rf "$bundle_check"' EXIT
|
||||
git init -q --bare "$bundle_check" &&
|
||||
git -C "$bundle_check" bundle verify /root/<sha>.bundle
|
||||
) || exit 1
|
||||
git -C /root/mosaic-stack fetch -q /root/<sha>.bundle refs/heads/refactor:refs/remotes/origin/refactor
|
||||
git -C /root/mosaic-stack checkout -q --detach <sha>
|
||||
install -o mosaic -g mosaic -m 0600 /root/<sha>.bundle /srv/mosaic/incoming/<sha>.bundle
|
||||
|
||||
@@ -333,3 +333,49 @@ test("row 240 pins and usage: the shipped pins are r6's, the script reads the pi
|
||||
assert.deepEqual([u.status, u.stderr], [2, "hostcheck: refusing: run it as root\n"]);
|
||||
}
|
||||
});
|
||||
|
||||
test("Vikunja 614 check: item 5 accepts dpkg's bare octal mode and leading-zero equivalents", (t) => {
|
||||
for (const mode of ["750", "0750", "000750"]) {
|
||||
const h = host(t);
|
||||
put(join(h.hc, "statoverride"), `root mosaic ${mode} /usr/bin/bwrap\n`);
|
||||
const r = run(h, "--check");
|
||||
assert.equal(r.status, 0, r.out + r.err);
|
||||
assert.deepEqual(fails(r), []);
|
||||
assert.ok(r.lines.some((line) => line.startsWith("ok 5 ")), r.out);
|
||||
}
|
||||
});
|
||||
|
||||
test("Vikunja 614 enforce: dpkg's bare 750 leaves bwrap open and writes no DRIFT", (t) => {
|
||||
const h = host(t);
|
||||
put(join(h.hc, "statoverride"), "root mosaic 750 /usr/bin/bwrap\n");
|
||||
const r = run(h, "--enforce");
|
||||
assert.equal(r.status, 0, r.out + r.err);
|
||||
assert.deepEqual(fails(r), []);
|
||||
assert.equal(r.lines.at(-1), "hostcheck: all seven hold");
|
||||
assert.deepEqual([calls(h, "apparmor_parser"), calls(h, "chown"), calls(h, "chmod")], [[], [], []]);
|
||||
assert.equal(existsSync(drift(h)), false);
|
||||
assert.equal(existsSync(hlog(h)), false);
|
||||
});
|
||||
|
||||
test("Vikunja 614 check: item 5 refuses other modes, owners, groups, paths and malformed overrides", (t) => {
|
||||
const overrides = [
|
||||
...["755", "0755", "4750", "75", "7500", "075", "0780", "8", "0o750", "+750", "-750", "7x0", "750+0", ""].map((mode) => `root mosaic ${mode} /usr/bin/bwrap\n`),
|
||||
"mosaic mosaic 750 /usr/bin/bwrap\n",
|
||||
"root root 750 /usr/bin/bwrap\n",
|
||||
"root mosaic 750 /usr/bin/other\n",
|
||||
"root mosaic 750 /usr/bin/bwrap extra\n",
|
||||
"root mosaic 750\n",
|
||||
"root mosaic 750 /usr/bin/bwrap\nroot mosaic 750 /usr/bin/bwrap\n",
|
||||
"\n",
|
||||
"",
|
||||
null,
|
||||
];
|
||||
for (const override of overrides) {
|
||||
const h = host(t);
|
||||
if (override === null) rmSync(join(h.hc, "statoverride"));
|
||||
else put(join(h.hc, "statoverride"), override);
|
||||
const r = run(h, "--check");
|
||||
assert.equal(r.status, 1, `${JSON.stringify(override)}: ${r.out}${r.err}`);
|
||||
assert.deepEqual(fails(r).map((line) => line.split(" ")[1]), ["5"], r.out);
|
||||
}
|
||||
});
|
||||
@@ -16,7 +16,7 @@
|
||||
# 3. `grep -rlw bwrap /etc/apparmor.d` lists that one file and nothing else.
|
||||
# 4. A bwrap child started as mosaic under the units' no-new-privs reads the label
|
||||
# `bwrap//&unpriv_bwrap (enforce)`, exactly.
|
||||
# 5. The statoverride on /usr/bin/bwrap reads `root mosaic 0750`, and stat agrees.
|
||||
# 5. The statoverride on /usr/bin/bwrap has root mosaic and octal mode 0750 (750 accepted), and stat agrees.
|
||||
# 6. kernel.apparmor_restrict_unprivileged_userns and fs.protected_hardlinks are 1.
|
||||
# 7. net.ipv4.ip_unprivileged_port_start is above the Console's --port in the installed unit, or
|
||||
# above 1023, the highest --port case2-unit.sh takes, while no unit is installed.
|
||||
@@ -114,7 +114,7 @@ item5() {
|
||||
local so st
|
||||
so="$(dpkg-statoverride --list "$BWRAP" 2>/dev/null)"
|
||||
st="$(stat -c '%U %G %a' "$ROOT$BWRAP" 2>/dev/null)"
|
||||
[ "$so" = "root mosaic 0750 $BWRAP" ] || { fail "5 the statoverride on $BWRAP reads '$so', not 'root mosaic 0750'"; return; }
|
||||
[[ "$so" =~ ^root[[:blank:]]+mosaic[[:blank:]]+0*750[[:blank:]]+"$BWRAP"$ ]] || { fail "5 the statoverride on $BWRAP reads '$so', not 'root mosaic 0750'"; return; }
|
||||
[ "$st" = "root mosaic 750" ] || { fail "5 $BWRAP is '$st', not 'root mosaic 750'"; return; }
|
||||
pass "5 $BWRAP is root mosaic 0750, by the statoverride and by stat"
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user