openship 0.6.9 → 0.7.0

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 (58) hide show
  1. package/dist/bare-3POKLHTW.js +29 -0
  2. package/dist/{chunk-UAWY6X7V.js → chunk-3KUW2UC6.js} +470 -59
  3. package/dist/{chunk-GNOMEMNI.js → chunk-3LWGDMJU.js} +1 -1
  4. package/dist/{chunk-ENKJ7XIF.js → chunk-5CFUYMPE.js} +11 -11
  5. package/dist/{chunk-NUT6HKK6.js → chunk-5D27WZBW.js} +5 -5
  6. package/dist/{chunk-NIYD7MD2.js → chunk-7MKZP4TW.js} +89 -45
  7. package/dist/{chunk-IAMOUDHY.js → chunk-AUBB5DLY.js} +24 -15
  8. package/dist/{chunk-7PEXM2UI.js → chunk-BOD2IQ3P.js} +6 -6
  9. package/dist/{chunk-D6HU4VUZ.js → chunk-CMGRMPRQ.js} +1 -1
  10. package/dist/{chunk-MUWVC5R4.js → chunk-DZBXOF5Q.js} +11 -8
  11. package/dist/{chunk-BO6CY4V2.js → chunk-GEHV7JBS.js} +47 -4
  12. package/dist/{chunk-R5DC5PEF.js → chunk-GYDROM4W.js} +39 -10
  13. package/dist/{chunk-TAZZZKYO.js → chunk-HBQWOJRP.js} +1 -1
  14. package/dist/{chunk-WEZFTL4V.js → chunk-IVRTIKNZ.js} +183 -0
  15. package/dist/{chunk-P7RCYELG.js → chunk-J2NDOB7D.js} +1 -1
  16. package/dist/{chunk-T6DVUX4F.js → chunk-J4SYG2LC.js} +14 -3
  17. package/dist/{chunk-VAI5VOOI.js → chunk-JAKVPLHT.js} +1 -1
  18. package/dist/{chunk-NPSRGIHV.js → chunk-JWW5YAFL.js} +5 -4
  19. package/dist/{chunk-FCGJN5Q5.js → chunk-KYTTPWRP.js} +9 -9
  20. package/dist/{chunk-7YBWXEM6.js → chunk-LL7M7GL4.js} +4 -4
  21. package/dist/{chunk-SK4FFCFR.js → chunk-MZYD3LFP.js} +1 -1
  22. package/dist/{chunk-6GU6JSK6.js → chunk-QNQFS37A.js} +3 -3
  23. package/dist/{chunk-T46BQOLY.js → chunk-RHHCAWW3.js} +3 -3
  24. package/dist/{chunk-5UXHT6ED.js → chunk-SPR7N2EK.js} +113 -20
  25. package/dist/{chunk-AHJYP7DG.js → chunk-SYQ3FOLE.js} +74 -17
  26. package/dist/{chunk-3MP6ACKM.js → chunk-TPGBT5UR.js} +185 -78
  27. package/dist/{chunk-634DDFT5.js → chunk-TT7P5ZZ3.js} +8 -8
  28. package/dist/{chunk-D3OEMXYP.js → chunk-XQC6KYZD.js} +12 -7
  29. package/dist/{chunk-X53JXRS4.js → chunk-YGA52DHX.js} +3 -3
  30. package/dist/{chunk-5DJOB7IX.js → chunk-ZFA3MZ5N.js} +3 -3
  31. package/dist/{cloud-REV3DPJH.js → cloud-RFZSO6P5.js} +19 -19
  32. package/dist/{detect-BBFT5GEU.js → detect-NXD3PYBM.js} +4 -4
  33. package/dist/{docker-EG3QSE6I.js → docker-U5APUZBI.js} +10 -10
  34. package/dist/{docker-edge-executor-E5TOTLMR.js → docker-edge-executor-HUQOWFQU.js} +7 -7
  35. package/dist/{edge-import-YJVJUGYC.js → edge-import-UXD52WQR.js} +26 -26
  36. package/dist/{edge-preflight-QUW4BM7N.js → edge-preflight-3PMJ5BWM.js} +13 -13
  37. package/dist/{ensure-container-edge-FOEFQ3PI.js → ensure-container-edge-GDPY7UJD.js} +11 -11
  38. package/dist/{executor-NTWDJ3DB.js → executor-XOVSO6QZ.js} +6 -6
  39. package/dist/{host-channel-preflight-OI2TRHSG.js → host-channel-preflight-T2QUDQXU.js} +26 -26
  40. package/dist/index.js +71 -49
  41. package/dist/{local-executor-OQ2GRN7K.js → local-executor-KR7BFCJP.js} +3 -3
  42. package/dist/{nginx-4U4C2XUS.js → nginx-JMLAS7YS.js} +9 -9
  43. package/dist/{openresty-lua-LLWT5XQW.js → openresty-lua-FJH3KEC4.js} +7 -7
  44. package/dist/{privilege-MNDVMDST.js → privilege-H2QTJ5TE.js} +5 -5
  45. package/dist/server/index.js +9627 -4439
  46. package/dist/server/lua/site_logger.lua +18 -1
  47. package/dist/server/migrations/0117_github_installation_workspace_scope.sql +24 -0
  48. package/dist/server/migrations/0118_git_sources.sql +66 -0
  49. package/dist/server/migrations/0119_backup_run_batch.sql +8 -0
  50. package/dist/server/migrations/0120_domain_primary_unique.sql +24 -0
  51. package/dist/server/migrations/0121_host_port_claim_overlap.sql +14 -0
  52. package/dist/server/migrations/meta/_journal.json +35 -0
  53. package/dist/{setup-IFIMPQZJ.js → setup-ERGE5XNW.js} +12 -12
  54. package/dist/{ssh-client-2XWZCMGI.js → ssh-client-WVLLOAYK.js} +2 -2
  55. package/dist/up-EFCE6KA6.js +61 -0
  56. package/package.json +1 -1
  57. package/dist/bare-FA66N7GC.js +0 -29
  58. package/dist/up-RC5ZQIAD.js +0 -61
