Skip to content

getNavigation() fails open: an unresolvable sectionRef silently returns the whole site #655

Description

@yumike

Problem

Site::navigation silently swallows an unresolvable section ref (crates/rw-site/src/site.rs:203):

let scope_path = section_ref
    .and_then(|r| snapshot.state.sections().find_by_ref(r).map(str::to_owned))
    .unwrap_or_default();   // -> "" -> the ROOT scope, i.e. the whole site

Ask for a scope that doesn't exist and you get the entire site, with no error and no signal that anything went wrong.

Why that's bad

The caller asked a specific question ("navigation scoped to system:default/payment-gateway") and got the answer to a different one ("navigation for everything"), which happens to look plausible.

Real consequences in the Backstage plugins:

  1. A typo'd annotation exposes the whole site. rwdocs.org/ref: component:default/arch#system:default/paymnt-gateway renders, on that entity's Documentation tab, every page of the arch site instead of failing. The docs repo renaming or moving a section produces the same drift with no warning anywhere.

  2. It hides host bugs. RwEntityDocsViewer.tsx:78 passes selfEntityRef — which is actually an entity path from toEntityPath() (default/component/foo), not a section ref at all, and not even parseable as one. It "works" only because find_by_ref returns None and rw falls open to the root scope. The plugin has been shipping a bug that rw's leniency conceals. (Ours to fix — but rw shouldn't have made it invisible.)

  3. It's inconsistent with the sibling API. pagePathFor(sectionRef, subpath) returns null for an unknown ref — the caller finds out. getNavigation(sectionRef) for the same unknown ref cheerfully returns the root scope. Same input, same site, two different philosophies.

Proposal

getNavigation(sectionRef) should fail when a non-null sectionRef resolves to no section — either by rejecting (SectionNotFound, ideally with the typed code from #653) or by returning a null/None navigation the host must handle.

sectionRef: null continues to mean "the whole site" — that's an explicit request for the root scope, not a failed lookup, and the two should never have been conflated.

This is a behavior break: a site with a typo'd annotation goes from "shows everything" to "shows an error". That's the point — the current behavior means a mis-scoped entity silently publishes documentation it was never meant to surface, and nobody finds out.

Related: #654 (a section ref that resolves to two sections is the mirror image of one that resolves to none — both are silent).

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

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions