@supacloud/admin 0.15.3 → 0.15.4

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.
Files changed (2) hide show
  1. package/dist/index.js +122 -31
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -26367,7 +26367,7 @@ function quoteShell(shellText) {
26367
26367
  // src/shared/releases/local-upgrade-bundle.ts
26368
26368
  import { spawn } from "node:child_process";
26369
26369
  import { createHash as createHash2, randomUUID as randomUUID2 } from "node:crypto";
26370
- import { accessSync, chmodSync as chmodSync2, constants as fsConstants, createWriteStream, lstatSync, mkdirSync, mkdtempSync as mkdtempSync2, readFileSync as readFileSync3, readdirSync, renameSync, rmSync as rmSync2, statSync, writeFileSync as writeFileSync2 } from "node:fs";
26370
+ import { accessSync, chmodSync as chmodSync2, constants as fsConstants, createWriteStream, lstatSync, mkdirSync, mkdtempSync as mkdtempSync2, readFileSync as readFileSync3, readdirSync, rmSync as rmSync2, statSync, writeFileSync as writeFileSync2 } from "node:fs";
26371
26371
  import { get } from "node:https";
26372
26372
  import { tmpdir as tmpdir2 } from "node:os";
26373
26373
  import { basename, delimiter, join } from "node:path";
@@ -26649,6 +26649,7 @@ async function withSigstoreVerificationDirectory(operation) {
26649
26649
  // src/shared/releases/local-upgrade-bundle.ts
26650
26650
  var RELEASES_API = `https://api.github.com/repos/${RELEASE_REPOSITORY}/releases`;
26651
26651
  var ATTESTATIONS_API = `https://api.github.com/repos/${RELEASE_REPOSITORY}/attestations`;
26652
+ var GITHUB_CLI_REPOSITORY = "cli/cli";
26652
26653
  var GH_VERSION = "2.96.0";
26653
26654
  var GH_ARCHIVE_SHA256 = {
26654
26655
  amd64: "83d5c2ccad5498f58bf6368acb1ab32588cf43ab3a4b1c301bf36328b1c8bd60",
@@ -26859,6 +26860,36 @@ async function downloadDirect(url, destination, maxBytes) {
26859
26860
  }
26860
26861
  throw new AggregateError(retryFailures, `Unable to download ${parsed.hostname}${parsed.pathname}`);
26861
26862
  }
26863
+ async function downloadGithubReleaseAsset(request) {
26864
+ const download = await runGithubCliDownload([
26865
+ "release",
26866
+ "download",
26867
+ request.tag,
26868
+ "--repo",
26869
+ `github.com/${request.repository}`,
26870
+ "--pattern",
26871
+ request.assetName,
26872
+ "--output",
26873
+ "-"
26874
+ ], request.destination, request.maxBytes, DOWNLOAD_TIMEOUT_MS);
26875
+ if (download.exitCode !== 0) {
26876
+ rmSync2(request.destination, { force: true });
26877
+ throw new Error(`GitHub release asset download failed: ${download.stderr.trim().slice(-1000) || download.exitCode}`);
26878
+ }
26879
+ assertDownloadedReleaseAsset(request);
26880
+ }
26881
+ function assertDownloadedReleaseAsset(request) {
26882
+ const stats = lstatSync(request.destination);
26883
+ if (!stats.isFile() || stats.isSymbolicLink() || stats.nlink !== 1) {
26884
+ rmSync2(request.destination, { force: true });
26885
+ throw new Error("GitHub release asset must be a direct regular file");
26886
+ }
26887
+ if (stats.size > request.maxBytes) {
26888
+ rmSync2(request.destination, { force: true });
26889
+ throw new Error(`GitHub release asset exceeded ${request.maxBytes} bytes`);
26890
+ }
26891
+ chmodSync2(request.destination, 384);
26892
+ }
26862
26893
  function parseJsonFile(filePath, label) {
26863
26894
  const contents = readFileSync3(filePath, "utf8");
26864
26895
  try {
@@ -26930,7 +26961,7 @@ function serializeAttestationBundles(candidate) {
26930
26961
  function directEnvironment() {
26931
26962
  const environment = { ...process.env };
26932
26963
  for (const key of Object.keys(environment)) {
26933
- if (/(?:^|_)proxy$/i.test(key) || /^(?:SUPACLOUD_GITHUB_PROXIES|NODE_USE_ENV_PROXY)$/.test(key)) {
26964
+ if (/(?:^|_)proxy$/i.test(key) || /^(?:GH_HOST|GH_REPO|SUPACLOUD_GITHUB_PROXIES|NODE_USE_ENV_PROXY)$/.test(key)) {
26934
26965
  delete environment[key];
26935
26966
  }
26936
26967
  }
@@ -26955,15 +26986,15 @@ function githubCliExecutable(environment) {
26955
26986
  }
26956
26987
  throw new Error("GitHub CLI executable was not found in PATH");
26957
26988
  }
26958
- async function runGithubCli(arguments_, timeoutMs) {
26959
- return await new Promise((resolve2, reject) => {
26960
- const environment = directEnvironment();
26961
- const child = spawn(githubCliExecutable(environment), arguments_, {
26962
- env: environment,
26963
- stdio: ["ignore", "pipe", "pipe"]
26964
- });
26965
- let stdout = "";
26966
- let stderr = "";
26989
+ function spawnGithubCli(arguments_) {
26990
+ const environment = directEnvironment();
26991
+ return spawn(githubCliExecutable(environment), arguments_, {
26992
+ env: environment,
26993
+ stdio: ["ignore", "pipe", "pipe"]
26994
+ });
26995
+ }
26996
+ function githubCliExitCode(child, timeoutMs) {
26997
+ return new Promise((resolve2, reject) => {
26967
26998
  let timedOut = false;
26968
26999
  let settled = false;
26969
27000
  let forceKillTimer;
@@ -26982,18 +27013,46 @@ async function runGithubCli(arguments_, timeoutMs) {
26982
27013
  if (error)
26983
27014
  reject(error);
26984
27015
  else
26985
- resolve2({ exitCode: timedOut ? 124 : exitCode, stdout, stderr });
27016
+ resolve2(timedOut ? 124 : exitCode);
26986
27017
  };
26987
- child.stdout.on("data", (chunk) => {
26988
- stdout = `${stdout}${chunk.toString()}`.slice(-8000);
26989
- });
26990
- child.stderr.on("data", (chunk) => {
26991
- stderr = `${stderr}${chunk.toString()}`.slice(-8000);
26992
- });
26993
27018
  child.once("error", (error) => settleExecution(error, 127));
26994
27019
  child.once("close", (code) => settleExecution(undefined, code ?? 1));
26995
27020
  });
26996
27021
  }
27022
+ async function runGithubCli(arguments_, timeoutMs) {
27023
+ const child = spawnGithubCli(arguments_);
27024
+ let stdout = "";
27025
+ let stderr = "";
27026
+ child.stdout.on("data", (chunk) => {
27027
+ stdout = `${stdout}${chunk.toString()}`.slice(-8000);
27028
+ });
27029
+ child.stderr.on("data", (chunk) => {
27030
+ stderr = `${stderr}${chunk.toString()}`.slice(-8000);
27031
+ });
27032
+ const exitCode = await githubCliExitCode(child, timeoutMs);
27033
+ return { exitCode, stdout, stderr };
27034
+ }
27035
+ async function runGithubCliDownload(arguments_, destination, maxBytes, timeoutMs) {
27036
+ const child = spawnGithubCli(arguments_);
27037
+ let stderr = "";
27038
+ child.stderr.on("data", (chunk) => {
27039
+ stderr = `${stderr}${chunk.toString()}`.slice(-8000);
27040
+ });
27041
+ const write = pipeline(child.stdout, boundedWriter(maxBytes), createWriteStream(destination, { flags: "wx", mode: 384 })).catch((error) => {
27042
+ child.kill("SIGKILL");
27043
+ throw error;
27044
+ });
27045
+ const [writeState, exitState] = await Promise.allSettled([write, githubCliExitCode(child, timeoutMs)]);
27046
+ if (writeState.status === "rejected") {
27047
+ rmSync2(destination, { force: true });
27048
+ throw writeState.reason;
27049
+ }
27050
+ if (exitState.status === "rejected") {
27051
+ rmSync2(destination, { force: true });
27052
+ throw exitState.reason;
27053
+ }
27054
+ return { exitCode: exitState.value, stdout: "", stderr };
27055
+ }
26997
27056
  function supportsStrictGithubVerification(execution) {
26998
27057
  const tokens = `${execution.stdout}
26999
27058
  ${execution.stderr}`.split(/\s+/);
@@ -27071,16 +27130,22 @@ function manifestAttestationDownloadUrl(release, manifest, manifestDigest) {
27071
27130
  }
27072
27131
  async function downloadManifestAttestation(request) {
27073
27132
  const { release, manifest, manifestPath, destination } = request;
27133
+ if (manifest.repository !== RELEASE_REPOSITORY) {
27134
+ await downloadGithubReleaseAsset({
27135
+ repository: RELEASE_REPOSITORY,
27136
+ tag: release.tag_name,
27137
+ assetName: RELEASE_ATTESTATION_NAME,
27138
+ destination,
27139
+ maxBytes: RELEASE_BUNDLE_SIZE_LIMITS.attestation
27140
+ });
27141
+ return;
27142
+ }
27074
27143
  const responsePath = `${destination}.response`;
27075
27144
  try {
27076
27145
  await downloadDirect(manifestAttestationDownloadUrl(release, manifest, sha256File(manifestPath)), responsePath, RELEASE_BUNDLE_SIZE_LIMITS.attestation);
27077
- if (manifest.repository === RELEASE_REPOSITORY) {
27078
- const bundles = serializeAttestationBundles(parseJsonFile(responsePath, "GitHub attestation response"));
27079
- writeFileSync2(destination, bundles, { mode: 384, flag: "wx" });
27080
- chmodSync2(destination, 384);
27081
- } else {
27082
- renameSync(responsePath, destination);
27083
- }
27146
+ const bundles = serializeAttestationBundles(parseJsonFile(responsePath, "GitHub attestation response"));
27147
+ writeFileSync2(destination, bundles, { mode: 384, flag: "wx" });
27148
+ chmodSync2(destination, 384);
27084
27149
  } finally {
27085
27150
  rmSync2(responsePath, { force: true });
27086
27151
  }
@@ -27089,7 +27154,14 @@ async function downloadComponent(request) {
27089
27154
  const release = await downloadReleaseMetadata(request.component, request.version, request.destination);
27090
27155
  const manifestPath = directChildPath(request.destination, RELEASE_MANIFEST_NAME);
27091
27156
  const attestationPath = directChildPath(request.destination, RELEASE_ATTESTATION_NAME);
27092
- await downloadDirect(releaseAssetUrl(release, RELEASE_MANIFEST_NAME), manifestPath, RELEASE_BUNDLE_SIZE_LIMITS.manifest);
27157
+ releaseAssetUrl(release, RELEASE_MANIFEST_NAME);
27158
+ await downloadGithubReleaseAsset({
27159
+ repository: RELEASE_REPOSITORY,
27160
+ tag: release.tag_name,
27161
+ assetName: RELEASE_MANIFEST_NAME,
27162
+ destination: manifestPath,
27163
+ maxBytes: RELEASE_BUNDLE_SIZE_LIMITS.manifest
27164
+ });
27093
27165
  const manifest = parseReleaseManifest(readFileSync3(manifestPath, "utf8"), request);
27094
27166
  await downloadManifestAttestation({ release, manifest, manifestPath, destination: attestationPath });
27095
27167
  await verifyManifestAttestation({
@@ -27099,12 +27171,26 @@ async function downloadComponent(request) {
27099
27171
  trustedRootPath: request.trustedRootPath
27100
27172
  });
27101
27173
  const checksumsPath = directChildPath(request.destination, RELEASE_CHECKSUMS_NAME);
27102
- await downloadDirect(releaseAssetUrl(release, RELEASE_CHECKSUMS_NAME), checksumsPath, RELEASE_BUNDLE_SIZE_LIMITS.checksums);
27174
+ releaseAssetUrl(release, RELEASE_CHECKSUMS_NAME);
27175
+ await downloadGithubReleaseAsset({
27176
+ repository: RELEASE_REPOSITORY,
27177
+ tag: release.tag_name,
27178
+ assetName: RELEASE_CHECKSUMS_NAME,
27179
+ destination: checksumsPath,
27180
+ maxBytes: RELEASE_BUNDLE_SIZE_LIMITS.checksums
27181
+ });
27103
27182
  assertSignedArtifact(checksumsPath, manifest);
27104
27183
  const checksums = parseReleaseChecksums(readFileSync3(checksumsPath, "utf8"), manifest);
27105
27184
  for (const assetName of request.assetNames) {
27106
27185
  const assetPath = directChildPath(request.destination, assetName);
27107
- await downloadDirect(releaseAssetUrl(release, assetName), assetPath, releaseAssetSizeLimit(request.component, assetName));
27186
+ releaseAssetUrl(release, assetName);
27187
+ await downloadGithubReleaseAsset({
27188
+ repository: RELEASE_REPOSITORY,
27189
+ tag: release.tag_name,
27190
+ assetName,
27191
+ destination: assetPath,
27192
+ maxBytes: releaseAssetSizeLimit(request.component, assetName)
27193
+ });
27108
27194
  verifyDownloadedFile(assetPath, manifest, checksums);
27109
27195
  }
27110
27196
  return [RELEASE_MANIFEST_NAME, RELEASE_ATTESTATION_NAME, RELEASE_CHECKSUMS_NAME, ...request.assetNames].map((name) => localUpgradeFile(directChildPath(request.destination, name), `bundle/${request.component}/${name}`));
@@ -27112,8 +27198,13 @@ async function downloadComponent(request) {
27112
27198
  async function downloadPinnedGithubCli(directory, architecture) {
27113
27199
  const identity = githubCliArchiveIdentity(architecture);
27114
27200
  const archivePath = directChildPath(directory, identity.archiveName);
27115
- const url = `https://github.com/cli/cli/releases/download/v${identity.version}/${identity.archiveName}`;
27116
- await downloadDirect(url, archivePath, MAX_GH_ARCHIVE_BYTES);
27201
+ await downloadGithubReleaseAsset({
27202
+ repository: GITHUB_CLI_REPOSITORY,
27203
+ tag: `v${identity.version}`,
27204
+ assetName: identity.archiveName,
27205
+ destination: archivePath,
27206
+ maxBytes: MAX_GH_ARCHIVE_BYTES
27207
+ });
27117
27208
  if (sha256File(archivePath) !== identity.sha256) {
27118
27209
  throw new Error("Pinned GitHub CLI archive SHA256 mismatch");
27119
27210
  }
@@ -32154,7 +32245,7 @@ Actions: list_releases, get_release, upload_release, activate_release`, {
32154
32245
  // package.json
32155
32246
  var package_default = {
32156
32247
  name: "@supacloud/admin",
32157
- version: "0.15.3",
32248
+ version: "0.15.4",
32158
32249
  description: "Platform administration CLI for SupaCloud operators",
32159
32250
  type: "module",
32160
32251
  main: "./dist/index.js",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@supacloud/admin",
3
- "version": "0.15.3",
3
+ "version": "0.15.4",
4
4
  "description": "Platform administration CLI for SupaCloud operators",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",