Audit log as a grantable account-level permission (#45) - #59
Merged
Conversation
Audit log as a grantable account-level permission (#45) The web audit endpoint was owner-only (entries carry player IPs). Let an owner grant a trusted co-admin read access without making them an owner, via an account-level flag distinct from the per-server RBAC scopes. - auth.ts: `canAudit` on the stored user + AuthUser; new setUserAudit(id, canAudit) returning the username for attribution. Migrates cleanly (`?? false`) for users.json written before this. - server.ts: /api/audit gate becomes `owner || canAudit`; /api/me now reports canAudit so the panel can reveal the tab. - IPC web:user-audit (desktop-only, like the rest of user management — so "owner-only to set" holds; NOT exposed as a web route, which would let a settings-scoped user self-grant). The grant AND revoke are themselves audited (source panel, action user.audit-grant). - WebPanelView: an "audit log" checkbox in the (non-owner) permissions modal; only writes when it actually changed. - panelHtml: Audit tab shows when `owner || canAudit` (myCanAudit set from both the login response and /api/me). - en/tr strings. Verify: MSMS_SMOKE_WEB — a fresh non-owner is 403, 200 after the grant (with /api/me carrying the flag), 403 again after revoke; the existing friend_t 403 test is untouched (dedicated auditor_t user). Panel tab visibility checked in a real browser engine across all four role/flag combinations. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> @
This was referenced Jul 27, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #45. First of the UX & access pass.
Why
The web audit endpoint was owner-only because entries carry player IPs (personal data). That meant a trusted co-admin couldn't see the log at all. This adds an account-level
canAuditgrant (distinct from the per-server RBAC scopes, since audit is global) so an owner can hand out audit access without full ownership.Changes
auth.ts—canAuditon the stored user andAuthUser; newsetUserAudit(id, canAudit)returning the username for attribution. Migrates cleanly (?? false) for ausers.jsonwritten before this.server.ts—/api/auditgate becomesowner || canAudit;/api/menow reportscanAuditso the panel can reveal the tab.web:user-audit— desktop-only, like the rest of user management, so "owner-only to set" holds. Deliberately not a web route: a web endpoint would let asettings-scoped user self-grant access to personal-data IPs. The grant and the revoke are themselves audited (source: panel,action: user.audit-grant).WebPanelView— an "audit log" checkbox in the (non-owner) permissions modal; only writes when it actually changed, so it doesn't log a spurious grant on every perms save.panelHtml— the Audit tab shows whenowner || canAudit(myCanAuditset from both the login response and/api/me).Verify
typecheck,build— pass.MSMS_SMOKE_WEBPASS: a fresh non-owner (auditor_t) is403,200after the grant (with/api/mecarrying the flag),403again after revoke. The existingfriend_t → 403audit test is untouched (dedicated user, no state leak).