@@ -8621,6 +8621,156 @@ Two things worth knowing, both upstream behaviour: if the console shows a branch
8621
8621
  defaultMode: "domain"
8622
8622
  }
8623
8623
  ]
8624
+ },
8625
+ {
8626
+ $schema: "https://openship.io/app.schema.json",
8627
+ available: true,
8628
+ minEngine: "0.6.6",
8629
+ id: "pocketbase",
8630
+ name: "PocketBase",
8631
+ description: "Self-hosted PocketBase with auth, a realtime SQLite database, file storage, and an admin dashboard in one small service.",
8632
+ repository: "https://github.com/pocketbase/pocketbase",
8633
+ kind: "template",
8634
+ logo: "pocketbase",
8635
+ category: "backend",
8636
+ tags: [
8637
+ "auth",
8638
+ "database",
8639
+ "sqlite",
8640
+ "realtime"
8641
+ ],
8642
+ framework: "docker-compose",
8643
+ services: [
8644
+ {
8645
+ name: "pocketbase",
8646
+ build: {
8647
+ dockerfile: 'FROM alpine:3.24.1 AS downloader\nARG PB_VERSION=0.40.1\nRUN apk add --no-cache ca-certificates unzip wget \\\n && ARCH=$(uname -m) \\\n && case "$ARCH" in x86_64) ARCH=amd64 ;; aarch64) ARCH=arm64 ;; *) echo "Unsupported architecture: $ARCH" >&2; exit 1 ;; esac \\\n && wget -q https://github.com/pocketbase/pocketbase/releases/download/v${PB_VERSION}/checksums.txt -O /tmp/checksums.txt \\\n && wget -q https://github.com/pocketbase/pocketbase/releases/download/v${PB_VERSION}/pocketbase_${PB_VERSION}_linux_${ARCH}.zip -O /tmp/pocketbase_${PB_VERSION}_linux_${ARCH}.zip \\\n && cd /tmp \\\n && grep " pocketbase_${PB_VERSION}_linux_${ARCH}.zip$" checksums.txt | sha256sum -c - \\\n && unzip pocketbase_${PB_VERSION}_linux_${ARCH}.zip -d /pb\nFROM alpine:3.24.1\nRUN apk add --no-cache ca-certificates su-exec \\\n && addgroup -S pocketbase \\\n && adduser -S -G pocketbase -h /pb pocketbase\nCOPY --chown=pocketbase:pocketbase --from=downloader /pb/pocketbase /pb/pocketbase\nCOPY --chown=pocketbase:pocketbase pocketbase/entrypoint.sh /pb/entrypoint.sh\nRUN chmod 755 /pb/entrypoint.sh\nWORKDIR /pb\nENTRYPOINT ["/pb/entrypoint.sh"]\nCMD ["/pb/pocketbase", "serve", "--http=0.0.0.0:8090", "--encryptionEnv=PB_ENCRYPTION_KEY"]\n',
8648
+ files: [
8649
+ {
8650
+ path: "entrypoint.sh",
8651
+ content: `#!/bin/sh
8652
+ set -eu
8653
+ mkdir -p /pb/pb_data
8654
+ chown pocketbase:pocketbase /pb/pb_data
8655
+ export PB_ENCRYPTION_KEY="$(printf '%.32s' "$PB_ENCRYPTION_SEED")"
8656
+ if [ ! -e /pb/pb_data/.openship-superuser ]; then
8657
+ su-exec pocketbase /pb/pocketbase superuser upsert "$POCKETBASE_SUPERUSER_EMAIL" "$POCKETBASE_SUPERUSER_PASSWORD" --dir=/pb/pb_data --encryptionEnv=PB_ENCRYPTION_KEY >/dev/null
8658
+ su-exec pocketbase touch /pb/pb_data/.openship-superuser
8659
+ fi
8660
+ exec su-exec pocketbase "$@"
8661
+ `
8662
+ }
8663
+ ]
8664
+ },
8665
+ environment: {
8666
+ GOMEMLIMIT: "512MiB"
8667
+ },
8668
+ secretEnv: [
8669
+ "PB_ENCRYPTION_SEED",
8670
+ "POCKETBASE_SUPERUSER_PASSWORD"
8671
+ ],
8672
+ ports: [
8673
+ "8090:8090"
8674
+ ],
8675
+ exposedPort: 8090,
8676
+ exposed: true,
8677
+ volumes: [
8678
+ "pocketbase_data:/pb/pb_data"
8679
+ ],
8680
+ healthcheck: {
8681
+ test: [
8682
+ "CMD",
8683
+ "wget",
8684
+ "-qO-",
8685
+ "http://127.0.0.1:8090/api/health"
8686
+ ],
8687
+ interval: "5s",
8688
+ timeout: "3s",
8689
+ retries: 20,
8690
+ startPeriod: "10s"
8691
+ },
8692
+ stopGracePeriod: "30s",
8693
+ restart: "unless-stopped"
8694
+ }
8695
+ ],
8696
+ configFields: [
8697
+ {
8698
+ key: "PB_ENCRYPTION_SEED",
8699
+ service: "pocketbase",
8700
+ label: "Settings encryption seed",
8701
+ help: "Derives the stable 32-character key that encrypts PocketBase settings in the data volume.",
8702
+ generate: "secret",
8703
+ secret: true
8704
+ },
8705
+ {
8706
+ key: "POCKETBASE_SUPERUSER_PASSWORD",
8707
+ service: "pocketbase",
8708
+ label: "Initial superuser password",
8709
+ help: "Auto-generated for the first deployment and shown in the connection card.",
8710
+ generate: "secret",
8711
+ secret: true
8712
+ },
8713
+ {
8714
+ key: "POCKETBASE_SUPERUSER_EMAIL",
8715
+ service: "pocketbase",
8716
+ label: "Superuser email",
8717
+ help: "Email for the superuser created during the first deployment.",
8718
+ type: "text",
8719
+ default: "admin@openship.local",
8720
+ required: true
8721
+ }
8722
+ ],
8723
+ connection: {
8724
+ title: "Connect to PocketBase",
8725
+ description: "Use the public URL from browsers and other projects. The admin dashboard is available at /_/.",
8726
+ guide: {
8727
+ intro: "PocketBase stores auth, records, and files in one persistent SQLite-backed volume.",
8728
+ useHint: "Create scoped credentials for automation, configure off-host backups, and point each app at this URL.",
8729
+ defaultMode: "public"
8730
+ },
8731
+ outputs: [
8732
+ {
8733
+ id: "url",
8734
+ label: "PocketBase URL",
8735
+ source: "publicUrl:pocketbase",
8736
+ kind: "url",
8737
+ envKey: "POCKETBASE_URL",
8738
+ recommended: true
8739
+ },
8740
+ {
8741
+ id: "email",
8742
+ label: "Superuser email",
8743
+ source: "env:pocketbase:POCKETBASE_SUPERUSER_EMAIL",
8744
+ envKey: "POCKETBASE_SUPERUSER_EMAIL"
8745
+ },
8746
+ {
8747
+ id: "password",
8748
+ label: "Initial superuser password",
8749
+ help: "Use this installation credential until you change the password in PocketBase.",
8750
+ source: "env:pocketbase:POCKETBASE_SUPERUSER_PASSWORD",
8751
+ envKey: "POCKETBASE_SUPERUSER_PASSWORD",
8752
+ secret: true
8753
+ }
8754
+ ]
8755
+ },
8756
+ provides: [
8757
+ {
8758
+ id: "pocketbase",
8759
+ outputRefs: [
8760
+ "url"
8761
+ ],
8762
+ category: "database"
8763
+ }
8764
+ ],
8765
+ endpoints: [
8766
+ {
8767
+ service: "pocketbase",
8768
+ port: 8090,
8769
+ label: "PocketBase API and dashboard",
8770
+ kind: "http",
8771
+ defaultMode: "domain"
8772
+ }
8773
+ ]
8624
8774
  }
