@supacloud/admin 0.7.5 → 0.7.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +85 -28
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -25096,6 +25096,11 @@ class SshConnectionPool {
|
|
|
25096
25096
|
} catch {}
|
|
25097
25097
|
}
|
|
25098
25098
|
}
|
|
25099
|
+
discard(conn) {
|
|
25100
|
+
try {
|
|
25101
|
+
conn.end();
|
|
25102
|
+
} catch {}
|
|
25103
|
+
}
|
|
25099
25104
|
closeAll() {
|
|
25100
25105
|
for (const conn of this.pool) {
|
|
25101
25106
|
try {
|
|
@@ -25130,13 +25135,15 @@ class SshTransport {
|
|
|
25130
25135
|
}
|
|
25131
25136
|
auditCommand(command, this.config.host, false);
|
|
25132
25137
|
const conn = await this.pool.acquire();
|
|
25138
|
+
let connectionReusable = true;
|
|
25133
25139
|
try {
|
|
25134
25140
|
return await new Promise((resolve, reject) => {
|
|
25135
25141
|
const outputLimit = this.config.maxOutputBytes ?? DEFAULT_MAX_OUTPUT_BYTES;
|
|
25136
25142
|
const stdout = new BoundedOutputCollector(outputLimit);
|
|
25137
25143
|
const stderr = new BoundedOutputCollector(outputLimit);
|
|
25138
25144
|
const timer = setTimeout(() => {
|
|
25139
|
-
|
|
25145
|
+
connectionReusable = false;
|
|
25146
|
+
this.pool.discard(conn);
|
|
25140
25147
|
reject(new Error(`SSH command timed out after ${timeoutMs}ms`));
|
|
25141
25148
|
}, timeoutMs);
|
|
25142
25149
|
conn.exec(command, (err, stream) => {
|
|
@@ -25162,7 +25169,8 @@ class SshTransport {
|
|
|
25162
25169
|
});
|
|
25163
25170
|
});
|
|
25164
25171
|
} finally {
|
|
25165
|
-
|
|
25172
|
+
if (connectionReusable)
|
|
25173
|
+
this.pool.release(conn);
|
|
25166
25174
|
}
|
|
25167
25175
|
}
|
|
25168
25176
|
async upload(localPath, remotePath) {
|
|
@@ -25622,10 +25630,28 @@ SUPACLOUD_GITHUB_REPOSITORY="\${SUPACLOUD_GITHUB_REPOSITORY:-zuohuadong/supaclou
|
|
|
25622
25630
|
SUPACLOUD_RELEASES_API="\${SUPACLOUD_RELEASES_API:-https://api.github.com/repos/\${SUPACLOUD_GITHUB_REPOSITORY}/releases}"
|
|
25623
25631
|
SUPACLOUD_ATTESTATION_SIGNER_WORKFLOW="\${SUPACLOUD_ATTESTATION_SIGNER_WORKFLOW:-\${SUPACLOUD_GITHUB_REPOSITORY}/.github/workflows/release-please.yml}"
|
|
25624
25632
|
SUPACLOUD_GH_VERSION="\${SUPACLOUD_GH_VERSION:-2.96.0}"
|
|
25625
|
-
SUPACLOUD_GH_MIN_VERSION="\${SUPACLOUD_GH_MIN_VERSION:-2.
|
|
25633
|
+
SUPACLOUD_GH_MIN_VERSION="\${SUPACLOUD_GH_MIN_VERSION:-2.68.0}"
|
|
25626
25634
|
SUPACLOUD_GH_AMD64_SHA256="\${SUPACLOUD_GH_AMD64_SHA256:-83d5c2ccad5498f58bf6368acb1ab32588cf43ab3a4b1c301bf36328b1c8bd60}"
|
|
25627
25635
|
SUPACLOUD_GH_ARM64_SHA256="\${SUPACLOUD_GH_ARM64_SHA256:-06f86ec7103d41993b76cd78072f43595c34aaa56506d971d9860e67140bf909}"
|
|
25628
25636
|
|
|
25637
|
+
supacloud_curl_release_json() {
|
|
25638
|
+
local url="$1"
|
|
25639
|
+
local output="$2"
|
|
25640
|
+
curl -fsSL --proto '=https' --proto-redir '=https' \\
|
|
25641
|
+
--retry 1 --retry-delay 2 --retry-max-time 60 \\
|
|
25642
|
+
--connect-timeout 15 --max-time 30 --speed-limit 128 --speed-time 10 \\
|
|
25643
|
+
-o "$output" "$url"
|
|
25644
|
+
}
|
|
25645
|
+
|
|
25646
|
+
supacloud_curl_release_asset() {
|
|
25647
|
+
local url="$1"
|
|
25648
|
+
local output="$2"
|
|
25649
|
+
curl -fL --proto '=https' --proto-redir '=https' \\
|
|
25650
|
+
--retry 1 --retry-delay 2 --retry-max-time 180 \\
|
|
25651
|
+
--connect-timeout 15 --max-time 90 --speed-limit 128 --speed-time 60 \\
|
|
25652
|
+
-o "$output" "$url"
|
|
25653
|
+
}
|
|
25654
|
+
|
|
25629
25655
|
supacloud_component_tag() {
|
|
25630
25656
|
local component="$1"
|
|
25631
25657
|
local version="$2"
|
|
@@ -25691,18 +25717,15 @@ supacloud_fetch_component_release() {
|
|
|
25691
25717
|
supacloud_select_release "$component" "\${required_assets[@]}" <<< "$response"
|
|
25692
25718
|
}
|
|
25693
25719
|
|
|
25694
|
-
supacloud_fetch_release_json()
|
|
25720
|
+
supacloud_fetch_release_json() (
|
|
25695
25721
|
local url="$1"
|
|
25696
|
-
local
|
|
25697
|
-
|
|
25698
|
-
|
|
25699
|
-
|
|
25700
|
-
|
|
25701
|
-
|
|
25702
|
-
|
|
25703
|
-
fi
|
|
25704
|
-
return 1
|
|
25705
|
-
}
|
|
25722
|
+
local response_file
|
|
25723
|
+
response_file=$(mktemp) || return 1
|
|
25724
|
+
trap 'rm -f "$response_file"' EXIT
|
|
25725
|
+
trap 'trap - EXIT HUP INT TERM; rm -f "$response_file"; exit 1' HUP INT TERM
|
|
25726
|
+
supacloud_download_release_metadata_url "$url" "$response_file" || return 1
|
|
25727
|
+
cat "$response_file"
|
|
25728
|
+
)
|
|
25706
25729
|
|
|
25707
25730
|
supacloud_release_asset_url() {
|
|
25708
25731
|
local release_json="$1"
|
|
@@ -25718,11 +25741,26 @@ supacloud_download_url() {
|
|
|
25718
25741
|
local output="$2"
|
|
25719
25742
|
local proxy="\${SUPACLOUD_GITHUB_PROXY:-\${GH_PROXY:-}}"
|
|
25720
25743
|
|
|
25721
|
-
if
|
|
25744
|
+
if supacloud_curl_release_asset "$url" "$output"; then
|
|
25745
|
+
return 0
|
|
25746
|
+
fi
|
|
25747
|
+
if [[ -n "$proxy" ]]; then
|
|
25748
|
+
supacloud_curl_release_asset "\${proxy%/}/\${url}" "$output"
|
|
25749
|
+
return
|
|
25750
|
+
fi
|
|
25751
|
+
return 1
|
|
25752
|
+
}
|
|
25753
|
+
|
|
25754
|
+
supacloud_download_release_metadata_url() {
|
|
25755
|
+
local url="$1"
|
|
25756
|
+
local output="$2"
|
|
25757
|
+
local proxy="\${SUPACLOUD_GITHUB_PROXY:-\${GH_PROXY:-}}"
|
|
25758
|
+
|
|
25759
|
+
if supacloud_curl_release_json "$url" "$output"; then
|
|
25722
25760
|
return 0
|
|
25723
25761
|
fi
|
|
25724
25762
|
if [[ -n "$proxy" ]]; then
|
|
25725
|
-
|
|
25763
|
+
supacloud_curl_release_json "\${proxy%/}/\${url}" "$output"
|
|
25726
25764
|
return
|
|
25727
25765
|
fi
|
|
25728
25766
|
return 1
|
|
@@ -25803,7 +25841,8 @@ supacloud_install_pinned_tar_xz_binary() (
|
|
|
25803
25841
|
fi
|
|
25804
25842
|
|
|
25805
25843
|
extract_dir=$(mktemp -d)
|
|
25806
|
-
trap 'rm -rf "$extract_dir"; [[ -z "\${staged_target:-}" ]] || rm -f "$staged_target"' EXIT
|
|
25844
|
+
trap 'rm -rf "$extract_dir"; [[ -z "\${staged_target:-}" ]] || rm -f "$staged_target"' EXIT
|
|
25845
|
+
trap 'trap - EXIT HUP INT TERM; rm -rf "$extract_dir"; [[ -z "\${staged_target:-}" ]] || rm -f "$staged_target"; exit 1' HUP INT TERM
|
|
25807
25846
|
if ! tar --no-same-owner --no-same-permissions -xJf "$archive" -C "$extract_dir" "$member"; then
|
|
25808
25847
|
return 1
|
|
25809
25848
|
fi
|
|
@@ -25992,7 +26031,8 @@ supacloud_verify_attestation() (
|
|
|
25992
26031
|
if ! verification_output=$(gh attestation verify "$artifact_file" \\
|
|
25993
26032
|
--bundle "$bundle_file" \\
|
|
25994
26033
|
--repo "$SUPACLOUD_GITHUB_REPOSITORY" \\
|
|
25995
|
-
--signer-workflow "$SUPACLOUD_ATTESTATION_SIGNER_WORKFLOW"
|
|
26034
|
+
--signer-workflow "$SUPACLOUD_ATTESTATION_SIGNER_WORKFLOW" \\
|
|
26035
|
+
--source-ref "refs/heads/main" 2>&1); then
|
|
25996
26036
|
echo "GitHub artifact attestation verification failed: \${verification_output}" >&2
|
|
25997
26037
|
return 1
|
|
25998
26038
|
fi
|
|
@@ -26011,12 +26051,15 @@ supacloud_verify_attestation() (
|
|
|
26011
26051
|
)
|
|
26012
26052
|
|
|
26013
26053
|
supacloud_attestation_verifier_available() {
|
|
26014
|
-
local version
|
|
26054
|
+
local version help
|
|
26015
26055
|
command -v gh >/dev/null 2>&1 || return 1
|
|
26016
26056
|
version=$(supacloud_gh_version)
|
|
26017
26057
|
[[ -n "$version" ]] || return 1
|
|
26018
26058
|
supacloud_version_at_least "$version" "$SUPACLOUD_GH_MIN_VERSION" || return 1
|
|
26019
|
-
gh attestation verify --help 2>&1
|
|
26059
|
+
help=$(gh attestation verify --help 2>&1) || return 1
|
|
26060
|
+
grep -Eq -- '(^|[[:space:]])--bundle([=[:space:]]|$)' <<< "$help" || return 1
|
|
26061
|
+
grep -Eq -- '(^|[[:space:]])--signer-workflow([=[:space:]]|$)' <<< "$help" || return 1
|
|
26062
|
+
grep -Eq -- '(^|[[:space:]])--source-ref([=[:space:]]|$)' <<< "$help"
|
|
26020
26063
|
}
|
|
26021
26064
|
|
|
26022
26065
|
supacloud_download_release_asset() (
|
|
@@ -26031,10 +26074,11 @@ supacloud_download_release_asset() (
|
|
|
26031
26074
|
mkdir -p "$(dirname "$destination")"
|
|
26032
26075
|
temporary_artifact=$(mktemp "\${destination}.tmp.XXXXXX")
|
|
26033
26076
|
temporary_checksums=$(mktemp "\${destination}.SHA256SUMS.tmp.XXXXXX")
|
|
26034
|
-
trap 'rm -f "\${temporary_artifact:-}" "\${temporary_checksums:-}"' EXIT
|
|
26077
|
+
trap 'rm -f "\${temporary_artifact:-}" "\${temporary_checksums:-}"' EXIT
|
|
26078
|
+
trap 'trap - EXIT HUP INT TERM; rm -f "\${temporary_artifact:-}" "\${temporary_checksums:-}"; exit 1' HUP INT TERM
|
|
26035
26079
|
|
|
26036
26080
|
if ! supacloud_download_url "$asset_url" "$temporary_artifact" \\
|
|
26037
|
-
|| !
|
|
26081
|
+
|| ! supacloud_download_release_metadata_url "$checksum_url" "$temporary_checksums" \\
|
|
26038
26082
|
|| ! supacloud_verify_checksum "$temporary_artifact" "$asset_name" "$temporary_checksums"; then
|
|
26039
26083
|
rm -f "$temporary_artifact" "$temporary_checksums"
|
|
26040
26084
|
return 1
|
|
@@ -26076,6 +26120,8 @@ var SAFE_HOSTNAME = /^(?=.{1,253}$)(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9
|
|
|
26076
26120
|
var SAFE_SYSTEMD_UNIT = /^[a-zA-Z0-9][a-zA-Z0-9_.@:-]{0,127}$/;
|
|
26077
26121
|
var SAFE_DB_IDENTIFIER = /^[a-zA-Z_][a-zA-Z0-9_-]{0,62}$/;
|
|
26078
26122
|
var MINIMUM_COMPONENT_UPGRADE_VERSION = "0.50.27";
|
|
26123
|
+
var DIRECT_UPGRADE_SSH_TIMEOUT_MS = 720000;
|
|
26124
|
+
var PROXIED_UPGRADE_SSH_TIMEOUT_MS = 1320000;
|
|
26079
26125
|
function hostnameSchema(fieldName) {
|
|
26080
26126
|
return decodedSchema(Type.String(), Type.String({ minLength: 1, maxLength: 253 }), (value) => {
|
|
26081
26127
|
const normalized = value.trim();
|
|
@@ -26171,6 +26217,12 @@ function componentPreflightCommands(request) {
|
|
|
26171
26217
|
`test "$EDGE_RUNTIME_MODE_VALUE" = external || { echo 'Edge Runtime component upgrade supports persisted external mode only' >&2; exit 1; }`
|
|
26172
26218
|
] : [];
|
|
26173
26219
|
}
|
|
26220
|
+
function signalSafeCleanupTraps(cleanupCommand) {
|
|
26221
|
+
return [
|
|
26222
|
+
`trap '${cleanupCommand}' EXIT`,
|
|
26223
|
+
`trap 'trap - EXIT HUP INT TERM; ${cleanupCommand}; exit 1' HUP INT TERM`
|
|
26224
|
+
];
|
|
26225
|
+
}
|
|
26174
26226
|
function buildRootUpgradeScript(request) {
|
|
26175
26227
|
const envAssignments = upgradeEnvAssignments(request);
|
|
26176
26228
|
return [
|
|
@@ -26179,12 +26231,12 @@ function buildRootUpgradeScript(request) {
|
|
|
26179
26231
|
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
|
|
26180
26232
|
"export PATH",
|
|
26181
26233
|
"unset SUPACLOUD_ALLOW_UNVERIFIED_RELEASE SUPACLOUD_GITHUB_REPOSITORY SUPACLOUD_RELEASES_API SUPACLOUD_ATTESTATION_SIGNER_WORKFLOW SUPACLOUD_GH_VERSION SUPACLOUD_GH_MIN_VERSION SUPACLOUD_GH_AMD64_SHA256 SUPACLOUD_GH_ARM64_SHA256 GH_PROXY",
|
|
26182
|
-
request.githubProxy ? `export SUPACLOUD_GITHUB_PROXY=${quoteEnvValue(request.githubProxy)}` : "unset SUPACLOUD_GITHUB_PROXY",
|
|
26234
|
+
request.githubProxy ? `export SUPACLOUD_GITHUB_PROXY=${quoteEnvValue(request.githubProxy)}` : "unset SUPACLOUD_GITHUB_PROXY SUPACLOUD_GITHUB_PROXIES",
|
|
26183
26235
|
'for tool in curl jq file sha256sum tar; do command -v "$tool" >/dev/null 2>&1 || { echo "Required upgrade tool is missing: $tool" >&2; exit 127; }; done',
|
|
26184
26236
|
"test -x /usr/local/bin/supacloud || { echo 'SupaCloud binary not found at /usr/local/bin/supacloud; run ssh install first.' >&2; exit 127; }",
|
|
26185
26237
|
...componentPreflightCommands(request),
|
|
26186
26238
|
"STAGED_MANAGEMENT=''",
|
|
26187
|
-
|
|
26239
|
+
...signalSafeCleanupTraps('test -z "$STAGED_MANAGEMENT" || rm -f "$STAGED_MANAGEMENT"'),
|
|
26188
26240
|
`source ${quoteEnvValue(request.helperPath)}`,
|
|
26189
26241
|
"if ! supacloud_attestation_verifier_available; then supacloud_install_pinned_gh /usr/local/bin/gh; fi",
|
|
26190
26242
|
"supacloud_attestation_verifier_available || { echo 'Pinned GitHub attestation verifier is unavailable' >&2; exit 1; }",
|
|
@@ -26195,7 +26247,11 @@ function buildRootUpgradeScript(request) {
|
|
|
26195
26247
|
}
|
|
26196
26248
|
function buildOfficialUpgradeCommand(request) {
|
|
26197
26249
|
const rootScript = buildRootUpgradeScript(request);
|
|
26198
|
-
return
|
|
26250
|
+
return [
|
|
26251
|
+
"set -e",
|
|
26252
|
+
...signalSafeCleanupTraps(`rm -f ${request.helperPath}`),
|
|
26253
|
+
'if [ "$(id -u)" -eq 0 ]; then ' + `bash -c ${quoteEnvValue(rootScript)}; ` + "else sudo -n true; " + `sudo -n bash -c ${quoteEnvValue(rootScript)}; fi`
|
|
26254
|
+
].join("; ");
|
|
26199
26255
|
}
|
|
26200
26256
|
async function removeRemoteUpgradeHelper(ssh, helperPath) {
|
|
26201
26257
|
const cleanup = await ssh.exec(`rm -f ${quoteEnvValue(helperPath)}`);
|
|
@@ -26224,12 +26280,12 @@ function officialUpgradeOutcome(execution, executionError, cleanupError) {
|
|
|
26224
26280
|
throw remoteUpgradeFailure(execution);
|
|
26225
26281
|
return execution;
|
|
26226
26282
|
}
|
|
26227
|
-
async function executeOfficialUpgrade(ssh, helperPath, command) {
|
|
26283
|
+
async function executeOfficialUpgrade(ssh, helperPath, command, timeoutMs) {
|
|
26228
26284
|
let execution;
|
|
26229
26285
|
let executionError;
|
|
26230
26286
|
try {
|
|
26231
26287
|
await ssh.uploadText(helperPath, release_assets_default, 384);
|
|
26232
|
-
execution = await ssh.exec(command,
|
|
26288
|
+
execution = await ssh.exec(command, timeoutMs);
|
|
26233
26289
|
} catch (error) {
|
|
26234
26290
|
executionError = error;
|
|
26235
26291
|
}
|
|
@@ -26544,7 +26600,8 @@ ${result.stderr.slice(-500)}`;
|
|
|
26544
26600
|
githubProxy,
|
|
26545
26601
|
helperPath
|
|
26546
26602
|
});
|
|
26547
|
-
const
|
|
26603
|
+
const upgradeTimeoutMs = githubProxy ? PROXIED_UPGRADE_SSH_TIMEOUT_MS : DIRECT_UPGRADE_SSH_TIMEOUT_MS;
|
|
26604
|
+
const upgradeExecution = await executeOfficialUpgrade(ssh, helperPath, cmd, upgradeTimeoutMs);
|
|
26548
26605
|
const edgeBoundary = edgeRuntimeVersion ? "" : `
|
|
26549
26606
|
⚠️ Edge Runtime was not upgraded; provide --edge_runtime_version for a component transaction.`;
|
|
26550
26607
|
text = `✅ Upgrade done
|