First run

An empty inventory is a fair first impression and a useless demonstration. Load the invented portfolio, run the whole loop against it, and then throw it away.

  1. Load the demo
  2. Run the loop
    1. What you will see on the plain image
    2. The score
  3. Look at it
  4. Starting over

Load the demo

docker run --rm -v "$PWD/data:/data" --user "$(id -u):$(id -g)" \
    ghcr.io/oscarvalenzuelab/crane:latest demo
loaded 140 rows: 8 products, 8 components, 5 SBOM records
SBOM files written to /data/demo-sboms

Next: crane validate sbom && crane worker run --once && crane assess cra

Eight invented products, chosen to show the situations this exists for: a component shared by several products, one with no build at all, SBOMs that pass and SBOMs that fail, a document that cannot be read, and a product nobody has scoped.

demo refuses to run against a database that already has anything in it, so it cannot be mistaken for real inventory. --force overrides that, and you should not need it.

The demo portfolio is fiction. Do not build a real deployment on top of it. Start over with an empty database instead, which is one file to delete.

Run the loop

The working loop is four commands, and they are the same four whether the portfolio is invented or real.

crane validate sbom --requested-by you   # queue conformance checks. Returns immediately
crane worker run --once                  # actually execute them
crane assess cra                         # score, and store the reasoning
crane report leadership                  # a document for somebody who did not run this

Queueing and executing are separate on purpose. validate never runs a tool; it registers work and returns. That is what makes it safe in cron and safe over an API, and it is why a deployment with no shell can still ask for validation.

What you will see on the plain image

claimed 15, succeeded 0, failed 15, retrying 0

All fifteen failed, and the exit code is 5. This is correct and it is not a misconfiguration: the plain image carries no validator. Ask a failed job why:

crane job list --status failed --json
{
  "definition_key": "ossbomer.validate",
  "error": "the SBOM file does not exist at /data/demo-sboms/cirrus-sensor-missing.spdx.json",
  "attempts": 1,
  "max_attempts": 3
}

Two different failures are mixed together here, and telling them apart is the point of the exercise:

  • The validator is not installed. Use the -ossbomer image, or install ossbomer next to the worker.
  • The SBOM file genuinely is not there. One demo product ships a deliberately missing document, because a source you cannot read is a real state and the report has to distinguish it from a source nobody asked about.

The score

crane assess cra
obligation:  cra v2
lens:        cra.regulatory

denominator:
  in scope           6
  scope undecided    1
  out of scope       1
  products total     8

bands:
  amber              4
  red                2
  average score      59.2

checks across the population:
  composition.known          2 pass, 4 warn
  owner.accountable          4 pass, 2 warn
  sbom.conformance           6 insufficient evidence
  sbom.present               1 fail, 4 pass, 1 source inaccessible
  scope.decided              6 pass
  support.period.declared    2 fail, 4 pass
  vuln.contact.published     3 fail, 3 pass

Read the denominator before the score. Eight products exist; six are in scope under this lens; one has no scope decision and is counted neither as passing nor as failing, and one is out of scope. A number that does not say which population it measured is not an answer.

Note the three distinct non-passing states, which most tools collapse into one:

State Means
fail Checked, and it does not hold
warn Checked, and it is weak rather than absent
insufficient evidence Nobody could check. Here, because no validator ran
source inaccessible The document exists in the inventory and could not be read

insufficient evidence is not a failing grade. Nothing is scored as failing on account of a tool that was never installed.

Look at it

docker run --rm -p 127.0.0.1:8000:8000 -v "$PWD/data:/data" \
    --user "$(id -u):$(id -g)" -e CRANE_ALLOW_UNAUTHENTICATED_BIND=1 \
    ghcr.io/oscarvalenzuelab/crane:latest serve --host 0.0.0.0 --port 8000 --worker
Page What it answers
/ Every obligation side by side. The only consolidated view
/attention What to do next, ranked. The page to open first on a working day
/products, /components The inventory, filterable, with a CSV at /products.csv
/graph How they interact: repositories feed components, components compose products. Anything nothing relates to is drawn as an island
/scope Scope decisions per lens, and what is undecided
/findings, /exceptions What failed, and what has been formally excused
/sbom Evidence, its content hashes, and its validation state
/jobs Queued and finished work, with stdout and stderr per run
/health Whether the build itself is coherent
/reports The three reports, rendered
/api/docs The HTTP API, browsable and complete

Every page except / works one obligation at a time, chosen in the header and carried in the URL as ?o=, so a filtered view is a link you can send someone.

--worker runs queued tools in the same process. Without it the interface will happily queue validations that nothing ever executes.

Starting over

The database is one file. Deleting it is the reset:

rm -rf data/crane.db data/demo-sboms
docker run --rm -v "$PWD/data:/data" --user "$(id -u):$(id -g)" \
    ghcr.io/oscarvalenzuelab/crane:latest init

Now go to Populate and put your own portfolio in.


Back to top

CRAne. The database is one SQLite file and it is yours.

This site uses Just the Docs, a documentation theme for Jekyll.