run-spaceapp 0.1.18 → 0.1.19

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/package.json +3 -3
  2. package/src/index.mjs +25 -8
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "run-spaceapp",
3
- "version": "0.1.18",
4
- "spaceappRuntimeVersion": "0.1.18",
3
+ "version": "0.1.19",
4
+ "spaceappRuntimeVersion": "0.1.19",
5
5
  "spaceappHostRootRuntimeCompatible": true,
6
6
  "description": "Cross-platform Docker launcher for the SpaceApp self-hosted agent workspace",
7
7
  "license": "Apache-2.0",
@@ -52,5 +52,5 @@
52
52
  "access": "public",
53
53
  "provenance": true
54
54
  },
55
- "gitHead": "cf4692ac9bbf433e035042caba2c29a64c3d5827"
55
+ "gitHead": "482d6e8db5b39ab0e3002f016a336e5a28288dc8"
56
56
  }
package/src/index.mjs CHANGED
@@ -23,6 +23,7 @@ const CONFIG_SCHEMA_VERSION = 3;
23
23
  const MIN_INSTALL_CPU_COUNT = 4;
24
24
  const MIN_INSTALL_MEMORY_BYTES = 7 * 1024 ** 3;
25
25
  const MIN_INSTALL_MEMORY_LABEL = "7 GiB usable (8 GB-class system)";
26
+ const CONTAINER_SECRET_MODE = 0o644;
26
27
  const MIN_INSTALL_FREE_DISK_BYTES = 15 * 1024 ** 3;
27
28
  const PROFILE_RUNTIME_SETTINGS = Object.freeze({
28
29
  light: Object.freeze({
@@ -603,8 +604,9 @@ export async function prepareInstallation(root, {
603
604
  throw error;
604
605
  }
605
606
  postgresPassword = randomBytes(32).toString("base64url");
606
- await atomicWrite(postgresPasswordPath, postgresPassword);
607
+ await atomicWrite(postgresPasswordPath, postgresPassword, CONTAINER_SECRET_MODE);
607
608
  }
609
+ await ensureContainerSecretReadable(postgresPasswordPath);
608
610
  const databaseUrlPath = join(root, "secrets", "database-url");
609
611
  try {
610
612
  await stat(databaseUrlPath);
@@ -615,9 +617,11 @@ export async function prepareInstallation(root, {
615
617
  const encodedPassword = encodeURIComponent(postgresPassword);
616
618
  await atomicWrite(
617
619
  databaseUrlPath,
618
- `postgresql://spaceapp:${encodedPassword}@postgres:5432/spaceapp`
620
+ `postgresql://spaceapp:${encodedPassword}@postgres:5432/spaceapp`,
621
+ CONTAINER_SECRET_MODE
619
622
  );
620
623
  }
624
+ await ensureContainerSecretReadable(databaseUrlPath);
621
625
 
622
626
  const sessionSecretPath = join(root, "secrets", "session-secret");
623
627
  try {
@@ -626,8 +630,9 @@ export async function prepareInstallation(root, {
626
630
  if (error?.code !== "ENOENT") {
627
631
  throw error;
628
632
  }
629
- await atomicWrite(sessionSecretPath, randomBytes(48).toString("base64url"));
633
+ await atomicWrite(sessionSecretPath, randomBytes(48).toString("base64url"), CONTAINER_SECRET_MODE);
630
634
  }
635
+ await ensureContainerSecretReadable(sessionSecretPath);
631
636
 
632
637
  const setupTokenPath = join(root, "secrets", "setup-token");
633
638
  let setupToken = null;
@@ -638,8 +643,9 @@ export async function prepareInstallation(root, {
638
643
  throw error;
639
644
  }
640
645
  setupToken = randomBytes(32).toString("base64url");
641
- await atomicWrite(setupTokenPath, setupToken);
646
+ await atomicWrite(setupTokenPath, setupToken, CONTAINER_SECRET_MODE);
642
647
  }
648
+ await ensureContainerSecretReadable(setupTokenPath);
643
649
  return { config, setupToken };
644
650
  }
645
651
 
@@ -707,20 +713,31 @@ function formatGibibytes(bytes) {
707
713
  return Math.floor((bytes / 1024 ** 3) * 10) / 10;
708
714
  }
709
715
 
710
- async function atomicWrite(target, value) {
716
+ async function atomicWrite(target, value, mode = 0o600) {
711
717
  await mkdir(dirname(target), { recursive: true, mode: 0o700 });
712
718
  const temporary = `${target}.tmp-${process.pid}-${randomBytes(6).toString("hex")}`;
713
719
  try {
714
- await writeFile(temporary, value, { encoding: "utf8", mode: 0o600, flag: "wx" });
715
- await chmod(temporary, 0o600);
720
+ await writeFile(temporary, value, { encoding: "utf8", mode, flag: "wx" });
721
+ await chmod(temporary, mode);
716
722
  await rename(temporary, target);
717
- await chmod(target, 0o600);
723
+ await chmod(target, mode);
718
724
  } catch (error) {
719
725
  await rm(temporary, { force: true }).catch(() => {});
720
726
  throw error;
721
727
  }
722
728
  }
723
729
 
730
+ async function ensureContainerSecretReadable(path) {
731
+ if (process.platform === "win32") {
732
+ return;
733
+ }
734
+ await chmod(path, CONTAINER_SECRET_MODE).catch((error) => {
735
+ if (error?.code !== "ENOENT") {
736
+ throw error;
737
+ }
738
+ });
739
+ }
740
+
724
741
  function defaultTemplateDir() {
725
742
  return resolve(dirname(fileURLToPath(import.meta.url)), "../templates");
726
743
  }