param( [string]$OutputDir = "runs/send-sandbox-gate-package", [switch]$NoZip ) $ErrorActionPreference = "Stop" Set-StrictMode -Version Latest $repo = (Resolve-Path -LiteralPath (Join-Path $PSScriptRoot "..")).Path $packageDir = Join-Path $repo $OutputDir $recorderRelative = Join-Path $OutputDir "recorder" $recorderDir = Join-Path $packageDir "recorder" $zipPath = "$packageDir.zip" if (Test-Path -LiteralPath $packageDir) { Remove-Item -LiteralPath $packageDir -Recurse -Force } if (Test-Path -LiteralPath $zipPath) { Remove-Item -LiteralPath $zipPath -Force } New-Item -ItemType Directory -Force -Path $packageDir | Out-Null & powershell -NoProfile -ExecutionPolicy Bypass -File (Join-Path $repo "scripts\package-live-probe-recorder.ps1") -OutputDir $recorderRelative -NoZip if ($LASTEXITCODE -ne 0) { throw "package-live-probe-recorder.ps1 failed with exit code $LASTEXITCODE" } if (-not (Test-Path -LiteralPath (Join-Path $recorderDir "ISphereLiveProbeRecorder.exe"))) { throw "recorder package was not created under $recorderDir" } @' R6c iSphere Send Sandbox Gate Package LOCAL_LOGIN_UNAVAILABLE: the development machine cannot log in to iSphere. ONLINE_SANDBOX_REQUIRED: run this package only on a machine/network where iSphere/IMPlatformClient can log in. Goal: - collect one operator-approved sandbox-send evidence package; - keep production send disabled in the repository; - return enough evidence to decide whether production send work can start later. What this package does: - runs the read-only live probe recorder before the manual sandbox send; - asks the operator to manually send exactly one sandbox message in the official client; - runs the same read-only recorder after the manual send; - zips the returned evidence folder. - provides RUN-RECORDING-SUITE.bat plus numbered 01/02/03 batch files so the operator can run the whole recording flow from this package. What this package does not do: - it does not send messages automatically; - it does not click or type; - it does not upload files; - it does not hook or inject into the client; - it does not enable production send. Required rule: - MANUAL_ONE_SEND_ONLY: send exactly one sandbox message manually. - DO_NOT_SEND_SECOND_TIME: do not send a second message with the same content or idempotency key. - Record content_sha256 and idempotency_key in SANDBOX-SEND-INPUTS.json. - Fill success_ack_or_sent_record after the operator sees the sent message, ack, or local sent record. Return: - run make-return-zip.ps1 and send back the generated zip. - preferred one-file flow: run RUN-RECORDING-SUITE.bat and follow the pauses. '@ | Set-Content -LiteralPath (Join-Path $packageDir "README.txt") -Encoding UTF8 @' # R6c Online Sandbox Send Gate - Operator Steps This package is for an online/internal sandbox only. Markers: - LOCAL_LOGIN_UNAVAILABLE: do not run this on the local development machine for proof. - ONLINE_SANDBOX_REQUIRED: run on a machine where iSphere/IMPlatformClient can log in. - MANUAL_ONE_SEND_ONLY: send exactly one test message manually. - DO_NOT_SEND_SECOND_TIME: do not repeat the send with the same idempotency_key. ## Step 1 - Prepare inputs 1. Copy `SANDBOX-SEND-INPUTS.template.json` to `SANDBOX-SEND-INPUTS.json`. 2. Fill: - `sandbox_target_type` - `sandbox_target_id` - `content_text_to_send` - `idempotency_key` 3. Run: ```powershell powershell -NoProfile -ExecutionPolicy Bypass -File .\compute-content-hash.ps1 -Text "" ``` 4. Copy the printed SHA256 into `content_sha256`. ## Step 2 - Before-send recording 1. Open and log in to iSphere/IMPlatformClient normally. 2. Open the sandbox target conversation. 3. Do not send anything yet. 4. Run `run-before-recorder.bat`. Alternative one-file flow: Run `RUN-RECORDING-SUITE.bat`. It will run the before recorder, pause for the manual one-send action, run the after recorder, and then call the return-zip script. ## Step 3 - Manual one-send action 1. In the official iSphere client, manually send exactly the `content_text_to_send`. 2. Send it only to the declared sandbox target. 3. Do not send a second copy. 4. Fill these fields in `SANDBOX-SEND-INPUTS.json`: - `manual_send_started_at_local` - `manual_send_finished_at_local` - `operator_observed_success` - `success_ack_or_sent_record` - `do_not_send_second_time_confirmed` ## Step 4 - After-send recording Run `run-after-recorder.bat`. ## Step 5 - Return package Run: ```powershell powershell -NoProfile -ExecutionPolicy Bypass -File .\make-return-zip.ps1 ``` Send back the generated zip file. You can also run `03-make-return-zip.bat`. ## Required returned evidence The returned evidence should contain: - before recorder output; - after recorder output; - completed `SANDBOX-SEND-INPUTS.json`; - success_ack_or_sent_record text; - confirmation that there was no second send. The repository must keep production send disabled until this evidence is reviewed. '@ | Set-Content -LiteralPath (Join-Path $packageDir "OPERATOR-STEPS.md") -Encoding UTF8 @' { "gate": "R6c online sandbox-send evidence gate", "LOCAL_LOGIN_UNAVAILABLE": true, "ONLINE_SANDBOX_REQUIRED": true, "MANUAL_ONE_SEND_ONLY": true, "DO_NOT_SEND_SECOND_TIME": true, "sandbox_target_type": "direct-or-group", "sandbox_target_id": "", "content_text_to_send": "", "content_sha256": "", "idempotency_key": "", "manual_send_started_at_local": "", "manual_send_finished_at_local": "", "operator_observed_success": false, "success_ack_or_sent_record": "", "do_not_send_second_time_confirmed": false, "notes": "" } '@ | Set-Content -LiteralPath (Join-Path $packageDir "SANDBOX-SEND-INPUTS.template.json") -Encoding UTF8 @' Expected return files for R6c: 1. SANDBOX-SEND-INPUTS.json - content_sha256 is filled. - idempotency_key is filled. - success_ack_or_sent_record is filled. - MANUAL_ONE_SEND_ONLY is true. - DO_NOT_SEND_SECOND_TIME is true. - do_not_send_second_time_confirmed is true. 2. return-evidence/before/* - Read-only recorder output before manual send. 3. return-evidence/after/* - Read-only recorder output after manual send. 4. The generated zip from make-return-zip.ps1. Decision rule: - If success_ack_or_sent_record is missing, production send remains blocked. - If duplicate/idempotency confirmation is missing, production send remains blocked. - If the target was not an explicit sandbox target, production send remains blocked. '@ | Set-Content -LiteralPath (Join-Path $packageDir "EXPECTED-RETURN-FILES.txt") -Encoding UTF8 @' @echo off setlocal cd /d "%~dp0" mkdir return-evidence 2>nul mkdir return-evidence\before 2>nul echo Running BEFORE read-only recorder... recorder\ISphereLiveProbeRecorder.exe --record-live-probe --out "%~dp0return-evidence\before" --no-pause echo Done. Check return-evidence\before. pause '@ | Set-Content -LiteralPath (Join-Path $packageDir "run-before-recorder.bat") -Encoding ASCII @' @echo off setlocal cd /d "%~dp0" mkdir return-evidence 2>nul mkdir return-evidence\after 2>nul echo Running AFTER read-only recorder... recorder\ISphereLiveProbeRecorder.exe --record-live-probe --out "%~dp0return-evidence\after" --no-pause echo Done. Check return-evidence\after. pause '@ | Set-Content -LiteralPath (Join-Path $packageDir "run-after-recorder.bat") -Encoding ASCII @' @echo off setlocal cd /d "%~dp0" call run-before-recorder.bat '@ | Set-Content -LiteralPath (Join-Path $packageDir "01-run-before-recorder.bat") -Encoding ASCII @' @echo off setlocal cd /d "%~dp0" echo Manual one-send action must already be complete before this step. call run-after-recorder.bat '@ | Set-Content -LiteralPath (Join-Path $packageDir "02-run-after-recorder.bat") -Encoding ASCII @' param( [Parameter(Mandatory=$true)] [string]$Text ) $bytes = [System.Text.Encoding]::UTF8.GetBytes($Text) $sha = [System.Security.Cryptography.SHA256]::Create() try { $hash = $sha.ComputeHash($bytes) -join ($hash | ForEach-Object { $_.ToString("x2") }) } finally { $sha.Dispose() } '@ | Set-Content -LiteralPath (Join-Path $packageDir "compute-content-hash.ps1") -Encoding ASCII @' $ErrorActionPreference = "Stop" Set-StrictMode -Version Latest $root = Split-Path -Parent $MyInvocation.MyCommand.Path $inputs = Join-Path $root "SANDBOX-SEND-INPUTS.json" if (-not (Test-Path -LiteralPath $inputs)) { throw "missing SANDBOX-SEND-INPUTS.json; copy the template and fill it first" } $before = Join-Path $root "return-evidence\before" $after = Join-Path $root "return-evidence\after" if (-not (Test-Path -LiteralPath $before)) { throw "missing before recorder output: $before" } if (-not (Test-Path -LiteralPath $after)) { throw "missing after recorder output: $after" } $stamp = Get-Date -Format "yyyyMMdd-HHmmss" $zip = Join-Path $root ("isphere-send-sandbox-return-" + $stamp + ".zip") $items = @( $inputs, (Join-Path $root "return-evidence"), (Join-Path $root "EXPECTED-RETURN-FILES.txt") ) Compress-Archive -Path $items -DestinationPath $zip -Force [ordered]@{ ok = $true zip = $zip production_send_enabled = $false online_sandbox_required = $true } | ConvertTo-Json -Depth 4 -Compress '@ | Set-Content -LiteralPath (Join-Path $packageDir "make-return-zip.ps1") -Encoding ASCII @' @echo off setlocal cd /d "%~dp0" powershell -NoProfile -ExecutionPolicy Bypass -File "%~dp0make-return-zip.ps1" echo exit code: %ERRORLEVEL% pause exit /b %ERRORLEVEL% '@ | Set-Content -LiteralPath (Join-Path $packageDir "03-make-return-zip.bat") -Encoding ASCII @' @echo off setlocal cd /d "%~dp0" echo R6c online sandbox-send recording suite echo. echo Step 1: BEFORE read-only recorder. call "%~dp0run-before-recorder.bat" echo. echo Step 2: manual one-send action. echo In the official iSphere client, manually send exactly one sandbox message. echo Fill SANDBOX-SEND-INPUTS.json before continuing. pause echo. echo Step 3: AFTER read-only recorder. call "%~dp0run-after-recorder.bat" echo. echo Step 4: make return zip. powershell -NoProfile -ExecutionPolicy Bypass -File "%~dp0make-return-zip.ps1" echo exit code: %ERRORLEVEL% pause exit /b %ERRORLEVEL% '@ | Set-Content -LiteralPath (Join-Path $packageDir "RUN-RECORDING-SUITE.bat") -Encoding ASCII @' { "package": "send-sandbox-gate", "LOCAL_LOGIN_UNAVAILABLE": true, "ONLINE_SANDBOX_REQUIRED": true, "MANUAL_ONE_SEND_ONLY": true, "DO_NOT_SEND_SECOND_TIME": true, "entrypoint": "RUN-RECORDING-SUITE.bat", "numbered_steps": [ "01-run-before-recorder.bat", "02-run-after-recorder.bat", "03-make-return-zip.bat" ], "recorder": "recorder/ISphereLiveProbeRecorder.exe", "return_inputs": "SANDBOX-SEND-INPUTS.json", "production_send_enabled": false } '@ | Set-Content -LiteralPath (Join-Path $packageDir "RECORDING-PACKAGE-MANIFEST.json") -Encoding ASCII if (-not $NoZip) { Compress-Archive -Path (Join-Path $packageDir "*") -DestinationPath $zipPath -Force } [ordered]@{ ok = $true package_dir = (Resolve-Path -LiteralPath $packageDir).Path recorder_dir = (Resolve-Path -LiteralPath $recorderDir).Path zip = if (Test-Path -LiteralPath $zipPath) { (Resolve-Path -LiteralPath $zipPath).Path } else { $null } local_login_required = $false online_sandbox_required = $true production_send_enabled = $false } | ConvertTo-Json -Depth 4 -Compress