Skip to content

feat(logging): Audit credentialed egress writes with one identity model - #2214

Merged
dcramer merged 3 commits into
mainfrom
feat/audit-log-egress-writes
Oct 23, 2026
Merged

dcramer merged 3 commits into
mainfrom
feat/audit-log-egress-writes

Conversation

@sentry-junior

@sentry-junior sentry-junior Bot commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

In production, logging.ts drops all info logs before they reach Sentry. Because of this, we had no searchable record of the provider writes that Junior makes through credentialed egress. That includes gh and curl writes and workflow dispatches.

This PR adds logAudit. It emits an info event marked app.log.audit: true, and Sentry keeps that event in production. Other info events stay suppressed as before. sandbox.egress.upstream.requested now uses logAudit for requests that use a write grant. Read-grant requests still log only outside production.

One identity model. Before this PR, Junior bound the person in different ways on different paths. Slack turns got both enduser.id and Sentry's user.id. Automation runs got no person. Sandbox egress got nothing. Now runs, resumes, and the sandbox egress proxy bind the same fields:

  • user.id, user.name, user.email, user.full_name: the accountable person. For a user Actor, this is that user. For a system Actor with delegated credentials, this is the credential owner, such as the Automation creator. These are OTel user.* fields. Sentry already writes them from the scope user and uses them for its user features. enduser.* is removed.
  • app.actor.type / app.actor.id: who acted, user or system.
  • app.credential.allowed_when / app.task.id: why delegated credentials were allowed, and for which Automation.
  • gen_ai.conversation.id: the Conversation. The sandbox proxy handles each request separately with no log context, so the run's conversationId now travels in the signed sandbox egress credential token. It is telemetry only and grants nothing.

credentialLogContext and actorLogContext in credentials/context.ts own this mapping. The proxy binds it from the verified token and sets the Sentry user. One run never has two different people: a delegated subject exists only with a system actor (credentialContextForActor). TELEMETRY.md has a new Identity section and an updated query recipe.

The record has metadata only: provider, grant, method, host, path and status. It has no request or response bodies.

Known gap: an Automation in system credential mode has no delegated subject, so its writes have no user.id. Naming its owner needs the dispatch to carry the owner. That is a follow-up.

Rollback note: the token schema is strict. If we roll back after this ships, the older code rejects tokens that already carry conversationId until they expire (30 minutes at most), so sandbox egress for active sandboxes fails during that time.

This is a stopgap. Sentry log retention is not audit retention.

Part of #2211.

via David Cramer.

--

View Junior Session [Sentry]

@vercel

vercel Bot commented Oct 23, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
junior-docs Ready Ready Preview Oct 23, 2026 9:36am UTC

Request Review

sentry-junior Bot and others added 3 commits October 23, 2026 09:08
Add logAudit, an info event that Sentry keeps in production, and use it for
credentialed egress requests that use a write grant. The event names the
credential actor, the delegated subject, and the Automation it is bound to.

Refs #2211

Co-Authored-By: David Cramer <david@sentry.io>
…ents

Carry the run's conversationId in the signed sandbox egress credential token
and in plugin egress, and log it as gen_ai.conversation.id. It is telemetry
only and does not grant access.

Refs #2211

Co-Authored-By: David Cramer <david@sentry.io>
…ox egress

Use OTel user.* for the accountable person instead of enduser.*. For a
system run with delegated credentials, user.id is the credential owner.
app.actor.* says who acted. app.credential.allowed_when and app.task.id
say why delegated credentials were allowed.

The sandbox egress proxy now binds the same fields from the signed token,
so its spans, logs, and errors carry the person. This replaces the
app.credential.actor.* and app.credential.subject.* audit fields.

Co-Authored-By: David Cramer <david@sentry.io>
@sentry-junior
sentry-junior Bot force-pushed the feat/audit-log-egress-writes branch from 3c9b88d to 58eab83 Compare October 23, 2026 09:35
@sentry-junior sentry-junior Bot changed the title feat(logging): Keep write-grant egress audit events in production feat(logging): Audit credentialed egress writes with one identity model Oct 23, 2026
@dcramer
dcramer merged commit 500cbc4 into main Oct 23, 2026
44 checks passed
@dcramer
dcramer deleted the feat/audit-log-egress-writes branch October 23, 2026 11:20

This branch was successfully deployed

1 active deployment
Preview – junior-docs — 58eab83d Deployed Oct 23, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

risk: high PR risk score: high

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant