Rename Concelier Source modules to Connector
This commit is contained in:
@@ -0,0 +1,118 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vulnerabilities>
|
||||
<vul>
|
||||
<identifier>BDU:2025-00001</identifier>
|
||||
<name>Множественные уязвимости криптопровайдера</name>
|
||||
<description>Удалённый злоумышленник может вызвать отказ в обслуживании или получить доступ к данным.</description>
|
||||
<solution>Установить обновление 8.2.19.116 защищённого комплекса.</solution>
|
||||
<identify_date>01.12.2013</identify_date>
|
||||
<severity>Высокий уровень опасности (базовая оценка CVSS 2.0 составляет 7,5)</severity>
|
||||
<exploit_status>Существует в открытом доступе</exploit_status>
|
||||
<fix_status>Уязвимость устранена</fix_status>
|
||||
<vul_status>Подтверждена производителем</vul_status>
|
||||
<vul_incident>0</vul_incident>
|
||||
<cvss>
|
||||
<vector score="7.5">AV:N/AC:L/Au:N/C:P/I:P/A:P</vector>
|
||||
</cvss>
|
||||
<cvss3>
|
||||
<vector score="9.8">AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H</vector>
|
||||
</cvss3>
|
||||
<vulnerable_software>
|
||||
<soft>
|
||||
<vendor>ООО «1С-Софт»</vendor>
|
||||
<name>1С:Предприятие</name>
|
||||
<version>8.2.18.96</version>
|
||||
<platform>Windows</platform>
|
||||
<types>
|
||||
<type>Прикладное ПО информационных систем</type>
|
||||
</types>
|
||||
</soft>
|
||||
<soft>
|
||||
<vendor>ООО «1С-Софт»</vendor>
|
||||
<name>1С:Предприятие</name>
|
||||
<version>8.2.19.116</version>
|
||||
<platform>Не указана</platform>
|
||||
<types>
|
||||
<type>Прикладное ПО информационных систем</type>
|
||||
</types>
|
||||
</soft>
|
||||
</vulnerable_software>
|
||||
<environment>
|
||||
<os>
|
||||
<vendor>Microsoft Corp</vendor>
|
||||
<name>Windows</name>
|
||||
<version>-</version>
|
||||
<platform>64-bit</platform>
|
||||
</os>
|
||||
<os>
|
||||
<vendor>Microsoft Corp</vendor>
|
||||
<name>Windows</name>
|
||||
<version>-</version>
|
||||
<platform>32-bit</platform>
|
||||
</os>
|
||||
</environment>
|
||||
<cwes>
|
||||
<cwe>
|
||||
<identifier>CWE-310</identifier>
|
||||
<name>Проблемы использования криптографии</name>
|
||||
</cwe>
|
||||
</cwes>
|
||||
<sources>
|
||||
https://advisories.example/BDU-2025-00001
|
||||
http://mirror.example/ru-bdu/BDU-2025-00001
|
||||
</sources>
|
||||
<identifiers>
|
||||
<identifier type="CVE" link="https://nvd.nist.gov/vuln/detail/CVE-2015-0206">CVE-2015-0206</identifier>
|
||||
<identifier type="CVE" link="https://nvd.nist.gov/vuln/detail/CVE-2009-3555">CVE-2009-3555</identifier>
|
||||
<identifier type="Positive Technologies Advisory" link="https://ptsecurity.com/PT-2015-0206">PT-2015-0206</identifier>
|
||||
</identifiers>
|
||||
<other>Язык разработки ПО – С</other>
|
||||
<vul_class>Уязвимость кода</vul_class>
|
||||
<vul_state>Опубликована</vul_state>
|
||||
</vul>
|
||||
<vul>
|
||||
<identifier>BDU:2025-00002</identifier>
|
||||
<name>Уязвимость контроллера АСУ ТП</name>
|
||||
<description>Локальный злоумышленник может повысить привилегии в контроллере.</description>
|
||||
<solution>Производитель готовит обновление микропрограммы.</solution>
|
||||
<identify_date>15.10.2024</identify_date>
|
||||
<severity>Средний уровень опасности</severity>
|
||||
<exploit_status>Данные уточняются</exploit_status>
|
||||
<fix_status>Информация об устранении отсутствует</fix_status>
|
||||
<vul_status>Потенциальная уязвимость</vul_status>
|
||||
<vul_incident>2</vul_incident>
|
||||
<cvss>
|
||||
<vector score="6.5">AV:L/AC:H/Au:S/C:P/I:P/A:P</vector>
|
||||
</cvss>
|
||||
<vulnerable_software>
|
||||
<soft>
|
||||
<vendor>АО «Системы Управления»</vendor>
|
||||
<name>SCADA Controller</name>
|
||||
<version>1.0.0;1.0.1</version>
|
||||
<platform>-</platform>
|
||||
<types>
|
||||
<type>ПО программно-аппаратного средства АСУ ТП</type>
|
||||
</types>
|
||||
</soft>
|
||||
</vulnerable_software>
|
||||
<cwes>
|
||||
<cwe>
|
||||
<identifier>CWE-269</identifier>
|
||||
<name>Неправильное управление привилегиями</name>
|
||||
</cwe>
|
||||
<cwe>
|
||||
<identifier>CWE-287</identifier>
|
||||
<name>Недостаточная аутентификация</name>
|
||||
</cwe>
|
||||
</cwes>
|
||||
<sources>
|
||||
www.vendor.example/security/advisories/ctl-2025-01
|
||||
</sources>
|
||||
<identifiers>
|
||||
<identifier type="ICSA" link="https://www.cisa.gov/news-events/ics-advisories/icsa-25-123-01">ICSA-25-123-01</identifier>
|
||||
</identifiers>
|
||||
<other>Поставщик сообщает об ограниченном наличии эксплойтов.</other>
|
||||
<vul_class>Уязвимость архитектуры</vul_class>
|
||||
<vul_state>Опубликована</vul_state>
|
||||
</vul>
|
||||
</vulnerabilities>
|
||||
@@ -0,0 +1,335 @@
|
||||
[
|
||||
{
|
||||
"advisoryKey": "BDU:2025-00001",
|
||||
"affectedPackages": [
|
||||
{
|
||||
"type": "vendor",
|
||||
"identifier": "ООО «1С-Софт» 1С:Предприятие",
|
||||
"platform": null,
|
||||
"versionRanges": [
|
||||
{
|
||||
"fixedVersion": null,
|
||||
"introducedVersion": null,
|
||||
"lastAffectedVersion": null,
|
||||
"primitives": null,
|
||||
"provenance": {
|
||||
"source": "ru-bdu",
|
||||
"kind": "package-range",
|
||||
"value": "8.2.19.116",
|
||||
"decisionReason": null,
|
||||
"recordedAt": "2025-10-14T08:00:00+00:00",
|
||||
"fieldMask": [
|
||||
"affectedpackages[].versionranges[]"
|
||||
]
|
||||
},
|
||||
"rangeExpression": "8.2.19.116",
|
||||
"rangeKind": "string"
|
||||
}
|
||||
],
|
||||
"normalizedVersions": [
|
||||
{
|
||||
"scheme": "ru-bdu.raw",
|
||||
"type": "exact",
|
||||
"min": null,
|
||||
"minInclusive": null,
|
||||
"max": null,
|
||||
"maxInclusive": null,
|
||||
"value": "8.2.19.116",
|
||||
"notes": null
|
||||
}
|
||||
],
|
||||
"statuses": [
|
||||
{
|
||||
"provenance": {
|
||||
"source": "ru-bdu",
|
||||
"kind": "package-status",
|
||||
"value": "Подтверждена производителем",
|
||||
"decisionReason": null,
|
||||
"recordedAt": "2025-10-14T08:00:00+00:00",
|
||||
"fieldMask": [
|
||||
"affectedpackages[].statuses[]"
|
||||
]
|
||||
},
|
||||
"status": "affected"
|
||||
},
|
||||
{
|
||||
"provenance": {
|
||||
"source": "ru-bdu",
|
||||
"kind": "package-fix-status",
|
||||
"value": "Уязвимость устранена",
|
||||
"decisionReason": null,
|
||||
"recordedAt": "2025-10-14T08:00:00+00:00",
|
||||
"fieldMask": [
|
||||
"affectedpackages[].statuses[]"
|
||||
]
|
||||
},
|
||||
"status": "fixed"
|
||||
}
|
||||
],
|
||||
"provenance": [
|
||||
{
|
||||
"source": "ru-bdu",
|
||||
"kind": "package",
|
||||
"value": "ООО «1С-Софт» 1С:Предприятие",
|
||||
"decisionReason": null,
|
||||
"recordedAt": "2025-10-14T08:00:00+00:00",
|
||||
"fieldMask": [
|
||||
"affectedpackages[]"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "vendor",
|
||||
"identifier": "ООО «1С-Софт» 1С:Предприятие",
|
||||
"platform": "Windows",
|
||||
"versionRanges": [
|
||||
{
|
||||
"fixedVersion": null,
|
||||
"introducedVersion": null,
|
||||
"lastAffectedVersion": null,
|
||||
"primitives": null,
|
||||
"provenance": {
|
||||
"source": "ru-bdu",
|
||||
"kind": "package-range",
|
||||
"value": "8.2.18.96",
|
||||
"decisionReason": null,
|
||||
"recordedAt": "2025-10-14T08:00:00+00:00",
|
||||
"fieldMask": [
|
||||
"affectedpackages[].versionranges[]"
|
||||
]
|
||||
},
|
||||
"rangeExpression": "8.2.18.96",
|
||||
"rangeKind": "string"
|
||||
}
|
||||
],
|
||||
"normalizedVersions": [
|
||||
{
|
||||
"scheme": "ru-bdu.raw",
|
||||
"type": "exact",
|
||||
"min": null,
|
||||
"minInclusive": null,
|
||||
"max": null,
|
||||
"maxInclusive": null,
|
||||
"value": "8.2.18.96",
|
||||
"notes": null
|
||||
}
|
||||
],
|
||||
"statuses": [
|
||||
{
|
||||
"provenance": {
|
||||
"source": "ru-bdu",
|
||||
"kind": "package-status",
|
||||
"value": "Подтверждена производителем",
|
||||
"decisionReason": null,
|
||||
"recordedAt": "2025-10-14T08:00:00+00:00",
|
||||
"fieldMask": [
|
||||
"affectedpackages[].statuses[]"
|
||||
]
|
||||
},
|
||||
"status": "affected"
|
||||
},
|
||||
{
|
||||
"provenance": {
|
||||
"source": "ru-bdu",
|
||||
"kind": "package-fix-status",
|
||||
"value": "Уязвимость устранена",
|
||||
"decisionReason": null,
|
||||
"recordedAt": "2025-10-14T08:00:00+00:00",
|
||||
"fieldMask": [
|
||||
"affectedpackages[].statuses[]"
|
||||
]
|
||||
},
|
||||
"status": "fixed"
|
||||
}
|
||||
],
|
||||
"provenance": [
|
||||
{
|
||||
"source": "ru-bdu",
|
||||
"kind": "package",
|
||||
"value": "ООО «1С-Софт» 1С:Предприятие",
|
||||
"decisionReason": null,
|
||||
"recordedAt": "2025-10-14T08:00:00+00:00",
|
||||
"fieldMask": [
|
||||
"affectedpackages[]"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"aliases": [
|
||||
"BDU:2025-00001",
|
||||
"CVE-2009-3555",
|
||||
"CVE-2015-0206",
|
||||
"PT-2015-0206"
|
||||
],
|
||||
"credits": [],
|
||||
"cvssMetrics": [
|
||||
{
|
||||
"baseScore": 7.5,
|
||||
"baseSeverity": "high",
|
||||
"provenance": {
|
||||
"source": "ru-bdu",
|
||||
"kind": "cvss",
|
||||
"value": "CVSS:2.0/AV:N/AC:L/AU:N/C:P/I:P/A:P",
|
||||
"decisionReason": null,
|
||||
"recordedAt": "2025-10-14T08:00:00+00:00",
|
||||
"fieldMask": [
|
||||
"cvssmetrics[]"
|
||||
]
|
||||
},
|
||||
"vector": "CVSS:2.0/AV:N/AC:L/AU:N/C:P/I:P/A:P",
|
||||
"version": "2.0"
|
||||
},
|
||||
{
|
||||
"baseScore": 9.8,
|
||||
"baseSeverity": "critical",
|
||||
"provenance": {
|
||||
"source": "ru-bdu",
|
||||
"kind": "cvss",
|
||||
"value": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
|
||||
"decisionReason": null,
|
||||
"recordedAt": "2025-10-14T08:00:00+00:00",
|
||||
"fieldMask": [
|
||||
"cvssmetrics[]"
|
||||
]
|
||||
},
|
||||
"vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
|
||||
"version": "3.1"
|
||||
}
|
||||
],
|
||||
"exploitKnown": true,
|
||||
"language": "ru",
|
||||
"modified": "2013-01-12T00:00:00+00:00",
|
||||
"provenance": [
|
||||
{
|
||||
"source": "ru-bdu",
|
||||
"kind": "advisory",
|
||||
"value": "BDU:2025-00001",
|
||||
"decisionReason": null,
|
||||
"recordedAt": "2025-10-14T08:00:00+00:00",
|
||||
"fieldMask": [
|
||||
"advisory"
|
||||
]
|
||||
}
|
||||
],
|
||||
"published": "2013-01-12T00:00:00+00:00",
|
||||
"references": [
|
||||
{
|
||||
"kind": "source",
|
||||
"provenance": {
|
||||
"source": "ru-bdu",
|
||||
"kind": "reference",
|
||||
"value": "http://mirror.example/ru-bdu/BDU-2025-00001",
|
||||
"decisionReason": null,
|
||||
"recordedAt": "2025-10-14T08:00:00+00:00",
|
||||
"fieldMask": [
|
||||
"references[]"
|
||||
]
|
||||
},
|
||||
"sourceTag": "ru-bdu",
|
||||
"summary": null,
|
||||
"url": "http://mirror.example/ru-bdu/BDU-2025-00001"
|
||||
},
|
||||
{
|
||||
"kind": "source",
|
||||
"provenance": {
|
||||
"source": "ru-bdu",
|
||||
"kind": "reference",
|
||||
"value": "https://advisories.example/BDU-2025-00001",
|
||||
"decisionReason": null,
|
||||
"recordedAt": "2025-10-14T08:00:00+00:00",
|
||||
"fieldMask": [
|
||||
"references[]"
|
||||
]
|
||||
},
|
||||
"sourceTag": "ru-bdu",
|
||||
"summary": null,
|
||||
"url": "https://advisories.example/BDU-2025-00001"
|
||||
},
|
||||
{
|
||||
"kind": "details",
|
||||
"provenance": {
|
||||
"source": "ru-bdu",
|
||||
"kind": "reference",
|
||||
"value": "https://bdu.fstec.ru/vul/2025-00001",
|
||||
"decisionReason": null,
|
||||
"recordedAt": "2025-10-14T08:00:00+00:00",
|
||||
"fieldMask": [
|
||||
"references[]"
|
||||
]
|
||||
},
|
||||
"sourceTag": "ru-bdu",
|
||||
"summary": null,
|
||||
"url": "https://bdu.fstec.ru/vul/2025-00001"
|
||||
},
|
||||
{
|
||||
"kind": "cwe",
|
||||
"provenance": {
|
||||
"source": "ru-bdu",
|
||||
"kind": "reference",
|
||||
"value": "https://cwe.mitre.org/data/definitions/310.html",
|
||||
"decisionReason": null,
|
||||
"recordedAt": "2025-10-14T08:00:00+00:00",
|
||||
"fieldMask": [
|
||||
"references[]"
|
||||
]
|
||||
},
|
||||
"sourceTag": "cwe",
|
||||
"summary": "Проблемы использования криптографии",
|
||||
"url": "https://cwe.mitre.org/data/definitions/310.html"
|
||||
},
|
||||
{
|
||||
"kind": "cve",
|
||||
"provenance": {
|
||||
"source": "ru-bdu",
|
||||
"kind": "reference",
|
||||
"value": "https://nvd.nist.gov/vuln/detail/CVE-2009-3555",
|
||||
"decisionReason": null,
|
||||
"recordedAt": "2025-10-14T08:00:00+00:00",
|
||||
"fieldMask": [
|
||||
"references[]"
|
||||
]
|
||||
},
|
||||
"sourceTag": "cve",
|
||||
"summary": "CVE-2009-3555",
|
||||
"url": "https://nvd.nist.gov/vuln/detail/CVE-2009-3555"
|
||||
},
|
||||
{
|
||||
"kind": "cve",
|
||||
"provenance": {
|
||||
"source": "ru-bdu",
|
||||
"kind": "reference",
|
||||
"value": "https://nvd.nist.gov/vuln/detail/CVE-2015-0206",
|
||||
"decisionReason": null,
|
||||
"recordedAt": "2025-10-14T08:00:00+00:00",
|
||||
"fieldMask": [
|
||||
"references[]"
|
||||
]
|
||||
},
|
||||
"sourceTag": "cve",
|
||||
"summary": "CVE-2015-0206",
|
||||
"url": "https://nvd.nist.gov/vuln/detail/CVE-2015-0206"
|
||||
},
|
||||
{
|
||||
"kind": "external",
|
||||
"provenance": {
|
||||
"source": "ru-bdu",
|
||||
"kind": "reference",
|
||||
"value": "https://ptsecurity.com/PT-2015-0206",
|
||||
"decisionReason": null,
|
||||
"recordedAt": "2025-10-14T08:00:00+00:00",
|
||||
"fieldMask": [
|
||||
"references[]"
|
||||
]
|
||||
},
|
||||
"sourceTag": "positivetechnologiesadvisory",
|
||||
"summary": "PT-2015-0206",
|
||||
"url": "https://ptsecurity.com/PT-2015-0206"
|
||||
}
|
||||
],
|
||||
"severity": "critical",
|
||||
"summary": "Удалённый злоумышленник может вызвать отказ в обслуживании или получить доступ к данным.",
|
||||
"title": "Множественные уязвимости криптопровайдера"
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,11 @@
|
||||
[
|
||||
{
|
||||
"metadata": {
|
||||
"ru-bdu.identifier": "BDU:2025-00001",
|
||||
"ru-bdu.name": "Множественные уязвимости криптопровайдера"
|
||||
},
|
||||
"sha256": "c43df9c4a75a74b281ff09122bb8f63096a0a73b30df74d73c3bc997019bd4d4",
|
||||
"status": "mapped",
|
||||
"uri": "https://bdu.fstec.ru/vul/2025-00001"
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,86 @@
|
||||
[
|
||||
{
|
||||
"documentUri": "https://bdu.fstec.ru/vul/2025-00001",
|
||||
"payload": {
|
||||
"identifier": "BDU:2025-00001",
|
||||
"name": "Множественные уязвимости криптопровайдера",
|
||||
"description": "Удалённый злоумышленник может вызвать отказ в обслуживании или получить доступ к данным.",
|
||||
"solution": "Установить обновление 8.2.19.116 защищённого комплекса.",
|
||||
"identifyDate": "2013-01-12T00:00:00+00:00",
|
||||
"severityText": "Высокий уровень опасности (базовая оценка CVSS 2.0 составляет 7,5)",
|
||||
"cvssVector": "AV:N/AC:L/Au:N/C:P/I:P/A:P",
|
||||
"cvssScore": 7.5,
|
||||
"cvss3Vector": "AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
|
||||
"cvss3Score": 9.8,
|
||||
"exploitStatus": "Существует в открытом доступе",
|
||||
"incidentCount": 0,
|
||||
"fixStatus": "Уязвимость устранена",
|
||||
"vulStatus": "Подтверждена производителем",
|
||||
"vulClass": "Уязвимость кода",
|
||||
"vulState": "Опубликована",
|
||||
"other": "Язык разработки ПО – С",
|
||||
"software": [
|
||||
{
|
||||
"vendor": "ООО «1С-Софт»",
|
||||
"name": "1С:Предприятие",
|
||||
"version": "8.2.18.96",
|
||||
"platform": "Windows",
|
||||
"types": [
|
||||
"Прикладное ПО информационных систем"
|
||||
]
|
||||
},
|
||||
{
|
||||
"vendor": "ООО «1С-Софт»",
|
||||
"name": "1С:Предприятие",
|
||||
"version": "8.2.19.116",
|
||||
"platform": "Не указана",
|
||||
"types": [
|
||||
"Прикладное ПО информационных систем"
|
||||
]
|
||||
}
|
||||
],
|
||||
"environment": [
|
||||
{
|
||||
"vendor": "Microsoft Corp",
|
||||
"name": "Windows",
|
||||
"version": "-",
|
||||
"platform": "64-bit"
|
||||
},
|
||||
{
|
||||
"vendor": "Microsoft Corp",
|
||||
"name": "Windows",
|
||||
"version": "-",
|
||||
"platform": "32-bit"
|
||||
}
|
||||
],
|
||||
"cwes": [
|
||||
{
|
||||
"identifier": "CWE-310",
|
||||
"name": "Проблемы использования криптографии"
|
||||
}
|
||||
],
|
||||
"sources": [
|
||||
"https://advisories.example/BDU-2025-00001",
|
||||
"http://mirror.example/ru-bdu/BDU-2025-00001"
|
||||
],
|
||||
"identifiers": [
|
||||
{
|
||||
"type": "CVE",
|
||||
"value": "CVE-2015-0206",
|
||||
"link": "https://nvd.nist.gov/vuln/detail/CVE-2015-0206"
|
||||
},
|
||||
{
|
||||
"type": "CVE",
|
||||
"value": "CVE-2009-3555",
|
||||
"link": "https://nvd.nist.gov/vuln/detail/CVE-2009-3555"
|
||||
},
|
||||
{
|
||||
"type": "Positive Technologies Advisory",
|
||||
"value": "PT-2015-0206",
|
||||
"link": "https://ptsecurity.com/PT-2015-0206"
|
||||
}
|
||||
]
|
||||
},
|
||||
"schemaVersion": "ru-bdu.v1"
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,11 @@
|
||||
[
|
||||
{
|
||||
"headers": {
|
||||
"accept": "application/zip,application/octet-stream,application/x-zip-compressed",
|
||||
"accept-Language": "ru-RU,ru; q=0.9,en-US; q=0.6,en; q=0.4",
|
||||
"user-Agent": "StellaOps/Concelier,(+https://stella-ops.org)"
|
||||
},
|
||||
"method": "GET",
|
||||
"uri": "https://bdu.fstec.ru/files/documents/vulxml.zip"
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"lastSuccessfulFetch": "2025-10-14T08:00:00.0000000+00:00",
|
||||
"pendingDocuments": [],
|
||||
"pendingMappings": []
|
||||
}
|
||||
@@ -0,0 +1,303 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Http;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
using MongoDB.Bson;
|
||||
using MongoDB.Bson.Serialization;
|
||||
using MongoDB.Driver;
|
||||
using StellaOps.Concelier.Models;
|
||||
using StellaOps.Concelier.Connector.Common.Testing;
|
||||
using StellaOps.Concelier.Connector.Ru.Bdu;
|
||||
using StellaOps.Concelier.Connector.Ru.Bdu.Configuration;
|
||||
using StellaOps.Concelier.Connector.Ru.Bdu.Internal;
|
||||
using StellaOps.Concelier.Storage.Mongo;
|
||||
using StellaOps.Concelier.Storage.Mongo.Advisories;
|
||||
using StellaOps.Concelier.Storage.Mongo.Documents;
|
||||
using StellaOps.Concelier.Storage.Mongo.Dtos;
|
||||
using StellaOps.Concelier.Testing;
|
||||
using Xunit;
|
||||
using Xunit.Sdk;
|
||||
|
||||
namespace StellaOps.Concelier.Connector.Ru.Bdu.Tests;
|
||||
|
||||
[Collection("mongo-fixture")]
|
||||
public sealed class RuBduConnectorSnapshotTests : IAsyncLifetime
|
||||
{
|
||||
private const string UpdateFixturesVariable = "UPDATE_BDU_FIXTURES";
|
||||
private static readonly Uri ArchiveUri = new("https://bdu.fstec.ru/files/documents/vulxml.zip");
|
||||
|
||||
private readonly MongoIntegrationFixture _fixture;
|
||||
private ConnectorTestHarness? _harness;
|
||||
|
||||
public RuBduConnectorSnapshotTests(MongoIntegrationFixture fixture)
|
||||
{
|
||||
_fixture = fixture;
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task FetchParseMap_ProducesDeterministicSnapshots()
|
||||
{
|
||||
var harness = await EnsureHarnessAsync();
|
||||
harness.Handler.AddResponse(ArchiveUri, BuildArchiveResponse);
|
||||
|
||||
var connector = harness.ServiceProvider.GetRequiredService<RuBduConnector>();
|
||||
await connector.FetchAsync(harness.ServiceProvider, CancellationToken.None);
|
||||
|
||||
var stateRepository = harness.ServiceProvider.GetRequiredService<ISourceStateRepository>();
|
||||
var initialState = await stateRepository.TryGetAsync(RuBduConnectorPlugin.SourceName, CancellationToken.None);
|
||||
Assert.NotNull(initialState);
|
||||
var cursorBeforeParse = initialState!.Cursor is null ? RuBduCursor.Empty : RuBduCursor.FromBson(initialState.Cursor);
|
||||
Assert.NotEmpty(cursorBeforeParse.PendingDocuments);
|
||||
var expectedDocumentIds = cursorBeforeParse.PendingDocuments.ToArray();
|
||||
|
||||
await connector.ParseAsync(harness.ServiceProvider, CancellationToken.None);
|
||||
await connector.MapAsync(harness.ServiceProvider, CancellationToken.None);
|
||||
|
||||
var documentsCollection = _fixture.Database.GetCollection<BsonDocument>(MongoStorageDefaults.Collections.Document);
|
||||
var documentCount = await documentsCollection.CountDocumentsAsync(Builders<BsonDocument>.Filter.Empty);
|
||||
Assert.True(documentCount > 0, "Expected persisted documents after map stage");
|
||||
|
||||
var documentsSnapshot = await BuildDocumentsSnapshotAsync(harness.ServiceProvider, expectedDocumentIds);
|
||||
WriteOrAssertSnapshot(documentsSnapshot, "ru-bdu-documents.snapshot.json");
|
||||
|
||||
var dtoSnapshot = await BuildDtoSnapshotAsync(harness.ServiceProvider);
|
||||
WriteOrAssertSnapshot(dtoSnapshot, "ru-bdu-dtos.snapshot.json");
|
||||
|
||||
var advisoriesSnapshot = await BuildAdvisoriesSnapshotAsync(harness.ServiceProvider);
|
||||
WriteOrAssertSnapshot(advisoriesSnapshot, "ru-bdu-advisories.snapshot.json");
|
||||
|
||||
var stateSnapshot = await BuildStateSnapshotAsync(harness.ServiceProvider);
|
||||
WriteOrAssertSnapshot(stateSnapshot, "ru-bdu-state.snapshot.json");
|
||||
|
||||
var requestsSnapshot = BuildRequestsSnapshot(harness.Handler.Requests);
|
||||
WriteOrAssertSnapshot(requestsSnapshot, "ru-bdu-requests.snapshot.json");
|
||||
|
||||
harness.Handler.AssertNoPendingResponses();
|
||||
}
|
||||
|
||||
public Task InitializeAsync() => Task.CompletedTask;
|
||||
|
||||
public async Task DisposeAsync()
|
||||
{
|
||||
if (_harness is not null)
|
||||
{
|
||||
await _harness.DisposeAsync();
|
||||
_harness = null;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<ConnectorTestHarness> EnsureHarnessAsync()
|
||||
{
|
||||
if (_harness is not null)
|
||||
{
|
||||
return _harness;
|
||||
}
|
||||
|
||||
var initialTime = new DateTimeOffset(2025, 10, 14, 8, 0, 0, TimeSpan.Zero);
|
||||
var harness = new ConnectorTestHarness(_fixture, initialTime, RuBduOptions.HttpClientName);
|
||||
await harness.EnsureServiceProviderAsync(services =>
|
||||
{
|
||||
services.AddLogging(builder =>
|
||||
{
|
||||
builder.ClearProviders();
|
||||
builder.AddProvider(NullLoggerProvider.Instance);
|
||||
});
|
||||
|
||||
services.AddRuBduConnector(options =>
|
||||
{
|
||||
options.BaseAddress = new Uri("https://bdu.fstec.ru/");
|
||||
options.DataArchivePath = "files/documents/vulxml.zip";
|
||||
options.MaxVulnerabilitiesPerFetch = 25;
|
||||
options.RequestTimeout = TimeSpan.FromSeconds(30);
|
||||
var cacheRoot = Path.Combine(Path.GetTempPath(), "stellaops-tests", _fixture.Database.DatabaseNamespace.DatabaseName, "ru-bdu");
|
||||
Directory.CreateDirectory(cacheRoot);
|
||||
options.CacheDirectory = cacheRoot;
|
||||
});
|
||||
|
||||
services.Configure<HttpClientFactoryOptions>(RuBduOptions.HttpClientName, options =>
|
||||
{
|
||||
options.HttpMessageHandlerBuilderActions.Add(builder => builder.PrimaryHandler = harness.Handler);
|
||||
});
|
||||
});
|
||||
|
||||
_harness = harness;
|
||||
return harness;
|
||||
}
|
||||
|
||||
private static HttpResponseMessage BuildArchiveResponse()
|
||||
{
|
||||
var archiveBytes = CreateArchiveBytes();
|
||||
var response = new HttpResponseMessage(HttpStatusCode.OK)
|
||||
{
|
||||
Content = new ByteArrayContent(archiveBytes),
|
||||
};
|
||||
response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/zip");
|
||||
response.Content.Headers.LastModified = new DateTimeOffset(2025, 10, 14, 9, 30, 0, TimeSpan.Zero);
|
||||
response.Content.Headers.ContentLength = archiveBytes.Length;
|
||||
return response;
|
||||
}
|
||||
|
||||
private async Task<string> BuildDocumentsSnapshotAsync(IServiceProvider provider, IReadOnlyCollection<Guid> documentIds)
|
||||
{
|
||||
var documentStore = provider.GetRequiredService<IDocumentStore>();
|
||||
var records = new List<object>(documentIds.Count);
|
||||
|
||||
foreach (var documentId in documentIds)
|
||||
{
|
||||
var record = await documentStore.FindAsync(documentId, CancellationToken.None);
|
||||
if (record is null)
|
||||
{
|
||||
var existing = await _fixture.Database
|
||||
.GetCollection<BsonDocument>("documents")
|
||||
.Find(Builders<BsonDocument>.Filter.Empty)
|
||||
.Project(Builders<BsonDocument>.Projection.Include("Uri"))
|
||||
.ToListAsync(CancellationToken.None);
|
||||
var uris = existing
|
||||
.Select(document => document.GetValue("Uri", BsonValue.Create(string.Empty)).AsString)
|
||||
.ToArray();
|
||||
throw new XunitException($"Document id not found: {documentId}. Known URIs: {string.Join(", ", uris)}");
|
||||
}
|
||||
|
||||
records.Add(new
|
||||
{
|
||||
record.Uri,
|
||||
record.Status,
|
||||
record.Sha256,
|
||||
Metadata = record.Metadata is null
|
||||
? null
|
||||
: record.Metadata
|
||||
.OrderBy(static pair => pair.Key, StringComparer.OrdinalIgnoreCase)
|
||||
.ToDictionary(static pair => pair.Key, static pair => pair.Value, StringComparer.OrdinalIgnoreCase)
|
||||
});
|
||||
}
|
||||
|
||||
var ordered = records
|
||||
.OrderBy(static entry => entry?.GetType().GetProperty("Uri")?.GetValue(entry)?.ToString(), StringComparer.Ordinal)
|
||||
.ToArray();
|
||||
|
||||
return SnapshotSerializer.ToSnapshot(ordered);
|
||||
}
|
||||
|
||||
private async Task<string> BuildDtoSnapshotAsync(IServiceProvider provider)
|
||||
{
|
||||
var dtoStore = provider.GetRequiredService<IDtoStore>();
|
||||
var documentStore = provider.GetRequiredService<IDocumentStore>();
|
||||
var records = await dtoStore.GetBySourceAsync(RuBduConnectorPlugin.SourceName, 25, CancellationToken.None);
|
||||
|
||||
var entries = new List<object>(records.Count);
|
||||
foreach (var record in records.OrderBy(static r => r.DocumentId))
|
||||
{
|
||||
var document = await documentStore.FindAsync(record.DocumentId, CancellationToken.None);
|
||||
Assert.NotNull(document);
|
||||
|
||||
var payload = BsonTypeMapper.MapToDotNetValue(record.Payload);
|
||||
entries.Add(new
|
||||
{
|
||||
DocumentUri = document!.Uri,
|
||||
record.SchemaVersion,
|
||||
Payload = payload,
|
||||
});
|
||||
}
|
||||
|
||||
return SnapshotSerializer.ToSnapshot(entries.OrderBy(static entry => entry.GetType().GetProperty("DocumentUri")!.GetValue(entry)?.ToString(), StringComparer.Ordinal).ToArray());
|
||||
}
|
||||
|
||||
private async Task<string> BuildAdvisoriesSnapshotAsync(IServiceProvider provider)
|
||||
{
|
||||
var advisoryStore = provider.GetRequiredService<IAdvisoryStore>();
|
||||
var advisories = await advisoryStore.GetRecentAsync(25, CancellationToken.None);
|
||||
var ordered = advisories
|
||||
.OrderBy(static advisory => advisory.AdvisoryKey, StringComparer.Ordinal)
|
||||
.ToArray();
|
||||
return SnapshotSerializer.ToSnapshot(ordered);
|
||||
}
|
||||
|
||||
private async Task<string> BuildStateSnapshotAsync(IServiceProvider provider)
|
||||
{
|
||||
var stateRepository = provider.GetRequiredService<ISourceStateRepository>();
|
||||
var state = await stateRepository.TryGetAsync(RuBduConnectorPlugin.SourceName, CancellationToken.None);
|
||||
Assert.NotNull(state);
|
||||
|
||||
var cursor = state!.Cursor is null ? RuBduCursor.Empty : RuBduCursor.FromBson(state.Cursor);
|
||||
var snapshot = new
|
||||
{
|
||||
PendingDocuments = cursor.PendingDocuments.Select(static guid => guid.ToString()).OrderBy(static id => id, StringComparer.Ordinal).ToArray(),
|
||||
PendingMappings = cursor.PendingMappings.Select(static guid => guid.ToString()).OrderBy(static id => id, StringComparer.Ordinal).ToArray(),
|
||||
LastSuccessfulFetch = cursor.LastSuccessfulFetch?.ToUniversalTime().ToString("O"),
|
||||
};
|
||||
|
||||
return SnapshotSerializer.ToSnapshot(snapshot);
|
||||
}
|
||||
|
||||
private static string BuildRequestsSnapshot(IReadOnlyCollection<CannedHttpMessageHandler.CannedRequestRecord> requests)
|
||||
{
|
||||
var ordered = requests
|
||||
.Select(record => new
|
||||
{
|
||||
Method = record.Method.Method,
|
||||
Uri = record.Uri.ToString(),
|
||||
Headers = record.Headers
|
||||
.OrderBy(static kvp => kvp.Key, StringComparer.OrdinalIgnoreCase)
|
||||
.ToDictionary(static kvp => kvp.Key, static kvp => kvp.Value, StringComparer.OrdinalIgnoreCase),
|
||||
})
|
||||
.OrderBy(static entry => entry.Uri, StringComparer.Ordinal)
|
||||
.ToArray();
|
||||
|
||||
return SnapshotSerializer.ToSnapshot(ordered);
|
||||
}
|
||||
|
||||
private static string ReadFixtureText(string filename)
|
||||
{
|
||||
var path = GetSourceFixturePath(filename);
|
||||
return File.ReadAllText(path, Encoding.UTF8);
|
||||
}
|
||||
|
||||
private static byte[] CreateArchiveBytes()
|
||||
{
|
||||
var xml = ReadFixtureText("export-sample.xml");
|
||||
using var buffer = new MemoryStream();
|
||||
using (var archive = new ZipArchive(buffer, ZipArchiveMode.Create, leaveOpen: true))
|
||||
{
|
||||
var entry = archive.CreateEntry("export/export.xml", CompressionLevel.NoCompression);
|
||||
entry.LastWriteTime = new DateTimeOffset(2025, 10, 14, 9, 0, 0, TimeSpan.Zero);
|
||||
using var entryStream = entry.Open();
|
||||
using var writer = new StreamWriter(entryStream, new UTF8Encoding(encoderShouldEmitUTF8Identifier: false));
|
||||
writer.Write(xml);
|
||||
}
|
||||
|
||||
return buffer.ToArray();
|
||||
}
|
||||
|
||||
private static bool ShouldUpdateFixtures()
|
||||
=> !string.IsNullOrWhiteSpace(Environment.GetEnvironmentVariable(UpdateFixturesVariable));
|
||||
|
||||
private static void WriteOrAssertSnapshot(string content, string filename)
|
||||
{
|
||||
var path = GetSourceFixturePath(filename);
|
||||
if (ShouldUpdateFixtures())
|
||||
{
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(path)!);
|
||||
File.WriteAllText(path, content, Encoding.UTF8);
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.True(File.Exists(path), $"Snapshot '{filename}' is missing. Run {UpdateFixturesVariable}=1 dotnet test to regenerate fixtures.");
|
||||
var expected = File.ReadAllText(path, Encoding.UTF8);
|
||||
Assert.Equal(expected, content);
|
||||
}
|
||||
}
|
||||
|
||||
private static string GetSourceFixturePath(string relativeName)
|
||||
=> Path.GetFullPath(Path.Combine(AppContext.BaseDirectory, "..", "..", "..", "Fixtures", relativeName));
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
using System.Collections.Immutable;
|
||||
using MongoDB.Bson;
|
||||
using StellaOps.Concelier.Connector.Common;
|
||||
using StellaOps.Concelier.Models;
|
||||
using StellaOps.Concelier.Connector.Ru.Bdu.Internal;
|
||||
using StellaOps.Concelier.Storage.Mongo.Documents;
|
||||
using Xunit;
|
||||
|
||||
namespace StellaOps.Concelier.Connector.Ru.Bdu.Tests;
|
||||
|
||||
public sealed class RuBduMapperTests
|
||||
{
|
||||
[Fact]
|
||||
public void Map_ConstructsCanonicalAdvisory()
|
||||
{
|
||||
var dto = new RuBduVulnerabilityDto(
|
||||
Identifier: "BDU:2025-12345",
|
||||
Name: "Уязвимость тестового продукта",
|
||||
Description: "Описание",
|
||||
Solution: "Обновить",
|
||||
IdentifyDate: new DateTimeOffset(2025, 10, 10, 0, 0, 0, TimeSpan.Zero),
|
||||
SeverityText: "Высокий уровень опасности",
|
||||
CvssVector: "AV:N/AC:L/Au:N/C:P/I:P/A:P",
|
||||
CvssScore: 7.5,
|
||||
Cvss3Vector: "AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
|
||||
Cvss3Score: 9.8,
|
||||
ExploitStatus: "Существует",
|
||||
IncidentCount: 2,
|
||||
FixStatus: "Уязвимость устранена",
|
||||
VulStatus: "Подтверждена производителем",
|
||||
VulClass: null,
|
||||
VulState: null,
|
||||
Other: null,
|
||||
Software: new[]
|
||||
{
|
||||
new RuBduSoftwareDto(
|
||||
"ООО Вендор",
|
||||
"Продукт",
|
||||
"1.2.3;1.2.4",
|
||||
"Windows",
|
||||
new[] { "ПО программно-аппаратного средства АСУ ТП" }.ToImmutableArray())
|
||||
}.ToImmutableArray(),
|
||||
Environment: ImmutableArray<RuBduEnvironmentDto>.Empty,
|
||||
Cwes: new[] { new RuBduCweDto("CWE-79", "XSS"), new RuBduCweDto("CWE-89", "SQL Injection") }.ToImmutableArray(),
|
||||
Sources: new[]
|
||||
{
|
||||
"https://advisories.example/BDU-2025-12345",
|
||||
"www.example.com/ru-bdu/BDU-2025-12345"
|
||||
}.ToImmutableArray(),
|
||||
Identifiers: new[]
|
||||
{
|
||||
new RuBduExternalIdentifierDto("CVE", "CVE-2025-12345", "https://nvd.nist.gov/vuln/detail/CVE-2025-12345"),
|
||||
new RuBduExternalIdentifierDto("Positive Technologies Advisory", "PT-2025-001", "https://ptsecurity.com/PT-2025-001")
|
||||
}.ToImmutableArray());
|
||||
|
||||
var document = new DocumentRecord(
|
||||
Guid.NewGuid(),
|
||||
RuBduConnectorPlugin.SourceName,
|
||||
"https://bdu.fstec.ru/vul/2025-12345",
|
||||
DateTimeOffset.UtcNow,
|
||||
"abc",
|
||||
DocumentStatuses.PendingMap,
|
||||
"application/json",
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
dto.IdentifyDate,
|
||||
ObjectId.GenerateNewId());
|
||||
|
||||
var advisory = RuBduMapper.Map(dto, document, dto.IdentifyDate!.Value);
|
||||
|
||||
Assert.Equal("BDU:2025-12345", advisory.AdvisoryKey);
|
||||
Assert.Contains("BDU:2025-12345", advisory.Aliases);
|
||||
Assert.Contains("CVE-2025-12345", advisory.Aliases);
|
||||
Assert.Equal("critical", advisory.Severity);
|
||||
Assert.True(advisory.ExploitKnown);
|
||||
|
||||
var package = Assert.Single(advisory.AffectedPackages);
|
||||
Assert.Equal(AffectedPackageTypes.IcsVendor, package.Type);
|
||||
Assert.Equal(2, package.VersionRanges.Length);
|
||||
Assert.Equal(2, package.NormalizedVersions.Length);
|
||||
Assert.All(package.NormalizedVersions, rule => Assert.Equal("ru-bdu.raw", rule.Scheme));
|
||||
Assert.Contains(package.NormalizedVersions, rule => rule.Value == "1.2.3");
|
||||
Assert.Contains(package.NormalizedVersions, rule => rule.Value == "1.2.4");
|
||||
Assert.Contains(package.Statuses, status => status.Status == AffectedPackageStatusCatalog.Affected);
|
||||
Assert.Contains(package.Statuses, status => status.Status == AffectedPackageStatusCatalog.Fixed);
|
||||
|
||||
Assert.Equal(2, advisory.CvssMetrics.Length);
|
||||
Assert.Contains(advisory.References, reference => reference.Url == "https://bdu.fstec.ru/vul/2025-12345" && reference.Kind == "details");
|
||||
Assert.Contains(advisory.References, reference => reference.Url == "https://nvd.nist.gov/vuln/detail/CVE-2025-12345" && reference.Kind == "cve");
|
||||
Assert.Contains(advisory.References, reference => reference.Url == "https://advisories.example/BDU-2025-12345" && reference.Kind == "source");
|
||||
Assert.Contains(advisory.References, reference => reference.Url == "https://www.example.com/ru-bdu/BDU-2025-12345" && reference.Kind == "source");
|
||||
Assert.Contains(advisory.References, reference => reference.SourceTag == "positivetechnologiesadvisory");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
using System.IO;
|
||||
using System.Xml.Linq;
|
||||
using StellaOps.Concelier.Connector.Ru.Bdu.Internal;
|
||||
using Xunit;
|
||||
|
||||
namespace StellaOps.Concelier.Connector.Ru.Bdu.Tests;
|
||||
|
||||
public sealed class RuBduXmlParserTests
|
||||
{
|
||||
[Fact]
|
||||
public void TryParse_ValidElement_ReturnsDto()
|
||||
{
|
||||
const string xml = """
|
||||
<vul>
|
||||
<identifier>BDU:2025-12345</identifier>
|
||||
<name>Уязвимость тестового продукта</name>
|
||||
<description>Описание уязвимости</description>
|
||||
<solution>Обновить продукт</solution>
|
||||
<identify_date>2025-10-10</identify_date>
|
||||
<severity>Высокий уровень опасности</severity>
|
||||
<exploit_status>Существует эксплойт</exploit_status>
|
||||
<fix_status>Устранена</fix_status>
|
||||
<vul_status>Подтверждена производителем</vul_status>
|
||||
<vul_incident>1</vul_incident>
|
||||
<cvss>
|
||||
<vector score="7.5">AV:N/AC:L/Au:N/C:P/I:P/A:P</vector>
|
||||
</cvss>
|
||||
<cvss3>
|
||||
<vector score="9.8">AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H</vector>
|
||||
</cvss3>
|
||||
<vulnerable_software>
|
||||
<soft>
|
||||
<vendor>ООО «Вендор»</vendor>
|
||||
<name>Продукт</name>
|
||||
<version>1.2.3</version>
|
||||
<platform>Windows</platform>
|
||||
<types>
|
||||
<type>ics</type>
|
||||
</types>
|
||||
</soft>
|
||||
</vulnerable_software>
|
||||
<sources>
|
||||
https://advisories.example/BDU-2025-12345
|
||||
https://mirror.example/ru-bdu/BDU-2025-12345
|
||||
</sources>
|
||||
<identifiers>
|
||||
<identifier type="CVE" link="https://nvd.nist.gov/vuln/detail/CVE-2025-12345">CVE-2025-12345</identifier>
|
||||
<identifier type="GHSA" link="https://github.com/advisories/GHSA-xxxx-yyyy-zzzz">GHSA-xxxx-yyyy-zzzz</identifier>
|
||||
</identifiers>
|
||||
<cwes>
|
||||
<cwe>
|
||||
<identifier>CWE-79</identifier>
|
||||
<name>XSS</name>
|
||||
</cwe>
|
||||
</cwes>
|
||||
</vul>
|
||||
""";
|
||||
|
||||
var element = XElement.Parse(xml);
|
||||
var dto = RuBduXmlParser.TryParse(element);
|
||||
|
||||
Assert.NotNull(dto);
|
||||
Assert.Equal("BDU:2025-12345", dto!.Identifier);
|
||||
Assert.Equal("Уязвимость тестового продукта", dto.Name);
|
||||
Assert.Equal("AV:N/AC:L/Au:N/C:P/I:P/A:P", dto.CvssVector);
|
||||
Assert.Equal(7.5, dto.CvssScore);
|
||||
Assert.Equal("AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H", dto.Cvss3Vector);
|
||||
Assert.Equal(9.8, dto.Cvss3Score);
|
||||
Assert.Single(dto.Software);
|
||||
Assert.Single(dto.Cwes);
|
||||
Assert.Equal(2, dto.Sources.Length);
|
||||
Assert.Contains("https://advisories.example/BDU-2025-12345", dto.Sources);
|
||||
Assert.Equal(2, dto.Identifiers.Length);
|
||||
Assert.Contains(dto.Identifiers, identifier => identifier.Type == "CVE" && identifier.Value == "CVE-2025-12345");
|
||||
Assert.Contains(dto.Identifiers, identifier => identifier.Type == "GHSA" && identifier.Link == "https://github.com/advisories/GHSA-xxxx-yyyy-zzzz");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TryParse_SampleArchiveEntries_ReturnDtos()
|
||||
{
|
||||
var path = Path.GetFullPath(Path.Combine(AppContext.BaseDirectory, "..", "..", "..", "Fixtures", "export-sample.xml"));
|
||||
var document = XDocument.Load(path);
|
||||
var vulnerabilities = document.Root?.Elements("vul");
|
||||
Assert.NotNull(vulnerabilities);
|
||||
|
||||
foreach (var element in vulnerabilities!)
|
||||
{
|
||||
var dto = RuBduXmlParser.TryParse(element);
|
||||
Assert.NotNull(dto);
|
||||
Assert.False(string.IsNullOrWhiteSpace(dto!.Identifier));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="../StellaOps.Concelier.Models/StellaOps.Concelier.Models.csproj" />
|
||||
<ProjectReference Include="../StellaOps.Concelier.Normalization/StellaOps.Concelier.Normalization.csproj" />
|
||||
<ProjectReference Include="../StellaOps.Concelier.Connector.Ru.Bdu/StellaOps.Concelier.Connector.Ru.Bdu.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
Reference in New Issue
Block a user