fix(bridge): grant with a null owner and read every grant back (D85)
EnsureGrant and EnsureGroupPermission passed `this` as the owner. Given an owner, Oxide first asks PermissionExists(perm, owner) — whether THAT plugin registered the name — and returns silently when it did not, so every site-authored grant of another plugin's permission was a no-op on Oxide that the report counted as applied (PLAN.md §27.6). Both now pass null and read the store back. A grant the store does not hold afterwards is reported in the new `notLanded` list instead of counted. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
This commit is contained in:
@@ -2775,6 +2775,13 @@ namespace Oxide.Plugins
|
||||
public readonly List<object> Foreign = new List<object>();
|
||||
public readonly List<string> Pending = new List<string>();
|
||||
|
||||
/// <summary>
|
||||
/// Grants the store did not hold after being told to (<c>subject:permission</c>).
|
||||
/// Reported rather than counted, so the site can never again be told a grant
|
||||
/// landed that did not (D85).
|
||||
/// </summary>
|
||||
public readonly List<string> NotLanded = new List<string>();
|
||||
|
||||
/// <summary>
|
||||
/// Group permissions an event lease holds (protocol 8). Neither applied to nor
|
||||
/// reported foreign; what the site asked for is kept on the hold instead.
|
||||
@@ -3138,12 +3145,22 @@ namespace Oxide.Plugins
|
||||
if (permission.GroupHasPermission(op.Subject, op.Object))
|
||||
{
|
||||
job.AlreadyCorrect++;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
permission.GrantGroupPermission(op.Subject, op.Object, this);
|
||||
|
||||
// **`null`, not `this`, as the owner (D85).** With an owner, Oxide's grant
|
||||
// first asks `PermissionExists(perm, owner)` — whether THAT plugin registered
|
||||
// the name — and returns without a word when it did not. Every permission the
|
||||
// site grants belongs to some other plugin, so from phase 7 until phase 13 this
|
||||
// call did nothing on Oxide and was counted as applied (PLAN.md §27.6). The
|
||||
// read-back is what makes the count true: only a grant the store now holds
|
||||
// is reported as one.
|
||||
permission.GrantGroupPermission(op.Subject, op.Object, null);
|
||||
|
||||
if (permission.GroupHasPermission(op.Subject, op.Object))
|
||||
job.GroupPermissions++;
|
||||
}
|
||||
else
|
||||
job.NotLanded.Add(op.Subject + ":" + op.Object);
|
||||
|
||||
break;
|
||||
|
||||
@@ -3173,12 +3190,16 @@ namespace Oxide.Plugins
|
||||
if (HoldsDirectly(op.Subject, op.Object))
|
||||
{
|
||||
job.AlreadyCorrect++;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
permission.GrantUserPermission(op.Subject, op.Object, this);
|
||||
|
||||
// The same owner trap as the group grant above (D85), and the same read-back.
|
||||
permission.GrantUserPermission(op.Subject, op.Object, null);
|
||||
|
||||
if (HoldsDirectly(op.Subject, op.Object))
|
||||
job.Grants++;
|
||||
}
|
||||
else
|
||||
job.NotLanded.Add(op.Subject + ":" + op.Object);
|
||||
|
||||
break;
|
||||
|
||||
@@ -3478,6 +3499,7 @@ namespace Oxide.Plugins
|
||||
report["foreign"] = job.Foreign;
|
||||
report["leased"] = job.Leased;
|
||||
report["pending"] = job.Pending;
|
||||
report["notLanded"] = job.NotLanded;
|
||||
report["operations"] = job.Ops.Count;
|
||||
|
||||
if (!string.IsNullOrEmpty(job.SetId))
|
||||
@@ -3490,7 +3512,7 @@ namespace Oxide.Plugins
|
||||
$"ops={job.Ops.Count} grants={job.Grants} revokes={job.Revokes} " +
|
||||
$"groups={job.GroupsCreated} members={job.Members} same={job.AlreadyCorrect} " +
|
||||
$"unresolved={job.Unresolved.Count} foreign={job.Foreign.Count} " +
|
||||
$"pending={job.Pending.Count} at={DateTime.UtcNow:HH:mm:ss}Z";
|
||||
$"pending={job.Pending.Count} notLanded={job.NotLanded.Count} at={DateTime.UtcNow:HH:mm:ss}Z";
|
||||
|
||||
EmitFrame(report);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user