Repository navigation
Harden proxy trust, guide output, and channel identity - #183
Merged
Merged
Conversation
Comment on lines
+44
to
+47
| const response = await axios.get(parsedUrl.href, { | ||
| responseType: 'stream', | ||
| signal: upstreamRequest.signal, | ||
| }); |
Contributor
There was a problem hiding this comment.
🟡 Changes recommended
The new stable-ID streaming paths still clone/scan the full channels cache per request in hot endpoints, which is an avoidable performance regression that should be fixed before approval.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
This PR hardens proxy/origin handling, stabilizes channel identity across provider/mapping edits, and makes lineup/XMLTV generation more deterministic and cache-bounded to avoid operational edge cases (empty profiles, filter variance blowups, nondeterministic guide dedupe).
Changes:
- Make reverse-proxy trust explicit (configurable trusted proxies) and route base-URL generation through Express’s trust proxy policy.
- Introduce stable source-channel playback URLs (
/stream/channel/:id) and preserve canonical/source relationships across provider and mapping updates. - Improve determinism and safety: bounded LRU caching for large XMLTV variants, deterministic XMLTV deduplication, and transactional/validated backup restore.
File summaries
| File | Description |
|---|---|
| test/unit/source-service.test.js | Updates provider persistence tests to include stable provider IDs and relationship preservation assertions. |
| test/unit/cache-manager.test.js | Adds LRU eviction test for bounded caches. |
| test/integration/output-profiles.test.js | Validates XMLTV fanout + deterministic dedupe behavior across canonical outputs. |
| test/integration/output-profile-routes.test.js | Adds MCP-assisted profile update coverage; verifies profile-isolated XMLTV + empty-profile behavior. |
| test/integration/mcp.test.js | Updates MCP provider listing expectations to include id and enabled. |
| test/integration/lineup.test.js | Prevents developer HTTP proxy inheritance from affecting nock-based tests. |
| test/integration/legacy-config-compat.test.js | Adjusts legacy provider API expectations for provider IDs; tests relationship preservation on saves. |
| test/integration/improvements.test.js | Extends backup/restore integration coverage to include DB snapshot restoration of bindings/output settings. |
| test/integration/epg.test.js | Adds coverage for deterministic XMLTV deduplication while preserving language-tagged titles. |
| test/integration/canonical-routes.test.js | Validates canonical settings survive mapping rename/renumber changes. |
| server/transcode.js | Supports stable channel-ID addressing for transcode route. |
| server/stream-probe.js | Supports stable channel-ID addressing for stream probe route. |
| server/oauth.js | Switches base URL computation to shared getBaseUrl logic (Express trust-proxy aware). |
| server/mcp.js | Extends list_providers MCP tool output with provider id and enabled. |
| server/lineup.js | Uses stable stream URLs when available; avoids legacy fallback when profiles are initialized; improves upstream cleanup on disconnect. |
| server/epg.js | Bounds XMLTV rewrite cache variants; adds deterministic XMLTV record dedup; profiles/filters intersect deterministically; base URL via getBaseUrl. |
| server/backup.js | Makes backup/restore transactional and validated; adds DB snapshot export of YAML configs; serializes backup ops; invalidates dependent caches post-restore. |
| scripts/check-channel-health.js | Ensures streaming probe connections are consistently torn down (including error response bodies). |
| libs/source-service.js | Preserves provider IDs/created_at on config replaces; avoids destructive delete-all; supports enabled flag. |
| libs/source-channel-resolver.js | Adds DB-backed resolver for stable source-channel lookup by ID. |
| libs/proxy-image.js | Adds abort/cleanup logic for upstream image streams to avoid holding connections after client disconnect. |
| libs/output-profile-service.js | Threads sourceChannelId through output channels; adds hasOutputProfileEntries() to disambiguate “empty vs uninitialized”. |
| libs/getBaseUrl.js | Avoids manual forwarded-header inspection for live Express requests; relies on Express trust-proxy policy. |
| libs/config-loader.js | Adds schema support for provider IDs, provider enabled flag, and trusted_proxies list in app config. |
| libs/canonical-channel-service.js | Preserves canonical IDs/settings across mapping identity changes using stable source-channel association. |
| libs/cache-manager.js | Adds bounded-entry support and LRU behavior to cache implementation. |
| index.js | Makes trust proxy explicit/opt-in via trusted_proxies config. |
| config/examples/app.example.yaml | Documents trusted_proxies configuration. |
Review details
- Files reviewed: 28/28 changed files
- Comments generated: 3
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Comment on lines
+369
to
+373
| let { source, name } = req.params; | ||
| const upstreamOverride = req.query.upstream ? String(req.query.upstream) : null; | ||
| const channels = loadChannels(); | ||
|
|
||
| const channel = channels.find(c => c.source === source && c.name === name); | ||
| let channel = channels.find(c => c.source === source && c.name === name); |
Comment on lines
366
to
+370
| app.get('/api/stream-probe/:source/:name', requireAuth, async (req, res) => { | ||
| const { source, name } = req.params; | ||
| let { source, name } = req.params; | ||
| const channels = getChannels(); | ||
| const channel = channels.find(c => c.source === source && c.name === name); | ||
| const channel = source === 'channel' ? getSourceChannelById(name) : channels.find(c => c.source === source && c.name === name); | ||
| if (channel) { |
Comment on lines
+50
to
+52
| let { source, name } = req.params; | ||
| const channels = getChannels(); | ||
| const channel = channels.find(c => c.source === source && c.name === name); | ||
| const channel = source === 'channel' ? getSourceChannelById(name) : channels.find(c => c.source === source && c.name === name); |
This was referenced Sep 6, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Validation
The admin build was intentionally not run.