8625
8775
  ]
8626
8776
  };
@@ -25919,6 +26069,39 @@ var AUDIT_EVENTS = {
25919
26069
  label: "GitHub app installed",
25920
26070
  tone: "info"
25921
26071
  },
26072
+ "github.source.created": {
26073
+ category: "system",
26074
+ action: "registered the GitHub App source",
26075
+ label: "GitHub App source registered",
26076
+ tone: "info",
26077
+ description: "An organization-owned GitHub App was verified and stored. Secret values are never recorded."
26078
+ },
26079
+ "github.source.updated": {
26080
+ category: "system",
26081
+ action: "updated the GitHub App source",
26082
+ label: "GitHub App source updated",
26083
+ tone: "info",
26084
+ description: "A GitHub App's identity, endpoint, or encrypted credentials changed."
26085
+ },
26086
+ "github.source.verified": {
26087
+ category: "system",
26088
+ action: "verified the GitHub App source",
26089
+ label: "GitHub App source verified",
26090
+ tone: "info"
26091
+ },
26092
+ "github.source.defaulted": {
26093
+ category: "system",
26094
+ action: "made the default GitHub App source",
26095
+ label: "Default GitHub App source changed",
26096
+ tone: "info"
26097
+ },
26098
+ "github.source.deleted": {
26099
+ category: "system",
26100
+ action: "deleted the GitHub App source",
26101
+ label: "GitHub App source deleted",
26102
+ tone: "warning",
26103
+ description: "The local App credentials and installation bindings were removed; the GitHub App itself was not uninstalled on GitHub."
26104
+ },
25922
26105
  "github.disconnect": {
25923
26106
  category: "system",
25924
26107
  action: "disconnected GitHub from",
@@ -4,7 +4,7 @@ import { createRequire as __ospCreateRequire } from "node:module";
4
4
  const require = __ospCreateRequire(import.meta.url);
5
5
  import {
6
6
  shellQuote
7
- } from "./chunk-WEZFTL4V.js";
7
+ } from "./chunk-IVRTIKNZ.js";
8
8
 
