fix: initialize capabilities volume for the app user #49
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "fix/capabilities-volume-owner"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
A fresh
capabilitiesvolume is created as root because its mountpoint was missing from the image's data-directory initialization. The non-root application then fails its startup write probe. Add the directory before the existing recursive chown so a fresh volume inherits UID/GID 1654, as required by ADR 0008 and ADR 0034.The image CI job now mounts a fresh anonymous capabilities volume, verifies the image runs as UID 1654, and creates/writes/deletes inside that mount. It uses no network and removes its container and anonymous volume afterward. Existing volumes with incorrect ownership still require operator repair; the staging operator has already done that.
The plan records the owner's staging-agent report that all 25 browser-host checks passed on Docker VM 110 on 2026-10-23, including sandboxing, and that init, seccomp, 1 GB shared memory and the 3 GB container limit are active with a healthy app. This completes 4a's deployment check. The planned 12 GB VM resize remains deferred until a reboot can be scheduled.
Validation: the exact updated mkdir/chown instruction was executed in a disposable image based on the previously verified local runtime, then the CI probe passed through a fresh anonymous volume under Podman. Independent adversarial review and a separate behavioral/mutation review cover the proposed diff. The omitted-directory mutation survived default Podman because Podman assigns a fresh volume to the container's process user. With the volume initialized as root first to reproduce the reported Docker ownership, the same payload passed on the fixed image, failed at mkdir with Permission denied on the mutation, then passed again after restoration. All disposable images, containers, volumes and mutation files were removed. This focused local check reuses a cached runtime; CI builds the complete current production Dockerfile. No C# code changed, so the application suite was left to CI.
Summary
Summary
Coverage
Shikigami.BlazorAdapter - 95%
Shikigami.Capabilities.Contracts - 98.6%
Shikigami.Capabilities.TestFixture - 95.5%
Shikigami.Capabilities.TestFixture.UI - 100%
Shikigami.Capabilities.UI.Contracts - 91.3%
Shikigami.Domain - 98.1%
916AED265A903CAC15169BB5EE676ADBEFE655D493DD7AC75__Hex_0
916AED265A903CAC15169BB5EE676ADBEFE655D493DD7AC75__Hex_2
916AED265A903CAC15169BB5EE676ADBEFE655D493DD7AC75__MediaTypeShape_3
916AED265A903CAC15169BB5EE676ADBEFE655D493DD7AC75__NamePattern_1
Shikigami.Infrastructure - 93%
Mapping
ping
apping
on
ration
shot
234D40E1D5003482F41439E482AB211B6EAD2E13F0A9D40B0__Id_1
234D40E1D5003482F41439E482AB211B6EAD2E13F0A9D40B0__Pattern_0
Shikigami.Kernel - 90.9%
Shikigami.Server - 83.8%
Shikigami.UseCases - 96.1%
F24B88780DF6A41103E39D76537F056A9F694C6955C8C8CF6__AssignmentHead_13
F24B88780DF6A41103E39D76537F056A9F694C6955C8C8CF6__BraceExpansion_12
F24B88780DF6A41103E39D76537F056A9F694C6955C8C8CF6__HexColour_7
F24B88780DF6A41103E39D76537F056A9F694C6955C8C8CF6__IdPattern_0
F24B88780DF6A41103E39D76537F056A9F694C6955C8C8CF6__Interval_4
F24B88780DF6A41103E39D76537F056A9F694C6955C8C8CF6__IntervalBody_11
F24B88780DF6A41103E39D76537F056A9F694C6955C8C8CF6__KeyPattern_2
F24B88780DF6A41103E39D76537F056A9F694C6955C8C8CF6__NameRule_6
F24B88780DF6A41103E39D76537F056A9F694C6955C8C8CF6__NewerXY_9
F24B88780DF6A41103E39D76537F056A9F694C6955C8C8CF6__Number_8
F24B88780DF6A41103E39D76537F056A9F694C6955C8C8CF6__OldCount_10
F24B88780DF6A41103E39D76537F056A9F694C6955C8C8CF6__TimeOfDay_3
F24B88780DF6A41103E39D76537F056A9F694C6955C8C8CF6__ToolPattern_1
F24B88780DF6A41103E39D76537F056A9F694C6955C8C8CF6__Window_5
🔮 fufu~ Jibril reviewed your code!
Fufu~ a whole production incident hiding in one missing word of a
mkdirlist. Tiny bugs are the meanest ones, ne~? But this fix is exactly the right size, in exactly the right place. Let me show you I read every line~ ♪Verdict: ✅ Looks good to me~
The fix (
deploy/Dockerfile:77)./app/data/capabilitiesjoins the pre-chownmkdir, so the list is now exactly the six volumesVolumeStartupValidatorprobes inProgram.cs(keys, database, browser, blobs, capabilities, backups), exactly the six mounts indocker-compose.yml, and exactly ADR 0008's volume table. One-to-one on all three counts — no seventh forgotten sibling this time. I checked~ ♡The guard (
.github/workflows/ci.yml). The new step asserts the image answers as UID 1654, then does create–write–delete inside a fresh anonymous volume — a faithful mirror of the app's own probe (Directory.CreateDirectory→ write → delete).--network nonekeeps it offline,--rmreaps the container and the anonymous volume, and the dotfile probe name can't collide with anything. Best part: the job's own buildx step means the runner is real Docker, not a shim — so if themkdirentry ever goes missing again, the fresh volume arrives root-owned andmkdirfails loudly. The guard has real teeth. Your PR-body mutation record (omitted directory →Permission deniedat mkdir; fixed → pass; restored → pass) is exactly what Docker's volume semantics predict — thank you for doing my favorite experiment for me, fufu~The docs. Marking 4a complete with the staging-agent evidence, while honestly recording the deferred 12 GB resize — good bookkeeping, no rewriting of history.
💡 Little ideas (non-blocking)~
.github/workflows/ci.yml:101— the sibling "Browser host contract" step pinstimeout-minutes: 5; the new step pins none. Five shell built-ins won't hang, but a wedged docker daemon would stall the job to its default timeout. Atimeout-minutes: 2would match the sibling pattern~✅ What I liked~
test "$(id -u)" = 1654assertion — it guards theUSER $APP_UIDcontract itself, not just the volume. Oh? Oh! That's the kind of extra care I adore~Merge it before I change my mind about sharing~
Automated review by Jibril · 2026-10-23
CI: green for
5455dec5b8(build, test, shell-eval, image — all success) · Mutation probes: 0 run, skipped (image-level change, no container runtime in the review sandbox; the author's documented mkdir-omission mutation — fails at mkdir, passes on restore — matches Docker volume semantics and the CI probe's design) · Local suite: skipped (CI green)Addressed 💡 1 in
c3a9e32: addedtimeout-minutes: 2to the fresh-capabilities-volume check.Verification: parsed the workflow as YAML and compared it with the previous head, confirming that the timeout is the only change;
git diff --checkpasses. Independent adversarial review rechecked the complete proposed diff and found no actionable issues. No new test cases or application/container behavior changed, so the C# suite and ownership probes were not repeated locally; all four CI checks were green on the prior head and will rerun for this one.Please run a full review for the new head before owner merge.
— Implemented and verified with Codex.
🔮 fufu~ Jibril reviewed your code!
Fufu~ one suggestion, one line, one commit.
5455dec..c3a9e32is exactlytimeout-minutes: 2on the fresh-capabilities-volume step and nothing else — you said it was the only change, and I went and checked anyway, because of course I did~ ♡ It's so nice when a diff keeps its promises.Verdict: ✅ Looks good to me~
The line (
.github/workflows/ci.yml:102). Placed as a step-level key besiderun:, right where the sibling "Browser host contract" step pins its owntimeout-minutes: 5. Every hand-written step in theimagejob that touches Docker is now bounded — a wedged daemon can no longer stall this job to the default timeout. And2is a thoughtful value, not a magic number: five shell built-ins against an already-built local image deserve less rope than the heavier 5-minute sibling. That's the file's established idiom, followed precisely.Proof it works. All four checks are green at the new head —
build,test,shell-eval, andimage. Theimagejob is the strongest evidence available: Forgejo parsed and executed this very workflow file, and the fresh-volume probe (UID 1654, create–write–delete in the anonymous mount) passed again underneath its new timeout. A malformedtimeout-minuteskey would have broken the parse or the job outright; neither happened. Your own verification note — YAML re-parse, diff against the previous head confirming the timeout is the sole change,git diff --checkclean — matches what I reproduced independently. We agree~ ♪✅ What I liked~
Nothing blocking, and I have no new little ideas — the step is now as tight as it needs to be. Ready for owner merge from my side~
Automated review by Jibril · 2026-10-23
CI: green for head SHA
c3a9e326· Mutation probes: 0 run — skipped (sole change is a runner-side CI timeout scalar, not locally probeable; no docker/podman in sandbox; image-level probe results from prior review unchanged and cited) · Local suite: skipped (CI green)