diff --git a/config/navigation.json b/config/navigation.json index d180b07..739d4db 100644 --- a/config/navigation.json +++ b/config/navigation.json @@ -71,6 +71,7 @@ { "group": "Attesting", "pages": [ + "tutorials/attest_custom", "tutorials/attest_snyk", "tutorials/custom-attestation-ctrf", "tutorials/attest_large_documents" diff --git a/tutorials/attest_custom.md b/tutorials/attest_custom.md new file mode 100644 index 0000000..91f77e6 --- /dev/null +++ b/tutorials/attest_custom.md @@ -0,0 +1,169 @@ +--- +title: "Reporting a custom attestation" +description: "Walk through reporting a kosli attest custom attestation against a trail or an artifact, using the different ways to identify the artifact." +--- + +In this tutorial, you'll report a custom attestation with [`kosli attest custom`](/client_reference/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](/getting_started/install) and [set the common env vars](/getting_started/install/#assigning-flags-via-environment-variables) (`KOSLI_API_TOKEN`, `KOSLI_ORG`, `KOSLI_FLOW`, `KOSLI_TRAIL`). +* A Kosli flow and trail — see the [Getting started guide](/getting_started/flows) 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 ` will fail if `` 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: + +* **CLI** — [`kosli create attestation-type`](/client_reference/kosli_create_attestation-type) (good for quick experiments). +* **Terraform** — the [`kosli_custom_attestation_type` resource](/terraform-reference/resources/custom_attestation_type) (recommended so the type is version-controlled). + +For this tutorial we'll create a minimal `coverage-report` type that requires a `coverage` field of at least 80: + +```shell +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`: + +```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. + +```shell +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. + + + + +Use this when the evidence is about a specific build artifact (a container image, a file, or a directory). You can identify the artifact in two ways: let Kosli compute the SHA256 fingerprint for you, or pass the fingerprint directly. + +#### Option A — Let Kosli fingerprint the artifact + +Pass the artifact reference as a positional argument together with `--artifact-type`. Supported types: + +| `--artifact-type` | Positional argument | Notes | +| :--- | :--- | :--- | +| `oci` | Container image reference (e.g. `ghcr.io/acme/web:1.2.3`) | Kosli pulls the digest from the registry. For private registries also pass `--registry-username` and `--registry-password`. | +| `docker` | Image present in the local Docker daemon (e.g. `acme/web:1.2.3`) | Reads the digest from the local daemon — no registry call. | +| `file` | Path to a single file (e.g. `./dist/app.tar.gz`) | | +| `dir` | Path to a directory (e.g. `./build/`) | Use `--exclude` to skip files/dirs from the fingerprint (e.g. `--exclude '**/*.log,**/node_modules'`). | + +**Container image — fingerprint from a registry:** + +```shell +kosli attest custom ghcr.io/acme/web:1.2.3 \ + --artifact-type oci \ + --type coverage-report \ + --name overall-coverage \ + --attestation-data coverage.json +``` + +**Container image — fingerprint from the local Docker daemon:** + +```shell +kosli attest custom acme/web:1.2.3 \ + --artifact-type docker \ + --type coverage-report \ + --name overall-coverage \ + --attestation-data coverage.json +``` + +**File artifact:** + +```shell +kosli attest custom ./dist/app.tar.gz \ + --artifact-type file \ + --type coverage-report \ + --name overall-coverage \ + --attestation-data coverage.json +``` + +**Directory artifact:** + +```shell +kosli attest custom ./build/ \ + --artifact-type dir \ + --exclude '**/*.log,**/node_modules' \ + --type coverage-report \ + --name overall-coverage \ + --attestation-data coverage.json +``` + +#### Option B — Match the artifact by SHA256 with `--fingerprint` + +Use this when you already have the SHA256 (e.g. computed earlier in the pipeline, returned by `kosli fingerprint`, or printed by your build tool). Omit the positional argument and `--artifact-type`. + +```shell +kosli attest custom \ + --fingerprint 9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08 \ + --type coverage-report \ + --name overall-coverage \ + --attestation-data coverage.json +``` + +`--fingerprint` and `--artifact-type` are mutually exclusive — pick one. + + + + +## 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. + +```shell +kosli attest custom \ + --type coverage-report \ + --name myArtifactTemplateName.overall-coverage \ + --commit $(git rev-parse HEAD) \ + --attestation-data coverage.json +``` + +The `--name` uses the dotted form `.`. `--commit` is required in this case so Kosli knows which future artifact this attestation belongs to. + +## 4. Add an attachment (optional) + +You can attach files or directories as evidence. They are compressed and stored in Kosli's evidence vault. + +```shell +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: +* [`kosli attest custom`](/client_reference/kosli_attest_custom) reference — full flag list. +* [`kosli create attestation-type`](/client_reference/kosli_create_attestation-type) reference — for managing types via CLI. +* [Terraform: `kosli_custom_attestation_type`](/terraform-reference/resources/custom_attestation_type) — recommended for managing types as code. +* [Tutorial: Creating a custom CTRF attestation type](/tutorials/custom-attestation-ctrf) — a worked example of a real-world custom type.