Send events to OpenWAFBeta

Send each CI job's destinations, blocks and detections to your organization's Egress events with GitHub OIDC, without storing a secret in the repository.

On this page

By default the action keeps everything in the run: the job summary and report.json. With send-events: on it also sends each job's destinations to your OpenWAF organization, where they can be read from the API across repositories and runs.

No secret is stored in the repository. The job proves who it is with a GitHub OIDC token, which OpenWAF exchanges for a token that only lets it send that run's events.

Before you start

  • Early access. Egress is turned on per organization; until it is, registration answers 403 feature_disabled. Write to support@openwaf.dev to join.
  • An organization-wide admin to register repositories. Reading the registered repositories needs any role of the whole organization.
  • The repository's GitHub ids, which pin the registration to that repository: a repository renamed, transferred or deleted and created again with the same name is not the same repository and must be registered again.
gh api repos/acme/app --jq '.id, .owner.id'

1. Register the repository

A GitHub repository can be registered in one organization only. refs limits which refs may send events (exact refs, no wildcards, up to 20); empty means any.

curl -sS -X POST "https://dash.openwaf.dev/v1/orgs/$ORG/egress/ci/repositories" \
  -H "Authorization: Bearer $OPENWAF_TOKEN" -H "Content-Type: application/json" \
  -H "X-Change-Reason: CI egress events for acme/app" \
  -d '{"repository": "acme/app", "repository_id": 123456789, "repository_owner_id": 987654, "refs": ["refs/heads/main"]}'

Answers 201 with the registration (id, repository, repository_id, repository_owner_id, refs, created_at, created_by). GET on the same path lists them under items; DELETE …/egress/ci/repositories/{id} removes one (204), and the tokens it was given stop working at once.

Registrations are recorded in the audit log with their reason.

2. Turn it on in the workflow

.github/workflows/test.yml
permissions:
  contents: read
  id-token: write   # lets the job ask GitHub for an OIDC token
jobs:
  test:
    runs-on: ubuntu-24.04
    steps:
      - uses: actions/checkout@v5
      - uses: openwaf-dev/egress-action@v0.3.2
        with:
          send-events: "on"
      - run: make test

At the end of the job the summary says how many destinations were sent, for example 14 destinations sent to OpenWAF Egress events (https://dash.openwaf.dev).

What is sent

One event per destination of the job, with the run's identity. A name that was only resolved, with nothing connected, refused or detected, is left out.

PartFields
RunRepository, run id and attempt, workflow, job, commit SHA, ref, event name, runner name
SummaryMode, number of destinations, blocked, would block, detections, DNS queries
Each destinationHost, first port, path (proxy, direct, container, udp, dns), container name, decision (allow, audit, block), reason, detection ids, connections, bytes up and down

Never request bodies, headers, URLs or the secrets a detection found.

How it works

  1. The post step asks GitHub for an OIDC token with the audience openwaf-egress-ci. It never prints or logs it.
  2. It sends it to POST /v1/egress/ci/token on openwaf-api (default https://dash.openwaf.dev). OpenWAF checks GitHub's signature, the issuer, the audience, the time and that the token has not been used before, and that the repository, its id and its owner's id match a registration (and the ref, when refs is set). It answers with a token (OWE_CI_…) valid for 15 minutes for that repository only.
  3. It sends the events to POST /v1/egress/ci/events in batches of up to 1000, with up to three attempts per batch. A batch carries a batch_id, so a retry never counts twice.

A failure never fails the job: the summary and the log get a warning such as Events not sent to OpenWAF: token exchange: 403 repository_not_registered.

ErrorMeaning and fix
GitHub OIDC token: … (the job needs permissions: id-token: write)Add id-token: write to the workflow's or the job's permissions. Pull requests from forks never get it.
401 invalid_tokenThe OIDC token was refused (signature, issuer, audience, time or used twice); or, for events, the OpenWAF token expired.
403 repository_not_registeredRegister the repository; again if it was renamed, transferred or created again.
403 ref_not_allowedThe run's ref is not in the registration's refs.
403 feature_disabledEgress is not enabled for the organization.
403 repository_mismatchThe run's repository is not the token's.
429 rate_limited, 503 unavailableTry again later; the job is not affected.

See the events

CI events are read from the API. The dashboard's Blocked requests view and the MCP tool egress_events show only the calls of your AI agents that the gateway refused, not CI events.

curl -sS "https://dash.openwaf.dev/v1/orgs/$ORG/egress/events?attack_type=egress_ci&limit=100" \
  -H "Authorization: Bearer $OPENWAF_TOKEN"

attack_type=egress_ci selects CI events; …/egress/events/stream takes the same filter and follows new ones as Server-Sent Events. In each event:

FieldValue
actionallow, log (audit: enforce would have refused it) or block
rule_nameThe reason, such as not_allowed or dlp
hostThe destination (and ip when the destination is an address)
methodThe path: proxy, direct, container, udp or dns
pathPort, container and counts, such as :443 container=db connections=3 bytes_up=812 bytes_down=6200
user_agentci:<owner>/<repo>/<workflow>/<job>#<run id>
msgThe detection ids

Last updated:

↑↓ to navigate↵ to openesc to close