-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathinstall.ps1
More file actions
executable file
·199 lines (163 loc) · 7.96 KB
/
install.ps1
File metadata and controls
executable file
·199 lines (163 loc) · 7.96 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
# SentinelGate installer for Windows
# Usage: irm https://raw.githubusercontent.com/Sentinel-Gate/Sentinelgate/main/install.ps1 | iex
#
# Environment variables:
# VERSION - specific version to install (e.g., v1.1.0). Default: latest
# INSTALL_DIR - installation directory. Default: %LOCALAPPDATA%\SentinelGate
# Wrap everything in a script block to avoid leaking variables into caller's session via iex
& {
$ErrorActionPreference = "Stop"
# Ensure TLS 1.2 (required by GitHub; older PS 5.1 defaults to TLS 1.0/1.1)
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
# Suppress progress bar (PS 5.1 progress rendering is pathologically slow on large downloads)
$ProgressPreference = 'SilentlyContinue'
$Repo = "Sentinel-Gate/Sentinelgate"
$BinaryName = "sentinel-gate"
# ── Logging ──────────────────────────────────────────────────────────────────
function Write-Info { param([string]$Message) Write-Host "=> " -ForegroundColor Blue -NoNewline; Write-Host $Message }
function Write-Ok { param([string]$Message) Write-Host "=> " -ForegroundColor Green -NoNewline; Write-Host $Message }
function Write-Warn { param([string]$Message) Write-Host "WARNING: " -ForegroundColor Yellow -NoNewline; Write-Host $Message }
function Write-Err { param([string]$Message) Write-Host "ERROR: " -ForegroundColor Red -NoNewline; Write-Host $Message; throw "Installation failed: $Message" }
# ── Architecture detection ───────────────────────────────────────────────────
function Get-Arch {
$arch = $env:PROCESSOR_ARCHITECTURE
switch ($arch) {
"AMD64" { return "amd64" }
"ARM64" { return "arm64" }
default {
# On ARM64 running x86 emulation, check PROCESSOR_ARCHITEW6432
$archW6432 = $env:PROCESSOR_ARCHITEW6432
if ($archW6432 -eq "ARM64") { return "arm64" }
if ($archW6432 -eq "AMD64") { return "amd64" }
Write-Err "Unsupported architecture: $arch. Only amd64 and arm64 are supported."
}
}
}
# ── Version resolution ───────────────────────────────────────────────────────
function Get-Version {
if ($env:VERSION) {
$v = $env:VERSION
if ($v -notmatch '^v') { $v = "v$v" }
Write-Info "Using specified version: $v"
return $v
}
Write-Info "Fetching latest release version..."
try {
$release = Invoke-RestMethod -Uri "https://api.github.com/repos/$Repo/releases/latest"
$version = $release.tag_name
} catch {
Write-Info "No stable release found, checking pre-releases..."
try {
$releases = @(Invoke-RestMethod -Uri "https://api.github.com/repos/$Repo/releases")
$version = $releases[0].tag_name
} catch {
Write-Err "Failed to fetch releases from GitHub API: $_"
}
}
if (-not $version) {
Write-Err "Could not determine latest version from GitHub API."
}
Write-Info "Latest version: $version"
return $version
}
# ── Download and verify ──────────────────────────────────────────────────────
function Install-SentinelGate {
Write-Host ""
Write-Host "SentinelGate Installer" -ForegroundColor White -BackgroundColor DarkCyan
Write-Host ""
$arch = Get-Arch
$version = Get-Version
$archiveName = "${BinaryName}_windows_${arch}.zip"
$archiveUrl = "https://github.com/$Repo/releases/download/$version/$archiveName"
$checksumsUrl = "https://github.com/$Repo/releases/download/$version/checksums.txt"
$tmpDir = Join-Path ([System.IO.Path]::GetTempPath()) "sentinelgate-install-$([System.Guid]::NewGuid().ToString('N').Substring(0,8))"
New-Item -ItemType Directory -Path $tmpDir -Force | Out-Null
try {
# Download archive
Write-Info "Downloading $archiveName..."
$archivePath = Join-Path $tmpDir $archiveName
try {
Invoke-WebRequest -Uri $archiveUrl -OutFile $archivePath -UseBasicParsing
} catch {
Write-Err "Failed to download archive from ${archiveUrl}: $_"
}
# Download checksums
Write-Info "Downloading checksums..."
$checksumsPath = Join-Path $tmpDir "checksums.txt"
try {
Invoke-WebRequest -Uri $checksumsUrl -OutFile $checksumsPath -UseBasicParsing
} catch {
Write-Err "Failed to download checksums from ${checksumsUrl}: $_"
}
# Verify checksum
Write-Info "Verifying SHA-256 checksum..."
$escapedName = [regex]::Escape($archiveName)
$checksumLine = Get-Content $checksumsPath | Where-Object { $_ -match "\s+${escapedName}$" } | Select-Object -First 1
if (-not $checksumLine) {
Write-Err "Could not find checksum for $archiveName in checksums.txt"
}
$expected = ($checksumLine -split '\s+')[0]
$actual = (Get-FileHash -Path $archivePath -Algorithm SHA256).Hash.ToLower()
if ($expected -ne $actual) {
Write-Err "Checksum mismatch for $archiveName`n Expected: $expected`n Actual: $actual"
}
Write-Ok "Checksum verified."
# Extract
Write-Info "Extracting $BinaryName..."
Expand-Archive -Path $archivePath -DestinationPath $tmpDir -Force
$binaryPath = Join-Path $tmpDir "$BinaryName.exe"
if (-not (Test-Path $binaryPath)) {
Write-Err "Binary '$BinaryName.exe' not found in archive."
}
# Determine install directory
if ($env:INSTALL_DIR) {
$installDir = $env:INSTALL_DIR
} else {
$installDir = Join-Path $env:LOCALAPPDATA "SentinelGate"
}
if (-not (Test-Path $installDir)) {
New-Item -ItemType Directory -Path $installDir -Force | Out-Null
}
$destPath = Join-Path $installDir "$BinaryName.exe"
# Check if binary is locked (already running)
if (Test-Path $destPath) {
try {
[IO.File]::Open($destPath, 'Open', 'ReadWrite', 'Read').Close()
} catch {
Write-Err "$BinaryName.exe is currently running. Please stop it first (sentinel-gate stop) and re-run the installer."
}
}
# Remove "downloaded from internet" mark to avoid SmartScreen popup
Unblock-File -Path $binaryPath
Copy-Item -Path $binaryPath -Destination $destPath -Force
# Add to PATH if not already there
$userPath = [Environment]::GetEnvironmentVariable("Path", "User")
$pathEntries = ($userPath -split ';') | Where-Object { $_ -ne '' }
if ($installDir -notin $pathEntries) {
Write-Info "Adding $installDir to user PATH..."
$newPath = if ([string]::IsNullOrEmpty($userPath)) { $installDir } else { "$userPath;$installDir" }
[Environment]::SetEnvironmentVariable("Path", $newPath, "User")
$env:Path = "$env:Path;$installDir"
Write-Warn "Restart your terminal for PATH changes to take effect."
}
Write-Host ""
Write-Ok "SentinelGate $version installed successfully!"
Write-Info "Binary: $destPath"
Write-Info "Run 'sentinel-gate start' to get started."
Write-Host ""
} finally {
# Cleanup
if (Test-Path $tmpDir) {
Remove-Item -Path $tmpDir -Recurse -Force -ErrorAction SilentlyContinue
}
}
}
try {
Install-SentinelGate
} catch {
if ($_.Exception.Message -notlike "Installation failed:*") {
Write-Host "ERROR: " -ForegroundColor Red -NoNewline
Write-Host "Unexpected error: $($_.Exception.Message)"
}
}
} # end of script block scope