9
9
  // ../../packages/adapters/src/system/local-shell.ts
10
10
  import { execFile } from "child_process";
@@ -8,13 +8,14 @@ import {
8
8
  getLocalShellPath,
9
9
  logEntry,
10
10
  sq
11
- } from "./chunk-P7RCYELG.js";
11
+ } from "./chunk-J2NDOB7D.js";
12
12
 
13
13
  // ../../packages/adapters/src/system/local-executor.ts
14
14
  import { exec, spawn } from "child_process";
15
15
  import {
16
16
  access,
17
17
  mkdir as fsMkdir,
18
+ open as fsOpen,
18
19
  readFile as fsReadFile,
19
20
  rename as fsRename,
20
21
  rm as fsRm,
@@ -82,9 +83,19 @@ var LocalExecutor = class {
82
83
  });
83
84
  });
84
85
  }
85
- async writeFile(path, content) {
86
+ async writeFile(path, content, opts) {
86
87
  await fsMkdir(dirname(path), { recursive: true });
87
- await fsWriteFile(path, content, "utf-8");
88
+ if (opts?.mode === void 0) {
89
+ await fsWriteFile(path, content, "utf-8");
90
+ return;
91
+ }
92
+ const file = await fsOpen(path, "w", opts.mode);
93
+ try {
94
+ await file.chmod(opts.mode);
95
+ await file.writeFile(content, "utf-8");
96
+ } finally {
97
+ await file.close();
98
+ }
88
99
  }
89
100
  async rename(from, to) {
90
101
  await fsRename(from, to);
@@ -4,7 +4,7 @@ import { createRequire as __ospCreateRequire } from "node:module";
4
4
  const require = __ospCreateRequire(import.meta.url);
5
5
  import {
6
6
  PACKAGE_ROOT_ONLY_EXCLUDES
7
- } from "./chunk-WEZFTL4V.js";
7
+ } from "./chunk-IVRTIKNZ.js";
8
8
 
9
9
  // ../../packages/adapters/src/archive.ts
10
10
  import { execFile } from "child_process";
@@ -4,7 +4,7 @@ import { createRequire as __ospCreateRequire } from "node:module";
4
4
  const require = __ospCreateRequire(import.meta.url);
5
5
  import {
6
6
  sq
7
- } from "./chunk-P7RCYELG.js";
7
+ } from "./chunk-J2NDOB7D.js";
8
8
  import {
9
9
  formatDuration,
10
10
  isRemoteConnectionError,
@@ -17,7 +17,7 @@ import {
17
17
  parseSystemArch,
18
18
  parseSystemOs,
19
19
  safeErrorMessage
20
- } from "./chunk-WEZFTL4V.js";
20
+ } from "./chunk-IVRTIKNZ.js";
21
21
 
