feat(cubesys): Task 6 — owner enforcement on mutating commands
Stamp owner_local_user on records written via prog/write and gate the mutating paths (prog, write, del — both live and buffered txn) so a session may only create or overwrite a record whose owner_local_user matches its HELLO-declared identity. Design (logical + expedient for the whole project): - Owner is the durable record-level CubeHeader.owner_local_user field, so enforcement is replay-safe and works across daemon restart. - Enforcement is opt-in/non-breaking: gated only when the session has a stamped identity AND the record has an owner. First write by an owner claims an unowned coord; a session with no identity (tests, legacy) writes freely. - COMMIT re-checks owner on each buffered op before applying, so a concurrent cross-owner commit between BEGIN and COMMIT is rejected (txn is restored for retry, not silently dropped). - seal/open (encrypted raw put/del) left ungated for now: their headers are not owner-stamped yet — tracked as follow-up. Verification: - ./check quick: EXIT=0, fmt+clippy clean, 26 cubesys tests (added owner_enforcement_blocks_cross_owner_overwrite, owner_enforcement_allows_first_claim_and_same_owner, for_tenant_carries_identity). - Ad-hoc daemon verifier over real cube-server socket (LE framing): cross-owner overwrite + delete rejected, same-owner + first-claim allowed, no-HELLO legacy writes allowed. ALL PASS.
This commit is contained in:
+15
-2
@@ -491,6 +491,17 @@ impl ConcurrentStore {
|
||||
out
|
||||
}
|
||||
|
||||
/// The `owner_local_user` stamped on the record at `key`, if it has one.
|
||||
/// Used by owner enforcement (Task 6): a mutating command may only
|
||||
/// overwrite a record whose owner matches the session's identity owner.
|
||||
pub fn owner(&self, key: &Czyx) -> Option<String> {
|
||||
self.inner
|
||||
.read()
|
||||
.unwrap()
|
||||
.get_record(key)
|
||||
.and_then(|(h, _)| h.owner_local_user.clone())
|
||||
}
|
||||
|
||||
/// A consistent point-in-time snapshot of the whole store. Used by the VM
|
||||
/// and cubefs, which take a `CubeStore` by value. A read-lock clone, so it
|
||||
/// does not block concurrent readers (it only waits for an in-flight
|
||||
@@ -580,6 +591,8 @@ impl ConcurrentStore {
|
||||
}
|
||||
|
||||
/// Store a code cell at `path` (the path->code bridge), durability-logged.
|
||||
/// `owner` (when set) is stamped on the record's `owner_local_user` field
|
||||
/// so owner enforcement (Task 6) can later reject cross-owner overwrites.
|
||||
pub fn put_code_cell(
|
||||
&self,
|
||||
path: &str,
|
||||
@@ -587,9 +600,9 @@ impl ConcurrentStore {
|
||||
name: &str,
|
||||
links: &[Czyx],
|
||||
code: &[Op],
|
||||
owner: Option<&str>,
|
||||
) -> Result<Czyx, crate::SysError> {
|
||||
let coord =
|
||||
self.with_mut(|store| crate::store_code_cell(store, path, kind, name, links, code))?;
|
||||
let coord = self.with_mut(|store| crate::store_code_cell(store, path, kind, name, links, code, owner))?;
|
||||
if let Some(v) = self.get_raw(&coord) {
|
||||
self.log_put(coord, v);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user