Skip to content

Fabric store: owner/group/mode derived from its two writers (CI claim principal can write) - #12294

Merged
briansrls merged 4 commits into
mainfrom
session/eager-badger-341
Sep 25, 2026
Merged

briansrls merged 4 commits into
mainfrom
session/eager-badger-341

Conversation

@gunbai-bot

@gunbai-bot gunbai-bot Bot commented Sep 25, 2026 •

Copy link
Copy Markdown
Contributor

The srv1 deploy ensured /opt/gunbc/fabric-storage/{,objects,heads} as briansrls:briansrls 0755,
but the host-effect claim writes those files directly as the CI job principal (ghrunner), so
fleet-converge run 36139624393 refused object publication refused: permission_denied.

  • gunbc.managed_directory: ManagedDirectory carries group_principal (the capability its frontier
    note named); class derivation compares against that gid; setgid derived iff group != owner's;
    managed_directory_admit refuses a writer outside owner+group instead of deriving o+w.
  • gunbc.fabric_storage_placement fabric_storage_store_directories: declares both writers
    (service principal owner, ghrunner primary group) -> objects/heads 2770, root 2710.
  • gunbc.live_deploy: EnsuredManagedHostDirectory arm; ensure lowers the admission to
    install -d -m/-o/-g (re-applies on existing dirs) or a GUNBC_DEPLOY_REFUSED marker.
  • Witnesses: RED (uncovered writer refuses, would have granted other-write, 0707), positive 2770 control, and the
    srv1 spec's lowered ensure for objects/heads carries 2770 briansrls/ghrunner.

Why a group and not a new shared group: with one owner and exactly one other writer, the smallest group that admits it is that writer's own primary group. No groupadd, no membership edit, no new sudo grant. A third writer with its own gid refuses at admission, and that is when a shared group gets modeled.

Local evaluation: the remote runner refused to evaluate (HostBudgetUnreadable: no cgroup memory bound) and the emit test was OOM-killed, so these witnesses have not run yet. The required floor lane on this PR will be their first execution.

Noted, not changed: the roster row fleet_posix_ci_runner_user says uid 1001, but srv1's observed ghrunner is uid 999. The emitted ensure uses names, and the class check only compares against gid 1000, so this change doesn't depend on it.

After merge: the srv1 dashboard deploy re-applies ownership (install -d on existing dirs). Wet control: rerun fleet-converge spark_v41_runtime_image_build host=srv1 target=srv8; the host-effect claim should land.

🤖 Generated with Claude Code

…+ CI claim principal)

The srv1 deploy ensured /opt/gunbc/fabric-storage/{,objects,heads} as briansrls:briansrls 0755,
but the host-effect claim writes those files directly as the CI job principal (ghrunner), so
fleet-converge run 36139624393 refused `object publication refused: permission_denied`.

- gunbc.managed_directory: ManagedDirectory carries group_principal (the capability its frontier
  note named); class derivation compares against that gid; setgid derived iff group != owner's;
  managed_directory_admit refuses a writer outside owner+group instead of deriving o+w.
- gunbc.fabric_storage_placement fabric_storage_store_directories: declares both writers
  (service principal owner, ghrunner primary group) -> objects/heads 2770, root 2710.
- gunbc.live_deploy: EnsuredManagedHostDirectory arm; ensure lowers the admission to
  install -d -m/-o/-g (re-applies on existing dirs) or a __GUNBC_DEPLOY_REFUSED__ marker.
- Witnesses: RED (uncovered writer refuses, would have been 0772), positive 2770 control, and the
  srv1 spec's lowered ensure for objects/heads carries 2770 briansrls/ghrunner.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@gunbai-bot

gunbai-bot Bot commented Sep 25, 2026

Copy link
Copy Markdown
Contributor Author

Re: group write on files (proud-deer-538). Checked in the store code: heads are never rewritten in place, and no principal rewrites or deletes another's file. That makes directory write (2770) sufficient, and files keep the umask's 0644.

  • Head advance: gunbc.fabric_storage_file_store fabric_storage_file_advance calls gunbc.durable_cas_file_store file_compare_and_set with DefaultAccessCreateOnly. Each generation is a NEW file, <key>.<N> (cas_file_slot_path). The CAS is the exclusive publish of generation N+1, not an update of N. The module states generations are append-only and that the store offers no delete.
  • Objects: fabric_storage_file_put is filesystem_create_new, write-once.
  • The create-new realization (extdeps_filesystem_rust_realization gunbc_file_write_create_new): the writer opens its OWN staging sibling <path>.gunbc-create-<pid>-<seq> with O_EXCL, writes and fsyncs it, then hard_links it to the final name, which fails if the name exists. The only unlink is remove_file of that same writer's staging file, which needs only directory write (no sticky bit).
  • No Delete, Remove or plain Write effect appears in durable_cas_file_store, fabric_storage_file_store or fabric_storage_serve.

So when writer B advances a head writer A created, B creates <key>.<N+1> in a directory it can write (group, 2770) and reads A's <key>.<N> (0644). No permission_denied path exists, so there is no 0660 change and no B-over-A RED. The assumption this rests on (create-only, no rewrite, no delete) is written into the fabric_storage_store_directories note. If a rewrite or delete is ever added to the store, that note and this mode have to be re-derived together.

gunbc-ci-auto-heal and others added 3 commits September 25, 2026 14:24
…'admission')

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
… 0772

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…rants other-write (0707), not a hand-computed octal

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@briansrls
briansrls added this pull request to the merge queue Sep 25, 2026
Merged via the queue into main with commit 73af40b Sep 25, 2026
5 checks passed
@briansrls
briansrls deleted the session/eager-badger-341 branch September 25, 2026 23:46
@briansrls
briansrls restored the session/eager-badger-341 branch September 25, 2026 23:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant