Skip to content

fix: invalid ids/names fail at authoring instead of mid-deploy; conformance suite repaired#149

Merged
wmadden-electric merged 4 commits into
mainfrom
claude/conformance-and-name-validation
Jul 22, 2026
Merged

fix: invalid ids/names fail at authoring instead of mid-deploy; conformance suite repaired#149
wmadden-electric merged 4 commits into
mainfrom
claude/conformance-and-name-validation

Conversation

@wmadden-electric

@wmadden-electric wmadden-electric commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Two unrelated fixes on one branch. The first changes when you find out a name is bad:

compute({ name: 'origin-proof', /* … */ })

Before: this authors fine, builds fine, and starts deploying — then, minutes in, with resources already created, the Management API rejects it:

key: must match POSIX env-var key shape: [A-Z_][A-Z0-9_]*

After: it fails the instant the module loads, in your editor or test run, with the framework's own explanation:

provision() id "origin-proof" (module "app") must contain only ASCII letters and digits
([A-Za-z0-9]) — the id becomes an address segment, and addresses derive deterministic
config keys (segments uppercased and joined with "_"). "origin-proof" would put
"ORIGIN-PROOF" inside the derived key.

The decision

Core's address-segment grammar is conservatively alphanumeric. Provision ids and declared input/param/secret names must match [A-Za-z0-9]+, enforced where they're written down — the node factory for declared names, module loading for provision ids — so a bad one can never reach a deploy.

Why these strings have a grammar at all

The framework hands each service its config through generated environment variables. The variable names are built from what you authored: segments (provision ids on the path to the service, then the declared name) are uppercased and joined with _ — id auth + param portCOMPOSER_AUTH_PORT. That derivation is deliberately dumb: no escaping, no sanitizing, so you can always predict the key from the code.

A dumb derivation is only safe if the segments are tame, and core already knew this: _ in an id was banned because it collides with the join separator (id auth_db + param url and id auth + input db + param url both derive AUTH_DB_URL), and . because it's the address path separator. What was missing is everything else — a - sails through and produces a key no env-var medium accepts. This PR closes the rule from "not _, not ." to "letters and digits only," which is the whole family of problems at once, not another special case.

Deliberately unchanged:

  • Node names stay free (only non-empty). Names are diagnostic labels and never enter keys (ADR-0006) — hyphenated app names like streams-example keep working.
  • The derivation itself is untouched — still no escaping, still predictable (ADR-0005's no-laundering rule). The grammar got narrower so the derivation never has to get cleverer.
  • The error cites core's rule, not any platform's. The POSIX motivation lives in a comment on isConfigKeySegment; what core enforces is its own address grammar.

Second fix: pnpm test:conformance:local runs again

Running the streams conformance suite locally failed with Cannot find module '../src/testing.ts' — and behind that first error were three stacked problems, invisible because no CI workflow runs this suite (verified — it's local-only):

  1. A stale import: the conformance file still pointed at src/testing.ts after the public-entrypoints move to src/exports/.
  2. Dependabot undid a deliberate pin: @durable-streams/server-conformance-tests was pinned to exactly 0.2.3 because 0.3.x tests features @prisma/streams-server 0.1.11 doesn't ship. The bump to 0.3.5 made 60 of 332 tests fail. The pin is restored, and the package is on dependabot's ignore list so it only moves by hand, together with streams-server.
  3. No root script: pnpm test:conformance:local now exists at the repo root, delegating to @internal/streams.

Result: 239/239 conformance tests pass. Adding the suite to CI is a real option but a separate decision (it needs the local server harness in CI) — not taken here.

Verification

Whole repo from root: build 29/29, typecheck 60/60, test 49/49, lint clean, cast delta 0, conformance 239/239. New tests: rejection of the live-failure case (hyphenated provision id, explicit and name-inferred) and a hyphenated param name; acceptance of camelCase, embedded digits, digits-only, and single-char segments. An independent review pass confirmed the segment coverage is complete: provision ids and input/param/secret names are exactly the user-controlled strings that reach key derivation — node names and expose names never do.

Alternatives considered

  • Target-side preflight instead of a core check (the strict reading of ADR-0019, "serialization is the target's contract"): a Prisma Cloud check at the start of lowering would keep core ignorant of key shapes entirely. Rejected: it trades away instant authoring-time feedback, and the core placement imports no target knowledge once the rule is core's own address grammar — any target can uppercase and join alphanumeric segments safely. If a future target wants richer names, the migration path is relaxing core's grammar plus per-target preflights; this PR makes that boundary explicit.
  • Escape or sanitize names during derivation (e.g. -_): rejected outright — it makes keys unpredictable from source, reintroduces the collision family the _ ban exists for, and violates the recorded no-laundering principle.
  • Fix conformance by upgrading @prisma/streams-server to match 0.3.x instead of re-pinning: the right long-term move, but a feature-work decision for the streams package, not a repair — the pin restores the suite's documented, intended state.

🤖 Generated with Claude Code

Three things broke or were missing:

- conformance/local.vitest.ts still imported ../src/testing.ts after PR #130
  moved public entrypoints to src/exports/, so the suite failed to load.
- Dependabot PR #126 bumped @durable-streams/server-conformance-tests from the
  exact pin 0.2.3 to 0.3.5, whose new tests exercise features
  @prisma/streams-server 0.1.11 does not ship (60 failures). Restore the pin
  and tell Dependabot to leave it alone; it moves by hand with streams-server.
- The repo root had no test:conformance:local script; add one that delegates
  to @internal/streams.

CI never runs the conformance suite (no workflow references it), which is why
these regressions went unnoticed.

Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
A compute service named "origin-proof", provisioned under its inferred id,
derived config env key COMPOSER_ORIGIN-PROOF_PORT — the Management API
rejects it minutes into a deploy ("key: must match POSIX env-var key shape:
[A-Z_][A-Z0-9_]*"). The same applies to any provision id (service, module,
resource, bucket, postgres, ...) because the id becomes an address segment,
and to input/param/secret names, since configKey uppercases all of these
segments and joins them with "_".

Tighten the two existing checks instead of adding a target-side one:

- core/src/load-module.ts: the provision-id check (previously banning only
  "_" and ".") now requires ids to be ASCII letters and digits, with an
  error naming the id, the module, and the derived key segment.
- core/src/node.ts: the input/param/secret name check (previously banning
  only "_") now requires the same charset at the factory.

Placement: both checks already lived in core and already justified
themselves by the config-key derivation, so extending them is the smallest
change consistent with that recorded placement; a Load-time integrity error
is the framework's documented failure point (Wiring precedes execution,
docs/design/01-principles). No sanitizing during key derivation — the
serializer stays deterministic (ADR-0005/ADR-0019); invalid names are
rejected loudly instead. Node NAMES stay unconstrained beyond non-empty
(ADR-0006: names are diagnostic; a hyphenated root/app name or a fake
served directly never enters a key) — only a name used as a provision id
is checked, at the moment it becomes an address segment.

Test fixtures that provisioned services under hyphenated ids (cli run
fixture, integration extension-config fixture) now use a key-safe id while
keeping their hyphenated app names.

Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
…the target's

Review nits on the previous commit:

- The rejection messages cited the POSIX env-var key shape
  [A-Z_][A-Z0-9_]* — a target medium leaking into core (ADR-0019). Both
  messages now state core's own rule: names/ids must be alphanumeric
  because addresses and declared names derive deterministic config keys.
  The POSIX motivation moved to a comment on isConfigKeySegment: the
  grammar is conservative by design so any target medium, POSIX env keys
  included, can uppercase and "_"-join segments without escaping.
- The integration extension-config fixture keeps its hyphenated compute
  NAME again — only the provision id needed to become key-safe.
- Boundary acceptance coverage: digits-only and single-char segments are
  accepted, for both provision ids and input/param names.

Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
@coderabbitai

coderabbitai Bot commented Jul 22, 2026

Copy link
Copy Markdown

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 882132aa-67d4-4ca2-b1c0-75f6c9b6fcdb

📥 Commits

Reviewing files that changed from the base of the PR and between db7ffd5 and 6598c16.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (11)
  • .github/dependabot.yml
  • package.json
  • packages/0-framework/1-core/core/src/__tests__/module-composition.test.ts
  • packages/0-framework/1-core/core/src/__tests__/module.test.ts
  • packages/0-framework/1-core/core/src/__tests__/node.test.ts
  • packages/0-framework/1-core/core/src/load-module.ts
  • packages/0-framework/1-core/core/src/node.ts
  • packages/0-framework/3-tooling/cli/src/__tests__/run.test.ts
  • packages/1-prisma-cloud/2-shared-modules/streams/conformance/local.vitest.ts
  • packages/1-prisma-cloud/2-shared-modules/streams/package.json
  • test/integration/test/fixtures/extension-config/service.ts

Knowledge base: Disabled due to Reviews -> Disable Knowledge Base setting


Summary by CodeRabbit

  • New Features

    • Added a command for running stream conformance tests locally.
    • Added consistent validation for configuration names and provision identifiers, allowing only ASCII letters and digits.
  • Bug Fixes

    • Improved error messages for invalid names and identifiers, including those containing dots, underscores, or hyphens.
    • Updated generated and test fixtures to use stable application identifiers.
  • Tests

    • Expanded coverage for valid and invalid configuration names and provision identifiers.
    • Updated local stream conformance testing to use the supported testing interface.

Walkthrough

The core framework now validates service, dependency, and provision identifiers as ASCII letters-and-digits-only config key segments. Error expectations and acceptance coverage were updated, while CLI and integration fixtures use the app identifier. Local streams conformance testing now uses exported testing utilities, has a root execution script, pins its conformance dependency, and excludes that dependency from automated updates.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/conformance-and-name-validation
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch claude/conformance-and-name-validation

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 Checkov (3.3.8)
.github/dependabot.yml

Traceback (most recent call last):
File "/usr/local/bin/checkov", line 2, in
from checkov.main import Checkov
ModuleNotFoundError: No module named 'checkov'

package.json

Traceback (most recent call last):
File "/usr/local/bin/checkov", line 2, in
from checkov.main import Checkov
ModuleNotFoundError: No module named 'checkov'

packages/1-prisma-cloud/2-shared-modules/streams/package.json

Traceback (most recent call last):
File "/usr/local/bin/checkov", line 2, in
from checkov.main import Checkov
ModuleNotFoundError: No module named 'checkov'

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint install timed out. The project may have too many dependencies for the sandbox.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@pkg-pr-new

pkg-pr-new Bot commented Jul 22, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/@prisma/composer@149
npm i https://pkg.pr.new/@prisma/composer-prisma-cloud@149

commit: 6598c16

@wmadden-electric wmadden-electric changed the title fix: names that can't derive config keys fail at authoring; conformance suite repaired fix: invalid ids/names fail at authoring instead of mid-deploy; conformance suite repaired Jul 22, 2026
@wmadden-electric
wmadden-electric merged commit aa44112 into main Jul 22, 2026
13 of 14 checks passed
@wmadden-electric
wmadden-electric deleted the claude/conformance-and-name-validation branch July 22, 2026 12:17
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.

2 participants