fix(deploy): weiger een checkout met vreemde eigendomsrechten #84

Merged
janpeter merged 1 commit from fix/deploy-repo-ownership-gate into main 2026-09-21 13:46:59 +02:00
Owner

Eén bevoorrecht git-commando in de deploy-checkout (sudo git fetch) laat root-eigendom refs achter. De volgende onbevoorrechte fetch sneuvelt dan op een ref-lock die hij niet mag aanmaken:

error: cannot lock ref 'refs/remotes/origin/spec/lean-a3b-auth':
Unable to create '…/spec/lean-a3b-auth.lock': Permission denied

Dat gebeurde op max2 op 2026-09-20: 29 objecten onder .git kregen root als eigenaar (.git/index, refs/heads/main, negen remote refs, twee packs, de submodule-configs). De storing werd pas een dag later zichtbaar, in een andere stap en ver van de oorzaak. Deze preflight weigert het meteen, met een eigen marker repo_ownership_drift op stderr naast het generieke media_organizer_deploy_failed.

Waarom de exitstatus apart wordt getoetst

Niet cosmetisch. De eerste versie van deze gate was [[ -z "$(find "$repo" ! -uid "$(id -u)" -print -quit)" ]], en die gaf tijdens het testen PASS op een onleesbare map: een find die niet kan afdalen print niets, dus een test op alleen de uitvoer zet de poort open op precies de rechten die hij moet vangen. Nu:

foreign=$(find "$repo" ! -uid "$(id -u)" -print -quit) || fail
[[ -z "$foreign" ]] || { printf '%s\n' 'repo_ownership_drift' >&2; fail; }

Kosten en dekking

  • ~30 ms over 1991 paden in de echte checkout; find toegevoegd aan de tool-check.
  • Handmatig geverifieerd op max2: schone checkout → PASS; repo van ops-agent met één root-eigendom ref → TRIP; map die de gebruiker niet in mag → TRIP; alles eigen bezit maar één submap op modus 000 (find faalt zónder uitvoer) → faalt dicht.
  • Nieuwe test dekt beide takken; welke uitvoerbaar is hangt van de uid af (alleen root kan chown-en, alleen niet-root wordt door modus 000 gestopt), en hij bevestigt dat Docker nooit bereikt wordt.

Testsuite lokaal

src/test/media-deploy.test.ts faalt op max2 in 5 van de 8 gevallen — óók op onaangeraakte main. Oorzaak is omgeving, niet code: het script eist timeout --version met GNU coreutils, en max2 heeft timeout (uutils coreutils) 0.8.0. Baseline en deze branch geven exact dezelfde 3 groen / 5 rood, plus de nieuwe test groen. CI is de echte poort.

🤖 Generated with Claude Code

