CI API

These endpoints let a CI pipeline that holds only an API key install es-python on its runner and then ask what the test run reported. The CI driver script calls both for you; see Run es-python in CI for complete pipeline examples.

Install on a runner

POST /api/ci/install/ returns a one-time install secret for one of your es-python machines, found by name, and creates the machine the first time. It is a write. Use it once per pipeline run: every call resets the machine for a fresh install, the same way reinstalling does, and keeps its name, configuration, rules and events.

POST /api/ci/install/

Form fields:

Field Meaning
machine_name Required. One name per pipeline, such as ci-myrepo. 1 to 128 characters.
attested Required, true. Your confirmation that you are authorized to monitor the computer this installs on, the same box the dashboard asks you to tick.
distro, arch Required the first time, when the machine does not exist yet, such as ubuntu_24_04 and x86_64. Sent for an existing machine, they change its OS. See supported targets.
python_version Optional. Used when the machine is created; the default is the usual default. For an existing machine it must match the machine's version.
format Optional. text answers with key=value lines instead of JSON, for scripts with no JSON parser.
curl -s https://eyalsec.com/api/ci/install/ \
  -H "X-API-Key: $EYALSEC_API_KEY" \
  -d machine_name=ci-myrepo -d distro=ubuntu_24_04 -d arch=x86_64 -d attested=true
{ "machine_name": "ci-myrepo", "public_id": "0b9d7e21-4c3a-4f5e-8a61-2d9c0e7f1b53",
  "created": false, "os_type": "ubuntu_24_04_x86_64", "python_version": "3.13",
  "secret": "<single-use-secret>", "script_path": "https://eyalsec.com/install.sh",
  "expires_in": 600, "server_time": "2026-10-07T12:00:00.123456Z",
  "events_url": "https://eyalsec.com/scanner/events?machine=ci-myrepo" }

The secret works once and expires after 10 minutes (expires_in is in seconds). Post it to script_path exactly as the install command does. server_time is the server's clock when the secret was made; you can pass it as since to the findings check.

A new machine counts against your machine limit like any other, and at the limit the answer is 409. An existing machine needs no new slot. Other errors: 409 when more than one es-python machine has that name, or when python_version differs from the existing machine's; 422 for a missing field, an unknown target, or a Python version not available for it; 403 when your account does not have es-python.

Check a run's findings

GET /api/ci/findings/ tells you what programs on one machine reported since a moment, and how many of those findings are at or above a severity. It is a read, so a read-only key may call it.

GET /api/ci/findings/
Parameter Meaning
machine Required. The machine's name.
since Required. Where the window starts: RFC3339 (2026-10-07T12:00:00Z), Unix seconds, or an HTTP date such as a Date response header. Prefer the server's clock (server_time above, or a Date header) to the runner's.
min_severity critical, high (the default), medium, low or info.
limit How many of the findings at or above min_severity to list, worst first, 0 to 100. The default is 20; the counts always cover all of them.
format text for key=value lines instead of JSON.
curl -s "https://eyalsec.com/api/ci/findings/?machine=ci-myrepo&since=2026-10-07T12:00:00Z" \
  -H "X-API-Key: $EYALSEC_API_KEY"
{ "machine": "ci-myrepo", "since": "2026-10-07T12:00:00Z", "min_severity": "high",
  "findings": 2, "new_findings": 1, "total": 5,
  "by_severity": { "critical": 1, "high": 1, "medium": 3, "low": 0, "info": 0 },
  "truncated": false, "hidden_by": "",
  "url": "https://eyalsec.com/scanner/events?machine=ci-myrepo&sev=critical%2Chigh",
  "events": [ { "id": 90210, "severity": "critical", "where": "os system",
                "count": 3, "last_seen": "2026-10-07T12:03:10Z", "new": true } ] }
Field Meaning
total Every event a run on this machine reached inside the window, at any severity.
findings Those at or above min_severity.
new_findings Of findings, the ones no earlier run had reached.
by_severity total, split by severity.
events The findings, worst first: the event id (open it on the dashboard, or with GET /api/event/{id}), its severity, its sink label (where), its all-time occurrence count, when it last happened, and whether it is new.
url The dashboard's events list for this machine at that severity.
truncated true when the run reached more distinct events than one check reads (10,000); the counts are then a lower bound.
hidden_by The name of your Hide rule that hides every es-python event, when one does; nothing can be counted then.

An event counts when a run on this machine reached it inside the window, even if it was found long before, so a re-run of a failing pipeline fails again until the flow is fixed or you decide to accept it. The check counts exactly what the es-python events list would show you: your event quota, your filters, your global and this machine's Hide rules, and the live bucket all apply, so a finding you hid or that was suppressed never fails a build.

The value that reached the sink is deliberately not in the answer, because CI logs are often public. Open the event on the dashboard to see it.

Errors: 404 when you have no es-python machine with that name, 409 when you have more than one, 400 for a missing or unreadable since or an unknown min_severity, 403 when your account does not have es-python.

The CI driver script

GET /ci.sh serves a small POSIX sh script that calls the two endpoints above: it installs es-python, runs your command under it, waits a few seconds for the events to arrive, then prints a short summary and exits non-zero when anything is at or above your threshold. It needs no key to download and contains no secret; it reads your key from EYALSEC_API_KEY when it runs.

curl -fsSL https://eyalsec.com/ci.sh -o es-python-ci.sh
sh es-python-ci.sh run --machine ci-myrepo --distro ubuntu_24_04 --arch x86_64 -- es-python -m pytest

Run it with sh, not source. Its options and exit codes are on Run es-python in CI.

Something unclear or missing on this page? Email support@eyalsec.com.

EyalSec Pricing Docs Security Research Vulnerabilities Security glossary About Contact עברית Login Book a live demo