Help:Public API
Публичные REST запросы
Для работы с сервером через различные приложения реализованы публичные запросы, которые не будут меняться при обновлении самого сервера. Если будут происходить значимые изменения, то запрос будет помечаться как deprecated и создаваться новый такой же запрос с пометкой /api/some/request/v2.
Получение токена
Для большинства запросов требуется JWT-токен, чтобы его получить нужно пройти аутентификацию. Это можно сделать двумя способами:
- Простой способ — POST запрос с basic auth на /api/login, который вернёт JWT-токен в body. Использование данного способа не желательно, так как он может меняться в будущем, а также не всегда правильно обрабатывает спец. символы и кириллицу в логине/пароле. Пример:
curl -X POST -u admin:admin http://svacer.example.com/api/login
- Предпочтительный способ — POST запрос на /api/public/login с передачей данных в теле запроса, как описано ниже. Пример:
curl -X POST -d '{"login": "admin", "password": "admin"}' http://svacer.example.com/api/public/login
Полученный токен надо добавлять в header всех запросов: Authorization: Bearer <token>
Базовые публичные запросы
| /api/public/login | POST | Аутентификация пользователя. Тело запроса имеет формат JSON и выглядит следующим образом:
{
"auth_type": "string",
"server": "string"
"login": "string",
"password": "string"
}
|
| /api/public/help | GET | Дополнительная информация по public REST API. Работает без авторизации |
| /api/health | GET | Проверка доступности сервера. Не требует авторизации. Возвращает статус 200 OK если сервер работает |
Описание остальных запросов смотрите в спецификации OpenAPI на вашем сервере Svacer по адресу /api/public/swagger/
Также можете посмотреть на нашем демо-сервере: https://svacer-demo.ispras.ru/api/public/swagger/
Управление контейнерами
См. Help:Public API/management/containers
Экспорт, импорт и копирование разметки
См. Markup2
Примеры использования public REST API
Получение URL загруженного снимка
Этот пример работает только с python3 и не работает при аутентификации в Svacer через LDAP.
Скачайте и распакуйте get_link.zip
Запрос:
python get_link.py --url http://svacer.example.com:8080 --user admin --password admin --project bash
Ответ:
http://svacer.example.com:8080/mode/review/project/0fd645aa-8e70-4a4f-b68b-766c4f337bf2/branch/8925df5a-7a98-4f07-bc88-ee4ea5b43813/snapshot/e3367efa-a804-4c05-9a7a-a7cb052bef1d
Примеры использования фильтров в public api
Данные фильтры служат только для ограничения вывода некоторых методов в public api. Они являются отдельной сущностью, наравне с глобальными фильтрами и пользовательскими фильтрами. Основное отличие в том, что время их жизни соответствует одному запросу, в котором они заданы.
Вспомогательные модули
В некоторых примерах API используется фильтр, с помощью которого можно ограничить вывод данных и получить более точные результаты. Для работы с этим фильтром используются следующие классы:
import requests
from requests import auth
from requests.models import HTTPBasicAuth
import json
from dataclasses import dataclass
import sys
import base64
def printerr(text):
#print in stderr and exit
print(f"{text}", file=sys.stderr, flush=True)
exit()
@dataclass
class ProjectFilter:
id: str
name: str
class ProjectFilterEncoder(json.JSONEncoder):
def default(self, o):
return o.__dict__
@dataclass
class BranchFilter:
id: str
name: str
class BranchFilterEncoder(json.JSONEncoder):
def default(self, o):
return o.__dict__
@dataclass
class SnapshotFilter:
id: str
name: str
class SnapshotFilterEncoder(json.JSONEncoder):
def default(self, o):
return o.__dict__
@dataclass
class MarkerFilter:
severity: str
file: str
checker: str
review: str
class MarkerFilterEncoder(json.JSONEncoder):
def default(self, o):
return o.__dict__
@dataclass
class Filter:
project: ProjectFilter
branch: BranchFilter
snapshot: SnapshotFilter
marker: MarkerFilter
class FilterEncoder(json.JSONEncoder):
def default(self, o):
return o.__dict__
def CreateFilterParam(filter: Filter):
jsoned = FilterEncoder().encode(filter)
b64ed = base64.b64encode(jsoned.encode("utf-8"))
return b64ed.decode("utf-8")
Принцип использования классов следующий:
- Создается экземпляр нужного класса XXXXFilter
- Создается base64 строка на основе объекта пункта 1, которая в дальнейшем передается в url запросе. Для этого используется метод CreateFilterParam()
Например. Для создания фильтра, ограничивающего множество проектов выражением darpa*, можно использовать следующие строчки кода:
f: Filter = Filter(ProjectFilter(id="", name="darpa*"), None, None, None) param = CreateFilterParam(f)
Для проекта, ветки и снимка можно указать как имя так и ID. Имя можно указать с использованием регулярного выражения. ID необходимо указать полностью.
Метод /api/public/login
Данный класс может быть использован для соединения с сервером Svacer. В данном модуле демонстрируется взаимодействие с методом /api/public/login.
import requests
class SvacerClient:
def __init__(self, host, user, password):
"""
Initialize the Svacer client
"""
self.host = host
self.user = user
self.password = password
self.token = None
self.auth_header = None
self.session = requests.Session() # Use session for connection pooling
self.set_auth_token()
def set_auth_token(self):
"""
Get authorization token using /api/public/login and setup in session
"""
try:
response = requests.post(
url=f"{self.host}/api/public/login",
json={
"login":self.user,
"password":self.password,
},
verify=False
)
response.raise_for_status() # Raise an exception for bad status codes
body = response.json()
self.token = body["token"]
self.auth_header = {'Authorization': f'Bearer {self.token}'}
# Set the authorization header in the session
self.session.headers.update(self.auth_header)
return self.token
except requests.exceptions.RequestException as e:
raise Exception(f"Failed to get authentication token: {e}")
except KeyError as e:
raise Exception(f"Token not found in response: {e}")
def post(self, endpoint, data=None, json=None, **kwargs):
"""
Make a POST request to the API
"""
if self.auth_header is None:
raise Exception("No authentication token available. Call get_auth_token() first.")
url = f"{self.host}{endpoint}"
try:
response = self.session.post(
url,
data=data,
json=json,
verify=False,
**kwargs
)
response.raise_for_status()
return response
except requests.exceptions.RequestException as e:
raise Exception(f"POST request failed: {e}")
def get(self, endpoint, params=None, **kwargs):
"""
Make a GET request to the API
"""
if self.auth_header is None:
raise Exception("No authentication token available. Call get_auth_token() first.")
url = f"{self.host}{endpoint}"
try:
response = self.session.get(
url,
params=params,
verify=False,
**kwargs
)
response.raise_for_status()
return response
except requests.exceptions.RequestException as e:
raise Exception(f"GET request failed: {e}")
Метод /api/public/projects
В данном примере выводится в формате json список проектов, имя которых соответствует регулярному выражению darpa*
from filters import *
from svacer import *
cl = SvacerClient(host="http://swarm-mgr:10142",user="admin",password="admin")
f: Filter = Filter(ProjectFilter(id="", name="darpa*"), None, None, None)
param = CreateFilterParam(f)
resp=cl.get(f"/api/public/projects?filters={param}")
print(f"Response: {resp.json()}")
Результат может быть следующим
[
{
"project":
{
"id": "019abb61-8cd3-7437-957d-aed0c87e603a",
"name": "darpa-clone",
"time": "2025-11-25T14:18:43.79526Z",
"created_by": "admin",
"created_by_id": "00000000-0000-0000-0000-000000000000"
},
"branches":
[
{
"id": "019abb61-83b1-7d80-8d23-ce849387bd6e",
"name": "master",
"time": "2025-11-25T14:18:41.457887Z",
"created_by": "admin",
"created_by_id": "00000000-0000-0000-0000-000000000000"
}
]
},
{
"project":
{
"id": "e6abca1b-23a0-4107-9120-4d8d3596030b",
"name": "darpa",
"time": "2020-04-03T04:54:13.754864Z",
"created_by": "importer",
"created_by_id": null
},
"branches":
[
{
"id": "ab179fad-c96a-498d-8407-2a3c82719385",
"name": "master",
"time": "2020-04-03T04:54:13.754864Z",
"created_by": "importer",
"created_by_id": null
}
]
}
]
Метод /api/public/projects/{project_id}/branch/{branch_id}/snapshots
С помощью данно метода можно получить список снимков указанной ветки. Пример кода для получения снимков с именем ver. 2.7.0*
from filters import *
from svacer import *
import json
def get_snapshots(pr_id, br_id):
cl = SvacerClient(host="http://swarm-mgr:10142",user="admin",password="admin")
f: Filter = Filter(None,None,SnapshotFilter(id="",name="ver. 2.7.0*"), None)
param = CreateFilterParam(f)
resp=cl.get(f"/api/public/projects/{pr_id}/branch/{br_id}/snapshots?filters={param}")
fmt = json.dumps(resp.json())
print(f"Response: {fmt}")
get_snapshots("e6abca1b-23a0-4107-9120-4d8d3596030b","ab179fad-c96a-498d-8407-2a3c82719385")
Возможный вывод команды:
[
{
"id": "4242b43a-da44-44ca-9b28-770295b98493",
"name": " ver. 2.7.1 200419 05:55",
"time": "2020-04-03T04:56:49.006218Z",
"link": "http://swarm-mgr.home:10142/mode/review/project/e6abca1b-23a0-4107-9120-4d8d3596030b/branch/ab179fad-c96a-498d-8407-2a3c82719385/snapshot/4242b43a-da44-44ca-9b28-770295b98493",
"created_by": "importer",
"created_by_id": "00000000-0000-0000-0000-000000000002",
"import_time": "2019-04-20T04:26:52Z",
"details":
{
"branch": "master",
"branchIDHint": "4d1f1413-c638-4a8b-aa4d-d9fccd8df3e9",
"buildObject": "cf43335308de8b7b3ae03735a7f738a6e9246f52",
"dxrIncluded": true,
"host":
{
"hostname": "seroshki",
"user": "sergey"
},
"id": "4242b43a-da44-44ca-9b28-770295b98493",
"importTime": "2019-04-20T04:26:52Z",
"migration-data":
{
"DXR": "ce03cd6d1bd54eac92e227d4184356a90b64b7c1",
"SOURCE_TREE": "0949114563f48d5a2df6e94816b7b1095b6c6540",
"date": "2019-04-20T04:26:52Z",
"description": " ver. 2.7.1 200419 05:55",
"id": "2af625b5faad4083be881135ad1daf6b304e4c99",
"owner": "7a831745d52244db2a4f1692f0c473e61f0f0157",
"parent_id": "0d491fde062e2795a4b38758488a47bf8481d03c",
"sourceData": "cf43335308de8b7b3ae03735a7f738a6e9246f52",
"svres": "2af625b5faad4083be881135ad1daf6b304e4c99.svres.gzip",
"type": "snapshot",
"user": "jenkins"
},
"project": "darpa",
"projectIDHint": "354c9c94-7b57-4427-8ce0-c41f1e59e6c2",
"snapshot": " ver. 2.7.1 200419 05:55",
"sourceIncluded": true
}
},
{
"id": "4f706c3a-fdac-475e-bb0a-8bdd753879ca",
"name": " ver. 2.7.1 130419 07:39",
"time": "2020-04-03T04:58:53.618464Z",
"link": "http://swarm-mgr.home:10142/mode/review/project/e6abca1b-23a0-4107-9120-4d8d3596030b/branch/ab179fad-c96a-498d-8407-2a3c82719385/snapshot/4f706c3a-fdac-475e-bb0a-8bdd753879ca",
"created_by": "importer",
"created_by_id": "00000000-0000-0000-0000-000000000002",
"import_time": "2019-04-13T04:33:46Z",
"details":
{
"branch": "master",
"branchIDHint": "c472aab7-d53f-496c-9d3d-069c0901d9bb",
"buildObject": "cf43335308de8b7b3ae03735a7f738a6e9246f52",
"dxrIncluded": false,
"host":
{
"hostname": "seroshki",
"user": "sergey"
},
"id": "4f706c3a-fdac-475e-bb0a-8bdd753879ca",
"importTime": "2019-04-13T04:33:46Z",
"migration-data":
{
"DXR": "ce03cd6d1bd54eac92e227d4184356a90b64b7c1",
"SOURCE_TREE": "0949114563f48d5a2df6e94816b7b1095b6c6540",
"date": "2019-04-13T04:33:46Z",
"description": " ver. 2.7.1 130419 07:39",
"id": "0d491fde062e2795a4b38758488a47bf8481d03c",
"owner": "7a831745d52244db2a4f1692f0c473e61f0f0157",
"parent_id": "edca1583aa41489d37ae9fb2c348ad066ecd3ab3",
"sourceData": "cf43335308de8b7b3ae03735a7f738a6e9246f52",
"svres": "0d491fde062e2795a4b38758488a47bf8481d03c.svres.gzip",
"type": "snapshot",
"user": "jenkins"
},
"project": "darpa",
"projectIDHint": "cf032d99-2efe-4ee0-8db8-ee85ff17b296",
"snapshot": " ver. 2.7.1 130419 07:39",
"sourceIncluded": false
}
}
]
Метод /api/public/projects/{project_id}/branch/{branch_id}/snapshots/{snapshot_id}/fullmarkers
Данный метод служит для получения информации о маркерах указанного снимка. Информация о маркере может включать в себя:
- трассу ошибки (параметр traces, возможные значения true,false)
- информацию о чекере (параметр checker_info, возможные значения true,false)
- историю разметки (параметр review_history, возможные значения true,false)
- история комментария (параметр comment_history, возможные значения true,false)
- идентификатор пользовательского фильтра (параметр custom_filter)
- фильтр на параметры маркера
Данный метод может требовать длительного времени выполнения для проектов с большим количеством предупреждений.
Пример кода для получения всего множества информации о маркерах, размеченных со статусом Conf*:
def get_markers (pr_id, br_id, snap_id):
cl = SvacerClient(host="http://swarm-mgr:10142",user="admin",password="admin")
f: Filter = Filter(None, None, None, MarkerFilter(severity="*",
file="*", checker="*", review="Conf*"))
param = CreateFilterParam(f)
resp=cl.get(f"/api/public/projects/{pr_id}/branch/{br_id}/snapshots/{snap_id}/fullmarkers?traces=true&checker_info=true&review_history=true&comment_history=true&filters={param}")
fmt = json.dumps(resp.json())
print(f"Response: {fmt}")
get_markers("e6abca1b-23a0-4107-9120-4d8d3596030b","ab179fad-c96a-498d-8407-2a3c82719385","250a4ff1-bfc8-439a-834d-18b62a545d8d")
Возможный вывод:
[
{
"id": "ab877a02-03ac-41ac-8b87-46f7e76791ba",
"file": "/mnt/scratch/sources/darpa-source/challenges/Divelogger2/lib/string.cc",
"function": "_ZN6StringaSERKS_",
"line": 179,
"locID": 1006,
"lang": "CXX",
"tool": "SvEng",
"warnClass": "ASSIGN_NO_CHECK_FOR_THIS",
"mtid": "SvEng.LA.4",
"msg": "Method 'operator=' doesn't check its argument with 'this' pointer.",
"details": "d96c832835f414a119ea8c7575a8926378fd7cf6",
"flags": 0,
"traces": [
{
"role": "declaration",
"locations": [
{
"file": "/mnt/scratch/sources/darpa-source/challenges/Divelogger2/lib/string.cc",
"line": 179,
"col": 0,
"spec": false,
"info": "declaration"
}
]
}
],
"checker_severity": "Normal",
"checker_reliability": "High",
"checker_origin": "builtin",
"review": {
"id": "65796",
"status": "Confirmed",
"severity": "Major",
"action": "Fix required",
"createdBy": "admin",
"created_by_id": "00000000-0000-0000-0000-000000000000",
"time": "2025-11-25T15:04:25.216816Z",
"createdFrom": "ab877a02-03ac-41ac-8b87-46f7e76791ba"
},
"review_history": [
{
"id": "65796",
"status": "Confirmed",
"severity": "Major",
"action": "Fix required",
"createdBy": "admin",
"created_by_id": "00000000-0000-0000-0000-000000000000",
"time": "2025-11-25T15:04:25.216816Z",
"createdFrom": "ab877a02-03ac-41ac-8b87-46f7e76791ba",
"createdFromContext": {
"projectID": "e6abca1b-23a0-4107-9120-4d8d3596030b",
"branchID": "ab179fad-c96a-498d-8407-2a3c82719385",
"snapshotID": "250a4ff1-bfc8-439a-834d-18b62a545d8d",
"markerID": "ab877a02-03ac-41ac-8b87-46f7e76791ba",
"projectName": "darpa",
"branchName": "master",
"snapshotName": " ver. 2.7.1 300319 07:08",
"created_by": "importer",
"created_by_id": "00000000-0000-0000-0000-000000000002",
"create_ts": "2020-04-03T04:56:40.524836Z"
}
},
{
"id": "65795",
"status": "Confirmed",
"severity": "Major",
"action": "Undecided",
"createdBy": "admin",
"created_by_id": "00000000-0000-0000-0000-000000000000",
"time": "2025-11-25T15:04:21.683963Z",
"createdFrom": "ab877a02-03ac-41ac-8b87-46f7e76791ba",
"createdFromContext": {
"projectID": "e6abca1b-23a0-4107-9120-4d8d3596030b",
"branchID": "ab179fad-c96a-498d-8407-2a3c82719385",
"snapshotID": "250a4ff1-bfc8-439a-834d-18b62a545d8d",
"markerID": "ab877a02-03ac-41ac-8b87-46f7e76791ba",
"projectName": "darpa",
"branchName": "master",
"snapshotName": " ver. 2.7.1 300319 07:08",
"created_by": "importer",
"created_by_id": "00000000-0000-0000-0000-000000000002",
"create_ts": "2020-04-03T04:56:40.524836Z"
}
},
{
"id": "63495",
"status": "Confirmed",
"severity": "Unspecified",
"action": "Undecided",
"createdBy": "reviewer",
"created_by_id": "077fdd75-b382-4008-97c4-ec6ef8732ccd",
"time": "2022-04-05T11:47:47.026161Z",
"createdFrom": "a94f92f4-4e3e-4071-9f10-aa8e4389dd0a",
"createdFromContext": {
"projectID": "e6abca1b-23a0-4107-9120-4d8d3596030b",
"branchID": "ab179fad-c96a-498d-8407-2a3c82719385",
"snapshotID": "4242b43a-da44-44ca-9b28-770295b98493",
"markerID": "a94f92f4-4e3e-4071-9f10-aa8e4389dd0a",
"projectName": "darpa",
"branchName": "master",
"snapshotName": " ver. 2.7.1 200419 05:55",
"created_by": "importer",
"created_by_id": "00000000-0000-0000-0000-000000000002",
"create_ts": "2020-04-03T04:56:49.006218Z"
},
"reviewer_attrs": ["review_master"]
}
],
"comments": [
{
"id": "e3287eb2-9e64-4780-a1c0-22ed9393a226",
"text": "aaaaaaaaa",
"type": "txt",
"ref": "ab877a02-03ac-41ac-8b87-46f7e76791ba",
"createdBy": "admin",
"created_by_id": "",
"invariant": "",
"createTs": "2025-11-25T15:04:11.358138Z",
"updateTs": "2025-11-25T15:04:17.220568Z",
"history": [
{
"id": "019abb8b-4244-7931-81f7-a7d1a4512de0",
"comment_id": "e3287eb2-9e64-4780-a1c0-22ed9393a226",
"comment_ref": "ab877a02-03ac-41ac-8b87-46f7e76791ba",
"text": "aaaa",
"created_by": "admin",
"created_by_id": "00000000-0000-0000-0000-000000000000",
"create_ts": "2025-11-25T15:04:11.358138Z"
}
]
}
],
"invariant": "1pQ3T5bq6AMYEYJqzFsW+Q"
}
]