CI¶
A pipeline can submit a sample to a running Maljan deployment, wait for the analysis and act on what it publishes, through the REST API and an API key. This page is a recipe built from those endpoints; Maljan ships no CI plug-in of its own. The checks this repository runs on itself are described in Development.
Keep samples off shared runners
A CI job that submits malware carries the sample through the runner. Use a runner you control, on a network you are authorised to use for this, and keep the deployment off the public internet.
An API key for the pipeline¶
A key acts as the account that minted it, so mint it signed in as the account the pipeline should act as:
curl -s -X POST http://maljan.internal:8000/api/v1/audit/api-keys \
-H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
-d '{"name": "ci", "expires_in_days": 90}'
The answer's raw_key is shown once; store it as a CI secret. Keys are stored
only as a SHA-256 hash, can carry an expiry, and an unknown, revoked or expired
key is refused with the same 401. last_used_at is stamped on every accepted
call. See Security.
Submit, wait, act¶
-
Upload the sample.
-
Start the job, naming the team if it is not the deployment's active one.
JOB=$(curl -s -X POST "$MALJAN/api/v1/jobs" \ -H "X-API-Key: $MALJAN_API_KEY" -H 'Content-Type: application/json' \ -d "{\"sample_id\":\"$SAMPLE\",\"config\":{\"profile\":\"default\"}}" | jq -r .id)A 422 here is a refusal to start a job that could only fail — a model no probe has reached, a static provider that is not ready, an unknown team — and its
detailsays which. -
Wait for a terminal status —
completed,failedorcancelled. -
Read the verdict and fetch what to act on.
REPORT=$(curl -s "$MALJAN/api/v1/reports/job/$JOB" -H "X-API-Key: $MALJAN_API_KEY") echo "$REPORT" | jq '{verdict, verdict_reading, overall_confidence}' REPORT_ID=$(echo "$REPORT" | jq -r .id) curl -s "$MALJAN/api/v1/reports/$REPORT_ID/iocs" -H "X-API-Key: $MALJAN_API_KEY" > iocs.json curl -s "$MALJAN/api/v1/reports/$REPORT_ID/stix" -H "X-API-Key: $MALJAN_API_KEY" > bundle.json
What to gate on¶
verdictisMalware,SuspiciousorBenign. Gate on it together withverdict_reading:statedmeans the judge's structured answer stated it,fallbackthat it was read from an answer that was not a bundle, andunrecognisedandunstatedthat the judge's conclusion could not be read, so the inconclusiveSuspiciouswas published.- The IOC feed's default is only what the publish rule publishes, each row
with
publish_answersaying why. That is the set to push to a blocklist; see The IOC feed. - A failed job can still have a report, with
incomplete_reasonsaying where the run failed. Treat it as incomplete rather than as a verdict.
Runs take minutes to hours depending on the model and the team, so give the waiting step a timeout that suits the deployment. Requests are rate-limited per client address and path; see Operations.