You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Ship the DLS OPA access policy in the image instead of a ConfigMap #5
b01-1's tiled loads DiamondOpenPolicyAgentAuthorizationPolicy (the class that asks OPA whether a token may read or write a node, using the proposal/visit/beamline in its access blob) from a ConfigMap at run time:
services/b01-1-tiled/templates/configmap.yaml in b01-1-services holds dls.py and an empty __init__.py
the chart mounts it at /deploy/access_policy and sets PYTHONPATH=/deploy/ so tiled can import access_policy.dls
Runtime-loaded code like this escapes the image's tests and versioning, and editing the ConfigMap silently changes running code. It belongs in this package like the visr router.
To do:
add the class as dls_tiled.access_policy with tests (it subclasses tiled.access_control.access_policies.ExternalPolicyDecisionPoint, so check it against the tiled version in TILED_VERSION)
release
in b01-1-services, remove the ConfigMap template, its volume and mount, and PYTHONPATH, and reference dls_tiled.access_policy:DiamondOpenPolicyAgentAuthorizationPolicy when access_control is switched on
Nothing calls the policy today: access_control is commented out in b01-1's tiled config, and the scopes_map there grants every valid identity token write access as a stop-gap. Switching on OPA with this policy is what replaces that.
In tiled 0.2.18 PrincipalType has only user and service (external was renamed to user somewhere between 0.2.7 and 0.2.12). With b01-1's copy, every request that reaches build_input would fail with AttributeError. Nobody has hit this because access_control is commented out. The p46–p49 copies work today only because those beamlines run tiled 0.2.7, and they will break the same way when they upgrade.
The p4x and t11 copies differ only in external vs user (and t11's header comment and ConfigMap name). p46, p48 and p49 are byte-identical; p47 differs by a trailing blank line.
b01-1 has no OPA service
The commented config points at http://b01-1-opa:8181/v1/data/diamond/policy/, but b01-1-services has no OPA service. p46 has p46-opa (reached via p46-tiled-authz), and t11 has t11-opa. The OPA endpoint names the current class calls (tiled/user_session, tiled/user_sessions, tiled/scopes, tiled/modify_session) must match the policy that OPA serves.
Behaviour to be aware of
_check_principal raises 401 for None (anonymous) principals and for service principals (API keys). With OPA on, allow_anonymous_access no longer gives access, and blueapi has to write with a user token.
Proposed fix
In this repo:
Port the current class (blueapi's / t11's, using PrincipalType.user), not b01-1's copy, as src/dls_tiled/access_policy.py. Config reference: dls_tiled.access_policy:DiamondOpenPolicyAgentAuthorizationPolicy.
Unit tests with _get_external_decision stubbed (no network, no new HTTP-mocking dependency):
build_input: JSON tag (proposal, visit and beamline), integer session tag, no access blob, token included only for user principals
_check_principal rejects None and service with 401
init_node turns the OPA result into {"tags": [result]} and raises when OPA returns nothing
filters: ["*"] gives ALL_ACCESS, a list gives AccessBlobFilter, no result gives NO_ACCESS
constructing the class succeeds, so it still satisfies tiled's abstract base class
Add dls_tiled.access_policy to the Dockerfile's import check. Don't enable the policy in the container smoke test: it needs OPA, and it returns 401 for anonymous requests, which would break the visr check.
README section on the policy and its access_control: config.
Follow-ups (separate issues)
b01-1-services: switching on access control also needs an OPA service (based on p46-opa) and a rethink of the loose scopes_map. Removing the ConfigMap, its volume and mount, and PYTHONPATH can happen as soon as this is released.
t11-services: already on tiled 0.2.18, so it can drop its ConfigMap and use the class from this package.
p46–p49-services: need external changed to user when they upgrade tiled; moving to this package at that point fixes it.
blueapi: its system tests keep their own copy of the class. In the long run they could run against the dls-tiled image, so that there is only one copy.
DiamondOpenPolicyAgentAuthorizationPolicy started as a test fixture in blueapi's system tests (tests/system_tests/services/tiled_config/dls.py), written by @ZohebShaikh. blueapi doesn't ship it as a package, so each deployment has copied it.
b01-1-services (GitLab), 2026-01-12, "Add configmap": the January version, not updated since
p46-services, 2026-03-11, blueapi and tiled update epics-containers/p46-services#148: the March version, the same day as blueapi#1431. p47–p49 were copied from p46 and still use external, because they predate the tiled 0.2.12 rename.
t11-services, copied from p46, then updated for tiled 0.2.18 on 2026-09-18 (external → user), which makes it match blueapi's current version
So the code has no single owner: it's a test fixture copied into six deployment repos at different points in its history. Moving it into dls_tiled gives it a single owner, with versions and tests.
Activity
gilesknap commentedon Oct 6, 2026
Findings
b01-1's ConfigMap holds an old version of the class that does not work on tiled 0.2.18
The class started in blueapi's system tests (
tests/system_tests/services/tiled_config/dls.py), and beamline repos have copied it from there at different times:PrincipalTypeusedbuild_input, endpointsession/write_to_beamline_visitexternal_check_principal, overridesinit_node/modify_node/filters,ALL_ACCESSfor["*"], integer session tagsexternaluseruserIn tiled 0.2.18
PrincipalTypehas onlyuserandservice(externalwas renamed tousersomewhere between 0.2.7 and 0.2.12). With b01-1's copy, every request that reachesbuild_inputwould fail withAttributeError. Nobody has hit this becauseaccess_controlis commented out. The p46–p49 copies work today only because those beamlines run tiled 0.2.7, and they will break the same way when they upgrade.The p4x and t11 copies differ only in
externalvsuser(and t11's header comment and ConfigMap name). p46, p48 and p49 are byte-identical; p47 differs by a trailing blank line.b01-1 has no OPA service
The commented config points at
http://b01-1-opa:8181/v1/data/diamond/policy/, but b01-1-services has no OPA service. p46 hasp46-opa(reached viap46-tiled-authz), and t11 hast11-opa. The OPA endpoint names the current class calls (tiled/user_session,tiled/user_sessions,tiled/scopes,tiled/modify_session) must match the policy that OPA serves.Behaviour to be aware of
_check_principalraises 401 forNone(anonymous) principals and forserviceprincipals (API keys). With OPA on,allow_anonymous_accessno longer gives access, and blueapi has to write with a user token.Proposed fix
In this repo:
PrincipalType.user), not b01-1's copy, assrc/dls_tiled/access_policy.py. Config reference:dls_tiled.access_policy:DiamondOpenPolicyAgentAuthorizationPolicy._get_external_decisionstubbed (no network, no new HTTP-mocking dependency):build_input: JSON tag (proposal, visit and beamline), integer session tag, no access blob, token included only foruserprincipals_check_principalrejectsNoneandservicewith 401init_nodeturns the OPA result into{"tags": [result]}and raises when OPA returns nothingfilters:["*"]givesALL_ACCESS, a list givesAccessBlobFilter, no result givesNO_ACCESSdls_tiled.access_policyto the Dockerfile's import check. Don't enable the policy in the container smoke test: it needs OPA, and it returns 401 for anonymous requests, which would break the visr check.access_control:config.Follow-ups (separate issues)
p46-opa) and a rethink of the loosescopes_map. Removing the ConfigMap, its volume and mount, andPYTHONPATHcan happen as soon as this is released.externalchanged touserwhen they upgrade tiled; moving to this package at that point fixes it.gilesknap commentedon Oct 6, 2026
Where the code comes from
DiamondOpenPolicyAgentAuthorizationPolicystarted as a test fixture in blueapi's system tests (tests/system_tests/services/tiled_config/dls.py), written by @ZohebShaikh. blueapi doesn't ship it as a package, so each deployment has copied it.Changes in blueapi:
build_input, in the new OPA + Keycloak + tiled system test_check_principal, overriddeninit_node/modify_node/filters, new OPA endpoint namesPrincipalType.externalbecomesPrincipalType.userWhen each beamline copied it:
external, because they predate the tiled 0.2.12 rename.external→user), which makes it match blueapi's current versionSo the code has no single owner: it's a test fixture copied into six deployment repos at different points in its history. Moving it into
dls_tiledgives it a single owner, with versions and tests.