source-cooperative / source-cooperative/data.source.coop

Account product listing is not subject-scoped: owners see only public products

Open
#215 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug
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

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.