Eén bevoorrecht git-commando in de deploy-checkout (`sudo git fetch`) laat root-eigendom refs achter. De volgende onbevoorrechte fetch sneuvelt dan op een ref-lock die hij niet mag aanmaken: ``` error: cannot lock ref 'refs/remotes/origin/spec/lean-a3b-auth': Unable to create '…/spec/lean-a3b-auth.lock': Permission denied ``` Dat gebeurde op max2 op 2026-09-20: 29 objecten onder `.git` kregen root als eigenaar (`.git/index`, `refs/heads/main`, negen remote refs, twee packs, de submodule-configs). De storing werd pas een dag later zichtbaar, in een andere stap en ver van de oorzaak. Deze preflight weigert het meteen, met een eigen marker `repo_ownership_drift` op stderr naast het generieke `media_organizer_deploy_failed`. ### Waarom de exitstatus apart wordt getoetst Niet cosmetisch. De eerste versie van deze gate was `[[ -z "$(find "$repo" ! -uid "$(id -u)" -print -quit)" ]]`, en die gaf tijdens het testen **PASS op een onleesbare map**: een `find` die niet kan afdalen print niets, dus een test op alleen de uitvoer zet de poort open op precies de rechten die hij moet vangen. Nu: ```bash foreign=$(find "$repo" ! -uid "$(id -u)" -print -quit) || fail [[ -z "$foreign" ]] || { printf '%s\n' 'repo_ownership_drift' >&2; fail; } ``` ### Kosten en dekking - ~30 ms over 1991 paden in de echte checkout; `find` toegevoegd aan de tool-check. - Handmatig geverifieerd op max2: schone checkout → PASS; repo van `ops-agent` met één root-eigendom ref → TRIP; map die de gebruiker niet in mag → TRIP; alles eigen bezit maar één submap op modus 000 (find faalt zónder uitvoer) → faalt dicht. - Nieuwe test dekt beide takken; welke uitvoerbaar is hangt van de uid af (alleen root kan chown-en, alleen niet-root wordt door modus 000 gestopt), en hij bevestigt dat Docker nooit bereikt wordt. ### Testsuite lokaal `src/test/media-deploy.test.ts` faalt op max2 in **5 van de 8** gevallen — óók op onaangeraakte `main`. Oorzaak is omgeving, niet code: het script eist `timeout --version` met `GNU coreutils`, en max2 heeft `timeout (uutils coreutils) 0.8.0`. Baseline en deze branch geven exact dezelfde 3 groen / 5 rood, plus de nieuwe test groen. CI is de echte poort. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
fix(deploy): weiger een checkout met vreemde eigendomsrechten
Some checks failed
CI / test (historical-bootstrap) (pull_request) Successful in 1m2s
CI / test (video-migration) (pull_request) Successful in 48s
CI / test (suite) (pull_request) Failing after 2m35s
CI / docker-build (pull_request) Successful in 1m37s
5a8aedcd71
Eén bevoorrecht git-commando in de deploy-checkout (`sudo git fetch`) laat
root-eigendom refs achter. De volgende onbevoorrechte fetch sneuvelt dan op
een ref-lock die hij niet mag aanmaken:

  error: cannot lock ref 'refs/remotes/origin/spec/lean-a3b-auth':
  Unable to create '…/spec/lean-a3b-auth.lock': Permission denied

Dat gebeurde op max2 op 2026-09-20: 29 objecten onder .git kregen root als
eigenaar, en de storing werd pas een dag later zichtbaar — in een andere
stap, ver van de oorzaak. De preflight weigert dit nu meteen, met een eigen
marker `repo_ownership_drift` op stderr naast het generieke faalwoord.

De exitstatus van `find` wordt apart getoetst. Dat is niet cosmetisch: een
find die niet kan afdalen print niets, dus `[[ -z "$(find …)" ]]` alleen zou
de poort openzetten op precies de rechten die hij moet vangen. Gemeten tijdens
het bouwen van deze wijziging: de eerste versie gaf PASS op een onleesbare map.

`find` is aan de tool-check toegevoegd. Kosten: ~30 ms over 1991 paden.

De nieuwe test dekt beide takken; welke uitvoerbaar is hangt af van de uid
(alleen root kan chown-en, alleen niet-root wordt door modus 000 gestopt).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
s4m-codex-reviewer left a comment

APPROVED

Geen gekoppeld plan gevonden — beoordeeld op codekwaliteit + product-standaarden.

Findings

Geen blokkerende of niet-blokkerende findings.

Review-notities

De wijziging in scripts/deploy-media-organizer.sh:20 faalt bewust vroeg wanneer de checkout paden bevat die niet van de uitvoerende gebruiker zijn, en faalt ook dicht wanneer find niet kan traversen. De toegevoegde test rond src/test/media-deploy.test.ts:95 dekt zowel foreign ownership onder root als untraversable paths onder een niet-root runtime en controleert dat Docker niet bereikt wordt.

# APPROVED Geen gekoppeld plan gevonden — beoordeeld op codekwaliteit + product-standaarden. ## Findings Geen blokkerende of niet-blokkerende findings. ## Review-notities De wijziging in `scripts/deploy-media-organizer.sh:20` faalt bewust vroeg wanneer de checkout paden bevat die niet van de uitvoerende gebruiker zijn, en faalt ook dicht wanneer `find` niet kan traversen. De toegevoegde test rond `src/test/media-deploy.test.ts:95` dekt zowel foreign ownership onder root als untraversable paths onder een niet-root runtime en controleert dat Docker niet bereikt wordt.
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
janpeter/Media-Organizer!84
No description provided.