22
22
  // ../../packages/adapters/src/system/elevated-executor.ts
23
23
  import { randomBytes } from "crypto";
@@ -47,12 +47,13 @@ function elevatedExecutor(inner) {
47
47
  if (await inner.exists(path).catch(() => false)) return true;
48
48
  return await inner.exec(elevateCommand(`test -e ${sq(path)}`)).then(() => true).catch(() => false);
49
49
  };
50
- const writeFileElevated = async (path, content) => {
50
+ const writeFileElevated = async (path, content, opts) => {
51
51
  const stage = `/tmp/.openship-elev-${randomBytes(12).toString("hex")}`;
52
52
  await inner.exec(`mkdir -m 700 ${sq(stage)}`);
53
53
  try {
54
54
  const staged = `${stage}/payload`;
55
- await inner.writeFile(staged, content);
55
+ if (opts === void 0) await inner.writeFile(staged, content);
56
+ else await inner.writeFile(staged, content, opts);
56
57
  await inner.exec(
57
58
  elevateCommand(
58
59
  `mkdir -p ${sq(dirOf(path))} && chown 0:0 ${sq(staged)} && mv -f ${sq(staged)} ${sq(path)}`
@@ -28,7 +28,7 @@ import {
28
28
  resolvePorts,
29
29
  sourceBuildDir,
30
30
  verifyHostChannel
31
- } from "./chunk-634DDFT5.js";
31
+ } from "./chunk-TT7P5ZZ3.js";
32
32
  import {
33
33
  bootstrapAdmin,
34
34
  importMigratedSites,
@@ -36,18 +36,18 @@ import {
36
36
  internalPost,
37
37
  mintBareInternalToken,
38
38
  waitHealthy
39
- } from "./chunk-7YBWXEM6.js";
39
+ } from "./chunk-LL7M7GL4.js";
40
40
  import {
41
41
  startUnitHint,
42
42
  thisHost
43
- } from "./chunk-5UXHT6ED.js";
43
+ } from "./chunk-SPR7N2EK.js";
44
44
  import {
45
45
  completeHostEdge,
46
46
  markStoppedProxyImported,
47
47
  planAndApplyHostEdge,
48
48
  previewHostEdge,
49
49
  rollbackHostEdge
50
- } from "./chunk-NUT6HKK6.js";
50
+ } from "./chunk-5D27WZBW.js";
51
51
  import {
52
52
  AUTH_SECRET_FILE,
53
53
  DATA_DIR,
@@ -58,17 +58,17 @@ import {
58
58
  } from "./chunk-ELGRMZOW.js";
59
59
  import {
60
60
  LocalExecutor
61
- } from "./chunk-T6DVUX4F.js";
61
+ } from "./chunk-J4SYG2LC.js";
62
62
  import {
63
63
  edgeCrashReason,
64
64
  edgeIsBroken
65
- } from "./chunk-X53JXRS4.js";
65
+ } from "./chunk-YGA52DHX.js";
66
66
  import {
67
67
  EDGE_CONTAINER_NAME
68
- } from "./chunk-D6HU4VUZ.js";
68
+ } from "./chunk-CMGRMPRQ.js";
69
69
  import {
70
70
  isValidEmail
71
- } from "./chunk-WEZFTL4V.js";
71
+ } from "./chunk-IVRTIKNZ.js";
72
72
 
73
73
  // src/commands/up.ts
74
74
  import { Command } from "commander";
