@yasg1988/ru-software-registry-skill 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,18 @@
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ https://www.apache.org/licenses/
4
+
5
+ Copyright 2026 Yakunin Sergey
6
+
7
+ Licensed under the Apache License, Version 2.0 (the "License");
8
+ you may not use this file except in compliance with the License.
9
+ You may obtain a copy of the License at
10
+
11
+ https://www.apache.org/licenses/LICENSE-2.0
12
+
13
+ Unless required by applicable law or agreed to in writing, software
14
+ distributed under the License is distributed on an "AS IS" BASIS,
15
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ See the License for the specific language governing permissions and
17
+ limitations under the License.
18
+
package/README.md ADDED
@@ -0,0 +1,62 @@
1
+ # Skill для подачи ПО в реестр российского ПО
2
+
3
+ ![Подача заявления в реестр отечественного ПО](assets/cover.svg)
4
+
5
+ [![npm version](https://img.shields.io/npm/v/@yasg1988/ru-software-registry-skill?style=for-the-badge&logo=npm&color=cb3837)](https://www.npmjs.com/package/@yasg1988/ru-software-registry-skill)
6
+ [![GitHub release](https://img.shields.io/github/v/release/yasg1988/ru-software-registry-skill?style=for-the-badge&logo=github)](https://github.com/yasg1988/ru-software-registry-skill/releases)
7
+ [![License](https://img.shields.io/github/license/yasg1988/ru-software-registry-skill?style=for-the-badge)](LICENSE)
8
+ [![Codex Skill](https://img.shields.io/badge/Codex-Skill-111827?style=for-the-badge)](skills/ru-software-registry/SKILL.md)
9
+
10
+ Этот репозиторий содержит skill для Codex, который помогает подготовить проект к подаче в реестр российского ПО Минцифры: проверить готовность продукта, собрать пакет документов, подготовить локальные данные правообладателя и провести заявку через портал до этапа подписи.
11
+
12
+ ## Что делает skill
13
+
14
+ - Проверяет проект на готовность к подаче: README, лицензия, версии, релизы, публичные репозитории, Docker/npm, инструкции, отсутствие секретов.
15
+ - Создает рабочую папку `registry_ru/` внутри проекта и складывает туда документы заявки.
16
+ - Генерирует шаблоны документов: описание функционала, инструкция установки, инструкция администратора, инструкция пользователя, жизненный цикл, технические средства хранения и сборки, протокол совместимости, декларации.
17
+ - Использует локальный файл с данными правообладателя, чтобы не спрашивать одно и то же каждый раз.
18
+ - Ведет заполнение заявки через браузер, но финальную подпись и отправку оставляет пользователю.
19
+
20
+ ## Установка
21
+
22
+ ```powershell
23
+ npm install -g @yasg1988/ru-software-registry-skill
24
+ install-ru-software-registry-skill
25
+ ```
26
+
27
+ После установки skill будет скопирован в:
28
+
29
+ ```text
30
+ %USERPROFILE%\.codex\skills\ru-software-registry
31
+ ```
32
+
33
+ ## Локальные данные правообладателя
34
+
35
+ В репозитории есть только безопасный шаблон:
36
+
37
+ ```text
38
+ data/applicant.example.json
39
+ ```
40
+
41
+ Скопируйте его в локальный файл:
42
+
43
+ ```powershell
44
+ Copy-Item data\applicant.example.json data\applicant.local.json
45
+ ```
46
+
47
+ Файл `data/applicant.local.json` добавлен в `.gitignore` и не должен попадать в публичный репозиторий. В него можно положить ИНН, ОГРН/ОГРНИП, адрес, контакты, сведения о поддержке и хостинге.
48
+
49
+ ## Как пользоваться
50
+
51
+ Откройте Codex в папке проекта и напишите:
52
+
53
+ ```text
54
+ Давай подадим этот продукт в реестр российского ПО.
55
+ ```
56
+
57
+ Codex должен включить skill `ru-software-registry`, проверить проект, создать папку `registry_ru/`, подготовить документы и сказать, каких данных не хватает для заявки.
58
+
59
+ ## Важное ограничение
60
+
61
+ Skill не заменяет юридическую экспертизу и не выполняет юридически значимую отправку без участия пользователя. Подписание КЭП, подтверждение данных и финальная отправка заявки выполняются правообладателем.
62
+
@@ -0,0 +1,73 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="1600" height="900" viewBox="0 0 1600 900" role="img" aria-label="Подача заявления для включения в реестр отечественного ПО">
2
+ <defs>
3
+ <linearGradient id="bg" x1="0" x2="1" y1="0" y2="1">
4
+ <stop offset="0" stop-color="#f8fbff"/>
5
+ <stop offset="0.55" stop-color="#dcecff"/>
6
+ <stop offset="1" stop-color="#9fc7fb"/>
7
+ </linearGradient>
8
+ <linearGradient id="blue" x1="0" x2="1">
9
+ <stop offset="0" stop-color="#0b4fbd"/>
10
+ <stop offset="1" stop-color="#1f7cf3"/>
11
+ </linearGradient>
12
+ <filter id="shadow" x="-20%" y="-20%" width="140%" height="140%">
13
+ <feDropShadow dx="0" dy="18" stdDeviation="18" flood-color="#0b2f67" flood-opacity=".25"/>
14
+ </filter>
15
+ </defs>
16
+ <rect width="1600" height="900" fill="url(#bg)"/>
17
+ <g opacity=".25" fill="#ffffff">
18
+ <circle cx="980" cy="120" r="4"/><circle cx="1010" cy="120" r="4"/><circle cx="1040" cy="120" r="4"/>
19
+ <circle cx="950" cy="150" r="4"/><circle cx="980" cy="150" r="4"/><circle cx="1010" cy="150" r="4"/><circle cx="1040" cy="150" r="4"/><circle cx="1070" cy="150" r="4"/>
20
+ <circle cx="920" cy="180" r="4"/><circle cx="950" cy="180" r="4"/><circle cx="980" cy="180" r="4"/><circle cx="1010" cy="180" r="4"/><circle cx="1040" cy="180" r="4"/><circle cx="1070" cy="180" r="4"/><circle cx="1100" cy="180" r="4"/>
21
+ <circle cx="890" cy="210" r="4"/><circle cx="920" cy="210" r="4"/><circle cx="950" cy="210" r="4"/><circle cx="980" cy="210" r="4"/><circle cx="1010" cy="210" r="4"/><circle cx="1040" cy="210" r="4"/><circle cx="1070" cy="210" r="4"/><circle cx="1100" cy="210" r="4"/><circle cx="1130" cy="210" r="4"/>
22
+ <circle cx="1170" cy="165" r="4"/><circle cx="1200" cy="165" r="4"/><circle cx="1230" cy="165" r="4"/>
23
+ <circle cx="1170" cy="195" r="4"/><circle cx="1200" cy="195" r="4"/><circle cx="1230" cy="195" r="4"/><circle cx="1260" cy="195" r="4"/>
24
+ <circle cx="1290" cy="225" r="4"/><circle cx="1320" cy="225" r="4"/><circle cx="1350" cy="225" r="4"/><circle cx="1380" cy="225" r="4"/>
25
+ </g>
26
+ <g transform="translate(76 80)">
27
+ <rect width="120" height="120" rx="18" fill="url(#blue)"/>
28
+ <text x="60" y="73" text-anchor="middle" font-family="Arial, sans-serif" font-weight="700" font-size="52" fill="#fff">РФ</text>
29
+ <text x="150" y="55" font-family="Arial, sans-serif" font-weight="700" font-size="26" fill="#1554b7">МИНЦИФРЫ</text>
30
+ <text x="150" y="89" font-family="Arial, sans-serif" font-weight="700" font-size="26" fill="#1554b7">РОССИИ</text>
31
+ </g>
32
+ <g transform="translate(78 260)">
33
+ <text font-family="Arial, sans-serif" font-weight="800" font-size="70" fill="#082e66">Подача заявления</text>
34
+ <text y="92" font-family="Arial, sans-serif" font-weight="800" font-size="70" fill="#082e66">для включения</text>
35
+ <text y="184" font-family="Arial, sans-serif" font-weight="800" font-size="70" fill="#082e66">в реестр отечественного ПО</text>
36
+ <rect y="230" width="4" height="130" fill="#1f6ed5"/>
37
+ <text x="28" y="260" font-family="Arial, sans-serif" font-size="31" fill="#1d5bbd">Официальный процесс включения</text>
38
+ <text x="28" y="304" font-family="Arial, sans-serif" font-size="31" fill="#1d5bbd">программного обеспечения</text>
39
+ <text x="28" y="348" font-family="Arial, sans-serif" font-size="31" fill="#1d5bbd">в Реестр российского ПО</text>
40
+ </g>
41
+ <g transform="translate(970 166) rotate(6)" filter="url(#shadow)">
42
+ <rect width="500" height="330" rx="18" fill="#111827"/>
43
+ <rect x="18" y="18" width="464" height="294" rx="8" fill="#ffffff"/>
44
+ <rect x="18" y="18" width="464" height="70" rx="8" fill="#123f78"/>
45
+ <text x="42" y="62" font-family="Arial, sans-serif" font-weight="700" font-size="25" fill="#fff">Минцифры России</text>
46
+ <text x="70" y="145" font-family="Arial, sans-serif" font-weight="700" font-size="34" fill="#1f2937">Реестр программного</text>
47
+ <text x="70" y="187" font-family="Arial, sans-serif" font-weight="700" font-size="34" fill="#1f2937">обеспечения</text>
48
+ <rect x="72" y="220" width="170" height="44" rx="6" fill="#1266d6"/>
49
+ <text x="157" y="249" text-anchor="middle" font-family="Arial, sans-serif" font-weight="700" font-size="16" fill="#fff">Подать заявление</text>
50
+ </g>
51
+ <g transform="translate(910 610) rotate(-5)" filter="url(#shadow)">
52
+ <rect x="18" y="28" width="360" height="210" rx="8" fill="#d6e6fb"/>
53
+ <rect width="360" height="210" rx="8" fill="#ffffff"/>
54
+ <text x="180" y="52" text-anchor="middle" font-family="Arial, sans-serif" font-weight="800" font-size="24" fill="#092f68">ЗАЯВЛЕНИЕ</text>
55
+ <text x="180" y="83" text-anchor="middle" font-family="Arial, sans-serif" font-size="16" fill="#092f68">на включение программного обеспечения</text>
56
+ <g stroke="#1d5bbd" stroke-width="2" fill="none">
57
+ <rect x="42" y="110" width="18" height="18"/><line x1="78" y1="120" x2="300" y2="120"/>
58
+ <rect x="42" y="146" width="18" height="18"/><line x1="78" y1="156" x2="300" y2="156"/>
59
+ <rect x="42" y="182" width="18" height="18"/><line x1="78" y1="192" x2="300" y2="192"/>
60
+ </g>
61
+ </g>
62
+ <g transform="translate(780 640)" filter="url(#shadow)">
63
+ <path d="M90 0 L170 28 V98 C170 170 125 216 90 232 C55 216 10 170 10 98 V28 Z" fill="url(#blue)"/>
64
+ <path d="M52 110 L80 138 L134 70" fill="none" stroke="#fff" stroke-width="18" stroke-linecap="round" stroke-linejoin="round"/>
65
+ </g>
66
+ <g transform="translate(85 735)" fill="#0e4ba7" font-family="Arial, sans-serif">
67
+ <g><circle cx="52" cy="30" r="34" fill="none" stroke="#0e4ba7" stroke-width="4"/><path d="M35 30 l13 13 l24 -30" fill="none" stroke="#0e4ba7" stroke-width="5"/><text x="0" y="95" font-weight="700" font-size="18">СООТВЕТСТВИЕ</text><text x="0" y="120" font-weight="700" font-size="18">ТРЕБОВАНИЯМ</text></g>
68
+ <g transform="translate(260 0)"><rect x="20" y="0" width="64" height="76" rx="7" fill="none" stroke="#0e4ba7" stroke-width="4"/><path d="M38 26 h28 M38 44 h28" stroke="#0e4ba7" stroke-width="4"/><circle cx="88" cy="70" r="20" fill="#eaf3ff" stroke="#0e4ba7" stroke-width="4"/><path d="M78 70 l8 8 l14 -20" fill="none" stroke="#0e4ba7" stroke-width="4"/><text x="0" y="120" font-weight="700" font-size="18">ПАКЕТ ДОКУМЕНТОВ</text></g>
69
+ <g transform="translate(545 0)"><path d="M48 78 V25 M28 45 L48 25 L68 45" fill="none" stroke="#0e4ba7" stroke-width="5" stroke-linecap="round"/><path d="M18 78 h76" stroke="#0e4ba7" stroke-width="5"/><text x="-20" y="120" font-weight="700" font-size="18">ПОДАЧА ЧЕРЕЗ ПОРТАЛ</text></g>
70
+ <g transform="translate(825 0)"><circle cx="52" cy="38" r="38" fill="none" stroke="#0e4ba7" stroke-width="4"/><path d="M32 38 l14 14 l28 -34" fill="none" stroke="#0e4ba7" stroke-width="5"/><text x="-10" y="120" font-weight="700" font-size="18">ВКЛЮЧЕНИЕ В РЕЕСТР</text></g>
71
+ </g>
72
+ </svg>
73
+
package/bin/install.js ADDED
@@ -0,0 +1,31 @@
1
+ #!/usr/bin/env node
2
+ const fs = require("fs");
3
+ const os = require("os");
4
+ const path = require("path");
5
+
6
+ const root = path.resolve(__dirname, "..");
7
+ const source = path.join(root, "skills", "ru-software-registry");
8
+ const targetBase = process.env.CODEX_HOME
9
+ ? path.join(process.env.CODEX_HOME, "skills")
10
+ : path.join(os.homedir(), ".codex", "skills");
11
+ const target = path.join(targetBase, "ru-software-registry");
12
+
13
+ function copyDir(src, dest) {
14
+ fs.mkdirSync(dest, { recursive: true });
15
+ for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
16
+ const from = path.join(src, entry.name);
17
+ const to = path.join(dest, entry.name);
18
+ if (entry.isDirectory()) copyDir(from, to);
19
+ else fs.copyFileSync(from, to);
20
+ }
21
+ }
22
+
23
+ if (!fs.existsSync(source)) {
24
+ console.error(`Skill source not found: ${source}`);
25
+ process.exit(1);
26
+ }
27
+
28
+ fs.rmSync(target, { recursive: true, force: true });
29
+ copyDir(source, target);
30
+ console.log(`Installed ru-software-registry skill to ${target}`);
31
+
@@ -0,0 +1,31 @@
1
+ {
2
+ "rightsholder_type": "individual_entrepreneur",
3
+ "rightsholder_name": "ИП Фамилия Имя Отчество",
4
+ "full_name": "Фамилия Имя Отчество",
5
+ "inn": "000000000000",
6
+ "ogrnip": "000000000000000",
7
+ "registration_date": "ДД.ММ.ГГГГ",
8
+ "legal_address": "Индекс, субъект РФ, город, улица, дом, офис/квартира",
9
+ "actual_address": "Индекс, субъект РФ, город, улица, дом, офис/квартира",
10
+ "phone": "+7 000 000-00-00",
11
+ "email": "support@example.ru",
12
+ "support": {
13
+ "email": "support@example.ru",
14
+ "phone": "+7 000 000-00-00",
15
+ "messenger": "MAX/Telegram/другое",
16
+ "response_time": "1-3 рабочих дня",
17
+ "provided_by": "Правообладатель лично"
18
+ },
19
+ "hosting": {
20
+ "provider": "Российский хостинг-провайдер",
21
+ "country": "Россия",
22
+ "city": "Санкт-Петербург",
23
+ "server_ip": "0.0.0.0"
24
+ },
25
+ "foreign_payments": {
26
+ "year": "2025",
27
+ "amount_rub": "0.00",
28
+ "revenue_rub": "0.00"
29
+ }
30
+ }
31
+
package/package.json ADDED
@@ -0,0 +1,43 @@
1
+ {
2
+ "name": "@yasg1988/ru-software-registry-skill",
3
+ "version": "0.1.2",
4
+ "description": "Skill Codex для подготовки проекта и заявки в реестр российского ПО Минцифры.",
5
+ "type": "commonjs",
6
+ "license": "Apache-2.0",
7
+ "author": "yasg1988",
8
+ "homepage": "https://github.com/yasg1988/ru-software-registry-skill#readme",
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "git+https://github.com/yasg1988/ru-software-registry-skill.git"
12
+ },
13
+ "bugs": {
14
+ "url": "https://github.com/yasg1988/ru-software-registry-skill/issues"
15
+ },
16
+ "keywords": [
17
+ "codex",
18
+ "skill",
19
+ "минцифры",
20
+ "реестр-по",
21
+ "российское-по",
22
+ "документы"
23
+ ],
24
+ "files": [
25
+ "README.md",
26
+ "LICENSE",
27
+ "bin/",
28
+ "skills/",
29
+ "data/applicant.example.json",
30
+ "assets/"
31
+ ],
32
+ "bin": {
33
+ "install-ru-software-registry-skill": "bin/install.js"
34
+ },
35
+ "scripts": {
36
+ "install-skill": "node bin/install.js",
37
+ "validate": "python ./tools/validate_skill.py",
38
+ "audit": "python ./skills/ru-software-registry/scripts/audit_project.py ."
39
+ },
40
+ "publishConfig": {
41
+ "access": "public"
42
+ }
43
+ }
@@ -0,0 +1,116 @@
1
+ ---
2
+ name: ru-software-registry
3
+ description: "Подготовка продукта к подаче в реестр российского ПО Минцифры и сопровождение заявки через портал. Use when the user asks in Russian or by meaning: подать в реестр отечественного ПО, подготовить документы для Минцифры, проверить готовность к реестру российского ПО, оформить заявку в реестр ПО, собрать пакет документов для реестра, including projects that need README/license/releases/GitVerse/npm/Docker checks, PDF/DOCX document package, and browser-based portal filling."
4
+ ---
5
+
6
+ # Реестр российского ПО
7
+
8
+ ## Рабочий принцип
9
+
10
+ Вести проект от технической проверки до готовой заявки. Не выполнять юридически значимые действия без пользователя: финальная отправка, подписание КЭП и подтверждение сведений остаются за правообладателем.
11
+
12
+ Всегда работать в папке текущего продукта. Создавать отдельную рабочую папку `registry_ru/` в корне продукта и добавлять ее в `.gitignore`, если пользователь явно не просит коммитить документы.
13
+
14
+ ## Быстрый старт
15
+
16
+ 1. Проверить проект:
17
+
18
+ ```powershell
19
+ python <skill>/scripts/audit_project.py .
20
+ ```
21
+
22
+ 2. Найти локальные данные правообладателя:
23
+
24
+ - сначала `data/applicant.local.json` в репозитории skill;
25
+ - затем `%USERPROFILE%\.codex\ru-software-registry\applicant.local.json`;
26
+ - если данных нет, попросить заполнить только недостающее.
27
+
28
+ 3. Создать пакет документов:
29
+
30
+ ```powershell
31
+ python <skill>/scripts/generate_registry_docs.py --project . --profile <path-to-applicant.local.json>
32
+ ```
33
+
34
+ 4. Проверить документы, ссылки и вложения. Для PDF/DOCX использовать доступные локальные инструменты проекта или Documents skill, если пользователь просит финальные файлы.
35
+
36
+ 5. Через Browser открыть `https://reestr.digital.gov.ru/`, дождаться авторизации пользователя, заполнить заявку, прикрепить документы, остановиться перед финальной подписью/отправкой.
37
+
38
+ ## Порядок работы
39
+
40
+ ### 1. Аудит проекта
41
+
42
+ Проверить:
43
+
44
+ - `README.md` с понятным описанием продукта, установкой, эксплуатацией, поддержкой;
45
+ - `LICENSE`, желательно Apache-2.0/MIT/AGPL/GPL или иная открытая лицензия;
46
+ - `package.json`, `pyproject.toml`, `Dockerfile`, `docker-compose.yml` или другая воспроизводимая установка;
47
+ - публичный GitHub/GitVerse или российское зеркало исходников;
48
+ - релизы и теги версий;
49
+ - отсутствие секретов в репозитории;
50
+ - инструкции запуска, резервного копирования и обновления;
51
+ - сведения о хостинге в РФ, если продукт работает как сервис.
52
+
53
+ Если обнаружены токены, пароли, приватные ключи, `.env`, дампы БД или персональные данные, остановиться и предложить исправить до публикации.
54
+
55
+ ### 2. Классификация ПО
56
+
57
+ Не угадывать окончательно, но предлагать классы. Для чат-ботов и диалоговых сервисов обычно начинать с:
58
+
59
+ - `05.09 Средства управления диалоговыми роботами (чат-боты и голосовые роботы)`;
60
+ - дополнительный класс при необходимости: `06.02 Коммуникационное программное обеспечение`;
61
+ - ОКПД2 часто подходит: `62.01.29 Оригиналы программного обеспечения прочие`.
62
+
63
+ Перед подачей сверить актуальные классы с официальным порталом, потому что реестр и классификатор могут меняться.
64
+
65
+ ### 3. Документы
66
+
67
+ Минимальный пакет:
68
+
69
+ - карточка ПО;
70
+ - описание функциональных характеристик;
71
+ - инструкция по установке;
72
+ - инструкция администратора;
73
+ - инструкция пользователя;
74
+ - описание жизненного цикла;
75
+ - технические средства хранения исходного и объектного кода, средства сборки/компиляции;
76
+ - программа и методика испытаний;
77
+ - протокол совместимости с ОС;
78
+ - декларация о данных и приватности;
79
+ - декларация правообладателя;
80
+ - чеклист готовности.
81
+
82
+ Для подробного состава и формулировок читать `references/document-package.md`.
83
+
84
+ ### 4. Подача через портал
85
+
86
+ При заполнении портала:
87
+
88
+ - использовать официальные формулировки из документов;
89
+ - прикладывать PDF;
90
+ - адрес технических средств указывать по российскому хостингу/серверу;
91
+ - подтверждение сайта/прав можно закрывать декларацией правообладателя, но предупредить, что эксперт может запросить более сильное подтверждение;
92
+ - по иностранным выплатам указывать реальные значения и год, прикладывать подтверждение/декларацию.
93
+
94
+ Для карты полей читать `references/portal-workflow.md`.
95
+
96
+ ### 5. После подачи
97
+
98
+ Проверить статус в "Мои заявления". Нормальные ранние статусы: `Новое`, затем проверка комплектности и экспертное рассмотрение. Если пришел запрос на уточнение, готовить точечный ответ и новые PDF без переписывания всего пакета.
99
+
100
+ ## Локальные данные
101
+
102
+ Не коммитить реальные данные правообладателя. Допустимые публичные файлы: только `applicant.example.json` и обезличенные шаблоны.
103
+
104
+ Если профиль правообладателя найден, использовать его для автозаполнения документов. Если профиль отсутствует, спросить у пользователя:
105
+
106
+ - тип правообладателя;
107
+ - ФИО/название, ИНН, ОГРН/ОГРНИП;
108
+ - адрес;
109
+ - телефон, email, поддержка;
110
+ - сведения о хостинге;
111
+ - год и суммы выплат иностранным лицам;
112
+ - сайт продукта и ссылки на исходники/релизы.
113
+
114
+ ## Проверка актуальности
115
+
116
+ Правила, сроки, поля портала и требования Минцифры могут меняться. При подготовке реальной заявки использовать web/browser для проверки актуальных требований на официальных источниках и явно отделять факты из источников от рабочих предположений.
@@ -0,0 +1,4 @@
1
+ interface:
2
+ display_name: "������ ����������� ��"
3
+ short_description: "���������� ������� � ������ � ������ �������������� �� ��������."
4
+ default_prompt: "��������� ���� ������ � ������ � ������ ����������� ��: ������� ����������, ������ ��������� � ������� ������ �� ����� �������."
@@ -0,0 +1,65 @@
1
+ # Пакет документов
2
+
3
+ ## Карточка ПО
4
+
5
+ Содержит название, версию, правообладателя, сайт, репозитории, лицензию, модель распространения, классы ПО, ОКПД2, контакты поддержки и краткое описание.
6
+
7
+ ## Функциональное описание
8
+
9
+ Писать простым языком:
10
+
11
+ - назначение продукта;
12
+ - основные сценарии пользователей;
13
+ - роли;
14
+ - ограничения;
15
+ - что продукт не делает;
16
+ - какие данные обрабатывает или не обрабатывает.
17
+
18
+ ## Инструкция установки
19
+
20
+ Должна позволять эксперту воспроизвести запуск:
21
+
22
+ - требования к серверу;
23
+ - установка зависимостей;
24
+ - переменные окружения;
25
+ - запуск через Docker/npm/другой способ;
26
+ - проверка работоспособности;
27
+ - обновление версии;
28
+ - резервное копирование.
29
+
30
+ ## Инструкция администратора
31
+
32
+ Описать настройку, эксплуатацию, мониторинг, логи, резервное копирование, обновление, восстановление, управление доступами.
33
+
34
+ ## Инструкция пользователя
35
+
36
+ Описать роли и основные действия без технических деталей. Для чат-ботов описывать сценарии в мессенджере.
37
+
38
+ ## Жизненный цикл
39
+
40
+ Описать разработку, тестирование, релизы, сопровождение, исправления, поддержку, вывод версии из эксплуатации.
41
+
42
+ ## Технические средства хранения и сборки
43
+
44
+ Указать:
45
+
46
+ - основной репозиторий;
47
+ - российское зеркало или хранилище;
48
+ - сервер/хостинг в РФ;
49
+ - способ сборки;
50
+ - Docker/npm/CI, если есть;
51
+ - где хранится объектный код или контейнеры;
52
+ - адрес нахождения технических средств.
53
+
54
+ ## Испытания и совместимость
55
+
56
+ Описать методику проверки и фактически проверенные ОС/среды. Не утверждать проверку на ОС, если пользователь не подтвердил.
57
+
58
+ ## Данные и приватность
59
+
60
+ Если продукт не собирает ФИО, телефоны, адреса и другие прямые ПДн, писать осторожно:
61
+
62
+ > Программное обеспечение не запрашивает у пользователей ФИО, паспортные данные, адреса проживания, номера телефонов, платежные данные и иные сведения, позволяющие правообладателю самостоятельно идентифицировать физическое лицо. Технические идентификаторы платформы используются только для маршрутизации сообщений и обеспечения работы сервиса.
63
+
64
+ Если продукт обрабатывает ПДн, готовить отдельное описание обработки и основания.
65
+
@@ -0,0 +1,31 @@
1
+ # Портал reestr.digital.gov.ru
2
+
3
+ ## Общий порядок
4
+
5
+ 1. Открыть портал и дождаться авторизации пользователя через ЕСИА.
6
+ 2. Создать заявление на включение ПО.
7
+ 3. Заполнить карточку ПО и классы.
8
+ 4. Заполнить описание, сайт, репозитории, документы.
9
+ 5. Указать технические средства хранения и сборки.
10
+ 6. Указать правообладателя.
11
+ 7. Указать сведения об исключительных правах.
12
+ 8. Заполнить выплаты иностранным лицам.
13
+ 9. Указать гарантийную поддержку и сопровождение.
14
+ 10. Приложить чеклист.
15
+ 11. Остановиться перед финальной подписью и получить подтверждение пользователя.
16
+
17
+ ## Частые проблемные поля
18
+
19
+ - Документ, подтверждающий принадлежность сайта правообладателю.
20
+ - Документация по техническим средствам хранения исходного и объектного кода.
21
+ - Адрес нахождения технических средств.
22
+ - Подтверждающий документ адреса технических средств.
23
+ - Год выплат иностранным лицам.
24
+ - Документы, подтверждающие сумму выплат.
25
+
26
+ ## Практические решения
27
+
28
+ - Для сайта можно приложить декларацию правообладателя, но лучше иметь DNS/хостинг/договор/скриншот панели, если эксперт запросит.
29
+ - Для технических средств приложить отдельный документ с описанием репозиториев, CI, Docker/npm, сервера и адреса хостинга.
30
+ - Для нулевых выплат приложить декларацию о нулевых выплатах за указанный год.
31
+
@@ -0,0 +1,69 @@
1
+ #!/usr/bin/env python3
2
+ import json
3
+ import re
4
+ import sys
5
+ from pathlib import Path
6
+
7
+ SECRET_PATTERNS = [
8
+ re.compile(r"npm_[A-Za-z0-9]{20,}"),
9
+ re.compile(r"ghp_[A-Za-z0-9_]{20,}"),
10
+ re.compile(r"github_pat_[A-Za-z0-9_]{20,}"),
11
+ re.compile(r"dckr_pat_[A-Za-z0-9_-]{20,}"),
12
+ re.compile(r"-----BEGIN (RSA |OPENSSH |EC |DSA )?PRIVATE KEY-----"),
13
+ re.compile(r"(?i)(token|secret|password|passwd|api_key)\s*[:=]\s*['\"]?[A-Za-z0-9_\-]{16,}"),
14
+ ]
15
+
16
+ TEXT_EXT = {
17
+ ".md", ".txt", ".json", ".js", ".ts", ".py", ".yml", ".yaml", ".env",
18
+ ".example", ".toml", ".ini", ".ps1", ".sh", ".dockerfile"
19
+ }
20
+
21
+ def exists(root: Path, *names: str) -> bool:
22
+ return any((root / name).exists() for name in names)
23
+
24
+ def scan_secrets(root: Path):
25
+ findings = []
26
+ ignored = {"node_modules", ".git", "dist", "build", ".next", "vendor"}
27
+ for path in root.rglob("*"):
28
+ if any(part in ignored for part in path.parts):
29
+ continue
30
+ if not path.is_file():
31
+ continue
32
+ if path.suffix.lower() not in TEXT_EXT and path.name not in {"Dockerfile", ".env", ".gitignore"}:
33
+ continue
34
+ try:
35
+ text = path.read_text(encoding="utf-8", errors="ignore")
36
+ except OSError:
37
+ continue
38
+ for pattern in SECRET_PATTERNS:
39
+ for match in pattern.finditer(text):
40
+ line = text.count("\n", 0, match.start()) + 1
41
+ findings.append({"file": str(path.relative_to(root)), "line": line, "pattern": pattern.pattern})
42
+ return findings
43
+
44
+ def main():
45
+ root = Path(sys.argv[1] if len(sys.argv) > 1 else ".").resolve()
46
+ checks = {
47
+ "readme": exists(root, "README.md", "README.ru.md"),
48
+ "license": exists(root, "LICENSE", "LICENSE.md"),
49
+ "package_json": exists(root, "package.json"),
50
+ "dockerfile": exists(root, "Dockerfile", "docker-compose.yml", "compose.yml"),
51
+ "gitignore": exists(root, ".gitignore"),
52
+ "github_workflows": (root / ".github" / "workflows").exists(),
53
+ }
54
+ secrets = scan_secrets(root)
55
+ result = {
56
+ "project": str(root),
57
+ "checks": checks,
58
+ "secret_findings": secrets,
59
+ "ready_score": sum(1 for ok in checks.values() if ok),
60
+ "ready_score_max": len(checks),
61
+ }
62
+ print(json.dumps(result, ensure_ascii=False, indent=2))
63
+ if secrets:
64
+ return 2
65
+ return 0
66
+
67
+ if __name__ == "__main__":
68
+ raise SystemExit(main())
69
+
@@ -0,0 +1,132 @@
1
+ #!/usr/bin/env python3
2
+ import argparse
3
+ import json
4
+ from datetime import date
5
+ from pathlib import Path
6
+
7
+ DOCS = {
8
+ "01_карточка_ПО.md": """# Карточка программного обеспечения
9
+
10
+ Название ПО: {software_name}
11
+
12
+ Версия: {version}
13
+
14
+ Правообладатель: {rightsholder_name}
15
+
16
+ Сайт продукта: {product_url}
17
+
18
+ Репозиторий исходного кода: {source_repo}
19
+
20
+ Лицензия: {license}
21
+
22
+ Модель распространения: {distribution}
23
+
24
+ Краткое описание: {short_description}
25
+ """,
26
+ "02_описание_функциональных_характеристик.md": """# Описание функциональных характеристик
27
+
28
+ {software_name} предназначено для {purpose}.
29
+
30
+ Основные функции:
31
+
32
+ - {feature_1}
33
+ - {feature_2}
34
+ - {feature_3}
35
+
36
+ ПО распространяется {distribution}. Поддержка оказывается: {support}.
37
+ """,
38
+ "03_инструкция_по_установке.md": """# Инструкция по установке
39
+
40
+ ## Требования
41
+
42
+ - Сервер или виртуальная машина под управлением Linux/совместимой ОС.
43
+ - Доступ к исходному коду: {source_repo}.
44
+ - Переменные окружения и секреты задаются вне репозитория.
45
+
46
+ ## Установка
47
+
48
+ 1. Получить исходный код.
49
+ 2. Установить зависимости согласно README проекта.
50
+ 3. Заполнить переменные окружения.
51
+ 4. Запустить приложение штатным способом проекта.
52
+ 5. Проверить доступность сервиса.
53
+ """,
54
+ "06_описание_жизненного_цикла.md": """# Описание жизненного цикла
55
+
56
+ Разработка ведется правообладателем. Изменения фиксируются в системе контроля версий. Релизы маркируются тегами версий.
57
+
58
+ Сопровождение включает исправление ошибок, обновление зависимостей, выпуск новых версий, поддержку пользователей и восстановление работоспособности при сбоях.
59
+ """,
60
+ "07_технические_средства_хранения_и_сборки.md": """# Технические средства хранения и сборки
61
+
62
+ Исходный код хранится: {source_repo}.
63
+
64
+ Технические средства размещены: {hosting_provider}, {hosting_country}, {hosting_city}, сервер {server_ip}.
65
+
66
+ Сборка и развертывание выполняются средствами проекта. Секреты и эксплуатационные настройки хранятся отдельно от исходного кода.
67
+ """,
68
+ "11_декларация_о_данных_и_приватности.md": """# Декларация о данных и приватности
69
+
70
+ ПО не запрашивает у пользователей ФИО, паспортные данные, адреса проживания, номера телефонов, платежные данные и иные сведения, позволяющие правообладателю самостоятельно идентифицировать физическое лицо.
71
+
72
+ Технические идентификаторы платформы используются только для маршрутизации сообщений и обеспечения работы сервиса.
73
+ """,
74
+ "13_декларация_правообладателя.md": """# Декларация правообладателя
75
+
76
+ {rightsholder_name} подтверждает наличие исключительных прав на программное обеспечение {software_name}.
77
+
78
+ ПО создано самостоятельно, распространяется на условиях лицензии {license}, доступно пользователям {distribution}.
79
+
80
+ Дата формирования документа: {today}.
81
+ """,
82
+ }
83
+
84
+ def load_json(path: Path):
85
+ if not path or not path.exists():
86
+ return {}
87
+ return json.loads(path.read_text(encoding="utf-8"))
88
+
89
+ def main():
90
+ parser = argparse.ArgumentParser()
91
+ parser.add_argument("--project", default=".")
92
+ parser.add_argument("--profile", default="")
93
+ parser.add_argument("--out", default="registry_ru")
94
+ parser.add_argument("--software-name", default="")
95
+ args = parser.parse_args()
96
+
97
+ project = Path(args.project).resolve()
98
+ profile = load_json(Path(args.profile)) if args.profile else {}
99
+ package_json = load_json(project / "package.json") if (project / "package.json").exists() else {}
100
+ support = profile.get("support", {})
101
+ hosting = profile.get("hosting", {})
102
+
103
+ values = {
104
+ "software_name": args.software_name or package_json.get("name", project.name),
105
+ "version": package_json.get("version", "указать версию"),
106
+ "rightsholder_name": profile.get("rightsholder_name", "указать правообладателя"),
107
+ "product_url": package_json.get("homepage", "указать сайт продукта"),
108
+ "source_repo": package_json.get("repository", {}).get("url", "указать репозиторий") if isinstance(package_json.get("repository"), dict) else package_json.get("repository", "указать репозиторий"),
109
+ "license": package_json.get("license", "указать лицензию"),
110
+ "distribution": "бесплатно / open source",
111
+ "short_description": package_json.get("description", "указать краткое описание"),
112
+ "purpose": "решения пользовательских задач, описанных в README проекта",
113
+ "feature_1": "указать ключевую функцию",
114
+ "feature_2": "указать ключевую функцию",
115
+ "feature_3": "указать ключевую функцию",
116
+ "support": f"{support.get('provided_by', 'указать')} ({support.get('email', 'email не указан')}, регламент {support.get('response_time', 'не указан')})",
117
+ "hosting_provider": hosting.get("provider", "указать провайдера"),
118
+ "hosting_country": hosting.get("country", "Россия"),
119
+ "hosting_city": hosting.get("city", "указать город"),
120
+ "server_ip": hosting.get("server_ip", "указать IP"),
121
+ "today": date.today().strftime("%d.%m.%Y"),
122
+ }
123
+
124
+ out = project / args.out
125
+ out.mkdir(parents=True, exist_ok=True)
126
+ for name, template in DOCS.items():
127
+ (out / name).write_text(template.format(**values), encoding="utf-8")
128
+ print(f"Created {len(DOCS)} draft documents in {out}")
129
+
130
+ if __name__ == "__main__":
131
+ main()
132
+