feat(§3.3): Implement Gitea PAT auth for guest-side git clone
Credential Manager target 'GiteaPAT' (default) read on host, passed securely to guest WinRM session. Token never appears in argv, URL, or logs. Guest auth flow (§1.5 compliant): 1. Host reads PAT via Get-StoredCredential -Target GiteaPAT 2. Username + password passed as ArgumentList to Invoke-Command 3. Guest writes temp .git-credentials file (https://user:token@host) 4. git clone uses: -c 'credential.helper=store --file <tmp>' 5. finally{} deletes credentials file regardless of clone success/fail Setup (one-time on host): New-StoredCredential -Target 'GiteaPAT' -UserName '<user>' ` -Password '<pat>' -Persist LocalMachine Invoke-CIJob.ps1: added -GiteaCredentialTarget param (default: 'GiteaPAT'), passed through to Invoke-RemoteBuild when -UseGitClone is set. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -100,6 +100,11 @@ param(
|
|||||||
# Prerequisite: Git for Windows installed in template.
|
# Prerequisite: Git for Windows installed in template.
|
||||||
[switch] $UseGitClone,
|
[switch] $UseGitClone,
|
||||||
|
|
||||||
|
# Credential Manager target for Gitea PAT used by -UseGitClone (private repos).
|
||||||
|
# Store with: New-StoredCredential -Target 'GiteaPAT' -UserName '<user>' -Password '<pat>' -Persist LocalMachine
|
||||||
|
# Ignored when -UseGitClone is not set.
|
||||||
|
[string] $GiteaCredentialTarget = 'GiteaPAT',
|
||||||
|
|
||||||
[string] $TemplatePath = $env:GITEA_CI_TEMPLATE_PATH,
|
[string] $TemplatePath = $env:GITEA_CI_TEMPLATE_PATH,
|
||||||
|
|
||||||
[string] $SnapshotName = $(if ($env:GITEA_CI_SNAPSHOT_NAME) { $env:GITEA_CI_SNAPSHOT_NAME } else { 'BaseClean' }),
|
[string] $SnapshotName = $(if ($env:GITEA_CI_SNAPSHOT_NAME) { $env:GITEA_CI_SNAPSHOT_NAME } else { 'BaseClean' }),
|
||||||
@@ -375,9 +380,9 @@ try {
|
|||||||
}
|
}
|
||||||
if ($UseGitClone) {
|
if ($UseGitClone) {
|
||||||
# §3.3: Clone in VM — pass URL/branch/commit instead of HostSourceDir
|
# §3.3: Clone in VM — pass URL/branch/commit instead of HostSourceDir
|
||||||
# PAT will be read from Credential Manager inside Invoke-RemoteBuild (§1.5)
|
|
||||||
$remoteBuildParams['CloneUrl'] = $RepoUrl
|
$remoteBuildParams['CloneUrl'] = $RepoUrl
|
||||||
$remoteBuildParams['CloneBranch'] = $Branch
|
$remoteBuildParams['CloneBranch'] = $Branch
|
||||||
|
$remoteBuildParams['GiteaCredentialTarget'] = $GiteaCredentialTarget
|
||||||
if ($Commit -ne '') { $remoteBuildParams['CloneCommit'] = $Commit }
|
if ($Commit -ne '') { $remoteBuildParams['CloneCommit'] = $Commit }
|
||||||
if ($Submodules) { $remoteBuildParams['CloneSubmodules'] = $true }
|
if ($Submodules) { $remoteBuildParams['CloneSubmodules'] = $true }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -99,6 +99,11 @@ param(
|
|||||||
# [Mode 2] Clone with --recurse-submodules. Ignored if HostSourceDir provided.
|
# [Mode 2] Clone with --recurse-submodules. Ignored if HostSourceDir provided.
|
||||||
[switch] $CloneSubmodules,
|
[switch] $CloneSubmodules,
|
||||||
|
|
||||||
|
# [Mode 2] Credential Manager target for Gitea PAT (private repos).
|
||||||
|
# Store with: New-StoredCredential -Target 'GiteaPAT' -UserName '<user>' -Password '<pat>' -Persist LocalMachine
|
||||||
|
# Leave empty for public repos (no auth needed).
|
||||||
|
[string] $GiteaCredentialTarget = 'GiteaPAT',
|
||||||
|
|
||||||
[string] $Configuration = 'Release',
|
[string] $Configuration = 'Release',
|
||||||
|
|
||||||
# Custom build command to run inside the VM (working dir = GuestWorkDir).
|
# Custom build command to run inside the VM (working dir = GuestWorkDir).
|
||||||
@@ -217,30 +222,40 @@ try {
|
|||||||
# PAT (if needed) read from Credential Manager inside session, never logged
|
# PAT (if needed) read from Credential Manager inside session, never logged
|
||||||
Write-Host "[Invoke-RemoteBuild] Cloning repository in guest (§3.3)..."
|
Write-Host "[Invoke-RemoteBuild] Cloning repository in guest (§3.3)..."
|
||||||
|
|
||||||
# Read PAT from Credential Manager (for private repos)
|
# Read PAT from host Credential Manager (§1.5: never in argv or logs)
|
||||||
# This runs in the HOST session, but PAT is passed securely to guest session only
|
$gitPatUser = $null
|
||||||
$gitPat = $null
|
$gitPatPass = $null
|
||||||
|
if (-not [string]::IsNullOrWhiteSpace($GiteaCredentialTarget)) {
|
||||||
try {
|
try {
|
||||||
# Try to load PAT from Credential Manager target 'git:https://gitea.emulab.it/...' or similar
|
$stored = Get-StoredCredential -Target $GiteaCredentialTarget -ErrorAction Stop
|
||||||
# For now, we assume public or ssh-key auth; if needed, caller provides CI_GIT_PAT env
|
$gitPatUser = $stored.UserName
|
||||||
# In future: $gitPat = (Get-StoredCredential -Target 'git:...' -ErrorAction SilentlyContinue).GetNetworkCredential().Password
|
$gitPatPass = $stored.GetNetworkCredential().Password
|
||||||
|
Write-Host "[Invoke-RemoteBuild] PAT loaded from Credential Manager ($GiteaCredentialTarget)."
|
||||||
} catch {
|
} catch {
|
||||||
Write-Warning "[Invoke-RemoteBuild] Could not read git PAT from Credential Manager (proceeding without auth)."
|
Write-Warning "[Invoke-RemoteBuild] Could not read PAT from Credential Manager '$GiteaCredentialTarget' — proceeding without auth (public repo only)."
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# Clone in guest via WinRM
|
# Clone in guest via WinRM
|
||||||
Invoke-Command -Session $session -ScriptBlock {
|
Invoke-Command -Session $session -ScriptBlock {
|
||||||
param($cloneUrl, $branch, $commit, $workDir, $pat, $submodules)
|
param($cloneUrl, $branch, $commit, $workDir, $patUser, $patPass, $submodules)
|
||||||
# Set PAT as env var (never in argv or logs)
|
|
||||||
if ($pat) {
|
|
||||||
$env:GITLAB_PRIVATE_TOKEN = $pat # or appropriate token name for your git server
|
|
||||||
}
|
|
||||||
|
|
||||||
Set-Location (Split-Path $workDir -Parent)
|
Set-Location (Split-Path $workDir -Parent)
|
||||||
$gitArgs = @('clone', '--depth', '1', '--branch', $branch)
|
$gitArgs = @('clone', '--depth', '1', '--branch', $branch)
|
||||||
if ($submodules) { $gitArgs += '--recurse-submodules' }
|
if ($submodules) { $gitArgs += '--recurse-submodules' }
|
||||||
$gitArgs += @($cloneUrl, (Split-Path $workDir -Leaf))
|
$gitArgs += @($cloneUrl, (Split-Path $workDir -Leaf))
|
||||||
|
|
||||||
|
# Credentials via temp .git-credentials file (§1.5: token never in URL, argv, or logs)
|
||||||
|
$tmpCreds = $null
|
||||||
|
if ($patUser -and $patPass) {
|
||||||
|
$uri = [uri]$cloneUrl
|
||||||
|
$credLine = "$($uri.Scheme)://${patUser}:${patPass}@$($uri.Host)"
|
||||||
|
$tmpCreds = "C:\CI\tmp_gc_$([guid]::NewGuid().ToString('N'))"
|
||||||
|
[System.IO.File]::WriteAllText($tmpCreds, $credLine)
|
||||||
|
$gitArgs = @('-c', "credential.helper=store --file $tmpCreds") + $gitArgs
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
Write-Host "[Guest] Cloning $cloneUrl (branch: $branch)..."
|
Write-Host "[Guest] Cloning $cloneUrl (branch: $branch)..."
|
||||||
& git @gitArgs 2>&1 | ForEach-Object { Write-Host "[Guest Clone] $_" }
|
& git @gitArgs 2>&1 | ForEach-Object { Write-Host "[Guest Clone] $_" }
|
||||||
if ($LASTEXITCODE -ne 0) {
|
if ($LASTEXITCODE -ne 0) {
|
||||||
@@ -256,10 +271,13 @@ try {
|
|||||||
throw "git checkout $commit failed in guest (exit $LASTEXITCODE)"
|
throw "git checkout $commit failed in guest (exit $LASTEXITCODE)"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} finally {
|
||||||
# Clear PAT from environment (§1.5: cleanup)
|
# Always delete credentials file (§1.5: cleanup)
|
||||||
if ($env:GITLAB_PRIVATE_TOKEN) { Remove-Item env:GITLAB_PRIVATE_TOKEN -ErrorAction SilentlyContinue }
|
if ($tmpCreds -and (Test-Path $tmpCreds)) {
|
||||||
} -ArgumentList $CloneUrl, $CloneBranch, $CloneCommit, $GuestWorkDir, $gitPat, $CloneSubmodules.IsPresent
|
Remove-Item $tmpCreds -Force -ErrorAction SilentlyContinue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} -ArgumentList $CloneUrl, $CloneBranch, $CloneCommit, $GuestWorkDir, $gitPatUser, $gitPatPass, $CloneSubmodules.IsPresent
|
||||||
|
|
||||||
Write-Host "[Invoke-RemoteBuild] Guest clone complete."
|
Write-Host "[Invoke-RemoteBuild] Guest clone complete."
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user