Skip to content

Commit 5c2656b

Browse files
committed
fix(core): stabilize box project container startup
1 parent 578de65 commit 5c2656b

6 files changed

Lines changed: 67 additions & 4 deletions

File tree

‎packages/app/src/lib/core/templates/dockerfile.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,7 @@ const renderDockerfileBun = (config: TemplateConfig): string =>
264264
*/
265265
const renderDockerfileUsers = (config: TemplateConfig): string =>
266266
`# Create non-root user for SSH (align UID/GID with host user 1000)
267-
RUN for BASE_USER in box ubuntu; do \
267+
RUN for BASE_USER in ubuntu box; do \
268268
if [ "$BASE_USER" != "${config.sshUser}" ] && id -u "$BASE_USER" >/dev/null 2>&1; then \
269269
if getent group 1000 >/dev/null 2>&1; then \
270270
EXISTING_GROUP="$(getent group 1000 | cut -d: -f1)"; \

‎packages/app/src/lib/usecases/errors.ts‎

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,23 @@ const renderDockerAccessActionPlan = (issue: DockerAccessError["issue"]): string
8080
return issue === "PermissionDenied" ? permissionDeniedPlan.join("\n") : daemonUnavailablePlan.join("\n")
8181
}
8282

83+
// CHANGE: classify Docker build apt signature noise that is commonly caused by storage exhaustion.
84+
// WHY: when Docker's backing filesystem is full, apt can report every repository as "not signed"; surfacing disk-pressure recovery avoids chasing false GPG/key fixes.
85+
// QUOTE(ТЗ): "Все пробелмы с котоырми ты сталкиваешься должны быть потом покрыты тестами"
86+
// REF: runtime-2026-05-14-docker-disk-full
87+
// SOURCE: n/a
88+
// FORMAT THEOREM: contains_apt_invalid_signature(details) -> render_error(details) includes disk_space_recovery_hint
89+
// PURITY: CORE
90+
// INVARIANT: the classifier only adds guidance and does not alter command execution semantics
91+
// COMPLEXITY: O(n) time / O(1) space where n = |details|.
92+
const isAptInvalidSignatureFailure = (details: string | undefined): boolean => {
93+
const normalized = details?.toLowerCase() ?? ""
94+
return normalized.includes("apt-get update failed") &&
95+
normalized.includes("invalid signature") &&
96+
normalized.includes("repository") &&
97+
normalized.includes("not signed")
98+
}
99+
83100
const renderDockerCommandError = ({ details, exitCode }: DockerCommandError): string =>
84101
[
85102
`docker compose failed with exit code ${exitCode}`,
@@ -92,6 +109,11 @@ const renderDockerCommandError = ({ details, exitCode }: DockerCommandError): st
92109
"Hint: NVIDIA GPU access is enabled but Docker cannot load the host NVIDIA runtime; run with GPU disabled (`--gpu none`) or install the NVIDIA driver and NVIDIA Container Toolkit."
93110
]
94111
: []),
112+
...(isAptInvalidSignatureFailure(details)
113+
? [
114+
"Hint: apt reported invalid signatures for multiple repositories during Docker build; this can be caused by low Docker host disk space. Check `df -h` and reclaim unused Docker cache with `docker builder prune -af` and `docker image prune -af` before retrying."
115+
]
116+
: []),
95117
"Hint: if output above contains 'lookup auth.docker.io' or 'read udp ... [::1]:53 ... connection refused', fix Docker DNS resolver (set working DNS in host/daemon config) and retry."
96118
].join("\n")
97119

‎packages/lib/src/core/templates/dockerfile.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,7 @@ const renderDockerfileBun = (config: TemplateConfig): string =>
264264
*/
265265
const renderDockerfileUsers = (config: TemplateConfig): string =>
266266
`# Create non-root user for SSH (align UID/GID with host user 1000)
267-
RUN for BASE_USER in box ubuntu; do \
267+
RUN for BASE_USER in ubuntu box; do \
268268
if [ "$BASE_USER" != "${config.sshUser}" ] && id -u "$BASE_USER" >/dev/null 2>&1; then \
269269
if getent group 1000 >/dev/null 2>&1; then \
270270
EXISTING_GROUP="$(getent group 1000 | cut -d: -f1)"; \

‎packages/lib/src/usecases/errors.ts‎

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,23 @@ const renderDockerAccessActionPlan = (issue: DockerAccessError["issue"]): string
7979
return issue === "PermissionDenied" ? permissionDeniedPlan.join("\n") : daemonUnavailablePlan.join("\n")
8080
}
8181

