Skip to content

History / Raising the PHP Floor

Revisions

  • Absorb the README's deep-dive content ahead of the README slim-down The project README is being reduced to a landing page; every fact it held that the wiki lacked is merged here first (615 lines across 33 pages): the full email-threading & reply-flow design onto Tickets, directory layout + module-page pattern + file-locations reference onto Architecture, per-endpoint tables onto API Reference, MFA login flow + LDAP subsection + injection/audit notes onto Security, the icon library and editor internals onto Network Mapper, Branding + landing-page and help/search internals + debug-tool depth onto System, planned objects onto CMDB, custody/locations/warranty onto Assets, and more. Also corrects stale claims found during the audit: the Knowledge audience table still said customer-visible articles had no reader (the portal Knowledge section shipped), a pre-#903 Portal-Privacy ambiguity row, the Workflows trigger-wiring section (catalogue spans every module now), the superseded System module-access bullet, the Multi-Tenancy users page marked "Planned" for a shipped feature, and the locale count (21 languages incl. Ukrainian, not 20). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

    @edmozley edmozley committed Jul 21, 2026
  • PHP-Enums-and-RBAC: describe the code that exists, not the code that used to Ed's catch, and a fair one — the page was comparing enums against a string-keyed design that no longer exists. It quoted four functions that have been deleted (rbacCapabilities, rbacAllCapabilityKeys, rbacCapabilityExists, rbacCapabilityLabel), invented a capability that was never shipped (tickets.manage_settings), and presented all of it under "what we built last week". A wiki page should describe the actual code. Rewritten against the codebase as it stands: Cap:: constants, and a registry DERIVED from each module's settings manifest. Every symbol and every number on the page verified against the source — 76 capabilities, 76 constants, and the guard's parameter really is still `string`. The rewrite also forced an honest walk-back the old page never made. Its central claim was that enums would collapse four hand-maintained lists (constants, registry, tab layout, setting-key map) onto one type. THOSE LISTS WERE ALREADY COLLAPSED — without enums — by deriving the registry from the manifest. So the headline benefit is banked, and the metadata arguably lives somewhere better: next to the tab it belongs to, rather than on the type. What genuinely remains is one narrow thing: a guard whose signature could refuse a string outright. requireCapabilityJson(string $capability) still accepts one; the constant makes the right thing easy and a typo loud, but it cannot make the wrong thing impossible. That is a real gap, and it is now the ONLY one — which is exactly why the floor stayed at 7.4. Also corrected two claims on the floor page that had aged with it: it still called the enum "the only correctness argument on offer" (it isn't — the constants answered that), and its phase-2 plan still listed the deleted helpers among the things the swap would remove.

    @edmozley edmozley committed Jul 14, 2026
  • Wiki: split the PHP floor page, refresh Roles & Permissions, restructure the sidebar The PHP floor page had grown to 861 lines and was three documents in a trench coat: a decision, a language tour, and a deep argument about permission keys. Split into three, each standing alone: Raising-the-PHP-Floor (307) the DECISION — where we are, who breaks, the verdict, and the constants-to-enums bridge PHP-8-Language-Features (261) the 101 tour of 8.0/8.1 with before/after from real code, including the features that WOULDN'T help us, said plainly PHP-Enums-and-RBAC (353) the one feature the argument turns on — and the reason a capability is a Cap:: constant and never a string. Worth reading even if the floor never moves, because it explains the permission system. Section numbers and cross-references rewritten by meaning rather than by find-and-replace, since the sections changed pages. Roles & Permissions was stale: written before the manifest became the single declaration and before the endpoint audit existed. Now says that capabilities are derived from one file per module (and why the four-list version was the bug), and carries a table of what D005 has actually found — the shared settings endpoint, six Intune endpoints, all 49 RFP Builder endpoints, unauthenticated audit-log forgery, and an LMS learner reaching the authoring settings. Every one found by hand, by accident, which is the point. Sidebar: the security pages are now grouped by the three layers they belong to (module access → capabilities → administrator), rather than a flat list, and all nine RBAC/PHP pages are linked. The two new PHP pages nest under the floor page.

    @edmozley edmozley committed Jul 13, 2026
  • PHP floor page: note that the registry is now derived from manifests The code samples in section 3.1 described rbacCapabilities() as current. They aren't any more — capabilities are Cap:: constants and the registry derives from the settings manifests. Kept the samples (they show the string-keyed shape the enum argument is about, which is precisely what the constants replaced) but flagged them so nobody reads them as today's code.

    @edmozley edmozley committed Jul 13, 2026
  • RBAC: bring the wiki up to date with per-tab capabilities Both Roles pages predated the per-tab decision and described a system that no longer exists: rbacCapabilities() (now capRegistry), bare-string guards (now Cap:: constants), "one manage per module, split later" (we went per-tab), and a rename that orphans grants and needs a data migration (there's an alias map now). Neither mentioned the settings manifest, the shared-endpoint key ownership, the sensitive badge, the umbrella, or the security fix. Roles & Permissions — rewritten around the per-tab model: why a tab is the unit (vCenter credentials sit next to a lookup list), the umbrella, sensitive badging, and a full "how it's enforced" section covering all three mechanisms — panels not rendered rather than hidden, hard guards on every write endpoint, and per-KEY authorisation on the shared settings endpoint (including the #829 hole it closed). Plus what is deliberately NOT guarded, and why gating a read breaks the module. Roles — Developer Guide — rewritten as the extension guide: why capabilities are constants (a mistyped string 403s silently and is invisible to admins, who bypass the check — so the typo becomes a privilege escalation), adding/renaming/removing a capability, and the full six-step recipe for converting a module, worked against Asset Management. Now carries the traps that actually bit: a get_* endpoint that isn't a read (get_vcenter performs the sync and Servers calls it), endpoints with no guard at all, and the reminder that converting a module is an audit of it. Plus the three-actor HTTP test matrix and a checklist. Security — the Authorisation section was wrong, not just stale: it claimed the System module "cannot be disabled" and is always accessible to active analysts, which stopped being true when is_admin shipped. Rewritten as the three layers, each with its gate and its default, and the note that hiding a button is never the control. Raising the PHP floor — made the constants-to-enums bridge concrete rather than asserted. Shows the actual migration: call sites are a symbol rename an IDE can do and the compiler verifies (a missed one FATALS; you cannot half-finish it), against hunting 200 string literals where a miss keeps working and a typo 403s in silence. The real work is confined to one file. Also states the honest caveat: constants make the typo loud, an enum makes the wrong thing impossible.

    @edmozley edmozley committed Jul 13, 2026
  • Blue sky: raising the PHP floor to 8.1 The case for dropping PHP 7.4/8.0 to unlock enums for the RBAC capability system, plus a 101 on what PHP 8.0/8.1 actually added, with before/after examples from real FreeITSM code. Parked, and the page says why: class constants close the dangerous failure mode (a typo in a capability key silently 403-ing, invisibly to the admin) without leaving 7.4. What the enum adds on top is elegance, not safety, and that doesn't justify breaking every 7.4 user's upgrade path. Documents the constant-to-enum bridge so the swap stays cheap, and the triggers for revisiting. Linked from the Blue Sky hub and the sidebar.

    @edmozley edmozley committed Jul 13, 2026