feat(interceptors): ordered before-chains + cycle guard + ctx plumbing (§9.4 M1+M2)
M1: introduces a clone-cheap InterceptorCtx { interceptors, self_engine,
limits } threaded into every SDK register fn (kv/docs/files/queue/pubsub/http)
so the non-KV services carry the hook seam (unused until M7-M11); KvHandle
collapses its three fields into one ictx.
M2: replaces the nearest-only resolver with ordered before/after chains. The
trait becomes resolve(cx, service, op) -> InterceptorChain { before, after }
(migration 0074 adds a phase column + phase-aware unique indexes). The before
-chain runs ancestor->app (depth DESC) so a group compliance guard can't be
bypassed by a descendant; single-marker behavior is byte-identical to before.
An identity cycle guard (thread-local visited-set keyed by script_id) denies a
detected cycle, alongside the existing binary re-entrancy break. Fail-closed
verdict preserved (allow only on #{ allowed: true }; a Dangling entry or a
missing engine back-ref denies); app_id still derives from cx.app_id only.
after-chains resolve but stay unused until M3. Pinned by two new interceptor
journeys (ancestor->app chain ordering; self-referential no-recurse).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -25,8 +25,14 @@ use serde_json::Value as Json;
|
||||
use tokio::runtime::Handle as TokioHandle;
|
||||
|
||||
use super::bridge::{block_on, MAX_JSON_MATERIALIZE_BYTES};
|
||||
use super::interceptor::InterceptorCtx;
|
||||
|
||||
pub(super) fn register(engine: &mut RhaiEngine, services: &Services, cx: Arc<SdkCallCx>) {
|
||||
pub(super) fn register(
|
||||
engine: &mut RhaiEngine,
|
||||
services: &Services,
|
||||
cx: Arc<SdkCallCx>,
|
||||
ictx: InterceptorCtx,
|
||||
) {
|
||||
let svc = services.pubsub.clone();
|
||||
let mut module = Module::new();
|
||||
{
|
||||
@@ -77,6 +83,7 @@ pub(super) fn register(engine: &mut RhaiEngine, services: &Services, cx: Arc<Sdk
|
||||
{
|
||||
let group_svc = services.group_pubsub.clone();
|
||||
let cx = cx.clone();
|
||||
let ictx = ictx.clone();
|
||||
module.set_native_fn(
|
||||
"shared_topic",
|
||||
move |name: &str| -> Result<GroupTopicHandle, Box<EvalAltResult>> {
|
||||
@@ -87,6 +94,7 @@ pub(super) fn register(engine: &mut RhaiEngine, services: &Services, cx: Arc<Sdk
|
||||
namespace: name.to_string(),
|
||||
service: group_svc.clone(),
|
||||
cx: cx.clone(),
|
||||
ictx: ictx.clone(),
|
||||
})
|
||||
},
|
||||
);
|
||||
@@ -104,6 +112,10 @@ pub struct GroupTopicHandle {
|
||||
namespace: String,
|
||||
service: Arc<dyn picloud_shared::GroupPubsubService>,
|
||||
cx: Arc<SdkCallCx>,
|
||||
// §9.4 M1 plumbing: carried so `publish` can run a before/after hook in a
|
||||
// later milestone (M11). Unused until then.
|
||||
#[allow(dead_code)]
|
||||
ictx: InterceptorCtx,
|
||||
}
|
||||
|
||||
fn shared_publish(
|
||||
|
||||
Reference in New Issue
Block a user