{"id":471775,"date":"2025-08-23T15:07:10","date_gmt":"2025-08-23T15:07:10","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=471775"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=471775","title":{"rendered":"<span>\u0410\u043d\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u0435\u043c \u0438\u0441\u0445\u043e\u0434\u043d\u044b\u0439 \u043a\u043e\u0434 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e GitLab<\/span>"},"content":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>\u0421\u0432\u043e\u0435\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0435 \u0432\u044b\u044f\u0432\u043b\u0435\u043d\u0438\u0435 \u0443\u044f\u0437\u0432\u0438\u043c\u043e\u0441\u0442\u0435\u0439 \u0432 \u043a\u043e\u0434\u0435 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043e\u0434\u043d\u043e\u0439 \u0438\u0437 \u0432\u0430\u0436\u043d\u0435\u0439\u0448\u0438\u0445 \u0437\u0430\u0434\u0430\u0447 \u043a\u043e\u043d\u0432\u0435\u0439\u0435\u0440\u0430 CI\/CD, \u0432\u0435\u0434\u044c \u0447\u0435\u043c \u0440\u0430\u043d\u044c\u0448\u0435 \u043c\u044b \u043e\u0431\u043d\u0430\u0440\u0443\u0436\u0438\u043c \u043e\u0448\u0438\u0431\u043a\u0443 \u0432 \u043a\u043e\u0434\u0435, \u0442\u0435\u043c \u0434\u0435\u0448\u0435\u0432\u043b\u0435 \u043d\u0430\u043c \u043e\u0431\u043e\u0439\u0434\u0435\u0442\u0441\u044f \u0435\u0435 \u0438\u0441\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435. \u0414\u043b\u044f \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u044d\u0442\u043e\u0439 \u0437\u0430\u0434\u0430\u0447\u0438 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u043e \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0445 \u0440\u0435\u0448\u0435\u043d\u0438\u0439. \u041d\u043e \u0435\u0441\u043b\u0438 \u043c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u043a\u043e\u043d\u0432\u0435\u0439\u0435\u0440 CI\/CD \u0442\u043e \u043d\u0430\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0438\u043d\u0442\u0435\u0433\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043d\u0430\u0448 \u0430\u043d\u0430\u043b\u0438\u0437\u0430\u0442\u043e\u0440 \u0432 \u044d\u0442\u043e\u0442 \u043f\u0440\u043e\u0446\u0435\u0441\u0441. \u041e\u0434\u043d\u0430\u043a\u043e, \u0432 GitLab \u0438\u043c\u0435\u0435\u0442\u0441\u044f \u0441\u0432\u043e\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u0434\u043b\u044f \u0430\u043d\u0430\u043b\u0438\u0437\u0430 \u0438\u0441\u0445\u043e\u0434\u043d\u043e\u0433\u043e \u043a\u043e\u0434\u0430. \u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u043c\u044b \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u043c GitLab SAST \u0434\u043b\u044f \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0433\u043e \u0430\u043d\u0430\u043b\u0438\u0437\u0430 \u0438\u0441\u0445\u043e\u0434\u043d\u043e\u0433\u043e \u043a\u043e\u0434\u0430 \u043d\u0430 \u043d\u0430\u043b\u0438\u0447\u0438\u0435 \u0443\u044f\u0437\u0432\u0438\u043c\u043e\u0441\u0442\u0435\u0439.<\/p>\n<h2>\u0413\u043e\u0442\u043e\u0432\u0438\u043c \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e<\/h2>\n<p>\u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u043d\u0430\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0432\u043a\u043b\u044e\u0447\u0438\u0442\u044c GitLab SAST \u0432 \u043d\u0430\u0448\u0435\u043c \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0438. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043d\u0443\u0436\u043d\u043e \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0439 \u0444\u0430\u0439\u043b \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 SAST \u0432 \u043f\u0430\u043f\u043a\u0435: ci\/SAST.gitlab-ci.yml.<\/p>\n<pre><code class=\"yaml\">variables:   SECURE_ANALYZERS_PREFIX: \"$CI_TEMPLATE_REGISTRY_HOST\/security-products\"   SAST_IMAGE_SUFFIX: \"\"   SAST_EXCLUDED_ANALYZERS: \"\"   DEFAULT_SAST_EXCLUDED_PATHS: \"\"   SAST_EXCLUDED_PATHS: \"$DEFAULT_SAST_EXCLUDED_PATHS\"   SCAN_KUBERNETES_MANIFESTS: \"false\"  sast:   extends: .sast   stage: sast   artifacts:     paths:       - gl-sast-report.json     expire_in: 1 day     access: 'developer'     reports:       sast: gl-sast-report.json   rules:     - when: never   variables:     SEARCH_MAX_DEPTH: 4   script:     - echo \"$CI_JOB_NAME is used for configuration only\"<\/code><\/pre>\n<p>\u041c\u044b \u0431\u0443\u0434\u0435\u043c \u043f\u043e\u0441\u0442\u0435\u043f\u0435\u043d\u043d\u043e \u0437\u0430\u043f\u043e\u043b\u043d\u044f\u0442\u044c \u044d\u0442\u043e\u0442 \u0444\u0430\u0439\u043b \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u044b\u043c \u0434\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u0431\u044b\u043b\u043e \u043f\u043e\u043d\u044f\u0442\u043d\u043e \u043a\u0430\u043a\u043e\u0439 \u0440\u0430\u0437\u0434\u0435\u043b \u0444\u0430\u0439\u043b\u0430 \u0437\u0430 \u0447\u0442\u043e \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442. \u0421\u0435\u0439\u0447\u0430\u0441 \u043c\u044b \u043e\u0431\u044a\u044f\u0432\u0438\u043b\u0438 \u0440\u044f\u0434 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445 \u0438 \u0440\u0430\u0437\u043c\u0435\u0441\u0442\u0438\u043b\u0438 \u0440\u0430\u0437\u0434\u0435\u043b SAST. \u0414\u0430\u043b\u0435\u0435 \u043d\u0430\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c \u0430\u043d\u0430\u043b\u0438\u0437\u0430\u0442\u043e\u0440\u044b SAST, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c<\/p>\n<p>\u041d\u0430\u0447\u043d\u0435\u043c \u0441 GitLab Advanced SAST. \u042d\u0442\u043e\u0442 \u0430\u043d\u0430\u043b\u0438\u0437\u0430\u0442\u043e\u0440 \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u043b\u044f Python, Go, Java, JavaScript, TypeScript. \u041d\u043e \u0437\u0434\u0435\u0441\u044c \u0435\u0441\u0442\u044c \u0432\u0430\u0436\u043d\u044b\u0439 \u043d\u044e\u0430\u043d\u0441 &#8212; GitLab Advanced SAST \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u0438\u0441\u043a\u043b\u044e\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0434\u043b\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u0443\u0440\u043e\u0432\u043d\u044f Ultimate. \u0415\u0441\u043b\u0438 \u0432\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0435 \u0443\u0440\u043e\u0432\u0435\u043d\u044c Free \u0438\u043b\u0438 Premium, \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u0442\u0435 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0430\u043d\u0430\u043b\u0438\u0437\u0430\u0442\u043e\u0440\u043e\u0432 SAST \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e.<\/p>\n<p>\u0412 \u0444\u0430\u0439\u043b SAST.gitlab-ci.yml \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0435:<\/p>\n<pre><code class=\"yaml\">gitlab-advanced-sast:   extends: .sast-analyzer   image:     name: \"$SAST_ANALYZER_IMAGE\"   variables:     SEARCH_MAX_DEPTH: 20     SAST_ANALYZER_IMAGE: \"$SECURE_ANALYZERS_PREFIX\/gitlab-advanced-sast:1$SAST_IMAGE_SUFFIX\"   rules:     - if: $SAST_DISABLED == 'true' || $SAST_DISABLED == '1'       when: never     - if: $SAST_EXCLUDED_ANALYZERS =~ \/gitlab-advanced-sast\/       when: never     - if: $GITLAB_ADVANCED_SAST_ENABLED != 'true'       when: never     - exists:         - '**\/*.py'         - '**\/*.go'         - '**\/*.java'         - '**\/*.js'         - '**\/*.ts'<\/code><\/pre>\n<p>\u0414\u043b\u044f \u044f\u0437\u044b\u043a\u043e\u0432 PHP, Swift, Scala, Ruby \u043c\u043e\u0436\u043d\u043e \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0430\u043d\u0430\u043b\u0438\u0437\u0430\u0442\u043e\u0440\u043e\u043c Semgrep SAST \u0438 \u0442\u043e\u0433\u0434\u0430 \u0432 \u0444\u0430\u0439\u043b \u043d\u0443\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c:<\/p>\n<pre><code class=\"yaml\">semgrep-sast:   extends: .sast-analyzer   image:     name: \"$SAST_ANALYZER_IMAGE\"   variables:     SAST_ANALYZER_IMAGE: \"$SECURE_ANALYZERS_PREFIX\/semgrep:5$SAST_IMAGE_SUFFIX\"   rules:     - exists:         - '**\/*.php'         - '**\/*.swift'         - '**\/*.scala'         - '**\/*.rb'<\/code><\/pre>\n<h2>\u0411\u043e\u0440\u0435\u043c\u0441\u044f \u0437\u0430 \u0447\u0438\u0442\u0430\u0435\u043c\u043e\u0441\u0442\u044c \u043e\u0442\u0447\u0435\u0442\u043e\u0432<\/h2>\n<p>\u041f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e GitLab SAST \u0432\u044b\u0434\u0430\u0435\u0442 \u043e\u0442\u0447\u0435\u0442\u044b \u0432 \u0444\u043e\u0440\u043c\u0430\u0442\u0435 JSON, \u043d\u043e \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u0443\u0435\u043c \u0438\u0445 \u0432 HTML \u0438 JUnit XML \u0434\u043b\u044f \u043b\u0443\u0447\u0448\u0435\u0439 \u043d\u0430\u0433\u043b\u044f\u0434\u043d\u043e\u0441\u0442\u0438.<\/p>\n<p>\u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043d\u0430\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0432 \u0444\u0430\u0439\u043b \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0435:<\/p>\n<pre><code class=\"yaml\">sast_to_html:   extends: .sast-analyzer   image: python:3.9   script:     - cp gl-sast-report.json ci\/     - cd ci     - python3 convert_sast_to_html.py gl-sast-report.json index.html     - python3 junit_convertor.py gl-sast-report.json report.xml   artifacts:     paths:       - ci\/index.html       - ci\/report.xml       - gl-sast-report.json     reports:       junit: ci\/report.xml            expire_in: 1 day<\/code><\/pre>\n<p>\u0412 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u043d\u043e\u043c YAML \u043c\u043e\u0436\u043d\u043e \u0437\u0430\u043c\u0435\u0442\u0438\u0442\u044c \u0443\u043f\u043e\u043c\u0438\u043d\u0430\u043d\u0438\u0435 \u0441\u043a\u0440\u0438\u043f\u0442\u043e\u0432 \u043d\u0430 Python. \u0427\u0442\u043e\u0431\u044b \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0442\u044c \u0432\u0438\u0437\u0443\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u0443\u044f\u0437\u0432\u0438\u043c\u043e\u0441\u0442\u0435\u0439 \u0432 \u0432\u0438\u0434\u0436\u0435\u0442\u0430\u0445 GitLab Merge Request, \u043c\u044b \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u0441\u043a\u0440\u0438\u043f\u0442  \u0434\u043b\u044f \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u043e\u0442\u0447\u0435\u0442\u0430 JSON SAST \u0432 \u0444\u043e\u0440\u043c\u0430\u0442 JUnit:<\/p>\n<pre><code class=\"python\">import json import sys import xml.etree.ElementTree as ET  def convert_json_to_junit(json_file, output_file):     try:         with open(json_file, \"r\") as f:             json_data = json.load(f)                  testsuites = ET.Element(\"testsuites\")         testsuite = ET.SubElement(testsuites, \"testsuite\", name=\"Security Scan\", tests=str(len(json_data[\"vulnerabilities\"])), failures=str(len(json_data[\"vulnerabilities\"])))                  for vulnerability in json_data[\"vulnerabilities\"]:             test_case = ET.SubElement(testsuite, \"testcase\", name=vulnerability[\"name\"], classname=vulnerability[\"category\"])             failure_message = f\"{vulnerability['description']}\\nSeverity: {vulnerability['severity']}\\n\"             failure_message += f\"File: {vulnerability['location']['file']} (Line {vulnerability['location']['start_line']})\\n\"                          if \"mitigation\" in vulnerability:                 failure_message += f\"Mitigation: {vulnerability['mitigation']}\\n\"                          failure_element = ET.SubElement(test_case, \"failure\", message=f\"{vulnerability['name']} detected\")             failure_element.text = failure_message                  tree = ET.ElementTree(testsuites)         ET.indent(tree, space=\"  \")         tree.write(output_file, encoding=\"utf-8\", xml_declaration=True)                  print(f\"JUnit report generated: {output_file}\")     except Exception as e:         print(f\"Error: {e}\")         sys.exit(1)  if __name__ == \"__main__\":     if len(sys.argv) != 3:         print(\"Usage: python convert_json_to_junit.py &lt;input_json_file&gt; &lt;output_xml_file&gt;\")         sys.exit(1)          json_file = sys.argv[1]     output_file = sys.argv[2]          convert_json_to_junit(json_file, output_file)<\/code><\/pre>\n<p>\u0410 \u0437\u0430\u0442\u0435\u043c \u043c\u044b \u0445\u043e\u0442\u0438\u043c \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u043d\u0430\u0448 \u0438\u0442\u043e\u0433\u043e\u0432\u044b\u0439 \u043e\u0442\u0447\u0435\u0442 \u043e \u043d\u0430\u0439\u0434\u0435\u043d\u043d\u044b\u0445 \u0443\u044f\u0437\u0432\u0438\u043c\u043e\u0441\u0442\u044f\u0445 \u0432 \u0444\u043e\u0440\u043c\u0430\u0442\u0435 HTML. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043d\u0430\u043c \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0432\u0442\u043e\u0440\u043e\u0439 \u0441\u043a\u0440\u0438\u043f\u0442.<\/p>\n<pre><code class=\"python\">import json import sys  def parse_json_to_html(json_data):     vulnerabilities = json_data.get('vulnerabilities', [])      html = '''     &lt;html&gt;     &lt;head&gt;         &lt;title&gt;SAST Report&lt;\/title&gt;         &lt;style&gt;             body {                 font-family: 'Arial', sans-serif;                 background-color: #f3f4f6;                 margin: 0;                 padding: 30px;             }              h2 {                 color: #2c3e50;                 text-align: center;                 font-size: 28px;                 font-weight: 600;                 margin-bottom: 20px;             }              table {                 border-collapse: collapse;                 width: 100%;                 box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);                 background: linear-gradient(135deg, #f0f8ff, #fdfdfd);                 border-radius: 12px;                 overflow: hidden;             }              th, td {                 padding: 15px;                 text-align: left;                 font-size: 14px;             }              th {                 background-color: #34495e;                 color: white;                 text-transform: uppercase;                 font-size: 16px;             }              td {                 background-color: #ecf0f1;                 color: #2c3e50;                 border-bottom: 1px solid #ddd;             }              tr:nth-child(odd) td {                 background-color: #f9fafb;             }              tr:nth-child(even) td {                 background-color: #ffffff;             }              tr:hover td {                 background-color: #dcdfe1;                 cursor: pointer;                 transition: background-color 0.3s ease;             }              .severity-high {                 background-color: #e74c3c; \/* Red for High *\/                 padding: 5px 10px;                 border-radius: 5px;                 text-align: center;                 font-weight: bold;                 color: white;             }              .severity-medium {                 background-color: #f39c12; \/* Orange for Medium *\/                 padding: 5px 10px;                 border-radius: 5px;                 text-align: center;                 font-weight: bold;                 color: white;             }              .severity-low {                 background-color: #f1c40f; \/* Yellow for Low *\/                 padding: 5px 10px;                 border-radius: 5px;                 text-align: center;                 font-weight: bold;                 color: white;             }          &lt;\/style&gt;     &lt;\/head&gt;     &lt;body&gt;         &lt;h2&gt;GitLab SAST Report&lt;\/h2&gt;         &lt;table&gt;             &lt;tr&gt;                 &lt;th&gt;Name&lt;\/th&gt;                 &lt;th&gt;Description&lt;\/th&gt;                 &lt;th&gt;Severity&lt;\/th&gt;                 &lt;th&gt;File&lt;\/th&gt;                 &lt;th&gt;Line&lt;\/th&gt;             &lt;\/tr&gt;     '''      for item in vulnerabilities:         severity = item.get('severity', '').strip().lower()           severity_class = ''                  if severity == 'high':             severity_class = 'severity-high'         elif severity == 'medium':             severity_class = 'severity-medium'         elif severity == 'low':             severity_class = 'severity-low'         else:             severity_class = 'severity-low'                    html += f'''             &lt;tr&gt;                 &lt;td&gt;{item.get('name', '')}&lt;\/td&gt;                 &lt;td&gt;{item.get('description', '')}&lt;\/td&gt;                 &lt;td class=\"{severity_class}\"&gt;{item.get('severity', '')}&lt;\/td&gt;                 &lt;td&gt;{item.get('location', {}).get('file', '')}&lt;\/td&gt;                 &lt;td&gt;{item.get('location', {}).get('start_line', '')}&lt;\/td&gt;             &lt;\/tr&gt;         '''      html += '''         &lt;\/table&gt;     &lt;\/body&gt;     &lt;\/html&gt;     '''      return html  def main():     if len(sys.argv) != 3:         print(\"Usage: python convert_sast_to_html.py &lt;input_json_file&gt; &lt;output_html_file&gt;\")         sys.exit(1)      input_json_file = sys.argv[1]     output_html_file = sys.argv[2]      with open(input_json_file, 'r') as file:         json_data = json.load(file)      html_content = parse_json_to_html(json_data)      with open(output_html_file, 'w') as file:         file.write(html_content)  if __name__ == \"__main__\":     main()<\/code><\/pre>\n<p>\u00a0\u0412 \u0438\u0442\u043e\u0433\u0435, \u043e\u0442\u0447\u0435\u0442 JUnit XML \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0434\u043b\u044f \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u043e\u0432 SAST \u0432 \u0432\u0438\u0434\u0436\u0435\u0442\u0435 Merge Request.<\/p>\n<figure class=\"full-width\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/7ee\/a14\/13e\/7eea1413e32f580d55f32d0187abf36c.png\" width=\"974\" height=\"479\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/getpro\/habr\/upload_files\/7ee\/a14\/13e\/7eea1413e32f580d55f32d0187abf36c.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/7ee\/a14\/13e\/7eea1413e32f580d55f32d0187abf36c.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/figure>\n<p>\u0410 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u0444\u043e\u0440\u043c\u0430\u0442\u0430 HTML \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c GitLab Pages \u0434\u043b\u044f \u043b\u0443\u0447\u0448\u0435\u0439 \u0432\u0438\u0437\u0443\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u043e\u0432.<\/p>\n<figure class=\"full-width\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/45d\/958\/6af\/45d9586afd5dc7f1d3d1ac6a19c21bac.png\" width=\"974\" height=\"134\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/getpro\/habr\/upload_files\/45d\/958\/6af\/45d9586afd5dc7f1d3d1ac6a19c21bac.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/45d\/958\/6af\/45d9586afd5dc7f1d3d1ac6a19c21bac.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/figure>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043d\u0430\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0438\u043d\u0442\u0435\u0433\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043d\u0430\u0448 SAST \u0432 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u043a\u043e\u043d\u0432\u0435\u0439\u0435\u0440.<\/p>\n<h2>\u0418\u043d\u0442\u0435\u0433\u0440\u0438\u0440\u0443\u0435\u043c \u0432 \u043a\u043e\u043d\u0432\u0435\u0439\u0435\u0440<\/h2>\n<p>\u0418\u0442\u0430\u043a, \u043a\u043e\u0433\u0434\u0430 \u043c\u044b \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u043b\u0438 GitLab SAST \u0438 \u043e\u0442\u0447\u0435\u0442\u043d\u043e\u0441\u0442\u044c, \u043f\u0440\u0438\u0448\u043b\u043e \u0432\u0440\u0435\u043c\u044f \u0438\u043d\u0442\u0435\u0433\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0435\u0433\u043e \u0432 \u043d\u0430\u0448 \u043a\u043e\u043d\u0432\u0435\u0439\u0435\u0440 CI\/CD. \u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u043c\u044b \u0433\u0430\u0440\u0430\u043d\u0442\u0438\u0440\u0443\u0435\u043c, \u0447\u0442\u043e \u043a\u0430\u0436\u0434\u044b\u0439 \u043a\u043e\u043c\u043c\u0438\u0442 \u043a\u043e\u0434\u0430 \u0438 \u0437\u0430\u043f\u0440\u043e\u0441 \u043d\u0430 \u0441\u043b\u0438\u044f\u043d\u0438\u0435 \u0431\u0443\u0434\u0443\u0442 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0441\u043a\u0430\u043d\u0438\u0440\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u043d\u0430 \u043d\u0430\u043b\u0438\u0447\u0438\u0435 \u0443\u044f\u0437\u0432\u0438\u043c\u043e\u0441\u0442\u0435\u0439 \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u0438. \u0427\u0442\u043e\u0431\u044b \u0432\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0435 \u0441\u043a\u0430\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 SAST, \u0434\u043e\u0431\u0430\u0432\u044c\u0442\u0435 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0443\u044e \u0437\u0430\u0434\u0430\u0447\u0443 SAST \u0432 \u0432\u0430\u0448 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u0444\u0430\u0439\u043b \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 .gitlab-ci.yml:<\/p>\n<pre><code class=\"yaml\">stages:   - sast  # Define a dedicated SAST stage in the pipeline  include:   - template: ci\/SAST.gitlab-ci.yml  # Includes GitLab\u2019s predefined SAST template  stages:   - build  # Typically used for compiling the application, running unit tests, etc.   - sast   # Dedicated to Static Application Security Testing (SAST) to identify security vulnerabilities in the codebase before deployment.  .sast:   variables:     SAST_DISABLE_DIND: \"true\" # Disables Docker-in-Docker (DinD) when running SAST scans     SEARCH_MAX_DEPTH: 10  # Defines how deep the SAST scanner should search for source code files<\/code><\/pre>\n<p>\u00a0\u041a\u0430\u043a \u0432\u0438\u0434\u043d\u043e, \u043c\u044b \u0434\u043e\u0431\u0430\u0432\u0438\u043b\u0438 \u043d\u0430\u0448 \u0444\u0430\u0439\u043b \u0441 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430\u043c\u0438 SAST \u0432 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u0444\u0430\u0439\u043b \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u043a\u043e\u043d\u0432\u0435\u0439\u0435\u0440\u0430 GitLab.<\/p>\n<h2>\u0417\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c SAST \u0432 GitLab<\/h2>\n<p>\u041f\u043e\u0441\u043b\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 GitLab SAST \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442\u0441\u044f \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 \u043a\u043e\u043d\u0432\u0435\u0439\u0435\u0440\u0430 \u0438 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u0445 \u043f\u0440\u0430\u0432\u0438\u043b. \u0422\u0430\u043a, \u043f\u043e\u044f\u0432\u043b\u0435\u043d\u0438\u0435 \u043b\u044e\u0431\u043e\u0433\u043e \u043d\u043e\u0432\u043e\u0433\u043e \u043a\u043e\u043c\u043c\u0438\u0442\u0430, \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u043d\u043e\u0433\u043e \u0432 \u0432\u0435\u0442\u043a\u0443 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f, \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442 \u043a\u043e\u043d\u0432\u0435\u0439\u0435\u0440, \u0438, \u0435\u0441\u043b\u0438 \u043f\u0440\u0430\u0432\u0438\u043b\u0430 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044e\u0442, SAST \u0441\u043a\u0430\u043d\u0438\u0440\u0443\u0435\u0442 \u043a\u043e\u0434 \u043d\u0430 \u043d\u0430\u043b\u0438\u0447\u0438\u0435 \u0443\u044f\u0437\u0432\u0438\u043c\u043e\u0441\u0442\u0435\u0439.<\/p>\n<p>\u0422\u0430\u043a\u0436\u0435, \u043f\u0440\u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u043d\u0430 \u0441\u043b\u0438\u044f\u043d\u0438\u0435 GitLab CI\/CD \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442 \u0441\u043a\u0430\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 SAST \u0434\u043b\u044f \u0430\u043d\u0430\u043b\u0438\u0437\u0430 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439 \u043f\u0435\u0440\u0435\u0434 \u0441\u043b\u0438\u044f\u043d\u0438\u0435\u043c, \u0447\u0442\u043e \u043f\u043e\u043c\u043e\u0433\u0430\u0435\u0442 \u0432\u044b\u044f\u0432\u0438\u0442\u044c \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u0438 \u043d\u0430 \u0440\u0430\u043d\u043d\u0438\u0445 \u044d\u0442\u0430\u043f\u0430\u0445 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0430 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438.<\/p>\n<p>\u0418, \u043d\u0430\u043a\u043e\u043d\u0435\u0446, \u0435\u0441\u043b\u0438 \u0443 \u043d\u0430\u0441 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442\u0441\u044f \u0437\u0430\u043f\u043b\u0430\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u043a\u043e\u043d\u0432\u0435\u0439\u0435\u0440, SAST \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f \u043f\u0435\u0440\u0438\u043e\u0434\u0438\u0447\u0435\u0441\u043a\u0438 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0435\u0436\u0435\u0434\u043d\u0435\u0432\u043d\u043e \u0438\u043b\u0438 \u0435\u0436\u0435\u043d\u0435\u0434\u0435\u043b\u044c\u043d\u043e) \u0434\u043b\u044f \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0435\u043d\u0438\u044f \u043d\u0435\u043f\u0440\u0435\u0440\u044b\u0432\u043d\u043e\u0433\u043e \u043c\u043e\u043d\u0438\u0442\u043e\u0440\u0438\u043d\u0433\u0430 \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u0438, \u0434\u0430\u0436\u0435 \u043a\u043e\u0433\u0434\u0430 \u0430\u043a\u0442\u0438\u0432\u043d\u0430\u044f \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u043d\u0435 \u0432\u0435\u0434\u0435\u0442\u0441\u044f.<\/p>\n<h2>\u0412\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u043f\u0440\u0430\u0432\u0438\u043b<\/h2>\n<p>\u0424\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 SAST \u0437\u0430\u0432\u0438\u0441\u0438\u0442 \u043e\u0442 \u043f\u0440\u0430\u0432\u0438\u043b, \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u0445 \u0432 .gitlab-ci.yml. \u042d\u0442\u0438 \u043f\u0440\u0430\u0432\u0438\u043b\u0430 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u044e\u0442, \u043f\u0440\u0438 \u043a\u0430\u043a\u0438\u0445 \u0443\u0441\u043b\u043e\u0432\u0438\u044f\u0445 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442\u0441\u044f \u0437\u0430\u0434\u0430\u043d\u0438\u0435 SAST. \u041f\u0440\u0438\u0432\u0435\u0434\u0435\u043c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043f\u0440\u0438\u043c\u0435\u0440\u043e\u0432:<\/p>\n<ul>\n<li>\n<p>\u0417\u0430\u043f\u0443\u0441\u043a \u0442\u043e\u043b\u044c\u043a\u043e \u043d\u0430 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u0445 \u0432\u0435\u0442\u043a\u0430\u0445 (only: [main])<\/p>\n<\/li>\n<li>\n<p>\u041f\u0440\u0438 \u043e\u0442\u043a\u0440\u044b\u0442\u0438\u0438 \u0438\u043b\u0438 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u043d\u0430 \u0441\u043b\u0438\u044f\u043d\u0438\u0435 (if: \u201e$CI_PIPELINE_SOURCE == \u00abmerge_request_event\u00bb\u201c)<\/p>\n<\/li>\n<li>\n<p>\u041f\u043e \u0440\u0430\u0441\u043f\u0438\u0441\u0430\u043d\u0438\u044e (if: \u201e$CI_PIPELINE_SOURCE == \u00abschedule\u00bb\u201c)<\/p>\n<\/li>\n<li>\n<p>\u041f\u0440\u0438 \u0432\u043d\u0435\u0441\u0435\u043d\u0438\u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439 \u0432 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u0435 \u0444\u0430\u0439\u043b\u044b (changes: [\u00ab**\/*.py\u00bb, \u00ab**\/*.js\u00bb])<\/p>\n<\/li>\n<\/ul>\n<p>\u041f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0432 \u043f\u0440\u0430\u0432\u0438\u043b\u0430, \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u043c\u043e\u0433\u0443\u0442 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u0438\u0440\u043e\u0432\u0430\u0442\u044c, \u043a\u043e\u0433\u0434\u0430 \u0438 \u043a\u0430\u043a \u0447\u0430\u0441\u0442\u043e \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442\u0441\u044f SAST, \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0438\u0440\u0443\u044f \u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d\u043e\u0441\u0442\u044c \u043a\u043e\u043d\u0432\u0435\u0439\u0435\u0440\u0430 \u0438 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u044f \u043f\u0440\u0438 \u044d\u0442\u043e\u043c \u043b\u0443\u0447\u0448\u0438\u0435 \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0438 \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u0438.<\/p>\n<p>\u0412 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u0438 \u043f\u0440\u0438\u0432\u0435\u0434\u0435\u043c \u043f\u043e\u043b\u043d\u044b\u0439 \u043f\u0440\u0438\u043c\u0435\u0440 \u0444\u0430\u0439\u043b\u0430 ci\/SAST.gitlab-ci.yml, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b\u0438 \u0434\u043b\u044f \u0430\u043d\u0430\u043b\u0438\u0437\u0430 \u0438\u0441\u0445\u043e\u0434\u043d\u043e\u0433\u043e \u043a\u043e\u0434\u0430.<\/p>\n<pre><code class=\"yaml\">variables:   SECURE_ANALYZERS_PREFIX: \"$CI_TEMPLATE_REGISTRY_HOST\/security-products\"   SAST_IMAGE_SUFFIX: \"\"   SAST_EXCLUDED_ANALYZERS: \"\"   DEFAULT_SAST_EXCLUDED_PATHS: \"\"   SAST_EXCLUDED_PATHS: \"$DEFAULT_SAST_EXCLUDED_PATHS\"   SCAN_KUBERNETES_MANIFESTS: \"false\"  sast:   extends: .sast   stage: sast   artifacts:     paths:       - gl-sast-report.json     expire_in: 1 day     access: 'developer'     reports:       sast: gl-sast-report.json   rules:     - when: never   variables:     SEARCH_MAX_DEPTH: 4   script:     - echo \"$CI_JOB_NAME is used for configuration only, and its script should not be executed\"     - exit 1  .sast-analyzer:   extends: sast   allow_failure: true   script:     - \/analyzer run   gitlab-advanced-sast:   extends: .sast-analyzer   image:     name: \"$SAST_ANALYZER_IMAGE\"   variables:     SEARCH_MAX_DEPTH: 20     SAST_ANALYZER_IMAGE_TAG: '1'     SAST_ANALYZER_IMAGE: \"$SECURE_ANALYZERS_PREFIX\/gitlab-advanced-sast:$SAST_ANALYZER_IMAGE_TAG$SAST_IMAGE_SUFFIX\"   rules:     - if: $SAST_DISABLED == 'true' || $SAST_DISABLED == '1'       when: never     - if: $SAST_EXCLUDED_ANALYZERS =~ \/gitlab-advanced-sast\/       when: never     - if: $GITLAB_ADVANCED_SAST_ENABLED != 'true' &amp;&amp; $GITLAB_ADVANCED_SAST_ENABLED != '1'       when: never     - if: $CI_COMMIT_BRANCH &amp;&amp;           $GITLAB_FEATURES =~ \/\\bsast_advanced\\b\/       exists:         - '**\/*.py'         - '**\/*.go'         - '**\/*.java'         - '**\/*.jsp'         - '**\/*.js'         - '**\/*.jsx'         - '**\/*.ts'         - '**\/*.tsx'         - '**\/*.cjs'         - '**\/*.mjs'         - '**\/*.cs'         - '**\/*.rb'   semgrep-sast:   extends: .sast-analyzer   image:     name: \"$SAST_ANALYZER_IMAGE\"   variables:     SEARCH_MAX_DEPTH: 20     SAST_ANALYZER_IMAGE_TAG: 5     SAST_ANALYZER_IMAGE: \"$SECURE_ANALYZERS_PREFIX\/semgrep:$SAST_ANALYZER_IMAGE_TAG$SAST_IMAGE_SUFFIX\"   rules:     - if: $SAST_DISABLED == 'true' || $SAST_DISABLED == '1'       when: never     - if: $SAST_EXCLUDED_ANALYZERS =~ \/semgrep\/       when: never     # In case gitlab-advanced-sast also runs, exclude files already scanned by gitlab-advanced-sast     - if: $CI_COMMIT_BRANCH &amp;&amp;           $GITLAB_FEATURES =~ \/\\bsast_advanced\\b\/ &amp;&amp;           $SAST_EXCLUDED_ANALYZERS !~ \/gitlab-advanced-sast\/ &amp;&amp;           ($GITLAB_ADVANCED_SAST_ENABLED == 'true' || $GITLAB_ADVANCED_SAST_ENABLED == '1')       variables:         SAST_EXCLUDED_PATHS: \"$DEFAULT_SAST_EXCLUDED_PATHS, **\/*.py, **\/*.go, **\/*.java, **\/*.js, **\/*.jsx, **\/*.ts, **\/*.tsx, **\/*.cjs, **\/*.mjs, **\/*.cs, **\/*.rb\"       exists:         - '**\/*.c'         - '**\/*.cc'         - '**\/*.cpp'         - '**\/*.c++'         - '**\/*.cp'         - '**\/*.cxx'         - '**\/*.h'         - '**\/*.hpp'         - '**\/*.scala'         - '**\/*.sc'         - '**\/*.php'         - '**\/*.swift'         - '**\/*.m'         - '**\/*.kt'     ## In case gitlab-advanced-sast already covers all the files that semgrep-sast would have scanned     - if: $CI_COMMIT_BRANCH &amp;&amp;           $GITLAB_FEATURES =~ \/\\bsast_advanced\\b\/ &amp;&amp;           $SAST_EXCLUDED_ANALYZERS !~ \/gitlab-advanced-sast\/ &amp;&amp;           ($GITLAB_ADVANCED_SAST_ENABLED == 'true' || $GITLAB_ADVANCED_SAST_ENABLED == '1')       when: never     - if: $CI_PIPELINE_SOURCE == \"merge_request_event\" || $CI_PIPELINE_SOURCE == \"schedule\"       exists:         - '**\/*.py'         - '**\/*.js'         - '**\/*.jsx'         - '**\/*.ts'         - '**\/*.tsx'         - '**\/*.cjs'         - '**\/*.mjs'         - '**\/*.c'         - '**\/*.cc'         - '**\/*.cpp'         - '**\/*.c++'         - '**\/*.cp'         - '**\/*.cxx'         - '**\/*.h'         - '**\/*.hpp'         - '**\/*.go'         - '**\/*.java'         - '**\/*.cs'         - '**\/*.scala'         - '**\/*.sc'         - '**\/*.php'         - '**\/*.swift'         - '**\/*.m'         - '**\/*.rb'         - '**\/*.kt'  sast_to_html:   extends: .sast-analyzer   image: python:3.9   script:     - cp gl-sast-report.json ci\/     - cd ci     - python3 convert_sast_to_html.py gl-sast-report.json index.html     - python3 junit_convertor.py gl-sast-report.json report.xml   artifacts:     paths:       - ci\/index.html       - ci\/report.xml       - gl-sast-report.json     reports:       junit: ci\/report.xml            expire_in: 1 day        rules:     - if: $CI_PIPELINE_SOURCE == \"merge_request_event\" || $CI_PIPELINE_SOURCE == \"schedule\"       when: always   needs:  # Ensure this job runs after the SAST jobs     - semgrep-sast           pages:   extends: .sast-analyzer   script:     - mkdir public     - mv ci\/index.html public\/   artifacts:     paths: [\"public\"]     expire_in: 1 day   rules:     - if: $CI_PIPELINE_SOURCE == \"merge_request_event\" || $CI_PIPELINE_SOURCE == \"schedule\"   needs:  # Ensure this job runs after the SAST jobs     - sast_to_html<\/code><\/pre>\n<h2>\u0417\u0430\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435<\/h2>\n<p>GitLab SAST, \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043f\u0440\u043e\u0430\u043a\u0442\u0438\u0432\u043d\u044b\u0439 \u043f\u043e\u0434\u0445\u043e\u0434 \u043a \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u0438 \u0432 \u0436\u0438\u0437\u043d\u0435\u043d\u043d\u043e\u043c \u0446\u0438\u043a\u043b\u0435 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438. \u0411\u043b\u0430\u0433\u043e\u0434\u0430\u0440\u044f \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u043c\u0443 \u0441\u043a\u0430\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044e, \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u044b\u043c \u043e\u0442\u0447\u0435\u0442\u0430\u043c \u0438 \u0431\u0435\u0441\u0448\u043e\u0432\u043d\u043e\u0439 \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u0438 \u0441 GitLab CI\/CD \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u043e\u0431\u043d\u0430\u0440\u0443\u0436\u0438\u0432\u0430\u0442\u044c \u0438 \u0443\u0441\u0442\u0440\u0430\u043d\u044f\u0442\u044c \u0443\u044f\u0437\u0432\u0438\u043c\u043e\u0441\u0442\u0438 \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u0438 \u043d\u0430 \u0440\u0430\u043d\u043d\u0435\u0439 \u0441\u0442\u0430\u0434\u0438\u0438, \u043f\u0440\u0435\u0436\u0434\u0435 \u0447\u0435\u043c \u043e\u043d\u0438 \u043f\u0440\u0438\u0432\u0435\u0434\u0443\u0442 \u043a \u0434\u043e\u0440\u043e\u0433\u043e\u0441\u0442\u043e\u044f\u0449\u0438\u043c \u043d\u0430\u0440\u0443\u0448\u0435\u043d\u0438\u044f\u043c.<\/p>\n<p>\u0418\u043d\u0442\u0435\u0433\u0440\u0438\u0440\u0443\u044f SAST \u0432 \u0432\u0430\u0448 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439 GitLab, \u0432\u044b \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0438\u0440\u0443\u0435\u0442\u0435 \u0441\u043a\u0430\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u0438, \u0441\u043d\u0438\u0436\u0430\u0435\u0442\u0435 \u0440\u0438\u0441\u043a\u0438 \u0438 \u0431\u0435\u0437 \u043e\u0441\u043e\u0431\u044b\u0445 \u0443\u0441\u0438\u043b\u0438\u0439 \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0432\u0430\u0435\u0442\u0435 \u0441\u043e\u0431\u043b\u044e\u0434\u0435\u043d\u0438\u0435 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u0439 \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u0438.<\/p>\n<hr\/>\n<p>\u0422\u0430\u043a\u0436\u0435 \u0432\u0430\u0436\u043d\u043e \u043e\u0442\u043c\u0435\u0442\u0438\u0442\u044c: \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0438 \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u044f GitLab SAST\u00a0\u2014\u00a0\u043b\u0438\u0448\u044c \u043e\u0434\u0438\u043d \u0438\u0437\u00a0\u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432 \u043a\u043e\u043c\u043f\u043b\u0435\u043a\u0441\u043d\u043e\u0433\u043e \u043f\u043e\u0434\u0445\u043e\u0434\u0430 \u043a\u00a0\u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u0438 \u0438 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0443 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438. \u041f\u043e\u043c\u0438\u043c\u043e \u0430\u043d\u0430\u043b\u0438\u0437\u0430 \u0438\u0441\u0445\u043e\u0434\u043d\u043e\u0433\u043e \u043a\u043e\u0434\u0430, DevOps\u2011\u043a\u043e\u043c\u0430\u043d\u0434\u0430\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0432\u044b\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0442\u044c \u043c\u043e\u043d\u0438\u0442\u043e\u0440\u0438\u043d\u0433, \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u043c\u0438\u043a\u0440\u043e\u0441\u0435\u0440\u0432\u0438\u0441\u0430\u043c\u0438, \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0438\u043d\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443 \u0438 \u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0441\u00a0CI\/CD.<\/p>\n<p>\u0427\u0442\u043e\u0431\u044b \u0433\u043b\u0443\u0431\u0436\u0435 \u0440\u0430\u0437\u043e\u0431\u0440\u0430\u0442\u044c\u0441\u044f \u0432\u00a0\u044d\u0442\u0438\u0445 \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0430\u0445, \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u043f\u0440\u0438\u0441\u043e\u0435\u0434\u0438\u043d\u0438\u0442\u044c\u0441\u044f \u043a\u00a0\u0441\u0435\u0440\u0438\u0438 <strong>\u0431\u0435\u0441\u043f\u043b\u0430\u0442\u043d\u044b\u0445<\/strong> \u043e\u0442\u043a\u0440\u044b\u0442\u044b\u0445 \u0443\u0440\u043e\u043a\u043e\u0432 \u043a\u0443\u0440\u0441\u0430 \u00abDevOps: \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0438 \u0438 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u044b\u00bb. \u0412\u0430\u0441 \u0436\u0434\u0443\u0442 \u0447\u0435\u0442\u044b\u0440\u0435 \u0437\u0430\u043d\u044f\u0442\u0438\u044f:<\/p>\n<ul>\n<li>\n<p><em>28\u00a0\u0430\u0432\u0433\u0443\u0441\u0442\u0430 \u0432 20:00<\/em>\u00a0\u2014 <a href=\"https:\/\/otus.pw\/lVCs\/\" rel=\"noopener noreferrer nofollow\">\u00ab\u041c\u043e\u043d\u0438\u0442\u043e\u0440\u0438\u043d\u0433 \u0438 \u0430\u043b\u0435\u0440\u0442\u0438\u043d\u0433 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u0441\u00a0\u043f\u043e\u043c\u043e\u0449\u044c\u044e Prometheus \u0438 Grafana\u00bb<\/a><\/p>\n<\/li>\n<li>\n<p><em>9\u00a0\u0441\u0435\u043d\u0442\u044f\u0431\u0440\u044f \u0432 20:00<\/em>\u00a0\u2014 <a href=\"https:\/\/otus.pw\/55iE\/\" rel=\"noopener noreferrer nofollow\">\u00abService Mesh: \u043a\u0430\u043a\u00a0\u043f\u0435\u0440\u0435\u0441\u0442\u0430\u0442\u044c \u0431\u0435\u0441\u043f\u043e\u043a\u043e\u0438\u0442\u044c\u0441\u044f \u0438 \u043d\u0430\u0447\u0430\u0442\u044c \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u043c\u0438\u043a\u0440\u043e\u0441\u0435\u0440\u0432\u0438\u0441\u0430\u043c\u0438\u00bb<\/a><\/p>\n<\/li>\n<li>\n<p><em>16\u00a0\u0441\u0435\u043d\u0442\u044f\u0431\u0440\u044f \u0432 20:00<\/em>\u00a0\u2014 <a href=\"https:\/\/otus.pw\/l7Jg\/\" rel=\"noopener noreferrer nofollow\">\u00ab\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 GitLab Runners. \u0425\u0430\u043a\u0438 \u043f\u043e\u00a0\u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0435 \u0438 \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u0438 \u0441\u0431\u043e\u0440\u043e\u043a \u043f\u0440\u043e\u0435\u043a\u0442\u043e\u0432\u00bb<\/a><\/p>\n<\/li>\n<li>\n<p><em>24\u00a0\u0441\u0435\u043d\u0442\u044f\u0431\u0440\u044f \u0432 20:00<\/em>\u00a0\u2014 <a href=\"https:\/\/otus.pw\/Omzw\/\" rel=\"noopener noreferrer nofollow\">\u00ab\u0410\u0432\u0442\u043e\u0432\u0435\u0431\u0438\u043d\u0430\u0440\u00a0\u2014 \u0418\u043d\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u043a\u0430\u043a\u00a0\u043a\u043e\u0434\u00bb<\/a><\/p>\n<\/li>\n<\/ul>\n<p>\u041a\u0440\u043e\u043c\u0435 \u0442\u043e\u0433\u043e, \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u043e <strong>\u0431\u0435\u0441\u043f\u043b\u0430\u0442\u043d\u043e\u0435<\/strong> <a href=\"https:\/\/otus.pw\/Dcj9\/\" rel=\"noopener noreferrer nofollow\">\u0432\u0441\u0442\u0443\u043f\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0435 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435<\/a>, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u0442 \u043e\u0446\u0435\u043d\u0438\u0442\u044c \u0432\u0430\u0448\u0438 \u0437\u043d\u0430\u043d\u0438\u044f \u0438 \u043d\u0430\u0432\u044b\u043a\u0438. <\/p>\n<p>\u0422\u0430\u043a\u0436\u0435, \u0435\u0441\u043b\u0438 \u0432\u0430\u043c \u0432\u0430\u0436\u043d\u043e \u043f\u043e\u043d\u044f\u0442\u044c, \u043a\u0430\u043a\u00a0\u043a\u0443\u0440\u0441 \u0432\u043e\u0441\u043f\u0440\u0438\u043d\u0438\u043c\u0430\u044e\u0442 \u0434\u0440\u0443\u0433\u0438\u0435 \u0443\u0447\u0430\u0441\u0442\u043d\u0438\u043a\u0438, \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u043e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u0442\u044c\u0441\u044f \u0441\u00a0<a href=\"https:\/\/otus.ru\/reviews\/course\/16%3A7\" rel=\"noopener noreferrer nofollow\"><strong>\u043e\u0442\u0437\u044b\u0432\u0430\u043c\u0438<\/strong><\/a>. \u042d\u0442\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u0442 \u0443\u0432\u0438\u0434\u0435\u0442\u044c, \u043a\u0430\u043a\u0438\u0435 \u0442\u0435\u043c\u044b \u043e\u043a\u0430\u0437\u0430\u043b\u0438\u0441\u044c \u043d\u0430\u0438\u0431\u043e\u043b\u0435\u0435 \u043f\u043e\u043b\u0435\u0437\u043d\u044b\u043c\u0438, \u043a\u0430\u043a\u00a0\u043f\u0440\u043e\u0445\u043e\u0434\u0438\u0442 \u043e\u0431\u0443\u0447\u0435\u043d\u0438\u0435 \u0438 \u0447\u0442\u043e\u00a0\u043e\u0442\u043c\u0435\u0447\u0430\u044e\u0442 \u0441\u043b\u0443\u0448\u0430\u0442\u0435\u043b\u0438 \u043f\u043e\u0441\u043b\u0435 \u043f\u0440\u043e\u0445\u043e\u0436\u0434\u0435\u043d\u0438\u044f \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b. <\/p>\n<\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/div>\n<p><!----><!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/939146\/\"> https:\/\/habr.com\/ru\/articles\/939146\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>\u0421\u0432\u043e\u0435\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0435 \u0432\u044b\u044f\u0432\u043b\u0435\u043d\u0438\u0435 \u0443\u044f\u0437\u0432\u0438\u043c\u043e\u0441\u0442\u0435\u0439 \u0432 \u043a\u043e\u0434\u0435 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043e\u0434\u043d\u043e\u0439 \u0438\u0437 \u0432\u0430\u0436\u043d\u0435\u0439\u0448\u0438\u0445 \u0437\u0430\u0434\u0430\u0447 \u043a\u043e\u043d\u0432\u0435\u0439\u0435\u0440\u0430 CI\/CD, \u0432\u0435\u0434\u044c \u0447\u0435\u043c \u0440\u0430\u043d\u044c\u0448\u0435 \u043c\u044b \u043e\u0431\u043d\u0430\u0440\u0443\u0436\u0438\u043c \u043e\u0448\u0438\u0431\u043a\u0443 \u0432 \u043a\u043e\u0434\u0435, \u0442\u0435\u043c \u0434\u0435\u0448\u0435\u0432\u043b\u0435 \u043d\u0430\u043c \u043e\u0431\u043e\u0439\u0434\u0435\u0442\u0441\u044f \u0435\u0435 \u0438\u0441\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435. \u0414\u043b\u044f \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u044d\u0442\u043e\u0439 \u0437\u0430\u0434\u0430\u0447\u0438 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u043e \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0445 \u0440\u0435\u0448\u0435\u043d\u0438\u0439. \u041d\u043e \u0435\u0441\u043b\u0438 \u043c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u043a\u043e\u043d\u0432\u0435\u0439\u0435\u0440 CI\/CD \u0442\u043e \u043d\u0430\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0438\u043d\u0442\u0435\u0433\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043d\u0430\u0448 \u0430\u043d\u0430\u043b\u0438\u0437\u0430\u0442\u043e\u0440 \u0432 \u044d\u0442\u043e\u0442 \u043f\u0440\u043e\u0446\u0435\u0441\u0441. \u041e\u0434\u043d\u0430\u043a\u043e, \u0432 GitLab \u0438\u043c\u0435\u0435\u0442\u0441\u044f \u0441\u0432\u043e\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u0434\u043b\u044f \u0430\u043d\u0430\u043b\u0438\u0437\u0430 \u0438\u0441\u0445\u043e\u0434\u043d\u043e\u0433\u043e \u043a\u043e\u0434\u0430. \u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u043c\u044b \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u043c GitLab SAST \u0434\u043b\u044f \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0433\u043e \u0430\u043d\u0430\u043b\u0438\u0437\u0430 \u0438\u0441\u0445\u043e\u0434\u043d\u043e\u0433\u043e \u043a\u043e\u0434\u0430 \u043d\u0430 \u043d\u0430\u043b\u0438\u0447\u0438\u0435 \u0443\u044f\u0437\u0432\u0438\u043c\u043e\u0441\u0442\u0435\u0439.<\/p>\n<h2>\u0413\u043e\u0442\u043e\u0432\u0438\u043c \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e<\/h2>\n<p>\u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u043d\u0430\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0432\u043a\u043b\u044e\u0447\u0438\u0442\u044c GitLab SAST \u0432 \u043d\u0430\u0448\u0435\u043c \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0438. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043d\u0443\u0436\u043d\u043e \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0439 \u0444\u0430\u0439\u043b \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 SAST \u0432 \u043f\u0430\u043f\u043a\u0435: ci\/SAST.gitlab-ci.yml.<\/p>\n<pre><code class=\"yaml\">variables:   SECURE_ANALYZERS_PREFIX: \"$CI_TEMPLATE_REGISTRY_HOST\/security-products\"   SAST_IMAGE_SUFFIX: \"\"   SAST_EXCLUDED_ANALYZERS: \"\"   DEFAULT_SAST_EXCLUDED_PATHS: \"\"   SAST_EXCLUDED_PATHS: \"$DEFAULT_SAST_EXCLUDED_PATHS\"   SCAN_KUBERNETES_MANIFESTS: \"false\"  sast:   extends: .sast   stage: sast   artifacts:     paths:       - gl-sast-report.json     expire_in: 1 day     access: 'developer'     reports:       sast: gl-sast-report.json   rules:     - when: never   variables:     SEARCH_MAX_DEPTH: 4   script:     - echo \"$CI_JOB_NAME is used for configuration only\"<\/code><\/pre>\n<p>\u041c\u044b \u0431\u0443\u0434\u0435\u043c \u043f\u043e\u0441\u0442\u0435\u043f\u0435\u043d\u043d\u043e \u0437\u0430\u043f\u043e\u043b\u043d\u044f\u0442\u044c \u044d\u0442\u043e\u0442 \u0444\u0430\u0439\u043b \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u044b\u043c \u0434\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u0431\u044b\u043b\u043e \u043f\u043e\u043d\u044f\u0442\u043d\u043e \u043a\u0430\u043a\u043e\u0439 \u0440\u0430\u0437\u0434\u0435\u043b \u0444\u0430\u0439\u043b\u0430 \u0437\u0430 \u0447\u0442\u043e \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442. \u0421\u0435\u0439\u0447\u0430\u0441 \u043c\u044b \u043e\u0431\u044a\u044f\u0432\u0438\u043b\u0438 \u0440\u044f\u0434 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445 \u0438 \u0440\u0430\u0437\u043c\u0435\u0441\u0442\u0438\u043b\u0438 \u0440\u0430\u0437\u0434\u0435\u043b SAST. \u0414\u0430\u043b\u0435\u0435 \u043d\u0430\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c \u0430\u043d\u0430\u043b\u0438\u0437\u0430\u0442\u043e\u0440\u044b SAST, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c<\/p>\n<p>\u041d\u0430\u0447\u043d\u0435\u043c \u0441 GitLab Advanced SAST. \u042d\u0442\u043e\u0442 \u0430\u043d\u0430\u043b\u0438\u0437\u0430\u0442\u043e\u0440 \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u043b\u044f Python, Go, Java, JavaScript, TypeScript. \u041d\u043e \u0437\u0434\u0435\u0441\u044c \u0435\u0441\u0442\u044c \u0432\u0430\u0436\u043d\u044b\u0439 \u043d\u044e\u0430\u043d\u0441 &#8212; GitLab Advanced SAST \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u0438\u0441\u043a\u043b\u044e\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0434\u043b\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u0443\u0440\u043e\u0432\u043d\u044f Ultimate. \u0415\u0441\u043b\u0438 \u0432\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0435 \u0443\u0440\u043e\u0432\u0435\u043d\u044c Free \u0438\u043b\u0438 Premium, \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u0442\u0435 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0430\u043d\u0430\u043b\u0438\u0437\u0430\u0442\u043e\u0440\u043e\u0432 SAST \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e.<\/p>\n<p>\u0412 \u0444\u0430\u0439\u043b SAST.gitlab-ci.yml \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0435:<\/p>\n<pre><code class=\"yaml\">gitlab-advanced-sast:   extends: .sast-analyzer   image:     name: \"$SAST_ANALYZER_IMAGE\"   variables:     SEARCH_MAX_DEPTH: 20     SAST_ANALYZER_IMAGE: \"$SECURE_ANALYZERS_PREFIX\/gitlab-advanced-sast:1$SAST_IMAGE_SUFFIX\"   rules:     - if: $SAST_DISABLED == 'true' || $SAST_DISABLED == '1'       when: never     - if: $SAST_EXCLUDED_ANALYZERS =~ \/gitlab-advanced-sast\/       when: never     - if: $GITLAB_ADVANCED_SAST_ENABLED != 'true'       when: never     - exists:         - '**\/*.py'         - '**\/*.go'         - '**\/*.java'         - '**\/*.js'         - '**\/*.ts'<\/code><\/pre>\n<p>\u0414\u043b\u044f \u044f\u0437\u044b\u043a\u043e\u0432 PHP, Swift, Scala, Ruby \u043c\u043e\u0436\u043d\u043e \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0430\u043d\u0430\u043b\u0438\u0437\u0430\u0442\u043e\u0440\u043e\u043c Semgrep SAST \u0438 \u0442\u043e\u0433\u0434\u0430 \u0432 \u0444\u0430\u0439\u043b \u043d\u0443\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c:<\/p>\n<pre><code class=\"yaml\">semgrep-sast:   extends: .sast-analyzer   image:     name: \"$SAST_ANALYZER_IMAGE\"   variables:     SAST_ANALYZER_IMAGE: \"$SECURE_ANALYZERS_PREFIX\/semgrep:5$SAST_IMAGE_SUFFIX\"   rules:     - exists:         - '**\/*.php'         - '**\/*.swift'         - '**\/*.scala'         - '**\/*.rb'<\/code><\/pre>\n<h2>\u0411\u043e\u0440\u0435\u043c\u0441\u044f \u0437\u0430 \u0447\u0438\u0442\u0430\u0435\u043c\u043e\u0441\u0442\u044c \u043e\u0442\u0447\u0435\u0442\u043e\u0432<\/h2>\n<p>\u041f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e GitLab SAST \u0432\u044b\u0434\u0430\u0435\u0442 \u043e\u0442\u0447\u0435\u0442\u044b \u0432 \u0444\u043e\u0440\u043c\u0430\u0442\u0435 JSON, \u043d\u043e \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u0443\u0435\u043c \u0438\u0445 \u0432 HTML \u0438 JUnit XML \u0434\u043b\u044f \u043b\u0443\u0447\u0448\u0435\u0439 \u043d\u0430\u0433\u043b\u044f\u0434\u043d\u043e\u0441\u0442\u0438.<\/p>\n<p>\u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043d\u0430\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0432 \u0444\u0430\u0439\u043b \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0435:<\/p>\n<pre><code class=\"yaml\">sast_to_html:   extends: .sast-analyzer   image: python:3.9   script:     - cp gl-sast-report.json ci\/     - cd ci     - python3 convert_sast_to_html.py gl-sast-report.json index.html     - python3 junit_convertor.py gl-sast-report.json report.xml   artifacts:     paths:       - ci\/index.html       - ci\/report.xml       - gl-sast-report.json     reports:       junit: ci\/report.xml            expire_in: 1 day<\/code><\/pre>\n<p>\u0412 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u043d\u043e\u043c YAML \u043c\u043e\u0436\u043d\u043e \u0437\u0430\u043c\u0435\u0442\u0438\u0442\u044c \u0443\u043f\u043e\u043c\u0438\u043d\u0430\u043d\u0438\u0435 \u0441\u043a\u0440\u0438\u043f\u0442\u043e\u0432 \u043d\u0430 Python. \u0427\u0442\u043e\u0431\u044b \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0442\u044c \u0432\u0438\u0437\u0443\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u0443\u044f\u0437\u0432\u0438\u043c\u043e\u0441\u0442\u0435\u0439 \u0432 \u0432\u0438\u0434\u0436\u0435\u0442\u0430\u0445 GitLab Merge Request, \u043c\u044b \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u0441\u043a\u0440\u0438\u043f\u0442  \u0434\u043b\u044f \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u043e\u0442\u0447\u0435\u0442\u0430 JSON SAST \u0432 \u0444\u043e\u0440\u043c\u0430\u0442 JUnit:<\/p>\n<pre><code class=\"python\">import json import sys import xml.etree.ElementTree as ET  def convert_json_to_junit(json_file, output_file):     try:         with open(json_file, \"r\") as f:             json_data = json.load(f)                  testsuites = ET.Element(\"testsuites\")         testsuite = ET.SubElement(testsuites, \"testsuite\", name=\"Security Scan\", tests=str(len(json_data[\"vulnerabilities\"])), failures=str(len(json_data[\"vulnerabilities\"])))                  for vulnerability in json_data[\"vulnerabilities\"]:             test_case = ET.SubElement(testsuite, \"testcase\", name=vulnerability[\"name\"], classname=vulnerability[\"category\"])             failure_message = f\"{vulnerability['description']}\\nSeverity: {vulnerability['severity']}\\n\"             failure_message += f\"File: {vulnerability['location']['file']} (Line {vulnerability['location']['start_line']})\\n\"                          if \"mitigation\" in vulnerability:                 failure_message += f\"Mitigation: {vulnerability['mitigation']}\\n\"                          failure_element = ET.SubElement(test_case, \"failure\", message=f\"{vulnerability['name']} detected\")             failure_element.text = failure_message                  tree = ET.ElementTree(testsuites)         ET.indent(tree, space=\"  \")         tree.write(output_file, encoding=\"utf-8\", xml_declaration=True)                  print(f\"JUnit report generated: {output_file}\")     except Exception as e:         print(f\"Error: {e}\")         sys.exit(1)  if __name__ == \"__main__\":     if len(sys.argv) != 3:         print(\"Usage: python convert_json_to_junit.py &lt;input_json_file&gt; &lt;output_xml_file&gt;\")         sys.exit(1)          json_file = sys.argv[1]     output_file = sys.argv[2]          convert_json_to_junit(json_file, output_file)<\/code><\/pre>\n<p>\u0410 \u0437\u0430\u0442\u0435\u043c \u043c\u044b \u0445\u043e\u0442\u0438\u043c \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u043d\u0430\u0448 \u0438\u0442\u043e\u0433\u043e\u0432\u044b\u0439 \u043e\u0442\u0447\u0435\u0442 \u043e \u043d\u0430\u0439\u0434\u0435\u043d\u043d\u044b\u0445 \u0443\u044f\u0437\u0432\u0438\u043c\u043e\u0441\u0442\u044f\u0445 \u0432 \u0444\u043e\u0440\u043c\u0430\u0442\u0435 HTML. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043d\u0430\u043c \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0432\u0442\u043e\u0440\u043e\u0439 \u0441\u043a\u0440\u0438\u043f\u0442.<\/p>\n<pre><code class=\"python\">import json import sys  def parse_json_to_html(json_data):     vulnerabilities = json_data.get('vulnerabilities', [])      html = '''     &lt;html&gt;     &lt;head&gt;         &lt;title&gt;SAST Report&lt;\/title&gt;         &lt;style&gt;             body {                 font-family: 'Arial', sans-serif;                 background-color: #f3f4f6;                 margin: 0;                 padding: 30px;             }              h2 {                 color: #2c3e50;                 text-align: center;                 font-size: 28px;                 font-weight: 600;                 margin-bottom: 20px;             }              table {                 border-collapse: collapse;                 width: 100%;                 box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);                 background: linear-gradient(135deg, #f0f8ff, #fdfdfd);                 border-radius: 12px;                 overflow: hidden;             }              th, td {                 padding: 15px;                 text-align: left;                 font-size: 14px;             }              th {                 background-color: #34495e;                 color: white;                 text-transform: uppercase;                 font-size: 16px;             }              td {                 background-color: #ecf0f1;                 color: #2c3e50;                 border-bottom: 1px solid #ddd;             }              tr:nth-child(odd) td {                 background-color: #f9fafb;             }              tr:nth-child(even) td {                 background-color: #ffffff;             }              tr:hover td {                 background-color: #dcdfe1;                 cursor: pointer;                 transition: background-color 0.3s ease;             }              .severity-high {                 background-color: #e74c3c; \/* Red for High *\/                 padding: 5px 10px;                 border-radius: 5px;                 text-align: center;                 font-weight: bold;                 color: white;             }              .severity-medium {                 background-color: #f39c12; \/* Orange for Medium *\/                 padding: 5px 10px;                 border-radius: 5px;                 text-align: center;                 font-weight: bold;                 color: white;             }              .severity-low {                 background-color: #f1c40f; \/* Yellow for Low *\/                 padding: 5px 10px;                 border-radius: 5px;                 text-align: center;                 font-weight: bold;                 color: white;             }          &lt;\/style&gt;     &lt;\/head&gt;     &lt;body&gt;         &lt;h2&gt;GitLab SAST Report&lt;\/h2&gt;         &lt;table&gt;             &lt;tr&gt;                 &lt;th&gt;Name&lt;\/th&gt;                 &lt;th&gt;Description&lt;\/th&gt;                 &lt;th&gt;Severity&lt;\/th&gt;                 &lt;th&gt;File&lt;\/th&gt;                 &lt;th&gt;Line&lt;\/th&gt;             &lt;\/tr&gt;     '''      for item in vulnerabilities:         severity = item.get('severity', '').strip().lower()           severity_class = ''                  if severity == 'high':             severity_class = 'severity-high'         elif severity == 'medium':             severity_class = 'severity-medium'         elif severity == 'low':             severity_class = 'severity-low'         else:             severity_class = 'severity-low'                    html += f'''             &lt;tr&gt;                 &lt;td&gt;{item.get('name', '')}&lt;\/td&gt;                 &lt;td&gt;{item.get('description', '')}&lt;\/td&gt;                 &lt;td class=\"{severity_class}\"&gt;{item.get('severity', '')}&lt;\/td&gt;                 &lt;td&gt;{item.get('location', {}).get('file', '')}&lt;\/td&gt;                 &lt;td&gt;{item.get('location', {}).get('start_line', '')}&lt;\/td&gt;             &lt;\/tr&gt;         '''      html += '''         &lt;\/table&gt;     &lt;\/body&gt;     &lt;\/html&gt;     '''      return html  def main():     if len(sys.argv) != 3:         print(\"Usage: python convert_sast_to_html.py &lt;input_json_file&gt; &lt;output_html_file&gt;\")         sys.exit(1)      input_json_file = sys.argv[1]     output_html_file = sys.argv[2]      with open(input_json_file, 'r') as file:         json_data = json.load(file)      html_content = parse_json_to_html(json_data)      with open(output_html_file, 'w') as file:         file.write(html_content)  if __name__ == \"__main__\":     main()<\/code><\/pre>\n<p>\u00a0\u0412 \u0438\u0442\u043e\u0433\u0435, \u043e\u0442\u0447\u0435\u0442 JUnit XML \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0434\u043b\u044f \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u043e\u0432 SAST \u0432 \u0432\u0438\u0434\u0436\u0435\u0442\u0435 Merge Request.<\/p>\n<figure class=\"full-width\"><\/figure>\n<p>\u0410 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435<\/p>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-471775","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/471775","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=471775"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/471775\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=471775"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=471775"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=471775"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}