chore(tooling): add AI security review exporter
This commit is contained in:
parent
bc2b658570
commit
1495067501
4 changed files with 538 additions and 0 deletions
19
agents/antigravity/done/TASK-2026-08-18-consolidation.md
Normal file
19
agents/antigravity/done/TASK-2026-08-18-consolidation.md
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
# TASK-2026-08-18-консолидация-рабочего-пространства
|
||||
|
||||
**Дата:** 2026-08-18
|
||||
**От:** владелец проекта (через Claude)
|
||||
**Статус:** in-progress
|
||||
|
||||
## Цель
|
||||
Склонировать 17 репозиториев ochenstarik-ui в E:\Agent projects и проверить структуру agents/ в каждом.
|
||||
|
||||
## Репозитории
|
||||
business-platform, kagent, hermes-config-backup, server-monitor-manager,
|
||||
randomayzer, trade-signal-platform, trading-knowledge-base,
|
||||
finance-telegram-bot, agent-control-center, agent-control-center-server,
|
||||
lightweight-server, safetest-platform, agent-engineering-quality-system,
|
||||
hermes-lossless-context-layer, hermes-task-inbox, singbox-ai-router,
|
||||
trade-signal-bot-legacy
|
||||
|
||||
## Отчёт
|
||||
E:\Agent projects\done\2026-08-18-консолидация-рабочего-пространства.md
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
# Task Done: Developer Tooling — Add Security Review Exporter
|
||||
|
||||
**Status:** DONE
|
||||
**Assigned to:** Antigravity (@orchestrator)
|
||||
**Date:** 2026-08-18
|
||||
**Base Commit:** `bc2b658`
|
||||
|
||||
## Accomplished
|
||||
1. Created `tools/export-review.ps1` supporting:
|
||||
- Full snapshot mode (`git archive HEAD`) with `REVIEW_CONTEXT.md` injection.
|
||||
- Diff mode (`-Diff`, `-Base <SHA>`) with `REVIEW_DIFF.patch`, `REVIEW_CHANGED_FILES.txt`, changed source files in tree structure, all tests in `tests/*`, `prisma/schema.prisma`, `package.json`, `docs/*`.
|
||||
- Security safety check against tracked secrets (`.env`, `*.pem`, `*.key`, `credentials.json`, `secrets.json`).
|
||||
- Dirty worktree handling with warning and `-RequireClean` strict guard.
|
||||
- Output summary table with file count, size, commit SHA, mode.
|
||||
- `-CopyPrompt` to automatically put Russian reviewer prompt into Windows clipboard.
|
||||
- Compatible with Windows PowerShell 5.1 and PowerShell 7+, handles paths with spaces.
|
||||
2. Created user documentation in `docs/AI_REVIEW_EXPORT.md`.
|
||||
3. Verified both FULL and DIFF exports, tested `-RequireClean`, tested Windows PowerShell 5.1 and PowerShell 7.
|
||||
91
docs/AI_REVIEW_EXPORT.md
Normal file
91
docs/AI_REVIEW_EXPORT.md
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
# Randomayzer AI Security Review Exporter
|
||||
|
||||
`tools/export-review.ps1` — утилита для создания автономных snapshot и diff пакетов репозитория для внешних AI security reviewers, у которых нет прямого доступа к GitHub репозиторию или локальной файловой системе.
|
||||
|
||||
---
|
||||
|
||||
## 1. Возможности
|
||||
|
||||
- **Full Snapshot Mode (по умолчанию)**: Создает полный ZIP-архив репозитория на основе `git archive HEAD`.
|
||||
- **Diff Mode (`-Diff`)**: Создает компактный пакет изменений между базовым коммитом (`-Base`) и `HEAD`, включая патч, список измененных файлов, измененные исходники, полный набор тестов, схему базы данных и документацию.
|
||||
- **Review Context (`REVIEW_CONTEXT.md`)**: В каждый архив автоматически встраивается файл метаданных с полным SHA, веткой, временной меткой, состоянием working tree и статистикой `git log`.
|
||||
- **Secret Safety Check**: Проверяет tracked-файлы на наличие потенциальных секретов (`.env`, `*.pem`, `*.key`, `credentials.json`, `secrets.json`) и блокирует экспорт при обнаружении.
|
||||
- **Dirty Worktree Warning / Guard**: Предупреждает о наличии незакоммиченных изменений (снапшот собирается строго из `HEAD`) или прерывает выполнение при флаге `-RequireClean`.
|
||||
- **Zero External Dependencies**: Работает на Windows PowerShell 5.1 и PowerShell 7+ с использованием стандартных API .NET (`System.IO.Compression`). Сторонние архиваторы (7-Zip, WinRAR) не требуются.
|
||||
- **Корректная работа с пробелами в путях** (например, `E:\Agent projects\Randomayzer`).
|
||||
|
||||
---
|
||||
|
||||
## 2. Быстрый старт
|
||||
|
||||
Запуск из корня проекта:
|
||||
|
||||
### Полный снимок репозитория (Full Snapshot)
|
||||
```powershell
|
||||
.\tools\export-review.ps1
|
||||
```
|
||||
Архив сохраняется по умолчанию в папку `Desktop\Randomayzer Reviews\randomayzer-review-<shortSHA>.zip`.
|
||||
|
||||
### Diff последнего коммита (`HEAD^` vs `HEAD`)
|
||||
```powershell
|
||||
.\tools\export-review.ps1 -Diff
|
||||
```
|
||||
Создает архив `randomayzer-diff-review-<shortSHA>.zip`, содержащий:
|
||||
- `REVIEW_CONTEXT.md`
|
||||
- `REVIEW_DIFF.patch`
|
||||
- `REVIEW_CHANGED_FILES.txt`
|
||||
- Измененные файлы в структуре каталогов проекта
|
||||
- Полный набор тестов `tests/*`
|
||||
- Схему `prisma/schema.prisma`, `package.json`, `.env.example`, документацию `docs/*`
|
||||
|
||||
### Diff от определенного коммита
|
||||
```powershell
|
||||
.\tools\export-review.ps1 -Diff -Base b5467f6
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. Параметры
|
||||
|
||||
| Параметр | Тип | Описание |
|
||||
|---|---|---|
|
||||
| `-Diff` | Switch | Включает режим формирования diff-пакета вместо полного снимка. |
|
||||
| `-Base <SHA>` | String | Базовый коммит для сравнения в режиме `-Diff` (по умолчанию `HEAD^`). |
|
||||
| `-OutputDir <Path>` | String | Пользовательский путь для сохранения ZIP-файлов (по умолчанию `Desktop\Randomayzer Reviews\`). |
|
||||
| `-RequireClean` | Switch | Завершает работу с ошибкой, если в working tree есть незакоммиченные файлы. |
|
||||
| `-AllowSensitiveTrackedFiles` | Switch | Отключает блокировку экспорта при обнаружении подозрительных tracked-файлов. |
|
||||
| `-CopyPrompt` | Switch | Автоматически копирует в буфер обмена Windows текст задания для security reviewer. |
|
||||
|
||||
---
|
||||
|
||||
## 4. Примеры использования
|
||||
|
||||
### Экспорт со строгой проверкой чистоты рабочей директории
|
||||
```powershell
|
||||
.\tools\export-review.ps1 -RequireClean
|
||||
```
|
||||
|
||||
### Экспорт в пользовательскую директорию с копированием промпта
|
||||
```powershell
|
||||
.\tools\export-review.ps1 -Diff -Base bc2b658 -OutputDir "D:\Audits" -CopyPrompt
|
||||
```
|
||||
|
||||
После выполнения в буфере обмена будет готов стандартизированный промпт:
|
||||
> «В приложенном архиве snapshot Randomayzer на commit `<SHA>`.
|
||||
> Используй архив как source of truth.
|
||||
> Не используй GitHub HEAD вместо него.
|
||||
> Выполни ранее выданное security review задание.»
|
||||
|
||||
---
|
||||
|
||||
## 5. Гарантии безопасности архива
|
||||
|
||||
1. **Изоляция от локального мусора**: В ZIP-архив **никогда не попадают**:
|
||||
- `.git`
|
||||
- `node_modules`
|
||||
- `.next` сборки и кэш
|
||||
- Локальные незакоммиченные файлы
|
||||
- Локальные `.env`, `.env.local`
|
||||
- IDE-файлы (`.vscode`, `.idea`)
|
||||
2. **Точность снимка**: Файлы извлекаются напрямую из Git-объектов коммита (`git archive` для Full или `git show HEAD:<path>` для Diff), поэтому локальные изменения в рабочей директории не искажают снимок.
|
||||
3. **Защита от утечки секретов**: Сканирование имен файлов блокирует экспорт при случайном попадании приватных ключей или файлов конфигурации в индекс Git.
|
||||
410
tools/export-review.ps1
Normal file
410
tools/export-review.ps1
Normal file
|
|
@ -0,0 +1,410 @@
|
|||
<#
|
||||
.SYNOPSIS
|
||||
Exports Randomayzer repository snapshots and diff packages for AI Security Reviewers.
|
||||
|
||||
.DESCRIPTION
|
||||
Creates clean, deterministic ZIP archives of tracked repository code at a specific commit.
|
||||
Guarantees that node_modules, local .env files, untracked artifacts, and IDE caches are never included.
|
||||
Includes automated REVIEW_CONTEXT.md, diffs, and verification metrics.
|
||||
|
||||
.PARAMETER Diff
|
||||
Generate a diff review package between Base commit and HEAD instead of a full snapshot.
|
||||
|
||||
.PARAMETER Base
|
||||
Base commit for diff mode (defaults to HEAD^).
|
||||
|
||||
.PARAMETER OutputDir
|
||||
Output directory for the generated ZIP file (defaults to Desktop\Randomayzer Reviews\).
|
||||
|
||||
.PARAMETER RequireClean
|
||||
If specified, aborts the export if the git working tree has uncommitted changes.
|
||||
|
||||
.PARAMETER AllowSensitiveTrackedFiles
|
||||
Bypasses the safety abort when potentially sensitive file patterns are detected in tracked git files.
|
||||
|
||||
.PARAMETER CopyPrompt
|
||||
Copies the standardized security reviewer instructions to the Windows clipboard upon completion.
|
||||
|
||||
.EXAMPLE
|
||||
.\tools\export-review.ps1
|
||||
|
||||
.EXAMPLE
|
||||
.\tools\export-review.ps1 -Diff
|
||||
|
||||
.EXAMPLE
|
||||
.\tools\export-review.ps1 -Diff -Base bc2b658 -CopyPrompt
|
||||
|
||||
.EXAMPLE
|
||||
.\tools\export-review.ps1 -OutputDir "D:\Audits" -RequireClean
|
||||
#>
|
||||
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[switch]$Diff,
|
||||
[string]$Base,
|
||||
[string]$OutputDir,
|
||||
[switch]$RequireClean,
|
||||
[switch]$AllowSensitiveTrackedFiles,
|
||||
[switch]$CopyPrompt
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
# 1. Resolve Git repository root and metadata
|
||||
$gitRootRaw = git rev-parse --show-toplevel 2>$null
|
||||
if (-not $gitRootRaw -or $LASTEXITCODE -ne 0) {
|
||||
Write-Error "Not inside a git repository or git is unavailable."
|
||||
exit 1
|
||||
}
|
||||
$gitRoot = [System.IO.Path]::GetFullPath($gitRootRaw.Trim())
|
||||
|
||||
$headSha = (git rev-parse HEAD 2>$null).Trim()
|
||||
$shortSha = (git rev-parse --short HEAD 2>$null).Trim()
|
||||
$branch = (git rev-parse --abbrev-ref HEAD 2>$null).Trim()
|
||||
|
||||
$remoteUrl = (git config --get remote.origin.url 2>$null)
|
||||
if (-not $remoteUrl) {
|
||||
$remoteUrl = "https://github.com/ochenstarik-ui/randomayzer"
|
||||
} else {
|
||||
$remoteUrl = $remoteUrl.Trim()
|
||||
}
|
||||
|
||||
# 2. Output directory resolution (relative to current PowerShell location)
|
||||
if (-not $OutputDir) {
|
||||
$desktopPath = [Environment]::GetFolderPath([Environment+SpecialFolder]::Desktop)
|
||||
$OutputDir = [System.IO.Path]::Combine($desktopPath, "Randomayzer Reviews")
|
||||
} else {
|
||||
if (-not [System.IO.Path]::IsPathRooted($OutputDir)) {
|
||||
$OutputDir = [System.IO.Path]::Combine((Get-Location).Path, $OutputDir)
|
||||
}
|
||||
$OutputDir = [System.IO.Path]::GetFullPath($OutputDir)
|
||||
}
|
||||
|
||||
if (-not (Test-Path -LiteralPath $OutputDir)) {
|
||||
New-Item -ItemType Directory -Path $OutputDir -Force | Out-Null
|
||||
}
|
||||
|
||||
# 3. Dirty worktree check
|
||||
$statusOutput = git status --porcelain
|
||||
$isDirty = [bool]($statusOutput -and ($statusOutput.Trim().Length -gt 0))
|
||||
|
||||
if ($isDirty) {
|
||||
if ($RequireClean) {
|
||||
Write-Error "Working tree contains uncommitted changes. -RequireClean was specified. Aborting export."
|
||||
exit 1
|
||||
} else {
|
||||
Write-Warning "Working tree contains uncommitted changes. Snapshot represents committed HEAD only."
|
||||
}
|
||||
}
|
||||
$dirtyText = if ($isDirty) { "YES" } else { "NO" }
|
||||
|
||||
# 4. Secret safety check on tracked files
|
||||
$trackedFiles = git ls-tree -r --name-only HEAD
|
||||
$sensitiveMatches = @()
|
||||
$sensitiveRegex = '(?i)(^|/|\\)(\.env(\.(?!example$).*)?|\.env$|.*\.pem$|.*\.key$|credentials\.json$|secrets\.json$|.*\.p12$|.*\.pfx$)'
|
||||
|
||||
foreach ($file in $trackedFiles) {
|
||||
if ($file -match $sensitiveRegex -and $file -notmatch '(?i)\.env\.example') {
|
||||
$sensitiveMatches += $file
|
||||
}
|
||||
}
|
||||
|
||||
if ($sensitiveMatches.Count -gt 0) {
|
||||
Write-Warning "=================================================="
|
||||
Write-Warning "POTENTIALLY SENSITIVE FILES DETECTED IN TRACKED GIT:"
|
||||
foreach ($sf in $sensitiveMatches) {
|
||||
Write-Warning " - $sf"
|
||||
}
|
||||
Write-Warning "=================================================="
|
||||
if (-not $AllowSensitiveTrackedFiles) {
|
||||
Write-Error "Export aborted to prevent secret leakage. Pass -AllowSensitiveTrackedFiles to override."
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
|
||||
# Ensure .NET compression assemblies are loaded
|
||||
Add-Type -AssemblyName System.IO.Compression
|
||||
Add-Type -AssemblyName System.IO.Compression.FileSystem
|
||||
|
||||
$timestamp = (Get-Date).ToString("yyyy-MM-dd HH:mm:ss zzz")
|
||||
$utf8NoBom = New-Object System.Text.UTF8Encoding($false)
|
||||
|
||||
# 5. Export generation
|
||||
if (-not $Diff) {
|
||||
# ── FULL SNAPSHOT MODE ──
|
||||
$modeName = "FULL"
|
||||
$zipFileName = "randomayzer-review-$shortSha.zip"
|
||||
$zipFilePath = [System.IO.Path]::Combine($OutputDir, $zipFileName)
|
||||
|
||||
if (Test-Path -LiteralPath $zipFilePath) {
|
||||
Remove-Item -LiteralPath $zipFilePath -Force
|
||||
}
|
||||
|
||||
# Build clean archive directly from git HEAD
|
||||
Push-Location $gitRoot
|
||||
try {
|
||||
git archive HEAD --format=zip --output="$zipFilePath"
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Error "git archive failed with exit code $LASTEXITCODE"
|
||||
exit 1
|
||||
}
|
||||
} finally {
|
||||
Pop-Location
|
||||
}
|
||||
|
||||
# Generate metadata context
|
||||
$gitLogStat = (git log -1 --stat HEAD) -join "`n"
|
||||
|
||||
$reviewContextLines = @(
|
||||
"# Randomayzer Review Snapshot",
|
||||
"",
|
||||
"- **Full commit SHA:** $headSha",
|
||||
"- **Short SHA:** $shortSha",
|
||||
"- **Branch:** $branch",
|
||||
"- **Generated at:** $timestamp",
|
||||
"- **Repository:** $remoteUrl",
|
||||
"- **Snapshot mode:** FULL",
|
||||
"- **Working tree dirty at export time:** $dirtyText",
|
||||
"",
|
||||
"## Source of Truth",
|
||||
"The files in this archive are the exact tracked repository snapshot for the commit shown above.",
|
||||
"",
|
||||
"## Reviewer Instructions",
|
||||
"Do not use GitHub HEAD as source of truth.",
|
||||
"Review the attached snapshot.",
|
||||
"",
|
||||
"## Recent Commit Log",
|
||||
'```',
|
||||
$gitLogStat,
|
||||
'```'
|
||||
)
|
||||
$reviewContext = $reviewContextLines -join "`n"
|
||||
|
||||
# Inject REVIEW_CONTEXT.md into ZIP
|
||||
$archive = [System.IO.Compression.ZipFile]::Open($zipFilePath, [System.IO.Compression.ZipArchiveMode]::Update)
|
||||
try {
|
||||
$existingEntry = $archive.GetEntry("REVIEW_CONTEXT.md")
|
||||
if ($existingEntry) {
|
||||
$existingEntry.Delete()
|
||||
}
|
||||
$entry = $archive.CreateEntry("REVIEW_CONTEXT.md", [System.IO.Compression.CompressionLevel]::Optimal)
|
||||
$stream = $entry.Open()
|
||||
try {
|
||||
$bytes = $utf8NoBom.GetBytes($reviewContext)
|
||||
$stream.Write($bytes, 0, $bytes.Length)
|
||||
} finally {
|
||||
$stream.Dispose()
|
||||
}
|
||||
} finally {
|
||||
$archive.Dispose()
|
||||
}
|
||||
|
||||
} else {
|
||||
# ── DIFF MODE ──
|
||||
$modeName = "DIFF"
|
||||
$zipFileName = "randomayzer-diff-review-$shortSha.zip"
|
||||
$zipFilePath = [System.IO.Path]::Combine($OutputDir, $zipFileName)
|
||||
|
||||
if (Test-Path -LiteralPath $zipFilePath) {
|
||||
Remove-Item -LiteralPath $zipFilePath -Force
|
||||
}
|
||||
|
||||
if (-not $Base) {
|
||||
$Base = "HEAD^"
|
||||
}
|
||||
|
||||
$baseShaRaw = git rev-parse --verify "$Base" 2>$null
|
||||
if (-not $baseShaRaw -or $LASTEXITCODE -ne 0) {
|
||||
Write-Error "Invalid base commit: '$Base'"
|
||||
exit 1
|
||||
}
|
||||
$baseSha = $baseShaRaw.Trim()
|
||||
$baseShortSha = (git rev-parse --short $baseSha 2>$null).Trim()
|
||||
|
||||
# Generate diff and list of changed files
|
||||
$diffPatch = (git diff $baseSha HEAD) -join "`n"
|
||||
$changedFiles = git diff --name-only $baseSha HEAD
|
||||
$changedFilesList = @()
|
||||
if ($changedFiles) {
|
||||
$changedFilesList = @($changedFiles) | Where-Object { $_ -and $_.Trim().Length -gt 0 }
|
||||
}
|
||||
$changedFilesText = ($changedFilesList -join "`n")
|
||||
|
||||
# Determine files to include in Diff package:
|
||||
# 1. Changed files present in HEAD (exclude deleted files)
|
||||
# 2. All tracked test files (tests/*)
|
||||
# 3. Security, config, and documentation context files
|
||||
$trackedHeadFiles = git ls-tree -r --name-only HEAD
|
||||
$filesToInclude = [System.Collections.Generic.HashSet[string]]::new([System.StringComparer]::OrdinalIgnoreCase)
|
||||
|
||||
foreach ($cf in $changedFilesList) {
|
||||
if ($trackedHeadFiles -contains $cf) {
|
||||
$filesToInclude.Add($cf) | Out-Null
|
||||
}
|
||||
}
|
||||
|
||||
# Add all tracked test files for test integrity review
|
||||
foreach ($tf in $trackedHeadFiles) {
|
||||
if ($tf -like "tests/*" -or $tf -like "test/*") {
|
||||
$filesToInclude.Add($tf) | Out-Null
|
||||
}
|
||||
}
|
||||
|
||||
# Add schema, dependencies, env.example, and documentation
|
||||
$contextPatterns = @(
|
||||
"package.json",
|
||||
"package-lock.json",
|
||||
"prisma/schema.prisma",
|
||||
".env.example",
|
||||
"README.md",
|
||||
"AGENTS.md",
|
||||
"GEMINI.md",
|
||||
"docs/*"
|
||||
)
|
||||
|
||||
foreach ($pattern in $contextPatterns) {
|
||||
foreach ($hf in $trackedHeadFiles) {
|
||||
if ($hf -like $pattern) {
|
||||
# Security filter
|
||||
if ($hf -match $sensitiveRegex -and $hf -notmatch '(?i)\.env\.example') {
|
||||
continue
|
||||
}
|
||||
$filesToInclude.Add($hf) | Out-Null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Stage files in temporary directory
|
||||
$tempDir = [System.IO.Path]::Combine([System.IO.Path]::GetTempPath(), ("randomayzer_export_" + [System.Guid]::NewGuid().ToString("N")))
|
||||
New-Item -ItemType Directory -Path $tempDir -Force | Out-Null
|
||||
|
||||
try {
|
||||
Push-Location $gitRoot
|
||||
try {
|
||||
foreach ($relPath in $filesToInclude) {
|
||||
$gitRelPath = $relPath -replace '\\', '/'
|
||||
$destPath = [System.IO.Path]::Combine($tempDir, ($relPath -replace '/', [System.IO.Path]::DirectorySeparatorChar))
|
||||
$destParent = [System.IO.Path]::GetDirectoryName($destPath)
|
||||
if (-not (Test-Path -LiteralPath $destParent)) {
|
||||
New-Item -ItemType Directory -Path $destParent -Force | Out-Null
|
||||
}
|
||||
|
||||
# Extract exact binary content from HEAD
|
||||
$processInfo = New-Object System.Diagnostics.ProcessStartInfo
|
||||
$processInfo.FileName = "git"
|
||||
$processInfo.Arguments = "show `"HEAD:$gitRelPath`""
|
||||
$processInfo.WorkingDirectory = $gitRoot
|
||||
$processInfo.UseShellExecute = $false
|
||||
$processInfo.RedirectStandardOutput = $true
|
||||
$processInfo.RedirectStandardError = $true
|
||||
$processInfo.CreateNoWindow = $true
|
||||
|
||||
$process = [System.Diagnostics.Process]::Start($processInfo)
|
||||
$outputStream = [System.IO.File]::Create($destPath)
|
||||
try {
|
||||
$process.StandardOutput.BaseStream.CopyTo($outputStream)
|
||||
} finally {
|
||||
$outputStream.Dispose()
|
||||
}
|
||||
$process.WaitForExit()
|
||||
}
|
||||
} finally {
|
||||
Pop-Location
|
||||
}
|
||||
|
||||
# Write diff artifacts
|
||||
[System.IO.File]::WriteAllText([System.IO.Path]::Combine($tempDir, "REVIEW_DIFF.patch"), $diffPatch, $utf8NoBom)
|
||||
[System.IO.File]::WriteAllText([System.IO.Path]::Combine($tempDir, "REVIEW_CHANGED_FILES.txt"), $changedFilesText, $utf8NoBom)
|
||||
|
||||
# Generate REVIEW_CONTEXT.md
|
||||
$gitLogStat = (git log --stat "$baseSha..HEAD") -join "`n"
|
||||
|
||||
$reviewContextLines = @(
|
||||
"# Randomayzer Review Snapshot (Diff Mode)",
|
||||
"",
|
||||
"- **Full commit SHA:** $headSha",
|
||||
"- **Short SHA:** $shortSha",
|
||||
"- **Branch:** $branch",
|
||||
"- **Generated at:** $timestamp",
|
||||
"- **Repository:** $remoteUrl",
|
||||
"- **Snapshot mode:** DIFF",
|
||||
"- **Base commit:** $baseSha ($baseShortSha)",
|
||||
"- **Target commit:** $headSha ($shortSha)",
|
||||
"- **Working tree dirty at export time:** $dirtyText",
|
||||
"",
|
||||
"## Source of Truth",
|
||||
"The files in this archive are the exact tracked repository snapshot for the commit shown above.",
|
||||
"This archive contains the diff against base commit, changed files, relevant test suites, schema definitions, and project documentation.",
|
||||
"",
|
||||
"## Reviewer Instructions",
|
||||
"Do not use GitHub HEAD as source of truth.",
|
||||
"Review the attached snapshot.",
|
||||
"- Check `REVIEW_DIFF.patch` for the complete patch.",
|
||||
"- Check `REVIEW_CHANGED_FILES.txt` for the list of modified files.",
|
||||
"- Inspect the included source and test files.",
|
||||
"",
|
||||
"## Recent Commit Log ($baseShortSha..$shortSha)",
|
||||
'```',
|
||||
$gitLogStat,
|
||||
'```'
|
||||
)
|
||||
$reviewContext = $reviewContextLines -join "`n"
|
||||
|
||||
[System.IO.File]::WriteAllText([System.IO.Path]::Combine($tempDir, "REVIEW_CONTEXT.md"), $reviewContext, $utf8NoBom)
|
||||
|
||||
# Compress staged directory
|
||||
[System.IO.Compression.ZipFile]::CreateFromDirectory($tempDir, $zipFilePath, [System.IO.Compression.CompressionLevel]::Optimal, $false)
|
||||
} finally {
|
||||
if (Test-Path -LiteralPath $tempDir) {
|
||||
Remove-Item -LiteralPath $tempDir -Recurse -Force -ErrorAction SilentlyContinue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# 6. Verify Archive & Display Summary
|
||||
$zip = [System.IO.Compression.ZipFile]::OpenRead($zipFilePath)
|
||||
$fileCount = $zip.Entries.Count
|
||||
$zip.Dispose()
|
||||
|
||||
$fileInfo = Get-Item -LiteralPath $zipFilePath
|
||||
$sizeBytes = $fileInfo.Length
|
||||
$sizeFormatted = if ($sizeBytes -ge 1MB) {
|
||||
"{0:N2} MB ({1:N0} bytes)" -f ($sizeBytes / 1MB), $sizeBytes
|
||||
} elseif ($sizeBytes -ge 1KB) {
|
||||
"{0:N2} KB ({1:N0} bytes)" -f ($sizeBytes / 1KB), $sizeBytes
|
||||
} else {
|
||||
"{0} bytes" -f $sizeBytes
|
||||
}
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "==================================================" -ForegroundColor Cyan
|
||||
Write-Host " Randomayzer Review Package Exported Successfully " -ForegroundColor Cyan
|
||||
Write-Host "==================================================" -ForegroundColor Cyan
|
||||
Write-Host ("Created: " + $zipFilePath) -ForegroundColor Green
|
||||
Write-Host ("Commit: " + $headSha + " (" + $shortSha + ")")
|
||||
Write-Host ("Mode: " + $modeName)
|
||||
Write-Host ("Files: " + $fileCount)
|
||||
Write-Host ("Size: " + $sizeFormatted)
|
||||
Write-Host "==================================================" -ForegroundColor Cyan
|
||||
|
||||
# 7. Optional Clipboard Prompt
|
||||
if ($CopyPrompt) {
|
||||
$clipboardPromptLines = @(
|
||||
"В приложенном архиве snapshot Randomayzer на commit $headSha.",
|
||||
"Используй архив как source of truth.",
|
||||
"Не используй GitHub HEAD вместо него.",
|
||||
"Выполни ранее выданное security review задание."
|
||||
)
|
||||
$clipboardPrompt = $clipboardPromptLines -join "`n"
|
||||
|
||||
try {
|
||||
if (Get-Command Set-Clipboard -ErrorAction SilentlyContinue) {
|
||||
Set-Clipboard -Value $clipboardPrompt
|
||||
Write-Host "Reviewer prompt copied to clipboard." -ForegroundColor Yellow
|
||||
} else {
|
||||
Write-Warning "Set-Clipboard is not available in this environment."
|
||||
}
|
||||
} catch {
|
||||
Write-Warning "Could not copy prompt to clipboard: $_"
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue