Classify an API endpoint's authorization (the M3b catalogue test)¶
Every routed API action and every public NotificationHub method must be catalogued. CI fails otherwise
(EndpointAuthorizationCatalogTests in SyRF.API.Endpoint.Tests, part of application-authority milestone M3b of the
transition plan).
What the test enforces¶
The inventory is MVC's own action discovery (the same application parts AddControllers maps), so a new controller
or action is picked up without anyone listing it.
- A policy or an exception. Each action carries an
[Authorize(<policy>)]whose policy the host registers (ProjectAuthorization,StageAuthorization,ApplicationAuthorizationor the named parity-read policy), or it has an entry inEndpointAuthorizationExceptionswith a category and a reason. The global authenticated-user filter alone is not a classification. - Anonymous and public endpoints are pinned by their response fields. For
AnonymousandPublicMetadataentries the test computes every JSON field path of the declared success response ([ProducesResponseType], or the return type) and compares it with the listed paths. Adding a field to a public response fails CI until someone decides it is public. An action returning an untypedIActionResultcannot be pinned: its entry must sayResponseFields.Undeclaredand describe the body in its reason (or declare[ProducesResponseType]). - Gaps stay honest. A
KnownGapentry must name a tracking reference (#…) and must still lack a policy: fixing it fails the test until the entry is deleted. An entry for an action that now has a policy, or no longer exists, also fails. - The catalogue is consistent.
- Every project and stage policy resolves to an activity enum member with a deployed
ResourceSecurity.jsondefault. A policy that does not resolve denies everyone silently; a missing default is a500. - Every activity has a default, and every default names a known activity, once.
- Every application policy has a default.
StageViewandStageDeleteare the two known unresolvable stage policies (#3335 D3).- Named protected workloads (export creation and download, administrative email sends, batch Risk of Bias, PDF corrections, RoB writes, bulk-PDF report and path downloads) must carry a resource policy. Moving one into the exception table is itself a failure.
Adding an endpoint¶
- Project or stage data: use the matching
Project…Policy/Stage…Policyon a route with{projectId}(and{stageId}), and bind every body or route ID you touch to that project inside the action (404if it is foreign, writing nothing).StudyController's study and correction actions show the pattern; Calculate Risk of Bias authorization shows a new activity end to end. A new activity needs itsProjectActivity/StageActivitymember (appended, never inserted) and aResourceSecurity.jsondefault. - Application-wide administration: an
Application…Policywhose activity is in the PM allowlist (application-authority mode). - Otherwise: add an
EndpointAuthorizationExceptionsentry. UseAuthenticatedSelfonly when the action reads or writes nothing but the caller's own records. UseInActionAuthoritywhen the action decides through an authority gate in its body. UseTrustedServicefor workload identities, never human sessions.AnonymousandPublicMetadataentries list their response fields; copy the "actual" list from the failure message only after checking that every field is fit for an anonymous or non-member caller.