ZDDC/zddc/internal/apps
ZDDC f7233237cd feat(server): collapse dot-guard into one admin-gated .zddc.d reserve
Replace the blanket "block every dot/underscore segment" dispatch guard
with a single reserved namespace, .zddc.d/, which is admin-only at every
depth. Everything else dot-prefixed is now ordinary ACL-governed content;
a leading dot only hides an entry from listings (UI), not from the ACL.

.zddc.d/ holds the bearer-token store, so it must stay closed even under a
broad operator grant (e.g. `*: rwcd`). The path-tree cascade has no
match-this-name-at-any-depth rule, so .zddc.d/ is gated by segment name via
a hard rule that overrides operator ACLs — on reads in dispatch (404,
existence-hidden) and on writes in authorizeAction (403 defense-in-depth
for direct callers). Token validation is unaffected: it reads
.zddc.d/tokens directly from the filesystem in ACLMiddleware, before the
HTTP-layer gate.

The segment match is case-insensitive (strings.EqualFold): ZDDC_ROOT may
sit on a case-insensitive filesystem (SMB/CIFS/Azure Files) where .ZDDC.D
resolves to the same dir, so a write to a case-varied path — e.g. a MOVE
destination header that skips dispatch's canonical case-folding — must not
slip past the gate and plant a forged token. The dispatch gate also runs
BEFORE the raw .zddc view so the reserve's own cascade
(/<dir>/.zddc.d/.zddc) is existence-hidden rather than leaked by
ServeZddcFile. Regression tests cover both.

To keep all bookkeeping inside the one reserve, relocate the last two
caches under it (both regenerable, no data migration): the apps cache
_app/ -> .zddc.d/apps/ and the per-directory MD-conversion cache
<dir>/.converted/ -> <dir>/.zddc.d/converted/.

New internal/handler/sidecar.go defines ReservedSidecar + the
HasReservedSidecar / ActiveAdminForSidecar predicates used by both the
dispatch read-gate and the write-path gate.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-03 13:23:00 -05:00
..
embedded chore(embedded): cut v0.0.27-beta 2026-06-03 12:46:12 -05:00
apps.go feat(server): collapse dot-guard into one admin-gated .zddc.d reserve 2026-06-03 13:23:00 -05:00
apps_test.go build: simplify to stable + exact-version (drop alpha/beta as public concepts) 2026-05-20 09:17:46 -05:00
availability.go refactor: nest lifecycle slots per-party + add virtual top-level aggregators 2026-05-21 07:57:45 -05:00
availability_test.go test(apps,fs): update availability + listing tests for flat-peer layout 2026-06-03 11:51:29 -05:00
cache.go fix(apps): cache key now includes scheme + full host:port (no collisions) 2026-05-04 17:57:28 -05:00
cache_test.go fix(apps): cache key now includes scheme + full host:port (no collisions) 2026-05-04 17:57:28 -05:00
embed.go chore: retire mdedit tool — markdown editor lives in browse now 2026-05-13 10:34:31 -05:00
fetch.go feat(apps): code-signed URL fetches; dev chart overlays prod data RO 2026-05-04 21:59:07 -05:00
handler.go refactor: unified listing protocol + form-editor retirement + admin elevation 2026-05-14 12:15:07 -05:00
handler_test.go build: simplify to stable + exact-version (drop alpha/beta as public concepts) 2026-05-20 09:17:46 -05:00
singleflight.go feat(zddc-server): apps fetch+cache subsystem with cascade overrides 2026-05-01 15:25:25 -05:00
singleflight_test.go feat(zddc-server): apps fetch+cache subsystem with cascade overrides 2026-05-01 15:25:25 -05:00
verify.go feat(apps): code-signed URL fetches; dev chart overlays prod data RO 2026-05-04 21:59:07 -05:00
verify_test.go feat(apps): code-signed URL fetches; dev chart overlays prod data RO 2026-05-04 21:59:07 -05:00
versions.go build: simplify to stable + exact-version (drop alpha/beta as public concepts) 2026-05-20 09:17:46 -05:00