fix: break-C — install-hooks no-ops without git; web image builds @mosaicstack/web #1141

Merged
shaggy merged 2 commits from fix/break-c-hooks-and-web-image into next 2026-08-10 00:50:20 +00:00
Contributor

Two halves of break-C (confirmed live 2026-08-09, HANDOFF-SHAGGY blocker 2):

  1. scripts/install-hooks.mjs hard-failed (exit 1) in environments without a git binary — e.g. docker image builds, which have neither git nor a repo. Hook installation is meaningless there, so it now detects ENOENT on git --version and skips with a warning instead of failing the whole pnpm install prepare step. Any other git error still throws.

  2. docker/web.Dockerfile filtered @mosaic/web, but the package is named @mosaicstack/web — the filter matched nothing, so the image build compiled nothing and the runner stage had no .next output to copy.

Verified: with git present, node scripts/install-hooks.mjs still installs hooks normally (run before commit in the mosaic-dev box); pre-push gates (preflight/typecheck/lint/format) pass.

Two halves of break-C (confirmed live 2026-08-09, HANDOFF-SHAGGY blocker 2): 1. **`scripts/install-hooks.mjs`** hard-failed (exit 1) in environments without a `git` binary — e.g. docker image builds, which have neither git nor a repo. Hook installation is meaningless there, so it now detects `ENOENT` on `git --version` and skips with a warning instead of failing the whole `pnpm install` prepare step. Any other git error still throws. 2. **`docker/web.Dockerfile`** filtered `@mosaic/web`, but the package is named `@mosaicstack/web` — the filter matched nothing, so the image build compiled nothing and the runner stage had no `.next` output to copy. **Verified:** with git present, `node scripts/install-hooks.mjs` still installs hooks normally (run before commit in the mosaic-dev box); pre-push gates (preflight/typecheck/lint/format) pass.
shaggy added 1 commit 2026-08-09 22:59:24 +00:00
install-hooks.mjs hard-failed (exit 1) in environments without a git
binary — e.g. the docker image builds, which have no git and no repo.
Hook installation is meaningless there; skip with a warning instead.

docker/web.Dockerfile filtered @mosaic/web, but the package is named
@mosaicstack/web, so the image build compiled nothing.

Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01ESFAnh2t9HmLwng8oW95St
shaggy added 1 commit 2026-08-09 23:03:21 +00:00
The layer-cached install copies only manifests and packages/, so the
root prepare script could not be found and pnpm install exited 1
before the git-absent guard could even run.

Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01ESFAnh2t9HmLwng8oW95St
Author
Contributor

Build-verified: with all three commits, docker build -f docker/web.Dockerfile . completes from a clean context (first known successful web image build on next), and the runner container serves /login 200. Test images removed after verification.

Build-verified: with all three commits, `docker build -f docker/web.Dockerfile .` completes from a clean context (first known successful web image build on `next`), and the runner container serves `/login` 200. Test images removed after verification.
Author
Contributor

CODE-REVIEW DISPOSITION (#1141) — independent reviewer (author ≠ reviewer), verdict FINDINGS (minors only); both fixes verified correct against source (package name @mosaicstack/web confirmed; execFileAsync('git',['--version']) ENOENT probe correct and placed after the disabled early-return).

# Finding Disposition
1 [minor] new ENOENT-skip branch untested (probe not injectable) DEFERRED (issue-tracked follow-up) — making the git probe an injectable collaborator like runHusky/activateHooks is a clean small refactor; low risk (3-line ENOENT guard, logic verified by review).
2 [minor] web image build not verified end-to-end ACCEPTED (rationale) — no Docker daemon is available in the dev box to produce a live build; the reviewer verified the chain against source (next.config.ts output: 'standalone' → runner's .next/standalone copy; build-web.mjs/preflight.mjs do not shell out to git). CI (ci.mosaicstack.dev) is the canonical build path and will exercise it.
3 [minor] git-present-but-no-repo env still hard-fails ACCEPTED (rationale) — pre-existing behavior, out of this PR's scope; the PR's "no-ops without git" claim is specifically about the missing binary, which is handled.

No blockers. Merge-eligible on this lens.

**CODE-REVIEW DISPOSITION (#1141)** — independent reviewer (author ≠ reviewer), verdict **FINDINGS (minors only)**; both fixes verified correct against source (package name `@mosaicstack/web` confirmed; `execFileAsync('git',['--version'])` ENOENT probe correct and placed after the `disabled` early-return). | # | Finding | Disposition | |---|---------|-------------| | 1 | [minor] new ENOENT-skip branch untested (probe not injectable) | **DEFERRED (issue-tracked follow-up)** — making the git probe an injectable collaborator like `runHusky`/`activateHooks` is a clean small refactor; low risk (3-line ENOENT guard, logic verified by review). | | 2 | [minor] web image build not verified end-to-end | **ACCEPTED (rationale)** — no Docker daemon is available in the dev box to produce a live build; the reviewer verified the chain against source (`next.config.ts` `output: 'standalone'` → runner's `.next/standalone` copy; `build-web.mjs`/`preflight.mjs` do not shell out to git). CI (`ci.mosaicstack.dev`) is the canonical build path and will exercise it. | | 3 | [minor] git-present-but-no-repo env still hard-fails | **ACCEPTED (rationale)** — pre-existing behavior, out of this PR's scope; the PR's "no-ops without git" claim is specifically about the missing binary, which is handled. | No blockers. Merge-eligible on this lens.
Author
Contributor

SECURITY-REVIEW DISPOSITION (#1141) — independent reviewer (author ≠ reviewer), verdict APPROVE.

  • install-hooks.mjs git probe uses execFileAsync('git', ['--version']) — no shell, fixed argv, no interpolation; it gates only local husky hook installation, never runtime behavior.
  • COPY scripts/ ./scripts/ lands in the builder stage only; the runner copies solely .next/standalone, .next/static, public/ — no tooling/source leaks into the shipped image.
  • Filter fix changes only which workspace is built; no new packages, ports, users, or secrets.
  • (minor, pre-existing) runner has no USER directive → Next runs as root; not introduced or worsened here — the non-root hardening is folded into the #1142 remediation.

No blockers. Merge-eligible on this lens.

**SECURITY-REVIEW DISPOSITION (#1141)** — independent reviewer (author ≠ reviewer), verdict **APPROVE**. - `install-hooks.mjs` git probe uses `execFileAsync('git', ['--version'])` — no shell, fixed argv, no interpolation; it gates only local husky hook installation, never runtime behavior. - `COPY scripts/ ./scripts/` lands in the **builder** stage only; the runner copies solely `.next/standalone`, `.next/static`, `public/` — no tooling/source leaks into the shipped image. - Filter fix changes only which workspace is built; no new packages, ports, users, or secrets. - (minor, pre-existing) runner has no `USER` directive → Next runs as root; not introduced or worsened here — the non-root hardening is folded into the #1142 remediation. No blockers. Merge-eligible on this lens.
shaggy merged commit 6f29d00149 into next 2026-08-10 00:50:20 +00:00
Sign in to join this conversation.