Skip to content

Commit 2261c1c

Browse files
committed
fix(entrypoint): clone into the dev-owned app folder
The standalone base image's Dockerfile prepares and chowns /home/dev/app to the unprivileged 'dev' user, but entrypoint.sh defaulted TARGET_DIR to /work/app. Since the auto-clone runs as 'su - dev', cloning into the root-created /work/app failed with permission denied, so the repo never landed in the prepared 'app' folder. - Default TARGET_DIR to /home/dev/app to match the Dockerfile's app folder. - chown the resolved TARGET_DIR to dev so overrides outside /home/dev also work. - Add a regression test pinning the entrypoint default to the chowned app dir. Fixes #408
1 parent fb68a4e commit 2261c1c

3 files changed

Lines changed: 66 additions & 2 deletions

File tree

.gitkeep

Lines changed: 0 additions & 1 deletion
This file was deleted.

entrypoint.sh

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ docker_git_repair_dns || true
4949

5050
REPO_URL="${REPO_URL:-}"
5151
REPO_REF="${REPO_REF:-}"
52-
TARGET_DIR="${TARGET_DIR:-/work/app}"
52+
TARGET_DIR="${TARGET_DIR:-/home/dev/app}"
5353

5454
# 1) Authorized keys are mounted from host at /authorized_keys
5555
mkdir -p /home/dev/.ssh
@@ -70,6 +70,11 @@ chown -R dev:dev /home/dev/.codex
7070
if [[ -n "$REPO_URL" && ! -d "$TARGET_DIR/.git" ]]; then
7171
mkdir -p "$TARGET_DIR"
7272
chown -R dev:dev /home/dev
73+
# git clone runs as `su - dev`, so the target must be writable by dev even when
74+
# TARGET_DIR is overridden to a path outside /home/dev (otherwise clone fails silently).
75+
if [[ "$TARGET_DIR" != "/" ]]; then
76+
chown -R dev:dev "$TARGET_DIR"
77+
fi
7378

7479
if [[ -n "$REPO_REF" ]]; then
7580
su - dev -c "git clone --branch '$REPO_REF' '$REPO_URL' '$TARGET_DIR'"
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
// CHANGE: pin the standalone base-image clone target to the dev-owned app folder
2+
// WHY: entrypoint runs `git clone` as `su - dev`; cloning into a root-owned dir (e.g. /work/app)
3+
// fails with permission denied, so the repo never lands in the prepared `app` folder
4+
// QUOTE(ТЗ): "Почему-то при docker-git clone не делается git clone в папку app"
5+
// REF: issue-408
6+
// SOURCE: n/a
7+
// FORMAT THEOREM: defaultTargetDir(entrypoint) = appDir(Dockerfile) ∧ appDir ⊂ chown(dev, /home/dev)
8+
// PURITY: SHELL (reads repository source files)
9+
// INVARIANT: clone target is owned by the unprivileged clone user
10+
// COMPLEXITY: O(|file|)
11+
import { describe, expect, it } from "@effect/vitest"
12+
import { readFileSync } from "node:fs"
13+
import path from "node:path"
14+
import { fileURLToPath } from "node:url"
15+
16+
const __filename = fileURLToPath(import.meta.url)
17+
const __dirname = path.dirname(__filename)
18+
// packages/lib/tests/shell -> repository root
19+
const repoRoot = path.resolve(__dirname, "..", "..", "..", "..")
20+
21+
const readRepoFile = (relativePath: string): string =>
22+
readFileSync(path.join(repoRoot, relativePath), "utf8")
23+
24+
describe("standalone base-image clone target", () => {
25+
const entrypoint = readRepoFile("entrypoint.sh")
26+
const dockerfile = readRepoFile("Dockerfile")
27+
28+
// CHANGE: derive the dev home that the Dockerfile recursively chowns to the clone user
29+
// WHY: `git clone` runs as `su - dev`, so the target must live under a dev-owned path
30+
// PURITY: CORE
31+
// INVARIANT: chownedHome captures the `chown -R dev:dev <home>` argument
32+
const chownedHome = (() => {
33+
const match = dockerfile.match(/chown -R dev:dev (\/home\/dev)\b/)
34+
return match?.[1]
35+
})()
36+
37+
// CHANGE: derive the default TARGET_DIR the entrypoint clones into
38+
// WHY: the bug is a wrong default that points outside the dev-owned home
39+
// PURITY: CORE
40+
// INVARIANT: defaultTargetDir captures `TARGET_DIR="${TARGET_DIR:-<default>}"`
41+
const defaultTargetDir = (() => {
42+
const match = entrypoint.match(/TARGET_DIR="\$\{TARGET_DIR:-([^}]+)\}"/)
43+
return match?.[1]
44+
})()
45+
46+
it("prepares an app folder under the dev home in the Dockerfile", () => {
47+
expect(dockerfile).toContain("mkdir -p /home/dev/app")
48+
expect(chownedHome).toBe("/home/dev")
49+
})
50+
51+
it("defaults the clone target to the prepared app folder", () => {
52+
expect(defaultTargetDir).toBe("/home/dev/app")
53+
})
54+
55+
it("keeps the clone target under the dev-owned home so `su - dev` can write into it", () => {
56+
expect(defaultTargetDir).toBeDefined()
57+
expect(chownedHome).toBeDefined()
58+
expect(`${defaultTargetDir}/`.startsWith(`${chownedHome}/`)).toBe(true)
59+
})
60+
})

0 commit comments

Comments
 (0)