@@ -1564,7 +1564,7 @@ async function runForeground(opts, source) {
1564
1564
  const uiSpinner = ora("Preparing the dashboard\u2026").start();
1565
1565
  try {
1566
1566
  const bundle = await ensureDashboard({
1567
- tag: source ? "local" : opts.uiVersion || `v${"0.6.9"}`,
1567
+ tag: source ? "local" : opts.uiVersion || `v${"0.7.0"}`,
1568
1568
  onProgress: (received, total) => {
1569
1569
  if (total) {
1570
1570
  uiSpinner.text = `Downloading dashboard\u2026 ${Math.round(received / total * 100)}%`;
@@ -7,20 +7,20 @@ import {
7
7
  composeInstallExists,
8
8
  readComposeEnvFile,
9
9
  startUnitHint
10
- } from "./chunk-5UXHT6ED.js";
10
+ } from "./chunk-SPR7N2EK.js";
11
11
  import {
12
12
  INTERNAL_TOKEN_FILE,
13
13
  OS_DIR
14
14
  } from "./chunk-ELGRMZOW.js";
15
15
  import {
16
16
  LocalExecutor
17
- } from "./chunk-T6DVUX4F.js";
17
+ } from "./chunk-J4SYG2LC.js";
18
18
  import {
19
19
  edgeCrashReason
20
- } from "./chunk-X53JXRS4.js";
20
+ } from "./chunk-YGA52DHX.js";
21
21
  import {
22
22
  EDGE_CONTAINER_NAME
23
- } from "./chunk-D6HU4VUZ.js";
23
+ } from "./chunk-CMGRMPRQ.js";
24
24
 
25
25
  // src/lib/edge-import.ts
26
26
  import chalk from "chalk";
@@ -4,7 +4,7 @@ import { createRequire as __ospCreateRequire } from "node:module";
4
4
  const require = __ospCreateRequire(import.meta.url);
5
5
  import {
6
6
  sq
7
- } from "./chunk-P7RCYELG.js";
7
+ } from "./chunk-J2NDOB7D.js";
8
8
 
9
9
  // ../../packages/adapters/src/runtime/managed-artifact.ts
10
10
  var MANAGED_ARTIFACT_BASE = "/opt/openship";
@@ -13,14 +13,14 @@ import {
13
13
  resolveDockerRootDirectory,
14
14
  resolveDockerfileCandidates,
15
15
  resolveWithinDirectory
16
- } from "./chunk-AHJYP7DG.js";
16
+ } from "./chunk-SYQ3FOLE.js";
17
17
  import {
18
18
  getTarCreateEnv,
19
19
  prepareSourceTarArgs
20
- } from "./chunk-VAI5VOOI.js";
20
+ } from "./chunk-JAKVPLHT.js";
21
21
  import {
22
22
  isValidEnvKey
23
- } from "./chunk-WEZFTL4V.js";
23
+ } from "./chunk-IVRTIKNZ.js";
24
24
  import {
25
25
  __commonJS,
26
26
  __toESM
@@ -4,15 +4,15 @@ import { createRequire as __ospCreateRequire } from "node:module";
4
4
  const require = __ospCreateRequire(import.meta.url);
5
5
  import {
6
6
  hostRefusal
7
- } from "./chunk-GNOMEMNI.js";
7
+ } from "./chunk-3LWGDMJU.js";
8
8
  import {
9
9
  elevatedExecutor,
10
10
  resolveEnvironment
11
- } from "./chunk-NPSRGIHV.js";
11
+ } from "./chunk-JWW5YAFL.js";
12
12
  import {
13
13
  answered,
14
14
  refused
15
- } from "./chunk-WEZFTL4V.js";
15
+ } from "./chunk-IVRTIKNZ.js";
16
16
 
17
17
  // ../../packages/adapters/src/system/privilege.ts
