CE: install the git-native access guard so push_enabled=false
Found by Task 10843's live proof of this epic on a ce-staging install (v1.2.5065, container node, single Operator-org user). Supersedes the parentless draft #10973 (same defect; delete that draft once this lands).
## Reproduction (observed)
CE project on jaah-ai/jaah-ce-staging with push_enabled=false (confirmed via GET /api/projects/1). A coder runner ran `git push --force-with-lease origin fleet/task-7` and the push LANDED on GitHub (branch appeared, since deleted). Only `jaah-forge pr create` refused ("this project has push_enabled=false"). The clone `.git` under the CE data dir had no `access-guard.*` config markers, no hooks dir and no disabled origin pushurl, i.e. neither layer of docs/policies/repo-access-levels.md § The git-native guard was present. The CE `command_audit_log` has no `sync_access_guard` row, although `activity_events` recorded `project_updated` with `push_enabled`.
## Cause (probable — verify first)
`apps/api/app/routes/projects.py`, the guard-sync block after commit: `default_dispatch_node` for the CE Operator principal falls through to `cp_node_id(...)` / `resolve_node_id() or "local"`; no `Node` row matches, so `resolve_clone(None, ...)` is empty and the sync is skipped silently. Separately, a fresh anchor clone only gets markers from sync-on-change, so a project created with push off may never be guarded.
## Fix
On the CE, resolve the node for the CE operator principal to the CE's one node so the existing `sync_access_guard` runs; apply the guard at first clone from the project row (push_enabled, branch_prefix); when a sync cannot resolve a clone, log a warning (never skip silently). Reuse the existing guard mechanism in `apps/jaahd/guards/` — no new surface.
## Acceptance
- AC1: on a CE install, project with push_enabled=false: `git push origin HEAD:refs/heads/fleet/task-N` from its slot is refused by the pre-push hook. Oracle: the refused push output, and `git config --get-regexp access-guard` in the clone shows markers.
- AC2: flipping push_enabled on an existing CE project writes a `sync_access_guard` row to command_audit_log and updates the markers. Oracle: the row and the before/after config.
- AC3: a skipped sync logs a warning naming the project. Oracle: a unit test.
- AC4: regression test for node resolution of the CE operator principal; cloud behaviour unchanged (`./dc check full` green).
Out of scope: cloud dispatch changes beyond what the fix needs; CE caps (`CE_MAX_*`); doctrine prose; LICENSE; the CE console UX items in draft #10974; the CE merge lane / compliance auditor (#10852). Do not flip jaah-ai/jaah-ce public or promote to master.
Done means:
- AC1–AC4 oracles cited in the report (CE install evidence for AC1/AC2; test output for AC3/AC4).
- PR merged to develop via the merge lane; Jaah Deploy for the merge succeeds (or is superseded).
Outcome
CE push guard fixed: CE guard sync now targets its one node, clones get the push guard at clone time (fails closed, reads only the clone's own config), a skipped sync warns. PR #7235 merged as 3f7241bff; Jaah Deploy green. Quick gate and changed-area tests green. Live CE recheck waits on a CE release. Draft #10973 left for an operator to delete. Memory: none applied.
Artifacts
Activity
- Ready
- Runner started
- Runner ended (done)