@norskvideo/ctl-product-template-schema 0.1.61 → 0.1.62

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.
package/index.js CHANGED
@@ -601,11 +601,14 @@ const ProductTemplateFileSchema = z.object({
601
601
  // subpath) turns this into tar bytes at the paths below.
602
602
  //
603
603
  // `workflow`, `components` and `dashboards` are known top-level paths in the
604
- // v1 tar format. The runner detects studio in the compose stack and mounts
605
- // all three into the studio container automatically — products don't need
606
- // to declare the mounts.
604
+ // v1 tar format. The runner detects studio in the compose stack and places
605
+ // all three in the studio container automatically — products don't need
606
+ // to declare the mounts. workflow.yml is COPIED into the working directory on
607
+ // every launch (a single-file bind under /data is refused by OrbStack and
608
+ // Docker Desktop); the template stays authoritative, so a Studio save of it
609
+ // lasts only until the next launch.
607
610
  //
608
- // workflow.yml → /data/studio-save-files/workflow.yml (RO)
611
+ // workflow.yml → /data/studio-save-files/workflow.yml (copied)
609
612
  // components/<name>/ → /usr/src/app/plugins/<name>/ (RO)
610
613
  // dashboards/<name>/ → /data/studio-save-files/<name>/dashboards/ (RO)
611
614
  //
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@norskvideo/ctl-product-template-schema",
3
- "version": "0.1.61",
3
+ "version": "0.1.62",
4
4
  "type": "module",
5
5
  "repository": {
6
6
  "type": "git",
package/workdir-path.js CHANGED
@@ -10,14 +10,19 @@
10
10
  // Two separate hazards, deliberately not conflated:
11
11
  // escape — `../../etc/x` writes outside the workdir. A hole.
12
12
  // shadowing — a file written UNDER one of the runner's read-only bind
13
- // mounts is on disk and invisible to the container. Not a
14
- // security problem, but a miserable one to debug, so it is
15
- // refused at upload time rather than discovered at runtime.
16
- /** Runner-managed read-only mount points inside the working directory
17
- * (override-generator.ts). `workflow.yml` is a file mount; the other two are
18
- * directory mounts, so anything beneath them is shadowed too. */
13
+ // mounts is on disk and invisible to the container, and a file
14
+ // at a path the launch writes itself is never the one used.
15
+ // Not a security problem, but a miserable one to debug, so it
16
+ // is refused at upload time rather than discovered at runtime.
17
+ /** Files the launch writes into the working directory itself. The product
18
+ * template's workflow.yml is copied to the path Studio's `server.document`
19
+ * names on every launch (norsk-ctl's workflow-sync.ts; it used to be a
20
+ * read-only single-file bind, which OrbStack and Docker Desktop refuse), so an
21
+ * operator asset there is replaced or skipped and never opened. */
22
+ const RUNNER_WRITTEN_FILES = ["studio-save-files/workflow.yml"];
23
+ /** Runner-managed read-only directory mount points inside the working
24
+ * directory (override-generator.ts); anything beneath them is shadowed. */
19
25
  const READONLY_MOUNTS = {
20
- file: ["studio-save-files/workflow.yml"],
21
26
  dir: [".norsk"],
22
27
  /** `studio-save-files/<anything>/dashboards` — the per-workflow dashboard mount. */
23
28
  pattern: [/^studio-save-files\/[^/]+\/dashboards(\/|$)/],
@@ -46,9 +51,17 @@ export function checkWorkdirPath(raw) {
46
51
  message: `'${path}' lands under the read-only mount '${mount}', where it would be on disk but invisible to the container`,
47
52
  },
48
53
  });
49
- for (const file of READONLY_MOUNTS.file)
50
- if (path === file)
51
- return shadowed(file);
54
+ for (const file of RUNNER_WRITTEN_FILES) {
55
+ if (path === file) {
56
+ return {
57
+ ok: false,
58
+ problem: {
59
+ kind: "shadowed",
60
+ message: `'${path}' is where each launch copies the product template's workflow.yml, so an asset there would never be the one Studio opens`,
61
+ },
62
+ };
63
+ }
64
+ }
52
65
  for (const dir of READONLY_MOUNTS.dir)
53
66
  if (path === dir || path.startsWith(`${dir}/`))
54
67
  return shadowed(dir);