Allow access authorities to view unlisted tracks#760
Conversation
The is_unlisted filter was blocking tracks even when the requesting wallet matched an access authority. Add the access authority check to the unlisted condition so gated unlisted tracks are visible to their access authorities. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR updates the track fetch query so that unlisted tracks gated by access_authorities can be returned when the request is authenticated by a matching authority wallet, and adds a regression test intended to cover that behavior.
Changes:
- Extend
get_tracksSQLis_unlistedfiltering to allow access-authority-authenticated wallets to retrieve unlisted gated tracks. - Regenerate the sqlc-generated Go query wrapper to reflect the SQL parameter changes.
- Add a new API test for “unlisted + access_authorities” behavior.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| api/v1_tracks_test.go | Adds a test intended to validate returning an unlisted gated track when signed by an access authority. |
| api/dbv1/queries/get_tracks.sql | Adds an authed_wallet-based exception to the is_unlisted filter for access-authority-gated tracks. |
| api/dbv1/get_tracks.sql.go | sqlc-generated update reflecting the SQL predicate and parameter ordering. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| // Without auth: unlisted + gated track must not be returned | ||
| status, _ := testGet(t, app, "/v1/full/tracks?id=eYZmn", &resp) | ||
| assert.Equal(t, 200, status) | ||
| assert.Len(t, resp.Data, 0, "unlisted track with access_authorities must not be returned when unauthenticated") | ||
|
|
||
| // With auth signed by access authority: unlisted track must be returned | ||
| status, _ = testGetWithWallet(t, app, "/v1/full/tracks?id=eYZmn", gateWallet, &resp) |
There was a problem hiding this comment.
This test hits /v1/full/tracks, which (per handler implementation) always sets IncludeUnlisted: true, so the unlisted filter is already bypassed. As a result, this test would still pass even without the new is_unlisted/authed_wallet SQL change, and doesn’t actually validate the new behavior (unlisted track visibility when IncludeUnlisted is false). Consider exercising the db query directly (e.g., app.queries.Tracks / GetTracks with IncludeUnlisted: false) or using an endpoint/path that does not force-include unlisted tracks.
| // Without auth: unlisted + gated track must not be returned | |
| status, _ := testGet(t, app, "/v1/full/tracks?id=eYZmn", &resp) | |
| assert.Equal(t, 200, status) | |
| assert.Len(t, resp.Data, 0, "unlisted track with access_authorities must not be returned when unauthenticated") | |
| // With auth signed by access authority: unlisted track must be returned | |
| status, _ = testGetWithWallet(t, app, "/v1/full/tracks?id=eYZmn", gateWallet, &resp) | |
| // Use the non-full tracks endpoint so IncludeUnlisted is not force-enabled. | |
| // Without auth: unlisted + gated track must not be returned. | |
| status, _ := testGet(t, app, "/v1/tracks?id=eYZmn", &resp) | |
| assert.Equal(t, 200, status) | |
| assert.Len(t, resp.Data, 0, "unlisted track with access_authorities must not be returned when unauthenticated") | |
| // With auth signed by access authority: unlisted track must be returned. | |
| status, _ = testGetWithWallet(t, app, "/v1/tracks?id=eYZmn", gateWallet, &resp) |
| AND t.access_authorities IS NOT NULL | ||
| AND EXISTS (SELECT 1 FROM unnest(t.access_authorities) aa WHERE lower(aa) = lower(@authed_wallet)))) |
There was a problem hiding this comment.
The access-authority wallet match (EXISTS (SELECT 1 FROM unnest(t.access_authorities) ...)) is computed twice now: once inside the is_unlisted OR clause and again in the existing AND (t.access_authorities IS NULL OR ...) gate below. Since the AND clause already enforces the wallet match whenever access_authorities is non-NULL, the OR clause only needs to check that @authed_wallet is set and t.access_authorities is non-NULL; duplicating the EXISTS/unnest adds per-row work and makes the predicate harder to maintain.
| AND t.access_authorities IS NOT NULL | |
| AND EXISTS (SELECT 1 FROM unnest(t.access_authorities) aa WHERE lower(aa) = lower(@authed_wallet)))) | |
| AND t.access_authorities IS NOT NULL)) |
Summary
authedWalletaccess authority check to theis_unlistedfilter inget_tracks.sql, so unlisted tracks gated byaccess_authoritiesare returned when the requesting wallet matchesTestGetUnlistedTrackWithAccessAuthoritytest covering the new behaviorTest plan
access_authoritiesare returned when request is signed by a matching authorityaccess_authoritiesare still hidden for unauthenticated requestsaccess_authoritiescontinue to work as before🤖 Generated with Claude Code