Streaming is what converts the audit log from a rolling window into a record.
It is also the piece of enterprise operations with the most specific failure semantics — at-least-once delivery, a seven-day buffer, a health check with a six-day repair window, and a hard data loss threshold — and every one of those numbers matters when something goes wrong.
The short answer
Section titled “The short answer”Supported destinations are Amazon S3, Azure Blob Storage, Azure Event Hubs, Datadog, Google Cloud Storage, Microsoft Purview and Splunk.
Delivery is at-least-once. GitHub states directly: “GitHub uses an at-least-once delivery method. Due to certain network or system issues, some events may be duplicated.”
Streaming can be paused, with events buffered for up to seven days.
A health check runs every 24 hours, emailing enterprise owners when a stream is unhealthy, with a repair window before data is lost.
Multiple streams are documented as being in public preview and subject to change.
OIDC authentication is available for Amazon S3 only, and is not available for GitHub Enterprise Cloud with data residency.
Choosing a destination
Section titled “Choosing a destination”Object storage — S3, Azure Blob, Google Cloud Storage. Cheap, durable, unlimited retention, and no ingestion cost. Queryable later with the tooling of your choice. This is the right default for an organisation whose primary need is retention.
SIEM — Splunk, Datadog. Events land where your detection lives. Higher cost, usually charged by ingestion volume, and correspondingly more valuable if GitHub events are part of an active detection strategy.
Azure Event Hubs. A pipeline rather than a destination, appropriate where events feed several downstream systems.
Microsoft Purview. Relevant for organisations already using it for compliance and data governance.
The pragmatic answer for many enterprises is both: everything to object storage for retention at low cost, and a filtered subset to the SIEM for detection. Multiple streams make that possible — with the caveat below.
Authentication to the destination
Section titled “Authentication to the destination”How the stream proves it is allowed to write, and the choices worth making.
OIDC is the better option where available. GitHub documents OIDC authentication for Amazon S3 — with the noted exception that it is not available for GitHub Enterprise Cloud with data residency. OIDC means no long-lived credential is stored, which removes an expiry, a rotation obligation and a theft target simultaneously.
Otherwise, a stored credential. An access key, a storage key, a token. Which brings the usual obligations: a secret manager, a rotation schedule, an expiry alert, and a documented owner.
Scope it to write. The stream writes objects. It does not need to read them, list them, or delete them. A credential scoped to write-only limits what an exposure of it could do — notably, it could not be used to read your audit archive.
Restrict the destination path. A credential able to write anywhere in a bucket is broader than one able to write to a single prefix.
Rotate it, and confirm the stream survives. A rotation that breaks the stream and is not noticed is a data loss event on a seven-day clock.
Alert on its expiry. Credential expiry is the most common cause of a broken stream, and it is entirely preventable.
And treat it as a privileged credential. Write access to your audit record is a capability worth protecting — an attacker able to write there could pollute the evidence, and one able to delete could remove it.
At-least-once delivery
Section titled “At-least-once delivery”The guarantee, stated by GitHub: “GitHub uses an at-least-once delivery method. Due to certain network or system issues, some events may be duplicated.”
Which means duplicates will occur. Not might — will, eventually, and the frequency depends on conditions outside your control.
The consequence for anything counting events: a metric derived from streamed events without deduplication will overcount. “How many repositories were deleted this month” answered from a raw stream is unreliable.
Deduplicate on ingestion. Events carry identifying information; use it as a key. In object storage this means handling it at query time; in a SIEM it means a deduplication rule.
The consequence for alerting: an alert may fire twice for the same event. Usually harmless, occasionally confusing, and worth designing for — an alert that pages somebody twice for one repository deletion erodes trust in the alert.
And the consequence for evidence: a count presented to an auditor should be deduplicated, and you should be able to say how. “We deduplicate on event identifier” is a satisfactory answer; “we counted the lines” is not.
At-least-once is the right guarantee — the alternative, at-most-once, would mean silently losing events, which is far worse for an audit record. But it is a guarantee you must design around rather than ignore.
Pause, buffering and the loss thresholds
Section titled “Pause, buffering and the loss thresholds”The numbers that matter during an outage at the destination.
A paused stream buffers events for up to seven days.
Resuming after more than seven days means the stream resumes from approximately one week prior — so the gap between seven days and the resume point is not recovered.
Beyond three weeks, data is lost.
Which gives you a clear operational picture: a destination outage of a few days is recoverable by pausing and resuming. An outage of more than a week loses data. An outage of three weeks loses a great deal.
The practical implication: if your destination will be unavailable for an extended period — a migration, a vendor change, a prolonged incident — the audit data for that period is at risk, and you should have a plan rather than discovering the loss afterwards.
Pausing deliberately is a legitimate operation during a short destination maintenance window, and it is better than letting delivery fail.
Health checks
Section titled “Health checks”GitHub runs a health check every 24 hours and emails enterprise owners when a stream is unhealthy.
There is a repair window — the documentation describes fixing the problem within six days to avoid data loss, which aligns with the seven-day buffer.
Which means the notification is not optional reading. An email to enterprise owners about an unhealthy stream is a six-day clock, and enterprise owners’ inboxes are not a monitoring system.
Route it properly. Enterprise owner notifications should reach a team address that somebody monitors, not an individual’s inbox. This is a small configuration detail with a large consequence.
Monitor from the destination side too. The most reliable check is whether events are arriving: an alert when no GitHub events have landed in the destination for some hours is independent of GitHub’s own health check and catches problems it might not.
Test the failure. Break the stream deliberately in a controlled way — revoke the destination credential — and confirm that somebody finds out. A health check nobody receives is not a health check.
The case for doing this first
Section titled “The case for doing this first”Among everything in this pillar, streaming has the strongest claim on being done before anything else, and the reasoning is worth stating plainly.
Every other capability depends on data. Access reviews, drift detection, compliance evidence, incident investigation, process metrics — all of them read audit data, and none of them can read data that was never captured.
The window is closing continuously. Administrative events age out at 180 days. Git events age out at seven. Every week without streaming is a week permanently unavailable.
It is cheap. A bucket, a credential, a configuration form. Measured in hours, not weeks, and the ongoing cost of object storage for audit events is negligible for almost any organisation.
It has no blast radius. Unlike a ruleset or a policy, streaming changes nothing for developers. Nobody is inconvenienced, nothing can break, and there is no rollout plan required.
It is the answer to questions you have not been asked yet. The value materialises retrospectively — when an incident occurs, when an auditor asks, when somebody needs to know what changed. At that point it is either configured or it is not, and there is no way to configure it in the past.
Which makes it the rare piece of enterprise work with high value, low cost and zero risk. If an enterprise account was configured recently and streaming is not on, that is the first thing to fix.
Configuring it
Section titled “Configuring it”-
Choose the destination and provision it: a bucket, a container, an index. Decide retention there deliberately.
-
Create the credentials. Prefer OIDC where available — GitHub documents OIDC authentication for Amazon S3, though not for GitHub Enterprise Cloud with data residency. OIDC removes a long-lived stored credential, which is the same argument as everywhere else.
-
Scope the destination permissions narrowly. The stream needs to write; it does not need to read, delete or configure.
-
Configure the stream and verify events arrive. Do not assume — look at the destination.
-
Confirm what is included. Enable Git events if you need them, and API request events if they are available for your configuration and you want them.
-
Set the destination retention to match the period you decided you need.
-
Route the health notifications to a monitored team address.
-
Add a destination-side freshness alert.
-
Document the recovery procedure: how to pause, how to resume, what the thresholds are, and who to tell.
What to include
Section titled “What to include”Standard audit events: always. This is the baseline.
Git events: yes, if you can. Their seven-day retention makes streaming the only way to answer clone and push questions retrospectively, and those questions arise in exactly the investigations that matter most.
API request events: if available and if you have a use. Documented as public preview, restricted to Enterprise Managed Users enterprises and GitHub Enterprise Cloud with data residency, streaming only, and requiring enablement. High volume, and genuinely useful for understanding automation behaviour.
Consider the volume. Git and API request events are substantially higher volume than administrative events. For a SIEM charged by ingestion, that is a cost decision; for object storage it is not.
Which is another argument for two streams where available: everything to object storage, administrative events to the SIEM.
Making the data usable
Section titled “Making the data usable”Streaming solves delivery. Making the delivered data answerable is a separate step that many organisations skip, and then discover during an incident.
Know the format. Events arrive as structured records, and understanding the field names before you need to query is the difference between five minutes and an hour.
Partition sensibly. In object storage, events land in a path structure. Partitioning by date is what makes a time-bounded query cheap rather than a full scan. Confirm what the structure is and design queries around it.
Establish a query path. Object storage with no query capability is an archive, not a record. Whether that is a serverless query service, a notebook, or a script that downloads and greps, somebody should have done it once and written down how.
Build the standard queries. The six investigations from the audit log article, expressed against your destination. This is a half-day of work and it is the difference between a usable record and a compliant one.
Handle the schema variation. Different actions carry different fields. A query assuming a uniform structure will fail on the first unusual event, and the failure mode is usually an empty result rather than an error.
Deduplicate in the query, not the ingest, for object storage — you cannot easily deduplicate immutable objects after the fact, so the deduplication belongs wherever the reading happens.
Test with a known event. Do something distinctive in a sandbox organisation, then find it in the destination. That end-to-end confirmation is worth more than any amount of configuration review.
Streaming and the SIEM
Section titled “Streaming and the SIEM”If GitHub events are going into a detection platform, a few things determine whether they are useful there.
Normalise the actor. GitHub usernames are not the same as directory identities, particularly with personal accounts. Mapping them is what lets a detection correlate GitHub activity with activity elsewhere, and it is the single most valuable enrichment.
Enrich with repository context. A deletion event names a repository; whether that repository was production-tier is what determines severity. Joining against your custom properties turns a flat event into a prioritised one.
Suppress known automation by default, and not during incidents. Bots generate most of the volume, and a detection surface dominated by dependency updates is one nobody reads.
Start with a small number of detections. Repository made public. Enterprise owner added. SSO configuration changed. Ruleset deleted. Each is rare, high-consequence, and unambiguous. A detection set that starts small and is trusted beats a comprehensive one that is muted.
Feed the volume decision back. If SIEM ingestion is charged by volume, streaming Git and API request events there may be expensive for limited detection value, while being cheap and valuable in object storage. Splitting by destination is the answer, subject to the preview status of multiple streams.
Operating it
Section titled “Operating it”Monitor freshness, from the destination.
Watch the volume trend. A sudden drop is a stream problem; a sudden rise is either an incident or a new automation.
Rotate the destination credentials on a schedule, and confirm the stream survives it.
Test a query periodically. Being able to answer a question from streamed data is the point, and a destination nobody has ever queried may have a format problem nobody has noticed.
Verify the retention policy at the destination annually. A lifecycle rule expiring objects after 90 days silently defeats the whole exercise.
Include streaming in change management for the destination. A cloud team migrating a bucket without knowing GitHub streams into it will break it.
Protecting the record
Section titled “Protecting the record”An audit record is only evidence if it cannot be quietly altered, and that property has to be designed in.
Write-only from GitHub’s perspective. The credential the stream uses should be able to write and nothing else. It does not need read, delete or list.
Immutability at the destination. Object storage services offer write-once retention modes that prevent objects being deleted or modified before a retention period elapses. For an audit record, this is the feature that turns storage into evidence.
Restrict who can delete. The people who can administer the bucket should not be the people whose actions it records, where that separation is achievable.
Log access to the record. Who read the audit archive, and when, is itself worth recording — particularly where the archive contains data about individuals.
Version and lock the retention policy. A lifecycle rule that can be changed by anybody with cloud console access is a retention policy in name only.
Consider the data protection angle. Audit events name individuals and record their activity. That is personal data in most jurisdictions, and the retention period, access controls and deletion obligations for it are a question for whoever owns data protection — not one to decide unilaterally because storage is cheap.
And check who can change the stream configuration. An enterprise owner can reconfigure or disable streaming. That action appears in the audit log, which is exactly the log that would stop being delivered — so alerting on streaming configuration changes matters, and the alert should not depend on the stream.
What streaming does not solve
Section titled “What streaming does not solve”Setting expectations, because streaming is frequently treated as the whole of audit capability.
It does not improve what GitHub records. The event set is the event set; streaming changes where it goes, not what it contains. Read access beyond Git events is still not enumerated.
It does not backfill. Streaming starts when you configure it. Everything before that is subject to the standard retention window and then gone.
It does not deduplicate. At-least-once means you handle that.
It does not make the data queryable. That is work at the destination.
It does not constitute a control. Having the data is a precondition for a control; the control is the process that reads it, acts on it, and records that it did.
And it does not produce compliance. No GitHub configuration produces compliance with SOC 2, PCI DSS, HIPAA, ISO 27001 or FedRAMP by itself. Streamed audit data can be evidence supporting a logging and monitoring control objective; whether it satisfies that objective is an assessment made against your stated control by your auditor.
Which is worth stating internally, because “we stream the audit log” is frequently offered as an answer to a question about monitoring, and it is only the first half of one.
Common mistakes
Section titled “Common mistakes”Assuming exactly-once delivery. Duplicates occur; deduplicate.
Counting raw events for metrics or evidence. Overcounts.
Health notifications to an individual inbox. A six-day clock nobody sees.
No destination-side freshness alert. GitHub’s check is not your only line of defence.
Not enabling Git events. The seven-day window makes streaming the only option.
Destination retention shorter than intended. A lifecycle rule defeats the purpose silently.
Long-lived stored credentials where OIDC is available. Same argument as any other credential.
Not testing a query. A destination nobody has queried may be unusable.
Depending on multiple streams without noting the preview status.
When a stream breaks
Section titled “When a stream breaks”The runbook, because the seven-day and six-day numbers make this time-sensitive in a way most operational failures are not.
-
Establish when it stopped. The last event in the destination gives you the start of the gap and how much of the seven-day buffer remains.
-
Diagnose at the destination first. Expired credential, changed permissions, deleted bucket, quota exceeded, network policy. The cause is at the destination far more often than at GitHub.
-
If the fix will be quick, fix it. Buffered events are delivered on recovery.
-
If the fix will be slow, pause the stream deliberately. Pausing buffers; a failing stream may not behave as favourably.
-
Track the clock. Seven days of buffering. Beyond that, resuming recovers from about a week prior and the intervening gap is not recovered.
-
Escalate before the threshold, not after. A destination problem that will take two weeks to resolve is a data loss decision that somebody other than the engineer fixing it should make.
-
Consider a temporary alternative destination if the primary will be unavailable for long. A second bucket is cheap; a permanent gap in the audit record is not.
-
Record the gap. If data was lost, document the period, the cause and the extent. An auditor finding an unexplained gap is much worse than one finding a documented incident.
The most common cause by far is credential expiry, which is entirely preventable with an expiry alert — and which is the argument for OIDC where it is available, since there is no stored credential to expire.
Mental model
Section titled “Mental model”Streaming turns a rolling window into a durable record, with at-least-once delivery, a seven-day buffer and a six-day repair window. Every one of those numbers becomes operationally relevant the day something breaks, and the whole capability is worth exactly as much as your confidence that events are still arriving.
What you learned
Section titled “What you learned”- Supported destinations are Amazon S3, Azure Blob Storage, Azure Event Hubs, Datadog, Google Cloud Storage, Microsoft Purview and Splunk
- Delivery is at-least-once, and GitHub states directly that some events may be duplicated
- A paused stream buffers for up to seven days; resuming after that recovers from about one week prior; beyond three weeks data is lost
- A health check runs every 24 hours and emails enterprise owners, with a six-day repair window
- Multiple streams are documented as being in public preview
- OIDC authentication is available for Amazon S3 only, and not for GitHub Enterprise Cloud with data residency
- Git events must be streamed to be retained beyond seven days
- Destination-side freshness monitoring is independent of GitHub’s health check and catches more
- Destination retention policies can silently defeat the entire exercise
Exercise
Section titled “Exercise”Use an enterprise you administer, or reason from documentation.
-
Determine whether streaming is configured. If so, to what destination?
-
Check whether Git events are included. Predict: are they?
-
Find the destination’s retention policy. Predict: does it match what you need?
-
Find where the stream health notifications go. Is it a monitored address?
-
Check whether a destination-side freshness alert exists.
-
Query the destination for an event you know happened. Predict: how long does it take, and does the format cooperate?
-
Look for duplicate events in a sample period. Design the deduplication key.
-
Write the recovery procedure: pause, resume, thresholds, who to tell.