OTCHE WINDOWS SOURCE SETUP / WORKER CONTRACT

Prerequisites and trust
- Windows 10/11 with Windows PowerShell Desktop 5.1, NTFS C:, QEMU Guest Agent,
  working display driver, Task Scheduler, active Defender, and an existing dedicated
  local non-RID500 administrator account with its existing password. Operator selects
  it explicitly with Get-Credential. Installer neither creates nor modifies accounts.
- UAC must already be enabled. Limited and Highest tasks use the same account's
  split interactive token. The user task is never elevated; admin is never silently
  downgraded. Actual account SID, console session and TokenElevation are checked.
  'user' means the filtered (Limited) token of this prepared local administrator,
  NOT a separate standard account. An account such as OtcheUser may exist harmlessly
  but is not used by the runner. True standard-user semantics require a separate
  source/profile whose console account is a standard user; this installer does not
  support that model. With the default ConsentPromptBehaviorAdmin=5, eligible Windows
  components can auto-elevate; Limited is not a guarantee against UAC bypasses. The
  installer records policy but never changes UAC or other protection settings.
- Restricted blocks ALL script files, including signed installer and signed runner.
  First obtain an independently approved organizational script-execution policy.
  Recommended: AllSigned, with every supplied .ps1 and .psm1 signed by an approved
  code-signing certificate trusted by LocalMachine and the selected account. Verify
  signatures with Get-AuthenticodeSignature. Sign only after reviewing final files.
  RemoteSigned requires valid signatures on downloaded/Internet-zoned scripts.
  No policy switch, Unblock-File, EncodedCommand, paste-to-evade-policy, or Bypass is
  supported. Interactive pasting does not solve Restricted blocking scheduled files.
  AppLocker/WDAC/ConstrainedLanguage must independently permit the reviewed runner,
  native Add-Type helpers and selected execution hosts. Protection stays enabled.
- Run elevated: .\Install-OtcheSource.ps1 -Credential (Get-Credential
  "$env:COMPUTERNAME\LabRunner") -EnableAutoLogon
  This command is one line. Omitting EnableAutoLogon leaves login to the operator.
  The password is validated, never reset; opt-in autologon stores only an LSA private
  secret. It refuses existing autologon/DefaultPassword configuration rather than
  overwriting it. LSA secrets remain recoverable by SYSTEM/admins: protect master,
  clones, exports and backups. Installation failures require operator inspection;
  installer does not destructively rollback accounts, registry or existing evidence.
- Maintenance (run elevated under the existing approved policy; no credential):
    .\Install-OtcheSource.ps1 -Verify
  Read-only JSON {ok,errors[]} checks directory ACL shape, local account SID,
  all four task principals/actions/working directories, on-demand/enabled state,
  Winlogon autologon/account values, and installed/supplied runner signatures and
  SHA256 equality. Both copies must have Valid trusted Authenticode signatures for
  AllSigned compatibility, even if the current policy is RemoteSigned. Without
  configured autologon, DefaultUserName is not required. This cannot verify the
  password stored in LSA or replace the real desktop/clone qualification check.
    .\Install-OtcheSource.ps1 -UpdateRunner
  Use the reviewed, newly signed installer bundle beside the six runner files on a
  source explicitly taken out of publication for maintenance. Stops on source/ACL/
  task/autologon drift or a busy task, before copying anything. Requires Valid
  trusted signatures for all six replacement files; stages all as .new, checks
  their hashes, then uses atomic per-file replacement preserving existing ACLs.
  ISO ReadOnly attributes are removed only from owned installed/staged copies,
  never from the source media; other attribute bits and ACLs are preserved. Updates
  clear a legacy target's ReadOnly bit only after all staged files pass validation,
  restoring original target attributes if replacement fails. A stale .new is reused
  only if it is a regular, non-reparse file whose hash matches the signed bundle;
  unrecognized staging files are left untouched for inspection. Cleanup failures
  are warnings when another failure is already pending, preserving its real cause.
  No task, account, registry, autologon secret or directory ACL is changed. The JSON
  output is the NEW Get-OtcheBaseline, not qualification. Do not dispatch during
  maintenance. Replacement is atomic per file, not a six-file transaction: if an
  I/O failure interrupts replacement, correct the failure and rerun -UpdateRunner,
  then -Verify. Existing installed-baseline.json is installation evidence, not
  rewritten by an update. Re-sign changed files, reboot/check the desktop as needed,
  and requalify disposable clones before republishing the source revision.
- No disk is initialized or formatted and no evidence disk is assumed. Artifacts
  use existing NTFS C:. The full source remains an ordinary stopped VM template=0.
  Operator reboots and verifies a real active console desktop before stopping it.
  Complete first-login privacy/setup through the real UI. An active WTS session alone
  is insufficient: the input desktop must be unlocked Default, with the expected
  account's real Explorer shell and visible taskbar, and no visible setup/sign-in host.
  Worker clones CURRENT disks with full=1, never a snapshot name. Never alter master.
  For a source without CD, provision an empty CD on the stopped CLONE, not the source.
- These files do not establish network isolation. Worker must remove clone NICs
  BEFORE media delivery in offline mode and prove fail-closed isolation for online.
  Sample delivery follows recorder writable-sink + full-frame readiness only.

Worker commands (native System32 WindowsPowerShell\v1.0\powershell.exe):
  -NoProfile -NonInteractive -File C:\ProgramData\Otche\runner\Test-OtcheReady.ps1 -Privilege user
  -NoProfile -NonInteractive -File C:\ProgramData\Otche\runner\Start-OtcheCommand.ps1 -ManifestPath C:\ProgramData\Otche\control\<command UUID>.json
Invoke-Otche.ps1 -ManifestPath is the installed interactive runner interface. QGA
never invokes the sample or submits a generic shell command. The fixed scheduler
starts prepared InteractiveToken tasks (Limited/Highest), plus a separate SYSTEM
Defender collector. All commands and control JSON must be short/bounded; use ISO
for samples and bounded QGA file-open/read offsets for binary artifacts. Mutable
JSON uses the worker's fixed read-only PowerShell snapshot with ReadWrite|Delete
sharing, closed before output, never file contents as code or a policy bypass.
No repeated file-write overwrites, credential, password or PVE token in a manifest.
Readiness uses a fixed Otche-DesktopReady InteractiveToken/Limited task running the
signed Test-OtcheReady.ps1 -Privilege user -DesktopProbe with no command/input API.
Each request has a new nonce and 60-second deadline; bounded response must match the
nonce, boot ID, configured account and active console session. The task is limited
to 90 seconds and runs without opening a console window. UserOOBEBroker residency
and arbitrary WWAHost applications are not treated as unfinished setup.
This bounded startup budget includes normal Authenticode/native-helper initialization
when an allowlist blocks certificate-network lookups; signature checks are not disabled.
The worker waits for the accepted QGA PID to exit and never overlaps readiness scripts.
Approved -UpdateRunner maintenance migrates the previous 15-second task budget.
Deadline timestamps are parsed with invariant RoundtripKind and normalized to UTC;
the guest may use any Windows time zone (UTC is no longer a prerequisite). The clock
still must be correct. Probe responses use results\desktop-probe-<nonce>.json; the
caller deletes its consumed response and checks at most 128 probe files per request
for stale responses older than 60 seconds. Session/task/desktop failures return
ready=false with error and baseline=null, without performing a full baseline. Only
a successful desktop probe pays for one baseline; -BaselineOnly still collects it
without probing sample-owned UI.
The normal readiness gate runs before media/dispatch; the actual runner repeats
desktop/token checks once before launch. During observation, -BootOnly returns only
the boot ID without launching a desktop probe. Post-run -BaselineOnly collects the
full source/Defender baseline without reinterpreting sample-owned GUI as setup.

Manifest (JSON data, max 1 MiB): command_id, attempt_id, job_id (canonical UUIDs),
iso_label OT<first 14 uppercase hexadecimal job UUID characters> (16 ASCII characters, identical ISO9660/Joliet labels), sha256 (lowercase),
filename (execution_filename selected ONCE by worker per Job), settings from API.
Settings require architecture auto|x86|x64, wsh_host cscript|wscript, msi_ui
full|quiet|passive, plus existing fields. args is a JSON string array; only
{sample.path}/{sample.name} are expanded. ISO root job.json contains job_id,
sha256,filename,iso_label; payload is sample/<filename>, unchanged original bytes.
Optional root qualification='benign'|'eicar'. EICAR is delivery-only, never started.
Fixture generation is a separate explicit disposable-only script, never installer.
Its short-lived machine-bound qualification marker is placed only on a clone.

Results: C:\ProgramData\Otche\results\<command UUID>\
- receipt.json: command_id,attempt_id,job_id,state accepted|running,accepted_at,
  started_at,deadline_at,session_id,user,privilege,pid,boot_id.
- status.json refreshed about every 3 seconds, result.json atomically terminal:
  command_id,attempt_id,job_id,phase,outcome,findings,telemetry,started_at,deadline_at,
  finished_at,error,report,artifacts[{path,filename,kind,content_type}]. report matches
  docs/API.md. Artifacts are bounded JSON/log files; preserve them if collection fails.
- receipt CreateNew precedes scheduling; dispatch.json CreateNew precedes runner
  activity. One clone accepts exactly one command. Existing receipt => duplicate,
  NEVER rerun after failure/crash. accepted receipt has null started_at/deadline_at;
  these become real timestamps only after selected sample host Process.Start succeeds.
  Preparation failure/quarantine never invents startup/duration/PID. Worker enforces
  a preparation deadline and then external runtime from started_at/deadline_at.
- Full observation uses Stopwatch and continues when the parent exits; descendants
  are not guessed from installed applications. Worker stops clone after collection.
  Unexpected reboot/disconnect is externally interrupted, never resumed/reset.
- Test-OtcheReady returns ready,session_id,user,privilege,boot_id,baseline
  {fingerprint,qualified,errors},defender,environment,error. qualified here means
  readable active prerequisites, NOT a published qualified revision. Worker compares
  observed fingerprint with externally qualified revision; drift or unreadable
  required telemetry is unqualified. Baseline fingerprints include full OS build,
  runner hashes/signatures, PS policy, Defender versions/preferences and security
  state. environment.security contains uac.{EnableLUA,ConsentPromptBehaviorAdmin,
  PromptOnSecureDesktop,FilterAdministratorToken}, smart_app_control (CI\Policy
  VerifiedAndReputablePolicyState), secure_boot (SecureBoot\State
  UEFISecureBootEnabled), and device_guard.{EnableVirtualizationBasedSecurity,
  RequirePlatformSecurityFeatures,HVCIEnabled}. Absent registry values are null;
  EnableLUA other than 1 makes the baseline unqualified. Secure Boot uses the
  user-readable registry value, never an elevated-only Confirm-SecureBootUEFI call.
  The Win32_DeviceGuard CIM snapshot is baseline.device_guard_runtime (null if
  unavailable): VirtualizationBasedSecurityStatus, SecurityServicesConfigured,
  SecurityServicesRunning, CodeIntegrityPolicyEnforcementStatus and
  UsermodeCodeIntegrityPolicyEnforcementStatus. This token-dependent diagnostic is
  NOT fingerprinted; registry DeviceGuard/HVCI configuration is. Thus these new
  fingerprint fields do not differ solely because a token is Limited vs Highest.
  Intelligence or security-state updates can change fingerprints; requalify rather
  than silently accept drift.

Dispatch and evidence semantics
- EXE/SCR/PE COM direct; DOS16/non-PE COM explicitly incompatible. PE x86/x64 chooses
  matching hosts; unsupported machines/architecture mismatch fail before dispatch.
- DLL regsvr32 requires actual DllRegisterServer export. rundll32 requires explicitly
  requested actual named/ordinal export, never guessed. Existence does not establish
  a compatible ABI; operator must choose a rundll32-compatible export. Commas in DLL
  paths are rejected. Native CRT quoting is separate from rundll32's module syntax.
- PS1 uses -File and no execution-policy bypass. WSH uses requested cscript/wscript.
  CMD/BAT uses fixed cmd /d /s /v:off /c with per-process environment transport and
  one nonrecursive percent substitution, not concatenation of user text into shell
  source. Delayed expansion remains OFF. Reports retain resolved original argument
  values, never internal environment-variable aliases.
  Actual CMD and BAT fixtures preserve spaces, Unicode, a&b, (parentheses), literal%,
  literal %PATH%, !bang!, caret^value, comma/semicolon/equal, empty strings, trailing
  backslashes, and balanced literal quotes such as say"hello". A terminal value a"b
  is also supported. These are measured cases, not a claim about every batch script's
  own argument processing (a script can itself reinterpret values through CALL/etc.).
  Native batch parameters have no general CRT-style quote escape. An unmatched quote
  in a NONFINAL value consumes following arguments: requesting [a"b, tail] yields
  first value a"b" "tail and no second value in the direct native control. The runner
  rejects that case. Inner quotes exposing spaces/tabs/comma/semicolon/equal also
  split native parameters: say "two words" is not one exact literal parameter.
  These specific boundaries, NUL/CR/LF, and the bounded cmd line limit fail explicitly;
  there is no blanket percent/metacharacter/quote rejection. A batch script needing
  otherwise unrepresentable text needs its own explicit data-file interface, not
  silently changed argument bytes. No generic shell API is added.
- MSI keeps /i <selected sample>, required /L*V <command MSI log>, and selected UI.
  Explicit custom install modifiers /norestart, /promptrestart, /forcerestart,
  /m <SMS MIF basename <=8 characters>, /n <instance ProductCode GUID> are accepted,
  alongside PROPERTY=value entries. /promptrestart with quiet UI is natively invalid.
  Operation/package replacements (/x, another /i, /a, /j, /p, /y, /z, etc.), custom
  log/UI switches and ACTION/UILEVEL properties cannot replace controlled invariants.
  Property values use Windows Installer syntax, not CRT backslash escaping:
  COMPANY=Acme "Widgets" becomes COMPANY="Acme ""Widgets"""; empty values and trailing
  backslashes remain literal. /m requires the environment's real SMS ISMIF32.DLL;
  no successful status-file generation is claimed from command construction alone.
  No implicit installed-application launch. Reboots are suppressed ONLY if explicitly
  requested by the submitted arguments; actual reboot is externally interrupted.
  Exit 3010 means reboot required; 1641 means reboot initiated, not Defender blocking.
  Microsoft command syntax references:
  https://learn.microsoft.com/en-us/windows/win32/msi/command-line-options
  https://learn.microsoft.com/en-us/windows/win32/msi/standard-installer-command-line-options
- SHA256 checks original ISO and isolated NTFS copy. ZoneId=3 is written only when on;
  off never removes a stream or unblocks. Missing file without correlated detection
  remains unknown/delivery_error. There is no retry after early quarantine.
- SYSTEM collector records Defender state/preferences before and after, correlated
  detections and Defender/AppLocker/CodeIntegrity events by time and sample path.
  Ordinary operational/audit events are not declared blocks. No SmartScreen result
  is invented from a dialog/exit. Crash/status exit differs from policy evidence.
  Collector publishes telemetry.json with initial=true immediately after the first
  successful Defender snapshot (after=before, empty detections), before querying
  detections/event logs or taking a second snapshot. This removes those queries
  from the start gate (normally targeting 1-3 seconds, not a timing guarantee).
  Invoke-Otche permits up to 90 seconds instead of 30 and still fails closed on
  missing/inactive/error telemetry. Subsequent snapshots set initial=false.
  Event channels use independent EventRecordID cursors plus the original UTC time
  filter, oldest-first bounded batches, avoiding repeated XML work. Threat detection
  queries still run every loop; threat-name metadata is queried only when a new
  correlated detection needs it. Collection loops sleep three seconds after work.
- Detection lists cap 64 (4 resources x 1 KiB), event lists 128, queries 200/channel,
  Defender queries 256, event XML 4 KiB,
  control JSON 1 MiB, output JSON 2 MiB, stdout/stderr 1 MiB, exported MSI log 4 MiB.
  Raw MSI logging can grow during observation; disposable disk must have capacity.
  Truncated/unreadable evidence is partial, not clean. Sample processes share their
  runner token and admin samples can alter guest evidence; external video and worker
  timestamps remain independent. Guest artifacts are observations, not tamper-proof.

Verification boundary
Local AST/harmless quoting/native helper smoke checks do not qualify a guest image.
Only real disposable-clone readiness, recorded benign controls and EICAR delivery,
with identical before/after fingerprint and collected evidence, qualify a revision.
The reproducible harmless regression is Test-OtcheArguments.ps1 (run normally under
the existing approved policy). It compiles a temporary benign environment reader,
executes both .cmd/.bat fixtures, prints the native unmatched-quote counterexample,
checks literal resolved argument values and MSI construction, and deletes its files.
Run local tests only under an approved existing policy; they do not authorize source or protection changes.

Grub optional file snapshots
- settings.grub_paths is an immutable bounded literal array: max32 paths, 1024 UTF8
  bytes/path, 8192 total. Exact local absolute DOS paths only; no environment/sample
  expansion. Percent/braces are ordinary filename characters. No directories/globs,
  UNC/devices/ADS/traversal, hard links or reparse points. Open handles must resolve
  to the verified actual local fixed NTFS volume, not merely a checked drive letter.
- Invoke-Otche captures after the observation deadline on its existing selected
  interactive token. It shares reads/writes (not delete), pins ancestor handles,
  captures at most open length and compares a second bounded read plus size/write
  metadata. Concurrent readable logs work; detected changes retain explicit
  best_effort snapshots, never assert atomic consistency. Unknown size/hash are null;
  zero bytes is a real captured empty file. Per-file failures do not change Defender.
- grub_limits is controller-only manifest data: per-file <=8MiB, total <=32MiB,
  further restricted by max_artifact_bytes/2 and collection deadline. No credentials.
  Numbered results/grub-NNN.bin are transient selected-user snapshots. SYSTEM only
  safe-opens those fixed files, verifies size/hash, copies into protected
  control/grub-<command>-NNN.bin and publishes a bounded export-ready receipt.
  Requested file paths are never read by SYSTEM or on the host. Raw staged copies
  are not individual artifacts; controller streams one ZIP with safe numbered
  members and a per-file manifest, commits it before allowed clone cleanup.
- Test-OtcheGrub.ps1 is a harmless local helper regression (not source qualification):
  actual live writer/read sharing, identical basenames, empty/missing/denied files,
  literal percent/braces, byte limits and device/network/traversal/reparse rejection.
