source-cooperative / source-cooperative/data.source.coop
Account product listing is not subject-scoped: owners see only public products
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 24
- Forks
- 6
- Avg merge
- 1h 32m
- Merged PRs (30d)
- 1
Description
Summary
aws s3 ls s3://{account}/ returns only public products, even when the caller owns the account. Unlisted and restricted products are invisible to their own owner.
Cause
SourceCoopRegistry::list_products passes None as the subject, so the product-list call is the only Source API lookup that is not subject-scoped — it goes out with no Authorization header:
https://github.com/source-cooperative/data.source.coop/blob/main/src/source_api/registry.rs#L29-L38
pub async fn list_products(&self, account: &str) -> Result<Vec<String>, ProxyError> {
let product_list = super::cache::get_or_fetch_product_list(
&self.api_base_url,
account,
&self.api_auth,
&self.request_id,
None, // <-- subject
)
With subject: None, cached_fetch skips the Authorization header and cache_key_with_subject returns the bare URL, so all callers share one cache entry.
Downstream, GET /api/v1/products/{account_id} filters on Actions.ListRepository, which returns true for an anonymous caller only when visibility === "public". Hence the owner sees the anonymous view of their own account.
Structural obstacle
AccountListHandler is a RouteHandler, and route handlers run before identity resolution in the multistore pipeline — so there is no resolved subject available at the point list_products is called. Fixing this likely means either resolving identity earlier for this route, or moving account listing off the route-handler path.
Impact
- Fails safe — over-restrictive, no data leak.
- But listing is a primary discovery path, and an owner cannot see their own non-public products through the S3 API.
- The shared, unsubjected cache entry is also inconsistent with the subject-scoped keying used by every other lookup.
Notes
Found while auditing the ADRs in #115 against the implementation. ADR-005 and ADR-007 currently claim all lookups are subject-scoped; that text is being corrected separately.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in src/source_api/registry.rs at SourceCoopRegistry::list_products and trace get_or_fetch_product_list, cached_fetch, and cache_key_with_subject. Then inspect AccountListHandler and the multistore identity-resolution path; done means account owners can list their unlisted and restricted products while anonymous results and cache entries remain correctly scoped.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- api, authorization, backend
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100