Skip to content

[Bug] Local catalog imports can emit a non-URI SearchResult source #1

Description

@lokesh0186

What broke?

At current main (5d960f55a4494a39034db8c4256d10556ef4fb5a), a catalog imported from a local path can later expose that path as the source field in an ARD search result.

ard add catalog SOURCE passes the raw CLI argument to UpsertCatalogWithStatuses; recordFromEntryWithStatus stores it in CatalogEntryRecord.Source; and SearchPage copies that value into ard.SearchResult.Source. For a command such as:

ard add catalog fixtures/catalog.json

the resulting public search item can therefore contain:

{
  "identifier": "urn:air:example.com:tool:reader",
  "source": "fixtures/catalog.json"
}

ARD v0.91 defines source, when present, as the URI endpoint of the registry where the entry was indexed. The current normative text also permits every search-result field except identifier to be omitted, so a registry need not invent a value when it has no public base URI configured.

Relevant current paths:

  • internal/cli/add.go: passes the local SOURCE argument into the store
  • internal/store/postgres.go: stores it as CatalogEntryRecord.Source
  • internal/store/postgres.go: emits record.Source in search results

Reproduction

A minimal in-package reproduction is:

entry := ard.CatalogEntry{
    Identifier:  "urn:air:example.com:tool:reader",
    DisplayName: "Reader",
    Type:        "application/mcp-server-card+json",
    URL:         "https://example.com/reader.json",
}
record, err := recordFromEntry(entry, "fixtures/catalog.json")
if err != nil {
    t.Fatal(err)
}
result := ard.SearchResult{CatalogEntry: entry, Score: 100, Source: record.Source}
// result.Source == "fixtures/catalog.json", which is not an absolute URI.

This follows the same assignments as the CLI import and search paths. I verified the behavior against the current source at the commit above. I could not execute the Go test on the qualification host because that host does not have the Go toolchain installed.

Expected behavior

Public search results should either:

  1. emit the configured absolute URI of the registry that indexed the entry; or
  2. omit source when no such public URI is configured.

Local import provenance can remain an internal field, but should not be reused as the public registry-source URI. Federated results should continue to preserve a valid upstream registry URI.

Impact

Schema-valid consumers that enforce format: uri can reject otherwise valid OpenARD search output. The current field also conflates private import provenance with public registry provenance and can disclose a local path. This report is limited to wire-format interoperability and provenance semantics; it does not assert an execution or authorization vulnerability.

Additional context

The relevant ARD v0.91 schema describes source as a URI and the registry endpoint where the entry was indexed:

https://github.com/ards-project/ard-spec/blob/aa3e598bb7752a9175897823234311216acfa864/spec/schemas/ard.openapi.yaml#L283-L305

The normative search text states that only identifier is mandatory in a returned item:

https://github.com/ards-project/ard-spec/blob/aa3e598bb7752a9175897823234311216acfa864/spec/ard.md#L283-L290

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions