Skip to content

command: reject empty segments in Parse - #122

Open
Zahanturel wants to merge 1 commit into
ucan-wg:mainfrom
Zahanturel:command/reject-empty-segments
Open

command: reject empty segments in Parse#122
Zahanturel wants to merge 1 commit into
ucan-wg:mainfrom
Zahanturel:command/reject-empty-segments

Conversation

@Zahanturel

@Zahanturel Zahanturel commented Aug 16, 2026

Copy link
Copy Markdown

command.Parse accepts /crud//create. rs-ucan rejects it with a dedicated EmptySegment error, so the two implementations currently disagree on whether that command is well formed. Parse is what runs on decode (token/delegation/delegation.go:252, token/invocation/invocation.go:290), so the disagreement is about which tokens each library accepts off the wire.

Parse implements the constraints the spec's Segment Structure section states (leading slash, no trailing slash, lowercase) and nothing beyond them, because that section says nothing about a segment being non-empty. ucan-wg/spec#196 proposes adding Segment MUST NOT be empty. to that paragraph, following from ucan-wg/delegation#26. That PR is not merged. rs-ucan made the corresponding change in ucan-wg/rs-ucan#178 while spec#196 was still open, which is the precedent this follows.

The check uses strings.Contains(s, separator+separator) rather than splitting into segments: at that point in the function the leading slash is mandatory and a trailing slash has already been rejected, so an empty segment can only appear as adjacent separators, and / needs no special case. It sits after the lowercase check so the error returned for a given input matches the one rs-ucan returns.

input before after
/ ok ok
/crud/create ok ok
/crud//create ok ErrEmptySegment
/crud// ErrDisallowsTrailingSlash unchanged
/CRUD//create ErrRequiresLowercase unchanged

Scope is Parse only; New and Join are untouched. Is their current contract intended? Join short-circuits on zero total length, so New("") returns Top, and TestNew/TestJoin assert that normalizing behaviour, so I have left it alone rather than assume.

This is a behaviour change: Parse gets stricter, so a caller that currently accepts /crud//create will start receiving an error. No fixture or test in the tree carries a command with an empty segment. The new case was confirmed to fail against unmodified Parse before the check was added, in both TestParseCommand/fails_when and TestIsValidCommand/fails_when. go test ./... -tags jwx_es256k passes.

Parse enforced the constraints stated in the spec's Segment Structure
section (leading slash, no trailing slash, lowercase) but placed no
constraint on the segments themselves, so "/crud//create" parsed
successfully.

rs-ucan rejects that input with a dedicated EmptySegment error, so the
two implementations disagree on whether such a command is well formed.
Add ErrEmptySegment and check for adjacent separators after the
lowercase check, matching the order rs-ucan applies its checks in.
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