Decide guest grants explicitly instead of by permission name

guest_grantable_permissions() opened any permission whose name ended
'.view' or '.read' to the guest role, on the reasoning that reading is
the safe default. That is true of a permission gating a list of asset
numbers and false of one gating bytes, and a suffix cannot tell them
apart. Twenty-four of eighty-five qualified and none had been decided:

  applications.view  reached the SYSTEM-context PowerShell bodies and
                     the installer binaries pushed to bays
  backups.view       returned the full payload that the separate
                     backups.download permission exists to protect
  assets.view        gated a global search that queries the staff
                     directory, USB history and network inventory with
                     no per-domain check of its own
  audit.view         usernames, addresses, the before/after of every
  settings.view      change, and every setting row - both admin
                     category, opened by naming alone
  users.view         gates nothing at all; list_users is
                     require_role('admin')

Every entry is now declared, by CORE_GUEST_GRANTABLE or by the plugin
that owns the permission, having read what its routes actually return.
Adding one is a code change, which is the point: it puts the decision
in a diff rather than in a suffix.

The two routes serving script bodies and installer packages move to a
new applications.download permission, which is not grantable, so a site
can still open the catalogue metadata to its floor without the bytes
going with it.

The declared set preserves the grants this site had already chosen:
applications.view, computers.view, endpoints.view, reports.view,
tools.secrets, warranty.view.

Two known gaps are recorded on the hooks that expose them rather than
silently carried: the computer serializer publishes every column plus
resolved rdp:// and vnc:// links, and the per-asset endpoint panels are
keyed on a small integer so walking ids reconstructs much of the roster
that endpoints.fleet exists to protect. Neither is widened here.

A shipped test was granting guests audit.view and passing.

Scope: product
This commit is contained in:
cproudlock
2026-08-31 07:01:52 -04:00
parent 5f27f81e88
commit 347402896c
10 changed files with 192 additions and 41 deletions

View File

@@ -2013,3 +2013,20 @@ class ComputersPlugin(BasePlugin):
('computers.edit', 'Edit computers', 'computers'),
('computers.delete', 'Delete computers', 'computers'),
]
def get_guest_grantable_permissions(self) -> List[str]:
"""Declared because a site chose it: the floor looks PCs up by number.
KNOWN GAP, tracked separately. The computer serializer is
BaseModel.to_dict(), so it publishes every column - serialnumber, the
Azure device and object ids - and the detail route resolves
accessmethods into working rdp:// and vnc:// links plus the full
Communication row. A guest granted this gets all of it, on the LIST
route as well, so it is one request rather than one per asset.
The fix is a field allowlist on Computer.to_dict() plus suppressing the
resolved links unless the caller holds a remote-access permission. Do
not widen this hook until that lands; a site enabling guest access
today should weigh it.
"""
return ['computers.view']