Runtime profiling and behavioral assertions for CI/CD and agentic workflows in GitHub Actions.
Garnet is powered by Jibril, an eBPF sensor that attaches to your CI runner and captures every process spawn and outbound connection — with full lineage. Results surface in-line showing pass / fail per run with context.
One YAML step. No code changes and minimal overhead.
Get your API token at app.garnet.ai
-
A behavioral profile of every run: kernel-level capture of every network call, process spawn, and file access — with full lineage from parent to child, down to the exact binary that made the connection.
-
Runtime assertions in your PR: Assertions are like unit tests for runtime behavior. Results appear as a PR comment and step summary: a table per job with pass / fail assertions and an egress table with lineage inline. A permalink links to the full run report, with Slack alerts configurable on failures.
-
Lineage-based evidence: When something unexpected runs, you don't get a domain name — you get the full chain:
npm install → dep@1.2.3 postinstall → bash → curl → unknown-domain.com
Create an API token in the Garnet app at https://app.garnet.ai, then add it as a repo secret named GARNET_API_TOKEN.
on:
push:
pull_request:
workflow_dispatch:
jobs:
monitor:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Checkout (recommended)
uses: actions/checkout@v4
- uses: garnet-org/action@v2
with:
api_token: ${{ secrets.GARNET_API_TOKEN }}
- name: Your existing steps
run: npm test
- GitHub job summary: A Markdown "security profile" appended at the end of the job—even if the job fails.
- Pull request comment: On pull request workflows, Garnet creates one comment per push, merging jobs and workflows from the same push into that comment.
- Garnet UI: linked from in-line results through a permalink, for in-depth investigation and additional management features.
- Main step: downloads
garnetctl+jibril, creates a Garnet agent for the run, fetches your merged network policy, and starts Jibril as asystemdservice on the runner. - Post step (always): stops Jibril so it flushes events, appends the generated profile to
GITHUB_STEP_SUMMARY, and creates or updates the pull request comment for the current push when the workflow runs for a PR. Whendebug=true, it also uploads Jibril logs as build artifacts.
For PR workflows, the action reads Jibril's JSON profile and rebuilds the markdown into one comment per push. Multiple jobs and workflows from the same push are merged into that comment so the PR stays readable while preserving history across pushes.
To let the action write PR comments, grant the workflow token write access to pull requests or issue comments. For example:
permissions:
contents: read
pull-requests: write
steps:
- uses: garnet-org/action@v2
with:
api_token: ${{ secrets.GARNET_API_TOKEN }}| Input | Required | Default | Description |
|---|---|---|---|
api_token |
Yes | — | Your Garnet API token from app.garnet.ai |
github_token |
No | ${{ github.token }} |
GitHub token used for pull request comments |
api_url |
No | https://api.garnet.ai |
Garnet API base URL |
garnetctl_version |
No | latest |
Garnet CLI version (1.2.3 or latest) |
jibril_version |
No | "" (auto) |
Jibril version (v2.10.8 or latest) |
debug |
No | false |
Enable debug mode and upload logs as artifacts |
Assertions are runtime invariants — like unit tests, but for execution behavior. The current assertion is known_bad_egress: it fails if any outbound connection matches a domain from Garnet's managed threat feed. Future assertion families will cover hidden binary execution, sensitive file access, and anomalous process spawns.
Your team reviews the code. Your CI runs it. Between git push and production, dependencies execute postinstall scripts, AI-generated functions spawn processes, and build steps make outbound connections — none of which appear in a static scan. Garnet tells you what your pipeline actually did — the ground truth for execution.
-
Shai-Hulud — 800+ npm packages with a second-stage payload. Postinstall hook bootstrapped Bun, ran TruffleHog to harvest runner secrets, then registered a rogue GitHub runner. See the breakdown →
-
Clinejection — LLM agent prompt injection via a malicious GitHub Issue triggered code execution, poisoned the Actions cache, and exposed an npm publish token. 4,000+ developers received a backdoored package within 8 hours.
-
tj-actions/changed-files — Supply chain compromise in a widely-pinned Action injected a memory scraper that printed runner secrets to public workflow logs across 23,000 repos.
runs-on: ubuntu-latest— Linux runner with systemdsudoaccess to install binaries and configure the Jibril serviceGARNET_API_TOKENset as a repository secret
| Symptom | Fix |
|---|---|
| "API token is required" | Confirm GARNET_API_TOKEN is set in repository secrets and passed as api_token |
| No PR comment appearing | The action posts comments only on pull_request events — confirm your workflow triggers include pull_request |
| No summary output | Enable debug: "true" to upload Jibril logs as artifacts, then inspect jibril.log and jibril.err |
| Restrictive permissions | This action works with permissions: contents: read — if your workflow hardens permissions aggressively, ensure the job can read repository contents |
See SECURITY.md to report vulnerabilities — or email security@garnet.ai. MIT — see LICENSE