Skip to content

v2.3.2 - #107

Merged
byteful merged 1 commit into
mainfrom
dev
Aug 21, 2026
Merged

v2.3.2#107
byteful merged 1 commit into
mainfrom
dev

Conversation

@byteful

@byteful byteful commented Aug 21, 2026 •

Copy link
Copy Markdown
Member

Confidence Score: 3/5

Not safe to merge until Super Admin identity is separated from billing access and client permission inheritance matches the backend contract.

Focused executable checks reproduced both permission failures using the real client hook and the related backend permission contract. The findings are independent: one hides authorized child settings, while the other grants Super Admin-only client behavior to a non-Super Admin role.

Files Needing Attention: client/src/hooks/use-permissions.tsx needs the Super Admin predicate and hierarchical permission matching corrected. client/src/lib/permissions.ts should also be reviewed because the billing permission is currently designated as the Super Admin-exclusive permission.

T-Rex T-Rex Logs

What T-Rex did

  • Ran the focused Super Admin billing permission validation script and captured logs showing both a missing-permission case and a permission-enabled case.
  • Executed the focused parent-to-child permission validation script and saved the repository status after validation, including a successful parent-grant permission result and a test attempt blocked by a missing Java runtime.
  • T-Rex posted additional P1 finding proofs in the review thread, documenting their existence and scope.
  • Validated the backend and frontend permission contracts without modifying repository source files, and noted that validation artifacts were created to support later review.
  • Observed a permission-change result after capture where isSuperAdmin became true for a role with billing-related permissions, and listed affected client gates and UI components.

View all artifacts

T-Rex Ran code and verified through T-Rex

Prompt To Fix All With AI
### Issue 1
client/src/hooks/use-permissions.tsx:58
**Billing permission impersonates Super Admin**

A custom non-Super Admin role granted only `admin.settings.view.billing` is classified as a Super Admin by the client. The executed comparison showed that adding only this permission changes `isSuperAdmin` from false to true, enables equal-authority role modification and assignment of another staff member, and reveals the billing, server-config, and migration settings sections. Billing access is independently grantable; derive Super Admin status from an authoritative role or identity signal instead of this permission.

### Issue 2
client/src/hooks/use-permissions.tsx:60-63
**Parent settings grants do not unlock child settings**

The permissions endpoint returns stored role grants, while the backend authorizes child permissions from a parent grant. A role holding only `admin.settings.view` is therefore authorized by the backend for `admin.settings.view.storage`, but this exact-membership check returns false and hides the Usage settings subcategory. Apply the same delimiter-safe parent-to-child permission implication used by the backend, or return expanded effective permissions from the endpoint.

### Issue 3
client/src/hooks/use-permissions.tsx:51-56
**Trivial values are over-memoized**

These new `useMemo` calls wrap inexpensive array normalization and Set construction without a measured performance need, adding dependency bookkeeping and indirection contrary to the repository's React Compiler guidance.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Reviews (1): Last reviewed commit: "perms fix" | Re-trigger Greptile

Greptile also left 3 inline comments on this PR.

Context used:

  • Rule used - This is a React frontend project on React 19 with ... (source)
  • Context used - Ensure all code meets SOLID, DRY, and KISS softwar... (source)


return defaultPermissions[user.role] || [];
}, [user, serverPermissions]);
const isSuperAdmin = grantedPermissions.has(SUPER_ADMIN_EXCLUSIVE_PERMISSION);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Billing permission impersonates Super Admin

A custom non-Super Admin role granted only admin.settings.view.billing is classified as a Super Admin by the client. The executed comparison showed that adding only this permission changes isSuperAdmin from false to true, enables equal-authority role modification and assignment of another staff member, and reveals the billing, server-config, and migration settings sections. Billing access is independently grantable; derive Super Admin status from an authoritative role or identity signal instead of this permission.

Context Used: Ensure all code meets SOLID, DRY, and KISS softwar... (source)

Artifacts

Focused Super Admin billing permission validation script

  • Authored Vite and React validation script that runs the real permission hook against identical custom-role scenarios; it directly exercises the claimed derivation and UI gate helpers.

Custom Billing Operator without billing permission

  • Executed baseline run for the custom non-Super Admin role without the billing permission; it shows all tested Super Admin behavior remains denied.

Custom Billing Operator with billing permission

  • Executed comparison run for the same custom non-Super Admin role with only the billing permission; it shows false Super Admin classification and elevated client UI behavior.

View artifacts

T-Rex Ran code and verified through T-Rex

Prompt To Fix With AI
This is a comment left during a code review.
Path: client/src/hooks/use-permissions.tsx
Line: 58

Comment:
**Billing permission impersonates Super Admin**

A custom non-Super Admin role granted only `admin.settings.view.billing` is classified as a Super Admin by the client. The executed comparison showed that adding only this permission changes `isSuperAdmin` from false to true, enables equal-authority role modification and assignment of another staff member, and reveals the billing, server-config, and migration settings sections. Billing access is independently grantable; derive Super Admin status from an authoritative role or identity signal instead of this permission.

**Context Used:** Ensure all code meets SOLID, DRY, and KISS softwar... ([source](https://app.greptile.com/review/custom-context?memory=instruction-0))

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Comment on lines 60 to +63
const hasPermission = useCallback((permission: string): boolean => {
if (!user) return false;
return userPermissions.some(p => p === permission || permission.startsWith(p + '.'));
}, [user, userPermissions]);
return grantedPermissions.has(permission);
}, [user, grantedPermissions]);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Parent settings grants do not unlock child settings

The permissions endpoint returns stored role grants, while the backend authorizes child permissions from a parent grant. A role holding only admin.settings.view is therefore authorized by the backend for admin.settings.view.storage, but this exact-membership check returns false and hides the Usage settings subcategory. Apply the same delimiter-safe parent-to-child permission implication used by the backend, or return expanded effective permissions from the endpoint.

Context Used: Ensure all code meets SOLID, DRY, and KISS softwar... (source)

Artifacts

Focused parent-to-child permission validation script

  • Authored validation script reads the frontend and backend contracts and executes the parent-grant versus child-gate scenario, proving the divergent result.

Successful parent-grant permission validation output

  • Executed Node validation output shows the backend authorizes storage while the client denies it and hides the Usage subcategory, verifying the bug.

Focused backend hierarchy test attempt blocked by missing Java

  • Attempted focused backend JUnit hierarchy test could not start because this environment has neither JAVA_HOME nor a java executable; the source-contract script supplied the completed runtime proof.

Repository status after validation

  • Executed Git status confirms the only untracked content is the required trex-artifacts validation evidence, with no source modification.

View artifacts

T-Rex Ran code and verified through T-Rex

Prompt To Fix With AI
This is a comment left during a code review.
Path: client/src/hooks/use-permissions.tsx
Line: 60-63

Comment:
**Parent settings grants do not unlock child settings**

The permissions endpoint returns stored role grants, while the backend authorizes child permissions from a parent grant. A role holding only `admin.settings.view` is therefore authorized by the backend for `admin.settings.view.storage`, but this exact-membership check returns false and hides the Usage settings subcategory. Apply the same delimiter-safe parent-to-child permission implication used by the backend, or return expanded effective permissions from the endpoint.

**Context Used:** Ensure all code meets SOLID, DRY, and KISS softwar... ([source](https://app.greptile.com/review/custom-context?memory=instruction-0))

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Comment on lines +51 to +56
const userPermissions = useMemo<string[]>(
() => (Array.isArray(serverPermissions) ? serverPermissions : []),
[serverPermissions]
);

// Query still loading - use default role permissions until first fetch completes
const defaultPermissions: Record<string, string[]> = {
'Super Admin': [
PERMISSIONS.ADMIN_SETTINGS_VIEW,
PERMISSIONS.ADMIN_SETTINGS_MODIFY,
PERMISSIONS.ADMIN_STAFF_MANAGE,
PERMISSIONS.ADMIN_AUDIT_VIEW,
PERMISSIONS.TICKET_VIEW_ALL,
PERMISSIONS.TICKET_REPLY_ALL,
PERMISSIONS.TICKET_CLOSE_ALL,
PERMISSIONS.TICKET_DELETE_ALL,
],
'Admin': [
PERMISSIONS.ADMIN_SETTINGS_VIEW,
PERMISSIONS.ADMIN_STAFF_MANAGE,
PERMISSIONS.ADMIN_AUDIT_VIEW,
PERMISSIONS.TICKET_VIEW_ALL,
PERMISSIONS.TICKET_REPLY_ALL,
PERMISSIONS.TICKET_CLOSE_ALL,
],
'Moderator': [
PERMISSIONS.TICKET_VIEW_ALL,
PERMISSIONS.TICKET_REPLY_ALL,
PERMISSIONS.TICKET_CLOSE_ALL,
],
'Helper': [
PERMISSIONS.TICKET_VIEW_ALL,
PERMISSIONS.TICKET_REPLY_ALL,
],
};
const grantedPermissions = useMemo(() => new Set(userPermissions), [userPermissions]);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Trivial values are over-memoized

These new useMemo calls wrap inexpensive array normalization and Set construction without a measured performance need, adding dependency bookkeeping and indirection contrary to the repository's React Compiler guidance.

Rule Used: This is a React frontend project on React 19 with ... (source)

Prompt To Fix With AI
This is a comment left during a code review.
Path: client/src/hooks/use-permissions.tsx
Line: 51-56

Comment:
**Trivial values are over-memoized**

These new `useMemo` calls wrap inexpensive array normalization and Set construction without a measured performance need, adding dependency bookkeeping and indirection contrary to the repository's React Compiler guidance.

**Rule Used:** This is a React frontend project on React 19 with ... ([source](https://app.greptile.com/modl-gg/-/custom-context?memory=b7532101-0c9e-4ab6-b168-353a105ba593))

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

@byteful
byteful merged commit e7e747e into main Aug 21, 2026
2 of 3 checks passed
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