Audit Log
Philosophy
The audit log captures all critical events that affect entities of interest within Sourcegraph services. The audit log is built on top of our logging standard, using structured logs as the base building block. Every captured entry is aligned with the following design mantra:
Actor takes action on an entity within a context
Here's a sample audit log entry:
SHELL{ "Resource": { "service.name": "frontend", "service.version": "328631_2025-06-03_6.4-38344483cde5", "service.instance.id": "sourcegraph-frontend-7b7fc6f469-5mc92" }, "message": "viewed (sampling immunity token: 3a5a87aa-c068-4d53-a489-d0e78c9a45d6)", "InstrumentationScope": "frontend.schemaResolver", "Caller": "graphqlbackend/site.go:132", "Function": "github.com/sourcegraph/sourcegraph/cmd/frontend/graphqlbackend.(*siteResolver).Configuration", "Attributes": { "audit": { "entity": "site.config", "auditID": "3a5a87aa-c068-4d53-a489-d0e78c9a45d6", "action": "viewed", "tenant": "1", "actor": { "X-Requested-With": "", "forwardedForRequestedWith": "", "X-Forwarded-For": "", "forwardedForUserAgent": "Go-http-client/1.1", "actorUID": "1", "X-Sourcegraph-API-Client-Version": "", "userAgent": "Go-http-client/1.1", "X-Sourcegraph-API-Client-Feature": "", "X-Sourcegraph-API-Client-Name": "", "sourcegraphOperator": true, "fromAccessTokenID": "1", "ip": "127.0.0.1" } } }, "timestampNanos": 1748958897357219600 }
Here's a word-by-word breakout to demonstrate how the captured entry aligns with the design mantra:
- Actor -
Attributes.audit.actor
field carries essential information about the actor who performed the action. - Action -
Body
field carries the action description. This action is suffixed with a "sampling immunity token," which carries the unique audit log entry ID. The audit entry ID must be present in theBody
so that the message is always unique and never gets dropped by the sampling mechanism (hence the sampling immunity token string). - Entity -
Attributes.audit.entity
describes the audited entity. - Context - Additional fields within the
audit
object provide context for the action.
What is audited?
The audit log captures a wide range of security-relevant events including:
- Authentication Events - Login attempts, access token usage, password changes, and sign-out events
- Authorization Events - Permission changes, role modifications, and access control updates
- User Management - User creation, modification, deletion, and email verification
- Configuration Changes - Site configuration updates, external service modifications
- Repository Access - Repository access events and gitserver requests
- API Usage - GraphQL requests and outbound API calls
- Code Host Integration - External service configuration and webhook events
- Tenant Operations - Multi-tenant workspace management events
Entities and Actions
Below is a comprehensive list of currently audited entities and their associated actions:
Authentication
- auth.accessToken: failed, invalid, impersonated
- auth.password: attempted, failed, succeeded
- auth.oauth (various providers): failed, sign-in
- auth.operator: access
User Management
- user: created, modified, deleted, hardDeleted
- user.email: added, deleted, changed, verified, unverified
- user.password: changed, reset
- user.accessToken: created, deleted, hardDeleted
- user.completions.quota: changed
- user.codecompletions.quota: changed
Configuration & Infrastructure
- site.config: viewed, changed
- site.config.redacted: viewed
- codehosts: created, changed, deleted
- repository: accessed
- gitserver: access
- requests.outbound: viewed
- webhooks.outbound: created, deleted
Organizations & Access Control
- organizations: viewed, created
- entitlements: viewed, created, updated, deleted
- rbac.permission: changed
- rbac.role: created, changed, deleted
Target audience
Security specialists. We expect these to ingest the logs into their SIEM tools and define alert policies as they see fit. Site admins are currently not the target audience, but we'll likely offer an easy-to-use in-app audit log.
Configuring
The audit log is currently configured using the site config. Here's the corresponding entry:
SHELL"log": { "auditLog": { "internalTraffic": false, "graphQL": false, "gitserverAccess": false, "severityLevel": "INFO" // DEPRECATED, defaults to SRC_LOG_LEVEL } }
Configuration options:
internalTraffic
: When false (default), suppresses audit logs from internal system actors to reduce noisegraphQL
: Controls auditing of GraphQL API requestsgitserverAccess
: Controls auditing of gitserver access eventsseverityLevel
: DEPRECATED - audit log level now follows the globalSRC_LOG_LEVEL
environment variable
Using
Audit logs are structured logs delivered as JSON to STDERR. As long as one can ingest logs, we assume one can also ingest audit logs.
Log Output
All audit logs are delivered to STDERR for each individual component.
Filtering Audit Logs
There are two approaches to filtering the audit logs:
- JSON-based: Look for the presence of the
Attributes.audit
node. Do not depend on the log level, as it can change based onSRC_LOG_LEVEL
. - Message-based: Filter based on the following string:
auditID
(note: this is the current field name, notauditId
).
Important Fields for Filtering
Customers can filter audit logs using these key fields:
Core Audit Fields
Attributes.audit.auditID
: Unique identifier for each audit eventAttributes.audit.entity
: The entity being acted upon (e.g., "user", "site.config")Attributes.audit.action
: The action performed (e.g., "created", "modified", "deleted")Attributes.audit.tenant
: Tenant ID for multi-tenant environments
Actor Information
Attributes.audit.actor.actorUID
: User ID of the actor performing the actionAttributes.audit.actor.ip
: IP address of the requestAttributes.audit.actor.fromAccessTokenID
: Access token ID if action performed via APIAttributes.audit.actor.sourcegraphOperator
: Boolean indicating if actor is a Sourcegraph operatorAttributes.audit.actor.userAgent
: User agent string from the requestAttributes.audit.actor.X-Forwarded-For
: Forwarded IP addressesAttributes.audit.actor.X-Sourcegraph-API-Client-Name
: API client nameAttributes.audit.actor.X-Sourcegraph-API-Client-Version
: API client version
Timestamp and Service Information
Timestamp
: Event timestamp (nanoseconds since Unix epoch)Resource.service.name
: Service that generated the audit logResource.service.version
: Version of the serviceBody
: Human-readable action description with sampling immunity token
Cloud
For Sourcegraph Cloud customers, please refer to Cloud documentations.
Developing
The single entry point to the audit logging API is made via the audit.Log
function. This internal function can be used from any place in the app, and nothing else needs to be done for the logged entry to appear in the audit log.
Example call:
GOaudit.Log(ctx, logger, audit.Record{ Entity: "user", Action: "modified", Fields: []log.Field{ log.Int32("userID", userID), log.String("operation", "updateProfile"), }, })
Parameters:
ctx
: Context parameter required for acquiringactor.Actor
andrequestclient.Client
logger
: Logger instance used for performing the actual log callaudit.Record
: Structure carrying all the information required for constructing a valid audit log entryEntity
: Name of the audited entityAction
: Description of the state changeFields
: Additional context fields specific to the actionMustRecord
: Optional flag to bypass internal traffic filtering
The audit log system automatically:
- Checks current settings via cached
schema.SiteConfiguration
- Extracts actor information from context
- Generates unique audit ID with sampling immunity
- Formats the log entry according to the structured format
FAQ
How do I map actor ID to the Sourcegraph user?
The audit.actor
node carries ID of the user who performed the action (actorUID
), but it’s not mapped into a full Sourcegraph user right now. You can, however, obtain the user details by following these steps:
- Grab the user ID from the audit log
- Base64 encode the ID with a "User:" prefix. For example, for Actor with ID 71 use
User:71
, which encodes toVXNlcjo3MQ==
- Navigate to Site Admin -> API Console and run the query below
- Find the corresponding user by searching the query results for the encoded ID from above
GraphQL query:
GRAPHQL{ users { nodes { id username } } }
How do I reduce audit log volume?
To reduce audit log volume:
- Set
log.auditLog.internalTraffic
tofalse
(default) to suppress logs from internal system actors - Configure specific audit types (
graphQL
,gitserverAccess
) based on your monitoring needs - Use log filtering at the ingestion level to focus on specific entities or actions