REST API

Hermine’s API uses the Djano REST framework.

Authentication via Token

The most convenient way to authenticate to the API is probably to use a token. You can get such token by making a POST request on ‘api/token-auth/’ with the fields ‘username’ and ‘password’ in a form-data, using your Hermine credentials.

In Python, using requests, it would look like:

import requests

HERMINE_HOST = "https://your.hermine.instance.org/"
CREDENTIALS = {"username": "admin", "password": "your_admin_pass"}
ENDPOINT = "api/token-auth/"

url = HERMINE_HOST + ENDPOINT
r = requests.post(url, data=CREDENTIALS)

print(r.json())

You will get a response like :

{
    "token": "1273e3f6XXXXXXXXXXXXXXXX71209ac3bf29"
}

This token can then be passed in a HTTP Header to authenticate your API calls:

"Authorization" : "Token 1273e3f6XXXXXXXXXXXXXXXX71209ac3bf29".

This could look like:

import requests

HERMINE_HOST = "https://your.hermine.instance.org/"
ENDPOINT = "api/releases/"
url = HERMINE_HOST + ENDPOINT

headers = {"Authorization": "Token 1273e3f6XXXXXXXXXXXXXXXX71209ac3bf29"}
r = requests.get(url, headers=headers)

Uploading a BOM file

ORT Evaluated model

PUT /api/upload_ort/

Adds the content of the SBOM as EvaluatedModel to a given release

Parameters:
  • release (int) – the id of the release the BOM will be added to

  • ort_file (file) – the evaluated-model.json file generated by ORT

Returns:

the status of the upload

A minimal example would be:

endpoint = "api/upload_ort/"
url = HERMINE_URL + endpoint

evmodel_path = "evaluated/evaluated-model.json"
ort_file = open(evmodel_path, "rb")

data = {
    "release": 1,
}

upload_response = requests.put(url, files={"ort_file": ort_file}, data=data, headers=headers)

SPDX file

PUT /api/upload_spdx/

Adds the content of the SBOM as SPDX to a given release

Parameters:
  • release (int) – the id of the release the BOM will be added to

  • spdx_file (file) – A yaml-SPDX BOM

Returns:

the status of the upload

Checking the validation steps

The validation process of a release is divided in 4 steps. You need to complete them in the right order.

When you encounter a result that does not fit requirements to go to next step, you’ll need to make the appropriate work inside Hermine UI.

Every endpoint has a “valid” field that is set to True if every action that should be done has been done, and False otherwise.

Step 1

GET api/releases/<int:release_id>/validation_1/

Adds the content of the SBOM as SPDX to a given release

Parameters:

release (int) – the id of the release the BOM will be added to

Returns:

the status of the upload

Can be found at ‘api/releases/int:release_id/validation_1/’

API endpoint that allows to know if there are components with license information which is not a valid SPDX expression.

The response is a dictionary with the following fields :

invalid_expressions An array of Version objects for which license expression is empty or invalid. fixed_expressions An array of Version objects for which there is a corrected_license and no spdx_valid_license_expr.

Step 2

Can be found at ‘api/releases/int:release_id/validation_2/’

Confirm ANDs operators in SPDX expressions are not poorly registered ORs.

Step 3

Can be found at ‘api/releases/int:release_id/validation_2/’

Check that all scopes in the release have a default exploitation mode defined.

Step 4

Can be found at ‘api/releases/int:release_id/validation_4/’

API endpoint that allows to know if there are complex license expressions in usages of this release.

A complex license expression is an expression with more than one License expressed in it.

A choice has to be made, either by keeping the whole expression either by picking the chosen licenses in the expression.

The response is a dictionnary with the following fields :

to_resolve An array of usages linked to a version that either has a complex “corrected_license” eother a “spdx_valid_license_expr” field, and for which no explicit choice as been made. To make a choice, click on “choose expression” in hermine UI. Pick the desired scope, type the actual expression you’ll want to use for this component, and enter an explanation for your choice. This will create a UsageChoice object that is linked to the Usage object.

resolved An array of usages linked to a version hat either has a complex “corrected_license” eother a “spdx_valid_license_expr” field, and for which an explicit choice as been made.

Step 5

Can be found at ‘api/releases/int:release_id/validation_5/’ API endpoint that allows to know if there are Usages of unnacepted licenes in this release. In this case, you must set relevant derogations in Hermine UI.

The response is a dictionnary with the following fields :

usages_lic_never_allowed An array of usages containing a license that has been marked as never allowed by the legal team.

usages_lic_context_allowed An array of usages containing a license that has been marked as allowed depending on context by the legal team. usages_lic_unknown An array of usages containing a license that still has to be reviewed by the legal team.

