Introduction to the FOSSA API
You'll first need to register for an API key to use the FOSSA API. You can do this by visiting the FOSSA website and creating an account. Once you have an account, you can generate an API key by navigating to the 'API Keys' section of your account dashboard.
Simple Tasks
https://app.fossa.com/api/projects
You can use this endpoint to get a list of all projects and filter by title. The example below is using the offset
and count
parameters for pagination
curl --location --request GET '<https://app.fossa.com/api/projects?title=DocsExample&sort=title&count=10&offset=20>'
--header 'Authorization: Bearer YOURTOKENHERE'
https://app.fossa.com/api/revisions?projectId=
After getting a list of all your projects, you can use one of the project locators to get a list of all the revisions. Make note of the URL encoding in the below example, the locator from the previous example was custom+27932/DocsExample
, and the encoded form is custom%2B27932%2FDocsExample
curl --location --request GET '<https://app.fossa.com/api/revisions?projectId=custom%2B27932%2FDocsExample>'
--header 'Authorization: Bearer YOURTOKENHERE'
Get a single revision’s details
https://app.fossa.com/api/revisions/
Once you’ve chosen the appropriate revision, you can use the locator
field of the response to get the details of that revision. You can also get this URL by navigating to the revision in the FOSSA UI and selecting 'Visit API endpoint'
curl --location --request GET '<https://app.fossa.com/api/revisions/custom%2B27932%2FDocsExample%242023-03-29T15%3A40%3A33Z>'
--header 'Authorization: Bearer YOURTOKENHERE'
Get a single revision’s dependencies
https://app.fossa.com/api/revisions//dependencies
Getting the dependencies can often be useful for automation purposes. This is identical to the previous link, but adds /dependencies on the end.
curl --location --request GET '<https://app.fossa.com/api/revisions/custom%2B27932%2FDocsExample%242023-03-29T15%3A40%3A33Z/dependencies>'
--header 'Authorization: Bearer YOURTOKENHERE'
Check for vulnerabilities using a locator
https://app.fossa.com/api/vulns/by-locator
FOSSA uses this concept of a “locator” heavily in our API, which may confuse you. You can find locators for dependencies using the API endpoints listed above.
curl --location --request POST '<https://app.fossa.com/api/vulns/by-locator>'
--header 'Authorization: Bearer YOURTOKENHERE'
--header 'Content-Type: application/json'
--data-raw '{
'locators': [
'npm+ssh2$0.6.1',
'npm+jsonwebtoken$8.5.1'
]
}'
Getting all projects which contain a dependency
https://app.fossa.com/api/revisions/
curl --location --request GET '<https://app.fossa.com/api/revisions/npm%2Bcoa%242.0.2/parent_projects>'
--header 'Authorization: Bearer YOURTOKENHERE'
Chaining tasks together
Getting a list of all NPM dependencies from projects with 'zd' in the title and finding out what vulnerabilities impact them
import requests
# simple function to encode the locators
def url_encode(s):
return s.replace('/','%2F').replace('+','%2b').replace('$','%24')
if __name__ == '__main__':
base = 'https://app.fossa.com/api'
auth = { 'Authorization': 'Bearer YOURTOKENHERE' }
# querying for all projects with 'zd' in the title
projs = requests.get(url=f'{base}/projects?title=zd', headers=auth).json()
# note that I use `last_analyzed_revision` in order to skip listing all of the revisions. This chunk just turns it into a list of revision locators since that's the only information I need
proj_locators = list(map(lambda p: url_encode(p['last_analyzed_revision']), projs))
# starting with an empty dep list, getting deps for the latest revision of each project, and adding them if their fetcher is 'npm'
deps = []
for loc in proj_locators:
resp = requests.get(url=f'{base}/revisions/{loc}/dependencies', headers=auth).json()
for dep in resp:
if dep['loc']['fetcher'] == 'npm':
deps.append(dep['locator'])
# after the loop, we use the `vulns/by-locator` endpoint to find what NPM vulns impact projects with 'zd' in the title
if (len(deps) == 0):
print('No deps found')
else:
resp = requests.post(url=f'{base}/vulns/by-locator', headers=auth, data={'locators': deps}).json()
print(resp)
Find dependencies whose licenses have GPL in the name in projects belonging to a certain team
import requests
def url_encode(s):
return s.replace('/','%2F').replace('+','%2b').replace('$','%24')
if __name__ == '__main__':
base = 'https://app.fossa.com/api'
auth = { 'Authorization': 'Bearer YOURTOKENHERE' }
projs = requests.get(url=f'{base}/projects', headers=auth).json()
# the objects returned by the /projects endpoint include a `teamProjects` field which we can use to check if a project belongs to a specific team (in this case, 1224)
teamProjs = filter(lambda p: {'teamId': 1224} in p['teamProjects'], projs)
# then we can get the last analyzed revision again, and i'm also deduping this list just as a precaution
locators = list(map(lambda p: url_encode(p['last_analyzed_revision']), teamProjs))
# we'll store each dependency as a tuple: ('dependency locator', 'license')
deps = []
for loc in locators:
resp = requests.get(url=f'{base}/revisions/{loc}/dependencies', headers=auth).json()
for dep in resp:
for lic in dep['licenses']:
if 'gpl' in lic['licenseId'].lower():
deps.append((dep['locator'], lic['licenseId']))
for dep in deps:
print(dep)
# ('mvn+org.apache.maven:maven-compat$3.6.3', 'GPL-2.0-with-classpath-exception')
# ('npm+@algolia/cache-browser-local-storage$4.13.1', 'AGPL-3.0-only')
# ('npm+node-forge$1.3.1', 'GPL-1.0-or-later')
Hopefully, you'll see how we can achieve some pretty complicated tasks using only a few simple endpoints. You can also try tinkering with the API in a tool like Postman at first to get repeatable results. Additionally, you can watch your browser's network tab to see what requests are done while using the FOSSA UI, and then you can try mimicking those API calls using Postman. Once you understand a working knowledge of the endpoint, it becomes much easier to script tasks using a language like Python.
Updated 8 months ago
Continue the Journey and take a look at our API examples and expanded documentation below