18
18
  function rootChecked(executor, why) {
@@ -134,10 +134,10 @@ import {
134
134
  } from "./chunk-ZWLDLTJP.js";
135
135
  import {
136
136
  CloudRuntime
137
- } from "./chunk-MUWVC5R4.js";
137
+ } from "./chunk-DZBXOF5Q.js";
138
138
  import {
139
139
  OPENRESTY_DEFAULT_PATHS
140
- } from "./chunk-7PEXM2UI.js";
140
+ } from "./chunk-BOD2IQ3P.js";
141
141
  import {
142
142
  DockerRuntime,
143
143
  daemonConnectionFrom,
@@ -146,26 +146,26 @@ import {
146
146
  resolveExecExitCode,
147
147
  startAttachStream,
148
148
  startExecStream
149
- } from "./chunk-3MP6ACKM.js";
149
+ } from "./chunk-TPGBT5UR.js";
150
150
  import {
151
151
  BareRuntime
152
- } from "./chunk-ENKJ7XIF.js";
152
+ } from "./chunk-5CFUYMPE.js";
153
153
  import {
154
154
  createExecutor
155
- } from "./chunk-UAWY6X7V.js";
155
+ } from "./chunk-3KUW2UC6.js";
156
156
  import {
157
157
  envOps
158
- } from "./chunk-GNOMEMNI.js";
158
+ } from "./chunk-3LWGDMJU.js";
159
159
  import {
160
160
  ENVIRONMENT_PROBE_SCRIPT,
161
161
  ENVIRONMENT_PROBE_TIMEOUT_MS,
162
162
  cacheEnvironment,
163
163
  parseEnvironmentProbe,
164
164
  profileIsFresh
165
- } from "./chunk-NPSRGIHV.js";
165
+ } from "./chunk-JWW5YAFL.js";
166
166
  import {
167
167
  MAIL_HOST_STATE_DIR
168
- } from "./chunk-D6HU4VUZ.js";
168
+ } from "./chunk-CMGRMPRQ.js";
169
169
  import {
170
170
  FAMILY_BY_DISTRO,
171
171
  isAwsS3Endpoint,
@@ -177,7 +177,7 @@ import {
177
177
  validateBackupPath,
178
178
  validateClearPath,
179
179
  withTimeout
180
- } from "./chunk-WEZFTL4V.js";
180
+ } from "./chunk-IVRTIKNZ.js";
181
181
 
182
182
  // ../../packages/adapters/src/runtime/image-transfer.ts
183
183
  import { Transform } from "stream";
