Skip to content

Publish a component under the name the guard approved, not the padded one - #401

Open
kevin9327 wants to merge 1 commit into
CopilotKit:mainfrom
kevin9327:fix/catalogue-trim
Open

Publish a component under the name the guard approved, not the padded one#401
kevin9327 wants to merge 1 commit into
CopilotKit:mainfrom
kevin9327:fix/catalogue-trim

Conversation

@kevin9327

Copy link
Copy Markdown
Contributor

What this changes

PUT /components/catalogue asks whether each announced component is more than whitespace, and then
publishes the string it did not ask about:

if (
  typeof name !== "string" || !name.trim() ||
  typeof title !== "string" || !title.trim() ||
  ...
) {
  return [];
}
return [{ name, title, kind, description }];

For title, kind and description that is cosmetic. For name it is not, because a component's
name is its identity:

  • syncCatalogue compares it against a Set of names already published, so " weatherPanel " is
    not weatherPanel and a new row is added
  • decide(name, agentId) and listForAgent look a component up by it
  • a grant and a revoke each name it, and the audit row for the arrival carries it

So a build that ships a name with a stray space publishes a second component beside the real one.
It is published and ungranted by anyone, it appears in the catalogue, and an administrator holding a
Bot back from weatherPanel does not hold it back from the other one, because as far as every one
of those lookups is concerned they are different components. Nothing reports this; the announcement
returns added: [" weatherPanel "] and the trail records that name as an arrival.

The four fields are now stored as the strings the guard approved.

This is the same shape as #376 and #377 — validate the trimmed string, store the raw one — and the
fourth place it appears. #393 is the third and is still open; the two are independent files and
neither depends on the other.

Where it runs

  • New state that outlives a request? None. The catalogue row already existed; this changes
    which string is written into it.
  • What happens on the second replica? The same announcement produces the same name on every
    replica, which is the point: today two replicas served by builds that differ by a space
    publish two components. syncCatalogue is additive and compares against what is in Postgres,
    so the row is shared and this makes the comparison agree across processes rather than depend
    on which build's string arrived.
  • Anything serialised? No new serialisation. syncCatalogue is unchanged: it still reads
    the published names and inserts only what is missing.
  • Anything fanned out to a browser? No.
  • New listener, port, or schedule? None.

Boundary and audit

  • Every acting call still goes through the gateway: this route is behind requireUser as
    before and its decision path is untouched.
  • New refusals and new failures each write a row: no new refusal. The existing
    component.published row now carries the trimmed name, which is the name every other part of
    the system uses for it.
  • Nothing new is trusted from the client: strictly less. The name is now the server's own
    normalisation of what the build sent.

Changelog

  • A line in CHANGELOG.md under Unreleased.

Tests

server/tests/component-catalogue.test.ts, new, against a stub store that records what was
published:

  • an ordinary component is published unchanged
  • a padded name is published as the name, not as a second component
  • a padded title and description are published as the reader will see them
  • a padded kind is published as the kind
  • an entry that is only whitespace is still refused
  • a body that is not a list is still a 400

Against main, three of the six fail:

expect(received).toBe(expected)
Expected: "weatherPanel"
Received: " weatherPanel "

How I tested

Windows 11, Bun 1.3.14. bun test server/tests/component-catalogue.test.ts server/tests/component-decision.test.ts is 11 passed, 0 failed.
bun run --filter server typecheck and bunx biome check are clean.

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant