Skip to main content
In this tutorial, you’ll report a with kosli attest custom. You’ll see how to:
  • Bind the attestation to a trail or to an artifact — two alternative options for the same command.
  • Identify an artifact by letting Kosli fingerprint it (container image, file, or directory), or by passing a SHA256 fingerprint directly.
  • Attest before the artifact has been reported, using the artifact’s template name and a git commit.

Prerequisites

  • Install Kosli CLI and set the common env vars (KOSLI_API_TOKEN, KOSLI_ORG, KOSLI_FLOW, KOSLI_TRAIL).
  • A Kosli flow and trail — see the Getting started guide if you don’t have one.
  • A custom attestation type that already exists in your org. This is a hard requirement — kosli attest custom --type <name> will fail if <name> hasn’t been created yet.

1. Create the custom attestation type first

Before you can report a custom attestation, the type referenced by --type must already exist in your Kosli org. You have two ways to create it: For this tutorial we’ll create a minimal coverage-report type that requires a coverage field of at least 80:
kosli create attestation-type coverage-report \
  --description "Code coverage report" \
  --jq '.coverage >= 80'
Prepare a JSON file with the data you want to attest. Save it as coverage.json:
{ "coverage": 92, "tool": "pytest-cov" }
In every example below, this coverage.json is the value of --attestation-data.

2. Report the attestation

A custom attestation can be bound to either a trail or an artifact. Pick the option that matches what you want to attest about.
Use this when the evidence applies to the trail as a whole (e.g. overall test results, release readiness, change approval) and is not tied to a specific build artifact.
kosli attest custom \
  --type coverage-report \
  --name overall-coverage \
  --attestation-data coverage.json
--name must match an attestation declared in the flow or trail YAML template.

3. Attest before the artifact exists

You can report an attestation for an artifact that hasn’t been reported to Kosli yet. Reference the artifact by its template name from the flow YAML and pass --commit so Kosli can bind the attestation when the artifact is later reported. When you pass --commit without a fingerprint, Kosli does not calculate or assume any fingerprint. Instead, it stores the attestation as pending against the artifact’s template name + commit, and binds it to the real fingerprint later — when an artifact attestation arrives for that same template name and commit.

How it works in practice

Say your flow template defines an artifact called artifact with an attestation test:
artifacts:
  - name: artifact
    attestations:
      - name: test
        type: junit
You can run tests before the artifact is built and report:
kosli attest junit \
  --name artifact.test \
  --commit $(git rev-parse HEAD) \
  ...
Notice:
  • --name uses the dotted form <artifact-template-name>.<attestation-name>.
  • No fingerprint, no --artifact-type, no positional artifact argument.
  • --commit is what tells Kosli which future artifact this attestation will belong to.
Later, when you build and report the artifact itself:
kosli attest artifact ./build/artifact.tar.gz \
  --artifact-type file \
  --name artifact \
  --commit $(git rev-parse HEAD)
Kosli matches the earlier artifact.test attestation to this newly-reported artifact because both share the same template name (artifact) and the same git commit. At that point the attestation is bound to the artifact’s actual SHA256 fingerprint.

Subtleties worth flagging

  1. The match key is (template artifact name, git commit) — not the fingerprint. The fingerprint is only resolved retroactively once the artifact itself is reported.
  2. The artifact name must match the template. artifact.test only works if your flow YAML declares an artifact named artifact. Without a template the dotted form has nothing to bind to.
  3. Same commit, both sides. If the pre-artifact attestation uses commit abc123 but the artifact is later reported with commit def456, they will not be linked. The attestation will stay floating, unbound to any artifact.
  4. The commit must be resolvable in a git repo. --commit requires access to a real git repo so Kosli can pull commit metadata (author, message, branch, PR info). It’s not just a string label.
  5. Multiple artifacts with the same name + commit will all match. If you report the artifact more than once from the same commit (e.g. rebuilds), every matching artifact picks up the attestation. Attestations are append-only, so this is usually what you want.
  6. Order doesn’t matter. You can report artifact.test before or after artifact itself — Kosli binds them whenever both sides exist.
  7. Without a template (auto-created flow/trail), --commit-based pre-artifact attestations still work for binding, but there’s no template-defined compliance requirement — the artifact’s compliance only reflects the attestations actually made against it.
  8. --commit is only required for the pre-artifact case. If you already have a fingerprint (via --fingerprint or --artifact-type), --commit is optional metadata.

4. Add an attachment (optional)

You can attach files or directories as evidence. They are compressed and stored in Kosli’s evidence vault.
kosli attest custom \
  --type coverage-report \
  --name overall-coverage \
  --attestation-data coverage.json \
  --attachments ./coverage-report.html

What you’ve accomplished

You can now report a custom attestation in every relevant shape:
  • against a trail, or against an artifact (by fingerprint or by name + commit);
  • identifying the artifact via container image, file, directory, or a raw SHA256.
From here:
Last modified on June 8, 2026