trainfabric 0.1.31 → 0.1.32

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.cjs +54 -11
  2. package/package.json +1 -1
package/dist/index.cjs CHANGED
@@ -8923,7 +8923,17 @@ function collectRuntimeFiles(repoPath) {
8923
8923
  if (found.length >= maxFiles) {
8924
8924
  return;
8925
8925
  }
8926
- for (const entry of import_node_fs.default.readdirSync(currentPath, { withFileTypes: true })) {
8926
+ let entries;
8927
+ try {
8928
+ entries = import_node_fs.default.readdirSync(currentPath, { withFileTypes: true });
8929
+ } catch (error) {
8930
+ if (error.code === "EACCES" || error.code === "EPERM") {
8931
+ const relativePath = import_node_path2.default.relative(repoPath, currentPath) || ".";
8932
+ throw new Error(`Permission denied while scanning repository path: ${relativePath}`);
8933
+ }
8934
+ throw new Error(`Failed to scan repository path: ${currentPath}`);
8935
+ }
8936
+ for (const entry of entries) {
8927
8937
  const absolute = import_node_path2.default.join(currentPath, entry.name);
8928
8938
  const relative = import_node_path2.default.relative(repoPath, absolute).split(import_node_path2.default.sep).join("/");
8929
8939
  if (entry.isDirectory()) {
@@ -8935,13 +8945,30 @@ function collectRuntimeFiles(repoPath) {
8935
8945
  if (!entry.isFile() || !shouldIncludeFile(entry.name)) {
8936
8946
  continue;
8937
8947
  }
8938
- const stat = import_node_fs.default.statSync(absolute);
8948
+ let stat;
8949
+ try {
8950
+ stat = import_node_fs.default.statSync(absolute);
8951
+ } catch (error) {
8952
+ if (error.code === "EACCES" || error.code === "EPERM") {
8953
+ throw new Error(`Permission denied while scanning repository file: ${relative}`);
8954
+ }
8955
+ throw new Error(`Failed to inspect repository file: ${relative}`);
8956
+ }
8939
8957
  if (stat.size > maxFileBytes) {
8940
8958
  continue;
8941
8959
  }
8960
+ let content;
8961
+ try {
8962
+ content = import_node_fs.default.readFileSync(absolute, "utf8");
8963
+ } catch (error) {
8964
+ if (error.code === "EACCES" || error.code === "EPERM") {
8965
+ throw new Error(`Permission denied while reading repository file: ${relative}`);
8966
+ }
8967
+ throw new Error(`Failed to read repository file: ${relative}`);
8968
+ }
8942
8969
  found.push({
8943
8970
  path: relative,
8944
- content: import_node_fs.default.readFileSync(absolute, "utf8")
8971
+ content
8945
8972
  });
8946
8973
  }
8947
8974
  }
@@ -8985,7 +9012,22 @@ function validateGitBranch(value) {
8985
9012
  function validateRepoPath(repoPath) {
8986
9013
  const absolute = import_node_path2.default.resolve(repoPath);
8987
9014
  const parsed = import_node_path2.default.parse(absolute);
8988
- if (absolute === parsed.root || absolute === import_node_os.default.homedir()) {
9015
+ const unsafeRoots = /* @__PURE__ */ new Set([
9016
+ parsed.root,
9017
+ import_node_os.default.homedir(),
9018
+ import_node_path2.default.resolve(import_node_os.default.tmpdir()),
9019
+ import_node_path2.default.resolve("/tmp"),
9020
+ import_node_path2.default.resolve("/private/tmp"),
9021
+ import_node_path2.default.resolve("/var"),
9022
+ import_node_path2.default.resolve("/Users"),
9023
+ import_node_path2.default.resolve("/System"),
9024
+ import_node_path2.default.resolve("/Library"),
9025
+ import_node_path2.default.resolve("/Applications"),
9026
+ import_node_path2.default.resolve("/etc"),
9027
+ import_node_path2.default.resolve("/bin"),
9028
+ import_node_path2.default.resolve("/usr")
9029
+ ]);
9030
+ if (unsafeRoots.has(absolute)) {
8989
9031
  throw new Error(`Refusing to package unsafe repository path: ${repoPath}`);
8990
9032
  }
8991
9033
  let stat;
@@ -9207,7 +9249,7 @@ function buildComputeSpec(options) {
9207
9249
 
9208
9250
  // src/index.ts
9209
9251
  var DEFAULT_TRAINFABRIC_API_URL2 = "https://api.trainfabric.com";
9210
- var CLI_VERSION = "0.1.31";
9252
+ var CLI_VERSION = "0.1.32";
9211
9253
  var CONFIG_DIR = import_node_path3.default.join(import_node_os2.default.homedir(), ".trainfabric");
9212
9254
  var CONFIG_PATH = import_node_path3.default.join(CONFIG_DIR, "config.json");
9213
9255
  var FALLBACK_SECRET_PATH = import_node_path3.default.join(CONFIG_DIR, "session.enc");
@@ -9731,14 +9773,15 @@ function normalizeHttpBaseUrl(value) {
9731
9773
  try {
9732
9774
  url = new URL(value);
9733
9775
  } catch {
9734
- throw new Error(`Invalid base URL "${value}". Use an absolute http(s) URL such as https://api.trainfabric.com.`);
9776
+ throw new Error(`Invalid base URL "${value}". Use an absolute HTTPS origin such as https://api.trainfabric.com.`);
9777
+ }
9778
+ const isLocalDevHost = url.hostname === "localhost" || url.hostname === "127.0.0.1" || url.hostname === "::1";
9779
+ if (url.protocol !== "https:" && !(isLocalDevHost && url.protocol === "http:")) {
9780
+ throw new Error(`Invalid base URL "${value}". Use HTTPS, or http://localhost for local development.`);
9735
9781
  }
9736
- if (url.protocol !== "https:" && url.protocol !== "http:") {
9737
- throw new Error(`Invalid base URL "${value}". Use an absolute http(s) URL such as https://api.trainfabric.com.`);
9782
+ if (url.pathname !== "/" || url.search || url.hash) {
9783
+ throw new Error(`Invalid base URL "${value}". Use the API origin without a path, query, or hash.`);
9738
9784
  }
9739
- url.pathname = url.pathname.replace(/\/+$/, "");
9740
- url.search = "";
9741
- url.hash = "";
9742
9785
  return url.toString().replace(/\/+$/, "");
9743
9786
  }
9744
9787
  async function login(config) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "trainfabric",
3
- "version": "0.1.31",
3
+ "version": "0.1.32",
4
4
  "description": "Trainfabric CLI for launching GPU training jobs on the hosted Trainfabric backend.",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",