Jaieu Sheil
11/10/2025, 6:19 PM- OPAL_INLINE_OPA_CONFIG={"decision_logs":{"console":true},"plugins":{"decision_logs":{"reporting":{"min_delay_seconds":1,"max_delay_seconds":5}}},"default_decision_id_enabled":true,"default_authorization_decision_id_enabled":true}Tony Ou
11/18/2025, 12:20 AMAndrea Di Saverio
11/18/2025, 4:01 PMNishanth Mathew Joy
11/19/2025, 11:12 AMTony Ou
11/24/2025, 9:14 AMBartosz Wasilewski
11/26/2025, 8:31 AMOPAL_OPA_V0_COMPAT=true) as recommended
3. Then disabled compatibility mode (OPAL_OPA_V0_COMPAT=false) to test breaking changes
4. Expected our policies to fail (since we didn't add .v1 to package names)
What actually happened: Everything continues to work perfectly, even with compatibility mode disabled.
Here's our policy structure:
package data.role # No .v1 suffix - should this fail in strict v1 mode?
import rego.v1
import data.utils.v1.functions.jwt as functions_jwt
import data.utils.v1.roles as roles
default allow := false
allow if {
functions_jwt.user_has_role(roles.admin)
input.action == "get-roles"
}
According to the migration guide, without .v1 suffix and with compatibility mode disabled, this should fail. But it doesn't.
My questions:
1. Is import rego.v1 now sufficient for v1 compatibility, making the package .v1 suffix optional?
2. Has something changed in OPAL 0.9.0 that we're not aware of?
3. Are we possibly misunderstanding how compatibility mode works?
We want to ensure we're not missing something important before rolling this out to other environments.
Thanks for any insights!Dai Zhang
11/28/2025, 7:53 AMsystem.rego file like below to limit the url.
# system.rego
allow if {
input.method == "POST"
input.path == ["v1", "data", "token"]
}
however, this would block the data update for that url. we know that the best benefit would be real-time data update in opal. so would there be any problem to trigger using curl --request POST '<https://opa.xxx.xxx/data/config>' . great thanks!Nishanth Mathew Joy
12/08/2025, 10:02 AMNishanth Mathew Joy
12/08/2025, 10:03 AMMario Enrico Ragucci
12/12/2025, 7:47 PMKSM
12/22/2025, 10:33 PMSlackbot
02/13/2026, 12:31 PMSlackbot
02/13/2026, 2:23 PMSlackbot
02/13/2026, 2:25 PMSlackbot
02/13/2026, 2:26 PMSlackbot
02/13/2026, 2:26 PMSlackbot
02/13/2026, 2:50 PMSlackbot
02/15/2026, 9:59 PMSlackbot
02/16/2026, 9:50 AMSlackbot
02/16/2026, 1:17 PMLucía Cabanillas
02/23/2026, 9:47 AMAndrea Di Saverio
03/04/2026, 7:19 AM2026-03-03T20:36:11.372421+0000 | 16 | opal_client.policy_store.opa_client | WARNING | OPA client health: False (policy: False, data: True)
2026-03-03T20:36:11.373165+0000 | 16 | uvicorn.protocols.http.httptools_impl | INFO | 10.100.35.127:51372 - "GET /healthcheck HTTP/1.1" 503
2026-03-03T20:36:11.379258+0000 | 16 | uvicorn.protocols.http.httptools_impl | INFO | 10.100.35.127:51384 - "GET /ready HTTP/1.1" 503
Root cause: OPAL pushes each policy individually via PUT /v1/policies/{path} to the OPA agent. With 500+ policies, each PUT takes ~0.5s+, and this duration appears to grow as more policies are loaded (likely because OPA recompiles/re-evaluates the entire policy set on every single insertion (not sure tho)). This sequential loading leads to a prohibitive startup time.
OPA logs:
{"client_addr":"[::1]:37922","level":"info","msg":"Received request.","req_body":"<policy_content>","req_id":3841,"req_method":"PUT","req_params":{},"req_path":"/v1/policies/main/domain/subdomain/policy1.rego","time":"2026-03-03T20:23:39Z"}
{"client_addr":"[::1]:37922","level":"info","msg":"Sent response.","req_id":3841,"req_method":"PUT","req_path":"/v1/policies/main/domain/subdomain/policy1.rego","resp_body":"{}\n","resp_bytes":3,"resp_duration":631.523340,"resp_status":200,"time":"2026-03-03T20:23:39Z"}
{"client_addr":"[::1]:37934","level":"info","msg":"Received request.","req_body":"<policy_content>","req_id":3842,"req_method":"PUT","req_params":{},"req_path":"/v1/policies/main/domain/subdomain/policy2.rego","time":"2026-03-03T20:23:39Z"}
{"client_addr":"[::1]:37934","level":"info","msg":"Sent response.","req_id":3842,"req_method":"PUT","req_path":"/v1/policies/main/domain/subdomain/policy2.rego","resp_body":"{}\n","resp_bytes":3,"resp_duration":716.441353,"resp_status":200,"time":"2026-03-03T20:23:39Z"}
What I've considered to solve: one idea is to use bundles and pre-bake the policies into the OPA container image (e.g. via opa run --bundle /policies, or different methods), so that OPA boots up instantly with all policies already compiled. However, OPAL client has no concept of a "starting commit hash" or awareness that OPA already has the policies — its internal state is in-memory and lost on every restart. So it would still perform the full sync via individual PUTs on every cold start, making the pre-bake effectively useless unless there's a way to tell OPAL "the store is already up-to-date as of commit X — only sync the delta."
I’d be very interested to know:
- whether others have seen similar behavior at this scale and how you handled/mitigated this
- whether there is a way to make OPAL skip the initial full sync if OPA is already pre-loaded (e.g. by providing the last policy commit hash present in the bundle)
- whether there is a way to switch OPAL to deliver policies as an OPA bundle instead of individual PUT calls
Any real-world experience or recommendations would be very helpful. Thanks!!! 🙏☺️Saliya Samarawickrama
03/12/2026, 9:36 AM2026-03-12T09:20:44.817436+0000 | fastapi_websocket_rpc.websocket_rpc_e...| INFO | Client disconnected - 43490 :: d78ae83fc0b4447a98a544a81f7465e0
2026-03-12T09:20:44.817686+0000 | websockets.legacy.server | INFO | connection closed
2026-03-12T09:20:44.889455+0000 | fastapi_websocket_rpc.websocket_rpc_e...| INFO | Client connected
2026-03-12T09:20:44.889886+0000 | websockets.legacy.server | INFO | connection open
2026-03-12T09:20:44.894689+0000 | fastapi_websocket_rpc.websocket_rpc_e...| INFO | Client disconnected - 39376 :: dee642b8daa4491a8ba991f19a80b981
2026-03-12T09:20:44.894872+0000 | websockets.legacy.server | INFO | connection closed
2026-03-12T09:20:46.382346+0000 | fastapi_websocket_rpc.websocket_rpc_e...| INFO | Client connected
2026-03-12T09:20:46.382868+0000 | websockets.legacy.server | INFO | connection open
2026-03-12T09:20:46.388795+0000 | fastapi_websocket_rpc.websocket_rpc_e...| INFO | Client disconnected - 37782 :: 44457ab56137481e9fb742fd39fe10b0
2026-03-12T09:20:46.389028+0000 | websockets.legacy.server | INFO | connection closed
2026-03-12T09:20:47.124470+0000 | fastapi_websocket_rpc.websocket_rpc_e...| INFO | Client connected
OPAL client log:
File "/usr/local/lib/python3.10/site-packages/fastapi_websocket_rpc/rpc_channel.py", line 433, in async_call
await self.send(msg)
│ │ └ RpcMessage(request=RpcRequest(method='_ping_', arguments={}, call_id='5369bcdcc34a4b4a9c32e3837ddec06a'), response=None)
│ └ <function RpcChannel.send at 0x7c45cc2e69e0>
└ <fastapi_websocket_rpc.rpc_channel.RpcChannel object at 0x7c45c541a890>
File "/usr/local/lib/python3.10/site-packages/fastapi_websocket_rpc/rpc_channel.py", line 211, in send
await self.socket.send(data)
│ │ │ └ RpcMessage(request=RpcRequest(method='_ping_', arguments={}, call_id='5369bcdcc34a4b4a9c32e3837ddec06a'), response=None)
│ │ └ <function JsonSerializingWebSocket.send at 0x7c45cc2e7c70>
│ └ <fastapi_websocket_rpc.simplewebsocket.JsonSerializingWebSocket object at 0x7c45c54183d0>
└ <fastapi_websocket_rpc.rpc_channel.RpcChannel object at 0x7c45c541a890>
File "/usr/local/lib/python3.10/site-packages/fastapi_websocket_rpc/simplewebsocket.py", line 44, in send
await self._websocket.send(self._serialize(msg))
│ │ │ │ │ └ RpcMessage(request=RpcRequest(method='_ping_', arguments={}, call_id='5369bcdcc34a4b4a9c32e3837ddec06a'), response=None)
│ │ │ │ └ <function JsonSerializingWebSocket._serialize at 0x7c45cc2e7b50>
│ │ │ └ <fastapi_websocket_rpc.simplewebsocket.JsonSerializingWebSocket object at 0x7c45c54183d0>
│ │ └ <function WebSocketsClientHandler.send at 0x7c45cc2fc280>
│ └ <fastapi_websocket_rpc.websocket_rpc_client.WebSocketsClientHandler object at 0x7c45c753c280>
└ <fastapi_websocket_rpc.simplewebsocket.JsonSerializingWebSocket object at 0x7c45c54183d0>
File "/usr/local/lib/python3.10/site-packages/fastapi_websocket_rpc/websocket_rpc_client.py", line 147, in send
await self._websocket.send(msg)
│ │ │ └ '{"request": {"method": "_ping_", "arguments": {}, "call_id": "5369bcdcc34a4b4a9c32e3837ddec06a"}, "response": null}'
│ │ └ <function Connection.send at 0x7c45c754cd30>
│ └ <websockets.asyncio.client.ClientConnection object at 0x7c45c547c790>
└ <fastapi_websocket_rpc.websocket_rpc_client.WebSocketsClientHandler object at 0x7c45c753c280>
File "/usr/local/lib/python3.10/site-packages/websockets/asyncio/connection.py", line 476, in send
async with self.send_context():
│ └ <function Connection.send_context at 0x7c45c754d360>
└ <websockets.asyncio.client.ClientConnection object at 0x7c45c547c790>
File "/usr/local/lib/python3.10/contextlib.py", line 199, in __aenter__
return await anext(self.gen)
│ └ <async_generator object Connection.send_context at 0x7c45c75f5fc0>
└ <contextlib._AsyncGeneratorContextManager object at 0x7c45c541aaa0>
File "/usr/local/lib/python3.10/site-packages/websockets/asyncio/connection.py", line 957, in send_context
raise self.protocol.close_exc from original_exc
│ │ │ └ None
│ │ └ <property object at 0x7c45c7e9f830>
│ └ <websockets.client.ClientProtocol object at 0x7c45c547c6d0>
└ <websockets.asyncio.client.ClientConnection object at 0x7c45c547c790>
websockets.exceptions.ConnectionClosedOK: received 1000 (OK); then sent 1000 (OK)
2026-03-12T09:21:48.511830+0000 | opal_client.policy_store.opa_client |WARNING | OPA client health: False (policy: False, data: False)
2026-03-12T09:21:48.512277+0000 | uvicorn.protocols.http.httptools_impl | INFO | 10.246.16.157:55704 - "GET /healthcheck HTTP/1.1" 503
2026-03-12T09:21:52.514744+0000 | opal_client.policy_store.opa_client |WARNING | OPA client health: False (policy: False, data: False)
2026-03-12T09:21:52.515261+0000 | uvicorn.protocols.http.httptools_impl | INFO | 10.246.16.157:57878 - "GET /healthcheck HTTP/1.1" 503
2026-03-12T09:22:04.668932+0000 | opal_client.policy_store.opa_client |WARNING | OPA client health: False (policy: False, data: False)
2026-03-12T09:22:04.669366+0000 | uvicorn.protocols.http.httptools_impl | INFO | 10.246.16.157:54528 - "GET /healthcheck HTTP/1.1" 503
2026-03-12T09:22:04.672225+0000 | opal_client.policy_store.opa_client |WARNING | OPA client health: False (policy: False, data: False)
2026-03-12T09:22:04.672794+0000 | uvicorn.protocols.http.httptools_impl | INFO | 10.246.16.157:54536 - "GET /healthcheck HTTP/1.1" 503
2026-03-12T09:22:19.672953+0000 | opal_client.policy_store.opa_client |WARNING | OPA client health: False (policy: False, data: False)
2026-03-12T09:22:19.673463+0000 | uvicorn.protocols.http.httptools_impl | INFO | 10.246.16.157:44232 - "GET /healthcheck HTTP/1.1" 503
2026-03-12T09:22:34.672830+0000 | opal_client.policy_store.opa_client |WARNING | OPA client health: False (policy: False, data: False)
2026-03-12T09:22:34.673382+0000 | uvicorn.protocols.http.httptools_impl | INFO | 10.246.16.157:35314 - "GET /healthcheck HTTP/1.1" 503Vivek Garg
03/23/2026, 4:00 PMMarcelo Almeida
03/24/2026, 6:04 PMJon Asbury
03/31/2026, 7:46 PMPrasenjit Roy
04/12/2026, 4:44 PME2
05/20/2026, 1:46 AMSlackbot
05/20/2026, 7:30 PMphil.lewis
06/11/2026, 7:48 AM