82+
// CHANGE: classify Docker build apt signature noise that is commonly caused by storage exhaustion.
83+
// WHY: when Docker's backing filesystem is full, apt can report every repository as "not signed"; surfacing disk-pressure recovery avoids chasing false GPG/key fixes.
84+
// QUOTE(ТЗ): "Все пробелмы с котоырми ты сталкиваешься должны быть потом покрыты тестами"
85+
// REF: runtime-2026-05-14-docker-disk-full
86+
// SOURCE: n/a
87+
// FORMAT THEOREM: contains_apt_invalid_signature(details) -> render_error(details) includes disk_space_recovery_hint
88+
// PURITY: CORE
89+
// INVARIANT: the classifier only adds guidance and does not alter command execution semantics
90+
// COMPLEXITY: O(n) time / O(1) space where n = |details|.
91+
const isAptInvalidSignatureFailure = (details: string | undefined): boolean => {
92+
const normalized = details?.toLowerCase() ?? ""
93+
return normalized.includes("apt-get update failed") &&
94+
normalized.includes("invalid signature") &&
95+
normalized.includes("repository") &&
96+
normalized.includes("not signed")
97+
}
98+
8299
const renderDockerCommandError = ({ details, exitCode }: DockerCommandError): string =>
83100
[
84101
`docker compose failed with exit code ${exitCode}`,
@@ -91,6 +108,11 @@ const renderDockerCommandError = ({ details, exitCode }: DockerCommandError): st
91108
"Hint: NVIDIA GPU access is enabled but Docker cannot load the host NVIDIA runtime; run with GPU disabled (`--gpu none`) or install the NVIDIA driver and NVIDIA Container Toolkit."
92109
]
93110
: []),
111+
...(isAptInvalidSignatureFailure(details)
112+
? [
113+
"Hint: apt reported invalid signatures for multiple repositories during Docker build; this can be caused by low Docker host disk space. Check `df -h` and reclaim unused Docker cache with `docker builder prune -af` and `docker image prune -af` before retrying."
114+
]
115+
: []),
94116
"Hint: if output above contains 'lookup auth.docker.io' or 'read udp ... [::1]:53 ... connection refused', fix Docker DNS resolver (set working DNS in host/daemon config) and retry."
95117
].join("\n")
96118

‎packages/lib/tests/core/templates.test.ts‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,10 +94,10 @@ describe("renderDockerfile", () => {
9494
expect(dockerfile).not.toContain("FROM ubuntu:24.04")
9595
})
9696

97-
it("renames the box base user to the configured SSH user", () => {
97+
it("renames the UID 1000 base user to the configured SSH user before the box fallback", () => {
9898
const dockerfile = renderDockerfile(makeTemplateConfig())
9999

100-
expect(dockerfile).toContain("for BASE_USER in box ubuntu; do")
100+
expect(dockerfile).toContain("for BASE_USER in ubuntu box; do")
101101
expect(dockerfile).toContain('if [ "$BASE_USER" != "dev" ] && id -u "$BASE_USER" >/dev/null 2>&1; then')
102102
expect(dockerfile).toContain('usermod -l dev -d /home/dev -m -s /usr/bin/zsh "$BASE_USER" || true')
103103
})

‎packages/lib/tests/usecases/errors.test.ts‎

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,25 @@ describe("renderError", () => {
4242
expect(message).toContain("NVIDIA Container Toolkit")
4343
})
4444

45+
it("includes disk pressure recovery hint for apt invalid signature build failures", () => {
46+
const message = renderError(
47+
new DockerCommandError({
48+
exitCode: 1,
49+
details: [
50+
"apt-get update failed after retries",
51+
"W: GPG error: http://archive.ubuntu.com/ubuntu noble InRelease: At least one invalid signature was encountered.",
52+
"E: The repository 'http://archive.ubuntu.com/ubuntu noble InRelease' is not signed.",
53+
"E: The repository 'http://security.ubuntu.com/ubuntu noble-security InRelease' is not signed."
54+
].join("\n")
55+
})
56+
)
57+
58+
expect(message).toContain("low Docker host disk space")
59+
expect(message).toContain("df -h")
60+
expect(message).toContain("docker builder prune -af")
61+
expect(message).toContain("docker image prune -af")
62+
})
63+
4564
it("shows NVIDIA hint iff docker output contains NVIDIA runtime markers", () => {
4665
const nvidiaContainerCliMarker = "nvidia-container-cli"
4766
const libNvidiaMlMarker = "libnvidia-ml.so.1"

0 commit comments

Comments
 (0)