jsconsumer: fail the retention check when it cannot read the stream

main

Commit

nodo3w ago

checkAgainstStream returned success for every StreamInfo error, so the one check standing between an invalid ladder and silent data loss answered "fine" whenever it could not run.

That is reachable with ordinary NATS permissions, not just a broken server. Reading the stream and creating the consumer are separate API subjects, so a credential granted $JS.API.CONSUMER.> and $JS.API.INFO but not $JS.API.STREAM.> can create and drive its durable while every STREAM.INFO publish is denied. Measured on the pinned server: CreateOrUpdateConsumer succeeds, $JS.API.STREAM.INFO.<stream> comes back "Permissions Violation for Publish". The consumer then starts with a ladder nobody checked against retention, and a message whose ladder outlives max_age is discarded by the stream before capture — the ENT-1492 loss this check exists to prevent. The current entire-search grant includes $JS.API.>, so the immediate adopter is not exposed; the library contract was.

The probe now returns its error. The legitimate case still rides out, through the classifier rather than a blanket pass: a stream that does not exist yet surfaces as ErrStreamNotFound, which isRetryableStartError already treats as retryable, so Run keeps waiting for the provisioner exactly as before. A denied STREAM.INFO gets no reply and times out, also retryable — so the outcome is a consumer that is loudly absent, logging every attempt, rather than one quietly running unchecked.

Also dropped the second round trip: js.Stream already fetches STREAM.INFO to build the handle, so CachedInfo has the config and the follow-up Info call was one more request and one more failure mode on the startup path.

Two regressions, and getting the first to be honest took two attempts worth recording. Granting only $JS.API.CONSUMER.> is not enough to create a consumer — the client also probes $JS.API.INFO — so the first draft failed for the wrong reason. Then a 3s test context was consumed by the denied probe, leaving CreateOrUpdateConsumer to fail on an expired context: the test went red under the old behaviour too and proved nothing. With no test-imposed deadline and the right grant it discriminates properly — under the old code Start SUCCEEDS, which is the finding. The cost is ~5s waiting out jetstream's API timeout, noted at the test. The second regression pins that ErrStreamNotFound stays retryable so the provisioning race is not broken by making the probe strict.

Refs ENT-1601, ENT-1535, ENT-1492, COR-1224.

Co-Authored-By: Claude Opus 5 (1M context) noreply@anthropic.com Claude-Session: https://claude.ai/code/session_018qXhU99D2Sxaa32yZWwYRP Entire-Checkpoint: a79abc9d36e2

Checkpoints

Reconcile jsconsumer Retry Schedule After Broker Semantics

Claude CodeOpus 5
View session
Checkpoint 1