@getmonoceros/workbench 1.26.1 → 1.26.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.
|
@@ -6,6 +6,14 @@ service:
|
|
|
6
6
|
image: rustfs/rustfs:latest
|
|
7
7
|
defaultPort: 9000
|
|
8
8
|
dataMount: /data
|
|
9
|
+
# rustfs runs as a fixed non-root uid (10001) and must write its
|
|
10
|
+
# bind-mounted /data. The apply-created host data dir is owned by the
|
|
11
|
+
# apply user; on native Linux (no Docker-Desktop ownership remapping)
|
|
12
|
+
# uid 10001 can't write it and rustfs exits with a FATAL "Read-only file
|
|
13
|
+
# system". Running as root lets it write the mount — the same de-facto
|
|
14
|
+
# situation as postgres (whose image starts as root and chowns its data
|
|
15
|
+
# dir). Verified on a native Ubuntu host.
|
|
16
|
+
user: '0:0'
|
|
9
17
|
healthcheck:
|
|
10
18
|
test: [CMD, curl, -f, 'http://localhost:9000/minio/health/live']
|
|
11
19
|
interval: 10s
|
package/dist/bin.js
CHANGED
|
@@ -189,6 +189,12 @@ var init_schema = __esm({
|
|
|
189
189
|
"Invalid service name. Use lowercase letters, digits, '_' or '-' (must start with a letter or digit)."
|
|
190
190
|
),
|
|
191
191
|
image: z.string().min(1, "Service image must not be empty."),
|
|
192
|
+
// Compose `user:` for the service container (e.g. "0:0"). Set for images
|
|
193
|
+
// that run as a fixed non-root uid but must write a host bind-mounted
|
|
194
|
+
// dataMount — without it they can't write the apply-created data dir on
|
|
195
|
+
// native Linux and exit (e.g. rustfs). Curated entries bake this from the
|
|
196
|
+
// catalog; a builder can also set it by hand.
|
|
197
|
+
user: z.string().min(1).optional(),
|
|
192
198
|
// In-container port the service listens on. Used by
|
|
193
199
|
// `monoceros tunnel <name> <service>` to forward without an explicit
|
|
194
200
|
// port argument. NOT a host port mapping — host exposure goes through
|
|
@@ -727,6 +733,16 @@ var init_descriptor = __esm({
|
|
|
727
733
|
image: z2.string().min(1),
|
|
728
734
|
defaultPort: z2.number().int().positive().optional(),
|
|
729
735
|
dataMount: z2.string().optional(),
|
|
736
|
+
/**
|
|
737
|
+
* Compose `user:` for the service container (e.g. `"0:0"`). Needed for
|
|
738
|
+
* images that run as a fixed non-root uid yet must write a host
|
|
739
|
+
* bind-mounted `dataMount`: a freshly-created host data dir is owned by
|
|
740
|
+
* the apply user, and on native Linux (no Docker-Desktop ownership
|
|
741
|
+
* remapping) such an image cannot write it and exits. Running as root
|
|
742
|
+
* lets it write the mount — the same de-facto situation as postgres,
|
|
743
|
+
* whose image starts as root and chowns its data dir. E.g. rustfs.
|
|
744
|
+
*/
|
|
745
|
+
user: z2.string().min(1).optional(),
|
|
730
746
|
healthcheck: HealthcheckSchema.optional(),
|
|
731
747
|
/**
|
|
732
748
|
* Connection env injected into the WORKSPACE container so the app / agent
|
|
@@ -2180,6 +2196,7 @@ function resolveService(entry2) {
|
|
|
2180
2196
|
...entry2.port !== void 0 ? { port: entry2.port } : {},
|
|
2181
2197
|
env: entry2.env ? { ...entry2.env } : {},
|
|
2182
2198
|
volumes: entry2.volumes ? [...entry2.volumes] : [],
|
|
2199
|
+
...entry2.user ? { user: entry2.user } : {},
|
|
2183
2200
|
...entry2.healthcheck ? { healthcheck: entry2.healthcheck } : {},
|
|
2184
2201
|
...entry2.restart ? { restart: entry2.restart } : {},
|
|
2185
2202
|
...entry2.command ? { command: entry2.command } : {},
|
|
@@ -2206,6 +2223,7 @@ function expandCuratedService(name) {
|
|
|
2206
2223
|
)
|
|
2207
2224
|
} : {},
|
|
2208
2225
|
...def.dataMount ? { volumes: [`data:${def.dataMount}`] } : {},
|
|
2226
|
+
...def.user ? { user: def.user } : {},
|
|
2209
2227
|
...def.healthcheck ? { healthcheck: def.healthcheck } : {},
|
|
2210
2228
|
// Bake the connection-env templates into the yml (suffix → template) so
|
|
2211
2229
|
// they travel with the service: a renamed/duplicated instance keeps them,
|
|
@@ -2312,6 +2330,7 @@ var init_catalog = __esm({
|
|
|
2312
2330
|
...Object.keys(env).length > 0 ? { env } : {},
|
|
2313
2331
|
...svc.healthcheck ? { healthcheck: svc.healthcheck } : {},
|
|
2314
2332
|
...svc.dataMount ? { dataMount: svc.dataMount } : {},
|
|
2333
|
+
...svc.user ? { user: svc.user } : {},
|
|
2315
2334
|
defaultPort: svc.defaultPort,
|
|
2316
2335
|
...svc.vscodeExtensions ? { vscodeExtensions: svc.vscodeExtensions } : {},
|
|
2317
2336
|
...svc.connectionEnv ? { connectionEnv: svc.connectionEnv } : {},
|
|
@@ -2326,6 +2345,8 @@ var init_catalog = __esm({
|
|
|
2326
2345
|
// src/init/service-doc.ts
|
|
2327
2346
|
function renderServiceObjectBody(svc) {
|
|
2328
2347
|
const lines = [`name: ${svc.name}`, `image: ${svc.image}`];
|
|
2348
|
+
if (svc.user !== void 0)
|
|
2349
|
+
lines.push(`user: '${svc.user.replace(/'/g, "''")}'`);
|
|
2329
2350
|
if (svc.port !== void 0) lines.push(`port: ${svc.port}`);
|
|
2330
2351
|
if (svc.env && Object.keys(svc.env).length > 0) {
|
|
2331
2352
|
lines.push("env:");
|
|
@@ -2354,6 +2375,12 @@ function renderServiceObjectBody(svc) {
|
|
|
2354
2375
|
if (svc.healthcheck.startPeriod)
|
|
2355
2376
|
lines.push(` startPeriod: ${svc.healthcheck.startPeriod}`);
|
|
2356
2377
|
}
|
|
2378
|
+
if (svc.connectionEnv && Object.keys(svc.connectionEnv).length > 0) {
|
|
2379
|
+
lines.push("connectionEnv:");
|
|
2380
|
+
for (const [k, v] of Object.entries(svc.connectionEnv)) {
|
|
2381
|
+
lines.push(` ${k}: '${v.replace(/'/g, "''")}'`);
|
|
2382
|
+
}
|
|
2383
|
+
}
|
|
2357
2384
|
return lines;
|
|
2358
2385
|
}
|
|
2359
2386
|
function renderCustomService(name, image) {
|
|
@@ -3066,6 +3093,9 @@ function buildComposeYaml(opts, dockerMode = "rootful") {
|
|
|
3066
3093
|
for (const svc of opts.services) {
|
|
3067
3094
|
lines.push(` ${svc.name}:`);
|
|
3068
3095
|
lines.push(` image: ${svc.image}`);
|
|
3096
|
+
if (svc.user !== void 0) {
|
|
3097
|
+
lines.push(` user: ${composeScalar(svc.user)}`);
|
|
3098
|
+
}
|
|
3069
3099
|
if (svc.restart) {
|
|
3070
3100
|
lines.push(` restart: ${svc.restart}`);
|
|
3071
3101
|
}
|
|
@@ -7310,7 +7340,7 @@ var CLI_VERSION;
|
|
|
7310
7340
|
var init_version = __esm({
|
|
7311
7341
|
"src/version.ts"() {
|
|
7312
7342
|
"use strict";
|
|
7313
|
-
CLI_VERSION = true ? "1.26.
|
|
7343
|
+
CLI_VERSION = true ? "1.26.4" : "dev";
|
|
7314
7344
|
}
|
|
7315
7345
|
});
|
|
7316
7346
|
|
|
@@ -9170,7 +9200,7 @@ async function runRemove(opts) {
|
|
|
9170
9200
|
logger.info(
|
|
9171
9201
|
`[remove] host-side rm hit ${code} on ${prettyPath(containerPath)}; using a throw-away alpine container to clean root-owned files\u2026`
|
|
9172
9202
|
);
|
|
9173
|
-
const { exitCode: exit } = await dockerExec([
|
|
9203
|
+
const { exitCode: exit, stderr } = await dockerExec([
|
|
9174
9204
|
"run",
|
|
9175
9205
|
"--rm",
|
|
9176
9206
|
"-v",
|
|
@@ -9182,12 +9212,14 @@ async function runRemove(opts) {
|
|
|
9182
9212
|
"1",
|
|
9183
9213
|
"-delete"
|
|
9184
9214
|
]);
|
|
9185
|
-
|
|
9215
|
+
try {
|
|
9216
|
+
await fs15.rm(containerPath, { recursive: true, force: true });
|
|
9217
|
+
} catch (err2) {
|
|
9218
|
+
const code2 = err2.code;
|
|
9186
9219
|
throw new Error(
|
|
9187
|
-
`docker-based cleanup of ${containerPath}
|
|
9220
|
+
`docker-based cleanup of ${containerPath} did not fully clear it (alpine find exit ${exit}${stderr.trim() ? `: ${stderr.trim()}` : ""}; host rm: ${code2}). Inspect with \`sudo ls -la ${containerPath}\` and clean manually.`
|
|
9188
9221
|
);
|
|
9189
9222
|
}
|
|
9190
|
-
await fs15.rm(containerPath, { recursive: true, force: true });
|
|
9191
9223
|
}
|
|
9192
9224
|
}
|
|
9193
9225
|
logger.success(
|