You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
P0 metadata: enforce visibility filter in List and Get #44
List (repository/video.go:64) и Get (handler/video.go:110) не фильтруют по visibility, gateway проксирует их без JWT (gateway/cmd/server/main.go:129). Публичный список отдаёт ID приватных видео — замыкает CRITICAL-цепочку data-plane обхода.
Фикс:WHERE (visibility='public' OR owner_id=$me) для List (owner из X-User-ID, если есть); Get — 403/404 для private не-владельцу; unlisted — не в List, но доступен по ссылке. Verify: приватное видео отсутствует в ленте и 403 по прямому ID под чужим юзером. Источник: docs/REVIEW-2026-09-13-merged.md §1, M1
Автоматически создано из сводного ревью. Сверяй актуальность номеров строк — они зафиксированы на коммите 91efb5b.
metadataList: SQL filter WHERE visibility='public' OR owner_id=$viewer — anonymous sees only public, owner sees own private/unlisted (repository/video.go)
metadataGet: private video → 403 for non-owner (and anonymous); unlisted stays reachable by direct link; /internal/* endpoints (transcoder, HLSAuth) bypass the check
metadata: new OptionalAuth middleware — viewer identity on public GETs comes only from a metadata-validated JWT (X-User-ID header is not trusted; metadata port is published). Refresh tokens rejected (type check)
gateway: public metadata GET routes wrapped in OptionalAuth — valid Bearer is forwarded, client-supplied X-User-ID stripped, invalid/expired token degrades to anonymous (no 401 on the public feed)
metadata/docs: swagger regenerated (Get now documents 403)
Acceptance criteria
Приватное видео отсутствует в ленте (anonymous/чужой юзер)
403 по прямому ID под чужим юзером (и anonymous)
Unlisted не в List, доступен по ссылке
Internal-эндпоинты работают как раньше (transcoder, HLS)
Verification
make lint-go — 0 issues
make test-go — all pass (new: TestListVisibilityFilter, TestGetVisibility + forged-header/refresh-token cases; gateway TestOptionalAuth* ×4)
make swagger — regenerated for metadata
make e2e — not run locally (docker stack not started in this session)
Review cycle
Iterations: 2 (independent review + re-review)
Fixed during review: forgeable X-User-ID trust boundary (→ metadata-side JWT), OptionalAuth 401 regression for expired tokens, refresh-token-as-identity, missing OptionalAuth tests
Remaining risks: existence oracle (403 vs 404 for private IDs) kept per ticket wording; pre-existing dev fallback: /internal/* open when INTERNAL_TOKEN is empty (out of scope)
Suggested PR title
fix(metadata): enforce visibility filter in list and get
Activity
SlavaKuntsov commentedon Sep 15, 2026
Ready for review
Implemented
metadataList: SQL filterWHERE visibility='public' OR owner_id=$viewer— anonymous sees only public, owner sees own private/unlisted (repository/video.go)metadataGet: private video → 403 for non-owner (and anonymous); unlisted stays reachable by direct link;/internal/*endpoints (transcoder, HLSAuth) bypass the checkmetadata: newOptionalAuthmiddleware — viewer identity on public GETs comes only from a metadata-validated JWT (X-User-ID header is not trusted; metadata port is published). Refresh tokens rejected (type check)gateway: public metadata GET routes wrapped inOptionalAuth— valid Bearer is forwarded, client-suppliedX-User-IDstripped, invalid/expired token degrades to anonymous (no 401 on the public feed)metadata/docs: swagger regenerated (Get now documents 403)Acceptance criteria
Verification
make lint-go— 0 issuesmake test-go— all pass (new: TestListVisibilityFilter, TestGetVisibility + forged-header/refresh-token cases; gateway TestOptionalAuth* ×4)make swagger— regenerated for metadatamake e2e— not run locally (docker stack not started in this session)Review cycle
/internal/*open whenINTERNAL_TOKENis empty (out of scope)Suggested PR title
fix(metadata): enforce visibility filter in list and getSlavaKuntsov commentedon Sep 15, 2026
Pull request opened
#72 — will auto-close via
Closes #44on merge.Project status:
In review(synced after PR creation).Verification
make lint-go— 0 issuesmake test-go— all pass (new regression tests for visibility filter + optional auth)make swagger— metadata docs regeneratedmake e2e— not run in this session (docker stack not started)Remaining risks
/internal/*open whenINTERNAL_TOKENis empty (out of scope)