docs(release): add readiness v0.2 hardening
This commit is contained in:
@@ -0,0 +1,29 @@
|
||||
name: release-assets
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "main" ]
|
||||
pull_request:
|
||||
branches: [ "main" ]
|
||||
|
||||
jobs:
|
||||
sbom-and-release-assets:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install stable Rust
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
|
||||
- name: Generate machine SBOM artifacts
|
||||
run: bash scripts/generate_release_sbom_v0_2.sh dist/release-v0.2
|
||||
|
||||
- name: Validate generated JSON artifacts
|
||||
run: |
|
||||
python3 -m json.tool dist/release-v0.2/sbom/cyclonedx-rust-v0.2.json >/dev/null
|
||||
python3 -m json.tool dist/release-v0.2/sbom/spdx-rust-v0.2.json >/dev/null
|
||||
python3 -m json.tool dist/release-v0.2/RELEASE_ASSETS_MANIFEST-v0.2.json >/dev/null
|
||||
|
||||
- name: Verify release asset checksum/signature script
|
||||
run: bash scripts/verify_release_assets.sh --self-test
|
||||
@@ -1,5 +1,24 @@
|
||||
# Журнал изменений
|
||||
|
||||
## release-readiness-v0.2 - 2026-06-03
|
||||
|
||||
Назначение этапа: усилить пакет для коммерческого релиза и реестра российского
|
||||
ПО за счет машинного SBOM, проверки release assets, пилотного акта приемки и
|
||||
корректного позиционирования pfSense.
|
||||
|
||||
### Добавлено
|
||||
|
||||
- `scripts/generate_release_sbom_v0_2.sh` - генерация CycloneDX/SPDX SBOM
|
||||
artifacts в `dist/release-v0.2/`.
|
||||
- `scripts/verify_release_assets.sh` - проверка `SHA256SUMS*.txt` и detached
|
||||
signature release assets.
|
||||
- `.github/workflows/release-assets.yml` - CI self-test checksum/signature
|
||||
verifier и генерации SBOM.
|
||||
- `docs/RELEASE_READINESS_V0.2_RU.md` - контрольная карта v0.2.
|
||||
- `docs/CUSTOMER_PILOT_ACCEPTANCE_RU.md` - шаблон акта приемки пилота.
|
||||
- `docs/NETWORK_PERIMETER_PFSENSE_RU.md` - pfSense как опциональный
|
||||
интеграционный слой, не обязательная часть продукта.
|
||||
|
||||
## release-readiness-v0.1 - 2026-06-03
|
||||
|
||||
Назначение этапа: довести DetMir/AWatch-rus до проверяемого release-readiness
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
# Акт приемки пилота DetMir
|
||||
|
||||
Документ-шаблон для коммерческого пилота DetMir/AWatch-rus. Перед передачей
|
||||
заказчику заполнить реквизиты сторон, даты, состав стенда и результаты
|
||||
проверок. Публичная версия не должна содержать live IP, домены, ФИО
|
||||
сотрудников, case IDs, evidence paths или screenshots с реальными данными.
|
||||
|
||||
## 1. Стороны
|
||||
|
||||
| Поле | Значение |
|
||||
|---|---|
|
||||
| Заказчик | `<CUSTOMER_LEGAL_NAME>` |
|
||||
| Исполнитель/правообладатель | `<RIGHT_HOLDER_LEGAL_NAME>` |
|
||||
| Проект | DetMir, программный комплекс AWatch-rus |
|
||||
| Период пилота | `<PILOT_START_DATE>` - `<PILOT_END_DATE>` |
|
||||
| Контур | `<PILOT_CONTOUR_NAME>` |
|
||||
|
||||
## 2. Цель пилота
|
||||
|
||||
Проверить применимость DetMir для:
|
||||
|
||||
- мониторинга активности рабочих мест;
|
||||
- управленческой аналитики Workforce;
|
||||
- технического аудита ИТ-контура;
|
||||
- фиксации DLP-lite/ИБ-событий;
|
||||
- просмотра evidence и отчетов в портале;
|
||||
- контроля готовности системы через signed readiness bundle.
|
||||
|
||||
## 3. Состав поставки
|
||||
|
||||
| Компонент | Проверка |
|
||||
|---|---|
|
||||
| DetMir portal | вход, роли оператора/руководителя/владельца |
|
||||
| ActivityWatch telemetry | актуальность bucket/event данных |
|
||||
| Workforce analytics | индекс активности, веса приложений, drill-down |
|
||||
| DLP-lite incidents | USB/print/clipboard/file/email/browser signals, если включены |
|
||||
| Evidence workflow | preview/download/view audit |
|
||||
| Grafana dashboards | наличие данных и отсутствие query errors |
|
||||
| Readiness bundle | checksum/signature/fingerprint |
|
||||
| Prometheus alerts | readiness/signature alerts настроены |
|
||||
|
||||
## 4. Критерии приемки
|
||||
|
||||
Пилот считается успешным, если:
|
||||
|
||||
- портал доступен ответственным пользователям заказчика;
|
||||
- telemetry freshness находится в согласованных пределах;
|
||||
- readiness status = `OK` или все `WARN` имеют согласованный план устранения;
|
||||
- signed readiness bundle проходит проверку;
|
||||
- не менее одного управленческого отчета сформировано и принято заказчиком;
|
||||
- не менее одного test incident/evidence workflow пройден end-to-end;
|
||||
- заказчик подтвердил, что состав данных и уведомлений соответствует правилам
|
||||
внутреннего контроля и локальным нормативным документам.
|
||||
|
||||
## 5. Результаты проверок
|
||||
|
||||
| Проверка | Результат | Комментарий |
|
||||
|---|---|---|
|
||||
| Portal login | `<OK/WARN/FAIL>` | `<COMMENT>` |
|
||||
| Readiness bundle | `<OK/WARN/FAIL>` | `<COMMENT>` |
|
||||
| Workforce report | `<OK/WARN/FAIL>` | `<COMMENT>` |
|
||||
| DLP-lite incident | `<OK/WARN/FAIL>` | `<COMMENT>` |
|
||||
| Evidence preview/download | `<OK/WARN/FAIL>` | `<COMMENT>` |
|
||||
| Grafana dashboards | `<OK/WARN/FAIL>` | `<COMMENT>` |
|
||||
| Alerting | `<OK/WARN/FAIL>` | `<COMMENT>` |
|
||||
|
||||
## 6. Ограничения пилота
|
||||
|
||||
- DetMir не заявляется как сертифицированная СЗИ, SIEM, EDR/XDR или
|
||||
enterprise DLP.
|
||||
- pfSense/network quarantine интеграции являются опциональным интеграционным
|
||||
слоем и не входят в обязательный состав пилота.
|
||||
- Telegram runtime может использоваться как интеграционный канал уведомлений,
|
||||
но не является ядром продукта.
|
||||
- Результаты Workforce analytics являются управленческими proxy-метриками и
|
||||
должны трактоваться с учетом ролей, весов приложений и локальных регламентов.
|
||||
|
||||
## 7. Решение
|
||||
|
||||
| Решение | Отметка |
|
||||
|---|---|
|
||||
| Пилот принят без замечаний | `<YES/NO>` |
|
||||
| Пилот принят с замечаниями | `<YES/NO>` |
|
||||
| Требуется доработка | `<YES/NO>` |
|
||||
| Рекомендуется коммерческое внедрение | `<YES/NO>` |
|
||||
|
||||
## 8. Подписи
|
||||
|
||||
| Сторона | ФИО/должность | Подпись | Дата |
|
||||
|---|---|---|---|
|
||||
| Заказчик | `<CUSTOMER_SIGNER>` | | |
|
||||
| Исполнитель | `<CONTRACTOR_SIGNER>` | | |
|
||||
@@ -0,0 +1,80 @@
|
||||
# Network perimeter и pfSense
|
||||
|
||||
Документ описывает роль pfSense в архитектуре DetMir/AWatch-rus для
|
||||
коммерческих внедрений и экспертной оценки. pfSense рассматривается как
|
||||
опциональный интеграционный слой сетевого периметра, а не как обязательная
|
||||
часть продукта.
|
||||
|
||||
## 1. Позиция продукта
|
||||
|
||||
DetMir/AWatch-rus поставляет:
|
||||
|
||||
- сбор и нормализацию endpoint/server telemetry;
|
||||
- Workforce analytics;
|
||||
- технический аудит;
|
||||
- DLP-lite/ИБ evidence workflow;
|
||||
- readiness checks и portal reporting.
|
||||
|
||||
Сетевой шлюз, firewall, NAT, VPN и quarantine enforcement могут быть
|
||||
интегрированы с DetMir, но не входят в минимальный состав продукта.
|
||||
|
||||
## 2. Роль pfSense
|
||||
|
||||
pfSense может использоваться как:
|
||||
|
||||
- источник сетевого контекста;
|
||||
- внешний policy enforcement point;
|
||||
- шлюз для ограничений VLAN/alias/rules;
|
||||
- источник логов для корреляции с endpoint activity.
|
||||
|
||||
DetMir не требует pfSense для базовой работы портала, readiness, workforce,
|
||||
DLP-lite evidence и отчетов.
|
||||
|
||||
## 3. Интеграционные границы
|
||||
|
||||
| Слой | Статус |
|
||||
|---|---|
|
||||
| Endpoint telemetry | обязательный слой DetMir |
|
||||
| Server-side checks/readiness | обязательный слой DetMir |
|
||||
| Portal/Grafana/Prometheus | обязательный слой DetMir |
|
||||
| pfSense logs/context | опциональная интеграция |
|
||||
| pfSense policy enforcement | опциональная интеграция с отдельным решением |
|
||||
| Автоматический quarantine | не включать без отдельного согласования |
|
||||
|
||||
## 4. Безопасный режим внедрения
|
||||
|
||||
По умолчанию:
|
||||
|
||||
- DetMir только читает сетевой контекст, если интеграция включена;
|
||||
- любые изменения firewall/NAT/VPN/quarantine запрещены без отдельного change
|
||||
request;
|
||||
- pfSense credentials хранятся вне Git и вне public release assets;
|
||||
- public docs используют placeholders и TEST-NET адреса.
|
||||
|
||||
## 5. Что не заявлять
|
||||
|
||||
Для реестра российского ПО и публичной экспертизы не позиционировать DetMir как:
|
||||
|
||||
- firewall;
|
||||
- NAC;
|
||||
- VPN gateway;
|
||||
- сертифицированное средство сетевой защиты;
|
||||
- обязательный модуль управления pfSense.
|
||||
|
||||
Корректная формулировка:
|
||||
|
||||
> DetMir поддерживает интеграцию с сетевым периметром заказчика, включая
|
||||
> pfSense-compatible gateways, как внешний источник контекста и опциональную
|
||||
> точку применения политик.
|
||||
|
||||
## 6. Будущий roadmap
|
||||
|
||||
Возможные этапы развития:
|
||||
|
||||
1. Read-only import сетевых событий.
|
||||
2. Корреляция endpoint activity и VPN/network context.
|
||||
3. Manual approval workflow для сетевых ограничений.
|
||||
4. Controlled enforcement через allowlist политик.
|
||||
5. Audit trail каждого сетевого действия.
|
||||
|
||||
До отдельного решения владельца продукта pfSense runtime остается no-touch.
|
||||
@@ -30,6 +30,28 @@ Additional readiness artifacts:
|
||||
- `docs/screenshots/release-v0.1/portal-reports-risk.png`
|
||||
- `docs/screenshots/release-v0.1/portal-owner-summary.png`
|
||||
|
||||
## Release-readiness v0.2 overlay
|
||||
|
||||
Additional release/commercial-readiness artifacts:
|
||||
|
||||
- `scripts/generate_release_sbom_v0_2.sh`
|
||||
- `scripts/verify_release_assets.sh`
|
||||
- `.github/workflows/release-assets.yml`
|
||||
- `docs/RELEASE_READINESS_V0.2_RU.md`
|
||||
- `docs/CUSTOMER_PILOT_ACCEPTANCE_RU.md`
|
||||
- `docs/NETWORK_PERIMETER_PFSENSE_RU.md`
|
||||
|
||||
Generated GitHub Release assets:
|
||||
|
||||
- `sbom/cyclonedx-rust-v0.2.json`
|
||||
- `sbom/spdx-rust-v0.2.json`
|
||||
- `sbom/cargo-metadata-v0.2.json`
|
||||
- `sbom/cargo-tree-v0.2.txt`
|
||||
- `sbom/python-inputs-v0.2.txt`
|
||||
- `RELEASE_ASSETS_MANIFEST-v0.2.json`
|
||||
- `SHA256SUMS-v0.2.txt`
|
||||
- `SHA256SUMS-v0.2.txt.sig`
|
||||
|
||||
## Artifacts
|
||||
|
||||
```text
|
||||
|
||||
@@ -16,6 +16,16 @@ Release type: public expert-review/source package.
|
||||
- architecture схема `docs/diagrams/release-readiness-v0.1.md`;
|
||||
- обезличенные screenshots портала в `docs/screenshots/release-v0.1/`.
|
||||
|
||||
## Release-readiness v0.2 addendum
|
||||
|
||||
Добавлен слой коммерческого/release hardening:
|
||||
|
||||
- machine SBOM generation для CycloneDX и SPDX;
|
||||
- CI self-test checksum/signature verifier;
|
||||
- шаблон customer pilot acceptance act;
|
||||
- документ network perimeter/pfSense как optional integration layer;
|
||||
- требование подписанного Git tag и detached signature для release assets.
|
||||
|
||||
## Что входит
|
||||
|
||||
- Обезличенный public source package DetMir/AWatch-rus.
|
||||
|
||||
@@ -0,0 +1,117 @@
|
||||
# Release readiness v0.2
|
||||
|
||||
`release-readiness-v0.2` усиливает v0.1 в части коммерческого релиза и
|
||||
подготовки к реестру российского ПО.
|
||||
|
||||
Дата фиксации: `2026-06-03`.
|
||||
|
||||
## 1. Что добавлено
|
||||
|
||||
| Блок | Файл |
|
||||
|---|---|
|
||||
| Machine SBOM generation | `scripts/generate_release_sbom_v0_2.sh` |
|
||||
| Release asset verification | `scripts/verify_release_assets.sh` |
|
||||
| CI checksum/signature self-test | `.github/workflows/release-assets.yml` |
|
||||
| Pilot acceptance act | `docs/CUSTOMER_PILOT_ACCEPTANCE_RU.md` |
|
||||
| pfSense perimeter positioning | `docs/NETWORK_PERIMETER_PFSENSE_RU.md` |
|
||||
|
||||
## 2. Machine SBOM as GitHub Release asset
|
||||
|
||||
Сгенерировать assets:
|
||||
|
||||
```bash
|
||||
bash scripts/generate_release_sbom_v0_2.sh dist/release-v0.2
|
||||
```
|
||||
|
||||
Ожидаемые файлы:
|
||||
|
||||
```text
|
||||
dist/release-v0.2/sbom/cyclonedx-rust-v0.2.json
|
||||
dist/release-v0.2/sbom/spdx-rust-v0.2.json
|
||||
dist/release-v0.2/sbom/cargo-metadata-v0.2.json
|
||||
dist/release-v0.2/sbom/cargo-tree-v0.2.txt
|
||||
dist/release-v0.2/sbom/python-inputs-v0.2.txt
|
||||
dist/release-v0.2/RELEASE_ASSETS_MANIFEST-v0.2.json
|
||||
dist/release-v0.2/SHA256SUMS-v0.2.txt
|
||||
```
|
||||
|
||||
Эти файлы публикуются как GitHub Release assets. Они не хранятся в tracked
|
||||
source, потому что `dist/` является generated output.
|
||||
|
||||
## 3. Подпись release assets
|
||||
|
||||
Release manager подписывает checksum file detached signature:
|
||||
|
||||
```bash
|
||||
openssl dgst -sha256 -sign <RELEASE_PRIVATE_KEY.pem> \
|
||||
-out dist/release-v0.2/SHA256SUMS-v0.2.txt.sig \
|
||||
dist/release-v0.2/SHA256SUMS-v0.2.txt
|
||||
```
|
||||
|
||||
Проверка:
|
||||
|
||||
```bash
|
||||
RELEASE_VERIFY_PUBLIC_KEY=<RELEASE_PUBLIC_KEY.pem> \
|
||||
bash scripts/verify_release_assets.sh dist/release-v0.2
|
||||
```
|
||||
|
||||
## 4. Подписанный Git tag
|
||||
|
||||
Требование для финального релиза:
|
||||
|
||||
```bash
|
||||
git tag -s release-readiness-v0.2 -m "release-readiness-v0.2"
|
||||
git tag -v release-readiness-v0.2
|
||||
git push origin release-readiness-v0.2
|
||||
```
|
||||
|
||||
Tag должен быть подписан пользовательским ключом правообладателя/maintainer, а
|
||||
не сторонним системным ключом пакетов ОС.
|
||||
|
||||
## 5. CI gate
|
||||
|
||||
Workflow:
|
||||
|
||||
```text
|
||||
.github/workflows/release-assets.yml
|
||||
```
|
||||
|
||||
Проверяет:
|
||||
|
||||
- генерацию CycloneDX/SPDX JSON;
|
||||
- валидность JSON;
|
||||
- self-test checksum/signature verifier;
|
||||
- отрицательные сценарии checksum mismatch и missing signature.
|
||||
|
||||
## 6. Pilot acceptance
|
||||
|
||||
Шаблон:
|
||||
|
||||
```text
|
||||
docs/CUSTOMER_PILOT_ACCEPTANCE_RU.md
|
||||
```
|
||||
|
||||
Использовать для коммерческого пилота после установки и первичной настройки.
|
||||
Публичная версия должна оставаться обезличенной.
|
||||
|
||||
## 7. pfSense perimeter
|
||||
|
||||
Документ:
|
||||
|
||||
```text
|
||||
docs/NETWORK_PERIMETER_PFSENSE_RU.md
|
||||
```
|
||||
|
||||
Ключевая позиция: pfSense является опциональным интеграционным слоем, а не
|
||||
обязательной частью продукта DetMir/AWatch-rus.
|
||||
|
||||
## 8. Acceptance checklist
|
||||
|
||||
- SBOM assets сгенерированы.
|
||||
- `SHA256SUMS-v0.2.txt` создан.
|
||||
- `SHA256SUMS-v0.2.txt.sig` создан release private key.
|
||||
- `scripts/verify_release_assets.sh` проходит с public key.
|
||||
- Git tag подписан ключом maintainer.
|
||||
- GitHub release содержит SBOM JSON/TXT, manifest, checksum и signature.
|
||||
- `CUSTOMER_PILOT_ACCEPTANCE_RU.md` заполнен для пилотного заказчика.
|
||||
- pfSense не описан как обязательный компонент продукта.
|
||||
@@ -147,6 +147,22 @@ git ls-files '*.py'
|
||||
|
||||
Сформировать машинные перечни зависимостей.
|
||||
|
||||
Для release-readiness v0.2 используется единый генератор:
|
||||
|
||||
```bash
|
||||
bash scripts/generate_release_sbom_v0_2.sh dist/release-v0.2
|
||||
```
|
||||
|
||||
Он формирует:
|
||||
|
||||
- `cyclonedx-rust-v0.2.json`;
|
||||
- `spdx-rust-v0.2.json`;
|
||||
- `cargo-metadata-v0.2.json`;
|
||||
- `cargo-tree-v0.2.txt`;
|
||||
- `python-inputs-v0.2.txt`;
|
||||
- `RELEASE_ASSETS_MANIFEST-v0.2.json`;
|
||||
- `SHA256SUMS-v0.2.txt`.
|
||||
|
||||
Rust:
|
||||
|
||||
```bash
|
||||
@@ -202,6 +218,19 @@ sha256sum dist/* install-kit-awindows-*.zip install-kit-awindows-*.tar.gz \
|
||||
> SHA256SUMS
|
||||
```
|
||||
|
||||
Проверка release assets v0.2:
|
||||
|
||||
```bash
|
||||
RELEASE_VERIFY_PUBLIC_KEY=<RELEASE_PUBLIC_KEY.pem> \
|
||||
bash scripts/verify_release_assets.sh dist/release-v0.2
|
||||
```
|
||||
|
||||
CI self-test:
|
||||
|
||||
```bash
|
||||
bash scripts/verify_release_assets.sh --self-test
|
||||
```
|
||||
|
||||
## 9. Документы для реестра российского ПО
|
||||
|
||||
Проверить наличие и актуальность:
|
||||
|
||||
Executable
+128
@@ -0,0 +1,128 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
OUT_DIR="${1:-"$ROOT_DIR/dist/release-v0.2"}"
|
||||
SBOM_DIR="$OUT_DIR/sbom"
|
||||
VERSION="release-readiness-v0.2"
|
||||
|
||||
mkdir -p "$SBOM_DIR"
|
||||
|
||||
cd "$ROOT_DIR"
|
||||
|
||||
COMMIT="$(git rev-parse HEAD)"
|
||||
GENERATED_AT="$(date -u '+%Y-%m-%dT%H:%M:%SZ')"
|
||||
|
||||
cargo metadata --manifest-path adk-rust/Cargo.toml --format-version 1 \
|
||||
> "$SBOM_DIR/cargo-metadata-v0.2.json"
|
||||
|
||||
(cd adk-rust && cargo tree --workspace) \
|
||||
> "$SBOM_DIR/cargo-tree-v0.2.txt"
|
||||
|
||||
find aw-server clickhouse-1c detmir-mcp scripts -maxdepth 4 -type f \
|
||||
\( -name 'requirements.txt' -o -name 'pyproject.toml' -o -name 'setup.py' \) \
|
||||
-print -exec sha256sum {} \; \
|
||||
> "$SBOM_DIR/python-inputs-v0.2.txt"
|
||||
|
||||
python3 - "$SBOM_DIR/cargo-metadata-v0.2.json" "$SBOM_DIR/cyclonedx-rust-v0.2.json" "$SBOM_DIR/spdx-rust-v0.2.json" "$COMMIT" "$GENERATED_AT" <<'PY'
|
||||
import json
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
metadata_path, cyclonedx_path, spdx_path, commit, generated_at = sys.argv[1:]
|
||||
metadata = json.loads(Path(metadata_path).read_text(encoding="utf-8"))
|
||||
packages = sorted(metadata.get("packages", []), key=lambda item: (item.get("name", ""), item.get("version", "")))
|
||||
|
||||
components = []
|
||||
spdx_packages = []
|
||||
for package in packages:
|
||||
name = package.get("name") or "unknown"
|
||||
version = package.get("version") or "0"
|
||||
license_value = package.get("license") or "NOASSERTION"
|
||||
components.append({
|
||||
"type": "library",
|
||||
"bom-ref": f"pkg:cargo/{name}@{version}",
|
||||
"name": name,
|
||||
"version": version,
|
||||
"licenses": [{"expression": license_value}] if license_value != "NOASSERTION" else [],
|
||||
"purl": f"pkg:cargo/{name}@{version}",
|
||||
})
|
||||
spdx_packages.append({
|
||||
"name": name,
|
||||
"SPDXID": f"SPDXRef-Package-{name.replace('_', '-').replace('.', '-')}-{version.replace('.', '-')}",
|
||||
"versionInfo": version,
|
||||
"downloadLocation": "NOASSERTION",
|
||||
"filesAnalyzed": False,
|
||||
"licenseConcluded": "NOASSERTION",
|
||||
"licenseDeclared": license_value,
|
||||
"copyrightText": "NOASSERTION",
|
||||
})
|
||||
|
||||
cyclonedx = {
|
||||
"bomFormat": "CycloneDX",
|
||||
"specVersion": "1.5",
|
||||
"serialNumber": f"urn:uuid:00000000-0000-4000-8000-{commit[:12].ljust(12, '0')}",
|
||||
"version": 1,
|
||||
"metadata": {
|
||||
"timestamp": generated_at,
|
||||
"component": {
|
||||
"type": "application",
|
||||
"name": "DetMir AWatch-rus",
|
||||
"version": "release-readiness-v0.2",
|
||||
"bom-ref": "pkg:generic/detmir-awatch-rus@release-readiness-v0.2",
|
||||
},
|
||||
"properties": [
|
||||
{"name": "git.commit", "value": commit},
|
||||
{"name": "scope", "value": "Rust workspace dependencies"},
|
||||
],
|
||||
},
|
||||
"components": components,
|
||||
}
|
||||
|
||||
spdx = {
|
||||
"spdxVersion": "SPDX-2.3",
|
||||
"dataLicense": "CC0-1.0",
|
||||
"SPDXID": "SPDXRef-DOCUMENT",
|
||||
"name": "DetMir AWatch-rus release-readiness-v0.2 Rust SBOM",
|
||||
"documentNamespace": f"https://github.com/igor04091968/AWatch-rus/sbom/{commit}",
|
||||
"creationInfo": {
|
||||
"created": generated_at,
|
||||
"creators": ["Tool: scripts/generate_release_sbom_v0_2.sh"],
|
||||
},
|
||||
"packages": spdx_packages,
|
||||
}
|
||||
|
||||
Path(cyclonedx_path).write_text(json.dumps(cyclonedx, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")
|
||||
Path(spdx_path).write_text(json.dumps(spdx, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")
|
||||
PY
|
||||
|
||||
cat > "$OUT_DIR/RELEASE_ASSETS_MANIFEST-v0.2.json" <<JSON
|
||||
{
|
||||
"release": "$VERSION",
|
||||
"generated_at_utc": "$GENERATED_AT",
|
||||
"git_commit": "$COMMIT",
|
||||
"assets": [
|
||||
"sbom/cyclonedx-rust-v0.2.json",
|
||||
"sbom/spdx-rust-v0.2.json",
|
||||
"sbom/cargo-metadata-v0.2.json",
|
||||
"sbom/cargo-tree-v0.2.txt",
|
||||
"sbom/python-inputs-v0.2.txt"
|
||||
]
|
||||
}
|
||||
JSON
|
||||
|
||||
(
|
||||
cd "$OUT_DIR"
|
||||
find . -type f ! -name 'SHA256SUMS-v0.2.txt' ! -name '*.sig' -print \
|
||||
| sort \
|
||||
| sed 's#^\./##' \
|
||||
| xargs -r sha256sum > SHA256SUMS-v0.2.txt
|
||||
)
|
||||
|
||||
cat <<EOF
|
||||
release SBOM v0.2 generated
|
||||
out_dir=$OUT_DIR
|
||||
commit=$COMMIT
|
||||
assets:
|
||||
$(sed 's/^/ /' "$OUT_DIR/SHA256SUMS-v0.2.txt")
|
||||
EOF
|
||||
Executable
+92
@@ -0,0 +1,92 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
usage() {
|
||||
cat <<'EOF'
|
||||
Usage:
|
||||
scripts/verify_release_assets.sh <asset-dir>
|
||||
scripts/verify_release_assets.sh --self-test
|
||||
|
||||
Checks:
|
||||
- SHA256SUMS*.txt exists and verifies all release assets.
|
||||
- Each SHA256SUMS*.txt has a detached signature (*.sig).
|
||||
- Signature is verified when RELEASE_VERIFY_PUBLIC_KEY is set.
|
||||
- Without RELEASE_VERIFY_PUBLIC_KEY, signature presence is still enforced.
|
||||
EOF
|
||||
}
|
||||
|
||||
fail() {
|
||||
echo "verify_release_assets: FAIL: $*" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
verify_dir() {
|
||||
local asset_dir="$1"
|
||||
[[ -d "$asset_dir" ]] || fail "asset directory does not exist: $asset_dir"
|
||||
|
||||
local sums
|
||||
sums="$(find "$asset_dir" -maxdepth 1 -type f -name 'SHA256SUMS*.txt' | sort | head -n 1)"
|
||||
[[ -n "$sums" ]] || fail "SHA256SUMS*.txt not found in $asset_dir"
|
||||
[[ -s "$sums" ]] || fail "checksum file is empty: $sums"
|
||||
[[ -f "$sums.sig" ]] || fail "detached signature is missing: $sums.sig"
|
||||
|
||||
(cd "$asset_dir" && sha256sum -c "$(basename "$sums")") || fail "checksum verification failed: $sums"
|
||||
|
||||
if [[ -n "${RELEASE_VERIFY_PUBLIC_KEY:-}" ]]; then
|
||||
[[ -f "$RELEASE_VERIFY_PUBLIC_KEY" ]] || fail "public key not found: $RELEASE_VERIFY_PUBLIC_KEY"
|
||||
openssl dgst -sha256 -verify "$RELEASE_VERIFY_PUBLIC_KEY" -signature "$sums.sig" "$sums" >/dev/null \
|
||||
|| fail "signature verification failed: $sums.sig"
|
||||
echo "verify_release_assets: signature verified with $RELEASE_VERIFY_PUBLIC_KEY"
|
||||
else
|
||||
echo "verify_release_assets: signature file present; cryptographic verification skipped because RELEASE_VERIFY_PUBLIC_KEY is not set"
|
||||
fi
|
||||
|
||||
echo "verify_release_assets: OK ($asset_dir)"
|
||||
}
|
||||
|
||||
self_test() {
|
||||
local tmp
|
||||
tmp="$(mktemp -d)"
|
||||
trap 'rm -rf "$tmp"' RETURN
|
||||
|
||||
printf 'release asset\n' > "$tmp/asset.txt"
|
||||
(cd "$tmp" && sha256sum asset.txt > SHA256SUMS-v0.2.txt)
|
||||
|
||||
openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 -out "$tmp/private-key.pem" >/dev/null 2>&1
|
||||
openssl pkey -in "$tmp/private-key.pem" -pubout -out "$tmp/public-key.pem" >/dev/null 2>&1
|
||||
openssl dgst -sha256 -sign "$tmp/private-key.pem" -out "$tmp/SHA256SUMS-v0.2.txt.sig" "$tmp/SHA256SUMS-v0.2.txt"
|
||||
|
||||
RELEASE_VERIFY_PUBLIC_KEY="$tmp/public-key.pem" verify_dir "$tmp"
|
||||
|
||||
cp "$tmp/SHA256SUMS-v0.2.txt" "$tmp/SHA256SUMS-v0.2.txt.good"
|
||||
printf 'tampered\n' > "$tmp/asset.txt"
|
||||
if (RELEASE_VERIFY_PUBLIC_KEY="$tmp/public-key.pem" verify_dir "$tmp") >/dev/null 2>&1; then
|
||||
fail "self-test did not catch checksum mismatch"
|
||||
fi
|
||||
mv "$tmp/SHA256SUMS-v0.2.txt.good" "$tmp/SHA256SUMS-v0.2.txt"
|
||||
printf 'release asset\n' > "$tmp/asset.txt"
|
||||
rm -f "$tmp/SHA256SUMS-v0.2.txt.sig"
|
||||
if (RELEASE_VERIFY_PUBLIC_KEY="$tmp/public-key.pem" verify_dir "$tmp") >/dev/null 2>&1; then
|
||||
fail "self-test did not catch missing signature"
|
||||
fi
|
||||
|
||||
echo "verify_release_assets: self-test OK"
|
||||
}
|
||||
|
||||
if [[ "${1:-}" == "--help" || "${1:-}" == "-h" ]]; then
|
||||
usage
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [[ "${1:-}" == "--self-test" ]]; then
|
||||
command -v openssl >/dev/null 2>&1 || fail "openssl is required for --self-test"
|
||||
self_test
|
||||
exit 0
|
||||
fi
|
||||
|
||||
[[ $# -eq 1 ]] || {
|
||||
usage >&2
|
||||
exit 2
|
||||
}
|
||||
|
||||
verify_dir "$1"
|
||||
Reference in New Issue
Block a user