You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/claude/permissions.md
+8-4Lines changed: 8 additions & 4 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -19,7 +19,10 @@ Logins are enforced as connection credentials at both front doors (TDS endpoint
19
19
-`SecurityIdentifierString` (string?) — the deterministic `S-1-9-3-…` SID a `CREATE USER … WITHOUT LOGIN` user reports through `SYSTEM_USER` / Msg 916 (FNV-derived from the name).
20
20
-`EffectiveLoginIdentity` — the `SYSTEM_USER` value while impersonating this user (login ?? SID ?? name).
21
21
22
-
**`DatabasePermission`** (`src/SqlServerSimulator/DatabasePermission.cs`) carries class + major_id + minor_id + grantee/grantor ids + permission_name + 4-char type code + state (`G`/`W`/`D`/`R`).
22
+
**`DatabasePermission`** (`src/SqlServerSimulator/DatabasePermission.cs`) carries class + major_id + minor_id + grantee/grantor ids + a `Permission` enum + a `PermissionState` enum (Grant / GrantWithGrantOption / Deny / Revoke, projecting the `G`/`W`/`D`/`R` state codes).
23
+
Canonical rows draw their `permission_name` and 4-char `type` code from `PermissionCatalog` at projection; off-catalog names (`Permission.Other`) carry their raw text on `PermissionName` and are never matched by a permission check.
24
+
`PermissionChecker` compares the enum throughout (closure walk, DENY precedence, covering/scope walk, read/write/DDL fixed-role virtual grants) — no permission-name string comparison remains on any check path; `HAS_PERMS_BY_NAME` / GRANT parsing resolve the incoming name to the enum once at the boundary via `Permission.Resolve` (a zero-alloc span switch, a `PermissionCatalog` static extension member).
25
+
The catalog surfaces per-enum lookups as extension members (`permission.CanonicalName` / `.CanonicalTypeCode` / `.Category` / `.Covering(class)`, `state.Code` / `.Description`); row-shaped concerns live on `DatabasePermission` itself (`IsFor` securable+permission identity, `DisplayName` / `DisplayTypeCode` projection).
23
26
24
27
Both live on `Database`:
25
28
-`Database.Principals` — `ConcurrentDictionary<string, DatabasePrincipal>` keyed by name
@@ -145,9 +148,10 @@ In-process connections never authenticate — login DDL through one is how the r
145
148
146
149
## Permission type-code derivation
147
150
148
-
`Simulation.CanonicalPermissionTypeCode` imports the canonical 4-char `sys.database_permissions.type` codes from `sys.fn_builtin_permissions` for the common OBJECT / SCHEMA / DATABASE / DATABASE_PRINCIPAL permissions (`SELECT` → `SL`, `UPDATE` → `UP`, `EXECUTE` → `EX`, `CONTROL` → `CL`, `IMPERSONATE` → `IM`, `CREATE TABLE` → `CRTB`, …).
149
-
Codes are stored space-padded to 4 chars and the view's `type` column is `char(4)`, matching real's trailing-space-bearing values (`'SL '`).
150
-
Names outside the imported set (AW's `VIEW ANY COLUMN … DEFINITION` grants) fall back to the first-letter-of-each-word heuristic (`VIEW ANY COLUMN MASTER KEY DEFINITION` → `VACM`), which won't byte-match real for every long name.
151
+
`PermissionCatalog` (`src/SqlServerSimulator/Permission.cs`) is the single source of truth: one static table indexed by the `Permission` enum carries each member's canonical name, 4-char `sys.database_permissions.type` code (imported from `sys.fn_builtin_permissions` for the common OBJECT / SCHEMA / DATABASE / DATABASE_PRINCIPAL permissions — `SELECT` → `SL`, `UPDATE` → `UP`, `EXECUTE` → `EX`, `CONTROL` → `CL`, `IMPERSONATE` → `IM`, `CREATE TABLE` → `CRTB`, …), and read/write/DDL category; the covering graph and name→enum resolver live alongside it.
152
+
Codes are projected space-padded to 4 chars and the view's `type` column is `char(4)`, matching real's trailing-space-bearing values (`'SL '`).
153
+
Names outside the catalog resolve to `Permission.Other` and project their raw stored text plus a first-letter-of-each-word type-code heuristic (`VIEW ANY COLUMN MASTER KEY DEFINITION` → `VACM`), which won't byte-match real for every long name.
154
+
Canonical names project their catalog spelling regardless of the GRANT's casing (real normalizes them the same way).
151
155
152
156
`class_desc` / `state_desc` are spelled out per the probe-confirmed enum:
/// State code: <c>G</c>=Grant, <c>R</c>=Revoke, <c>D</c>=Deny,
78
-
/// <c>W</c>=Grant_with_grant. Real SQL Server treats REVOKE as a
79
-
/// row-deletion rather than a stored state; the simulator keeps the
80
-
/// REVOKE row so DENY ⇄ GRANT toggling can be observed in
81
-
/// <c>sys.database_permissions</c> for debugging.
71
+
/// State: Grant / GrantWithGrantOption / Deny / Revoke. Real SQL Server treats
72
+
/// REVOKE as a row-deletion; the simulator likewise removes rows on REVOKE and
73
+
/// keeps only live Grant / GrantWithGrantOption / Deny rows.
82
74
/// </summary>
83
-
publicreadonlystringState=state;
75
+
publicreadonlyPermissionStateState=state;
76
+
77
+
/// <summary>The catalog-view <c>permission_name</c> — the canonical catalog spelling, or the raw stored text for an off-catalog (<see cref="SqlServerSimulator.Permission.Other"/>) name.</summary>
0 commit comments