Skip to content

Send per-feed auth headers when fetching GTFS-RT feeds#6

Merged
aaronbrethorst merged 2 commits into
mainfrom
fix/gtfs-rt-feed-auth-headers
Jun 10, 2026
Merged

Send per-feed auth headers when fetching GTFS-RT feeds#6
aaronbrethorst merged 2 commits into
mainfrom
fix/gtfs-rt-feed-auth-headers

Conversation

@aaronbrethorst

@aaronbrethorst aaronbrethorst commented Jun 9, 2026

Copy link
Copy Markdown
Member

Summary

  • Protected GTFS-RT feeds (e.g. Swiftly) require an Authorization header, but the validator fetched the vehicle-positions, trip-updates, and service-alerts feeds with no auth and got HTTP 401 — failing every RT check (rt-freshness, *-sampling, service-alert-crossref) even though the feeds were reachable.
  • Adds a per-data-source RealtimeHeaders map[string]string to the config, threads it through FetchRealtime(ctx, url, hdr)get(), and applies it to the three RT feeds.
  • The static GTFS bundle is fetched without these headers, so a feed's credential never leaks to the bundle host.
  • Companion change in obacloud populates realtimeHeaders in the validator config it generates (OneBusAway/obacloud — see that PR).

Test plan

  • go test ./... — all packages green
  • go vet ./... — clean
  • New unit tests at each layer: TestFetchRealtimeSendsHeaders (fetch), TestLoadParsesRealtimeHeaders (config), TestPrepareSendsRealtimeAuthHeaders (wiring — asserts the header reaches the RT feed and is absent on the static feed)
  • End-to-end against the live Tampa Swiftly endpoint through the actual fetch path: no-header → status 401 (reproduces the failure); with-header → 200, 9465 bytes of protobuf

Review notes (non-blocking)

  • Secret redaction: the validator's redaction set (util.go / document.go) scrubs apiKey/db_pass but not the new feed header value. The common 401 path does not leak (errors contain only URL + status; the Swiftly key is a header, not a query param). Defense-in-depth would add the feed header values to the redaction set — left as a follow-up to keep this change focused.

Summary by CodeRabbit

  • New Features

    • Per-data-source custom headers can be configured and will be sent with GTFS-Realtime requests (vehicle positions, trip updates, service alerts). Static GTFS fetches remain unaffected and do not receive these headers.
  • Tests

    • Added tests verifying header parsing and that realtime requests receive configured headers while static feed requests do not.

Protected GTFS-RT feeds (e.g. Swiftly) require an Authorization header,
but the validator fetched the vehicle-positions, trip-updates, and
service-alerts feeds with no auth and got HTTP 401 — failing every RT
check even though the feeds were reachable.

Add a per-data-source RealtimeHeaders map to the config, thread it
through FetchRealtime, and apply it to the three RT feeds. The static
GTFS bundle is fetched without these headers so a feed's credential
never leaks to the bundle host.
@coderabbitai

coderabbitai Bot commented Jun 9, 2026

Copy link
Copy Markdown

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: ffefe43a-db1f-4064-8a10-6d05f8d08025

📥 Commits

Reviewing files that changed from the base of the PR and between d2c3812 and 5424c33.

📒 Files selected for processing (2)
  • feeds/fetch_test.go
  • validator/prepare_test.go

📝 Walkthrough

Walkthrough

This PR adds support for per-source HTTP headers on GTFS-RT realtime feed requests. The DataSource config struct gains a RealtimeHeaders map, the Fetcher.FetchRealtime method accepts optional headers, and the validator propagates configured headers to realtime feed requests while keeping static feed requests header-free.

Changes

Realtime Headers Feature

Layer / File(s) Summary
Configuration schema for realtime headers
config/config.go, config/config_test.go
DataSource adds an optional RealtimeHeaders field (map of string pairs) to allow per-source headers in configuration JSON. Test verifies the field is parsed correctly from config.
Fetcher API support for per-request headers
feeds/fetch.go, feeds/fetch_test.go
FetchRealtime now accepts an optional http.Header parameter and forwards it to the HTTP request. FetchStatic's non-cached fallback explicitly passes nil to preserve prior behavior. Tests verify headers are forwarded and reach the network request.
Validator integration and end-to-end validation
validator/validator.go, validator/prepare_test.go
The prepare function constructs an http.Header from each DataSource's RealtimeHeaders configuration and passes it to FetchRealtime calls. Integration test confirms headers reach the realtime endpoint (/vp) but not the static feed endpoint (/static).

🎯 3 (Moderate) | ⏱️ ~20 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Send per-feed auth headers when fetching GTFS-RT feeds' accurately captures the main objective of the PR: adding support for per-feed authentication headers when fetching realtime GTFS data.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/gtfs-rt-feed-auth-headers

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@feeds/fetch_test.go`:
- Line 35: The test HTTP handler in fetch_test.go calls w.Write([]byte("rt"))
without checking its error; update the handler that contains the w.Write call to
capture the returned (int, error) and handle the error (e.g. if err != nil {
t.Fatalf("write failed: %v", err) } or use require.NoError(t, err)) so the test
fails loudly on write errors and satisfies errcheck; reference the w.Write call
in the test handler in fetch_test.go.

In `@validator/prepare_test.go`:
- Around line 51-53: The test currently only checks auth["/static"] == "" which
can pass if the "/static" handler was never invoked; first assert that the
"/static" entry was actually recorded (e.g., check for presence with _, ok :=
auth["/static"] or a request counter/hits map) and fail the test immediately if
it was not hit (use t.Fatalf or t.Fatalf-like assertion), then proceed to assert
the header value is empty; update the checks around the auth map access in
prepare_test.go so you explicitly verify the request occurred before asserting
auth["/static"] == "".
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: b52270fe-117d-4549-a29f-11fda3a512d0

📥 Commits

Reviewing files that changed from the base of the PR and between d8e626f and d2c3812.

📒 Files selected for processing (6)
  • config/config.go
  • config/config_test.go
  • feeds/fetch.go
  • feeds/fetch_test.go
  • validator/prepare_test.go
  • validator/validator.go

Comment thread feeds/fetch_test.go Outdated
Comment thread validator/prepare_test.go Outdated
…tion

- TestFetchRealtimeSendsHeaders: handle the httptest handler's w.Write
  error so the test fails loudly instead of silently dropping a write.
- TestPrepareSendsRealtimeAuthHeaders: assert /static was actually
  requested before checking its Authorization header was empty, so the
  credential-leak check can't pass vacuously when the feed is never hit.
@sonarqubecloud

Copy link
Copy Markdown

@aaronbrethorst aaronbrethorst merged commit ca60f4e into main Jun 10, 2026
5 of 6 checks passed
@aaronbrethorst aaronbrethorst deleted the fix/gtfs-rt-feed-auth-headers branch June 10, 2026 00:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant