Markup2: Difference between revisions
mNo edit summary |
m (some minor fixes) |
||
(One intermediate revision by one other user not shown) | |||
Line 1: | Line 1: | ||
== Public REST API для экспорта, импорта и копирования разметки == | == Public REST API для экспорта, импорта и копирования разметки == | ||
Релиз 10.х Svacer включает новый API предназначенный для экспорта, импорта и копирования разметки. API доступен по endpoint-ам | Релиз 10.х Svacer включает новый API, предназначенный для экспорта, импорта и копирования разметки. API доступен по endpoint-ам | ||
POST /api/public/markup/import | POST /api/public/markup/import | ||
POST /api/public/markup/export | POST /api/public/markup/export | ||
POST /api/public/markup/copy | POST /api/public/markup/copy | ||
Разметка описывается посредством protobuf схемы: | Разметка описывается посредством protobuf схемы: | ||
// Represents exported review (review itself + comments) | // Represents exported review (review itself + comments) | ||
// Review is associated with invariant and has list of locations | // Review is associated with invariant and has list of locations | ||
Line 73: | Line 75: | ||
map<string,string> properties = 6; // extra properties | map<string,string> properties = 6; // extra properties | ||
} | } | ||
Актуальную версию схемы можно получить из Svacer по API: <code>GET /api/public/markup/schema</code>. | Актуальную версию схемы можно получить из Svacer по API: <code>GET /api/public/markup/schema</code>. | ||
{{Note|type=reminder|text=При сериализации в JSON используются proto-имена полей. При работе с данными из Go рекомендуется использовать [https://pkg.go.dev/google.golang.org/protobuf/encoding/protojson protojson] для сериализации и десериализации.}} | |||
Svacer поддерживает два формата для экспортирования/импортирования разметки: | Svacer поддерживает два формата для экспортирования/импортирования разметки: | ||
* | * JSON с разделением по newline-ам. Каждая строка представляет собой объект типа '''Review''' (указано выше) сериализованный в JSON | ||
* | * Бинарный формат: последовательность блоков <code>[lenght little endian][proto]</code>, где первый блок содержит длину следующего блока в формате <code>u32 little endian</code>, а второй блок содержит proto-сериализацию объекта '''Review''' | ||
В обоих случаях при выгрузке разметки первый элемент типа | В обоих случаях при выгрузке разметки первый элемент типа '''Review''' будет содержать мета-информацию об исходном контексте, откуда была выгружена разметка. | ||
Разметка привязывается к инварианту маркера и может содержать собственно разметку (статус маркера) и совокупность комментариев, связанных с данным маркером. При выгрузке разметки | Разметка привязывается к инварианту маркера и может содержать собственно разметку (статус маркера) и совокупность комментариев, связанных с данным маркером. При выгрузке разметки также добавляется информация о конкретных локациях предупреждений, ассоциированных с инвариантом. В будущих версиях данная информация будет использоваться для переноса разметки при отсутствии прямого совпадения инвариантов. | ||
=== Экспорт разметки === | === Экспорт разметки === | ||
POST /api/public/markup/export | POST /api/public/markup/export | ||
* | * Параметры передаются в '''body''' запроса | ||
* | * Запрос должен иметь токен аутентификации | ||
* | * Пользователь должен иметь доступы на Public API и экспорт разметки из ветки, откуда производится экспорт | ||
Формат body: | Формат body: | ||
Line 102: | Line 105: | ||
"export_all": <true|false> | "export_all": <true|false> | ||
} | } | ||
Опция | * Пользователь должен указать либо '''source''' элемент, либо '''source_id''' | ||
* Опция '''skip_comments''' позволяет игнорировать комментарии при выгрузке разметки | |||
* Опция '''skip_review''' позволяет игнорировать статусы маркеров при выгрузке разметки (т. е. выгружать только комментарии) | |||
* Опция '''export_all''' позволяет выгрузить пустую разметку (т. е. статусы Undecided/Unspecified/Undecided). Это позволяет получить список всех инвариантов для ветки и использовать данные для генерации требуемой разметки для импорта | |||
* Метод возвращает gzipped файл содержащий разметку в указанном формате | |||
=== Импорт разметки === | |||
POST /api/public/markup/import | |||
* Параметры передаются в '''query''' запроса | |||
* Запрос должен быть формата '''multipart/form-data''', поле '''file''' должно содержать файл с разметкой | |||
* Запрос должен иметь токен аутентификации | |||
* Пользователь должен иметь доступы на Public API, импорт разметки/снимка, разрешения '''Update any review''' и '''Update any comment''' | |||
Query параметры: | |||
project — <project name> — имя проекта | |||
branch — <branch name> — имя бранча | |||
target_id — <branch id> — id бранча. Должно быть либо id бранча, либо имя проекта + имя бранча. Приоритет — id бранча | |||
format — <proto|json> — формат импортируемой разметки. Если не указан, будет определяться автоматически | |||
overwrite — <none|force|last> — контролирует логику применения разметки к бранчу при импорте | |||
skip_comments — <true|false> — игнорировать комментарии | |||
skip_review — <true|false> — игнорировать статус разметки (импорт только комментариев) | |||
response_with_result — <true|false> — вернуть детальный список разметок, которые были применены, в формате JSON с newline-разделителями. Если не указан, то возвращается краткий статус | |||
compressed — <true|false> — формат файла с разметкой, если true то подразумевается gzip-compressed файл | |||
В случае успеха, метод возвращает body со следующими данными | |||
{"total":<total number of loaded reviews>,"applied_reviews":<applied reviews>,"applied_comments":<applied comments>,"skipped_reviews":<skipped reviews>,"duplicate_reviews":<duplicate reviews>,"duplicate_comments":<duplicate comments} | {"total":<total number of loaded reviews>,"applied_reviews":<applied reviews>,"applied_comments":<applied comments>,"skipped_reviews":<skipped reviews>,"duplicate_reviews":<duplicate reviews>,"duplicate_comments":<duplicate comments} | ||
<json representation of applied review>* | <json representation of applied review>* | ||
Первая строка | |||
Первая строка body содержит JSON с информацией о выполненных действиях. Если был указан параметр '''response_with_result''', то дальше будут идти newline-separated JSON представления примененных review. | |||
==== Алгоритм импорта ==== | ==== Алгоритм импорта ==== | ||
* Блокируются операции по | * Блокируются операции по разметке и импорту на целевой бранч | ||
* Выгружается текущая разметка бранча с комментариями | * Выгружается текущая разметка бранча с комментариями | ||
* Загруженная разметка сопоставляется с текущей и формируется список разметки для применения. Дублирующая разметка и комментарии игнорируются | * Загруженная разметка сопоставляется с текущей и формируется список разметки для применения. Дублирующая разметка и комментарии игнорируются | ||
* Сформированный список применяется к бранчу. При выборе маркера, куда добавлять комментарий, выбирается маркер из наиболее раннего снимка, где маркер с соответствующим инвариантом появился | * Перезапись разметки контролируется параметром '''overwrite'''. Если значение '''none''', то разметка не перезаписывается при наличии разметки в целевом бранче. Если значение '''force''', то разметка будет перезаписана. Если значение '''last''', то разметка будет перезаписана, если загруженная разметка имеет более новую дату | ||
* Пустая разметка (Undecided/Unspecified/Undecided) явным образом не применяется к инварианту, если разметка отсутствует на бранче | |||
* Сформированный список применяется к бранчу. При выборе маркера, куда добавлять комментарий, выбирается маркер из наиболее раннего снимка, где маркер с соответствующим инвариантом появился | |||
'''Допустимые значения полей разметки:''' | '''Допустимые значения полей разметки:''' | ||
* Status | * Status — <code>"Confirmed", "Won't fix", "False Positive", "Unclear", "Undecided"</code> | ||
* Severity | * Severity — <code>"Unspecified", "Critical", "Major", "Minor"</code> | ||
* Action | * Action — <code>"Undecided", "Fix required", "Fix submitted", "Ignore"</code> | ||
=== Копирование разметки === | === Копирование разметки === | ||
POST /api/public/markup/copy | POST /api/public/markup/copy | ||
* | * Параметры передаются в '''body''' запроса | ||
* | * Запрос должен иметь токен аутентификации | ||
* | * Пользователь должен иметь доступы на Public API, импорт разметки/снимка, разрешения '''Update any review''' и '''Update any comment''' | ||
Формат body: | Формат body: | ||
{ | { | ||
"source": ["<project name>","<branch name>"], | "source": ["<project name>","<branch name>"], | ||
Line 166: | Line 174: | ||
"response_with_result": <true|false> | "response_with_result": <true|false> | ||
} | } | ||
В случае успеха, метод возвращает | |||
В случае успеха, метод возвращает body со следующими данными | |||
{"total":<total number of loaded reviews>,"applied_reviews":<applied reviews>,"applied_comments":<applied comments>,"skipped_reviews":<skipped reviews>,"duplicate_reviews":<duplicate reviews>,"duplicate_comments":<duplicate comments} | {"total":<total number of loaded reviews>,"applied_reviews":<applied reviews>,"applied_comments":<applied comments>,"skipped_reviews":<skipped reviews>,"duplicate_reviews":<duplicate reviews>,"duplicate_comments":<duplicate comments} | ||
<json representation of applied review>* | <json representation of applied review>* | ||
Первая строка | |||
Первая строка body содержит JSON с информацией о выполненных действиях. Если был указан параметр '''response_with_result''', то дальше будут идти newline-separated JSON представления примененных review. | |||
== CLI API для импорта/экспорта/копирования разметки == | == CLI API для импорта/экспорта/копирования разметки == | ||
Данное API является '''экспериментальным''' и может меняться. Основные аргументы будут сохранены. По умолчанию, команды под | |||
Данное API является '''экспериментальным''' и может меняться. Основные аргументы будут сохранены. По умолчанию, команды под '''markup2''' скрыты. Использовать можно, указывая их явно. Для получения помощи запустить: | |||
svacer markup2 --help | svacer markup2 --help | ||
svacer markup2 copy --help | svacer markup2 copy --help | ||
svacer markup2 import --help | svacer markup2 import --help | ||
svacer markup2 export --help | svacer markup2 export --help | ||
Описание команд: | Описание команд: | ||
NAME: | NAME: | ||
Line 204: | Line 218: | ||
--dry-run Do actions but don't commit result to database (default: false) | --dry-run Do actions but don't commit result to database (default: false) | ||
--help Show help (default: false) | --help Show help (default: false) | ||
Импорт разметки из файла | Импорт разметки из файла | ||
NAME: | NAME: | ||
Line 222: | Line 237: | ||
--format value Specify explicit format for data. If not specified, format will be detected from content | --format value Specify explicit format for data. If not specified, format will be detected from content | ||
--help Show help (default: false) | --help Show help (default: false) | ||
Экспорт разметки в файл | Экспорт разметки в файл | ||
NAME: | NAME: | ||
Line 239: | Line 255: | ||
--export-all Export empty (undecided) review (default: false) | --export-all Export empty (undecided) review (default: false) | ||
--help Show help (default: false) | --help Show help (default: false) | ||
Копирование разметки | Копирование разметки | ||
NAME: | NAME: | ||
Line 259: | Line 276: | ||
--verbose-out Include information about applied reviews (default: false) | --verbose-out Include information about applied reviews (default: false) | ||
--help Show help (default: false) | --help Show help (default: false) | ||
Примеры использования: | Примеры использования: | ||
svacer markup2 --user admin --password admin copy --overwrite=force --source-project bash --target-project bash --source-branch master --target-branch bash_clone | svacer markup2 --user admin --password admin copy --overwrite=force --source-project bash --target-project bash --source-branch master --target-branch bash_clone |
Latest revision as of 15:38, 27 November 2024
Public REST API для экспорта, импорта и копирования разметки
Релиз 10.х Svacer включает новый API, предназначенный для экспорта, импорта и копирования разметки. API доступен по endpoint-ам
POST /api/public/markup/import POST /api/public/markup/export POST /api/public/markup/copy
Разметка описывается посредством protobuf схемы:
// Represents exported review (review itself + comments) // Review is associated with invariant and has list of locations message Review { // Defines model for concrete location of the review message Location { string warnClass = 1; string file = 2; uint32 line = 3; string details = 4; string mtid = 5; string function = 10; bytes content_hash = 6; bytes trace_hash = 7; bytes marker_hash = 8; bytes line_hash = 9; string tool = 11; string lang = 12; } // Defines model for comment message Comment { string text = 1; optional string format = 2; google.protobuf.Timestamp create_ts = 3; optional google.protobuf.Timestamp update_ts = 4; string createdBy = 5; string origin_id = 6; optional uint64 review_id = 7; // refers to Review.id field optional string created_by_id = 8; } // Defines model for review itself message ReviewData { string status = 1; string severity = 2; string action = 3; string origin_id = 4; google.protobuf.Timestamp create_ts = 5; string created_by = 6; optional string created_by_id = 7; optional string created_from = 8; } // Invariant of the marker string invariant = 1; // Review information associated with markers having given invariant optional ReviewData review_data = 2; // List of comments associated with all markers having given invariant repeated Comment comments = 3; // List of locations associated with given invariant. Locations can be used to apply fuzzy matching of review with existing data when there is no invariant match repeated Location locations = 4; // Export-specific ID, comments can refer to this id if comment is associated with review operation uint64 id = 5; // Meta-information about export, when exporting to file field is initialized only for the first element optional ReviewExportMeta meta = 6; } // Defines meta-information about exported review message ReviewExportMeta { message Container { string id = 1; string name = 2; } google.protobuf.Timestamp create_ts = 1; // timestamp when export was produced (UTC) string created_by = 2; // user who triggered export string svacer_version = 3; // svacer version optional Container project = 4; // source container (project) optional Container branch = 5; // source container (branch) map<string,string> properties = 6; // extra properties }
Актуальную версию схемы можно получить из Svacer по API: GET /api/public/markup/schema
.
Svacer поддерживает два формата для экспортирования/импортирования разметки:
- JSON с разделением по newline-ам. Каждая строка представляет собой объект типа Review (указано выше) сериализованный в JSON
- Бинарный формат: последовательность блоков
[lenght little endian][proto]
, где первый блок содержит длину следующего блока в форматеu32 little endian
, а второй блок содержит proto-сериализацию объекта Review
В обоих случаях при выгрузке разметки первый элемент типа Review будет содержать мета-информацию об исходном контексте, откуда была выгружена разметка.
Разметка привязывается к инварианту маркера и может содержать собственно разметку (статус маркера) и совокупность комментариев, связанных с данным маркером. При выгрузке разметки также добавляется информация о конкретных локациях предупреждений, ассоциированных с инвариантом. В будущих версиях данная информация будет использоваться для переноса разметки при отсутствии прямого совпадения инвариантов.
Экспорт разметки
POST /api/public/markup/export
- Параметры передаются в body запроса
- Запрос должен иметь токен аутентификации
- Пользователь должен иметь доступы на Public API и экспорт разметки из ветки, откуда производится экспорт
Формат body:
{ "source": ["<project name>","<branch name>"], "source_id": "<branch id>", "skip_comments": <true|false>, "skip_review": <true|false>, "format": "<json|proto>", "export_all": <true|false> }
- Пользователь должен указать либо source элемент, либо source_id
- Опция skip_comments позволяет игнорировать комментарии при выгрузке разметки
- Опция skip_review позволяет игнорировать статусы маркеров при выгрузке разметки (т. е. выгружать только комментарии)
- Опция export_all позволяет выгрузить пустую разметку (т. е. статусы Undecided/Unspecified/Undecided). Это позволяет получить список всех инвариантов для ветки и использовать данные для генерации требуемой разметки для импорта
- Метод возвращает gzipped файл содержащий разметку в указанном формате
Импорт разметки
POST /api/public/markup/import
- Параметры передаются в query запроса
- Запрос должен быть формата multipart/form-data, поле file должно содержать файл с разметкой
- Запрос должен иметь токен аутентификации
- Пользователь должен иметь доступы на Public API, импорт разметки/снимка, разрешения Update any review и Update any comment
Query параметры:
project — <project name> — имя проекта branch — <branch name> — имя бранча target_id — <branch id> — id бранча. Должно быть либо id бранча, либо имя проекта + имя бранча. Приоритет — id бранча format — <proto|json> — формат импортируемой разметки. Если не указан, будет определяться автоматически overwrite — <none|force|last> — контролирует логику применения разметки к бранчу при импорте skip_comments — <true|false> — игнорировать комментарии skip_review — <true|false> — игнорировать статус разметки (импорт только комментариев) response_with_result — <true|false> — вернуть детальный список разметок, которые были применены, в формате JSON с newline-разделителями. Если не указан, то возвращается краткий статус compressed — <true|false> — формат файла с разметкой, если true то подразумевается gzip-compressed файл
В случае успеха, метод возвращает body со следующими данными
{"total":<total number of loaded reviews>,"applied_reviews":<applied reviews>,"applied_comments":<applied comments>,"skipped_reviews":<skipped reviews>,"duplicate_reviews":<duplicate reviews>,"duplicate_comments":<duplicate comments} <json representation of applied review>*
Первая строка body содержит JSON с информацией о выполненных действиях. Если был указан параметр response_with_result, то дальше будут идти newline-separated JSON представления примененных review.
Алгоритм импорта
- Блокируются операции по разметке и импорту на целевой бранч
- Выгружается текущая разметка бранча с комментариями
- Загруженная разметка сопоставляется с текущей и формируется список разметки для применения. Дублирующая разметка и комментарии игнорируются
- Перезапись разметки контролируется параметром overwrite. Если значение none, то разметка не перезаписывается при наличии разметки в целевом бранче. Если значение force, то разметка будет перезаписана. Если значение last, то разметка будет перезаписана, если загруженная разметка имеет более новую дату
- Пустая разметка (Undecided/Unspecified/Undecided) явным образом не применяется к инварианту, если разметка отсутствует на бранче
- Сформированный список применяется к бранчу. При выборе маркера, куда добавлять комментарий, выбирается маркер из наиболее раннего снимка, где маркер с соответствующим инвариантом появился
Допустимые значения полей разметки:
- Status —
"Confirmed", "Won't fix", "False Positive", "Unclear", "Undecided"
- Severity —
"Unspecified", "Critical", "Major", "Minor"
- Action —
"Undecided", "Fix required", "Fix submitted", "Ignore"
Копирование разметки
POST /api/public/markup/copy
- Параметры передаются в body запроса
- Запрос должен иметь токен аутентификации
- Пользователь должен иметь доступы на Public API, импорт разметки/снимка, разрешения Update any review и Update any comment
Формат body:
{ "source": ["<project name>","<branch name>"], "source_id": "<branch id>", "target": ["<project name>","<branch name>"], "target_id": "<branch id>", "skip_comments": <true|false>, "skip_review": <true|false>, "overwrite": "<none|last|force>", "response_with_result": <true|false> }
В случае успеха, метод возвращает body со следующими данными
{"total":<total number of loaded reviews>,"applied_reviews":<applied reviews>,"applied_comments":<applied comments>,"skipped_reviews":<skipped reviews>,"duplicate_reviews":<duplicate reviews>,"duplicate_comments":<duplicate comments} <json representation of applied review>*
Первая строка body содержит JSON с информацией о выполненных действиях. Если был указан параметр response_with_result, то дальше будут идти newline-separated JSON представления примененных review.
CLI API для импорта/экспорта/копирования разметки
Данное API является экспериментальным и может меняться. Основные аргументы будут сохранены. По умолчанию, команды под markup2 скрыты. Использовать можно, указывая их явно. Для получения помощи запустить:
svacer markup2 --help svacer markup2 copy --help svacer markup2 import --help svacer markup2 export --help
Описание команд:
NAME: svacer markup2 - New [experimental] API for review export/import/copy USAGE: svacer markup2 command [command options] [arguments...] COMMANDS: import Import markup from file and apply to specified branch export Export markup to file or stdout. Command needs either branch ID or project and branch name. When exporting to file, data is gzipped. copy Copy markup between branches help, h Shows a list of commands or help for one command OPTIONS: --ssl Connect to the server using https protocol (default: false) --ssl-ca-certs value Trusted CA cert path. Example: /usr/local/certs/* , /usr/local/certs/ca.crt, /usr/local/certs/ca*.crt --user value Valid user name --password value Valid user password --oidc-client value ClientID for login with OpenID Connect protocol --oidc-secret value Client's secret for login with OpenID Connect protocol --host value Valid host name with running svace history server (default: localhost) [$SVACER_HOST_NAME] --port value Defines port for REST API (default: 8080) [$SVACER_API_PORT] --grpc value Defines port for gRPC API (default: 3002) [$SVACER_GRPC_PORT] --ldap_server value Server for LDAP authentication [$SVACER_LDAP_SERVER] --conn_file value Use connection file [$SVACER_CONN_FILE] --dry-run Do actions but don't commit result to database (default: false) --help Show help (default: false)
Импорт разметки из файла
NAME: svacer markup2 import - Import markup from file and apply to specified branch USAGE: svacer markup2 import [command options] <file> - path to file to import. If file is not specified, data is loaded from stdin OPTIONS: --project value Target project name --branch value Target branch name --branch-id value Target branch ID --skip-review Import comments only (default: false) --skip-comments Import review only (default: false) --overwrite value Overwrite mode: none, force, last --out value Write information about applied reviews to given file (in json format). If not specified, result is printed to stdout --verbose-out Include information about applied reviews (default: false) --format value Specify explicit format for data. If not specified, format will be detected from content --help Show help (default: false)
Экспорт разметки в файл
NAME: svacer markup2 export - Export markup to file or stdout. Command needs either branch ID or project and branch name. When exporting to file, data is gzipped. USAGE: svacer markup2 export [command options] <file name or empty> - if no file name is specified, result is printed to stdout OPTIONS: --project value Source project name --branch value Source branch name. Branch name will be resolved against source project --branch-id value Source branch ID --skip-review Export comments only (default: false) --skip-comments Export review only (default: false) --format value Format: json or proto. If format is not specified, proto is used. If output file is not specified and format is not specified, json will be used. --uncompressed Get data in raw format without gzip compression (default: false) --export-all Export empty (undecided) review (default: false) --help Show help (default: false)
Копирование разметки
NAME: svacer markup2 copy - Copy markup between branches USAGE: svacer markup2 copy [command options] [arguments...] OPTIONS: --target-project value Target project name --target-branch value Target branch name --target-branch-id value Target branch ID --source-project value Source project name --source-branch value Source branch name --source-branch-id value Source branch ID --skip-review Copy comments only (default: false) --skip-comments Copy review only (default: false) --overwrite value Overwrite mode: none, force, last --out value Write information about applied reviews to given file (in json format). If not specified, result is printed to stdout --verbose-out Include information about applied reviews (default: false) --help Show help (default: false)
Примеры использования:
svacer markup2 --user admin --password admin copy --overwrite=force --source-project bash --target-project bash --source-branch master --target-branch bash_clone 2024-11-15T13:19:41.735+0300 info Log file location /tmp/svacer-1543671068.log 2024-11-15T13:19:41.735+0300 info Quering server configuration from http://localhost:8080/api/public/server/info 2024-11-15T13:19:41.745+0300 info Server version: [devel] {"total":771,"applied_reviews":0,"applied_comments":0,"skipped_reviews":771,"duplicate_reviews":771,"duplicate_comments":5}
svacer markup2 --user admin --password admin import --overwrite=force --project bash --branch bash_clone /tmp/out.json 2024-11-15T13:20:17.433+0300 info Log file location /tmp/svacer-1480510331.log 2024-11-15T13:20:17.433+0300 info Quering server configuration from http://localhost:8080/api/public/server/info 2024-11-15T13:20:17.435+0300 info Server version: [devel] {"total":771,"applied_reviews":0,"applied_comments":0,"skipped_reviews":771,"duplicate_reviews":771,"duplicate_comments":5}
2024-11-15T15:46:06.809+0300 info Log file location /tmp/svacer-1792255677.log 2024-11-15T15:46:06.809+0300 info Quering server configuration from http://localhost:8080/api/public/server/info 2024-11-15T15:46:06.810+0300 info Server version: [devel] {"invariant":"+1vB4JXkME3AAcbXR7tezA", "review_data":{"status":"Confirmed", "severity":"Unspecified", "action":"Undecided", "create_ts":"2024-10-16T14:44:07.233554Z", "created_by":"admin", "created_from":"1c8cea92-7708-4bb9-9a88-40325f39efe8"}, "locations":[{"warnClass":"PROC_USE.VULNERABLE", "file":"/.build/jobs.c", "line":4207, "details":"b043c5a63bf9d432c816f2cb421c907fe912bf16", "mtid":"SvEng.L.1", "function":"run_sigchld_trap", "content_hash":"s4AMYzKR8Ol8k4OODPpOlPUsSWI=", "marker_hash":"XiVQmRu8HmhzOnq1+XY7AaujT+o=", "tool":"SvEng", "lang":"C_Cpp"}], "id":"699", "meta":{"create_ts":"2024-11-15T12:46:06.835078490Z", "created_by":"admin", "svacer_version":"devel.2024-11-15@15:45:34.a290bc7e", "project":{"id":"0fd645aa-8e70-4a4f-b68b-766c4f337bf2", "name":"bash"}, "branch":{"id":"8925df5a-7a98-4f07-bc88-ee4ea5b43813", "name":"master"}}}