Two halves of break-C (confirmed live 2026-08-09, HANDOFF-SHAGGY blocker 2):
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.
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.
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
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
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.
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.tsoutput: '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.
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 next2026-08-10 00:50:20 +00:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Two halves of break-C (confirmed live 2026-08-09, HANDOFF-SHAGGY blocker 2):
scripts/install-hooks.mjshard-failed (exit 1) in environments without agitbinary — e.g. docker image builds, which have neither git nor a repo. Hook installation is meaningless there, so it now detectsENOENTongit --versionand skips with a warning instead of failing the wholepnpm installprepare step. Any other git error still throws.docker/web.Dockerfilefiltered@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.nextoutput to copy.Verified: with git present,
node scripts/install-hooks.mjsstill installs hooks normally (run before commit in the mosaic-dev box); pre-push gates (preflight/typecheck/lint/format) pass.Build-verified: with all three commits,
docker build -f docker/web.Dockerfile .completes from a clean context (first known successful web image build onnext), and the runner container serves/login200. Test images removed after verification.CODE-REVIEW DISPOSITION (#1141) — independent reviewer (author ≠ reviewer), verdict FINDINGS (minors only); both fixes verified correct against source (package name
@mosaicstack/webconfirmed;execFileAsync('git',['--version'])ENOENT probe correct and placed after thedisabledearly-return).runHusky/activateHooksis a clean small refactor; low risk (3-line ENOENT guard, logic verified by review).next.config.tsoutput: 'standalone'→ runner's.next/standalonecopy;build-web.mjs/preflight.mjsdo not shell out to git). CI (ci.mosaicstack.dev) is the canonical build path and will exercise it.No blockers. Merge-eligible on this lens.
SECURITY-REVIEW DISPOSITION (#1141) — independent reviewer (author ≠ reviewer), verdict APPROVE.
install-hooks.mjsgit probe usesexecFileAsync('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.USERdirective → 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.