project-nomad/admin/app/validators
chriscrosstalk 8f06e850a3
feat: support gated downloads for self-hosted curated content (#1172)
Adds an optional `auth: 'nomad_app_key'` discriminator to curated manifest
resources so a curated collection tier can carry content we host ourselves,
gated to official release builds. Without this, only Creator Packs could use
the entitlement Worker; curated tier installs always downloaded
unauthenticated.

No behaviour change for any existing manifest entry: absent `auth` means
unauthenticated, exactly as today.

- `auth` declared on both the type and the VineJS validator. It has to be on
  the validator or VineJS strips it silently on fetch, and the gated download
  would then go out with no header and 401 for everyone. A dedicated spec
  guards that regression.
- Gated resources are pinned to their manifest URL (resolveZimDownload skips
  the catalog comparison) and excluded from catalog update checks, so a
  resource-id collision cannot let a third-party mirror overwrite our content.
  Consequence, commented rather than implied: gated content does not
  auto-update; new versions ship via the manifest.
- 401/403 on a download now reports that an official build is required instead
  of a raw axios status, which is what a fork build will hit.
- The pure `isGatedResource` predicate is deliberately split from the
  env-reading header builder: importing `#start/env` into
  zim_download_resolution triggers env validation at import time and breaks its
  unit tests.

Reuses CREATOR_PACKS_APP_KEY rather than minting a second secret — the question
it answers ("is this an official build?") is identical for both content types.

Verified end to end on a test server: `auth` survives validation into the
cached spec, the Bearer header attaches to only the gated resource, the file
lands byte-exact with an installed_resources row and a Kiwix library entry, and
an entry with a gated URL but no `auth` field fails with the intended message.

No catalog entry is included here. Manifests are fetched live from `main`, so a
gated entry must not merge until this ships and is adopted — pre-`auth` builds
strip the field and 401.

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-02 12:23:00 -07:00
..
responses feat: auto-generating OpenAPI docs with Scalar UI (#1128) 2026-07-21 12:36:40 -07:00
benchmark.ts feat: Add system benchmark feature with NOMAD Score 2026-01-22 21:48:12 -08:00
chat.ts feat: [wip] native AI chat interface 2026-01-31 20:39:49 -08:00
common.ts fix(security): harden assertNotPrivateUrl with ipaddr.js + host normalization 2026-06-23 04:46:55 +00:00
conditions.ts Add offline FDA drug reference (labels, interaction view, conditions, remedies) (#1040) 2026-07-21 11:06:18 -07:00
curated_collections.ts feat: support gated downloads for self-hosted curated content (#1172) 2026-08-02 12:23:00 -07:00
download.ts feat(Open WebUI): manage models via Command Center 2026-01-19 22:15:52 -08:00
drug_reference.ts Add offline FDA drug reference (labels, interaction view, conditions, remedies) (#1040) 2026-07-21 11:06:18 -07:00
nomad_md.ts feat(AI): nomad.md for custom instructions (#1127) 2026-07-21 11:15:58 -07:00
ollama.ts feat(AI): per-model thinking toggle with global default (off) (#1079) 2026-07-20 16:33:09 -07:00
rag.ts feat(KnowledgeBase): add document viewer, download, metadata, and sorting (#721) 2026-06-23 04:47:09 +00:00
settings.ts feat: configurable internet test url override in new Advanced Settings page 2026-06-23 04:47:10 +00:00
system.ts feat(supply-depot): add uninstall for curated apps (#1006) 2026-06-23 04:47:05 +00:00
zim.ts feat(Content): custom ZIM library sources with pre-seeded mirrors (#593) 2026-05-20 10:16:00 -07:00