involved_lic An array containing all the licenses that are red, orange or grey and that need a derogation for this release.

derogations An array of the derogations that has been made.

Example

An example

  - run : "curl -X PUT https://chantier.hermine-foss.org/api/upload_ort/ -H 'Authorization: Token ${{ secrets.HERMINE_TOKEN }}' -F 'ort_file=@.tortellini/out/evaluated-model.json' -F 'release=1' --silent"
              if: ${{ success() }}
            - run : "curl https://chantier.hermine-foss.org/api/releases/1/validation_1/ -H 'Authorization: Token ${{ secrets.HERMINE_TOKEN }}' --output .hermine/validation_1.json --silent"
              if: ${{ success() }}
            - run : "curl https://chantier.hermine-foss.org/api/releases/1/validation_2/ -H 'Authorization: Token ${{ secrets.HERMINE_TOKEN }}' --output .hermine/validation_2.json --silent"
              if: ${{ success() }}
            - run : "curl https://chantier.hermine-foss.org/api/releases/1/validation_3/ -H 'Authorization: Token ${{ secrets.HERMINE_TOKEN }}' --output .hermine/validation_3.json --silent"
              if: ${{ success() }}
            - run : "curl https://chantier.hermine-foss.org/api/releases/1/validation_4/ -H 'Authorization: Token ${{ secrets.HERMINE_TOKEN }}' --output .hermine/validation_4.json --silent"
              if: ${{ success() }}
            - run : "curl https://chantier.hermine-foss.org/api/releases/1/validation_4/ -H 'Authorization: Token ${{ secrets.HERMINE_TOKEN }}' --output .hermine/validation_5.json --silent"
              if: ${{ success() }}
            - uses: actions/upload-artifact@v2

JUnit

A JUnit endpoint can be used at ‘api/releases/int:release_id/junit/’.

It returns a testsuite where each validation step is a testcase.

Example :

<?xml version="1.0" ?>
<testsuites disabled="0" errors="0" failures="1" tests="4">
    <testsuite disabled="0" errors="0" failures="1" name="Foobar" skipped="0" tests="4" time="0">
        <testcase name="Licenses curation"/>
        <testcase name="ANDs confirmation"/>
        <testcase name="Scope exploitations"/>
        <testcase name="License choices"/>
        <testcase name="Policy compatibility">
            <failure type="failure" message="3 invalid component usages"/>
        </testcase>
    </testsuite>
</testsuites>

Endpoints for generic obligations

GET api/generics/

List generic obligations, optionnaly filtered by license or exploitation.

Accept the following filtering parameters to list only obligations triggered by some licenses and usage contexts :

Parameters:
  • spdx (str) – a comma-separated list of SPDX license id

  • exploitation (str) – an exploitation among Usage.EXPLOITATION_CHOICES

  • modification (str) – a modification among Usage.MODIFICATION_CHOICES

  • exploitation – an exploitation among Usage.EXPLOITATION_CHOICES

  • modification – a modification among Usage.MODIFICATION_CHOICES

POST api/generics/sbom/

List generic obligations for a list of components with their licenses and context.

Parameters:
  • packages (list) – a list of package objects with

  • packages.package_id (str) – a arbitrary identifier name (used in the response)

  • packages.spdx (str) – the SPDX identifier for the package license

  • packages.exploitation (str) – an exploitation among Usage.EXPLOITATION_CHOICES

  • packages.modification (str) – a modification among Usage.MODIFICATION_CHOICES

Returns:

a list of generic obligations with a triggered_by attributes containing the package identifier which triggered the obligation

Example

POST /api/generics/sbom/
{
    "packages": [
        {
            "package_id": "foobar",
            "spdx": "MIT",
            "exploitation": "DistributionSource",
            "modificaiton": "Altered"
        },
        {
            "package_id": "barfoo",
            "spdx": "Apache-2.0",
            "exploitation": "DistributionSourceDistributionNonSource",
            "modificaiton": "Unmodified"
        }
    ]
}

200 OK
[
        {
            "id": 1,
            "name": "Patent Grant",
            "description": "",
            "in_core": false,
            "metacategory": "",
            "team": null,
            "passivity": "",
            "triggered_by": ["foobar", "barfoo"]
        },
        {
            "id": 12,
            "name": "Indemnification of contributors",
            "description": "",
            "in_core": false,
            "metacategory": "",
            "team": null,
            "passivity": "",
            "triggered_by": ["barfoo"]
        }
    ]

Generic API endpoints for Models

For the main models of the application, you can get a list of their instances at: /api/<str:class_name>. For example, the list of your products will be at api/products/.

A detailed view for an instance of a class can be found at /api/<str:class_name>/<int:instance_id>. For example: /api/products/1/.

You can check the list of the endpoints at /api.