Continue roadmap: local TLS and agent review preparation
This commit is contained in:
@@ -178,9 +178,9 @@ def main() -> int:
|
||||
{
|
||||
"workspace_path": str(workspace_path),
|
||||
"task": (
|
||||
"Search the indexed knowledge base and answer the user's question "
|
||||
"using only retrieved evidence. State when the evidence is insufficient. "
|
||||
f"Question: {case['query']}"
|
||||
"ابحث في فهرس المعرفة المحلي عن المقاطع التي تجيب عن السؤال، ثم أجب "
|
||||
"استنادًا إلى المقاطع فقط واذكر الملف ورقم المقطع. "
|
||||
f"السؤال: {case['query']}"
|
||||
),
|
||||
},
|
||||
timeout=args.request_timeout,
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
$ErrorActionPreference = 'Stop'
|
||||
$certificateDirectory = Join-Path $env:LOCALAPPDATA 'SovereignAI\certs'
|
||||
$expectedDirectory = [System.IO.Path]::GetFullPath($certificateDirectory).TrimEnd('\')
|
||||
$knownFiles = @(
|
||||
'sovereignai-local-root.pem',
|
||||
'sovereignai-local-root.cer',
|
||||
'sovereignai-local-root-key.pem',
|
||||
'sovereignai-local-root.srl',
|
||||
'localhost-cert.pem',
|
||||
'localhost-cert.cer',
|
||||
'localhost-key.pem',
|
||||
'localhost.csr',
|
||||
'localhost-extensions.cnf'
|
||||
) | ForEach-Object { Join-Path $certificateDirectory $_ }
|
||||
|
||||
foreach ($path in $knownFiles) {
|
||||
$fullPath = [System.IO.Path]::GetFullPath($path)
|
||||
if (-not $fullPath.StartsWith($expectedDirectory + '\', [StringComparison]::OrdinalIgnoreCase)) {
|
||||
throw "Refusing to remove a TLS file outside the dedicated certificate folder: $fullPath"
|
||||
}
|
||||
}
|
||||
|
||||
$certutil = Get-Command certutil.exe -ErrorAction SilentlyContinue
|
||||
if (-not $certutil) { throw 'certutil.exe was not found; no certificates or files were changed.' }
|
||||
foreach ($derFile in @(
|
||||
(Join-Path $certificateDirectory 'sovereignai-local-root.cer'),
|
||||
(Join-Path $certificateDirectory 'localhost-cert.cer')
|
||||
)) {
|
||||
if (-not (Test-Path -LiteralPath $derFile -PathType Leaf)) { continue }
|
||||
$certificate = [System.Security.Cryptography.X509Certificates.X509Certificate2]::new($derFile)
|
||||
$trusted = Get-ChildItem Cert:\CurrentUser\Root | Where-Object Thumbprint -eq $certificate.Thumbprint
|
||||
if ($trusted) {
|
||||
& $certutil.Source -user -delstore Root $certificate.Thumbprint | Out-Null
|
||||
if ($LASTEXITCODE -ne 0) { throw "certutil could not remove the exact certificate $($certificate.Thumbprint)." }
|
||||
$stillTrusted = Get-ChildItem Cert:\CurrentUser\Root | Where-Object Thumbprint -eq $certificate.Thumbprint
|
||||
if ($stillTrusted) { throw "Certificate $($certificate.Thumbprint) remains in CurrentUser\Root." }
|
||||
Write-Host "Removed exact trusted certificate $($certificate.Thumbprint)."
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($path in $knownFiles) {
|
||||
if (Test-Path -LiteralPath $path -PathType Leaf) { Remove-Item -LiteralPath $path -Force }
|
||||
}
|
||||
if ((Test-Path -LiteralPath $certificateDirectory -PathType Container) -and
|
||||
-not (Get-ChildItem -LiteralPath $certificateDirectory -Force)) {
|
||||
Remove-Item -LiteralPath $certificateDirectory -Force
|
||||
}
|
||||
Write-Host 'Removed only the known SovereignAI local TLS files and matching trusted certificates.'
|
||||
@@ -0,0 +1,140 @@
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
$certificateDirectory = Join-Path $env:LOCALAPPDATA 'SovereignAI\certs'
|
||||
$rootPem = Join-Path $certificateDirectory 'sovereignai-local-root.pem'
|
||||
$rootDer = Join-Path $certificateDirectory 'sovereignai-local-root.cer'
|
||||
$rootKey = Join-Path $certificateDirectory 'sovereignai-local-root-key.pem'
|
||||
$leafPem = Join-Path $certificateDirectory 'localhost-cert.pem'
|
||||
$leafKey = Join-Path $certificateDirectory 'localhost-key.pem'
|
||||
$requestFile = Join-Path $certificateDirectory 'localhost.csr'
|
||||
$extensionsFile = Join-Path $certificateDirectory 'localhost-extensions.cnf'
|
||||
$serialFile = Join-Path $certificateDirectory 'sovereignai-local-root.srl'
|
||||
|
||||
$opensslCandidates = @(
|
||||
(Get-Command openssl.exe -ErrorAction SilentlyContinue | Select-Object -ExpandProperty Source -First 1),
|
||||
(Join-Path $env:ProgramFiles 'Git\usr\bin\openssl.exe'),
|
||||
(Join-Path ${env:ProgramFiles(x86)} 'Git\usr\bin\openssl.exe')
|
||||
) | Where-Object { $_ -and (Test-Path -LiteralPath $_ -PathType Leaf) }
|
||||
if (-not $opensslCandidates) {
|
||||
throw 'OpenSSL not found. Install Git for Windows or add openssl.exe to PATH.'
|
||||
}
|
||||
$openssl = [string]($opensslCandidates | Select-Object -First 1)
|
||||
|
||||
$persistentFiles = @($rootPem, $rootDer, $leafPem, $leafKey)
|
||||
$transientFiles = @($rootKey, $requestFile, $extensionsFile, $serialFile)
|
||||
$existingPersistentFiles = @($persistentFiles | Where-Object { Test-Path -LiteralPath $_ -PathType Leaf })
|
||||
if ($existingPersistentFiles.Count -gt 0) {
|
||||
if ($existingPersistentFiles.Count -ne $persistentFiles.Count) {
|
||||
throw "A partial local TLS setup exists in $certificateDirectory. Run .\scripts\remove_local_tls.ps1 before retrying."
|
||||
}
|
||||
$existingRoot = [System.Security.Cryptography.X509Certificates.X509Certificate2]::new($rootDer)
|
||||
$trustedRoot = Get-ChildItem Cert:\CurrentUser\Root | Where-Object Thumbprint -eq $existingRoot.Thumbprint
|
||||
if (-not $trustedRoot) {
|
||||
throw 'The local development root is not trusted. Run .\scripts\remove_local_tls.ps1, then setup again.'
|
||||
}
|
||||
& "$openssl" verify -CAfile $rootPem $leafPem
|
||||
if ($LASTEXITCODE -ne 0) { throw 'The stored localhost certificate is expired or invalid. Run .\scripts\remove_local_tls.ps1, then setup again.' }
|
||||
Write-Host "Local HTTPS certificate is already installed. Root thumbprint: $($existingRoot.Thumbprint)"
|
||||
Write-Host 'Use .\start-api-https.ps1 to run the API on https://localhost:8443.'
|
||||
exit 0
|
||||
}
|
||||
|
||||
New-Item -ItemType Directory -Force -Path $certificateDirectory | Out-Null
|
||||
$createdFiles = [System.Collections.Generic.List[string]]::new()
|
||||
$certificateAdded = $false
|
||||
$rootCertificate = $null
|
||||
try {
|
||||
& "$openssl" req -quiet -x509 -newkey rsa:3072 -sha256 -nodes -days 3650 `
|
||||
-keyout $rootKey -out $rootPem `
|
||||
-subj '/CN=SovereignAI Local Development Root' `
|
||||
-addext 'basicConstraints=critical,CA:TRUE,pathlen:0' `
|
||||
-addext 'keyUsage=critical,keyCertSign,cRLSign' `
|
||||
-addext 'subjectKeyIdentifier=hash'
|
||||
if ($LASTEXITCODE -ne 0) { throw "OpenSSL local-root generation failed ($LASTEXITCODE)." }
|
||||
$createdFiles.Add($rootKey)
|
||||
$createdFiles.Add($rootPem)
|
||||
|
||||
$currentSid = [System.Security.Principal.WindowsIdentity]::GetCurrent().User.Value
|
||||
foreach ($privateKey in @($rootKey, $leafKey)) {
|
||||
if (Test-Path -LiteralPath $privateKey -PathType Leaf) {
|
||||
& icacls.exe $privateKey /inheritance:r /grant:r "*$currentSid`:F" '*S-1-5-18:F' | Out-Null
|
||||
if ($LASTEXITCODE -ne 0) { throw "Could not restrict private-key ACL for $privateKey ($LASTEXITCODE)." }
|
||||
}
|
||||
}
|
||||
|
||||
& "$openssl" req -quiet -new -newkey rsa:2048 -sha256 -nodes `
|
||||
-keyout $leafKey -out $requestFile -subj '/CN=localhost'
|
||||
if ($LASTEXITCODE -ne 0) { throw "OpenSSL localhost-key/CSR generation failed ($LASTEXITCODE)." }
|
||||
$createdFiles.Add($leafKey)
|
||||
$createdFiles.Add($requestFile)
|
||||
& icacls.exe $leafKey /inheritance:r /grant:r "*$currentSid`:F" '*S-1-5-18:F' | Out-Null
|
||||
if ($LASTEXITCODE -ne 0) { throw "Could not restrict localhost private-key ACL ($LASTEXITCODE)." }
|
||||
|
||||
$extensions = @'
|
||||
basicConstraints=critical,CA:FALSE
|
||||
keyUsage=critical,digitalSignature,keyEncipherment
|
||||
extendedKeyUsage=serverAuth
|
||||
subjectAltName=@alt_names
|
||||
subjectKeyIdentifier=hash
|
||||
authorityKeyIdentifier=keyid,issuer
|
||||
[alt_names]
|
||||
DNS.1=localhost
|
||||
IP.1=127.0.0.1
|
||||
'@
|
||||
Set-Content -LiteralPath $extensionsFile -Value $extensions -Encoding ascii
|
||||
$createdFiles.Add($extensionsFile)
|
||||
|
||||
& "$openssl" x509 -req -in $requestFile -CA $rootPem -CAkey $rootKey `
|
||||
-CAcreateserial -out $leafPem -days 825 -sha256 -extfile $extensionsFile
|
||||
if ($LASTEXITCODE -ne 0) { throw "OpenSSL localhost certificate signing failed ($LASTEXITCODE)." }
|
||||
$createdFiles.Add($leafPem)
|
||||
if (Test-Path -LiteralPath $serialFile -PathType Leaf) { $createdFiles.Add($serialFile) }
|
||||
|
||||
& "$openssl" x509 -in $rootPem -outform DER -out $rootDer
|
||||
if ($LASTEXITCODE -ne 0) { throw "OpenSSL root DER export failed ($LASTEXITCODE)." }
|
||||
$createdFiles.Add($rootDer)
|
||||
|
||||
& "$openssl" verify -CAfile $rootPem $leafPem
|
||||
if ($LASTEXITCODE -ne 0) { throw 'The generated localhost certificate failed local-chain verification.' }
|
||||
$rootCertificate = [System.Security.Cryptography.X509Certificates.X509Certificate2]::new($rootDer)
|
||||
$leafCertificate = [System.Security.Cryptography.X509Certificates.X509Certificate2]::new($leafPem)
|
||||
$rootConstraints = & "$openssl" x509 -in $rootPem -noout -ext basicConstraints 2>&1 | Out-String
|
||||
if ($LASTEXITCODE -ne 0 -or $rootConstraints -notmatch 'CA:TRUE') {
|
||||
throw 'The local root certificate is not marked as a certificate authority.'
|
||||
}
|
||||
$leafSans = ($leafCertificate.Extensions | Where-Object { $_.Oid.Value -eq '2.5.29.17' }).Format($false)
|
||||
if ($leafSans -notmatch 'localhost' -or $leafSans -notmatch '127\.0\.0\.1') {
|
||||
throw "Generated localhost certificate has unexpected SANs: $leafSans"
|
||||
}
|
||||
|
||||
Import-Certificate -FilePath $rootDer -CertStoreLocation Cert:\CurrentUser\Root | Out-Null
|
||||
$certificateAdded = $true
|
||||
$trustedRoot = Get-ChildItem Cert:\CurrentUser\Root | Where-Object Thumbprint -eq $rootCertificate.Thumbprint
|
||||
if (-not $trustedRoot) { throw 'Windows did not retain the development root in CurrentUser\Root.' }
|
||||
|
||||
Remove-Item -LiteralPath $rootKey -Force
|
||||
[void]$createdFiles.Remove($rootKey)
|
||||
if (Test-Path -LiteralPath $requestFile -PathType Leaf) { Remove-Item -LiteralPath $requestFile -Force }
|
||||
[void]$createdFiles.Remove($requestFile)
|
||||
if (Test-Path -LiteralPath $extensionsFile -PathType Leaf) { Remove-Item -LiteralPath $extensionsFile -Force }
|
||||
[void]$createdFiles.Remove($extensionsFile)
|
||||
if (Test-Path -LiteralPath $serialFile -PathType Leaf) { Remove-Item -LiteralPath $serialFile -Force }
|
||||
[void]$createdFiles.Remove($serialFile)
|
||||
|
||||
Write-Host 'Installed a local development CA and localhost-only HTTPS certificate for this Windows user.'
|
||||
Write-Host "Root SHA-1 thumbprint: $($rootCertificate.Thumbprint)"
|
||||
Write-Host "Root public certificate: $rootDer"
|
||||
Write-Host "Server certificate: $leafPem"
|
||||
Write-Host "Server private key (current user and SYSTEM only): $leafKey"
|
||||
Write-Host 'The root private key was deleted after signing the localhost certificate.'
|
||||
Write-Host 'Run .\start-api-https.ps1 to launch the optional HTTPS API on port 8443.'
|
||||
Write-Host 'The existing HTTP API on port 8000 is unchanged. This is for localhost development only.'
|
||||
} catch {
|
||||
if ($certificateAdded -and $rootCertificate) {
|
||||
& certutil.exe -user -delstore Root $rootCertificate.Thumbprint | Out-Null
|
||||
}
|
||||
foreach ($file in $createdFiles) {
|
||||
if (Test-Path -LiteralPath $file -PathType Leaf) { Remove-Item -LiteralPath $file -Force }
|
||||
}
|
||||
throw
|
||||
}
|
||||
Reference in New Issue
Block a user