Skip to content

Commit bb2fd2a

Browse files
fix(setup): identify Sim compose projects by content, not filename
Cursor (High): composeInstalls treated any project whose config basename was docker-compose.prod.yml or docker-compose.local.yml as a Sim install. Those names are common, and sim reset runs 'compose down -v' — so a stranger's stack could have had its volumes destroyed. I introduced that reach. The previous ROOT-scoped '-f' probe was implicitly safe because it could only ever see the project in this checkout; switching to a global 'compose ls' to find stacks started elsewhere means projects must be identified by content instead. Read the config file Docker recorded and require a Sim marker (the published app image, or the app Dockerfile this repo builds), so both the prod and local variants match while an unrelated file with the same name does not. An unreadable or since-deleted file is left unmanaged rather than assumed ours. Verified against a decoy nginx compose file using our exact filename: ignored, while both real Sim compose files still match.
1 parent ccac475 commit bb2fd2a

1 file changed

Lines changed: 30 additions & 3 deletions

File tree

scripts/setup/lifecycle.ts

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { spawnSync } from 'node:child_process'
2+
import { readFileSync } from 'node:fs'
23
import path from 'node:path'
34
import { DB_CONTAINER, type Detection, REDIS_CONTAINER, runDetection } from './detect.ts'
45
import { archiveEnvFile, ROOT } from './env-files.ts'
@@ -90,6 +91,33 @@ interface ComposeProject {
9091
ConfigFiles: string
9192
}
9293

94+
/**
95+
* Markers that a compose file is actually Sim's: the published app image
96+
* (docker-compose.prod.yml) or the app Dockerfile this repo builds
97+
* (docker-compose.local.yml).
98+
*/
99+
const SIM_COMPOSE_MARKERS = ['ghcr.io/simstudioai/simstudio', 'docker/app.Dockerfile'] as const
100+
101+
/**
102+
* `docker-compose.prod.yml` is a common filename, so the name alone cannot say a
103+
* project is ours — and `sim reset` runs `compose down -v`, which would destroy
104+
* an unrelated stack's volumes. Read the file Docker recorded for the project and
105+
* require a Sim marker inside it. The old ROOT-scoped `-f` probe was implicitly
106+
* safe because it could only ever see the local project; discovering projects
107+
* globally means identifying them by content instead.
108+
*/
109+
function isSimComposeFile(file: string): boolean {
110+
if (!(COMPOSE_FILES as readonly string[]).includes(path.basename(file))) return false
111+
try {
112+
const contents = readFileSync(file, 'utf8')
113+
return SIM_COMPOSE_MARKERS.some((marker) => contents.includes(marker))
114+
} catch {
115+
// Unreadable or deleted since the stack started — better to not manage it
116+
// than to guess from the filename.
117+
return false
118+
}
119+
}
120+
93121
/**
94122
* Ask Docker which compose projects exist rather than guessing from the working
95123
* directory. Compose derives a project name from the directory it was started
@@ -98,8 +126,7 @@ interface ComposeProject {
98126
* — and it reports the same stack once per candidate file, since both files map
99127
* to the same directory-derived project. `compose ls` records the real project
100128
* and the exact config file, so one running stack yields exactly one install
101-
* wherever it was started from. Projects whose compose file isn't one of ours
102-
* (a devcontainer, an unrelated app) are filtered out by filename.
129+
* wherever it was started from.
103130
*/
104131
function composeInstalls(): ComposeInstall[] {
105132
const raw = dockerText(['compose', 'ls', '-a', '--format', 'json'])
@@ -116,7 +143,7 @@ function composeInstalls(): ComposeInstall[] {
116143
const file = (project.ConfigFiles ?? '')
117144
.split(',')
118145
.map((entry) => entry.trim())
119-
.find((entry) => (COMPOSE_FILES as readonly string[]).includes(path.basename(entry)))
146+
.find(isSimComposeFile)
120147
if (!file) continue
121148
installs.push({
122149
kind: 'compose',

0 commit comments

Comments
 (0)