├── .media ├── 00_DevSecOps_Process.png ├── 01_AI-Arch.png ├── 01_AI-Arch_2.png ├── 02_AI-in-build-steps.png ├── 02_AI-in-build-steps_2.png ├── 03_idef0-devops-process-habr.png ├── 04_PlantUML_Docker_Build.png ├── 05_PlantUML_Ci_Process.png ├── 06_TeamCity_CI_Process.png ├── 07_Docker_in_Artifactory_v1.png ├── 08_Docker_in_Artifactory_v2.png ├── 09_Docker_in_Artifactory_v3.png ├── 10_AISA_args_example.png ├── 11_Table_of_AISA_args.png ├── 12_GitLab_CI_Templates_Common.png ├── 13_GitLab_CI_Template_Custom.png ├── 14_GitLab_CI_Template_include_example.png ├── 15_GitLab_CI_log.png ├── 16_Project_settings_file.png ├── 17_TeamCity_MetaRunner_Windows_xml.png ├── 18_TeamCity_MetaRunner_Linux_view.png ├── 19_TeamCity_MetaRunner_log.png ├── 20_UI_Dashboard.png ├── 21_UI_Agents.png ├── 22_Report_Preview_html.png ├── 23_Report_Preview_json.png ├── 24_SecurityGates_spec.png ├── 24_SecurityGates_spec_2.png ├── 25_ai-sec-gates-rules-1.png ├── 26_ai-sec-gates-rules-2.png ├── 27_AI-Information-Mode.png ├── 28_AI-Lock-Mode.png ├── 29_AI-Strictest-Mode.png ├── Readme.png ├── Report.html ├── Report.json ├── ptaiee_adminguide_en.pdf └── ptaiee_adminguide_ru.pdf ├── AIE_Server_installation ├── AI-one-click-install.ps1 └── README.md ├── AISA_Docker ├── aisa-linux │ ├── Dockerfile │ └── docker_build_data │ │ ├── applications │ │ ├── aisa-codequality.py │ │ ├── aisa-set-policy.py │ │ └── aisa-set-settings.py │ │ └── config │ │ └── .gitkeep └── aisa-windows │ ├── Dockerfile │ └── docker_build_data │ ├── certs │ └── import-certs.ps1 │ ├── create-json │ └── create-json.ps1 │ ├── download-and-unpack │ └── download-and-unpack-auth.ps1 │ └── install-web │ └── install-web.ps1 ├── GitLab_templates ├── AI.Cli.Plugin │ ├── AI-Plugin-dockerbuild │ │ ├── .gitlab-ci.yml │ │ └── Docker │ │ │ ├── Dockerfile │ │ │ └── docker_build_data │ │ │ ├── applications │ │ │ ├── codequality.py │ │ │ ├── set-policy.py │ │ │ └── set-settings.py │ │ │ └── config │ │ │ └── .gitkeep │ ├── AI-Templates │ │ └── AI-basic-template │ │ │ ├── AI-Run-in-parallel.yml │ │ │ ├── AI-Run-in-parallel │ │ │ ├── AI-Information-Mode.yml │ │ │ ├── AI-Lock-Mode.yml │ │ │ └── AI-Strictest-Mode.yml │ │ │ ├── AI-Run-in-sequence.yml │ │ │ └── download-dependencies.yml │ ├── README.md │ └── demo-example.gitlab-ci.yml ├── create_project.yml ├── customer-full │ ├── .AI │ │ ├── .gitlab-ci.ai.png │ │ ├── .gitlab-ci.ai.yml │ │ ├── AI-Information-Mode.png │ │ ├── AI-Information-Mode.yml │ │ ├── AI-Lock-Mode.png │ │ ├── AI-Lock-Mode.yml │ │ ├── AI-Strictest-Mode.png │ │ └── AI-Strictest-Mode.yml │ └── .gitlab-ci.yml ├── customer-lite │ ├── .AI │ │ └── AI-scan.yml │ └── .gitlab-ci.yml ├── default_project_files │ ├── default_policy.json │ ├── default_project.aiproj │ └── default_project_with_comments.aiproj ├── example_1.yml ├── example_2.yml ├── existing_project.yml ├── no-wait-existing_project.yml ├── no-wait-non-existent_project.yml └── non-existent_project.yml ├── LICENSE ├── README.md └── TeamCity_meta-runners ├── MetaRunnerAisaRunLinux.xml └── MetaRunnerAisaRunWindows.xml /.media/00_DevSecOps_Process.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devopshq/dohq-ai-best-practices/563f94b3b0371b25305ed03349c42564beaac92b/.media/00_DevSecOps_Process.png -------------------------------------------------------------------------------- /.media/01_AI-Arch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devopshq/dohq-ai-best-practices/563f94b3b0371b25305ed03349c42564beaac92b/.media/01_AI-Arch.png -------------------------------------------------------------------------------- /.media/01_AI-Arch_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devopshq/dohq-ai-best-practices/563f94b3b0371b25305ed03349c42564beaac92b/.media/01_AI-Arch_2.png -------------------------------------------------------------------------------- /.media/02_AI-in-build-steps.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devopshq/dohq-ai-best-practices/563f94b3b0371b25305ed03349c42564beaac92b/.media/02_AI-in-build-steps.png -------------------------------------------------------------------------------- /.media/02_AI-in-build-steps_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devopshq/dohq-ai-best-practices/563f94b3b0371b25305ed03349c42564beaac92b/.media/02_AI-in-build-steps_2.png -------------------------------------------------------------------------------- /.media/03_idef0-devops-process-habr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devopshq/dohq-ai-best-practices/563f94b3b0371b25305ed03349c42564beaac92b/.media/03_idef0-devops-process-habr.png -------------------------------------------------------------------------------- /.media/04_PlantUML_Docker_Build.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devopshq/dohq-ai-best-practices/563f94b3b0371b25305ed03349c42564beaac92b/.media/04_PlantUML_Docker_Build.png -------------------------------------------------------------------------------- /.media/05_PlantUML_Ci_Process.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devopshq/dohq-ai-best-practices/563f94b3b0371b25305ed03349c42564beaac92b/.media/05_PlantUML_Ci_Process.png -------------------------------------------------------------------------------- /.media/06_TeamCity_CI_Process.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devopshq/dohq-ai-best-practices/563f94b3b0371b25305ed03349c42564beaac92b/.media/06_TeamCity_CI_Process.png -------------------------------------------------------------------------------- /.media/07_Docker_in_Artifactory_v1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devopshq/dohq-ai-best-practices/563f94b3b0371b25305ed03349c42564beaac92b/.media/07_Docker_in_Artifactory_v1.png -------------------------------------------------------------------------------- /.media/08_Docker_in_Artifactory_v2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devopshq/dohq-ai-best-practices/563f94b3b0371b25305ed03349c42564beaac92b/.media/08_Docker_in_Artifactory_v2.png -------------------------------------------------------------------------------- /.media/09_Docker_in_Artifactory_v3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devopshq/dohq-ai-best-practices/563f94b3b0371b25305ed03349c42564beaac92b/.media/09_Docker_in_Artifactory_v3.png -------------------------------------------------------------------------------- /.media/10_AISA_args_example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devopshq/dohq-ai-best-practices/563f94b3b0371b25305ed03349c42564beaac92b/.media/10_AISA_args_example.png -------------------------------------------------------------------------------- /.media/11_Table_of_AISA_args.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devopshq/dohq-ai-best-practices/563f94b3b0371b25305ed03349c42564beaac92b/.media/11_Table_of_AISA_args.png -------------------------------------------------------------------------------- /.media/12_GitLab_CI_Templates_Common.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devopshq/dohq-ai-best-practices/563f94b3b0371b25305ed03349c42564beaac92b/.media/12_GitLab_CI_Templates_Common.png -------------------------------------------------------------------------------- /.media/13_GitLab_CI_Template_Custom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devopshq/dohq-ai-best-practices/563f94b3b0371b25305ed03349c42564beaac92b/.media/13_GitLab_CI_Template_Custom.png -------------------------------------------------------------------------------- /.media/14_GitLab_CI_Template_include_example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devopshq/dohq-ai-best-practices/563f94b3b0371b25305ed03349c42564beaac92b/.media/14_GitLab_CI_Template_include_example.png -------------------------------------------------------------------------------- /.media/15_GitLab_CI_log.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devopshq/dohq-ai-best-practices/563f94b3b0371b25305ed03349c42564beaac92b/.media/15_GitLab_CI_log.png -------------------------------------------------------------------------------- /.media/16_Project_settings_file.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devopshq/dohq-ai-best-practices/563f94b3b0371b25305ed03349c42564beaac92b/.media/16_Project_settings_file.png -------------------------------------------------------------------------------- /.media/17_TeamCity_MetaRunner_Windows_xml.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devopshq/dohq-ai-best-practices/563f94b3b0371b25305ed03349c42564beaac92b/.media/17_TeamCity_MetaRunner_Windows_xml.png -------------------------------------------------------------------------------- /.media/18_TeamCity_MetaRunner_Linux_view.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devopshq/dohq-ai-best-practices/563f94b3b0371b25305ed03349c42564beaac92b/.media/18_TeamCity_MetaRunner_Linux_view.png -------------------------------------------------------------------------------- /.media/19_TeamCity_MetaRunner_log.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devopshq/dohq-ai-best-practices/563f94b3b0371b25305ed03349c42564beaac92b/.media/19_TeamCity_MetaRunner_log.png -------------------------------------------------------------------------------- /.media/20_UI_Dashboard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devopshq/dohq-ai-best-practices/563f94b3b0371b25305ed03349c42564beaac92b/.media/20_UI_Dashboard.png -------------------------------------------------------------------------------- /.media/21_UI_Agents.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devopshq/dohq-ai-best-practices/563f94b3b0371b25305ed03349c42564beaac92b/.media/21_UI_Agents.png -------------------------------------------------------------------------------- /.media/22_Report_Preview_html.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devopshq/dohq-ai-best-practices/563f94b3b0371b25305ed03349c42564beaac92b/.media/22_Report_Preview_html.png -------------------------------------------------------------------------------- /.media/23_Report_Preview_json.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devopshq/dohq-ai-best-practices/563f94b3b0371b25305ed03349c42564beaac92b/.media/23_Report_Preview_json.png -------------------------------------------------------------------------------- /.media/24_SecurityGates_spec.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devopshq/dohq-ai-best-practices/563f94b3b0371b25305ed03349c42564beaac92b/.media/24_SecurityGates_spec.png -------------------------------------------------------------------------------- /.media/24_SecurityGates_spec_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devopshq/dohq-ai-best-practices/563f94b3b0371b25305ed03349c42564beaac92b/.media/24_SecurityGates_spec_2.png -------------------------------------------------------------------------------- /.media/25_ai-sec-gates-rules-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devopshq/dohq-ai-best-practices/563f94b3b0371b25305ed03349c42564beaac92b/.media/25_ai-sec-gates-rules-1.png -------------------------------------------------------------------------------- /.media/26_ai-sec-gates-rules-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devopshq/dohq-ai-best-practices/563f94b3b0371b25305ed03349c42564beaac92b/.media/26_ai-sec-gates-rules-2.png -------------------------------------------------------------------------------- /.media/27_AI-Information-Mode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devopshq/dohq-ai-best-practices/563f94b3b0371b25305ed03349c42564beaac92b/.media/27_AI-Information-Mode.png -------------------------------------------------------------------------------- /.media/28_AI-Lock-Mode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devopshq/dohq-ai-best-practices/563f94b3b0371b25305ed03349c42564beaac92b/.media/28_AI-Lock-Mode.png -------------------------------------------------------------------------------- /.media/29_AI-Strictest-Mode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devopshq/dohq-ai-best-practices/563f94b3b0371b25305ed03349c42564beaac92b/.media/29_AI-Strictest-Mode.png -------------------------------------------------------------------------------- /.media/Readme.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devopshq/dohq-ai-best-practices/563f94b3b0371b25305ed03349c42564beaac92b/.media/Readme.png -------------------------------------------------------------------------------- /.media/ptaiee_adminguide_en.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devopshq/dohq-ai-best-practices/563f94b3b0371b25305ed03349c42564beaac92b/.media/ptaiee_adminguide_en.pdf -------------------------------------------------------------------------------- /.media/ptaiee_adminguide_ru.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devopshq/dohq-ai-best-practices/563f94b3b0371b25305ed03349c42564beaac92b/.media/ptaiee_adminguide_ru.pdf -------------------------------------------------------------------------------- /AIE_Server_installation/README.md: -------------------------------------------------------------------------------- 1 | # PT AI Install Wizard 2 | Автоматический установщик для анализатора кода Positive Technologies Application Inspector Enterprise. 3 | 4 | Раздел документации и скрипты инсталляции PT AI сопровождает Aleksandr Khudyshkin (AKhudyshkin@ptsecurity.com, [@alexkhudyshkin](https://github.com/alexkhudyshkin)). Для получения дистрибутива запросите бесплатный пилот по ссылке https://www.ptsecurity.com/ru-ru/products/ai/#free-demo. 5 | 6 | 7 | Убедитесь, что ваш сервер соотвествует рекомендуемым системным требованиям 8 | 9 | | PT AI Enterprise Server | PT AI Enterprise Agent | 10 | |-------------------------------------------------------------|-----------------------------------------------------------------------------| 11 | | Процессор Intel Core i7 с частотой 3,2 ГГц или аналоги | Процессор Intel Core i7 с частотой 3,2 ГГц или аналоги | 12 | | От 8 ГБ оперативной памяти | От 16 ГБ оперативной памяти | 13 | | Сетевой адаптер от 100 Мбит/с | Сетевой адаптер от 100 Мбит/с | 14 | | От 200 ГБ на жестком диске | От 100 ГБ на жестком диске | 15 | | 64-разрядная версия Windows Server 2016 и выше | 64-разрядная версия Windows Server 2016 и выше | 16 | | Браузер: Mozilla Firefox 46 и выше, Google Chrome 50 и выше | | 17 | | Средство автоматизации Windows PowerShell версии 5.0 и выше | | 18 | 19 | Для запуска: 20 | - Выполнить вход в Windows под учётной записью с правами администратора. 21 | - Дополнительно установить следующие программы: 22 | 23 | | Программное обеспечение | Ссылка на скачивание | 24 | |--------------------------------------------------|------------------------------------------------------------------------------------------| 25 | | Win64 OpenSSL v1.1.1h Light (если генерируются самоподписанные сертификаты) | https://slproweb.com/products/Win32OpenSSL.html | 26 | | VC Redist x64 (если генерируются самоподписанные сертификаты) | https://aka.ms/vs/16/release/vc_redist.x64.exe | 27 | | .NET Framework 4.8 (Windows Server 2012 R2 only) | https://dotnet.microsoft.com/download/dotnet-framework/thank-you/net48-offline-installer | 28 | | KB3191564 (Windows Server 2012 R2 only) | http://www.catalog.update.microsoft.com/Search.aspx?q=3191564 | 29 | 30 | - Запустить Powershell с правами администратора. 31 | - Запустить скрипт инсталляции, пример запуска: 32 | ```powershell 33 | .\AI-one-click-install.ps1 -aiepath C:\Users\Administrator\Downloads\AIE 34 | # aiepath - путь до каталога с дистрибутивом AI (там где папки aic/aiv/aie) 35 | ``` 36 | ```powershell 37 | # Если скрипт не запускается из-за ограничений доменной политики, выполните следующую команду 38 | Set-ExecutionPolicy Unrestricted Process 39 | ``` 40 | -------------------------------------------------------------------------------- /AISA_Docker/aisa-linux/Dockerfile: -------------------------------------------------------------------------------- 1 | # (c) DevOpsHQ, 2021 2 | 3 | FROM mcr.microsoft.com/dotnet/core/aspnet:3.1.6-bionic 4 | 5 | # You must define some specific variables: 6 | 7 | # All Access tokens are here: https:///ui/admin/settings 8 | ARG AISA_TOKEN 9 | 10 | # URL of Application Inspector Enterprise Server 11 | ARG AISA_URI 12 | 13 | COPY docker_build_data/config/ /tmp/aisa_config/ 14 | COPY docker_build_data/applications/ /usr/src/app/ 15 | 16 | # INSTALL EXTERNAL PACKAGES 17 | RUN set -ex && apt-get update && apt-get install -y --no-install-recommends \ 18 | wget libunwind8-dev liblttng-ust0 cmake tree jq git tar xz-utils gcc make locales openssl ssh openssh-server openssh-client gnupg && \ 19 | apt-get clean && \ 20 | rm -rf /var/lib/apt/lists/* 21 | 22 | # INSTALL PYTHON 3.7 23 | RUN mkdir /tmp/py3.7_build && \ 24 | cd /tmp/py3.7_build && \ 25 | apt-get update && \ 26 | apt-get install --no-install-recommends -y libssl-dev libsqlite3-dev zlib1g-dev libffi-dev && \ 27 | apt-get clean && \ 28 | wget -c "https://www.python.org/ftp/python/3.7.7/Python-3.7.7.tgz" && \ 29 | tar xf "Python-3.7.7.tgz" && \ 30 | cd "Python-3.7.7" && \ 31 | LDFLAGS="-Wl,-rpath,/usr/local/lib" ./configure --enable-optimizations --enable-shared --with-ensurepip=install && \ 32 | make -j$(nproc) build_all && \ 33 | make altinstall && \ 34 | apt-get remove -y libssl-dev libsqlite3-dev zlib1g-dev libffi-dev && \ 35 | cd - && \ 36 | rm -rf /tmp/py3.7_build /var/lib/apt/lists/* 37 | 38 | RUN ln -s python3.7 /usr/local/bin/python && \ 39 | ln -s python3.7 /usr/local/bin/python3 && \ 40 | python --version 41 | 42 | RUN python -m pip install --upgrade pip && \ 43 | python -m pip install --upgrade virtualenv pip-review texttable psycopg2-binary psycopg2 && \ 44 | pip-review --auto 45 | 46 | RUN pip3 install pyyaml requests crosspm texttable psycopg2-binary psycopg2 47 | 48 | # INSTALL AISA HELP TOOLS 49 | RUN set -ex && \ 50 | cd /usr/src/app/ && \ 51 | chmod +x /usr/src/app/aisa-codequality.py && \ 52 | chmod +x /usr/src/app/aisa-set-policy.py && \ 53 | chmod +x /usr/src/app/aisa-set-settings.py && \ 54 | ln -s /usr/src/app/aisa-codequality.py /usr/bin/aisa-codequality && \ 55 | ln -s /usr/src/app/aisa-set-policy.py /usr/bin/aisa-set-policy && \ 56 | ln -s /usr/src/app/aisa-set-settings.py /usr/bin/aisa-set-settings 57 | 58 | # INSTALL CERT 59 | RUN set -ex && \ 60 | cd /tmp/aisa_config/ ;\ 61 | cp *.crt /usr/local/share/ca-certificates/ ;\ 62 | update-ca-certificates 63 | 64 | # INSTALL AISA 65 | RUN set -ex && \ 66 | wget -qO - https://update.ptsecurity.com/packages/PT-public.gpg | apt-key add - && \ 67 | echo deb https://update.ptsecurity.com/packages/deb/AI.Shell/release all non-free >> /etc/apt/sources.list && \ 68 | apt update && apt install aisa 69 | 70 | # GENERATE en_US LOCALE 71 | RUN set -ex; \ 72 | echo "en_US.UTF-8 UTF-8" >/etc/locale.gen; \ 73 | locale-gen 74 | 75 | # SET ENVIRONMENT 76 | ENV LANG="en_US.UTF-8" \ 77 | LANGUAGE="en_US:en" \ 78 | LC_ALL="en_US.UTF-8" 79 | 80 | RUN rm -rf /tmp/aisa_config 81 | 82 | # SET AISA SETTINGS 83 | RUN aisa --set-settings -u ${AISA_URI} -t ${AISA_TOKEN} 84 | -------------------------------------------------------------------------------- /AISA_Docker/aisa-linux/docker_build_data/applications/aisa-codequality.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # (c) DevOpsHQ, 2021 4 | 5 | import os 6 | import requests 7 | import json 8 | import argparse 9 | import yaml 10 | import texttable 11 | from pathlib import Path 12 | 13 | 14 | def teamcity_open_block(): 15 | print() 16 | print("##teamcity[blockOpened name='Vulnerabilities table']") 17 | 18 | 19 | def teamcity_close_block(): 20 | print("##teamcity[blockClosed name='Vulnerabilities table']") 21 | print() 22 | 23 | 24 | def rename_html_report(input_folder, CI): 25 | files = [] 26 | print(f'INFO - Try to rename html report to "aie_report.html"') 27 | try: 28 | dir_files = os.listdir(input_folder) 29 | for f in [os.path.join(input_folder, basename) for basename in dir_files]: 30 | if '.html' in f: 31 | files.append(f) 32 | if len(files) > 0: 33 | file = max(files, key=os.path.getctime) 34 | old_file = os.path.join(file) 35 | CI.html_report = os.path.join(input_folder, "aie_report.html") 36 | os.rename(old_file, CI.html_report) 37 | print(f'INFO - {CI.html_report} was renamed successfully') 38 | else: 39 | print('WARNING - AI html-report not found.') 40 | CI.html_report = None 41 | 42 | except IndexError as e: 43 | try: 44 | print(f'\nWARNING - Report in {input_folder} directory not found.') 45 | except KeyError as ke: 46 | print('\nWARNING - Report directory not found') 47 | except FileNotFoundError as e: 48 | print('\nWARNING - Report directory not found') 49 | exit(0) 50 | 51 | 52 | def set_security_rules(items_info, items_minor, items_major, items_critical, items_blocker, CI, settings): 53 | if settings is None: 54 | mapping = {'info': 'Potential', 55 | 'minor': 'Low', 56 | 'major': 'Medium', 57 | 'critical': 'High', 58 | 'blocker': ''} 59 | settings = {'info': 0, 60 | 'minor': 0, 61 | 'major': 0, 62 | 'critical': 0, 63 | 'blocker': 0} 64 | else: 65 | for p in Path('./').resolve().glob(settings): 66 | with p.open(encoding='utf-8-sig') as f: 67 | settings = yaml.full_load(f) # .get('security gates') 68 | mapping = settings['threats mapping'] 69 | settings = settings['security gates'] 70 | try: 71 | print('INFO - The AI Security gates is:') 72 | x = texttable.Texttable() 73 | x.header(['Gitlab Ci Code Quality', 'AI Severity Rules']) 74 | for key, value in settings.items(): 75 | x.add_row([key, value]) 76 | print(x.draw()) 77 | except AttributeError as e: 78 | print('ERROR - We have bad settings file') 79 | print(e) 80 | exit(1) 81 | 82 | len_info = {'info': f' {len(items_info)}'} 83 | len_minor = {'minor': f' {len(items_minor)}'} 84 | len_major = {'major': f' {len(items_major)}'} 85 | len_critical = {'critical': f' {len(items_critical)}'} 86 | len_blocker = {'blocker': f' {len(items_blocker)}'} 87 | len_total = len_info, len_minor, len_major, len_critical, len_blocker 88 | 89 | CI.result_blocker_vars = [] 90 | CI.block_mr = False 91 | 92 | for key, value in settings.items(): 93 | for item in len_total: 94 | for i in item.items(): 95 | if i[0] in key: 96 | if value != 0: 97 | if value < int(i[1]): 98 | CI.block_mr = True 99 | CI.result_blocker_vars.append(key) 100 | CI.security_gates = 'Check Security Gates: FAILED' 101 | print(f'WARNING - Exceeded the maximum number of allowed "{key}" level vulnerabilities') 102 | 103 | CI.result_blocker_body = '
**Threats Mapping:**'
104 | 
105 |     for key, value in mapping.items():
106 |         CI.result_blocker_body = CI.result_blocker_body + f'
    **{key}**: *{value}*' 107 | 108 | CI.result_blocker_body = CI.result_blocker_body + f'
**Security Gates:**' 109 | 110 | for key, value in settings.items(): 111 | CI.result_blocker_body = CI.result_blocker_body + f'
    **{key}**: *{value}*' 112 | 113 | CI.result_blocker_body = CI.result_blocker_body + f'

