Skip to content

feat(audit): session ID generation, sequence counter, and BoundaryLog wiring#196

Open
SasSwart wants to merge 6 commits intomainfrom
sasswart/feat-audit-session-sequence-wiring
Open

feat(audit): session ID generation, sequence counter, and BoundaryLog wiring#196
SasSwart wants to merge 6 commits intomainfrom
sasswart/feat-audit-session-sequence-wiring

Conversation

@SasSwart
Copy link
Copy Markdown
Contributor

@SasSwart SasSwart commented Apr 30, 2026

PR Map

  1. 👉🏼 feat(audit): session ID generation, sequence counter, and BoundaryLog wiring #196
  2. feat(config): session correlation header injection configuration #197
  3. feat(proxy): inject session ID and sequence number headers on matching requests #198

RFC: Bridge ↔ Boundaries Correlation

Generate a per-session UUID at startup, introduce an atomic sequence counter, and wire both into SocketAuditor so that every emitted BoundaryLog carries a sequence_number and every flushed ReportBoundaryLogsRequest carries the session_id.

Depends on coder/coder#24809 (proto bump).

Note

This PR was authored by Coder Agents.

Add SessionID field to config.AppConfig and generate a UUIDv4 in Run
(run_linux.go) at process startup. The session ID is logged once and
will be used by future work to group all audit events from a single
boundary invocation into a session.

No consumers yet; this is the first step of the session correlation
RFC.
Introduce SequenceCounter, a shared atomic uint64 counter intended to
be initialized once per boundary session and shared between the socket
auditor and the proxy. The Next() method returns a zero-based,
monotonically increasing value so the audit event and any injected
header for the same request agree on the sequence number.

No wiring yet; this commit only adds the type and its tests.
… BoundaryLogs

Wire the session ID (from PR 1) and SequenceCounter (from PR 2) into
SocketAuditor so that every emitted BoundaryLog carries a sequence
number and every flushed ReportBoundaryLogsRequest carries the session
ID.

Changes:
- socket_auditor.go: Add sessionID and seq fields to SocketAuditor.
  AuditRequest now sets SequenceNumber via seq.Next(). flush() accepts
  and sets SessionId on ReportBoundaryLogsRequest.
- multi_auditor.go: SetupAuditor accepts sessionID, creates a
  SequenceCounter, and passes both to NewSocketAuditor.
- landjail/parent.go, nsjail_manager/parent.go: Pass config.SessionID
  to SetupAuditor.
- go.mod: Bump coder/coder to the commit that adds SequenceNumber and
  SessionId to the generated proto types.
- socket_auditor_test.go: Update test helpers to set the new fields.
  Add TestSocketAuditor_AuditRequest_SequenceNumberIncrements and
  TestSocketAuditor_Loop_FlushIncludesSessionID.
@SasSwart SasSwart marked this pull request as draft April 30, 2026 13:00
@SasSwart SasSwart changed the title feat(audit): include session_id, sequence_number, and time on emitted BoundaryLogs feat(audit): session ID generation, sequence counter, and BoundaryLog wiring Apr 30, 2026
@SasSwart SasSwart changed the base branch from sasswart/feat-audit-sequence-counter to main April 30, 2026 13:45
@SasSwart SasSwart self-assigned this May 1, 2026
Copy link
Copy Markdown
Contributor Author

@SasSwart SasSwart left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Self review complete. A few notes and questions. Nothing major.

Comment thread audit/multi_auditor.go Outdated
// and conditionally adds a SocketAuditor if audit logs are enabled and the
// workspace agent's log proxy socket exists.
func SetupAuditor(ctx context.Context, logger *slog.Logger, disableAuditLogs bool, logProxySocketPath string) (Auditor, error) {
func SetupAuditor(ctx context.Context, logger *slog.Logger, disableAuditLogs bool, logProxySocketPath string, sessionID string) (Auditor, error) {
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use a UUID here.

Comment thread audit/multi_auditor.go
agentWillProxy := !os.IsNotExist(err)
if agentWillProxy {
socketAuditor := NewSocketAuditor(logger, logProxySocketPath)
seq := &SequenceCounter{}
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't currently included in the log auditor. Only the socket auditor. Does that matter? I don't think so, but I'm open to the idea.

Comment thread audit/multi_auditor_test.go Outdated
ctx := context.Background()

auditor, err := SetupAuditor(ctx, logger, true, "")
auditor, err := SetupAuditor(ctx, logger, true, "", "test-session")
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need any new test cases for the multi auditor? I think higher level integration tests are a good point to start at for now. Those will be written on top of the PR stack once all of the moving parts are in place.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed regarding integration tests. Separate PR on top of the stack is fine.

Comment thread audit/socket_auditor.go Outdated
batchSize int
batchTimerDuration time.Duration
socketPath string
sessionID string
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

again, session id should be UUID

@SasSwart SasSwart requested a review from dannykopping May 1, 2026 10:39
@SasSwart SasSwart marked this pull request as ready for review May 1, 2026 10:39
@SasSwart SasSwart requested a review from johnstcn May 1, 2026 10:42
Comment thread audit/sequence_test.go
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: This is basically testing atomic.Int32. The only real valid test I could see is testing that it starts at zero and increments.

Comment on lines +36 to +38
if log.Time == nil {
t.Fatal("expected Time to be set")
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also validate that it's not the zero time

Copy link
Copy Markdown
Member

@johnstcn johnstcn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No blocking comments apart from what has already been noted.

- Change sessionID type from string to uuid.UUID across SetupAuditor,
  NewSocketAuditor, SocketAuditor struct, flush(), config.AppConfig,
  and callers. Call .String() only at the proto serialization boundary
  in flush().
- Remove TestSequenceCounter_ConcurrentAccess and
  TestSequenceCounter_IndependentInstances since they only test
  atomic.Int32 stdlib behavior.
- Add zero-time assertion in TestSocketAuditor_AuditRequest_QueuesLog
  to validate Time is not the zero time after checking for nil.
Copy link
Copy Markdown

@dannykopping dannykopping left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants