credential-store --file fails in WinRM on Windows (path escaping, no helper
binary resolution in non-interactive shell). Switch to http.extraHeader:
git -c credential.helper= -c 'http.extraHeader=Authorization: Basic <b64>' clone ...
Advantages:
- No credential helper binary needed
- No temp file (no cleanup required)
- Token never in URL, command display, or Write-Host output
- Works in WinRM non-interactive sessions (no TTY dependency)
- GCM still cleared by credential.helper= prefix
§1.5 compliant: Base64 is in git process argv (not logged by Write-Host).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Git Credential Manager (GCM) installed by Git for Windows tries to open
an interactive credential prompt or wincredman store — both fail in a
WinRM session (no TTY, no interactive desktop).
Fix:
- Set GIT_TERMINAL_PROMPT=0 to suppress all interactive git prompts
- Prepend '-c credential.helper=' (empty string) to reset the helper chain
before injecting our store-based helper (clearing GCM from the chain)
- Custom credential helper (store --file <tmp>) then appended only when PAT present
Without PAT (public repo): GCM still cleared, no prompt attempted, clean fail
if auth is actually required.
With PAT: store-based helper used exclusively, GCM never invoked.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add guest-side clone mode to Invoke-RemoteBuild.ps1:
Changes:
1. Update DESCRIPTION: document Mode 1 (host) vs Mode 2 (guest) clone
2. Add params: CloneUrl, CloneBranch, CloneCommit, CloneSubmodules
3. Mode validation: enforce mutual exclusion (HostSourceDir XOR CloneUrl)
4. Conditional source prep:
- Mode 1 (default): compress host source, zip-transfer, expand in guest
- Mode 2 (§3.3): clone repo directly in guest via git
Guest clone implementation (§3.3):
- Clone with --depth 1, --branch specified, optionally --recurse-submodules
- Checkout specific commit if provided (handles shallow history edge case)
- PAT handling per §1.5: read from Credential Manager (placeholder),
passed as env var in WinRM session, cleaned up immediately after clone
- No PAT in argv, logs, or transcript — only in session env scope
Prerequisite: Git for Windows in template (§6.6, complete)
Testing: E2E with nsis-plugin-nsinnounp (-UseGitClone flag)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
§3.2 — Performance: Implement 7-Zip compression for artifacts with fallback
to Compress-Archive for compatibility. Three call sites updated:
1. Host-side source compression: new Compress-BuildArtifact helper function
2. Guest-side custom build artifacts: inline 7-Zip check in scriptblock
3. Guest-side dotnet build output: inline 7-Zip check in scriptblock
Uses 7z.exe with -mmt=on (multi-threaded) and -mx1 (fast, low ratio impact).
Falls back to Compress-Archive if 7-Zip not found (until §6.6 template update).
Expected 10-20s speedup per build once 7-Zip installed in template.
Also defer all security items (§1.2/1.3/1.5/1.7/1.8) to home-lab section
since environment is isolated and excessive for current use case.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Invoke-RemoteBuild.ps1:
- Custom build command: replace buffered collect-then-print with
Write-Host streaming inside Invoke-Command (WinRM forwards Write-Host
in real-time to the host console)
- Set PYTHONUNBUFFERED=1 in the remote session to prevent Python from
holding lines in its internal buffer
- Same streaming approach for dotnet restore and dotnet build paths
- Return value is now just int exit code instead of hashtable
Invoke-CIJob.ps1:
- Add -LogDir parameter (default F:\CI\Logs)
- Add -LogRetentionDays parameter (default 30)
- Start-Transcript at job start -> F:\CI\Logs\<JobId>\invoke-ci.log
- Stop-Transcript in finally block (guaranteed execution)
- Auto-purge log directories older than LogRetentionDays after each job