@@ -1141,6 +1141,8 @@ function demuxDockerStream(source, stdout, stderr, onError) {
1141
1141
 
1142
1142
  // ../../packages/adapters/src/backup/executors/docker.ts
1143
1143
  var HELPER_IMAGE = "alpine:3";
1144
+ var BIND_PROBE_TARGET = "/__openship_bind_source";
1145
+ var DOCKER_MODE_DIRECTORY = 2 ** 31;
1144
1146
  var ARTIFACT_BUFFER_BYTES = 4 * 1024 * 1024;
1145
1147
  var DEFAULT_HELPER_IDLE_MS = 10 * 60 * 1e3;
1146
1148
  var DEFAULT_HELPER_TIMEOUT_MS = 6 * 60 * 60 * 1e3;
@@ -1216,6 +1218,29 @@ function parseVolumeSpec(spec) {
1216
1218
  const type = isHostPathSource(source) ? "bind" : "volume";
1217
1219
  return { source, target, type };
1218
1220
  }
1221
+ function archivePathIsDirectory(response, path) {
1222
+ const rawHeader = response.headers?.["x-docker-container-path-stat"];
1223
+ const encoded = Array.isArray(rawHeader) ? rawHeader[0] : rawHeader;
1224
+ if (!encoded) {
1225
+ throw new Error(`Docker returned no path-stat header while inspecting ${path}`);
1226
+ }
1227
+ let stat;
1228
+ try {
1229
+ stat = JSON.parse(Buffer.from(encoded, "base64").toString("utf8"));
1230
+ } catch (err) {
1231
+ throw new Error(`Docker returned an invalid path-stat header while inspecting ${path}`, {
1232
+ cause: err
1233
+ });
1234
+ }
1235
+ const mode = stat?.mode;
1236
+ if (typeof mode !== "number" || !Number.isSafeInteger(mode)) {
1237
+ throw new Error(`Docker returned no valid path mode while inspecting ${path}`);
1238
+ }
1239
+ return mode >= DOCKER_MODE_DIRECTORY;
1240
+ }
1241
+ function isMissingBindSourceError(err) {
1242
+ return err?.statusCode === 400 && /bind source path does not exist/i.test(safeErrorMessage(err));
1243
+ }
1219
1244
  var DockerBackupExecutor = class {
1220
1245
  constructor(runtime) {
1221
1246
  this.runtime = runtime;
@@ -1244,23 +1269,82 @@ var DockerBackupExecutor = class {
1244
1269
  );
1245
1270
  }
1246
1271
  }
1272
+ /**
1273
+ * Ask the Docker daemon about a path in a container's mount namespace.
1274
+ *
1275
+ * The API may itself run in a container or connect to Docker over SSH/TLS, so
1276
+ * `node:fs` would inspect the wrong filesystem. Docker's archive-info endpoint
1277
+ * returns the daemon-side path's Go FileMode without copying any archive bytes.
1278
+ */
1279
+ async containerPathIsDirectory(container, path) {
1280
+ let response;
1281
+ try {
1282
+ response = await container.infoArchive({ path });
1283
+ return archivePathIsDirectory(response, path);
1284
+ } finally {
1285
+ response?.resume?.();
1286
+ }
1287
+ }
1288
+ /**
1289
+ * Classify a recorded bind source when there is no service container to inspect.
1290
+ * A never-started helper gives Docker a mount namespace, and archive-info reports
1291
+ * the source type from the daemon host. `Mounts` (rather than legacy `Binds`) is
1292
+ * deliberate: a missing source is rejected instead of being created as a directory.
1293
+ */
1294
+ async declaredBindIsDirectory(sourcePath) {
1295
+ try {
1296
+ return await this.withHelper(
1297
+ {
1298
+ Image: HELPER_IMAGE,
1299
+ NetworkDisabled: true,
1300
+ HostConfig: {
1301
+ Mounts: [
1302
+ {
1303
+ Type: "bind",
1304
+ Source: sourcePath,
1305
+ Target: BIND_PROBE_TARGET,
1306
+ ReadOnly: true
1307
+ }
1308
+ ]
1309
+ }
1310
+ },
1311
+ (helper) => this.containerPathIsDirectory(helper, BIND_PROBE_TARGET)
1312
+ );
1313
+ } catch (err) {
1314
+ if (isMissingBindSourceError(err)) return true;
1315
+ throw new Error(
1316
+ `Could not inspect bind mount source "${sourcePath}" on the Docker host: ` + safeErrorMessage(err),
1317
+ { cause: err }
1318
+ );
1319
+ }
1320
+ }
1247
1321
  async listSources(service) {
1248
1322
  if (service.containerId) {
1323
+ const container = this.dockerode.getContainer(service.containerId);
1324
+ let data = null;
1249
1325
  try {
1250
- const data = await this.dockerode.getContainer(service.containerId).inspect();
1251
- const mounts = data.Mounts ?? [];
1252
- return mounts.filter((m2) => m2.Type === "volume" || m2.Type === "bind").map(
1253
- (m2, i2) => ({
1254
- id: m2.Name ?? m2.Source ?? `mount-${i2}`,
1255
- target: m2.Destination ?? "",
1256
- source: m2.Name ?? m2.Source ?? "",
1257
- type: m2.Type ?? "volume"
1258
- })
1259
- );
1326
+ data = await container.inspect();
1260
1327
  } catch {
1261
1328
  }
1329
+ if (data) {
1330
+ const mounts = data.Mounts ?? [];
1331
+ const sources2 = [];
1332
+ for (const [i2, mount] of mounts.entries()) {
1333
+ if (mount.Type !== "volume" && mount.Type !== "bind") continue;
1334
+ if (mount.Type === "bind" && (!mount.Destination || !await this.containerPathIsDirectory(container, mount.Destination))) {
1335
+ continue;
1336
+ }
1337
+ sources2.push({
1338
+ id: mount.Name ?? mount.Source ?? `mount-${i2}`,
1339
+ target: mount.Destination ?? "",
1340
+ source: mount.Name ?? mount.Source ?? "",
1341
+ type: mount.Type
1342
+ });
1343
+ }
1344
+ return sources2;
1345
+ }
1262
1346
  }
1263
- return service.volumes.map((spec, i2) => {
1347
+ const sources = service.volumes.map((spec, i2) => {
1264
1348
  const parsed = parseVolumeSpec(spec);
1265
1349
  if (!parsed || !parsed.source) return null;
1266
1350
  const source = parsed.type === "volume" && service.namespaceVolumes ? ensureScopedVolumeName(service.projectSlug, parsed.source) : parsed.source;
@@ -1271,6 +1355,15 @@ var DockerBackupExecutor = class {
1271
1355
  type: parsed.type
1272
1356
  };
1273
1357
  }).filter((x2) => x2 !== null);
1358
+ if (!sources.some((source) => source.type === "bind")) return sources;
1359
+ await this.ensureImage(HELPER_IMAGE);
1360
+ const backupable = [];
1361
+ for (const source of sources) {
1362
+ if (source.type !== "bind" || await this.declaredBindIsDirectory(source.source)) {
1363
+ backupable.push(source);
1364
+ }
1365
+ }
1366
+ return backupable;
1274
1367
  }
1275
1368
  /**
1276
1369
  * The container's own `Config.Env`, as `KEY=value` pairs already split.