src/public/Security/Initialize-AitherSecrets.ps1
|
#Requires -Version 7.0 <# .SYNOPSIS Loads stored AitherZero secrets into environment variables for local development. .DESCRIPTION Automatically loads API keys from the local encrypted vault into environment variables, eliminating the need to manually set .env files. This enables a seamless workflow: 1. Store secrets once: Set-AitherCredential -Name "OPENAI_API_KEY" -ApiKey $key 2. Initialize at session start: Initialize-AitherSecrets 3. Use normally: $env:OPENAI_API_KEY is available Secrets are loaded from the encrypted local vault, not from GitHub. .PARAMETER Names Specific secret names to load. If not provided, loads all API keys. .PARAMETER Prefix Only load secrets matching this prefix (e.g., "OPENAI", "ANTHROPIC"). .PARAMETER Scope Environment variable scope: Process (default), User, or Machine. .PARAMETER NoClobber Don't overwrite existing environment variables. .EXAMPLE Initialize-AitherSecrets Loads all stored API keys into the current process environment. .EXAMPLE Initialize-AitherSecrets -Names "OPENAI_API_KEY", "ANTHROPIC_API_KEY" Loads specific API keys. .EXAMPLE Initialize-AitherSecrets -Prefix "GOOGLE" Loads all secrets starting with "GOOGLE" (GOOGLE_API_KEY, GOOGLE_PROJECT_ID, etc.) .NOTES Call this in your PowerShell profile or at the start of scripts that need API keys. Add to your profile: Initialize-AitherSecrets -ShowOutput #> function Initialize-AitherSecrets { [CmdletBinding()] param( [Parameter()] [string[]]$Names, [Parameter()] [string]$Prefix, [Parameter()] [ValidateSet('Process', 'User', 'Machine')] [string]$Scope = 'Process', [Parameter()] [switch]$NoClobber, [Parameter()] [switch]$ShowOutput ) begin { # Get credential storage path $credentialPath = if ($IsWindows) { Join-Path $env:USERPROFILE ".aitherzero" "credentials" } else { Join-Path $env:HOME ".aitherzero" "credentials" } $loadedSecrets = @() $skippedSecrets = @() } process { try { if (-not (Test-Path $credentialPath)) { if ($ShowOutput) { Write-AitherLog -Level Warning -Message "⚠️ No secrets stored yet. Use Set-AitherCredential to store API keys." -Source 'Initialize-AitherSecrets' } return } # Get credential files $credFiles = Get-ChildItem -Path $credentialPath -Filter "*.cred" -File if ($Names) { $credFiles = $credFiles | Where-Object { $Names -contains $_.BaseName } } if ($Prefix) { $credFiles = $credFiles | Where-Object { $_.BaseName -like "$Prefix*" } } foreach ($credFile in $credFiles) { $name = $credFile.BaseName try { # Read the credential file $credData = Import-Clixml -Path $credFile.FullName -ErrorAction Stop # Only process API keys (not full credentials) if ($credData.Type -ne 'ApiKey') { continue } # Convert environment variable name (ensure uppercase, underscores) $envName = $name.ToUpper() -replace '-', '_' # Check if already set $existingValue = [Environment]::GetEnvironmentVariable($envName, $Scope) if ($existingValue -and $NoClobber) { $skippedSecrets += $name if ($ShowOutput) { Write-AitherLog -Level Information -Message "⏭️ Skipped (exists): $envName" -Source 'Initialize-AitherSecrets' } continue } # Get the secret value $secretValue = Get-AitherCredential -Name $name -AsPlainText -ErrorAction Stop if ($secretValue) { # Set the environment variable [Environment]::SetEnvironmentVariable($envName, $secretValue, $Scope) $loadedSecrets += $name if ($ShowOutput) { # Show masked value for security $masked = if ($secretValue.Length -gt 8) { $secretValue.Substring(0, 4) + "..." + $secretValue.Substring($secretValue.Length - 4) } else { "****" } Write-AitherLog -Level Information -Message "✅ Loaded: `$env:$envName = $masked" -Source 'Initialize-AitherSecrets' } } } catch { Write-AitherLog -Level Warning -Message "Failed to load '$name': $_" -Source 'Initialize-AitherSecrets' -Exception $_ } } if ($ShowOutput) { Write-AitherLog -Level Information -Message "📦 Loaded $($loadedSecrets.Count) secrets into environment ($Scope scope)" -Source 'Initialize-AitherSecrets' if ($skippedSecrets.Count -gt 0) { Write-AitherLog -Level Information -Message "⏭️ Skipped $($skippedSecrets.Count) existing variables" -Source 'Initialize-AitherSecrets' } } return [PSCustomObject]@{ Loaded = $loadedSecrets Skipped = $skippedSecrets Scope = $Scope } } catch { Write-AitherLog -Level Error -Message "Failed to initialize secrets: $_" -Source 'Initialize-AitherSecrets' -Exception $_ throw } } } |