' 114 | 115 | 116 | def get_items(items, CI): 117 | items_total = [] 118 | items_info = [] 119 | items_minor = [] 120 | items_major = [] 121 | items_critical = [] 122 | items_blocker = [] 123 | 124 | emoji = {'info': ':white_small_square:', 125 | 'minor': ':small_blue_diamond:', 126 | 'major': ':small_orange_diamond:', 127 | 'critical': ':small_red_triangle:', 128 | 'blocker': ':no_entry_sign:'} 129 | 130 | for key, value in emoji.items(): 131 | for data in items: 132 | if key in data['severity']: 133 | row = f"{value} {data['description']}
in [{data['location']['path']}:" \ 134 | f"{data['location']['lines']['begin']}]({CI.project_url}/blob/" \ 135 | f"{CI.commit_sha}/{data['location']['path']}#L{data['location']['lines']['begin']})
" 136 | items_total.append(row) 137 | if key == 'info': 138 | items_info.append(row) 139 | if key == 'minor': 140 | items_minor.append(row) 141 | if key == 'major': 142 | items_major.append(row) 143 | if key == 'critical': 144 | items_critical.append(row) 145 | if key == 'blocker': 146 | items_blocker.append(row) 147 | else: 148 | pass 149 | 150 | table = texttable.Texttable() 151 | table.header(['Level', 'Description', 'location']) 152 | for data in items: 153 | row = [f"{data['severity']}", f"{data['description']}", 154 | f"{data['location']['path']}#L{data['location']['lines']['begin']}"] 155 | table.add_row(row) 156 | table.set_cols_width((8, 50, 90)) 157 | 158 | if CI.ci_name == 'TeamCity': 159 | teamcity_open_block() 160 | print(table.draw()) 161 | teamcity_close_block() 162 | 163 | if len(items_total) == 0: 164 | print('WARNING - json file with vulnerabilities not found') 165 | print('Check Security Gates: PASSED') 166 | exit(0) 167 | 168 | return items_total, items_info, items_minor, items_major, items_critical, items_blocker 169 | 170 | 171 | def convert_to_markdown(items_total, items_info, items_minor, items_major, items_critical, items_blocker, CI, 172 | input_folder): 173 | 174 | print(f"INFO - Application Inspector detect {len(items_total)} vulnerabilities:\n\n" 175 | f" {len(items_blocker)} Blocker\n" 176 | f" {len(items_critical)} High\n" 177 | f" {len(items_major)} Medium\n" 178 | f" {len(items_minor)} Low\n" 179 | f" {len(items_info)} Potential\n\n") 180 | 181 | if CI.commit_sha is not None: 182 | short_commit_sha = CI.commit_sha[:9] 183 | else: 184 | print('WARNING - SHA not found, no threads were generated.') 185 | print(CI.security_gates) 186 | exit(0) 187 | 188 | if CI.html_report is not None: 189 | if CI.ci_name == 'GitLab': 190 | gitlab_artifacts_url = os.environ.get('CI_JOB_URL') 191 | CI.gitlab_artifacts_url = f'{gitlab_artifacts_url}/artifacts/file/{input_folder}/aie_report.html' 192 | CI.footer = f'
:chart_with_upwards_trend: See full [AI HTML report]({CI.gitlab_artifacts_url}) ' \ 193 | f'in [GitLab job]({gitlab_artifacts_url}).' 194 | elif CI.ci_name == 'TeamCity': 195 | CI.tc_build_url = f'{CI.teamcity_server_url}/viewLog.html?buildTypeId={CI.teamcity_buildType_id}&buildId=' \ 196 | f'{CI.teamcity_build_id}' 197 | CI.tc_artifacts_url = f'{CI.teamcity_server_url}/repository/download/{CI.teamcity_buildType_id}/' \ 198 | f'{CI.teamcity_build_id}:id/aie_report.html' 199 | CI.footer = f'
:chart_with_upwards_trend: See full [AI HTML report]({CI.tc_artifacts_url}) ' \ 200 | f'in [TeamCity build]({CI.tc_build_url}).' 201 | else: 202 | CI.footer = '
:chart_with_upwards_trend: See full AI html-report in local job artifacts.' 203 | else: 204 | CI.footer = '' 205 | 206 | if CI.block_mr is True: 207 | result_blocker = '
:no_entry_sign: Merge Request has been locked by ' \ 208 | 'current AI Security Gates' \ 209 | f'{CI.result_blocker_body}
' 210 | else: 211 | result_blocker = '
' 212 | 213 | result = f"![](https://www.ptsecurity.com/local/templates/pt_corp2017/build/img/favicon.ico)" \ 214 | f" Application Inspector detect **{len(items_total)}** vulnerabilities for *[{short_commit_sha}]" \ 215 | f"({CI.project_url}/-/commit/{CI.commit_sha})*:
{result_blocker}" \ 216 | f"**Found vulnerabilities:**
" \ 217 | f":small_red_triangle: **{len(items_blocker)}** Blocker
" \ 218 | f":small_red_triangle_down: **{len(items_critical)}** High
" \ 219 | f":small_orange_diamond: **{len(items_major)}** Medium
" \ 220 | f":small_blue_diamond: **{len(items_minor)}** Low
" \ 221 | f":white_small_square: **{len(items_info)}** Potential
" \ 222 | f"
More results...

" 223 | result_footer = f'

{CI.footer}' 224 | 225 | if len(items_blocker) > 0: 226 | result_blocker = '
:small_red_triangle: Blocker vulnerabilities list:

' 227 | for x in items_blocker: 228 | result_blocker = result_blocker + x 229 | result_blocker = result_blocker + '

' 230 | else: 231 | result_blocker = '' 232 | if len(items_critical) > 0: 233 | result_critical = '
:small_red_triangle: High vulnerabilities list:

' 234 | for x in items_critical: 235 | result_critical = result_critical + x 236 | result_critical = result_critical + '

' 237 | else: 238 | result_critical = '' 239 | if len(items_major) > 0: 240 | result_major = '
:small_orange_diamond: Medium vulnerabilities list:

' 241 | for x in items_major: 242 | result_major = result_major + x 243 | result_major = result_major + '

' 244 | else: 245 | result_major = '' 246 | if len(items_minor) > 0: 247 | result_minor = '
:small_blue_diamond: Low vulnerabilities list:

' 248 | for x in items_minor: 249 | result_minor = result_minor + x 250 | result_minor = result_minor + '

' 251 | else: 252 | result_minor = '' 253 | if len(items_info) > 0: 254 | result_info = '
:white_small_square: Potential vulnerabilities list:

' 255 | for x in items_info: 256 | result_info = result_info + x 257 | result_info = result_info + '

' 258 | else: 259 | result_info = '' 260 | 261 | result = result + result_blocker + result_critical + result_major + result_minor + result_info + result_footer 262 | 263 | return result 264 | 265 | 266 | def create_gitlab_thread(result, gitlab_token, CI): 267 | print('INFO - Script started generating Gitlab Merge Request threads.') 268 | headers = {'Content-Type': "application/x-www-form-urlencoded; charset=UTF-8", "attachment": "filename=file.md"} 269 | body = {'body': '{result}'.format(**locals())} 270 | 271 | gitlab_token = '&access_token=' + gitlab_token 272 | pages = '&per_page=100' 273 | 274 | opened_merge_requests = [] 275 | 276 | count = 1 277 | while count < 40: 278 | page = "&page={count}".format(**locals()) 279 | count += 1 280 | merge_requests_url = f"{CI.api_url}/projects/{CI.project_id}/merge_requests?{gitlab_token}{pages}{page}" 281 | 282 | response = requests.get(url=merge_requests_url, headers=headers) 283 | if response.status_code == 404: 284 | print('WARNING - Merge requests not found. Maybe you have no access to the GitLab projects or all merge ' 285 | 'requests are merged..') 286 | print(f'DEBUG - URL: {merge_requests_url}') 287 | print(CI.security_gates) 288 | exit(0) 289 | 290 | json_response_body = json.loads(response.content.decode('utf-8')) 291 | 292 | for merge_request in json_response_body: 293 | if merge_request['state'] == 'opened': 294 | opened_merge_requests.append(merge_request) 295 | if len(json_response_body) == 0: 296 | break 297 | 298 | if len(opened_merge_requests) == 0: 299 | print('INFO - Opened merge requests not found') 300 | print(CI.security_gates) 301 | exit(0) 302 | 303 | founded_mr_with_needed_sha = 0 304 | for mr in opened_merge_requests: 305 | if mr['sha'] == CI.commit_sha: 306 | founded_mr_with_needed_sha += 1 307 | iid = mr['iid'] 308 | mr_list = [] 309 | modify = 0 310 | count = 1 311 | 312 | while count < 100: 313 | page = "&page={count}".format(**locals()) 314 | count += 1 315 | merge_requests_url = f"{CI.api_url}/projects/{CI.project_id}/merge_requests/{iid}/discussions?" \ 316 | f"{gitlab_token}{pages}{page}" 317 | response = requests.get(url=merge_requests_url, headers=headers) 318 | json_response_body = json.loads(response.content.decode('utf-8')) 319 | 320 | mr_list.append(json_response_body) 321 | 322 | if len(json_response_body) == 0: 323 | break 324 | 325 | for x in mr_list[0]: 326 | if 'Application Inspector detect' in x['notes'][0]['body']: 327 | new_merge_requests_url = f"{CI.api_url}/projects/{CI.project_id}/merge_requests/{iid}/" \ 328 | f"discussions/{x['id']}/notes/{x['notes'][0]['id']}?" \ 329 | f"{gitlab_token}" 330 | requests.put(url=new_merge_requests_url, data=body, headers=headers) 331 | 332 | if CI.block_mr is True: 333 | if 'Draft: ' in str(mr['title']): 334 | print('INFO - Merge request has been drafted already') 335 | else: 336 | title = f'Draft: {mr["title"]}' 337 | new_title = {'title': '{title}'.format(**locals())} 338 | 339 | blocked_merge_request_url = f"{CI.api_url}/projects/{CI.project_id}/merge_requests/{iid}?" \ 340 | f"{gitlab_token}" 341 | requests.put(url=blocked_merge_request_url, data=new_title, headers=headers) 342 | print(F"INFO - State on {CI.project_url}/-/merge_requests/{iid} was changed to draft.") 343 | modify = 1 344 | print(F"INFO - Thread on {CI.project_url}/-/merge_requests/{iid} was modified.") 345 | else: 346 | pass 347 | if modify == 0: 348 | merge_requests_url = f"{CI.api_url}/projects/{CI.project_id}/merge_requests/{iid}/discussions?" \ 349 | f"{gitlab_token}" 350 | response = requests.post(url=merge_requests_url, data=body, headers=headers) 351 | json_response_body = json.loads(response.content.decode('utf-8')) 352 | if CI.block_mr is True: 353 | if 'Draft: ' in str(mr['title']): 354 | print('INFO - Merge request has been drafted already') 355 | else: 356 | title = f'Draft: {mr["title"]}' 357 | new_title = {'title': '{title}'.format(**locals())} 358 | 359 | blocked_merge_request_url = f"{CI.api_url}/projects/{CI.project_id}/merge_requests/{iid}?" \ 360 | f"{gitlab_token}" 361 | requests.put(url=blocked_merge_request_url, data=new_title, headers=headers) 362 | print(F"INFO - State on {CI.project_url}/-/merge_requests/{iid} was changed to draft.") 363 | print(F"INFO - Thread on {CI.project_url}/-/merge_requests/{iid} was created.") 364 | if founded_mr_with_needed_sha > 0: 365 | pass 366 | else: 367 | print('WARNING - SHA not found, no threads were generated.') 368 | 369 | 370 | def convert_items(items, settings): 371 | try: 372 | print('INFO - The threats mapping is:') 373 | x = texttable.Texttable() 374 | x.header(['Gitlab Ci Code Quality', 'AI Threats Mapping']) 375 | for key, value in settings.items(): 376 | x.add_row([key, value]) 377 | print(x.draw()) 378 | except AttributeError as e: 379 | print('ERROR - We have bad settings file') 380 | print(e) 381 | exit(1) 382 | 383 | for key, value in settings.items(): 384 | for i in items: 385 | if i['Level']['DisplayName'] in value: 386 | yield { 387 | "description": f"[{i['Level']['DisplayName']}] {i['Type']['DisplayName']}", 388 | "fingerprint": i['Id'], 389 | "severity": f"{key}", 390 | "location": { 391 | "path": i['SourceFile'].split(':')[0].replace('\\', '/').replace('./', '').strip(), 392 | "lines": { 393 | "begin": i.get('BeginLine', i.get('NumberLine')) 394 | } 395 | } 396 | } 397 | else: 398 | pass 399 | 400 | 401 | def read_reports(input_folder, settings): 402 | dir_files = os.listdir(input_folder) 403 | files = [] 404 | 405 | if settings is None: 406 | settings = {'info': 'Potential', 407 | 'minor': 'Low', 408 | 'major': 'Medium', 409 | 'critical': 'High', 410 | 'blocker': ''} 411 | else: 412 | for p in Path('./').resolve().glob(settings): 413 | with p.open(encoding='utf-8-sig') as f: 414 | settings = yaml.full_load(f).get('threats mapping') 415 | 416 | for f in dir_files: 417 | if '.json' in f: 418 | f = input_folder + '/' + f 419 | files.append(f) 420 | if len(files) > 0: 421 | file = max(files, key=os.path.getctime) 422 | for p in Path('./').resolve().glob(file): 423 | with p.open(encoding='utf-8-sig') as f: 424 | x = json.load(f) 425 | try: 426 | yield from convert_items(x['Items'], settings) 427 | except TypeError: 428 | print('ERROR - In input folder we have bad json file') 429 | exit(1) 430 | else: 431 | print('WARNING - Json report not found.') 432 | print('Check Security Gates: Unknown') 433 | exit(0) 434 | 435 | 436 | def main(input_folder, output_file, gitlab_token, settings_file, block_mr, income_args): 437 | print('INFO - aisa-codequality started successfully!') 438 | 439 | def define_ci_server(arguments): 440 | """ 441 | Return CI server type with specific environment 442 | """ 443 | # Check predefined environment variable to define CI server, TC by default, Gitlab CI by checking CI variable 444 | # https://docs.gitlab.com/ee/ci/variables/ 445 | if os.environ.get('CI', False): 446 | return GitlabCI() 447 | elif arguments.ci_type == 'GitLab': 448 | return GitlabCI() 449 | elif arguments.ci_type == 'TeamCity': 450 | return TeamCity(arguments) 451 | else: 452 | return Local(arguments) 453 | 454 | class GitlabCI(object): 455 | def __init__(self): 456 | self.ci_name = 'GitLab' 457 | self.commit_sha = os.environ.get('CI_COMMIT_SHA') 458 | self.project_id = os.environ.get('CI_PROJECT_ID') 459 | self.project_url = os.environ.get('CI_PROJECT_URL') 460 | self.api_url = os.environ.get('CI_API_V4_URL') 461 | 462 | class TeamCity(object): 463 | def __init__(self, arguments): 464 | self.ci_name = 'TeamCity' 465 | self.commit_sha = arguments.commit_sha 466 | self.teamcity_server_url = arguments.teamcity_server_url 467 | self.teamcity_build_id = arguments.teamcity_build_id 468 | self.teamcity_buildType_id = arguments.teamcity_buildType_id 469 | self.project_id = arguments.gitlab_project_id 470 | self.project_url = arguments.gitlab_project_url 471 | self.api_url = arguments.gitlab_api_url 472 | 473 | class Local(object): 474 | def __init__(self, arguments): 475 | self.ci_name = 'Local' 476 | self.commit_sha = arguments.commit_sha 477 | self.project_id = arguments.gitlab_project_id 478 | self.project_url = arguments.gitlab_project_url 479 | self.api_url = arguments.gitlab_api_url 480 | 481 | CI = define_ci_server(income_args) 482 | CI.security_gates = 'Check Security Gates: PASSED' 483 | rename_html_report(input_folder, CI) 484 | 485 | print('\n+-- Variables -----------------------------------+') 486 | print(f' CI name: {CI.ci_name}\n' 487 | f' Commit sha: {CI.commit_sha}\n' 488 | f' Project ID: {CI.project_id}\n' 489 | f' Project URL: {CI.project_url}\n' 490 | f' API URL: {CI.api_url}\n' 491 | f' Input folder: {input_folder}\n') 492 | print('+------------------------------------------------+') 493 | 494 | print('INFO - Try to convert report to {output_file}.'.format(**locals())) 495 | result = list(read_reports(input_folder, settings_file)) 496 | if len(result) == 0: 497 | print('INFO - Result is null'.format(**locals())) 498 | else: 499 | with open(output_file, 'w', encoding='utf-8') as f: 500 | json.dump(result, f), f.close() 501 | print('INFO - File {output_file} was generated.'.format(**locals())) 502 | 503 | if gitlab_token is None: 504 | print('INFO - Script was completed without Thread.\n ' 505 | 'Please specify GitLab personal token for create threads.') 506 | print('Check Security Gates: Unknown') 507 | exit(0) 508 | 509 | items_total, items_info, items_minor, items_major, items_critical, items_blocker = get_items(result, CI) 510 | set_security_rules(items_info, items_minor, items_major, items_critical, items_blocker, CI, settings=settings_file) 511 | 512 | result = convert_to_markdown(items_total, items_info, items_minor, items_major, items_critical, items_blocker, 513 | CI, input_folder) 514 | if block_mr is False: 515 | CI.block_mr = False 516 | 517 | create_gitlab_thread(result, gitlab_token, CI) 518 | print('INFO - aisa-codequality completed successfully!') 519 | print(CI.security_gates) 520 | 521 | 522 | def parse_args(): 523 | parser = argparse.ArgumentParser() 524 | parser.add_argument('-i', "--input_folder", action="store", required=False, default='.report', 525 | help="The name of reports folder") 526 | parser.add_argument('-o', "--output_file", action="store", required=False, default='codequality.json', 527 | help="The name of json file") 528 | parser.add_argument('-t', "--token", action="store", required=False, help="Gitlab CI builder Token") 529 | parser.add_argument('-s', "--settings_file", action="store", required=False, help="The name of settings file") 530 | parser.add_argument('-sha', "--commit_sha", action="store", required=False, help="The commit sha") 531 | parser.add_argument('-gpid', "--gitlab_project_id", action="store", required=False, help="Gitlab project id") 532 | parser.add_argument('-gpurl', "--gitlab_project_url", action="store", required=False, help="Gitlab project url") 533 | parser.add_argument('-gaurl', "--gitlab_api_url", action="store", required=False, help="Gitlab api url") 534 | parser.add_argument('-tcbid', "--teamcity_build_id", action="store", required=False, 535 | help="TeamCity build id %teamcity.build.id%") 536 | parser.add_argument('-tcbtid', "--teamcity_buildType_id", action="store", required=False, 537 | help="TeamCity project build id %system.teamcity.buildType.id%") 538 | parser.add_argument('-tcurl', "--teamcity_server_url", action="store", required=False, help="TeamCity server url") 539 | parser.add_argument('-ci', "--ci_type", action="store", required=False, default='Local', 540 | help="Variable for define CI system (TeamCity, GitLab, etc.)") 541 | parser.add_argument('-b', "--block_mr", action="store", required=False, default=False, 542 | help="Rename MR from `title` to `draft: title`") 543 | arguments = parser.parse_args() 544 | return arguments 545 | 546 | 547 | if __name__ == '__main__': 548 | args = parse_args() 549 | main( 550 | input_folder=args.input_folder, # Folder with json report from aisa 551 | output_file=args.output_file, # Output json file for code quality 552 | gitlab_token=args.token, # Folder with json report from aisa 553 | settings_file=args.settings_file, # The name of yaml file with settings 554 | block_mr=args.block_mr, # Rename MR from `title` to `draft: title` 555 | income_args=args 556 | ) 557 | -------------------------------------------------------------------------------- /AISA_Docker/aisa-linux/docker_build_data/applications/aisa-set-policy.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # (c) DevOpsHQ, 2021 4 | 5 | import os 6 | import re 7 | import argparse 8 | import sys 9 | 10 | 11 | def parse_args(): 12 | parser = argparse.ArgumentParser() 13 | parser.add_argument("--count_to_actualize", action="store", default=1, required=False) 14 | parser.add_argument("--level", action="store", default="Medium", required=False) 15 | parser.add_argument("--exploit", action="store", default='"."', required=False) 16 | parser.add_argument("--is_suspected", action="store", default="false", required=False) 17 | parser.add_argument("--approval_state", action="store", default="[^2]", required=False) 18 | args = parser.parse_args() 19 | return args 20 | 21 | 22 | def create_json(args): 23 | json = ''' 24 | [ 25 | { 26 | "CountToActualize": $count_to_actl, 27 | "Scopes": [ 28 | { 29 | "Rules": [ 30 | { 31 | "Field": "Level", 32 | "Value": "$level", 33 | "IsRegex": false 34 | }, 35 | { 36 | "Field": "Exploit", 37 | "Value": $exploit, 38 | "IsRegex": true 39 | }, 40 | { 41 | "Field": "IsSuspected", 42 | "Value": "$is_suspected", 43 | "IsRegex": false 44 | }, 45 | { 46 | "Field": "ApprovalState", 47 | "Value": "$approval_state", 48 | "IsRegex": true 49 | } 50 | ] 51 | } 52 | ] 53 | } 54 | ] 55 | ''' 56 | json = re.sub(r"\$count_to_actl", str(args.count_to_actualize), json, 1) 57 | json = re.sub(r"\$level", str(args.level), json, 1) 58 | json = re.sub(r"\$exploit", str(args.exploit), json, 1) 59 | json = re.sub(r"\$is_suspected", str(args.is_suspected), json, 1) 60 | json = re.sub(r"\$approval_state", str(args.approval_state), json, 1) 61 | 62 | return json 63 | 64 | 65 | def print_info(count_to_actualize, 66 | level, 67 | exploit, 68 | is_suspected, 69 | approval_state): 70 | print("-" * 50) 71 | print("[INFO]: CountToActualize: {count_to_actualize}".format(**locals())) 72 | print("[INFO]: Level: {level}".format(**locals())) 73 | print("[INFO]: Exploit: {exploit}".format(**locals())) 74 | print("[INFO]: IsSuspected: {is_suspected}".format(**locals())) 75 | print("[INFO]: ApprovalState: {approval_state}".format(**locals())) 76 | print("-" * 50) 77 | 78 | 79 | def main(args): 80 | print("[INFO]: Start generating policy") 81 | 82 | print_info(count_to_actualize=args.count_to_actualize, 83 | level=args.level, 84 | exploit=args.exploit, 85 | is_suspected=args.is_suspected, 86 | approval_state=args.approval_state) 87 | 88 | json_file = create_json(args) 89 | 90 | file_name = "policy.json" 91 | 92 | if "{file_name}".format(**locals()) in os.listdir("."): 93 | sys.stderr.write("[ERROR]: File exists\n") 94 | else: 95 | proj = open("{file_name}".format(**locals()), "a") 96 | proj.write(json_file) 97 | proj.close() 98 | print("[INFO]: File {proj.name} was generated successfully".format(**locals())) 99 | 100 | 101 | if __name__ == '__main__': 102 | arguments = parse_args() 103 | main(arguments) 104 | -------------------------------------------------------------------------------- /AISA_Docker/aisa-linux/docker_build_data/applications/aisa-set-settings.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # (c) DevOpsHQ, 2021 4 | 5 | import sys 6 | import os 7 | import re 8 | import argparse 9 | 10 | import platform 11 | 12 | 13 | def parse_args(): 14 | parser = argparse.ArgumentParser() 15 | parser.add_argument("--projectname", 16 | action="store", 17 | help="The name of project", 18 | required=True) 19 | parser.add_argument("--language", 20 | action="store", 21 | help="Programming language to find in project", 22 | required=True) 23 | parser.add_argument("--path", 24 | action="store", 25 | help="Path to project for scan", 26 | default="./", 27 | required=False) 28 | parser.add_argument("--exclude-formats", 29 | action="store", 30 | help="Whether to exclude non-sources files from scanning (True or False)", 31 | default="True", 32 | required=False) 33 | parser.add_argument("--excluded-paths", 34 | action="store", 35 | nargs="+", 36 | help="Exclude certain files and folders from scan. " 37 | "Use single \\ with apostrophes and double \\ with quotes " 38 | "(e.g. '\\devops-tools' " 39 | '"\\\\.git\\\\")', 40 | required=False) 41 | arguments = parser.parse_args() 42 | return arguments 43 | 44 | 45 | def check_platform(os_type): 46 | if os_type == 'Windows': 47 | return "Windows" 48 | else: 49 | return "Linux" 50 | 51 | 52 | def check_args(projectname, language, languages, path_to_folder): 53 | if "{projectname}.aiproj".format(**locals()) in os.listdir("."): 54 | print("-" * 50) 55 | print("[WARNING]: File {projectname}.aiproj exists".format(**locals())) 56 | print(" Try to overwrite") 57 | print("-" * 50) 58 | if language in map(lambda x: x.lower(), languages): 59 | print("[INFO]: Arguments is correct") 60 | else: 61 | sys.stderr.write("[ERROR]: Unknown language\n") 62 | sys.exit(1) 63 | 64 | 65 | def create_json(projectname, language, exclude_formats, excluded_paths_list): 66 | config = r'''{ 67 | "ProjectName": "$ProjectName", 68 | "ProgrammingLanguage": "$LANG", 69 | "ScanAppType": "Configuration, Fingerprint, PmTaint, DependencyCheck, $COND", 70 | "ThreadCount": 2, 71 | "Site": "http://localhost", 72 | "IsDownloadDependencies": true, 73 | 74 | "IsUsePublicAnalysisMethod": true, 75 | "IsUseEntryAnalysisPoint": true, 76 | 77 | "ScanUnitTimeout": 360, 78 | "PreprocessingTimeout": 60, 79 | "CustomParameters": $CUSTOM, 80 | 81 | "SkipFileFormats": $EXCLUDED_FILE_FORMATS, 82 | "SkipFilesFolders": ["\\devops-tools", "\\.git\\", "\\.gitignore", "\\.gitmodules", "\\.gitattributes", "\\$tf\\", "\\$BuildProcessTemplate\\", "\\.tfignore"$EXCLUDED_FILES_FOLDERS], 83 | 84 | "DisabledPatterns": ["145", "146", "148", "149"], 85 | "DisabledTypes": [], 86 | 87 | "UseIncrementalScan": true, 88 | "FullRescanOnNewFilesAdded": true, 89 | 90 | "ConsiderPreviousScan": true, 91 | "HideSuspectedVulnerabilities": false, 92 | "UseIssueTrackerIntegration": false, 93 | 94 | "IsUnpackUserPackages": false, 95 | "JavaParameters": null, 96 | "JavaVersion": 0, 97 | "UseJavaNormalizeVersionPattern": "true", 98 | "JavaNormalizeVersionPattern": "-\\d+(\\.\\d+)*", 99 | 100 | "JavaScriptProjectFile": null, 101 | "JavaScriptProjectFolder": null, 102 | 103 | "UseTaintAnalysis": true, 104 | "UsePmAnalysis": true, 105 | "DisableInterpretCores": false, 106 | 107 | "UseDefaultFingerprints": true, 108 | "UseCustomYaraRules": false, 109 | 110 | "CustomHeaders": [["", ""]], 111 | "Authentication": { 112 | "auth_item": { 113 | "domain": null, 114 | "credentials": { 115 | "cookie": null, 116 | "type": 2, 117 | "login": { 118 | "name": null, 119 | "value": null, 120 | "regexp": null, 121 | "is_regexp": false 122 | }, 123 | "password": { 124 | "name": null, 125 | "value": null, 126 | "regexp": null, 127 | "is_regexp": false 128 | } 129 | }, 130 | "test_url": null, 131 | "form_url": null, 132 | "form_xpath": ".//form", 133 | "regexp_of_success": null 134 | } 135 | }, 136 | "ProxySettings": { 137 | "IsEnabled": false, 138 | "Host": null, 139 | "Port": null, 140 | "Type": 0, 141 | "Username": null, 142 | "Password": null 143 | }, 144 | 145 | "RunAutocheckAfterScan": false, 146 | "AutocheckSite": "http://localhost", 147 | "AutocheckCustomHeaders": [["", ""]], 148 | "AutocheckAuthentication": { 149 | "auth_item": { 150 | "domain": null, 151 | "credentials": { 152 | "cookie": null, 153 | "cookies": null, 154 | "type": 2, 155 | "login": { 156 | "name": null, 157 | "value": null, 158 | "regexp": null, 159 | "is_regexp": false 160 | }, 161 | "password": { 162 | "name": null, 163 | "value": null, 164 | "regexp": null, 165 | "is_regexp": false 166 | } 167 | }, 168 | "test_url": null, 169 | "form_url": null, 170 | "form_xpath": ".//form", 171 | "regexp_of_success": null 172 | } 173 | }, 174 | "AutocheckProxySettings": { 175 | "IsEnabled": false, 176 | "Host": null, 177 | "Port": null, 178 | "Type": 0, 179 | "Username": null, 180 | "Password": null 181 | }, 182 | 183 | "SendEmailWithReportsAfterScan": false, 184 | "CompressReport": false, 185 | 186 | "EmailSettings": null, 187 | 188 | "ReportParameters": { 189 | "SaveAsPath": null, 190 | "UseElectronicSignature": false, 191 | "CertificatePath": null, 192 | "Password": null, 193 | "ShowSignatureTime": false, 194 | "SignatureReason": null, 195 | "Location": null, 196 | "DoSignatureVisible": false, 197 | "IncludeDiscardedVulnerabilities": false, 198 | "IncludeSuppressedVulnerabilities": true, 199 | "IncludeSuspectedVulnerabilities": false, 200 | "IncludeGlossary": false, 201 | "ConverHtmlToPdf": false, 202 | "RemoveHtml": false, 203 | "CreatePdfPrintVersion": false, 204 | "MakeAFReport": false, 205 | "IncludeDFD": false 206 | } 207 | } 208 | ''' # noqa 209 | json = re.sub(r"\$ProjectName", projectname, config, 1) 210 | json = re.sub(r"\$LANG", language, json, 1) 211 | 212 | if language == "php": 213 | json = re.sub(r", \$COND", ", Php", json, 1) 214 | elif language == "java": 215 | json = re.sub(r", \$COND", ", Java", json, 1) 216 | elif language == "javascript": 217 | json = re.sub(r", \$COND", ", JavaScript", json, 1) 218 | elif language == "csharp" or language == "vb": 219 | json = re.sub(r", \$COND", ", CSharp", json, 1) 220 | else: 221 | json = re.sub(r", \$COND", "", json, 1) 222 | 223 | if language == "python": 224 | json = re.sub(r"\$CUSTOM", r'"--multifile"', json, 1) 225 | else: 226 | json = re.sub(r"\$CUSTOM", "null", json, 1) 227 | 228 | excluded_formats_list = '["*.7z", "*.bmp", "*.dib", "*.dll", "*.doc", "*.docx", "*.exe", "*.gif", "*.ico", ' \ 229 | '"*.jfif", "*.jpe", "*.jpe6", "*.jpeg", "*.jpg", "*.odt", "*.pdb", "*.pdf", "*.png", ' \ 230 | '"*.rar", "*.swf", "*.tif", "*.tiff", "*.zip"]' 231 | 232 | try: 233 | print("[INFO]: Exclude non-source files from scanning: {exclude_formats}".format(**locals())) 234 | if exclude_formats in ('FALSE', 'False', 'false'): 235 | json = re.sub(r"\$EXCLUDED_FILE_FORMATS", "null", json, 1) 236 | elif exclude_formats in ('TRUE', 'True', 'true'): 237 | json = re.sub(r"\$EXCLUDED_FILE_FORMATS", excluded_formats_list, json, 1) 238 | else: 239 | raise ValueError() 240 | except (ValueError, Exception): 241 | print('[WARNING]: You have specified an invalid value. Used "True" as the default.') 242 | json = re.sub(r"\$EXCLUDED_FILE_FORMATS", excluded_formats_list, json, 1) 243 | 244 | try: 245 | print("[INFO]: Excluded files and folders list: {excluded_paths_list}".format(**locals())) 246 | if excluded_paths_list is not None: 247 | excluded_paths_string = '' 248 | for excluded_item in excluded_paths_list: 249 | # Take raw value and remove apostrophes 250 | prepared_excluded_item = repr(excluded_item).replace("'", "") 251 | excluded_paths_string = excluded_paths_string + r', "{prepared_excluded_item}"'.format(**locals()) 252 | json = json.replace("$EXCLUDED_FILES_FOLDERS", excluded_paths_string, 1) 253 | else: 254 | json = json.replace("$EXCLUDED_FILES_FOLDERS", '', 1) 255 | except (ValueError, Exception): 256 | print('[WARNING]: Something went wrong! The default values are used.') 257 | json = json.replace("$EXCLUDED_FILES_FOLDERS", '', 1) 258 | 259 | return json 260 | 261 | 262 | def print_info(projectname, language, path_to_file): 263 | if path_to_file == '': 264 | folder = './' 265 | print("-" * 50) 266 | print("[INFO]: Project name: {projectname}".format(**locals())) 267 | print("[INFO]: File name: {projectname}.aiproj".format(**locals())) 268 | print("[INFO]: Language: {language}".format(**locals())) 269 | print("[INFO]: Path: {path_to_file}".format(**locals())) 270 | print("-" * 50) 271 | 272 | 273 | def main(prj, lang, path, exclude_formats, excluded_paths_list): 274 | # ---------- Variables ---------- 275 | lang = lang.lower() 276 | langs = ["java", "php", "csharp", "vb", "objectivec", "cplusplus", "sql", "swift", "python", "javascript", "go", 277 | "kotlin"] 278 | os_type = platform.system() 279 | 280 | # ------------- Run ------------- 281 | 282 | check_args(prj, lang, langs, path) 283 | json_file = create_json(prj, lang, exclude_formats, excluded_paths_list) 284 | print_info(prj, lang, path) 285 | 286 | proj = open("{prj}.aiproj".format(**locals()), "w") 287 | proj.write(json_file) 288 | proj.close() 289 | print("[INFO]: File {proj.name} was generated successfully".format(**locals())) 290 | 291 | 292 | if __name__ == '__main__': 293 | print("[INFO]: Start generating project") 294 | args = parse_args() 295 | main( 296 | prj=args.projectname, # Project name 297 | lang=args.language, # Language 298 | path=args.path, # Path to folder 299 | exclude_formats=args.exclude_formats, # Exclusion non-sources files from scanning (on/off) 300 | excluded_paths_list=args.excluded_paths # Exclusion paths from scanning 301 | ) 302 | -------------------------------------------------------------------------------- /AISA_Docker/aisa-linux/docker_build_data/config/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devopshq/dohq-ai-best-practices/563f94b3b0371b25305ed03349c42564beaac92b/AISA_Docker/aisa-linux/docker_build_data/config/.gitkeep -------------------------------------------------------------------------------- /AISA_Docker/aisa-windows/Dockerfile: -------------------------------------------------------------------------------- 1 | # (c) DevOpsHQ, 2020 2 | 3 | FROM mcr.microsoft.com/windows/servercore:10.0.17763.379 4 | 5 | ARG AISA_PACKAGE 6 | ARG ARTIFACTORY_LOGIN 7 | ARG ARTIFACTORY_PASSWORD 8 | ARG CERT_PASSWORD 9 | 10 | SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"] 11 | 12 | ADD "docker_build_data\download-and-unpack" "c:\scripts\download-and-unpack" 13 | ADD "docker_build_data\install-web" "c:\scripts\install-web" 14 | ADD "docker_build_data\create-json" "c:\scripts\create-json" 15 | ADD "docker_build_data\certs" "c:\scripts\certs" 16 | 17 | # -------------------- Установка ПО -------------------- 18 | 19 | # --- Install dotnet runtime ---------- 20 | RUN "C:\scripts\install-web\install-web.ps1"\ 21 | -URL https://download.visualstudio.microsoft.com/download/pr/93d4ac87-6db0-4ddd-9bef-8050067b5e5d/605b178040bdd75b63d021d9387219ea/dotnet-runtime-3.1.4-win-x64.exe \ 22 | -Filename dotnet-runtime-3.1.4-win-x64.exe \ 23 | -InstallArgs '/install /passive' 24 | 25 | # --- Install aisa -------------------- 26 | RUN "c:\scripts\download-and-unpack\download-and-unpack-auth.ps1" \ 27 | -PKG $(${env:AISA_PACKAGE}) \ 28 | -UnpackTo 'C:\Program Files (x86)\Positive Technologies\Application Inspector Agent Shell' \ 29 | -Login $(${env:ARTIFACTORY_LOGIN}) \ 30 | -Key $(${env:ARTIFACTORY_PASSWORD}) 31 | 32 | ENV AISA_PATH C:\\Program Files (x86)\\Positive Technologies\\Application Inspector Agent Shell 33 | 34 | # --- Ai.Shell setting ---------------- 35 | ARG AISA_TOKEN 36 | ARG AISA_URI 37 | 38 | RUN "C:\scripts\create-json\create-json.ps1" 39 | 40 | # --- Import Certs -------------------- 41 | 42 | #RUN "c:\scripts\certs\import-certs.ps1" \ 43 | # -KEY $(${env:CERT_PASSWORD}) 44 | 45 | # --- Fast changes -------------------- 46 | 47 | # SAVE PATHS IN REGISTRY: 48 | RUN $path = [environment]::GetEnvironmentVariable('Path', 'Machine'); \ 49 | Get-ChildItem ENV: | Where-Object -Property Name -match '.+_PATH' | ForEach-Object { \ 50 | if (($path -notlike '*;'+$_.Value) -And ($path -notlike '*'+$_.Value+';*')) { $path+=';'+$_.Value } }; \ 51 | [Environment]::SetEnvironmentVariable('Path', $path, 'Machine'); \ 52 | # Enable Long paths fix. Windows default limit of 255 chars may cause problems with builds. 53 | reg add "HKLM\SYSTEM\CurrentControlSet\Control\FileSystem" /f /v LongPathsEnabled /t REG_DWORD /d 1 54 | 55 | CMD ["cmd"] 56 | -------------------------------------------------------------------------------- /AISA_Docker/aisa-windows/docker_build_data/certs/import-certs.ps1: -------------------------------------------------------------------------------- 1 | Param( 2 | [Parameter(Mandatory = $True, Position = 1)] 3 | [string]$KEY 4 | ) 5 | 6 | Write-Host "##teamcity[blockOpened name='Import certificates']" 7 | 8 | certutil -f -v -p $KEY -importpfx "" 9 | certutil -f -v -p $KEY -importpfx root "" 10 | 11 | Write-Host "##teamcity[blockOpened name='Import certificates to local machine']" 12 | # ---------- Import to local machine ---------- 13 | Import-Certificate -FilePath -CertStoreLocation Cert:\LocalMachine\Root 14 | Import-Certificate -FilePath .crt -CertStoreLocation Cert:\LocalMachine\Trust 15 | Import-Certificate -FilePath .crt -CertStoreLocation Cert:\LocalMachine\CA 16 | Import-Certificate -FilePath .pem.crt -CertStoreLocation Cert:\LocalMachine\Root 17 | Import-Certificate -FilePath .pem.crt -CertStoreLocation Cert:\LocalMachine\Trust 18 | Import-Certificate -FilePath .pem.crt -CertStoreLocation Cert:\LocalMachine\CA 19 | Write-Host "##teamcity[blockClosed name='Import certificates to local machine']" 20 | 21 | 22 | Write-Host "##teamcity[blockOpened name='Import certificates to Current User']" 23 | # ---------- Import to Current User ---------- 24 | Import-Certificate -FilePath .pem.crt -CertStoreLocation Cert:\CurrentUser\Root 25 | Import-Certificate -FilePath .pem.crt -CertStoreLocation Cert:\CurrentUser\Trust 26 | Import-Certificate -FilePath .pem.crt -CertStoreLocation Cert:\CurrentUser\CA 27 | Import-Certificate -FilePath .pem.crt -CertStoreLocation Cert:\CurrentUser\Root 28 | Import-Certificate -FilePath .pem.crt -CertStoreLocation Cert:\CurrentUser\Trust 29 | Import-Certificate -FilePath .pem.crt -CertStoreLocation Cert:\CurrentUser\CA 30 | Write-Host "##teamcity[blockClosed name='Import certificates to Current User']" 31 | 32 | Write-Host "##teamcity[blockClosed name='Import certificates']" 33 | -------------------------------------------------------------------------------- /AISA_Docker/aisa-windows/docker_build_data/create-json/create-json.ps1: -------------------------------------------------------------------------------- 1 | Write-Host "##teamcity[blockOpened name='Create-json']" 2 | 3 | Write-Host "[DEBUG]: Aisa URI: $( ${env:AISA_URI} )" 4 | Write-Host "[DEBUG]: Aisa Token: $( ${env:AISA_TOKEN} )" 5 | 6 | Write-Host "##teamcity[blockOpened name='Generate-json']" 7 | Remove-Item 'C:\Program Files (x86)\Positive Technologies\Application Inspector Agent Shell\appSettings.user.json' 8 | Write-Output "{`"ServerConnectSettings`":{`"EnterpriseApiUri`":`"$( ${env:AISA_URI} )`",`"AccessToken`":`"$( ${env:AISA_TOKEN} )`"}}" >> 'C:\Program Files (x86)\Positive Technologies\Application Inspector Agent Shell\appSettings.user.json' 9 | 10 | Write-Host "##teamcity[blockOpened name='Verify appSettings.user.json']" 11 | cat 'C:\Program Files (x86)\Positive Technologies\Application Inspector Agent Shell\appSettings.user.json' 12 | Write-Host "##teamcity[blockClosed name='Verify appSettings.user.json']" 13 | 14 | Write-Host "##teamcity[blockClosed name='Generate-json']" 15 | -------------------------------------------------------------------------------- /AISA_Docker/aisa-windows/docker_build_data/download-and-unpack/download-and-unpack-auth.ps1: -------------------------------------------------------------------------------- 1 | Param( 2 | [Parameter(Mandatory = $True, Position = 1)] 3 | [string]$PKG, 4 | 5 | [Parameter(Mandatory = $True, Position = 2)] 6 | [string]$UnpackTo, 7 | 8 | [Parameter(Mandatory = $True, Position = 3)] 9 | [string]$Login, 10 | 11 | [Parameter(Mandatory = $True, Position = 4)] 12 | [string]$Key 13 | ) 14 | 15 | $ErrorActionPreference = 'Stop' 16 | Write-Host "##teamcity[blockOpened name='Download']" 17 | 18 | # Generate URL to artifactory 19 | Write-Host "Aisa package version is $PKG" 20 | Write-Host "Aisa package is $PKG" 21 | 22 | $ARTIFACTORY_URL = "https://repo.artifactory.com:443" 23 | $ARTIFACTORY_REPO = "your_repo" 24 | $URL = $ARTIFACTORY_URL + '/' + $ARTIFACTORY_REPO + '/' + $PKG 25 | Write-Host $URL 26 | 27 | $tmp = $env:TEMP 28 | 29 | $url_extension = $URL.Split('.')[-1] 30 | 31 | Write-Host "URL Extension is $url_extension" 32 | 33 | if ($url_extension -eq "zip") 34 | { 35 | Write-Host "URL Extension is $url_extension" 36 | # Prepare 37 | $zip_name = $URL.Split('/')[-1] 38 | $zip_fullname = "$tmp\$zip_name" 39 | 40 | # Download 41 | Write-Host "Download $URL to $zip_fullname" 42 | $wc = New-Object net.webclient # System.Net.WebClient 43 | $wc.Credentials = new-object System.Net.NetworkCredential($Login, $Key) 44 | $wc.Downloadfile($URL, $zip_fullname) 45 | 46 | # Unpack 47 | Write-Host "Unpack $zip_fullname to $UnpackTo" 48 | Expand-Archive $zip_fullname $UnpackTo 49 | } 50 | 51 | Write-Host "##teamcity[blockOpened name='Clean']" 52 | Remove-Item $env:temp\* -Force -Verbose -Recurse 53 | Write-Host "##teamcity[blockClosed name='Clean']" 54 | 55 | Write-Host "##teamcity[blockClosed name='Download']" 56 | -------------------------------------------------------------------------------- /AISA_Docker/aisa-windows/docker_build_data/install-web/install-web.ps1: -------------------------------------------------------------------------------- 1 | Param( 2 | [Parameter(Mandatory=$True,Position=1)] 3 | [string]$URL, 4 | 5 | [Parameter(Mandatory=$True,Position=2)] 6 | [string]$Filename, 7 | 8 | [Parameter(Mandatory=$True,Position=3)] 9 | [string]$InstallArgs 10 | ) 11 | 12 | $ErrorActionPreference = 'Stop' 13 | Write-Host "##teamcity[blockOpened name='Install']" 14 | 15 | $tmp = $env:TEMP 16 | 17 | $url_extension = $URL.Split('.')[-1] 18 | if ($url_extension -eq "zip"){ 19 | # Prepare 20 | $zip_name = $URL.Split('/')[-1] 21 | $zip_fullname = "$tmp\$zip_name" 22 | $folder = $zip_fullname -replace '.zip' 23 | 24 | # Download 25 | Write-Host "Download $URL to $zip_fullname" 26 | $wc = New-Object net.webclient 27 | $wc.Downloadfile($URL, $zip_fullname) 28 | 29 | # Unpack 30 | Write-Host "Unpack $zip_fullname to $folder" 31 | Expand-Archive $zip_fullname $tmp 32 | Get-ChildItem $folder 33 | 34 | # Set variables 35 | $fullpath = "$folder\$Filename" 36 | } 37 | else{ 38 | # Prepare 39 | $fullpath = "$env:TEMP\$filename" 40 | 41 | # Download 42 | Write-Host "Download $URL to $fullpath" 43 | $wc = New-Object net.webclient 44 | $wc.Downloadfile($URL, $fullpath) 45 | } 46 | 47 | $extension = $fullpath.Split('.')[-1] 48 | if ($extension -eq "exe"){ 49 | Write-Host "Run: $fullpath $InstallArgs" 50 | Start-Process $fullpath -ArgumentList $InstallArgs -Wait 51 | } 52 | 53 | if ($extension -eq "msi"){ 54 | Write-Host "Run: msiexec.exe /I $fullpath $InstallArgs" 55 | Start-Process msiexec.exe -ArgumentList "/I $fullpath $InstallArgs" -Wait 56 | } 57 | 58 | Write-Host "##teamcity[blockOpened name='Clean']" 59 | Remove-Item $fullpath -Force -Verbose 60 | Remove-Item $env:temp\* -Force -Verbose -Recurse 61 | Write-Host "##teamcity[blockClosed name='Clean']" 62 | 63 | Write-Host "##teamcity[blockClosed name='Install']" 64 | -------------------------------------------------------------------------------- /GitLab_templates/AI.Cli.Plugin/AI-Plugin-dockerbuild/.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | stages: 2 | - build 3 | 4 | docker build: 5 | stage: build 6 | tags: 7 | - linux 8 | - docker 9 | image: docker 10 | script: 11 | - docker login -u="${DOCKER_USERNAME}" -p="${DOCKER_PASSWORD}" ${REGISTRY_ADDRESS} 12 | - docker build --build-arg AI_URI="https://${AI_URN}" --build-arg PLUGIN_TOKEN="${PLUGIN_TOKEN}" -t ${REGISTRY_ADDRESS}/tools/ai-plugin:latest --no-cache $CI_PROJECT_DIR/Docker 13 | - docker push ${REGISTRY_ADDRESS}/tools/ai-plugin:latest 14 | when: manual 15 | -------------------------------------------------------------------------------- /GitLab_templates/AI.Cli.Plugin/AI-Plugin-dockerbuild/Docker/Dockerfile: -------------------------------------------------------------------------------- 1 | # (c) DevOpsHQ, 2021 2 | 3 | FROM gradle:7-jdk8 4 | 5 | # You must define some specific variables: 6 | # All Access tokens are here: https:///ui/admin/settings 7 | ARG PLUGIN_TOKEN 8 | 9 | # URL of Application Inspector Enterprise Server 10 | ARG AI_URI 11 | 12 | COPY docker_build_data/config/ /tmp/plugin_config/ 13 | COPY docker_build_data/applications/ /usr/src/app/ 14 | 15 | # INSTALL EXTERNAL PACKAGES 16 | RUN set -ex && apt-get update && apt-get install -y --no-install-recommends \ 17 | wget libunwind8-dev liblttng-ust0 cmake tree jq git tar xz-utils gcc make locales openssl ssh openssh-server openssh-client && \ 18 | apt-get clean && \ 19 | rm -rf /var/lib/apt/lists/* 20 | 21 | # INSTALL PYTHON 3.7 22 | RUN mkdir /tmp/py3.7_build && \ 23 | cd /tmp/py3.7_build && \ 24 | apt-get update && \ 25 | apt-get install --no-install-recommends -y libssl-dev libsqlite3-dev zlib1g-dev libffi-dev && \ 26 | apt-get clean && \ 27 | wget -c "https://www.python.org/ftp/python/3.7.7/Python-3.7.7.tgz" && \ 28 | tar xf "Python-3.7.7.tgz" && \ 29 | cd "Python-3.7.7" && \ 30 | LDFLAGS="-Wl,-rpath,/usr/local/lib" ./configure --enable-optimizations --enable-shared --with-ensurepip=install && \ 31 | make -j$(nproc) build_all && \ 32 | make altinstall && \ 33 | apt-get remove -y libssl-dev libsqlite3-dev zlib1g-dev libffi-dev && \ 34 | cd - && \ 35 | rm -rf /tmp/py3.7_build /var/lib/apt/lists/* 36 | 37 | RUN ln -s python3.7 /usr/local/bin/python && \ 38 | ln -s python3.7 /usr/local/bin/python3 && \ 39 | python --version 40 | 41 | RUN python -m pip install --upgrade pip && \ 42 | python -m pip install --upgrade virtualenv pip-review texttable psycopg2-binary psycopg2 && \ 43 | pip-review --auto 44 | 45 | RUN pip3 install pyyaml requests crosspm texttable psycopg2-binary psycopg2 46 | 47 | # INSTALL PLUGIN HELP TOOLS 48 | RUN set -ex && \ 49 | cd /usr/src/app/ && \ 50 | chmod +x /usr/src/app/codequality.py && \ 51 | chmod +x /usr/src/app/set-policy.py && \ 52 | chmod +x /usr/src/app/set-settings.py && \ 53 | ln -s /usr/src/app/codequality.py /usr/bin/codequality && \ 54 | ln -s /usr/src/app/set-policy.py /usr/bin/set-policy && \ 55 | ln -s /usr/src/app/set-settings.py /usr/bin/set-settings 56 | 57 | # INSTALL CERT 58 | RUN set -ex && \ 59 | cd /tmp/plugin_config/ ;\ 60 | for cert in $(ls *.crt) ; do keytool -importcert -keystore $JAVA_HOME/jre/lib/security/cacerts -storepass "changeit" -alias $cert -file $cert -noprompt ; done 61 | 62 | # INSTALL PLUGIN 63 | RUN set -ex && \ 64 | mkdir /tmp/plugin_src/ ;\ 65 | cd /tmp/plugin_src/ ;\ 66 | git clone https://github.com/PositiveTechnologies/ptaiPlugins ;\ 67 | cd ptaiPlugins/ptai-cli-plugin/ ;\ 68 | gradle build ;\ 69 | mv build/libs/ptai-cli-plugin.jar /root/ptai-plugin.jar ;\ 70 | echo "java -jar /root/ptai-plugin.jar \"\$@\" --token=${PLUGIN_TOKEN} --url=${AI_URI}" > /usr/src/app/ptai-plugin.sh ;\ 71 | chmod +x /usr/src/app/ptai-plugin.sh ;\ 72 | ln -s /usr/src/app/ptai-plugin.sh /usr/bin/ptai-plugin 73 | 74 | # GENERATE en_US LOCALE 75 | RUN set -ex; \ 76 | echo "en_US.UTF-8 UTF-8" >/etc/locale.gen; \ 77 | locale-gen 78 | 79 | # SET ENVIRONMENT 80 | ENV LANG="en_US.UTF-8" \ 81 | LANGUAGE="en_US:en" \ 82 | LC_ALL="en_US.UTF-8" 83 | 84 | RUN rm -rf /tmp/plugin_config 85 | RUN rm -rf /tmp/plugin_src 86 | -------------------------------------------------------------------------------- /GitLab_templates/AI.Cli.Plugin/AI-Plugin-dockerbuild/Docker/docker_build_data/applications/codequality.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # (c) DevOpsHQ, 2021 4 | 5 | import os 6 | import requests 7 | import json 8 | import argparse 9 | import yaml 10 | import texttable 11 | from pathlib import Path 12 | 13 | 14 | def teamcity_open_block(): 15 | print() 16 | print("##teamcity[blockOpened name='Vulnerabilities table']") 17 | 18 | 19 | def teamcity_close_block(): 20 | print("##teamcity[blockClosed name='Vulnerabilities table']") 21 | print() 22 | 23 | def set_security_rules(items_info, items_minor, items_major, items_critical, items_blocker, CI, settings): 24 | if settings is None: 25 | mapping = {'info': 'Potential', 26 | 'minor': 'Low', 27 | 'major': 'Medium', 28 | 'critical': 'High', 29 | 'blocker': ''} 30 | settings = {'info': 0, 31 | 'minor': 0, 32 | 'major': 0, 33 | 'critical': 0, 34 | 'blocker': 0} 35 | else: 36 | for p in Path('./').resolve().glob(settings): 37 | with p.open(encoding='utf-8-sig') as f: 38 | settings = yaml.full_load(f) # .get('security gates') 39 | mapping = settings['threats mapping'] 40 | settings = settings['security gates'] 41 | try: 42 | print('INFO - The AI Security gates is:') 43 | x = texttable.Texttable() 44 | x.header(['Gitlab Ci Code Quality', 'AI Severity Rules']) 45 | for key, value in settings.items(): 46 | x.add_row([key, value]) 47 | print(x.draw()) 48 | except AttributeError as e: 49 | print('ERROR - We have bad settings file') 50 | print(e) 51 | exit(1) 52 | 53 | len_info = {'info': f' {len(items_info)}'} 54 | len_minor = {'minor': f' {len(items_minor)}'} 55 | len_major = {'major': f' {len(items_major)}'} 56 | len_critical = {'critical': f' {len(items_critical)}'} 57 | len_blocker = {'blocker': f' {len(items_blocker)}'} 58 | len_total = len_info, len_minor, len_major, len_critical, len_blocker 59 | 60 | CI.result_blocker_vars = [] 61 | CI.block_mr = False 62 | 63 | for key, value in settings.items(): 64 | for item in len_total: 65 | for i in item.items(): 66 | if i[0] in key: 67 | if value != 0: 68 | if value < int(i[1]): 69 | CI.block_mr = True 70 | CI.result_blocker_vars.append(key) 71 | CI.security_gates = 'Check Security Gates: FAILED' 72 | print(f'WARNING - Exceeded the maximum number of allowed "{key}" level vulnerabilities') 73 | 74 | CI.result_blocker_body = '
**Threats Mapping:**'
 75 | 
 76 |     for key, value in mapping.items():
 77 |         CI.result_blocker_body = CI.result_blocker_body + f'
    **{key}**: *{value}*' 78 | 79 | CI.result_blocker_body = CI.result_blocker_body + f'
**Security Gates:**' 80 | 81 | for key, value in settings.items(): 82 | CI.result_blocker_body = CI.result_blocker_body + f'
    **{key}**: *{value}*' 83 | 84 | CI.result_blocker_body = CI.result_blocker_body + f'

' 85 | 86 | 87 | def get_items(items, CI): 88 | items_total = [] 89 | items_info = [] 90 | items_minor = [] 91 | items_major = [] 92 | items_critical = [] 93 | items_blocker = [] 94 | 95 | emoji = {'info': ':white_small_square:', 96 | 'minor': ':small_blue_diamond:', 97 | 'major': ':small_orange_diamond:', 98 | 'critical': ':small_red_triangle:', 99 | 'blocker': ':no_entry_sign:'} 100 | 101 | for key, value in emoji.items(): 102 | for data in items: 103 | if key in data['severity']: 104 | row = f"{value} {data['description']}
in [{data['location']['path']}:" \ 105 | f"{data['location']['lines']['begin']}]({CI.project_url}/blob/" \ 106 | f"{CI.commit_sha}/{data['location']['path']}#L{data['location']['lines']['begin']})
" 107 | items_total.append(row) 108 | if key == 'info': 109 | items_info.append(row) 110 | if key == 'minor': 111 | items_minor.append(row) 112 | if key == 'major': 113 | items_major.append(row) 114 | if key == 'critical': 115 | items_critical.append(row) 116 | if key == 'blocker': 117 | items_blocker.append(row) 118 | else: 119 | pass 120 | 121 | table = texttable.Texttable() 122 | table.header(['Level', 'Description', 'location']) 123 | for data in items: 124 | row = [f"{data['severity']}", f"{data['description']}", 125 | f"{data['location']['path']}#L{data['location']['lines']['begin']}"] 126 | table.add_row(row) 127 | table.set_cols_width((8, 50, 90)) 128 | 129 | if CI.ci_name == 'TeamCity': 130 | teamcity_open_block() 131 | print(table.draw()) 132 | teamcity_close_block() 133 | 134 | if len(items_total) == 0: 135 | print('WARNING - json file with vulnerabilities not found') 136 | print('Check Security Gates: PASSED') 137 | exit(0) 138 | 139 | return items_total, items_info, items_minor, items_major, items_critical, items_blocker 140 | 141 | 142 | def convert_to_markdown(items_total, items_info, items_minor, items_major, items_critical, items_blocker, CI, 143 | input_folder): 144 | 145 | print(f"INFO - Application Inspector detect {len(items_total)} vulnerabilities:\n\n" 146 | f" {len(items_blocker)} Blocker\n" 147 | f" {len(items_critical)} High\n" 148 | f" {len(items_major)} Medium\n" 149 | f" {len(items_minor)} Low\n" 150 | f" {len(items_info)} Potential\n\n") 151 | 152 | if CI.commit_sha is not None: 153 | short_commit_sha = CI.commit_sha[:9] 154 | else: 155 | print('WARNING - SHA not found, no threads were generated.') 156 | print(CI.security_gates) 157 | exit(0) 158 | 159 | if CI.html_report is not None: 160 | if CI.ci_name == 'GitLab': 161 | gitlab_artifacts_url = os.environ.get('CI_JOB_URL') 162 | CI.gitlab_artifacts_url = f'{gitlab_artifacts_url}/artifacts/file/{input_folder}/ai_full_report.html' 163 | CI.footer = f'
:chart_with_upwards_trend: See full [AI HTML report]({CI.gitlab_artifacts_url}) ' \ 164 | f'in [GitLab job]({gitlab_artifacts_url}).' 165 | elif CI.ci_name == 'TeamCity': 166 | CI.tc_build_url = f'{CI.teamcity_server_url}/viewLog.html?buildTypeId={CI.teamcity_buildType_id}&buildId=' \ 167 | f'{CI.teamcity_build_id}' 168 | CI.tc_artifacts_url = f'{CI.teamcity_server_url}/repository/download/{CI.teamcity_buildType_id}/' \ 169 | f'{CI.teamcity_build_id}:id/ai_full_report.html' 170 | CI.footer = f'
:chart_with_upwards_trend: See full [AI HTML report]({CI.tc_artifacts_url}) ' \ 171 | f'in [TeamCity build]({CI.tc_build_url}).' 172 | else: 173 | CI.footer = '
:chart_with_upwards_trend: See full AI html-report in local job artifacts.' 174 | else: 175 | CI.footer = '' 176 | 177 | if CI.block_mr is True: 178 | result_blocker = '
:no_entry_sign: Merge Request has been locked by ' \ 179 | 'current AI Security Gates' \ 180 | f'{CI.result_blocker_body}
' 181 | else: 182 | result_blocker = '
' 183 | 184 | result = f"![](https://www.ptsecurity.com/local/templates/pt_corp2017/build/img/favicon.ico)" \ 185 | f" Application Inspector detect **{len(items_total)}** vulnerabilities for *[{short_commit_sha}]" \ 186 | f"({CI.project_url}/-/commit/{CI.commit_sha})*:
{result_blocker}" \ 187 | f"**Found vulnerabilities:**
" \ 188 | f":small_red_triangle: **{len(items_blocker)}** Blocker
" \ 189 | f":small_red_triangle_down: **{len(items_critical)}** High
" \ 190 | f":small_orange_diamond: **{len(items_major)}** Medium
" \ 191 | f":small_blue_diamond: **{len(items_minor)}** Low
" \ 192 | f":white_small_square: **{len(items_info)}** Potential
" \ 193 | f"
More results...

" 194 | result_footer = f'

{CI.footer}' 195 | 196 | if len(items_blocker) > 0: 197 | result_blocker = '
:small_red_triangle: Blocker vulnerabilities list:

' 198 | for x in items_blocker: 199 | result_blocker = result_blocker + x 200 | result_blocker = result_blocker + '

' 201 | else: 202 | result_blocker = '' 203 | if len(items_critical) > 0: 204 | result_critical = '
:small_red_triangle: High vulnerabilities list:

' 205 | for x in items_critical: 206 | result_critical = result_critical + x 207 | result_critical = result_critical + '

' 208 | else: 209 | result_critical = '' 210 | if len(items_major) > 0: 211 | result_major = '
:small_orange_diamond: Medium vulnerabilities list:

' 212 | for x in items_major: 213 | result_major = result_major + x 214 | result_major = result_major + '

' 215 | else: 216 | result_major = '' 217 | if len(items_minor) > 0: 218 | result_minor = '
:small_blue_diamond: Low vulnerabilities list:

' 219 | for x in items_minor: 220 | result_minor = result_minor + x 221 | result_minor = result_minor + '

' 222 | else: 223 | result_minor = '' 224 | if len(items_info) > 0: 225 | result_info = '
:white_small_square: Potential vulnerabilities list:

' 226 | for x in items_info: 227 | result_info = result_info + x 228 | result_info = result_info + '

' 229 | else: 230 | result_info = '' 231 | 232 | result = result + result_blocker + result_critical + result_major + result_minor + result_info + result_footer 233 | 234 | return result 235 | 236 | 237 | def create_gitlab_thread(result, gitlab_token, CI): 238 | print('INFO - Script started generating Gitlab Merge Request threads.') 239 | headers = {'Content-Type': "application/x-www-form-urlencoded; charset=UTF-8", "attachment": "filename=file.md"} 240 | body = {'body': '{result}'.format(**locals())} 241 | 242 | gitlab_token = '&access_token=' + gitlab_token 243 | pages = '&per_page=100' 244 | 245 | opened_merge_requests = [] 246 | 247 | count = 1 248 | while count < 40: 249 | page = "&page={count}".format(**locals()) 250 | count += 1 251 | merge_requests_url = f"{CI.api_url}/projects/{CI.project_id}/merge_requests?{gitlab_token}{pages}{page}" 252 | 253 | response = requests.get(url=merge_requests_url, headers=headers) 254 | if response.status_code == 404: 255 | print('WARNING - Merge requests not found. Maybe you have no access to the GitLab projects or all merge ' 256 | 'requests are merged..') 257 | print(f'DEBUG - URL: {merge_requests_url}') 258 | print(CI.security_gates) 259 | exit(0) 260 | 261 | json_response_body = json.loads(response.content.decode('utf-8')) 262 | 263 | for merge_request in json_response_body: 264 | if merge_request['state'] == 'opened': 265 | opened_merge_requests.append(merge_request) 266 | if len(json_response_body) == 0: 267 | break 268 | 269 | if len(opened_merge_requests) == 0: 270 | print('INFO - Opened merge requests not found') 271 | print(CI.security_gates) 272 | exit(0) 273 | 274 | founded_mr_with_needed_sha = 0 275 | for mr in opened_merge_requests: 276 | if mr['sha'] == CI.commit_sha: 277 | founded_mr_with_needed_sha += 1 278 | iid = mr['iid'] 279 | mr_list = [] 280 | modify = 0 281 | count = 1 282 | 283 | while count < 100: 284 | page = "&page={count}".format(**locals()) 285 | count += 1 286 | merge_requests_url = f"{CI.api_url}/projects/{CI.project_id}/merge_requests/{iid}/discussions?" \ 287 | f"{gitlab_token}{pages}{page}" 288 | response = requests.get(url=merge_requests_url, headers=headers) 289 | json_response_body = json.loads(response.content.decode('utf-8')) 290 | 291 | mr_list.append(json_response_body) 292 | 293 | if len(json_response_body) == 0: 294 | break 295 | 296 | for x in mr_list[0]: 297 | if 'Application Inspector detect' in x['notes'][0]['body']: 298 | new_merge_requests_url = f"{CI.api_url}/projects/{CI.project_id}/merge_requests/{iid}/" \ 299 | f"discussions/{x['id']}/notes/{x['notes'][0]['id']}?" \ 300 | f"{gitlab_token}" 301 | requests.put(url=new_merge_requests_url, data=body, headers=headers) 302 | 303 | if CI.block_mr is True: 304 | if 'Draft: ' in str(mr['title']): 305 | print('INFO - Merge request has been drafted already') 306 | else: 307 | title = f'Draft: {mr["title"]}' 308 | new_title = {'title': '{title}'.format(**locals())} 309 | 310 | blocked_merge_request_url = f"{CI.api_url}/projects/{CI.project_id}/merge_requests/{iid}?" \ 311 | f"{gitlab_token}" 312 | requests.put(url=blocked_merge_request_url, data=new_title, headers=headers) 313 | print(F"INFO - State on {CI.project_url}/-/merge_requests/{iid} was changed to draft.") 314 | modify = 1 315 | print(F"INFO - Thread on {CI.project_url}/-/merge_requests/{iid} was modified.") 316 | else: 317 | pass 318 | if modify == 0: 319 | merge_requests_url = f"{CI.api_url}/projects/{CI.project_id}/merge_requests/{iid}/discussions?" \ 320 | f"{gitlab_token}" 321 | response = requests.post(url=merge_requests_url, data=body, headers=headers) 322 | json_response_body = json.loads(response.content.decode('utf-8')) 323 | if CI.block_mr is True: 324 | if 'Draft: ' in str(mr['title']): 325 | print('INFO - Merge request has been drafted already') 326 | else: 327 | title = f'Draft: {mr["title"]}' 328 | new_title = {'title': '{title}'.format(**locals())} 329 | 330 | blocked_merge_request_url = f"{CI.api_url}/projects/{CI.project_id}/merge_requests/{iid}?" \ 331 | f"{gitlab_token}" 332 | requests.put(url=blocked_merge_request_url, data=new_title, headers=headers) 333 | print(F"INFO - State on {CI.project_url}/-/merge_requests/{iid} was changed to draft.") 334 | print(F"INFO - Thread on {CI.project_url}/-/merge_requests/{iid} was created.") 335 | if founded_mr_with_needed_sha > 0: 336 | pass 337 | else: 338 | print('WARNING - SHA not found, no threads were generated.') 339 | 340 | 341 | def convert_items(items, settings): 342 | try: 343 | print('INFO - The threats mapping is:') 344 | x = texttable.Texttable() 345 | x.header(['Gitlab Ci Code Quality', 'AI Threats Mapping']) 346 | for key, value in settings.items(): 347 | x.add_row([key, value]) 348 | print(x.draw()) 349 | except AttributeError as e: 350 | print('ERROR - We have bad settings file') 351 | print(e) 352 | exit(1) 353 | 354 | for key, value in settings.items(): 355 | for i in items: 356 | if i['Level']['DisplayName'] in value: 357 | yield { 358 | "description": f"[{i['Level']['DisplayName']}] {i['Type']['DisplayName']}", 359 | "fingerprint": i['Id'], 360 | "severity": f"{key}", 361 | "location": { 362 | "path": i['SourceFile'].split(':')[0].replace('\\', '/').replace('./', '').strip(), 363 | "lines": { 364 | "begin": i.get('BeginLine', i.get('NumberLine')) 365 | } 366 | } 367 | } 368 | else: 369 | pass 370 | 371 | 372 | def read_reports(input_folder, settings): 373 | dir_files = os.listdir(input_folder) 374 | files = [] 375 | 376 | if settings is None: 377 | settings = {'info': 'Potential', 378 | 'minor': 'Low', 379 | 'major': 'Medium', 380 | 'critical': 'High', 381 | 'blocker': ''} 382 | else: 383 | for p in Path('./').resolve().glob(settings): 384 | with p.open(encoding='utf-8-sig') as f: 385 | settings = yaml.full_load(f).get('threats mapping') 386 | 387 | for f in dir_files: 388 | if '.json' in f: 389 | f = input_folder + '/' + f 390 | files.append(f) 391 | if len(files) > 0: 392 | file = max(files, key=os.path.getctime) 393 | for p in Path('./').resolve().glob(file): 394 | with p.open(encoding='utf-8-sig') as f: 395 | x = json.load(f) 396 | try: 397 | yield from convert_items(x['Items'], settings) 398 | except TypeError: 399 | print('ERROR - In input folder we have bad json file') 400 | exit(1) 401 | else: 402 | print('WARNING - Json report not found.') 403 | print('Check Security Gates: Unknown') 404 | exit(0) 405 | 406 | 407 | def main(input_folder, output_file, gitlab_token, settings_file, block_mr, income_args): 408 | print('INFO - aisa-codequality started successfully!') 409 | 410 | def define_ci_server(arguments): 411 | """ 412 | Return CI server type with specific environment 413 | """ 414 | # Check predefined environment variable to define CI server, TC by default, Gitlab CI by checking CI variable 415 | # https://docs.gitlab.com/ee/ci/variables/ 416 | if os.environ.get('CI', False): 417 | return GitlabCI() 418 | elif arguments.ci_type == 'GitLab': 419 | return GitlabCI() 420 | elif arguments.ci_type == 'TeamCity': 421 | return TeamCity(arguments) 422 | else: 423 | return Local(arguments) 424 | 425 | class GitlabCI(object): 426 | def __init__(self): 427 | self.ci_name = 'GitLab' 428 | self.commit_sha = os.environ.get('CI_COMMIT_SHA') 429 | self.project_id = os.environ.get('CI_PROJECT_ID') 430 | self.project_url = os.environ.get('CI_PROJECT_URL') 431 | self.api_url = os.environ.get('CI_API_V4_URL') 432 | 433 | class TeamCity(object): 434 | def __init__(self, arguments): 435 | self.ci_name = 'TeamCity' 436 | self.commit_sha = arguments.commit_sha 437 | self.teamcity_server_url = arguments.teamcity_server_url 438 | self.teamcity_build_id = arguments.teamcity_build_id 439 | self.teamcity_buildType_id = arguments.teamcity_buildType_id 440 | self.project_id = arguments.gitlab_project_id 441 | self.project_url = arguments.gitlab_project_url 442 | self.api_url = arguments.gitlab_api_url 443 | 444 | class Local(object): 445 | def __init__(self, arguments): 446 | self.ci_name = 'Local' 447 | self.commit_sha = arguments.commit_sha 448 | self.project_id = arguments.gitlab_project_id 449 | self.project_url = arguments.gitlab_project_url 450 | self.api_url = arguments.gitlab_api_url 451 | 452 | CI = define_ci_server(income_args) 453 | CI.security_gates = 'Check Security Gates: PASSED' 454 | CI.html_report = os.path.join(input_folder, "ai_full_report.html") 455 | 456 | print('\n+-- Variables -----------------------------------+') 457 | print(f' CI name: {CI.ci_name}\n' 458 | f' Commit sha: {CI.commit_sha}\n' 459 | f' Project ID: {CI.project_id}\n' 460 | f' Project URL: {CI.project_url}\n' 461 | f' API URL: {CI.api_url}\n' 462 | f' Input folder: {input_folder}\n') 463 | print('+------------------------------------------------+') 464 | 465 | print('INFO - Try to convert report to {output_file}.'.format(**locals())) 466 | result = list(read_reports(input_folder, settings_file)) 467 | if len(result) == 0: 468 | print('INFO - Result is null'.format(**locals())) 469 | else: 470 | with open(output_file, 'w', encoding='utf-8') as f: 471 | json.dump(result, f), f.close() 472 | print('INFO - File {output_file} was generated.'.format(**locals())) 473 | 474 | if gitlab_token is None: 475 | print('INFO - Script was completed without Thread.\n ' 476 | 'Please specify GitLab personal token for create threads.') 477 | print('Check Security Gates: Unknown') 478 | exit(0) 479 | 480 | items_total, items_info, items_minor, items_major, items_critical, items_blocker = get_items(result, CI) 481 | set_security_rules(items_info, items_minor, items_major, items_critical, items_blocker, CI, settings=settings_file) 482 | 483 | result = convert_to_markdown(items_total, items_info, items_minor, items_major, items_critical, items_blocker, 484 | CI, input_folder) 485 | if block_mr is False: 486 | CI.block_mr = False 487 | 488 | create_gitlab_thread(result, gitlab_token, CI) 489 | print('INFO - aisa-codequality completed successfully!') 490 | print(CI.security_gates) 491 | 492 | 493 | def parse_args(): 494 | parser = argparse.ArgumentParser() 495 | parser.add_argument('-i', "--input_folder", action="store", required=False, default='.report', 496 | help="The name of reports folder") 497 | parser.add_argument('-o', "--output_file", action="store", required=False, default='codequality.json', 498 | help="The name of json file") 499 | parser.add_argument('-t', "--token", action="store", required=False, help="Gitlab CI builder Token") 500 | parser.add_argument('-s', "--settings_file", action="store", required=False, help="The name of settings file") 501 | parser.add_argument('-sha', "--commit_sha", action="store", required=False, help="The commit sha") 502 | parser.add_argument('-gpid', "--gitlab_project_id", action="store", required=False, help="Gitlab project id") 503 | parser.add_argument('-gpurl', "--gitlab_project_url", action="store", required=False, help="Gitlab project url") 504 | parser.add_argument('-gaurl', "--gitlab_api_url", action="store", required=False, help="Gitlab api url") 505 | parser.add_argument('-tcbid', "--teamcity_build_id", action="store", required=False, 506 | help="TeamCity build id %teamcity.build.id%") 507 | parser.add_argument('-tcbtid', "--teamcity_buildType_id", action="store", required=False, 508 | help="TeamCity project build id %system.teamcity.buildType.id%") 509 | parser.add_argument('-tcurl', "--teamcity_server_url", action="store", required=False, help="TeamCity server url") 510 | parser.add_argument('-ci', "--ci_type", action="store", required=False, default='Local', 511 | help="Variable for define CI system (TeamCity, GitLab, etc.)") 512 | parser.add_argument('-b', "--block_mr", action="store", required=False, default=False, 513 | help="Rename MR from `title` to `draft: title`") 514 | arguments = parser.parse_args() 515 | return arguments 516 | 517 | 518 | if __name__ == '__main__': 519 | args = parse_args() 520 | main( 521 | input_folder=args.input_folder, # Folder with json report from aisa 522 | output_file=args.output_file, # Output json file for code quality 523 | gitlab_token=args.token, # Folder with json report from aisa 524 | settings_file=args.settings_file, # The name of yaml file with settings 525 | block_mr=args.block_mr, # Rename MR from `title` to `draft: title` 526 | income_args=args 527 | ) 528 | -------------------------------------------------------------------------------- /GitLab_templates/AI.Cli.Plugin/AI-Plugin-dockerbuild/Docker/docker_build_data/applications/set-policy.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # (c) DevOpsHQ, 2021 4 | 5 | import os 6 | import re 7 | import argparse 8 | import sys 9 | 10 | 11 | def parse_args(): 12 | parser = argparse.ArgumentParser() 13 | parser.add_argument("--count_to_actualize", action="store", default=1, required=False) 14 | parser.add_argument("--level", action="store", default="Medium", required=False) 15 | parser.add_argument("--exploit", action="store", default='"."', required=False) 16 | parser.add_argument("--is_suspected", action="store", default="false", required=False) 17 | parser.add_argument("--approval_state", action="store", default="[^2]", required=False) 18 | args = parser.parse_args() 19 | return args 20 | 21 | 22 | def create_json(args): 23 | json = ''' 24 | [ 25 | { 26 | "CountToActualize": $count_to_actl, 27 | "Scopes": [ 28 | { 29 | "Rules": [ 30 | { 31 | "Field": "Level", 32 | "Value": "$level", 33 | "IsRegex": false 34 | }, 35 | { 36 | "Field": "Exploit", 37 | "Value": $exploit, 38 | "IsRegex": true 39 | }, 40 | { 41 | "Field": "IsSuspected", 42 | "Value": "$is_suspected", 43 | "IsRegex": false 44 | }, 45 | { 46 | "Field": "ApprovalState", 47 | "Value": "$approval_state", 48 | "IsRegex": true 49 | } 50 | ] 51 | } 52 | ] 53 | } 54 | ] 55 | ''' 56 | json = re.sub(r"\$count_to_actl", str(args.count_to_actualize), json, 1) 57 | json = re.sub(r"\$level", str(args.level), json, 1) 58 | json = re.sub(r"\$exploit", str(args.exploit), json, 1) 59 | json = re.sub(r"\$is_suspected", str(args.is_suspected), json, 1) 60 | json = re.sub(r"\$approval_state", str(args.approval_state), json, 1) 61 | 62 | return json 63 | 64 | 65 | def print_info(count_to_actualize, 66 | level, 67 | exploit, 68 | is_suspected, 69 | approval_state): 70 | print("-" * 50) 71 | print("[INFO]: CountToActualize: {count_to_actualize}".format(**locals())) 72 | print("[INFO]: Level: {level}".format(**locals())) 73 | print("[INFO]: Exploit: {exploit}".format(**locals())) 74 | print("[INFO]: IsSuspected: {is_suspected}".format(**locals())) 75 | print("[INFO]: ApprovalState: {approval_state}".format(**locals())) 76 | print("-" * 50) 77 | 78 | 79 | def main(args): 80 | print("[INFO]: Start generating policy") 81 | 82 | print_info(count_to_actualize=args.count_to_actualize, 83 | level=args.level, 84 | exploit=args.exploit, 85 | is_suspected=args.is_suspected, 86 | approval_state=args.approval_state) 87 | 88 | json_file = create_json(args) 89 | 90 | file_name = "policy.json" 91 | 92 | if "{file_name}".format(**locals()) in os.listdir("."): 93 | sys.stderr.write("[ERROR]: File exists\n") 94 | else: 95 | proj = open("{file_name}".format(**locals()), "a") 96 | proj.write(json_file) 97 | proj.close() 98 | print("[INFO]: File {proj.name} was generated successfully".format(**locals())) 99 | 100 | 101 | if __name__ == '__main__': 102 | arguments = parse_args() 103 | main(arguments) 104 | -------------------------------------------------------------------------------- /GitLab_templates/AI.Cli.Plugin/AI-Plugin-dockerbuild/Docker/docker_build_data/applications/set-settings.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # (c) Positive Technologies, 2020 4 | 5 | import sys 6 | import os 7 | import re 8 | import argparse 9 | 10 | import platform 11 | 12 | 13 | def parse_args(): 14 | parser = argparse.ArgumentParser() 15 | parser.add_argument("--projectname", 16 | action="store", 17 | help="The name of project", 18 | required=True) 19 | parser.add_argument("--language", 20 | action="store", 21 | help="Programming language to find in project", 22 | required=True) 23 | parser.add_argument("--path", 24 | action="store", 25 | help="Path to project for scan", 26 | default="./", 27 | required=False) 28 | parser.add_argument("--exclude-formats", 29 | action="store", 30 | help="Whether to exclude non-sources files from scanning (True or False)", 31 | default="True", 32 | required=False) 33 | parser.add_argument("--excluded-paths", 34 | action="store", 35 | nargs="+", 36 | help="Exclude certain files and folders from scan. " 37 | "Use single \\ with apostrophes and double \\ with quotes " 38 | "(e.g. '\\devops-tools' " 39 | '"\\\\.git\\\\")', 40 | required=False) 41 | arguments = parser.parse_args() 42 | return arguments 43 | 44 | 45 | def check_platform(os_type): 46 | if os_type == 'Windows': 47 | return "Windows" 48 | else: 49 | return "Linux" 50 | 51 | 52 | def check_args(projectname, language, languages, path_to_folder): 53 | if "{projectname}.aiproj".format(**locals()) in os.listdir("."): 54 | print("-" * 50) 55 | print("[WARNING]: File {projectname}.aiproj exists".format(**locals())) 56 | print(" Try to overwrite") 57 | print("-" * 50) 58 | if language in languages: 59 | print("[INFO]: Arguments is correct") 60 | else: 61 | sys.stderr.write("[ERROR]: Unknown language\n") 62 | sys.exit(1) 63 | 64 | # TODO: IsUsePublicAnalysisMethod вынести в args 65 | def create_json(projectname, language, exclude_formats, excluded_paths_list): 66 | config = r'''{ 67 | "ProjectName": "$ProjectName", 68 | "ProgrammingLanguage": "$LANG", 69 | "ScanAppType": "Configuration, Fingerprint, PmTaint, DependencyCheck, $COND", 70 | "Site": "http://localhost", 71 | "IsDownloadDependencies": true, 72 | 73 | "IsUsePublicAnalysisMethod": true, 74 | "IsUseEntryAnalysisPoint": true, 75 | 76 | "ScanUnitTimeout": 360, 77 | "PreprocessingTimeout": 60, 78 | "CustomParameters": $CUSTOM, 79 | 80 | "SkipFileFormats": $EXCLUDED_FILE_FORMATS, 81 | "SkipFilesFolders": ["\\devops-tools", "\\.git\\", "\\.gitignore", "\\.gitmodules", "\\.gitattributes", "\\$tf\\", "\\$BuildProcessTemplate\\", "\\.tfignore"$EXCLUDED_FILES_FOLDERS], 82 | 83 | "DisabledPatterns": ["145", "146", "148", "149"], 84 | "DisabledTypes": [], 85 | 86 | "UseIncrementalScan": true, 87 | "FullRescanOnNewFilesAdded": true, 88 | 89 | "ConsiderPreviousScan": true, 90 | "HideSuspectedVulnerabilities": false, 91 | "UseIssueTrackerIntegration": false, 92 | 93 | "IsUnpackUserPackages": false, 94 | "JavaParameters": null, 95 | "JavaVersion": 0, 96 | "UseJavaNormalizeVersionPattern": "true", 97 | "JavaNormalizeVersionPattern": "-\\d+(\\.\\d+)*", 98 | 99 | "JavaScriptProjectFile": null, 100 | "JavaScriptProjectFolder": null, 101 | 102 | "UseTaintAnalysis": true, 103 | "UsePmAnalysis": true, 104 | "DisableInterpretCores": false, 105 | 106 | "UseDefaultFingerprints": true, 107 | "UseCustomYaraRules": false, 108 | 109 | "CustomHeaders": [["", ""]], 110 | "Authentication": { 111 | "auth_item": { 112 | "domain": null, 113 | "credentials": { 114 | "cookie": null, 115 | "type": 2, 116 | "login": { 117 | "name": null, 118 | "value": null, 119 | "regexp": null, 120 | "is_regexp": false 121 | }, 122 | "password": { 123 | "name": null, 124 | "value": null, 125 | "regexp": null, 126 | "is_regexp": false 127 | } 128 | }, 129 | "test_url": null, 130 | "form_url": null, 131 | "form_xpath": ".//form", 132 | "regexp_of_success": null 133 | } 134 | }, 135 | "ProxySettings": { 136 | "IsEnabled": false, 137 | "Host": null, 138 | "Port": null, 139 | "Type": 0, 140 | "Username": null, 141 | "Password": null 142 | }, 143 | 144 | "RunAutocheckAfterScan": false, 145 | "AutocheckSite": "http://localhost", 146 | "AutocheckCustomHeaders": [["", ""]], 147 | "AutocheckAuthentication": { 148 | "auth_item": { 149 | "domain": null, 150 | "credentials": { 151 | "cookie": null, 152 | "cookies": null, 153 | "type": 2, 154 | "login": { 155 | "name": null, 156 | "value": null, 157 | "regexp": null, 158 | "is_regexp": false 159 | }, 160 | "password": { 161 | "name": null, 162 | "value": null, 163 | "regexp": null, 164 | "is_regexp": false 165 | } 166 | }, 167 | "test_url": null, 168 | "form_url": null, 169 | "form_xpath": ".//form", 170 | "regexp_of_success": null 171 | } 172 | }, 173 | "AutocheckProxySettings": { 174 | "IsEnabled": false, 175 | "Host": null, 176 | "Port": null, 177 | "Type": 0, 178 | "Username": null, 179 | "Password": null 180 | }, 181 | 182 | "SendEmailWithReportsAfterScan": false, 183 | "CompressReport": false, 184 | 185 | "EmailSettings": null, 186 | 187 | "ReportParameters": { 188 | "SaveAsPath": null, 189 | "UseElectronicSignature": false, 190 | "CertificatePath": null, 191 | "Password": null, 192 | "ShowSignatureTime": false, 193 | "SignatureReason": null, 194 | "Location": null, 195 | "DoSignatureVisible": false, 196 | "IncludeDiscardedVulnerabilities": false, 197 | "IncludeSuppressedVulnerabilities": true, 198 | "IncludeSuspectedVulnerabilities": false, 199 | "IncludeGlossary": false, 200 | "ConverHtmlToPdf": false, 201 | "RemoveHtml": false, 202 | "CreatePdfPrintVersion": false, 203 | "MakeAFReport": false, 204 | "IncludeDFD": false 205 | } 206 | } 207 | ''' # noqa 208 | json = re.sub(r"\$ProjectName", projectname, config, 1) 209 | json = re.sub(r"\$LANG", language, json, 1) 210 | 211 | if language == "Php": 212 | json = re.sub(r", \$COND", ", Php", json, 1) 213 | elif language == "Java": 214 | json = re.sub(r", \$COND", ", Java", json, 1) 215 | elif language == "JavaScript": 216 | json = re.sub(r", \$COND", ", JavaScript", json, 1) 217 | elif language == "Csharp" or language == "Vb": 218 | json = re.sub(r", \$COND", ", CSharp", json, 1) 219 | else: 220 | json = re.sub(r", \$COND", "", json, 1) 221 | 222 | if language == "Python": 223 | json = re.sub(r"\$CUSTOM", r'"--multifile"', json, 1) 224 | else: 225 | json = re.sub(r"\$CUSTOM", "null", json, 1) 226 | 227 | 228 | excluded_formats_list = '["*.7z", "*.bmp", "*.dib", "*.dll", "*.doc", "*.docx", "*.exe", "*.gif", "*.ico", ' \ 229 | '"*.jfif", "*.jpe", "*.jpe6", "*.jpeg", "*.jpg", "*.odt", "*.pdb", "*.pdf", "*.png", ' \ 230 | '"*.rar", "*.swf", "*.tif", "*.tiff", "*.zip"]' 231 | 232 | try: 233 | print("[INFO]: Exclude non-source files from scanning: {exclude_formats}".format(**locals())) 234 | if exclude_formats in ('FALSE', 'False', 'false'): 235 | json = re.sub(r"\$EXCLUDED_FILE_FORMATS", "null", json, 1) 236 | elif exclude_formats in ('TRUE', 'True', 'true'): 237 | json = re.sub(r"\$EXCLUDED_FILE_FORMATS", excluded_formats_list, json, 1) 238 | else: 239 | raise ValueError() 240 | except (ValueError, Exception): 241 | print('[WARNING]: You have specified an invalid value. Used "True" as the default.') 242 | json = re.sub(r"\$EXCLUDED_FILE_FORMATS", excluded_formats_list, json, 1) 243 | 244 | try: 245 | print("[INFO]: Excluded files and folders list: {excluded_paths_list}".format(**locals())) 246 | if excluded_paths_list is not None: 247 | excluded_paths_string = '' 248 | for excluded_item in excluded_paths_list: 249 | # Take raw value and remove apostrophes 250 | prepared_excluded_item = repr(excluded_item).replace("'", "") 251 | excluded_paths_string = excluded_paths_string + r', "{prepared_excluded_item}"'.format(**locals()) 252 | json = json.replace("$EXCLUDED_FILES_FOLDERS", excluded_paths_string, 1) 253 | else: 254 | json = json.replace("$EXCLUDED_FILES_FOLDERS", '', 1) 255 | except (ValueError, Exception): 256 | print('[WARNING]: Something went wrong! The default values are used.') 257 | json = json.replace("$EXCLUDED_FILES_FOLDERS", '', 1) 258 | 259 | return json 260 | 261 | 262 | def print_info(projectname, language, path_to_file): 263 | if path_to_file == '': 264 | folder = './' 265 | print("-" * 50) 266 | print("[INFO]: Project name: {projectname}".format(**locals())) 267 | print("[INFO]: File name: {projectname}.aiproj".format(**locals())) 268 | print("[INFO]: Language: {language}".format(**locals())) 269 | print("[INFO]: Path: {path_to_file}".format(**locals())) 270 | print("-" * 50) 271 | 272 | 273 | def main(prj, lang, path, exclude_formats, excluded_paths_list): 274 | # ---------- Variables ---------- 275 | #lang = lang.lower() 276 | langs = ["Kotlin", "Java", "Swift", "Csharp", "Go", "ObjectiveC", "Vb", "JavaScript", "Sql", "CPlusPlus", "Php", "Python"] 277 | os_type = platform.system() 278 | 279 | # ------------- Run ------------- 280 | 281 | check_args(prj, lang, langs, path) 282 | json_file = create_json(prj, lang, exclude_formats, excluded_paths_list) 283 | print_info(prj, lang, path) 284 | 285 | proj = open("{prj}.aiproj".format(**locals()), "w") 286 | proj.write(json_file) 287 | proj.close() 288 | print("[INFO]: File {proj.name} was generated successfully".format(**locals())) 289 | 290 | 291 | if __name__ == '__main__': 292 | print("[INFO]: Start generating project") 293 | args = parse_args() 294 | main( 295 | prj=args.projectname, # Project name 296 | lang=args.language, # Language 297 | path=args.path, # Path to folder 298 | exclude_formats=args.exclude_formats, # Exclusion non-sources files from scanning (on/off) 299 | excluded_paths_list=args.excluded_paths # Exclusion paths from scanning 300 | ) -------------------------------------------------------------------------------- /GitLab_templates/AI.Cli.Plugin/AI-Plugin-dockerbuild/Docker/docker_build_data/config/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devopshq/dohq-ai-best-practices/563f94b3b0371b25305ed03349c42564beaac92b/GitLab_templates/AI.Cli.Plugin/AI-Plugin-dockerbuild/Docker/docker_build_data/config/.gitkeep -------------------------------------------------------------------------------- /GitLab_templates/AI.Cli.Plugin/AI-Templates/AI-basic-template/AI-Run-in-parallel.yml: -------------------------------------------------------------------------------- 1 | # This template is used for parallel scanning with PT Application Inspector 2 | 3 | stages: 4 | - AI Downstream scan 5 | 6 | # --- Pipeline Aliases --------------------------------------- 7 | 8 | # Common variables to run AI Scan 9 | .common-variables: &common-variables 10 | variables: 11 | DOCKER_IMAGE: ${REGISTRY_ADDRESS}/tools/ai-plugin:latest # URN of docker registry with AI plugin container 12 | PARENT_CI_PIPELINE_ID: ${CI_PIPELINE_ID} 13 | PROJECT_NAME: ${AI_PROJECT_NAME} 14 | PROJECT_LANGUAGE: ${AI_PROJECT_LANGUAGE} 15 | USE_SERVER_SETTINGS: ${AI_USE_SERVER_SETTINGS} 16 | PROJECT_SETTINGS: ${AI_PROJECT_SETTINGS} 17 | CUSTOM_PLUGIN_PARAMS: ${AI_CUSTOM_PLUGIN_PARAMS} 18 | DEPS_MANAGER: ${AI_DEPENDENCY_PROVIDER} 19 | REPORT_JSON: | # Reports to be generated after scanning is finished 20 | { 21 | "report" : [ 22 | { 23 | "fileName" : "ai_full_report.html", 24 | "locale" : "RU", 25 | "format" : "HTML", 26 | "template" : "Отчет по результатам сканирования" 27 | },{ 28 | "fileName" : "tier1.html", 29 | "locale" : "RU", 30 | "format" : "HTML", 31 | "template" : "Отчет по результатам сканирования", 32 | "filters": { 33 | "issueLevels": ["MEDIUM", "HIGH"], 34 | "scanMode": "FROMENTRYPOINT", 35 | "confirmationStatuses": ["UNDEFINED", "NONE", "APPROVED", "AUTOAPPROVED"] 36 | } 37 | },{ 38 | "fileName" : "tier2.html", 39 | "locale" : "RU", 40 | "format" : "HTML", 41 | "template" : "Отчет по результатам сканирования", 42 | "filters": { 43 | "issueLevels": ["MEDIUM", "HIGH"], 44 | "scanMode": "FROMPUBLICPROTECTED", 45 | "confirmationStatuses": ["UNDEFINED", "NONE", "APPROVED", "AUTOAPPROVED"] 46 | } 47 | },{ 48 | "fileName" : "tier3.html", 49 | "locale" : "RU", 50 | "format" : "HTML", 51 | "template" : "Отчет по результатам сканирования", 52 | "filters": { 53 | "issueLevels": ["LOW", "POTENTIAL"], 54 | "confirmationStatuses": ["UNDEFINED", "NONE", "APPROVED", "AUTOAPPROVED"], 55 | "sourceType": "STATIC" 56 | } 57 | },{ 58 | "fileName" : "new.html", 59 | "locale" : "RU", 60 | "format" : "HTML", 61 | "template" : "Отчет по результатам сканирования", 62 | "filters": { 63 | "actualStatus": "ISNEW", 64 | "confirmationStatuses": ["UNDEFINED", "NONE", "APPROVED", "AUTOAPPROVED"] 65 | } 66 | },{ 67 | "fileName" : "vulnerable components.html", 68 | "locale" : "RU", 69 | "format" : "HTML", 70 | "template" : "Отчет по результатам сканирования", 71 | "filters": { 72 | "issueLevels": ["MEDIUM", "HIGH"], 73 | "confirmationStatuses": ["UNDEFINED", "NONE", "APPROVED", "AUTOAPPROVED"], 74 | "scanMode": "FROMOTHER", 75 | "sourceType": "STATIC" 76 | } 77 | },{ 78 | "fileName" : "blackbox.html", 79 | "locale" : "RU", 80 | "format" : "HTML", 81 | "template" : "Отчет по результатам сканирования", 82 | "filters": { 83 | "confirmationStatuses": ["UNDEFINED", "NONE", "APPROVED", "AUTOAPPROVED"], 84 | "sourceType": "BLACKBOX" 85 | } 86 | }], 87 | "data": [{ 88 | "fileName" : "ai_report.json", 89 | "locale" : "EN", 90 | "format" : "JSON" 91 | }] 92 | } 93 | POLICY_JSON: | # Security policy used in Application Inspector 94 | [ 95 | { 96 | "CountToActualize": 1, 97 | "Scopes": [ 98 | { 99 | "Rules": [ 100 | { 101 | "Field": "Level", 102 | "Value": "High", 103 | "IsRegex": false 104 | }, 105 | { 106 | "Field": "Exploit", 107 | "Value": ".", 108 | "IsRegex": true 109 | }, 110 | { 111 | "Field": "IsSuspected", 112 | "Value": "false", 113 | "IsRegex": false 114 | }, 115 | { 116 | "Field": "ApprovalState", 117 | "Value": "[^2]", 118 | "IsRegex": true 119 | } 120 | ] 121 | } 122 | ] 123 | } 124 | ] 125 | CODEQUALITY_SETTINGS: | # GitLab Code Quality settings, also used to block merge requests with bot 126 | threats mapping: 127 | info: Potential 128 | minor: Low 129 | major: Medium 130 | critical: High 131 | blocker: [] 132 | security gates: 133 | info: 0 134 | minor: 0 135 | major: 5 136 | critical: 1 137 | blocker: 0 138 | 139 | # Anchors for selecting the launch mode 140 | .information-mode: &information-mode 141 | <<: *common-variables 142 | stage: AI Downstream scan 143 | trigger: 144 | include: 145 | - project: 'ptai-demo/pt-ai-demo-templates' 146 | file: '/AI-basic-template/AI-Run-in-parallel/AI-Information-Mode.yml' 147 | 148 | .lock-mode: &lock-mode 149 | <<: *common-variables 150 | stage: AI Downstream scan 151 | trigger: 152 | include: 153 | - project: 'ptai-demo/pt-ai-demo-templates' 154 | file: '/AI-basic-template/AI-Run-in-parallel/AI-Lock-Mode.yml' 155 | 156 | .strictest-mode: &strictest-mode 157 | <<: *common-variables 158 | stage: AI Downstream scan 159 | trigger: 160 | include: 161 | - project: 'ptai-demo/pt-ai-demo-templates' 162 | file: '/AI-basic-template/AI-Run-in-parallel/AI-Strictest-Mode.yml' 163 | 164 | # --- Start pipelines ------------------------------------------- 165 | 166 | # Starting a child pipeline depending on the branch 167 | AI Information mode scan: 168 | <<: *information-mode 169 | except: 170 | - release 171 | - develop 172 | - master 173 | - main 174 | only: 175 | - branches 176 | 177 | AI Lock mode scan: 178 | <<: *lock-mode 179 | only: 180 | - master 181 | - main 182 | 183 | AI Strictest mode scan: 184 | <<: *strictest-mode 185 | only: 186 | - develop 187 | -------------------------------------------------------------------------------- /GitLab_templates/AI.Cli.Plugin/AI-Templates/AI-basic-template/AI-Run-in-parallel/AI-Information-Mode.yml: -------------------------------------------------------------------------------- 1 | # This template is used for components scanning in "Information Mode" 2 | 3 | stages: 4 | - download dependencies 5 | - AI Scan 6 | - Update report status 7 | - Security Gates 8 | - Build verification 9 | - Notifications 10 | 11 | 12 | # --- Pipeline Aliases --------------------------------------- 13 | 14 | # Common docker image and GitLab Runners tags 15 | .common-build: &common-build 16 | image: ${DOCKER_IMAGE} 17 | tags: 18 | - docker 19 | - linux 20 | - build-low # change to your tag 21 | 22 | # Common structure to keep artifacts in GitLab CI Jobs 23 | .common-artifacts: &common-artifacts 24 | artifacts: 25 | expire_in: 31 day 26 | paths: 27 | - .ai_report/ 28 | 29 | # Anchor for run condition, designed to simplify the pipeline 30 | .on-success: &on-success 31 | when: on_success 32 | 33 | # Anchor for run condition, designed to simplify the pipeline 34 | .on-failure: &on-failure 35 | when: on_failure 36 | 37 | 38 | # --- AI Aliases ---------------------------------------------------- 39 | # Common steps to start procedure for processing scan results 40 | .codequality: &codequality > 41 | codequality 42 | -i .ai_report 43 | -o codequality.json 44 | -t ${AI_GITLAB_BOT_TOKEN} 45 | -s ./codequality.settings.yml | tee temp_result 46 | 47 | 48 | # --- Additional scripts aliases ------------------------------------ 49 | 50 | # Push "Success" status with report hyperlink to parent pipeline 51 | .push-AI-report-status-success-to-upstream: &push-AI-report-status-success-to-upstream > 52 | curl --location --request POST "$CI_API_V4_URL/projects/$CI_PROJECT_ID/statuses/$CI_COMMIT_SHA?state=success&name=AI%20Downstream%20Scan%20Report&description=Click%20to%20watch%20scanning%20report&target_url=$CI_JOB_URL/artifacts/browse/.ai_report/&pipeline_id=$PARENT_CI_PIPELINE_ID" --header "PRIVATE-TOKEN: ${AI_GITLAB_BOT_TOKEN}" 53 | 54 | # Push "Security Gates: Passed / Failed" status to parent pipeline 55 | .push-Security-Gates-status-to-upstream: &push-Security-Gates-status-to-upstream > 56 | if cat temp_result | grep -q "Check Security Gates: PASSED"; then 57 | curl --location --request POST "$CI_API_V4_URL/projects/$CI_PROJECT_ID/statuses/$CI_COMMIT_SHA?state=success&name=Code%20Quality:%20PASSED&description=Check%20Security%20Gates:%20PASSED&pipeline_id=$PARENT_CI_PIPELINE_ID" 58 | --header "PRIVATE-TOKEN: ${AI_GITLAB_BOT_TOKEN}"; 59 | elif cat temp_result | grep -q "Check Security Gates: FAILED"; then 60 | curl --location --request POST "$CI_API_V4_URL/projects/$CI_PROJECT_ID/statuses/$CI_COMMIT_SHA?state=success&name=Code%20Quality:%20FAILED&description=Check%20Security%20Gates:%20FAILED&pipeline_id=$PARENT_CI_PIPELINE_ID" 61 | --header "PRIVATE-TOKEN: ${AI_GITLAB_BOT_TOKEN}"; fi && rm -rf temp_result 62 | 63 | # --- AI Scan Stages ------------------------------------------------ 64 | # download project dependencies 65 | include: 66 | - project: 'ptai-demo/pt-ai-demo-templates' 67 | file: '/AI-basic-template/download-dependencies.yml' 68 | 69 | # Code scan with report generation 70 | AI-scanning: 71 | <<: *common-build 72 | <<: *common-artifacts 73 | stage: AI Scan 74 | script: 75 | # creating aiproj file from variable or with default values 76 | - if [ ! "${USE_SERVER_SETTINGS}" == "true" ]; then if [ ! x"${PROJECT_SETTINGS}" = x ]; then echo ${PROJECT_SETTINGS} > "${PROJECT_NAME}.aiproj"; else set-settings --projectname "${PROJECT_NAME}" --language ${PROJECT_LANGUAGE}; fi; fi; 77 | # adding reports and policy parameters to the plugin 78 | - if [ ! x"${REPORT_JSON}" = x ]; then echo ${REPORT_JSON} > ai-reports.json && REPORT="--report-json=ai-reports.json"; fi; 79 | - if [ ! x"${POLICY_JSON}" = x ]; then echo ${POLICY_JSON} > ai-policy.json && POLICY="--policy-json=ai-policy.json"; fi; 80 | # check if the server is available 81 | - ptai-plugin check-server 82 | # run the scan in ui-ast or in json-ast mode 83 | - if [ "${USE_SERVER_SETTINGS}" == "true" ]; then ptai-plugin ui-ast --project="${PROJECT_NAME}" --input=./ --output=.ai_report ${REPORT} ${CUSTOM_PLUGIN_PARAMS}; else ptai-plugin json-ast --settings-json="${PROJECT_NAME}.aiproj" --input=./ --output=.ai_report ${REPORT} ${POLICY} ${CUSTOM_PLUGIN_PARAMS}; fi; 84 | - *push-AI-report-status-success-to-upstream 85 | 86 | # --- Security Gates Stage ------------------------------------------ 87 | 88 | # This job processes the results of the AI-scanning and makes a verdict on them. See the documentation for more info 89 | Check Security Gate: 90 | <<: *common-build 91 | stage: Security Gates 92 | before_script: 93 | - echo "${CODEQUALITY_SETTINGS}" > ./codequality.settings.yml 94 | script: 95 | - *codequality 96 | - *push-Security-Gates-status-to-upstream 97 | rules: 98 | - if: $CODEQUALITY_SETTINGS != "" 99 | - when: on_success 100 | needs: 101 | - job: AI-scanning 102 | artifacts: true 103 | artifacts: 104 | expire_in: 31 day 105 | paths: 106 | - codequality.json 107 | reports: 108 | dotenv: .env 109 | codequality: codequality.json 110 | 111 | # Fake job for demonstration 112 | #Send failed status to monitoring: 113 | # <<: *common-build 114 | # <<: *on-failure 115 | # stage: Security Gates 116 | # script: 117 | # - exit 0 118 | 119 | 120 | # --- Notification Stage -------------------------------------------- 121 | 122 | # Fake job for demonstration 123 | #Notify by email and chats (Success): 124 | # <<: *common-build 125 | # <<: *on-success 126 | # stage: Notifications 127 | # script: 128 | # - exit 0 129 | 130 | # Fake job for demonstration 131 | #Notify by email and chats (Failure): 132 | # <<: *common-build 133 | # <<: *on-failure 134 | # stage: Notifications 135 | # script: 136 | # - exit 0 137 | -------------------------------------------------------------------------------- /GitLab_templates/AI.Cli.Plugin/AI-Templates/AI-basic-template/AI-Run-in-parallel/AI-Lock-Mode.yml: -------------------------------------------------------------------------------- 1 | # This template is used for components scanning in "Lock Mode" 2 | 3 | stages: 4 | - download dependencies 5 | - AI Scan 6 | - Update report status 7 | - Security Gates 8 | - Build verification 9 | - Notifications 10 | 11 | 12 | # --- Pipeline Aliases --------------------------------------- 13 | 14 | # Common docker image and GitLab Runners tags 15 | .common-build: &common-build 16 | image: ${DOCKER_IMAGE} 17 | tags: 18 | - docker 19 | - linux 20 | - build-low # change to your tag 21 | 22 | # Common structure to keep artifacts in GitLab CI Jobs 23 | .common-artifacts: &common-artifacts 24 | artifacts: 25 | expire_in: 31 day 26 | paths: 27 | - .ai_report/ 28 | 29 | # Anchor for run condition, designed to simplify the pipeline 30 | .on-success: &on-success 31 | when: on_success 32 | 33 | # Anchor for run condition, designed to simplify the pipeline 34 | .on-failure: &on-failure 35 | when: on_failure 36 | 37 | 38 | # --- AI Aliases ---------------------------------------------------- 39 | # Common steps to start procedure for processing scan results 40 | .codequality: &codequality > 41 | codequality 42 | -i .ai_report 43 | -o codequality.json 44 | -t ${AI_GITLAB_BOT_TOKEN} 45 | -b True 46 | -s ./codequality.settings.yml | tee temp_result 47 | 48 | 49 | # --- Additional scripts aliases ------------------------------------ 50 | 51 | # Push "Running" status to parent pipeline (for easier perception in MergeRequest) 52 | .push-AI-report-status-run-to-upstream: &push-AI-report-status-run-to-upstream > 53 | curl --location --request POST "$CI_API_V4_URL/projects/$CI_PROJECT_ID/statuses/$CI_COMMIT_SHA?state=running&name=AI%20Downstream%20Scan%20Report&description=Waiting%20for%20scan%20report%20from%20child%20pipeline&pipeline_id=$PARENT_CI_PIPELINE_ID" 54 | --header "PRIVATE-TOKEN: ${AI_GITLAB_BOT_TOKEN}" 55 | 56 | # Push "Success" status with report hyperlink to parent pipeline 57 | .push-AI-report-status-success-to-upstream: &push-AI-report-status-success-to-upstream > 58 | curl --location --request POST "$CI_API_V4_URL/projects/$CI_PROJECT_ID/statuses/$CI_COMMIT_SHA?state=success&name=AI%20Downstream%20Scan%20Report&description=Click%20to%20watch%20scanning%20report&target_url=$CI_JOB_URL/artifacts/browse/.ai_report/&pipeline_id=$PARENT_CI_PIPELINE_ID" --header "PRIVATE-TOKEN: ${AI_GITLAB_BOT_TOKEN}" 59 | 60 | # Push "Failed" status with report hyperlink to parent pipeline 61 | .push-AI-report-status-failed-to-upstream: &push-AI-report-status-failed-to-upstream > 62 | curl --location --request POST "$CI_API_V4_URL/projects/$CI_PROJECT_ID/statuses/$CI_COMMIT_SHA?state=failed&name=AI%20Downstream%20Scan%20Report&description=Code%20scan%20failed&pipeline_id=$PARENT_CI_PIPELINE_ID" --header "PRIVATE-TOKEN: ${AI_GITLAB_BOT_TOKEN}" 63 | 64 | # Push "Security Gates: Passed / Failed" status to parent pipeline 65 | .push-Security-Gates-status-to-upstream: &push-Security-Gates-status-to-upstream > 66 | if cat temp_result | grep -q "Check Security Gates: PASSED"; then 67 | curl --location --request POST "$CI_API_V4_URL/projects/$CI_PROJECT_ID/statuses/$CI_COMMIT_SHA?state=success&name=Code%20Quality:%20PASSED&description=Check%20Security%20Gates:%20PASSED&pipeline_id=$PARENT_CI_PIPELINE_ID" 68 | --header "PRIVATE-TOKEN: ${AI_GITLAB_BOT_TOKEN}"; 69 | elif cat temp_result | grep -q "Check Security Gates: FAILED"; then 70 | curl --location --request POST "$CI_API_V4_URL/projects/$CI_PROJECT_ID/statuses/$CI_COMMIT_SHA?state=success&name=Code%20Quality:%20FAILED&description=Check%20Security%20Gates:%20FAILED&pipeline_id=$PARENT_CI_PIPELINE_ID" 71 | --header "PRIVATE-TOKEN: ${AI_GITLAB_BOT_TOKEN}"; fi && rm -rf temp_result 72 | 73 | # --- AI Scan Stages ------------------------------------------------ 74 | # download project dependencies 75 | include: 76 | - project: 'ptai-demo/pt-ai-demo-templates' 77 | file: '/AI-basic-template/download-dependencies.yml' 78 | 79 | # Code scan with report generation 80 | AI-scanning: 81 | <<: *common-build 82 | <<: *common-artifacts 83 | stage: AI Scan 84 | before_script: 85 | - *push-AI-report-status-run-to-upstream 86 | script: 87 | # creating aiproj file from variable or with default values 88 | - if [ ! "${USE_SERVER_SETTINGS}" == "true" ]; then if [ ! x"${PROJECT_SETTINGS}" = x ]; then echo ${PROJECT_SETTINGS} > "${PROJECT_NAME}.aiproj"; else set-settings --projectname "${PROJECT_NAME}" --language ${PROJECT_LANGUAGE}; fi; fi; 89 | # adding reports and policy parameters to the plugin 90 | - if [ ! x"${REPORT_JSON}" = x ]; then echo ${REPORT_JSON} > ai-reports.json && REPORT="--report-json=ai-reports.json"; fi; 91 | - if [ ! x"${POLICY_JSON}" = x ]; then echo ${POLICY_JSON} > ai-policy.json && POLICY="--policy-json=ai-policy.json"; fi; 92 | # check if the server is available 93 | - ptai-plugin check-server 94 | # run the scan in ui-ast or in json-ast mode 95 | - if [ "${USE_SERVER_SETTINGS}" == "true" ]; then ptai-plugin ui-ast --project="${PROJECT_NAME}" --input=./ --output=.ai_report ${REPORT} ${CUSTOM_PLUGIN_PARAMS}; else ptai-plugin json-ast --settings-json="${PROJECT_NAME}.aiproj" --input=./ --output=.ai_report ${REPORT} ${POLICY} ${CUSTOM_PLUGIN_PARAMS}; fi; 96 | - *push-AI-report-status-success-to-upstream 97 | 98 | # Push failed status if scanning failed: 99 | Send failed report status: 100 | <<: *common-build 101 | <<: *on-failure 102 | stage: Update report status 103 | script: 104 | - *push-AI-report-status-failed-to-upstream 105 | 106 | # --- Security Gates Stage ------------------------------------------ 107 | 108 | # This job processes the results of the AI-scanning and makes a verdict on them. See the documentation for more info 109 | Check Security Gate: 110 | <<: *common-build 111 | stage: Security Gates 112 | before_script: 113 | - echo "${CODEQUALITY_SETTINGS}" > ./codequality.settings.yml 114 | script: 115 | - *codequality 116 | - *push-Security-Gates-status-to-upstream 117 | rules: 118 | - if: $CODEQUALITY_SETTINGS != "" 119 | - when: on_success 120 | needs: 121 | - job: AI-scanning 122 | artifacts: true 123 | artifacts: 124 | expire_in: 31 day 125 | paths: 126 | - codequality.json 127 | reports: 128 | dotenv: .env 129 | codequality: codequality.json 130 | 131 | # Fake job for demonstration 132 | #Send failed status to monitoring: 133 | # <<: *common-build 134 | # <<: *on-failure 135 | # stage: Security Gates 136 | # script: 137 | # - exit 0 138 | 139 | 140 | # --- Notification Stage -------------------------------------------- 141 | 142 | # Fake job for demonstration 143 | #Notify by email and chats (Success): 144 | # <<: *common-build 145 | # <<: *on-success 146 | # stage: Notifications 147 | # script: 148 | # - exit 0 149 | 150 | # Fake job for demonstration 151 | #Notify by email and chats (Failure): 152 | # <<: *common-build 153 | # <<: *on-failure 154 | # stage: Notifications 155 | # script: 156 | # - exit 0 157 | -------------------------------------------------------------------------------- /GitLab_templates/AI.Cli.Plugin/AI-Templates/AI-basic-template/AI-Run-in-parallel/AI-Strictest-Mode.yml: -------------------------------------------------------------------------------- 1 | # This template is used for components scanning in "Strictest Mode" 2 | 3 | stages: 4 | - download dependencies 5 | - AI Scan 6 | - Update report status 7 | - Security Gates 8 | - Build verification 9 | - Notifications 10 | 11 | 12 | # --- Pipeline Aliases --------------------------------------- 13 | 14 | # Common docker image and GitLab Runners tags 15 | .common-build: &common-build 16 | image: ${DOCKER_IMAGE} 17 | tags: 18 | - docker 19 | - linux 20 | - build-low # change to your tag 21 | 22 | # Common structure to keep artifacts in GitLab CI Jobs 23 | .common-artifacts: &common-artifacts 24 | artifacts: 25 | expire_in: 31 day 26 | paths: 27 | - .ai_report/ 28 | 29 | # Anchor for run condition, designed to simplify the pipeline 30 | .on-success: &on-success 31 | when: on_success 32 | 33 | # Anchor for run condition, designed to simplify the pipeline 34 | .on-failure: &on-failure 35 | when: on_failure 36 | 37 | 38 | # --- AI Aliases ---------------------------------------------------- 39 | # Common steps to start procedure for processing scan results 40 | .codequality: &codequality > 41 | codequality 42 | -i .ai_report 43 | -o codequality.json 44 | -t ${AI_GITLAB_BOT_TOKEN} 45 | -b True 46 | -s ./codequality.settings.yml | tee temp_result 47 | 48 | 49 | # --- Additional scripts aliases ------------------------------------ 50 | 51 | # Push "Running" status to parent pipeline (for easier perception in MergeRequest) 52 | .push-AI-report-status-run-to-upstream: &push-AI-report-status-run-to-upstream > 53 | curl --location --request POST "$CI_API_V4_URL/projects/$CI_PROJECT_ID/statuses/$CI_COMMIT_SHA?state=running&name=AI%20Downstream%20Scan%20Report&description=Waiting%20for%20scan%20report%20from%20child%20pipeline&pipeline_id=$PARENT_CI_PIPELINE_ID" 54 | --header "PRIVATE-TOKEN: ${AI_GITLAB_BOT_TOKEN}" 55 | 56 | # Push "Success" status with report hyperlink to parent pipeline 57 | .push-AI-report-status-success-to-upstream: &push-AI-report-status-success-to-upstream > 58 | curl --location --request POST "$CI_API_V4_URL/projects/$CI_PROJECT_ID/statuses/$CI_COMMIT_SHA?state=success&name=AI%20Downstream%20Scan%20Report&description=Click%20to%20watch%20scanning%20report&target_url=$CI_JOB_URL/artifacts/browse/.ai_report/&pipeline_id=$PARENT_CI_PIPELINE_ID" --header "PRIVATE-TOKEN: ${AI_GITLAB_BOT_TOKEN}" 59 | 60 | # Push "Failed" status with report hyperlink to parent pipeline 61 | .push-AI-report-status-failed-to-upstream: &push-AI-report-status-failed-to-upstream > 62 | curl --location --request POST "$CI_API_V4_URL/projects/$CI_PROJECT_ID/statuses/$CI_COMMIT_SHA?state=failed&name=AI%20Downstream%20Scan%20Report&description=Code%20scan%20failed&pipeline_id=$PARENT_CI_PIPELINE_ID" --header "PRIVATE-TOKEN: ${AI_GITLAB_BOT_TOKEN}" 63 | 64 | # Push "Security Gates: Passed / Failed" status to parent pipeline 65 | .push-Security-Gates-status-to-upstream: &push-Security-Gates-status-to-upstream > 66 | if cat temp_result | grep -q "Check Security Gates: PASSED"; then 67 | curl --location --request POST "$CI_API_V4_URL/projects/$CI_PROJECT_ID/statuses/$CI_COMMIT_SHA?state=success&name=Code%20Quality:%20PASSED&description=Check%20Security%20Gates:%20PASSED&pipeline_id=$PARENT_CI_PIPELINE_ID" 68 | --header "PRIVATE-TOKEN: ${AI_GITLAB_BOT_TOKEN}"; 69 | elif cat temp_result | grep -q "Check Security Gates: FAILED"; then 70 | curl --location --request POST "$CI_API_V4_URL/projects/$CI_PROJECT_ID/statuses/$CI_COMMIT_SHA?state=failed&name=Code%20Quality:%20FAILED&description=Check%20Security%20Gates:%20FAILED&pipeline_id=$PARENT_CI_PIPELINE_ID" 71 | --header "PRIVATE-TOKEN: ${AI_GITLAB_BOT_TOKEN}"; fi && rm -rf temp_result 72 | 73 | # Write the scan status to the variable 74 | .get-Security-Gates-status: &get-Security-Gates-status > 75 | if cat temp_result | grep -q "Check Security Gates: PASSED"; then echo 'SECURITY_GATES_STATUS="PASSED"' > .env; 76 | elif cat temp_result | grep -q "Check Security Gates: FAILED"; then echo 'SECURITY_GATES_STATUS="FAILED"' > .env; fi 77 | 78 | # Starting the manual job in the parent pipeline if the Security Gates status is Passed 79 | # Also repeat the launch requests until the manual job is available in the parent pipeline (for builds with long build times) 80 | .run-manual-job-from-upstream: &run-manual-job-from-upstream > 81 | PARENT_JOB_ID=null && while [[ "$PARENT_JOB_ID" == null ]]; 82 | do PARENT_JOB_ID=$(curl --location --request GET "$CI_API_V4_URL/projects/$CI_PROJECT_ID/pipelines/$PARENT_CI_PIPELINE_ID/jobs?scope[]=manual" 83 | --header "PRIVATE-TOKEN: ${AI_GITLAB_BOT_TOKEN}" > .json && cat .json | jq ".[0].id" && rm -rf .json); 84 | echo 'Sleep 1m for waiting upstream pipeline, then retry...'; sleep 1m; done; 85 | curl --location -g --request POST "$CI_API_V4_URL/projects/$CI_PROJECT_ID/jobs/$PARENT_JOB_ID/play" 86 | --header "PRIVATE-TOKEN: ${AI_GITLAB_BOT_TOKEN}" 87 | 88 | 89 | # --- AI Scan Stage ------------------------------------------------ 90 | # download project dependencies 91 | include: 92 | - project: 'ptai-demo/pt-ai-demo-templates' 93 | file: '/AI-basic-template/download-dependencies.yml' 94 | 95 | # Code scan with report generation 96 | AI-scanning: 97 | <<: *common-build 98 | <<: *common-artifacts 99 | stage: AI Scan 100 | before_script: 101 | - *push-AI-report-status-run-to-upstream 102 | script: 103 | # creating aiproj file from variable or with default values 104 | - if [ ! "${USE_SERVER_SETTINGS}" == "true" ]; then if [ ! x"${PROJECT_SETTINGS}" = x ]; then echo ${PROJECT_SETTINGS} > "${PROJECT_NAME}.aiproj"; else set-settings --projectname "${PROJECT_NAME}" --language ${PROJECT_LANGUAGE}; fi; fi; 105 | # adding reports and policy parameters to the plugin 106 | - if [ ! x"${REPORT_JSON}" = x ]; then echo ${REPORT_JSON} > ai-reports.json && REPORT="--report-json=ai-reports.json"; fi; 107 | - if [ ! x"${POLICY_JSON}" = x ]; then echo ${POLICY_JSON} > ai-policy.json && POLICY="--policy-json=ai-policy.json"; fi; 108 | # check if the server is available 109 | - ptai-plugin check-server 110 | # run the scan in ui-ast or in json-ast mode 111 | - if [ "${USE_SERVER_SETTINGS}" == "true" ]; then ptai-plugin ui-ast --project="${PROJECT_NAME}" --input=./ --output=.ai_report ${REPORT} ${CUSTOM_PLUGIN_PARAMS}; else ptai-plugin json-ast --settings-json="${PROJECT_NAME}.aiproj" --input=./ --output=.ai_report ${REPORT} ${POLICY} ${CUSTOM_PLUGIN_PARAMS}; fi; 112 | - *push-AI-report-status-success-to-upstream 113 | 114 | # Push failed status if scanning failed: 115 | Send failed report status: 116 | <<: *common-build 117 | <<: *on-failure 118 | stage: Update report status 119 | script: 120 | - *push-AI-report-status-failed-to-upstream 121 | 122 | # --- Security Gates Stage ------------------------------------------ 123 | 124 | # This job processes the results of the AI-scanning and makes a verdict on them. See the documentation for more info 125 | Check Security Gate: 126 | <<: *common-build 127 | stage: Security Gates 128 | before_script: 129 | - echo "${CODEQUALITY_SETTINGS}" > ./codequality.settings.yml 130 | script: 131 | - *codequality 132 | - *get-Security-Gates-status 133 | - *push-Security-Gates-status-to-upstream 134 | rules: 135 | - if: $CODEQUALITY_SETTINGS != "" 136 | - when: on_success 137 | needs: 138 | - job: AI-scanning 139 | artifacts: true 140 | artifacts: 141 | expire_in: 31 day 142 | paths: 143 | - codequality.json 144 | reports: 145 | dotenv: .env 146 | codequality: codequality.json 147 | 148 | # Fake job for demonstration 149 | #Send failed status to monitoring: 150 | # <<: *common-build 151 | # <<: *on-failure 152 | # stage: Security Gates 153 | # script: 154 | # - exit 0 155 | 156 | 157 | # --- Approve Stage ------------------------------------------------- 158 | 159 | # Completes successfully if the build is passed, if not, it fails the downstream pipeline 160 | Approve build: 161 | <<: *common-build 162 | stage: Build verification 163 | script: 164 | - if [[ $SECURITY_GATES_STATUS == \"PASSED\" ]]; then exit 0; else exit 1; fi 165 | dependencies: 166 | - Check Security Gate 167 | 168 | # Starts a manual job in the parent pipeline 169 | Run manual job: 170 | <<: *common-build 171 | stage: Build verification 172 | script: 173 | - if [[ "$SECURITY_GATES_STATUS" == \"PASSED\" ]] ; then echo $SECURITY_GATES_STATUS; else echo $SECURITY_GATES_STATUS; exit 1; fi 174 | - *run-manual-job-from-upstream 175 | dependencies: 176 | - Check Security Gate 177 | 178 | 179 | # --- Notification Stage -------------------------------------------- 180 | 181 | # Fake job for demonstration 182 | #Notify by email and chats (Success): 183 | # <<: *common-build 184 | # <<: *on-success 185 | # stage: Notifications 186 | # script: 187 | # - exit 0 188 | 189 | # Fake job for demonstration 190 | #Notify by email and chats (Failure): 191 | # <<: *common-build 192 | # <<: *on-failure 193 | # stage: Notifications 194 | # script: 195 | # - exit 0 196 | -------------------------------------------------------------------------------- /GitLab_templates/AI.Cli.Plugin/AI-Templates/AI-basic-template/AI-Run-in-sequence.yml: -------------------------------------------------------------------------------- 1 | # This template is used for sequence scanning with PT Application Inspector 2 | 3 | # Anchor for static security analysis 4 | .ai-static-scan: 5 | image: ${REGISTRY_ADDRESS}/tools/ai-plugin:latest # url of docker registry with AI plugin container 6 | tags: 7 | - docker 8 | - linux 9 | - build-low # change to your tag 10 | variables: 11 | ST_PROJECT_NAME: ${AI_PROJECT_NAME} 12 | ST_PROJECT_LANGUAGE: ${AI_PROJECT_LANGUAGE} 13 | ST_USE_SERVER_SETTINGS: ${AI_USE_SERVER_SETTINGS} 14 | ST_PROJECT_SETTINGS: ${AI_PROJECT_SETTINGS} 15 | ST_CUSTOM_PLUGIN_PARAMS: ${AI_CUSTOM_PLUGIN_PARAMS} 16 | ST_REPORT_JSON: | # Reports to be generated after scanning is finished 17 | { 18 | "report" : [ 19 | { 20 | "fileName" : "ai_full_report.html", 21 | "locale" : "RU", 22 | "format" : "HTML", 23 | "template" : "Отчет по результатам сканирования" 24 | },{ 25 | "fileName" : "tier1.html", 26 | "locale" : "RU", 27 | "format" : "HTML", 28 | "template" : "Отчет по результатам сканирования", 29 | "filters": { 30 | "issueLevels": ["MEDIUM", "HIGH"], 31 | "scanMode": "FROMENTRYPOINT", 32 | "confirmationStatuses": ["UNDEFINED", "NONE", "APPROVED", "AUTOAPPROVED"] 33 | } 34 | },{ 35 | "fileName" : "tier2.html", 36 | "locale" : "RU", 37 | "format" : "HTML", 38 | "template" : "Отчет по результатам сканирования", 39 | "filters": { 40 | "issueLevels": ["MEDIUM", "HIGH"], 41 | "scanMode": "FROMPUBLICPROTECTED", 42 | "confirmationStatuses": ["UNDEFINED", "NONE", "APPROVED", "AUTOAPPROVED"] 43 | } 44 | },{ 45 | "fileName" : "tier3.html", 46 | "locale" : "RU", 47 | "format" : "HTML", 48 | "template" : "Отчет по результатам сканирования", 49 | "filters": { 50 | "issueLevels": ["LOW", "POTENTIAL"], 51 | "confirmationStatuses": ["UNDEFINED", "NONE", "APPROVED", "AUTOAPPROVED"], 52 | "sourceType": "STATIC" 53 | } 54 | },{ 55 | "fileName" : "new.html", 56 | "locale" : "RU", 57 | "format" : "HTML", 58 | "template" : "Отчет по результатам сканирования", 59 | "filters": { 60 | "actualStatus": "ISNEW", 61 | "confirmationStatuses": ["UNDEFINED", "NONE", "APPROVED", "AUTOAPPROVED"] 62 | } 63 | },{ 64 | "fileName" : "vulnerable components.html", 65 | "locale" : "RU", 66 | "format" : "HTML", 67 | "template" : "Отчет по результатам сканирования", 68 | "filters": { 69 | "issueLevels": ["MEDIUM", "HIGH"], 70 | "confirmationStatuses": ["UNDEFINED", "NONE", "APPROVED", "AUTOAPPROVED"], 71 | "scanMode": "FROMOTHER", 72 | "sourceType": "STATIC" 73 | } 74 | },{ 75 | "fileName" : "blackbox.html", 76 | "locale" : "RU", 77 | "format" : "HTML", 78 | "template" : "Отчет по результатам сканирования", 79 | "filters": { 80 | "confirmationStatuses": ["UNDEFINED", "NONE", "APPROVED", "AUTOAPPROVED"], 81 | "sourceType": "BLACKBOX" 82 | } 83 | }], 84 | "data": [{ 85 | "fileName" : "ai_report.json", 86 | "locale" : "EN", 87 | "format" : "JSON" 88 | }] 89 | } 90 | ST_POLICY_JSON: | # Security policy for AI 91 | { 92 | "CountToActualize": 1, 93 | "Scopes": [ 94 | { 95 | "Rules": [ 96 | { 97 | "Field": "VulnerabilityLevel", 98 | "Value": "High", 99 | "IsRegex": false 100 | }, 101 | { 102 | "Field": "IsSuspected", 103 | "Value": "false", 104 | "IsRegex": false 105 | }, 106 | { 107 | "Field": "ApprovalState", 108 | "Value": "[^2]", 109 | "IsRegex": true 110 | } 111 | ] 112 | } 113 | ] 114 | } 115 | ST_CODEQUALITY_SETTINGS: | # Security Gates settings for GitLab bot to block merge requests 116 | threats mapping: 117 | info: Potential 118 | minor: Low 119 | major: Medium 120 | critical: High 121 | blocker: [] 122 | security gates: 123 | info: 0 124 | minor: 1 125 | major: 4 126 | critical: 0 127 | blocker: 0 128 | script: 129 | # creating aiproj file from variable or with default values 130 | - if [ ! "${ST_USE_SERVER_SETTINGS}" == "true" ]; then if [ ! x"${ST_PROJECT_SETTINGS}" = x ]; then echo ${ST_PROJECT_SETTINGS} > "${ST_PROJECT_NAME}.aiproj"; else set-settings --projectname "${ST_PROJECT_NAME}" --language ${ST_PROJECT_LANGUAGE}; fi; fi; 131 | # adding reports and policy parameters to the plugin 132 | - if [ ! x"${ST_REPORT_JSON}" = x ]; then echo ${ST_REPORT_JSON} > ai-reports.json && REPORT="--report-json=ai-reports.json"; fi; 133 | - if [ ! x"${ST_POLICY_JSON}" = x ]; then echo ${ST_POLICY_JSON} > ai-policy.json && POLICY="--policy-json=ai-policy.json"; fi; 134 | # check if the server is available 135 | - ptai-plugin check-server 136 | # run the scan in ui-ast or in json-ast mode 137 | - if [ "${ST_USE_SERVER_SETTINGS}" == "true" ]; then ptai-plugin ui-ast --project="${ST_PROJECT_NAME}" --input=./ --output=.ai_report ${REPORT} ${ST_CUSTOM_PLUGIN_PARAMS}; else ptai-plugin json-ast --settings-json="${ST_PROJECT_NAME}.aiproj" --input=./ --output=.ai_report ${REPORT} ${POLICY} ${ST_CUSTOM_PLUGIN_PARAMS}; fi; 138 | # run Security Gates checks to block merge requests 139 | - if [ ! x"${ST_CODEQUALITY_SETTINGS}" = x ]; then codequality -i .ai_report -o codequality.json -t ${AI_GITLAB_BOT_TOKEN} -b True; fi; 140 | artifacts: 141 | expire_in: 31 day 142 | paths: 143 | - .ai_report/ 144 | allow_failure: false 145 | 146 | # Anchor for blackbox scan 147 | .ai-blackbox-scan: 148 | image: ${REGISTRY_ADDRESS}/tools/ai-plugin:latest # url of docker registry with AI plugin container 149 | tags: 150 | - docker 151 | - linux 152 | - build-low # change to your tag 153 | variables: 154 | BB_PROJECT_NAME: ${AI_BB_PROJECT_NAME} 155 | BB_PROJECT_SETTINGS: ${AI_BB_PROJECT_SETTINGS} 156 | BB_CUSTOM_PLUGIN_PARAMS: ${AI_BB_CUSTOM_PLUGIN_PARAMS} 157 | BB_REPORT_JSON: | # Reports to be generated after scanning is finished 158 | { 159 | "report" : [ 160 | { 161 | "fileName" : "ai_full_report.html", 162 | "locale" : "RU", 163 | "format" : "HTML", 164 | "template" : "Отчет по результатам сканирования" 165 | } 166 | ] 167 | } 168 | BB_POLICY_JSON: | # Security policy for AI 169 | [ 170 | { 171 | "CountToActualize": 1, 172 | "Scopes": [ 173 | { 174 | "Rules": [ 175 | { 176 | "Field": "VulnerabilityLevel", 177 | "Value": "Medium", 178 | "IsRegex": false 179 | }, 180 | { 181 | "Field": "IsSuspected", 182 | "Value": "false", 183 | "IsRegex": false 184 | }, 185 | { 186 | "Field": "ApprovalState", 187 | "Value": "[^2]", 188 | "IsRegex": true 189 | } 190 | ] 191 | } 192 | ] 193 | } 194 | ] 195 | script: 196 | # converting settings to JSON files for plugin 197 | - if [ ! x"${BB_PROJECT_SETTINGS}" = x ]; then echo ${BB_PROJECT_SETTINGS} > ai-settings.aiproj; fi; 198 | - if [ ! x"${BB_REPORT_JSON}" = x ]; then echo ${BB_REPORT_JSON} > ai-reports.json && REPORT="--report-json=ai-reports.json"; fi; 199 | - if [ ! x"${BB_POLICY_JSON}" = x ]; then echo ${BB_POLICY_JSON} > ai-policy.json && POLICY="--policy-json=ai-policy.json"; fi; 200 | # workaround to avoid sources uploading 201 | - mkdir empty && touch empty/1.empty 202 | # check if the server is available 203 | - ptai-plugin check-server 204 | # run the scan in ui-ast or in json-ast mode 205 | - if [ ! x"${BB_PROJECT_NAME}" = x ]; then ptai-plugin ui-ast --project="${BB_PROJECT_NAME}" --input=./empty --output=.ai_report ${REPORT} ${BB_CUSTOM_PLUGIN_PARAMS}; else ptai-plugin json-ast --settings-json=ai-settings.aiproj --input=./empty --output=.ai_report ${REPORT} ${POLICY} ${BB_CUSTOM_PLUGIN_PARAMS}; fi; 206 | artifacts: 207 | expire_in: 31 day 208 | paths: 209 | - .ai_report/ 210 | allow_failure: true 211 | -------------------------------------------------------------------------------- /GitLab_templates/AI.Cli.Plugin/AI-Templates/AI-basic-template/download-dependencies.yml: -------------------------------------------------------------------------------- 1 | # example: download dependencies with package manager (can be used with Maven) 2 | Maven dependencies: 3 | stage: download dependencies 4 | image: maven:3-jdk-8 5 | tags: 6 | - docker 7 | - linux 8 | - build-low # change to your tag 9 | script: 10 | - mvn dependency:copy-dependencies -DoutputDirectory="libs" 11 | artifacts: 12 | expire_in: 1 day 13 | paths: 14 | - libs/ 15 | rules: 16 | # only when you use this variable 17 | - if: '$DEPS_MANAGER == "Maven"' 18 | when: always 19 | - when: never 20 | 21 | # example: copy dependencies from build job (can be used with gradle in Spring applications) 22 | Gradle Spring dependencies: 23 | stage: download dependencies 24 | image: alpine 25 | tags: 26 | - docker 27 | - linux 28 | - build-low # change to your tag 29 | needs: 30 | - pipeline: $PARENT_CI_PIPELINE_ID 31 | job: build and test # change to the name of your build job 32 | script: 33 | - mkdir libs && mv target/*/WEB-INF/lib/* libs # copy artifacts from build job 34 | artifacts: 35 | expire_in: 1 day 36 | paths: 37 | - libs/ 38 | rules: 39 | # only when you use this variable 40 | - if: '$DEPS_MANAGER == "Gradle_spring"' 41 | when: always 42 | - when: never -------------------------------------------------------------------------------- /GitLab_templates/AI.Cli.Plugin/README.md: -------------------------------------------------------------------------------- 1 | # Использование AI.Cli.Plugin для анализа кода в сборочном процессе GitLab 2 | 3 | Здесь описан пример интеграции сканирования кода с PT Application Inspector и плагином AI.Cli.Plugin в сборочный процесс GitLab посредством подключения шаблонов. Интеграция состоит из нескольких этапов: 4 | 1. Сборка docker-образа плагина 5 | 2. Настройка шаблонов сканирования 6 | 3. Подключение шаблонов сканирования в pipeline ваших проектов 7 | 8 | ## Сборка docker-образа плагина 9 | Для сборки вам потребуется: 10 | 1. Создать проект в GitLab с файлами из \AI-Plugin-dockerbuild 11 | 2. Задать переменные проекта 12 | - DOCKER_USERNAME – логин для docker registry 13 | - DOCKER_PASSWORD – пароль для docker registry 14 | - REGISTRY_ADDRESS – адрес docker registry, например registry.ptsecurity.com 15 | - AI_URN – адрес сервера PT AI, например ai.ptsecurity.com 16 | - PLUGIN_TOKEN – токен доступа для плагина CI/CD, сгенерированный на сервере PT AI 17 | 3. Задать теги используемых GitLab Runners в файле .gitlab-ci.yml 18 | 4. Запустить сборку 19 | 20 | ## Настройка шаблонов сканирования 21 | Все подробности о работе шаблонов и используемых в них параметрах см. в документе ptaiee_integrationscenario_ru.pdf. 22 | Для подключения шаблонов сканирования вам потребуется: 23 | 1. Создать проект в GitLab с файлами из \AI-Templates 24 | 2. Задать теги используемых GitLab Runners во всех файлах 25 | 3. В файлах AI-Run-in-parallel.yml, AI-Information-Mode.yml, AI-Lock-Mode.yml, AI-Strictest-Mode.yml заменить путь к вашему проекту, созданному в п.1, в блоке include: 26 | ```sh 27 | project: 'ptai-demo/pt-ai-demo-templates' 28 | ``` 29 | 30 | ## Подключение шаблонов сканирования в pipeline ваших проектов 31 | Рассмотрим этот этап на примере проекта https://github.com/ptssdl/App01.git 32 | Чтобы подключить анализ кода к проекту App01 вам потребуется: 33 | 1. Создать проект в GitLab, выполнив следующие команды 34 | ```sh 35 | git clone https://github.com/ptssdl/App01.git 36 | cd App01 37 | git remote set-url origin https:////ptai-demo-App01.git 38 | wget https://raw.githubusercontent.com/devopshq/dohq-ai-best-practices/master/GitLab_templates/AI.Cli.Plugin/demo-example.gitlab-ci.yml -O .gitlab-ci.yml 39 | git add . 40 | git commit -m "Initial commit" 41 | git push -u origin master 42 | ``` 43 | 2. Задать переменные проекта 44 | - REGISTRY_ADDRESS – адрес docker registry, например registry.ptsecurity.com 45 | - AI_GITLAB_BOT_TOKEN – токен доступа с правами на вызов API 46 | - FTP_ADDRESS – адрес FTP сервера на веб-сервере Tomcat 47 | - FTP_CREDENTIALS – учетные данные для подключения к FTP серверу 48 | -------------------------------------------------------------------------------- /GitLab_templates/AI.Cli.Plugin/demo-example.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | stages: 2 | - Build 3 | - AI Downstream scan 4 | - Deploy 5 | - AI Blackbox scan 6 | 7 | # --- Workflow ------------------------------------------------------ 8 | 9 | # The workflow field allows you to disable the duplicate pipeline launch if Merge Request exists. 10 | workflow: 11 | rules: 12 | - if: $CI_COMMIT_TAG 13 | when: never 14 | - if: $CI_MERGE_REQUEST_ID 15 | when: never 16 | - when: always 17 | 18 | # --- AI in downstream pipeline ---------------------------------------------- 19 | 20 | # AI Static Analysis in parallel pipeline (AI-Run-in-parallel.yml file) 21 | variables: 22 | AI_PROJECT_NAME: "Java App 01" # AI project name or GitLab variable like ${CI_PROJECT_PATH_SLUG} 23 | AI_PROJECT_LANGUAGE: "Java" # To use default AI project settings, please specify main programming language of your project, one of: "Kotlin", "Java", "Swift", "Csharp", "Go", "ObjectiveC", "Vb", "JavaScript", "Sql", "CPlusPlus", "Php", "Python" 24 | #AI_USE_SERVER_SETTINGS: "true" # Get AI project settings from server 25 | #AI_PROJECT_SETTINGS: | # Set AI project settings manually 26 | # { 27 | # "ProjectName": "Java App 01", 28 | # "ProgrammingLanguage": "Java", 29 | # "ScanAppType": "Java, PMtaint, Configuration", 30 | # "IsDownloadDependencies": false, 31 | # "IsUsePublicAnalysisMethod": false, 32 | # "IsUseEntryAnalysisPoint": true 33 | # } 34 | AI_DEPENDENCY_PROVIDER: "Maven" # Dependency download method (from AI-basic-template/download-dependencies.yml) 35 | AI_CUSTOM_PLUGIN_PARAMS: "--excludes=*.aiproj,ptai-cli-plugin.* --use-default-excludes" # add special parameters for the plugin 36 | 37 | 38 | # --- AI scan templates ------------------------------------------------ 39 | include: 40 | - project: 'ptai-demo/pt-ai-demo-templates' 41 | file: 42 | - '/AI-basic-template/AI-Run-in-parallel.yml' 43 | - '/AI-basic-template/AI-Run-in-sequence.yml' 44 | 45 | # --- Your stages -------------------------------------------------- 46 | build and test: 47 | stage: Build 48 | image: maven:3-jdk-8 49 | tags: 50 | - docker 51 | - linux 52 | - build-low 53 | script: 54 | - mvn install 55 | when: always 56 | artifacts: 57 | expire_in: 1 day 58 | paths: 59 | - target/app01.war 60 | 61 | Deploy: 62 | stage: Deploy 63 | image: curlimages/curl 64 | tags: 65 | - docker 66 | - linux 67 | - build-low 68 | script: 69 | - curl -T target/app01.war ftp://${FTP_ADDRESS}/ --user "${FTP_CREDENTIALS}" 70 | when: on_success 71 | 72 | # --- AI in parent pipeline -------------------------------------------------- 73 | 74 | # AI Blackbox Analysis in parent pipeline (AI-Run-in-sequence.yml file) 75 | AI Blackbox: 76 | stage: AI Blackbox scan 77 | extends: .ai-blackbox-scan 78 | variables: 79 | #AI_BB_PROJECT_NAME: "Java App 02" # Get AI project settings from server by project name 80 | AI_BB_PROJECT_SETTINGS: | # Set AI project settings manually 81 | { 82 | "ProjectName": "Java App BlackBox", 83 | "ProgrammingLanguage": "Java", 84 | "ScanAppType": "BlackBox", 85 | "Site": "http://${FTP_ADDRESS}/app01/", 86 | "Level": "Normal" 87 | } 88 | #AI_BB_CUSTOM_PLUGIN_PARAMS: "--fail-if-failed" # add special parameters for the plugin 89 | 90 | # Promote artifact to use in production environment 91 | # This step is used to demonstrate the work of AI-Strictest-Mode.yml template 92 | Promote: 93 | stage: Promote 94 | image: alpine 95 | script: 96 | - exit 0 97 | when: manual 98 | -------------------------------------------------------------------------------- /GitLab_templates/create_project.yml: -------------------------------------------------------------------------------- 1 | # (c) DevOpsHQ, 2020 2 | 3 | # This template is used to generate projects without running a scan later 4 | 5 | Create proiect on AIE: 6 | image: [your-repo]/aisa-linux:latest 7 | before_script: 8 | - aisa-set-settings 9 | --projectname $CI_PROJECT_NAME 10 | --language $PROJECT_MAIN_LANGUAGE 11 | script: 12 | - aisa --version 13 | - aisa 14 | --project-settings-file $CI_PROJECT_NAME.aiproj 15 | --scan-off 16 | -------------------------------------------------------------------------------- /GitLab_templates/customer-full/.AI/.gitlab-ci.ai.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devopshq/dohq-ai-best-practices/563f94b3b0371b25305ed03349c42564beaac92b/GitLab_templates/customer-full/.AI/.gitlab-ci.ai.png -------------------------------------------------------------------------------- /GitLab_templates/customer-full/.AI/.gitlab-ci.ai.yml: -------------------------------------------------------------------------------- 1 | # This template is used for components scanning 2 | 3 | stages: 4 | - AI scan start 5 | 6 | 7 | # --- Pipeline Aliases --------------------------------------- 8 | 9 | # Common variables to run AI Scan 10 | .common-variables: &common-variables 11 | variables: 12 | PARENT_CI_PIPELINE_ID: ${CI_PIPELINE_ID} 13 | PARENT_SCANNING_PROJECT: ${SCANNING_PROJECT} 14 | PARENT_SCANNING_PROJECT_LANGUAGE: ${SCANNING_PROJECT_LANGUAGE} 15 | PARENT_CODEQUALITY_SETTINGS: ${CODEQUALITY_SETTINGS} 16 | 17 | # Anchor for selecting the launch mode 18 | .information-mode: &information-mode 19 | <<: *common-variables 20 | stage: AI scan start 21 | trigger: 22 | include: 23 | - local: .AI/AI-Information-Mode.yml 24 | 25 | # Anchor for selecting the launch mode 26 | .lock-mode: &lock-mode 27 | <<: *common-variables 28 | stage: AI scan start 29 | trigger: 30 | include: 31 | - local: .AI/AI-Lock-Mode.yml 32 | 33 | # Anchor for selecting the launch mode 34 | .strictest-mode: &strictest-mode 35 | <<: *common-variables 36 | stage: AI scan start 37 | trigger: 38 | include: 39 | - local: .AI/AI-Strictest-Mode.yml 40 | 41 | 42 | # --- Start pipelines ------------------------------------------- 43 | 44 | # Starting a child pipeline in a specific branch 45 | AI Information mode scan: 46 | <<: *information-mode 47 | except: 48 | - release 49 | - develop 50 | - master 51 | only: 52 | - branches 53 | 54 | # Starting a child pipeline in a specific branch 55 | AI Lock mode scan: 56 | <<: *lock-mode 57 | only: 58 | - master 59 | 60 | # Starting a child pipeline in a specific branch 61 | AI Strictest mode scan: 62 | <<: *strictest-mode 63 | only: 64 | - develop 65 | -------------------------------------------------------------------------------- /GitLab_templates/customer-full/.AI/AI-Information-Mode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devopshq/dohq-ai-best-practices/563f94b3b0371b25305ed03349c42564beaac92b/GitLab_templates/customer-full/.AI/AI-Information-Mode.png -------------------------------------------------------------------------------- /GitLab_templates/customer-full/.AI/AI-Information-Mode.yml: -------------------------------------------------------------------------------- 1 | # This template is used for components scanning in "Information Mode" 2 | 3 | stages: 4 | - AI Scan 5 | - Security Gates 6 | - Build verification 7 | - Notifications 8 | 9 | 10 | # --- Variables ---------------------------------------------- 11 | 12 | # Common variables to run AI Scan 13 | variables: 14 | SCANNING_PROJECT: ${PARENT_SCANNING_PROJECT} 15 | SCANNING_PROJECT_LANGUAGE: ${PARENT_SCANNING_PROJECT_LANGUAGE} 16 | CODEQUALITY_SETTINGS: ${PARENT_CODEQUALITY_SETTINGS} 17 | 18 | 19 | # --- Pipeline Aliases --------------------------------------- 20 | 21 | # Common docker image and GitLab Runners tags 22 | .common-build: &common-build 23 | image: /aisa-linux:latest 24 | tags: 25 | - linux 26 | 27 | # Common structure to keep artifacts in GitLab CI Jobs 28 | .common-artifacts: &common-artifacts 29 | artifacts: 30 | expire_in: 14 day 31 | paths: 32 | - .report/ 33 | 34 | # Anchor for run condition, designed to simplify the pipeline 35 | .on-success: &on-success 36 | when: on_success 37 | 38 | # Anchor for run condition, designed to simplify the pipeline 39 | .on-failure: &on-failure 40 | when: on_failure 41 | 42 | 43 | # --- AI Aliases ---------------------------------------------------- 44 | 45 | # Common steps to generate a settings file 46 | .aisa-set-settings: &aisa-set-settings > 47 | aisa-set-settings 48 | --projectname ${SCANNING_PROJECT} 49 | --language ${SCANNING_PROJECT_LANGUAGE} 50 | 51 | # Common steps to start a scan 52 | .aisa-run-scan: &aisa-run-scan > 53 | aisa --version && 54 | aisa 55 | --project-settings-file ${SCANNING_PROJECT}.aiproj 56 | --scan-target ./ 57 | --reports "HTML,JSON" 58 | --reports-folder ".report" 59 | 60 | # Common steps to start procedure for processing scan results 61 | .aisa-codequality: &aisa-codequality > 62 | aisa-codequality 63 | -i .report 64 | -o codequality.json 65 | -t ${AI_GITLAB_BOT_TOKEN} 66 | -s ./aisa-codequality.settings.yml | tee temp_result 67 | 68 | 69 | # --- Additional scripts aliases ------------------------------------ 70 | 71 | # Push "Success" status with report hyperlink to parent pipeline 72 | .push-AI-report-status-success-to-upstream: &push-AI-report-status-success-to-upstream > 73 | curl --location --request POST "$CI_API_V4_URL/projects/$CI_PROJECT_ID/statuses/$CI_COMMIT_SHA?state=success&name=AI%20Scan%20Report&description=Click%20to%20watch%20scanning%20report&target_url=$CI_JOB_URL/artifacts/file/.report/ai_report.html&pipeline_id=$PARENT_CI_PIPELINE_ID" 74 | --header "PRIVATE-TOKEN: ${AI_GITLAB_BOT_TOKEN}" 75 | 76 | # Push "Security Gates: Passed / Failed" status to parent pipeline 77 | .push-Security-Gates-status-to-upstream: &push-Security-Gates-status-to-upstream > 78 | if cat temp_result | grep -q "Check Security Gates: PASSED"; then 79 | curl --location --request POST "$CI_API_V4_URL/projects/$CI_PROJECT_ID/statuses/$CI_COMMIT_SHA?state=success&name=Code%20Quality:%20PASSED&description=Check%20Security%20Gates:%20PASSED&pipeline_id=$PARENT_CI_PIPELINE_ID" 80 | --header "PRIVATE-TOKEN: ${AI_GITLAB_BOT_TOKEN}"; 81 | elif cat temp_result | grep -q "Check Security Gates: FAILED"; then 82 | curl --location --request POST "$CI_API_V4_URL/projects/$CI_PROJECT_ID/statuses/$CI_COMMIT_SHA?state=success&name=Code%20Quality:%20FAILED&description=Check%20Security%20Gates:%20FAILED&pipeline_id=$PARENT_CI_PIPELINE_ID" 83 | --header "PRIVATE-TOKEN: ${AI_GITLAB_BOT_TOKEN}"; fi && rm -rf temp_result 84 | 85 | 86 | # --- AI Scan Stage ------------------------------------------------ 87 | 88 | # Code scan with Aisa and report generation 89 | AI-scanning: 90 | <<: *common-build 91 | <<: *common-artifacts 92 | stage: AI Scan 93 | before_script: 94 | - *aisa-set-settings 95 | script: 96 | - *aisa-run-scan 97 | - *push-AI-report-status-success-to-upstream 98 | - mv .report/*.html .report/ai_report.html 99 | 100 | 101 | # --- Security Gates Stage ------------------------------------------ 102 | 103 | # This job processes the results of the AI-scanning and makes a verdict on them. See the documentation for more info 104 | Check Security Gate: 105 | <<: *common-build 106 | <<: *common-artifacts 107 | <<: *on-success 108 | stage: Security Gates 109 | before_script: 110 | - echo "${CODEQUALITY_SETTINGS}" > ./aisa-codequality.settings.yml 111 | script: 112 | - *aisa-codequality 113 | - *push-Security-Gates-status-to-upstream 114 | needs: 115 | - job: AI-scanning 116 | artifacts: true 117 | 118 | # Fake job for demonstration 119 | Send failed status to monitoring: 120 | <<: *common-build 121 | <<: *on-failure 122 | stage: Security Gates 123 | script: 124 | - exit 0 125 | 126 | 127 | # --- Notification Stage -------------------------------------------- 128 | 129 | # Fake job for demonstration 130 | Notify by email and chats (Success): 131 | <<: *common-build 132 | <<: *on-success 133 | stage: Notifications 134 | script: 135 | - exit 0 136 | 137 | # Fake job for demonstration 138 | Notify by email and chats (Failure): 139 | <<: *common-build 140 | <<: *on-failure 141 | stage: Notifications 142 | script: 143 | - exit 0 144 | -------------------------------------------------------------------------------- /GitLab_templates/customer-full/.AI/AI-Lock-Mode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devopshq/dohq-ai-best-practices/563f94b3b0371b25305ed03349c42564beaac92b/GitLab_templates/customer-full/.AI/AI-Lock-Mode.png -------------------------------------------------------------------------------- /GitLab_templates/customer-full/.AI/AI-Lock-Mode.yml: -------------------------------------------------------------------------------- 1 | # This template is used for components scanning in "Lock Mode" 2 | 3 | stages: 4 | - AI Scan 5 | - Security Gates 6 | - Build verification 7 | - Notifications 8 | 9 | 10 | # --- Variables ---------------------------------------------- 11 | 12 | # Common variables to run AI Scan 13 | variables: 14 | SCANNING_PROJECT: ${PARENT_SCANNING_PROJECT} 15 | SCANNING_PROJECT_LANGUAGE: ${PARENT_SCANNING_PROJECT_LANGUAGE} 16 | CODEQUALITY_SETTINGS: ${PARENT_CODEQUALITY_SETTINGS} 17 | 18 | 19 | # --- Pipeline Aliases --------------------------------------- 20 | 21 | # Common docker image and GitLab Runners tags 22 | .common-build: &common-build 23 | image: /aisa-linux:latest 24 | tags: 25 | - linux 26 | - docker 27 | 28 | # Common structure to keep artifacts in GitLab CI Jobs 29 | .common-artifacts: &common-artifacts 30 | artifacts: 31 | expire_in: 14 day 32 | paths: 33 | - .report/ 34 | 35 | # Anchor for run condition, designed to simplify the pipeline 36 | .on-success: &on-success 37 | when: on_success 38 | 39 | # Anchor for run condition, designed to simplify the pipeline 40 | .on-failure: &on-failure 41 | when: on_failure 42 | 43 | 44 | # --- AI Aliases ---------------------------------------------------- 45 | 46 | # Common steps to generate a settings file 47 | .aisa-set-settings: &aisa-set-settings > 48 | aisa-set-settings 49 | --projectname ${SCANNING_PROJECT} 50 | --language ${SCANNING_PROJECT_LANGUAGE} 51 | 52 | # Common steps to start a scan 53 | .aisa-run-scan: &aisa-run-scan > 54 | aisa --version && 55 | aisa 56 | --project-settings-file ${SCANNING_PROJECT}.aiproj 57 | --scan-target ./ 58 | --reports "HTML,JSON" 59 | --reports-folder ".report" 60 | 61 | # Common steps to start procedure for processing scan results 62 | .aisa-codequality: &aisa-codequality > 63 | aisa-codequality 64 | -i .report 65 | -o codequality.json 66 | -t ${AI_GITLAB_BOT_TOKEN} 67 | -b True 68 | -s ./aisa-codequality.settings.yml | tee temp_result 69 | 70 | 71 | # --- Additional scripts aliases ------------------------------------ 72 | 73 | # Push "Running" status to parent pipeline (for easier perception in MergeRequest) 74 | .push-AI-report-status-run-to-upstream: &push-AI-report-status-run-to-upstream > 75 | curl --location --request POST "$CI_API_V4_URL/projects/$CI_PROJECT_ID/statuses/$CI_COMMIT_SHA?state=running&name=AI%20Scan%20Report&description=Waiting%20for%20scan%20report%20from%20child%20pipeline&pipeline_id=$PARENT_CI_PIPELINE_ID" 76 | --header "PRIVATE-TOKEN: ${AI_GITLAB_BOT_TOKEN}" 77 | 78 | # Push "Success" status with report hyperlink to parent pipeline 79 | .push-AI-report-status-success-to-upstream: &push-AI-report-status-success-to-upstream > 80 | curl --location --request POST "$CI_API_V4_URL/projects/$CI_PROJECT_ID/statuses/$CI_COMMIT_SHA?state=success&name=AI%20Scan%20Report&description=Click%20to%20watch%20scanning%20report&target_url=$CI_JOB_URL/artifacts/file/.report/ai_report.html&pipeline_id=$PARENT_CI_PIPELINE_ID" 81 | --header "PRIVATE-TOKEN: ${AI_GITLAB_BOT_TOKEN}" 82 | 83 | # Push "Security Gates: Passed / Failed" status to parent pipeline 84 | .push-Security-Gates-status-to-upstream: &push-Security-Gates-status-to-upstream > 85 | if cat temp_result | grep -q "Check Security Gates: PASSED"; then 86 | curl --location --request POST "$CI_API_V4_URL/projects/$CI_PROJECT_ID/statuses/$CI_COMMIT_SHA?state=success&name=Code%20Quality:%20PASSED&description=Check%20Security%20Gates:%20PASSED&pipeline_id=$PARENT_CI_PIPELINE_ID" 87 | --header "PRIVATE-TOKEN: ${AI_GITLAB_BOT_TOKEN}"; 88 | elif cat temp_result | grep -q "Check Security Gates: FAILED"; then 89 | curl --location --request POST "$CI_API_V4_URL/projects/$CI_PROJECT_ID/statuses/$CI_COMMIT_SHA?state=success&name=Code%20Quality:%20FAILED&description=Check%20Security%20Gates:%20FAILED&pipeline_id=$PARENT_CI_PIPELINE_ID" 90 | --header "PRIVATE-TOKEN: ${AI_GITLAB_BOT_TOKEN}"; fi && rm -rf temp_result 91 | 92 | 93 | # --- AI Scan Stage ------------------------------------------------ 94 | 95 | # Code scan with Aisa and report generation 96 | AI-scanning: 97 | <<: *common-build 98 | <<: *common-artifacts 99 | stage: AI Scan 100 | before_script: 101 | - *push-AI-report-status-run-to-upstream 102 | - *aisa-set-settings 103 | script: 104 | - *aisa-run-scan 105 | - *push-AI-report-status-success-to-upstream 106 | - mv .report/*.html .report/ai_report.html 107 | 108 | 109 | # --- Security Gates Stage ------------------------------------------ 110 | 111 | # This job processes the results of the AI-scanning and makes a verdict on them. See the documentation for more info 112 | Check Security Gate: 113 | <<: *common-build 114 | <<: *common-artifacts 115 | <<: *on-success 116 | stage: Security Gates 117 | before_script: 118 | - echo "${CODEQUALITY_SETTINGS}" > ./aisa-codequality.settings.yml 119 | script: 120 | - *aisa-codequality 121 | - *push-Security-Gates-status-to-upstream 122 | needs: 123 | - job: AI-scanning 124 | artifacts: true 125 | 126 | # Fake job for demonstration 127 | Send failed status to monitoring: 128 | <<: *common-build 129 | <<: *on-failure 130 | stage: Security Gates 131 | script: 132 | - exit 0 133 | 134 | 135 | # --- Notification Stage -------------------------------------------- 136 | 137 | # Fake job for demonstration 138 | Notify by email and chats (Success): 139 | <<: *common-build 140 | <<: *on-success 141 | stage: Notifications 142 | script: 143 | - exit 0 144 | 145 | # Fake job for demonstration 146 | Notify by email and chats (Failure): 147 | <<: *common-build 148 | <<: *on-failure 149 | stage: Notifications 150 | script: 151 | - exit 0 152 | -------------------------------------------------------------------------------- /GitLab_templates/customer-full/.AI/AI-Strictest-Mode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devopshq/dohq-ai-best-practices/563f94b3b0371b25305ed03349c42564beaac92b/GitLab_templates/customer-full/.AI/AI-Strictest-Mode.png -------------------------------------------------------------------------------- /GitLab_templates/customer-full/.AI/AI-Strictest-Mode.yml: -------------------------------------------------------------------------------- 1 | # This template is used for components scanning in "Strictest Mode" 2 | 3 | stages: 4 | - AI Scan 5 | - Security Gates 6 | - Build verification 7 | - Notifications 8 | 9 | 10 | # --- Variables ---------------------------------------------- 11 | 12 | # Common variables to run AI Scan 13 | variables: 14 | SCANNING_PROJECT: ${PARENT_SCANNING_PROJECT} 15 | SCANNING_PROJECT_LANGUAGE: ${PARENT_SCANNING_PROJECT_LANGUAGE} 16 | CODEQUALITY_SETTINGS: ${PARENT_CODEQUALITY_SETTINGS} 17 | 18 | 19 | # --- Pipeline Aliases --------------------------------------- 20 | 21 | # Common docker image and GitLab Runners tags 22 | .common-build: &common-build 23 | image: /aisa-linux:latest 24 | tags: 25 | - linux 26 | - docker 27 | 28 | # Common structure to keep artifacts in GitLab CI Jobs 29 | .common-artifacts: &common-artifacts 30 | artifacts: 31 | expire_in: 14 day 32 | paths: 33 | - .report/ 34 | 35 | # Anchor for run condition, designed to simplify the pipeline 36 | .on-success: &on-success 37 | when: on_success 38 | 39 | # Anchor for run condition, designed to simplify the pipeline 40 | .on-failure: &on-failure 41 | when: on_failure 42 | 43 | 44 | # --- AI Aliases ---------------------------------------------------- 45 | 46 | # Common steps to generate a settings file 47 | .aisa-set-settings: &aisa-set-settings > 48 | aisa-set-settings 49 | --projectname ${SCANNING_PROJECT} 50 | --language ${SCANNING_PROJECT_LANGUAGE} 51 | 52 | # Common steps to start a scan 53 | .aisa-run-scan: &aisa-run-scan > 54 | aisa --version && 55 | aisa 56 | --project-settings-file ${SCANNING_PROJECT}.aiproj 57 | --scan-target ./ 58 | --reports "HTML,JSON" 59 | --reports-folder ".report" 60 | 61 | # Common steps to start procedure for processing scan results 62 | .aisa-codequality: &aisa-codequality > 63 | aisa-codequality 64 | -i .report 65 | -o codequality.json 66 | -t ${AI_GITLAB_BOT_TOKEN} 67 | -b True 68 | -s ./aisa-codequality.settings.yml | tee temp_result 69 | 70 | 71 | # --- Additional scripts aliases ------------------------------------ 72 | 73 | # Push "Running" status to parent pipeline (for easier perception in MergeRequest) 74 | .push-AI-report-status-run-to-upstream: &push-AI-report-status-run-to-upstream > 75 | curl --location --request POST "$CI_API_V4_URL/projects/$CI_PROJECT_ID/statuses/$CI_COMMIT_SHA?state=running&name=AI%20Scan%20Report&description=Waiting%20for%20scan%20report%20from%20child%20pipeline&pipeline_id=$PARENT_CI_PIPELINE_ID" 76 | --header "PRIVATE-TOKEN: ${AI_GITLAB_BOT_TOKEN}" 77 | 78 | # Push "Success" status with report hyperlink to parent pipeline 79 | .push-AI-report-status-success-to-upstream: &push-AI-report-status-success-to-upstream > 80 | curl --location --request POST "$CI_API_V4_URL/projects/$CI_PROJECT_ID/statuses/$CI_COMMIT_SHA?state=success&name=AI%20Scan%20Report&description=Click%20to%20watch%20scanning%20report&target_url=$CI_JOB_URL/artifacts/file/.report/ai_report.html&pipeline_id=$PARENT_CI_PIPELINE_ID" 81 | --header "PRIVATE-TOKEN: ${AI_GITLAB_BOT_TOKEN}" 82 | 83 | # Push "Security Gates: Passed / Failed" status to parent pipeline 84 | .push-Security-Gates-status-to-upstream: &push-Security-Gates-status-to-upstream > 85 | if cat temp_result | grep -q "Check Security Gates: PASSED"; then 86 | curl --location --request POST "$CI_API_V4_URL/projects/$CI_PROJECT_ID/statuses/$CI_COMMIT_SHA?state=success&name=Code%20Quality:%20PASSED&description=Check%20Security%20Gates:%20PASSED&pipeline_id=$PARENT_CI_PIPELINE_ID" 87 | --header "PRIVATE-TOKEN: ${AI_GITLAB_BOT_TOKEN}"; 88 | elif cat temp_result | grep -q "Check Security Gates: FAILED"; then 89 | curl --location --request POST "$CI_API_V4_URL/projects/$CI_PROJECT_ID/statuses/$CI_COMMIT_SHA?state=failed&name=Code%20Quality:%20FAILED&description=Check%20Security%20Gates:%20FAILED&pipeline_id=$PARENT_CI_PIPELINE_ID" 90 | --header "PRIVATE-TOKEN: ${AI_GITLAB_BOT_TOKEN}"; fi && rm -rf temp_result 91 | 92 | # Write the scan status to the variable 93 | .get-Security-Gates-status: &get-Security-Gates-status > 94 | if cat temp_result | grep -q "Check Security Gates: PASSED"; then echo 'SECURITY_GATES_STATUS="PASSED"' > .env; 95 | elif cat temp_result | grep -q "Check Security Gates: FAILED"; then echo 'SECURITY_GATES_STATUS="FAILED"' > .env; fi 96 | 97 | # Starting the manual job in the parent pipeline if the Security Gates status is Passed 98 | # Also repeat the launch requests until the manual job is available in the parent pipeline (for builds with long build times) 99 | .run-manual-job-from-upstream: &run-manual-job-from-upstream > 100 | PARENT_JOB_ID=null && while [[ "$PARENT_JOB_ID" == null ]]; 101 | do PARENT_JOB_ID=$(curl --location --request GET "$CI_API_V4_URL/projects/$CI_PROJECT_ID/pipelines/$PARENT_CI_PIPELINE_ID/jobs?scope[]=manual" 102 | --header "PRIVATE-TOKEN: ${AI_GITLAB_BOT_TOKEN}" > .json && cat .json | jq ".[0].id" && rm -rf .json); 103 | echo 'Sleep 1m for waiting upstream pipeline, then retry...'; sleep 1; done; 104 | curl --location -g --request POST "$CI_API_V4_URL/projects/$CI_PROJECT_ID/jobs/$PARENT_JOB_ID/play" 105 | --header "PRIVATE-TOKEN: ${AI_GITLAB_BOT_TOKEN}" 106 | 107 | 108 | # --- AI Scan Stage ------------------------------------------------ 109 | 110 | # Code scan with Aisa and report generation 111 | AI-scanning: 112 | <<: *common-build 113 | <<: *common-artifacts 114 | stage: AI Scan 115 | before_script: 116 | - *push-AI-report-status-run-to-upstream 117 | - *aisa-set-settings 118 | script: 119 | - *aisa-run-scan 120 | - *push-AI-report-status-success-to-upstream 121 | - mv .report/*.html .report/ai_report.html 122 | 123 | 124 | # --- Security Gates Stage ------------------------------------------ 125 | 126 | # This job processes the results of the AI-scanning and makes a verdict on them. See the documentation for more info 127 | Check Security Gate: 128 | <<: *common-build 129 | <<: *on-success 130 | stage: Security Gates 131 | before_script: 132 | - echo "${CODEQUALITY_SETTINGS}" > ./aisa-codequality.settings.yml 133 | script: 134 | - *aisa-codequality 135 | - *get-Security-Gates-status 136 | - *push-Security-Gates-status-to-upstream 137 | needs: 138 | - job: AI-scanning 139 | artifacts: true 140 | artifacts: 141 | expire_in: 14 day 142 | paths: 143 | - .report/ 144 | reports: 145 | dotenv: .env 146 | 147 | # Fake job for demonstration 148 | Send failed status to monitoring: 149 | <<: *common-build 150 | <<: *on-failure 151 | stage: Security Gates 152 | script: 153 | - exit 0 154 | 155 | 156 | # --- Approve Stage ------------------------------------------------- 157 | 158 | # Completes successfully if the build is passed, if not, it fails the downstream pipeline 159 | Approve build: 160 | <<: *common-build 161 | stage: Build verification 162 | script: 163 | - if [[ $SECURITY_GATES_STATUS == \"PASSED\" ]]; then exit 0; else exit 1; fi 164 | dependencies: 165 | - Check Security Gate 166 | 167 | # Starts a manual job in the parent pipeline 168 | Run upload: 169 | <<: *common-build 170 | stage: Build verification 171 | script: 172 | - if [[ "$SECURITY_GATES_STATUS" == \"PASSED\" ]] ; then echo $SECURITY_GATES_STATUS; else echo $SECURITY_GATES_STATUS; exit 1; fi 173 | - *run-manual-job-from-upstream 174 | dependencies: 175 | - Check Security Gate 176 | 177 | 178 | # --- Notification Stage -------------------------------------------- 179 | 180 | # Fake job for demonstration 181 | Notify by email and chats (Success): 182 | <<: *common-build 183 | <<: *on-success 184 | stage: Notifications 185 | script: 186 | - exit 0 187 | 188 | # Fake job for demonstration 189 | Notify by email and chats (Failure): 190 | <<: *common-build 191 | <<: *on-failure 192 | stage: Notifications 193 | script: 194 | - exit 0 195 | -------------------------------------------------------------------------------- /GitLab_templates/customer-full/.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | stages: 2 | - AI scan start 3 | - Tests 4 | - Build 5 | - Upload 6 | 7 | 8 | # --- Workflow ----------------------------------------------- 9 | 10 | # The workflow field allows you to disable the duplicate pipeline launch if Merge Request exists. 11 | workflow: 12 | rules: 13 | - if: $CI_COMMIT_TAG 14 | when: never 15 | - if: $CI_MERGE_REQUEST_ID 16 | when: never 17 | - when: always 18 | 19 | 20 | # --- Variables ---------------------------------------------- 21 | 22 | 23 | # Common variables to run AI Scan 24 | variables: 25 | DOCKER_IMAGE: /aisa-linux:latest 26 | SCANNING_PROJECT: ${CI_PROJECT_PATH_SLUG} 27 | SCANNING_PROJECT_LANGUAGE: javascript 28 | CODEQUALITY_SETTINGS: | 29 | threats mapping: 30 | info: Potential 31 | minor: Low 32 | major: Medium 33 | critical: High 34 | blocker: [] 35 | security gates: 36 | info: 0 37 | minor: 1 38 | major: 4 39 | critical: 0 40 | blocker: 0 41 | 42 | 43 | # --- AI Scan Stage ------------------------------------------------- 44 | 45 | # Running a template from a third-party .yml file to save space in the current one 46 | include: 47 | - local: .AI/.gitlab-ci.ai.yml 48 | 49 | 50 | # --- Tests Stage --------------------------------------------------- 51 | 52 | # Fake job for demonstration 53 | Tests: 54 | image: ${DOCKER_IMAGE} 55 | stage: Tests 56 | script: 57 | - exit 0 58 | 59 | 60 | # --- Build Stage --------------------------------------------------- 61 | 62 | # Fake job for demonstration 63 | Build: 64 | image: ${DOCKER_IMAGE} 65 | stage: Build 66 | script: 67 | - exit 0 68 | 69 | 70 | # --- Upload Stage -------------------------------------------------- 71 | 72 | # Fake job in two states for demonstration 73 | Upload to registry: 74 | image: ${DOCKER_IMAGE} 75 | stage: Upload 76 | script: 77 | - exit 0 78 | rules: 79 | - if: '$CI_COMMIT_BRANCH == "develop"' 80 | when: manual 81 | - when: on_success 82 | -------------------------------------------------------------------------------- /GitLab_templates/customer-lite/.AI/AI-scan.yml: -------------------------------------------------------------------------------- 1 | stages: 2 | - AI Scan 3 | - Notifications 4 | 5 | # --- Pipeline Aliases --------------------------------------- 6 | 7 | .common-build: &common-build 8 | image: ${PARENT_DOCKER_IMAGE} 9 | tags: 10 | - linux 11 | artifacts: 12 | expire_in: 30 day 13 | paths: 14 | - .report/ 15 | 16 | # --- AI Aliases --------------------------------------------------- 17 | 18 | .aisa-set-settings: &aisa-set-settings > 19 | aisa-set-settings 20 | --projectname ${PARENT_SCANNING_PROJECT} 21 | --language ${PARENT_SCANNING_PROJECT_LANGUAGE} 22 | 23 | .aisa-run-scan: &aisa-run-scan > 24 | aisa --version && 25 | aisa 26 | --project-settings-file ${PARENT_SCANNING_PROJECT}.aiproj 27 | --scan-target ./ 28 | --reports "HTML,JSON" 29 | --reports-folder ".report" 30 | 31 | 32 | # --- Additional scripts aliases ------------------------------------ 33 | 34 | .push-AI-report-status-success-to-upstream: &push-AI-report-status-success-to-upstream > 35 | curl --location --request POST "$CI_API_V4_URL/projects/$CI_PROJECT_ID/statuses/$CI_COMMIT_SHA?state=success&name=AI%20Scan%20Report&description=Click%20to%20watch%20scanning%20report&target_url=$CI_JOB_URL/artifacts/file/.report/ai_report.html&pipeline_id=$PARENT_CI_PIPELINE_ID" --header "PRIVATE-TOKEN: ${AI_GITLAB_BOT_TOKEN}" 36 | 37 | # --- AI Scan Stage ------------------------------------------------ 38 | 39 | AI-scanning: 40 | <<: *common-build 41 | stage: AI Scan 42 | before_script: 43 | - *aisa-set-settings 44 | script: 45 | - *aisa-run-scan 46 | - *push-AI-report-status-success-to-upstream 47 | - mv .report/*.html .report/ai_report.html 48 | 49 | 50 | # --- Notification Stage -------------------------------------------- 51 | 52 | Send failed status to monitoring: 53 | <<: *common-build 54 | stage: Notifications 55 | script: 56 | - echo "There is a problem with AI Server!" 57 | - exit 1 58 | when: on_failure -------------------------------------------------------------------------------- /GitLab_templates/customer-lite/.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | # Copy lines 3 - 18 to your .gitlab-ci.yml before main build steps 2 | 3 | stages: 4 | - Start AI scan 5 | 6 | # --- AI Scan Stage ------------------------------------------------ 7 | 8 | Start AI Information Scan: 9 | stage: Start AI scan 10 | trigger: 11 | include: 12 | - local: .AI/AI-scan.yml 13 | # include: https://raw.githubusercontent.com/devopshq/dohq-ai-best-practices/master/GitLab_templates/customer-lite/.AI/AI-scan.yml 14 | variables: 15 | PARENT_CI_PIPELINE_ID: $CI_PIPELINE_ID # Default GitLab CI Variable 16 | PARENT_SCANNING_PROJECT: $CI_PROJECT_PATH_SLUG # AI project name 17 | PARENT_SCANNING_PROJECT_LANGUAGE: "javascript" # one of: "java", "php", "csharp", "vb", "objectivec", "cplusplus", "sql", "swift", "python", "javascript", "go", "kotlin" 18 | PARENT_DOCKER_IMAGE: "/aisa-linux:latest" 19 | # ${AI_GITLAB_BOT_TOKEN} - a user token that has read rights to the repository content. This variable is set at the project settings/ci_cd/Variables or project group 20 | -------------------------------------------------------------------------------- /GitLab_templates/default_project_files/default_policy.json: -------------------------------------------------------------------------------- 1 | // Default policy template for AIE 3.5.0 2 | [ 3 | { 4 | "CountToActualize": 1, 5 | "Scopes": [ 6 | { 7 | "Rules": [ 8 | { 9 | "Field": "Level", // field name 10 | "Value": "High", // field value, case insensitive 11 | "IsRegex": false // whether to use regular expressions 12 | }, 13 | { 14 | "Field": "IsSuspected", 15 | "Value": "false", 16 | "IsRegex": false 17 | }, 18 | { 19 | "Field": "ApprovalState", 20 | "Value": "[^2]", 21 | "IsRegex": true 22 | } 23 | ] 24 | } 25 | ] 26 | } 27 | ] 28 | -------------------------------------------------------------------------------- /GitLab_templates/default_project_files/default_project.aiproj: -------------------------------------------------------------------------------- 1 | { 2 | "ProjectName": "Project", 3 | "ProgrammingLanguage": "Csharp" 4 | "ScanAppType": "Configuration, Fingerprint, PmTaint, DependencyCheck", 5 | "ThreadCount": 2, 6 | "Site": "http://localhost", 7 | "IsDownloadDependencies": true, 8 | 9 | "IsUsePublicAnalysisMethod": true, 10 | "IsUseEntryAnalysisPoint": true, 11 | 12 | "ScanUnitTimeout": 360, 13 | "PreprocessingTimeout": 60, 14 | "CustomParameters": "--multifile", 15 | 16 | "SkipFileFormats": ["*.7z", "*.bmp", "*.dib", "*.dll", "*.doc", "*.docx", "*.exe", "*.gif", "*.ico", "*.jfif", "*.jpe", "*.jpe6", "*.jpeg", "*.jpg", "*.odt", "*.pdb", "*.pdf", "*.png", "*.rar", "*.swf", "*.tif", "*.tiff", "*.zip"], 17 | "SkipFilesFolders": ["\\\\devops-tools\\\\", "\\\\.git\\\\", "\\\\.gitignore", "\\\\.gitmodules", "\\\\.gitattributes", "\\\\$tf\\\\", "\\\\$BuildProcessTemplate\\\\", "\\\\.tfignore"], 18 | 19 | "DisabledPatterns": ["145", "146", "148", "149"], 20 | "DisabledTypes": [], 21 | 22 | "UseIncrementalScan": true, 23 | "FullRescanOnNewFilesAdded": true, 24 | 25 | "ConsiderPreviousScan": true, 26 | "HideSuspectedVulnerabilities": false, 27 | "UseIssueTrackerIntegration": false, 28 | 29 | "IsUnpackUserPackages": false, 30 | "JavaParameters": null, 31 | "JavaVersion": 0, 32 | "UseJavaNormalizeVersionPattern": "true", 33 | "JavaNormalizeVersionPattern": "-\\\\d+(\\\\.\\\\d+)*", 34 | 35 | "JavaScriptProjectFile": null, 36 | "JavaScriptProjectFolder": null, 37 | 38 | "UseTaintAnalysis": true, 39 | "UsePmAnalysis": true, 40 | "DisableInterpretCores": false, 41 | 42 | "UseDefaultFingerprints": true, 43 | "UseCustomYaraRules": false, 44 | 45 | "CustomHeaders": [["", ""]], 46 | "Authentication": { 47 | "auth_item": { 48 | "domain": null, 49 | "credentials": { 50 | "cookie": null, 51 | "type": 2, 52 | "login": { 53 | "name": null, 54 | "value": null, 55 | "regexp": null, 56 | "is_regexp": false 57 | }, 58 | "password": { 59 | "name": null, 60 | "value": null, 61 | "regexp": null, 62 | "is_regexp": false 63 | } 64 | }, 65 | "test_url": null, 66 | "form_url": null, 67 | "form_xpath": ".//form", 68 | "regexp_of_success": null 69 | } 70 | }, 71 | "ProxySettings": { 72 | "IsEnabled": false, 73 | "Host": null, 74 | "Port": null, 75 | "Type": 0, 76 | "Username": null, 77 | "Password": null 78 | }, 79 | 80 | "RunAutocheckAfterScan": false, 81 | "AutocheckSite": "http://localhost", 82 | "AutocheckCustomHeaders": [["", ""]], 83 | "AutocheckAuthentication": { 84 | "auth_item": { 85 | "domain": null, 86 | "credentials": { 87 | "cookie": null, 88 | "cookies": null, 89 | "type": 2, 90 | "login": { 91 | "name": null, 92 | "value": null, 93 | "regexp": null, 94 | "is_regexp": false 95 | }, 96 | "password": { 97 | "name": null, 98 | "value": null, 99 | "regexp": null, 100 | "is_regexp": false 101 | } 102 | }, 103 | "test_url": null, 104 | "form_url": null, 105 | "form_xpath": ".//form", 106 | "regexp_of_success": null 107 | } 108 | }, 109 | "AutocheckProxySettings": { 110 | "IsEnabled": false, 111 | "Host": null, 112 | "Port": null, 113 | "Type": 0, 114 | "Username": null, 115 | "Password": null 116 | }, 117 | 118 | "SendEmailWithReportsAfterScan": false, 119 | "CompressReport": false, 120 | 121 | "EmailSettings": null, 122 | 123 | "ReportParameters": { 124 | "SaveAsPath": null, 125 | "UseElectronicSignature": false, 126 | "CertificatePath": null, 127 | "Password": null, 128 | "ShowSignatureTime": false, 129 | "SignatureReason": null, 130 | "Location": null, 131 | "DoSignatureVisible": false, 132 | "IncludeDiscardedVulnerabilities": false, 133 | "IncludeSuppressedVulnerabilities": true, 134 | "IncludeSuspectedVulnerabilities": false, 135 | "IncludeGlossary": false, 136 | "ConverHtmlToPdf": false, 137 | "RemoveHtml": false, 138 | "CreatePdfPrintVersion": false, 139 | "MakeAFReport": false, 140 | "IncludeDFD": false 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /GitLab_templates/default_project_files/default_project_with_comments.aiproj: -------------------------------------------------------------------------------- 1 | { 2 | // Main Settings 3 | "ProjectName": "Project", // Имя проекта 4 | "ProgrammingLanguage": "Csharp", // Язык приложения. 5 | // Доступны: Java, Php, Csharp, Vb, ObjectiveC, CPlusPlus, Sql, Swift, Python, JavaScript, Kotlin, Go 6 | "ScanAppType": "CSharp , Configuration, Fingerprint, PmTaint ", // Модули поиска уязвимостей. 7 | // Доступны: Php, Java, CSharp, JavaScript, Configuration, Fingerprint (включает в себя DependencyCheck), PmTaint, BlackBox 8 | 9 | "ThreadCount": 1, // Количество потоков 10 | "Site": "http://localhost", // Адрес сайта 11 | "IsDownloadDependencies": true, // Загрузить зависимости 12 | 13 | "IsUsePublicAnalysisMethod": false, // Искать от доступных public и protected методов 14 | "IsUseEntryAnalysisPoint": true, // Искать от точек входа 15 | 16 | "ScanUnitTimeout": 600, // Максимальное время сканирования файла в seconds 17 | "PreprocessingTimeout": 60, // Таймаут препроцессинга в minutes 18 | "CustomParameters": null, // Дополнительные параметры запуска 19 | 20 | "SkipFileFormats": ["*.gif"], // Исключенные форматы файлов 21 | "SkipFilesFolders": ["\\.git\\", "\\.gitignore", "\\.gitmodules", "\\.gitattributes", "\\$tf\\", "\\$BuildProcessTemplate\\", "\\.tfignore"], // Фильтр дерева 22 | 23 | // Vulnerabilities to find 24 | "DisabledPatterns": ["145", "146", "148", "149"], // Отключенные шаблоны 25 | "DisabledTypes": [], // Отключенные проверки исходного кода 26 | 27 | "ConsiderPreviousScan": true, // Учитывать предыдущее сканирование 28 | "HideSuspectedVulnerabilities": true, //Скрывать подозрения на уязвимость 29 | "UseIssueTrackerIntegration": true, // Использовать интеграцию с системами обработки заявок 30 | 31 | // Java Parameters 32 | "IsUnpackUserPackages": false, // Распаковывать пользовательские пакеты 33 | "JavaParameters": null, // Параметры запуска JDK 34 | "JavaVersion": 0, // Версия jdk, 0 соответствует версии 1.8, 1 соответствует версии 1.10 35 | 36 | //JavaScript Parameters 37 | "JavaScriptProjectFile": "path_to_file", // Путь к файлу скрипта 38 | "JavaScriptProjectFolder": "path_to_dir", // Путь к корневой папке проекта javascript 39 | 40 | //PMTaint Parameters 41 | "UseTaintAnalysis": false, // Использовать ли движок AI.Taint для анализа 42 | "UsePmAnalysis": true, // Использовать ли движок PT.PM для анализа 43 | "DisableInterpretCores": false, // Игнорировать ли ядра интерпретации (C#, Java, PHP) при анализе 44 | 45 | // YARA Parameters 46 | "UseDefaultFingerprints": true, // Использовать предустановленные фингерпринты 47 | "UseCustomYaraRules": false, // Использовать пользовательские правила YARA (сами правила задаются только через базу в UI) 48 | 49 | // BlackBox Parameters 50 | "BlackBoxScanLevel": "None", // Режим поиска. Доступны: Fast, Normal, Full 51 | "CustomHeaders": [["", ""]], // Дополнительные заголовки 52 | "Authentication": { 53 | "auth_item": { 54 | "domain": null, // Адрес проверки 55 | "credentials": { 56 | "cookie": null, // Значение куки 57 | "type": 2, // Тип аутентификации. Доступно: 0 = Form, 1 = HTTP, 2 = None, 3 = Cookie 58 | "login": { 59 | "name": null, // поле "Ключ логина" 60 | "value": null, // поле значения логина 61 | "regexp": null, 62 | "is_regexp": false 63 | }, 64 | "password": { 65 | "name": null, // поле "Ключ пароля" 66 | "value": null, // поле значения пароля 67 | "regexp": null, // ex: "p[aA]ss(word)?" 68 | "is_regexp": false 69 | } 70 | }, 71 | "test_url": null, // поле "Адрес проверки" 72 | "form_url": null, // поле "Адрес формы" 73 | "form_xpath": ".//form", // поле "XPath формы" 74 | "regexp_of_success": null // поле "Шаблон проверки" 75 | } 76 | }, 77 | "ProxySettings": { 78 | "IsEnabled": false, // Активировать настройки прокси 79 | "Host": null, // "ip address" 80 | "Port": null, // Порт 81 | "Type": 0, // Тип прокси. Доступно: 0 or HTTP, 1 or HTTPNOCONNECT, 2 or SOCKS4, 3 or SOCKS5 82 | "Username": null, // Логин 83 | "Password": null // Пароль 84 | }, 85 | 86 | // Autocheck Parameters 87 | "RunAutocheckAfterScan": false, // Запустить автопроверку после сканирования 88 | "AutocheckSite": "http://localhost", // Адрес для автопроверки, если не указан берется значение параметра "Site" 89 | "AutocheckCustomHeaders": [["", ""]], // Дополнительные заголовки 90 | "AutocheckAuthentication": { 91 | "auth_item": { 92 | "domain": null, // Адрес проверки 93 | "credentials": { 94 | "cookie": null, // Значение куки 95 | "cookies": null, 96 | "type": 2, // Тип аутентификации. Доступно: 0 = Form, 1 = HTTP, 2 = None, 3 = Cookie 97 | "login": { 98 | "name": null, // поле "Ключ логина" 99 | "value": null, // поле значения логина 100 | "regexp": null, 101 | "is_regexp": false 102 | }, 103 | "password": { 104 | "name": null, // поле "Ключ пароля" 105 | "value": null, // поле значения пароля 106 | "regexp": null, // пример: "p[aA]ss(word)?" 107 | "is_regexp": false 108 | } 109 | }, 110 | "test_url": null, // поле "Адрес проверки" 111 | "form_url": null, // поле "Адрес формы" 112 | "form_xpath": ".//form", // поле "XPath формы" 113 | "regexp_of_success": null // поле "Шаблон проверки" 114 | } 115 | }, 116 | "AutocheckProxySettings": { 117 | "IsEnabled": false, // Активировать настройки прокси 118 | "Host": null, // IP-адрес 119 | "Port": null, // Порт 120 | "Type": 0, // Тип прокси. Доступно: 0 or HTTP, 1 or HTTPNOCONNECT, 2 or SOCKS4, 3 or SOCKS5 121 | "Username": null, // Логин 122 | "Password": null // Пароль 123 | }, 124 | 125 | "SendEmailWithReportsAfterScan": true, // Отправлять отчет на почту по завершении сканирования 126 | "CompressReport": false, // Сжимать отчет перед отправкой 127 | 128 | // Email Parameters 129 | "EmailSettings": { 130 | "SmtpServerAddress": "mail.ptsecurity.ru", // Адрес SMTP сервера 131 | "UserName": "testagent_wes@ptsecurity.com", // Имя пользователя 132 | "Password": "P@ssw0rd", // Пароль 133 | "EmailRecipients": "User@ptsecurity.ru", // Адрес получателя отчета 134 | "EnableSsl": true, // Включить SSL 135 | "Subject": "Email Title", // Тема 136 | "ConsiderCertificateError": true, // Учитывать ошибки сертификата 137 | "SenderEmail": "testagent_wes@ptsecurity.com" // Отправитель 138 | }, 139 | 140 | // Report Settings 141 | "ReportParameters": { 142 | "SaveAsPath": null, // Папка, в которую сохраняются отчеты 143 | "UseFilters": false, // Использовать фильтры 144 | "CreatePdfPrintVersion": false, // Создавать версию для печати 145 | "IncludeDiscardedVulnerabilities": false, // Включить опровергнутые уязвимости в отчет (по умолчанию не добавлять) 146 | "IncludeSuppressedVulnerabilities": false, // Добавить исключенные уязвимости в отчет (по умолчанию не добавлять) 147 | "IncludeSuspectedVulnerabilities": true, // Включить подозрения на уязвимость в отчет (по умолчанию добавлять) 148 | "IncludeGlossary": false, // Добавить глоссарий 149 | "IncludeDFD": false // Добавить диаграмму потока данных 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /GitLab_templates/example_1.yml: -------------------------------------------------------------------------------- 1 | # (c) DevOpsHQ, 2020 2 | 3 | # --- Example template 1: existing project ---------------------------- 4 | 5 | include: https://gitlab..com//-/raw///existing_project.yml 6 | 7 | variables: 8 | PROJECT_LANG: python 9 | -------------------------------------------------------------------------------- /GitLab_templates/example_2.yml: -------------------------------------------------------------------------------- 1 | # (c) DevOpsHQ, 2020 2 | 3 | # --- Example template 2: non-existing project ------------------------ 4 | 5 | include: https://gitlab..com//-/raw///non-existing_project.yml 6 | 7 | variables: 8 | PROJECT_LANG: csharp 9 | -------------------------------------------------------------------------------- /GitLab_templates/existing_project.yml: -------------------------------------------------------------------------------- 1 | # (c) DevOpsHQ, 2020 2 | 3 | # This template is used for projects that were generated in advance. 4 | 5 | Start AIE scan: 6 | image: [your-repo]/aisa-linux:latest 7 | script: 8 | - aisa --version 9 | - aisa 10 | --project-name $CI_PROJECT_PATH_SLUG 11 | --scan-target ./ 12 | --reports "HTML,JSON" 13 | --reports-folder ".report" 14 | allow_failure: true 15 | artifacts: 16 | expire_in: 3 day 17 | paths: 18 | - .report/ 19 | -------------------------------------------------------------------------------- /GitLab_templates/no-wait-existing_project.yml: -------------------------------------------------------------------------------- 1 | # (c) DevOpsHQ, 2020 2 | 3 | # This template is used for projects that were generated in advance with "no wait" mode. 4 | 5 | 6 | No-wait AIE scanning without aiproj: 7 | image: [your-repo]/aisa-linux:latest 8 | script: 9 | - aisa --version 10 | - aisa 11 | --project-name $CI_PROJECT_PATH_SLUG 12 | --scan-target ./ 13 | --no-wait 14 | allow_failure: true -------------------------------------------------------------------------------- /GitLab_templates/no-wait-non-existent_project.yml: -------------------------------------------------------------------------------- 1 | # (c) DevOpsHQ, 2020 2 | 3 | # This template is used for projects that were not generated in advance with "no wait" mode. 4 | 5 | No-wait AIE scanning with aiproj: 6 | image: [your-repo]/aisa-linux:latest 7 | before_script: 8 | - aisa-set-settings 9 | --projectname $CI_PROJECT_PATH_SLUG 10 | --language $PROJECT_LANG 11 | script: 12 | - aisa --version 13 | - aisa 14 | --project-settings-file $CI_PROJECT_PATH_SLUG.aiproj 15 | --scan-target ./ 16 | --no-wait 17 | allow_failure: true 18 | only: 19 | variables: 20 | - $PROJECT_LANG -------------------------------------------------------------------------------- /GitLab_templates/non-existent_project.yml: -------------------------------------------------------------------------------- 1 | # (c) DevOpsHQ, 2020 2 | 3 | # This template is used for projects that were not generated in advance. 4 | 5 | Start AIE scan: 6 | image: [your-repo]/aisa-linux:latest 7 | before_script: 8 | - aisa-set-settings 9 | --projectname $CI_PROJECT_PATH_SLUG 10 | --language $PROJECT_LANG 11 | script: 12 | - aisa --version 13 | - aisa 14 | --project-settings-file $CI_PROJECT_PATH_SLUG.aiproj 15 | --scan-target ./ 16 | --reports "HTML,JSON" 17 | --reports-folder ".report" 18 | allow_failure: true 19 | only: 20 | variables: 21 | - $PROJECT_LANG 22 | artifacts: 23 | expire_in: 14 day 24 | paths: 25 | - .report/ 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Open DevOps Community 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /TeamCity_meta-runners/MetaRunnerAisaRunLinux.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Meta-runner for run Application Inspector Shell Agent in Linux Docker. 4 | 5 | 6 | 8 | 10 | 12 | 14 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | '/home/src/dockerTaskScript_exitcode' 197 | """.format(**vars()) 198 | 199 | print('Docker wrapper: {}'.format(docker_wrapper)) 200 | 201 | # write content to wrapper file 202 | with open(tc_checkout_dir + '/docker_wrapper.sh', 'w') as output: 203 | output.write(docker_wrapper) 204 | 205 | teamcity_close_block("Aisa: Prepare container") 206 | 207 | teamcity_open_block("Aisa: Scan project") 208 | 209 | container.start() 210 | 211 | print("\nContainer {} has started, reading the log ...".format(container.name)) 212 | 213 | # Print output 214 | for line in container.logs(stream=True, follow=True): 215 | print(line.strip().decode("utf-8")) 216 | 217 | with open(tc_checkout_dir + '/dockerTaskScript_exitcode', 'r') as file: 218 | exit_code = file.read().strip() 219 | 220 | if exit_code: 221 | if int(exit_code) == 0: 222 | msg = "Script return code {}".format(exit_code) 223 | teamcity_add_custom_status_and_message(msg) 224 | else: 225 | msg = "Script return code {}".format(exit_code) 226 | teamcity_add_custom_status_and_message(msg) 227 | exit_with_error(exit_code, msg) 228 | 229 | teamcity_close_block("Aisa: Scan project") 230 | 231 | except docker.errors.ImageNotFound: # as err: 232 | print("\n[ERROR]: Image does not exist.") # .format(err) 233 | sys.exit(10) 234 | 235 | except docker.errors.APIError as err: 236 | print("\n[ERROR]: Some error occurred: {}".format(err)) 237 | sys.exit(11) 238 | finally: 239 | 240 | teamcity_open_block("Aisa: After tasks") 241 | fix_owner(dirs_for_chown) 242 | 243 | # Remove container 244 | try: 245 | container.remove() 246 | print("\n[INFO]: Container {} was successfully removed".format(container.name)) 247 | 248 | except docker.errors.APIError as err: 249 | print("\n[ERROR]: Some error occurred while you delete the container: {}".format(err)) 250 | sys.exit(1) 251 | 252 | teamcity_close_block("Aisa: After tasks") 253 | teamcity_close_block( 254 | "Aisa running".format(**locals())) 255 | 256 | 257 | if __name__ == "__main__": 258 | init_logging() 259 | docker_run('%devops_aisa_docker_user%', 260 | '%devops_aisa_docker_passwd%', 261 | '%devops_aisa_docker_registry%', 262 | '%devops_aisa_docker_image_name%', 263 | '%devops_aisa_arguments%', 264 | '%teamcity.build.checkoutDir%') 265 | #]]> 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | -------------------------------------------------------------------------------- /TeamCity_meta-runners/MetaRunnerAisaRunWindows.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Meta-runner for run Application Inspector Shell Agent in Windows Docker. 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | {build_dir}\dockerTaskScript_exitcode 115 | cd /D {build_dir} 116 | echo -------------------------------------- 117 | echo Aisa version: 118 | aisa --version 119 | echo -------------------------------------- 120 | echo aisa {arguments} 121 | aisa {arguments} 122 | echo %errorlevel% > {build_dir}\dockerTaskScript_exitcode 123 | '''.format(**vars()) 124 | 125 | # write content to wrapper file 126 | with open('docker_wrapper.cmd', 'w') as output: 127 | output.write(docker_wrapper) 128 | # ------ END prepare ------ 129 | 130 | # ------ Check image exist ----- 131 | check_cmd = r'docker images --format "{{.Repository}}:{{.Tag}}"'.split() 132 | data = None 133 | try: 134 | process = subprocess.Popen(check_cmd, stdout=subprocess.PIPE) 135 | data = process.communicate() 136 | except Exception as err: 137 | msg = 'Some error occred while checking image: {}'.format(err) 138 | teamcity_add_custom_status_and_message(msg, msg) 139 | exit_with_error(10, msg) 140 | 141 | image_list = data[0].decode().replace('"', '').splitlines() 142 | image_with_tag = '{aisa_docker_registry}/{docker_image_name}'.format(**locals()) 143 | if image_with_tag not in image_list: 144 | msg = 'Docker image {docker_image_name} not found. '.format(**locals()) 145 | teamcity_add_custom_status_and_message(msg, msg) 146 | exit_with_error(10, msg) 147 | # ------ END Check image exist ----- 148 | 149 | # ------ START run docker ------ 150 | mount_cmd = "".join("-v {}:{} ".format(tc_checkout_dir, build_dir)) 151 | environment_variables = "-e TEAMCITY_VERSION -e TEAMCITY_BUILDCONF_NAME -e TEAMCITY_PROJECT_NAME" 152 | cmd = r"docker run --rm {mount_cmd} {environment_variables} -i {docker_image_full_name} " \ 153 | r"cmd /c {build_dir}\docker_wrapper.cmd".format(**locals()).split() 154 | 155 | print("DEBUG - command to execute: '{}'".format(" ".join(cmd))) 156 | call(cmd) 157 | # ------ END run docker ------ 158 | 159 | # ------ START check exit code ------ 160 | exitcode_filepath = tc_checkout_dir + '/dockerTaskScript_exitcode' 161 | 162 | if not os.path.isfile(exitcode_filepath): 163 | msg = "Some error when run docker {}".format(docker_image_full_name) 164 | teamcity_add_custom_status_and_message(msg, msg) 165 | exit_with_error(1000, msg) 166 | 167 | with open(exitcode_filepath, 'r') as file: 168 | exit_str = str(file.read().strip()) 169 | if exit_str != "": 170 | exit_code = int(exit_str) 171 | else: 172 | print('Exit code at file not found. Set it to 1') 173 | exit_code = 1 174 | 175 | print("Script EXITCODE='{}'".format(exit_code)) 176 | 177 | if exit_code: 178 | msg = "Script return code {}".format(exit_code) 179 | print('ERROR - {}'.format(msg)) 180 | teamcity_add_custom_status_and_message(msg) 181 | exit_with_error(exit_code, msg) 182 | # ------ END check exit code ------ 183 | 184 | teamcity_close_block("Run the container") 185 | 186 | 187 | if __name__ == "__main__": 188 | docker_run('%devops_aisa_docker_user%', 189 | '%devops_aisa_docker_passwd%', 190 | '%devops_aisa_docker_registry%', 191 | '%devops_aisa_docker_image_name%', 192 | '%devops_aisa_arguments%', 193 | '%teamcity.agent.work.dir%', 194 | '%teamcity.build.default.checkoutDir%') 195 | """ 196 | import sys 197 | 198 | fileName = r"%teamcity.build.checkoutDir%\_meta_runner_wrapper.py" 199 | 200 | print("Custom script redirecting to file {}".format(fileName)) 201 | 202 | with open(fileName, "w") as fH: 203 | fH.write(script)]]> 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | --------------------------------------------------------------------------------