Feat: Add the lineage demo — per-request lineage from the sidecar - #762
Draft
JoshSag wants to merge 2 commits into
Draft
Feat: Add the lineage demo — per-request lineage from the sidecar#762JoshSag wants to merge 2 commits into
JoshSag wants to merge 2 commits into
Conversation
Shows how to get per-request data lineage out of the AuthBridge sidecar: attach
the envoy-sidecar to an agent or tool, switch on the lineage-telemetry plugin,
and every HTTP exchange becomes two facts-only spans sent to any OTLP consumer.
On a stock install that is the platform's own collector, whose default pipeline
exports to debug — so the spans are readable from its log with nothing extra
deployed. Phoenix is not installed by default; the README shows both routes.
Five mechanism files plus a README:
attach-lineage.sh the one generator — emits every YAML byte, as a full
manifest, the plugin ConfigMap alone, or a sidecar patch
Dockerfile.otel-shim the propagate-only shim layer
build-otel-shim.sh builds the shim onto an app image, refusing only images
where wrapping would stack a second instrumentor on a
library the shim already covers
sidecar-patch.sh the patch path, for a Deployment you do not own
container-runtime.sh docker-vs-podman detection and kind loading
The shim is the non-obvious half. The sidecar sees every hop but lives outside
the app's execution context, so it cannot know which coroutine issued which
outbound call; attributing an outbound call to its causing inbound needs
traceparent carried through the app in-process. Without it the plugin falls back
to "this agent's current inbound span", correct only at concurrency 1.
The README is written around what actually goes wrong, all of it measured:
the ownership fork (EMIT=manifest replaces a Deployment; an operator-owned
workload must take the additive patch instead), the half-instrumented quadrant
(an app with a client instrumentor but no server-side one can neither be shimmed
nor propagate on its own — its outbound work scatters into one-interaction
traces), that a refusal to bake is not a promise the app propagates, that baking
is not purely additive on an image already carrying an SDK, and that a
structural cleanliness check cannot detect total attribution failure.
The generated workload deliberately carries no <prefix>/type label: a current
platform reserves that label for its operator through a ValidatingAdmissionPolicy
and rejects manifests that set it by hand. Omitting it costs platform-inventory
registration, which an AgentRuntime CR provides, and costs lineage nothing.
Defaults target a stock platform: otel-collector.rossoctl-system, kind cluster
rossoctl, and the published ghcr.io/rossoctl/cortex sidecar images — all
overridable by environment variable. A published sidecar image carries the
lineage-telemetry plugin only once that plugin has merged and a release is cut;
until then, build the images from this repo and point SIDECAR_IMAGE /
PROXY_INIT_IMAGE at them.
Signed-off-by: YehoshuaSagron <ysagron@gmail.com>
Signed-off-by: YehoshuaSagron <ysagron@gmail.com>
|
Important Review skippedDraft detected. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this adds
A demo under
authbridge/demos/lineage/showing how to get per-request datalineage out of the AuthBridge sidecar: attach the envoy-sidecar to an agent or
tool, switch on the
lineage-telemetryplugin, and every HTTP exchange becomestwo facts-only spans that go to any OTLP consumer — on a stock install, the
platform's own collector, whose default pipeline exports to
debug, so a readercan read them straight from its log with nothing extra deployed. (Phoenix is not
installed by default; the README says so and shows both routes.)
Six files, five of them the mechanism and one the argument:
attach-lineage.shREADME.mdbuild-otel-shim.shsidecar-patch.shDockerfile.otel-shimcontainer-runtime.shThe interesting half: why a sidecar alone is not enough
The sidecar sees every hop with parsed bodies, but it lives outside the
app's execution context and cannot know which internal coroutine issued which
outbound call. Attributing an outbound call to the inbound request that caused
it needs a token carried with the execution scope through the app — which is
what W3C
traceparentis for, and only code inside the request's context canpropagate it.
Without it, the plugin falls back to "this agent's current inbound span". That
is correct only while the agent handles one request at a time. Under
concurrency it collapses: with 6 concurrent requests, all 6 outbound calls
attach to whichever inbound updated the process-wide pointer last — 1/6,
measured.
So the demo ships a propagate-only OpenTelemetry shim: stock
auto-instrumentation for the mainstream Python HTTP stack, layered onto an app
image without touching its source, running under
opentelemetry-instrument --traces_exporter none. It extracts the inboundtraceparent, injects it on outbound calls, carries the context across threadboundaries — and exports nothing. An app that configures its own exporter
keeps exporting exactly as before; the shim silences only its own
instrumentation.
The
threadinginstrumentor is load-bearing rather than incidental: frameworksthat run the LLM call in a worker thread lose the context at the thread
boundary, and propagation silently reverts to 1/N.
Two paths, and the demo says which one to use
This is the part we would most like reviewed, because choosing wrong destroys
resources. The question is not what your app is — it is who owns the
Deployment:
attach-lineage.shwithEMIT=manifestemits a completeConfigMap + Service + Deployment. It is a replacement by design.
sidecar-patch.shapplies astrategic-merge patch that only adds the sidecar containers, leaving the
owner's spec alone.
Point the first at a name some other controller manages and you have silently
rewritten that controller's object. The README states this as a decision table
before any command, with the consequence spelled out.
It also states two limits we would rather a reader hit in prose than in
production: a patch is not durable (any platform-side rewrite silently drops
the sidecar — there is no error, lineage just stops), and the uninstrumented +
operator-owned quadrant is unsolved, because the shim needs an image change
you cannot make for a workload you do not control.
Runs against a stock platform, with no service of ours
Everything defaults to your side of the fence:
rossoctl.io/*workload labels,otel-collector.rossoctl-systemas the OTLP endpoint, kind clusterrossoctl,and
ghcr.io/rossoctl/cortex/{authbridge-envoy,proxy-init}for the sidecarimages — all overridable by environment variable. The demo names no service,
repository or endpoint that is not either in this repo or supplied by the
reader.
One caveat we should state rather than have you discover: a published
sidecar image only carries the
lineage-telemetryplugin once lane 2 has mergedand a release is cut. Until then, build the two images from this repo and
point
SIDECAR_IMAGE/PROXY_INIT_IMAGEat your local tags. The README saysthis where a reader will hit it.
It has been run, exactly as written
The worked example uses this repo's own
weather_serviceimage, and itsfacts are measured from that image rather than assumed — its
Cmdis["uv","run","--no-sync","server"], its venv is at/app/.venv, it runs as UID1001, and it already bundles OpenTelemetry instrumentation. That last fact is
what makes it a good example:
build-otel-shim.shrefuses to wrap it,because wrapping an already-instrumented app would double-instrument it. The
honest recipe for such an app is sidecar-only, and the README shows that.
Executed against a live cluster: the manifest applies, the pod comes up 2/2, and
one A2A request produces
both with the same
lineage.exchange.id.What is deliberately not here
A considerably larger operational kit exists behind this demo — a fleet catalog
and deployer, a global on/off switch, a probe application, concurrency
harnesses, per-app expectation cards, from-zero cluster runbooks. We are not
offering it, and that is a decision rather than an oversight.
The cut line is "runs with no other service and no lab of ours". The rest of
the kit fails it: it scales named objects in a service you do not have, encodes
our own 14-app inventory, and computes paths into a sibling clone in our
workspace layout. Asking a maintainer to host that would be asking you to carry
our lab. What is here is ~1,000 lines of generic mechanism that works against
Phoenix, Jaeger, or any OTLP endpoint.
Gates
shellcheck --severity=error, as your Security Scans job runs ithadolint --failure-threshold errorwith your ignore listDockerfile.otel-shim(oneDL3066info: non-numeric UID)Assisted-By: Claude (Anthropic AI) noreply@anthropic.com