Skip to content

feat(cedarling-js): add JavaScript runtime agnostic sdk for Cedarling. - #14635

Open
Dahkenangnon wants to merge 11 commits into
mainfrom
jans-cedarling-14582
Open

feat(cedarling-js): add JavaScript runtime agnostic sdk for Cedarling.#14635
Dahkenangnon wants to merge 11 commits into
mainfrom
jans-cedarling-14582

Conversation

@Dahkenangnon

Copy link
Copy Markdown

Prepare


Description

Target issue

Closes #14582

Implementation Details

This PR introduces @janssenproject/cedarling, a JavaScript and TypeScript SDK wrapping the generated @janssenproject/cedarling_wasm package.

Key changes:

  • Adds a typed, runtime-neutral API for authorization, context management, issuer inspection, decision logs, and client lifecycle management.
  • Supports Node.js, browsers, Bun, Deno, Electron, Cloudflare Workers/workerd, and edge runtimes through runtime-specific package entry points.
  • Adds validation and contract tests that fail early when critical upstream Cedarling WASM exports or response shapes change.
  • Adds unit, contract, browser, packed-consumer, and end-to-end tests across the supported runtimes.
  • Adds runnable React/Node.js, Hono, Electron, and Next.js examples.
  • Excludes bindings/cedarling_js from the parent Rust workspace because it is an npm project built on top of the WASM binding.
  • Integrates the SDK into the existing Cedarling workflows:
    • test-cedarling.yml builds the WASM package locally and runs the complete JavaScript SDK check suite.
    • build-packages.yml shares the generated WASM artifact, builds and validates the SDK package, coordinates release versions, and publishes it to npm using the existing npm publishing secret.
  • Adds consumer documentation and a focused maintainer guide covering the SDK boundary, project structure, supported runtimes, testing strategy, build order, and CI release lifecycle.

No new workflow files or npm publishing credentials were introduced.


Test and Document the changes

  • Static code analysis has been run locally and issues have been fixed
  • Relevant unit and integration tests have been added/updated
  • Relevant documentation has been updated

Validation included:

  • npm ci
  • npm run check
  • TypeScript type checking
  • Unit and WASM contract tests
  • Supported-runtime test suites
  • Browser and packed-consumer tests
  • Package build and dry-run publication checks
  • GitHub Actions workflow syntax validation

Documentation is included in the SDK root README and docs/README.md.

  • I confirm that there is no impact on the docs due to the code changes in this PR.

Not applicable: this PR has documentation impact, and the relevant documentation has been updated.

Signed-off-by: Justin Dah-kenangnon <dah.kenangnon@gmail.com>
Signed-off-by: Justin Dah-kenangnon <dah.kenangnon@gmail.com>
Signed-off-by: Justin Dah-kenangnon <dah.kenangnon@gmail.com>
Signed-off-by: Justin Dah-kenangnon <dah.kenangnon@gmail.com>
Signed-off-by: Justin Dah-kenangnon <dah.kenangnon@gmail.com>
@Dahkenangnon
Dahkenangnon requested a review from moabu as a code owner July 27, 2026 10:15
@coderabbitai

coderabbitai Bot commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Too many files!

This PR contains 249 files, which is 99 over the limit of 150.

To get a review, narrow the scope:
• coderabbit review --committed # exclude uncommitted changes
• coderabbit review --dir # limit to a subdirectory
• coderabbit review --base # compare against a closer base

Upgrade to a paid plan to raise the limit.

This review couldn't start because sufficient usage credits or metered capacity aren't available. Add credits or update usage-based reviews in the billing tab, then retry.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 3763f8c6-f19b-47c7-8606-daabff72ae31

📥 Commits

Reviewing files that changed from the base of the PR and between 9671e8a and 4ac3926.

⛔ Files ignored due to path filters (8)
  • demos/cedarling-js-examples/common/package-lock.json is excluded by !**/package-lock.json
  • demos/cedarling-js-examples/electron/assets/icon.png is excluded by !**/*.png
  • demos/cedarling-js-examples/electron/package-lock.json is excluded by !**/package-lock.json
  • demos/cedarling-js-examples/hono/package-lock.json is excluded by !**/package-lock.json
  • demos/cedarling-js-examples/react-nodejs/backend/package-lock.json is excluded by !**/package-lock.json
  • demos/cedarling-js-examples/react-nodejs/frontend/package-lock.json is excluded by !**/package-lock.json
  • demos/cedarling-js-examples/vercel-nextjs/package-lock.json is excluded by !**/package-lock.json
  • jans-cedarling/bindings/cedarling_js/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (249)
  • .github/workflows/build-packages.yml
  • .github/workflows/test-cedarling.yml
  • demos/README.md
  • demos/cedarling-js-examples/README.md
  • demos/cedarling-js-examples/common/.gitignore
  • demos/cedarling-js-examples/common/README.md
  • demos/cedarling-js-examples/common/idp.js
  • demos/cedarling-js-examples/common/package.json
  • demos/cedarling-js-examples/common/policies.cedar
  • demos/cedarling-js-examples/common/policy-store.json
  • demos/cedarling-js-examples/common/schema.cedarschema
  • demos/cedarling-js-examples/common/test-config.json
  • demos/cedarling-js-examples/electron/.erb/configs/.eslintrc
  • demos/cedarling-js-examples/electron/.erb/configs/webpack.config.base.ts
  • demos/cedarling-js-examples/electron/.erb/configs/webpack.config.main.dev.ts
  • demos/cedarling-js-examples/electron/.erb/configs/webpack.config.main.prod.ts
  • demos/cedarling-js-examples/electron/.erb/configs/webpack.config.preload.dev.ts
  • demos/cedarling-js-examples/electron/.erb/configs/webpack.config.renderer.dev.dll.ts
  • demos/cedarling-js-examples/electron/.erb/configs/webpack.config.renderer.dev.ts
  • demos/cedarling-js-examples/electron/.erb/configs/webpack.config.renderer.prod.ts
  • demos/cedarling-js-examples/electron/.erb/configs/webpack.paths.ts
  • demos/cedarling-js-examples/electron/.erb/mocks/fileMock.js
  • demos/cedarling-js-examples/electron/.erb/scripts/.eslintrc
  • demos/cedarling-js-examples/electron/.erb/scripts/check-build-exists.ts
  • demos/cedarling-js-examples/electron/.erb/scripts/check-node-env.js
  • demos/cedarling-js-examples/electron/.erb/scripts/check-port-in-use.js
  • demos/cedarling-js-examples/electron/.erb/scripts/delete-source-maps.js
  • demos/cedarling-js-examples/electron/.gitignore
  • demos/cedarling-js-examples/electron/README.md
  • demos/cedarling-js-examples/electron/eslint.config.js
  • demos/cedarling-js-examples/electron/package.json
  • demos/cedarling-js-examples/electron/postcss.config.js
  • demos/cedarling-js-examples/electron/scripts/verify-renderer-bundle.mjs
  • demos/cedarling-js-examples/electron/scripts/verify-renderer-dev-bundle.mjs
  • demos/cedarling-js-examples/electron/src/__tests__/App.test.tsx
  • demos/cedarling-js-examples/electron/src/__tests__/ipc.test.ts
  • demos/cedarling-js-examples/electron/src/main/cedarling/authorize.ts
  • demos/cedarling-js-examples/electron/src/main/cedarling/init.ts
  • demos/cedarling-js-examples/electron/src/main/ipc.ts
  • demos/cedarling-js-examples/electron/src/main/main.ts
  • demos/cedarling-js-examples/electron/src/main/preload.ts
  • demos/cedarling-js-examples/electron/src/main/tasks.ts
  • demos/cedarling-js-examples/electron/src/main/util.ts
  • demos/cedarling-js-examples/electron/src/renderer/App.css
  • demos/cedarling-js-examples/electron/src/renderer/App.tsx
  • demos/cedarling-js-examples/electron/src/renderer/cedarling/exercise-signed.ts
  • demos/cedarling-js-examples/electron/src/renderer/cedarling/exercise-unsigned.ts
  • demos/cedarling-js-examples/electron/src/renderer/cedarling/init.ts
  • demos/cedarling-js-examples/electron/src/renderer/index.ejs
  • demos/cedarling-js-examples/electron/src/renderer/index.tsx
  • demos/cedarling-js-examples/electron/src/renderer/preload.d.ts
  • demos/cedarling-js-examples/electron/tsconfig.app.json
  • demos/cedarling-js-examples/electron/tsconfig.json
  • demos/cedarling-js-examples/hono/.gitignore
  • demos/cedarling-js-examples/hono/README.md
  • demos/cedarling-js-examples/hono/deno.json
  • demos/cedarling-js-examples/hono/package.json
  • demos/cedarling-js-examples/hono/src/app.ts
  • demos/cedarling-js-examples/hono/src/cedarling/authorize.ts
  • demos/cedarling-js-examples/hono/src/cedarling/init.ts
  • demos/cedarling-js-examples/hono/src/entry.bun.ts
  • demos/cedarling-js-examples/hono/src/entry.cloudflare.ts
  • demos/cedarling-js-examples/hono/src/entry.deno.ts
  • demos/cedarling-js-examples/hono/src/tasks.ts
  • demos/cedarling-js-examples/hono/tsconfig.json
  • demos/cedarling-js-examples/hono/wrangler.toml
  • demos/cedarling-js-examples/react-nodejs/.gitignore
  • demos/cedarling-js-examples/react-nodejs/README.md
  • demos/cedarling-js-examples/react-nodejs/backend/.gitignore
  • demos/cedarling-js-examples/react-nodejs/backend/README.md
  • demos/cedarling-js-examples/react-nodejs/backend/cedarling/authz-middleware.js
  • demos/cedarling-js-examples/react-nodejs/backend/cedarling/exercise-context.js
  • demos/cedarling-js-examples/react-nodejs/backend/cedarling/exercise-issuers.js
  • demos/cedarling-js-examples/react-nodejs/backend/cedarling/exercise-lifecycle.js
  • demos/cedarling-js-examples/react-nodejs/backend/cedarling/exercise-logs.js
  • demos/cedarling-js-examples/react-nodejs/backend/cedarling/index.js
  • demos/cedarling-js-examples/react-nodejs/backend/cedarling/init.js
  • demos/cedarling-js-examples/react-nodejs/backend/package.json
  • demos/cedarling-js-examples/react-nodejs/backend/server.js
  • demos/cedarling-js-examples/react-nodejs/frontend/.gitignore
  • demos/cedarling-js-examples/react-nodejs/frontend/README.md
  • demos/cedarling-js-examples/react-nodejs/frontend/index.html
  • demos/cedarling-js-examples/react-nodejs/frontend/package.json
  • demos/cedarling-js-examples/react-nodejs/frontend/postcss.config.js
  • demos/cedarling-js-examples/react-nodejs/frontend/src/App.tsx
  • demos/cedarling-js-examples/react-nodejs/frontend/src/cedarling/exercise-signed.ts
  • demos/cedarling-js-examples/react-nodejs/frontend/src/cedarling/exercise-unsigned.ts
  • demos/cedarling-js-examples/react-nodejs/frontend/src/cedarling/init.ts
  • demos/cedarling-js-examples/react-nodejs/frontend/src/index.css
  • demos/cedarling-js-examples/react-nodejs/frontend/src/main.tsx
  • demos/cedarling-js-examples/react-nodejs/frontend/tailwind.config.js
  • demos/cedarling-js-examples/react-nodejs/frontend/vite.config.ts
  • demos/cedarling-js-examples/scripts/install-example.mjs
  • demos/cedarling-js-examples/scripts/install.mjs
  • demos/cedarling-js-examples/vercel-nextjs/.gitignore
  • demos/cedarling-js-examples/vercel-nextjs/README.md
  • demos/cedarling-js-examples/vercel-nextjs/app/api/cedarling/exercises/route.ts
  • demos/cedarling-js-examples/vercel-nextjs/app/api/check-edge/route.ts
  • demos/cedarling-js-examples/vercel-nextjs/app/api/check/route.ts
  • demos/cedarling-js-examples/vercel-nextjs/app/api/config/route.ts
  • demos/cedarling-js-examples/vercel-nextjs/app/api/oidc/callback/route.ts
  • demos/cedarling-js-examples/vercel-nextjs/app/api/oidc/logout/callback/route.ts
  • demos/cedarling-js-examples/vercel-nextjs/app/api/oidc/logout/route.ts
  • demos/cedarling-js-examples/vercel-nextjs/app/api/oidc/session/route.ts
  • demos/cedarling-js-examples/vercel-nextjs/app/api/oidc/start/route.ts
  • demos/cedarling-js-examples/vercel-nextjs/app/api/tasks/[id]/route.ts
  • demos/cedarling-js-examples/vercel-nextjs/app/api/tasks/route.ts
  • demos/cedarling-js-examples/vercel-nextjs/app/globals.css
  • demos/cedarling-js-examples/vercel-nextjs/app/layout.tsx
  • demos/cedarling-js-examples/vercel-nextjs/app/page.tsx
  • demos/cedarling-js-examples/vercel-nextjs/libs/cedarling/authorize.ts
  • demos/cedarling-js-examples/vercel-nextjs/libs/cedarling/exercises.ts
  • demos/cedarling-js-examples/vercel-nextjs/libs/cedarling/init.ts
  • demos/cedarling-js-examples/vercel-nextjs/libs/oidc/auth.ts
  • demos/cedarling-js-examples/vercel-nextjs/libs/oidc/provider.ts
  • demos/cedarling-js-examples/vercel-nextjs/libs/oidc/session.ts
  • demos/cedarling-js-examples/vercel-nextjs/libs/oidc/verify.ts
  • demos/cedarling-js-examples/vercel-nextjs/libs/tasks.ts
  • demos/cedarling-js-examples/vercel-nextjs/next-env.d.ts
  • demos/cedarling-js-examples/vercel-nextjs/next.config.ts
  • demos/cedarling-js-examples/vercel-nextjs/package.json
  • demos/cedarling-js-examples/vercel-nextjs/playwright.config.ts
  • demos/cedarling-js-examples/vercel-nextjs/postcss.config.mjs
  • demos/cedarling-js-examples/vercel-nextjs/tailwind.config.ts
  • demos/cedarling-js-examples/vercel-nextjs/tests/e2e/oidc.spec.ts
  • demos/cedarling-js-examples/vercel-nextjs/tsconfig.json
  • jans-cedarling/Cargo.toml
  • jans-cedarling/bindings/cedarling_js/.gitignore
  • jans-cedarling/bindings/cedarling_js/.npmrc
  • jans-cedarling/bindings/cedarling_js/README.md
  • jans-cedarling/bindings/cedarling_js/docs/README.md
  • jans-cedarling/bindings/cedarling_js/package.json
  • jans-cedarling/bindings/cedarling_js/scripts/assert-publishable.mjs
  • jans-cedarling/bindings/cedarling_js/scripts/clean.mjs
  • jans-cedarling/bindings/cedarling_js/scripts/stage-release.mjs
  • jans-cedarling/bindings/cedarling_js/scripts/verify-consumer.mjs
  • jans-cedarling/bindings/cedarling_js/src/authorization/dispatch.ts
  • jans-cedarling/bindings/cedarling_js/src/authorization/request.ts
  • jans-cedarling/bindings/cedarling_js/src/authorization/types.ts
  • jans-cedarling/bindings/cedarling_js/src/client/client.ts
  • jans-cedarling/bindings/cedarling_js/src/client/types.ts
  • jans-cedarling/bindings/cedarling_js/src/configuration/prepare.ts
  • jans-cedarling/bindings/cedarling_js/src/configuration/types.ts
  • jans-cedarling/bindings/cedarling_js/src/context/input.ts
  • jans-cedarling/bindings/cedarling_js/src/context/types.ts
  • jans-cedarling/bindings/cedarling_js/src/engine/edge.ts
  • jans-cedarling/bindings/cedarling_js/src/engine/engine.ts
  • jans-cedarling/bindings/cedarling_js/src/engine/factory.ts
  • jans-cedarling/bindings/cedarling_js/src/engine/generated.ts
  • jans-cedarling/bindings/cedarling_js/src/engine/node.ts
  • jans-cedarling/bindings/cedarling_js/src/engine/wasm-modules.d.ts
  • jans-cedarling/bindings/cedarling_js/src/engine/web.ts
  • jans-cedarling/bindings/cedarling_js/src/engine/workerd.ts
  • jans-cedarling/bindings/cedarling_js/src/entries/edge.ts
  • jans-cedarling/bindings/cedarling_js/src/entries/node.ts
  • jans-cedarling/bindings/cedarling_js/src/entries/workerd.ts
  • jans-cedarling/bindings/cedarling_js/src/errors/errors.ts
  • jans-cedarling/bindings/cedarling_js/src/errors/types.ts
  • jans-cedarling/bindings/cedarling_js/src/index.ts
  • jans-cedarling/bindings/cedarling_js/src/issuers/input.ts
  • jans-cedarling/bindings/cedarling_js/src/issuers/types.ts
  • jans-cedarling/bindings/cedarling_js/src/logs/normalize.ts
  • jans-cedarling/bindings/cedarling_js/src/logs/query.ts
  • jans-cedarling/bindings/cedarling_js/src/logs/types.ts
  • jans-cedarling/bindings/cedarling_js/src/values/inspect.ts
  • jans-cedarling/bindings/cedarling_js/src/values/snapshot.ts
  • jans-cedarling/bindings/cedarling_js/src/values/types.ts
  • jans-cedarling/bindings/cedarling_js/tests/.browser.sh
  • jans-cedarling/bindings/cedarling_js/tests/.bun.sh
  • jans-cedarling/bindings/cedarling_js/tests/.deno.sh
  • jans-cedarling/bindings/cedarling_js/tests/.edge.sh
  • jans-cedarling/bindings/cedarling_js/tests/.electron.sh
  • jans-cedarling/bindings/cedarling_js/tests/.workerd.sh
  • jans-cedarling/bindings/cedarling_js/tests/build-sandbox.mjs
  • jans-cedarling/bindings/cedarling_js/tests/contract/authorization.test.ts
  • jans-cedarling/bindings/cedarling_js/tests/contract/authorize-multi-issuer.test.ts
  • jans-cedarling/bindings/cedarling_js/tests/contract/authorize-unsigned.test.ts
  • jans-cedarling/bindings/cedarling_js/tests/contract/configuration.test.ts
  • jans-cedarling/bindings/cedarling_js/tests/contract/context.test.ts
  • jans-cedarling/bindings/cedarling_js/tests/contract/error-contract.test.ts
  • jans-cedarling/bindings/cedarling_js/tests/contract/exports.test.ts
  • jans-cedarling/bindings/cedarling_js/tests/contract/index.ts
  • jans-cedarling/bindings/cedarling_js/tests/contract/issuers.test.ts
  • jans-cedarling/bindings/cedarling_js/tests/contract/lifecycle.test.ts
  • jans-cedarling/bindings/cedarling_js/tests/contract/logs.test.ts
  • jans-cedarling/bindings/cedarling_js/tests/contract/policy-archive.test.ts
  • jans-cedarling/bindings/cedarling_js/tests/contract/policy-loader.test.ts
  • jans-cedarling/bindings/cedarling_js/tests/contract/policy-url.test.ts
  • jans-cedarling/bindings/cedarling_js/tests/contract/value-validation.test.ts
  • jans-cedarling/bindings/cedarling_js/tests/contract/web-entry.test.ts
  • jans-cedarling/bindings/cedarling_js/tests/contract/web-initialization-errors.test.ts
  • jans-cedarling/bindings/cedarling_js/tests/contract/web-native-policy-sources.test.ts
  • jans-cedarling/bindings/cedarling_js/tests/contract/web-tracer.test.ts
  • jans-cedarling/bindings/cedarling_js/tests/e2e/browser-tracer.test.ts
  • jans-cedarling/bindings/cedarling_js/tests/e2e/consumer.test.ts
  • jans-cedarling/bindings/cedarling_js/tests/e2e/index.ts
  • jans-cedarling/bindings/cedarling_js/tests/e2e/stage-release.test.ts
  • jans-cedarling/bindings/cedarling_js/tests/e2e/webpack-build.test.ts
  • jans-cedarling/bindings/cedarling_js/tests/fixtures/browser-tracer-consumer.mjs
  • jans-cedarling/bindings/cedarling_js/tests/fixtures/browser-tracer.html
  • jans-cedarling/bindings/cedarling_js/tests/fixtures/fixtures.ts
  • jans-cedarling/bindings/cedarling_js/tests/fixtures/multi-issuer-policy-store.ts
  • jans-cedarling/bindings/cedarling_js/tests/fixtures/tracer-policy-store.cjar
  • jans-cedarling/bindings/cedarling_js/tests/fixtures/tracer-policy-store.ts
  • jans-cedarling/bindings/cedarling_js/tests/fixtures/webpack.mjs
  • jans-cedarling/bindings/cedarling_js/tests/playwright.config.ts
  • jans-cedarling/bindings/cedarling_js/tests/run-edge.mjs
  • jans-cedarling/bindings/cedarling_js/tests/run.ts
  • jans-cedarling/bindings/cedarling_js/tests/runners/assets.d.ts
  • jans-cedarling/bindings/cedarling_js/tests/runners/browser-page.ts
  • jans-cedarling/bindings/cedarling_js/tests/runners/browser.ts
  • jans-cedarling/bindings/cedarling_js/tests/runners/bun.ts
  • jans-cedarling/bindings/cedarling_js/tests/runners/deno.ts
  • jans-cedarling/bindings/cedarling_js/tests/runners/edge.ts
  • jans-cedarling/bindings/cedarling_js/tests/runners/electron.ts
  • jans-cedarling/bindings/cedarling_js/tests/runners/file-url-fetch-shim.ts
  • jans-cedarling/bindings/cedarling_js/tests/runners/node.ts
  • jans-cedarling/bindings/cedarling_js/tests/runners/portable-suites.ts
  • jans-cedarling/bindings/cedarling_js/tests/runners/sandbox-fixtures.ts
  • jans-cedarling/bindings/cedarling_js/tests/runners/tracer-archive.ts
  • jans-cedarling/bindings/cedarling_js/tests/runners/workerd.ts
  • jans-cedarling/bindings/cedarling_js/tests/tsconfig.json
  • jans-cedarling/bindings/cedarling_js/tests/unit/archive-policy.test.ts
  • jans-cedarling/bindings/cedarling_js/tests/unit/authorize-dispatch.test.ts
  • jans-cedarling/bindings/cedarling_js/tests/unit/authorize-multi-issuer.test.ts
  • jans-cedarling/bindings/cedarling_js/tests/unit/authorize-unsigned.test.ts
  • jans-cedarling/bindings/cedarling_js/tests/unit/common-values.test.ts
  • jans-cedarling/bindings/cedarling_js/tests/unit/context.test.ts
  • jans-cedarling/bindings/cedarling_js/tests/unit/edge-initialization.test.ts
  • jans-cedarling/bindings/cedarling_js/tests/unit/engine-boundary.test.ts
  • jans-cedarling/bindings/cedarling_js/tests/unit/engine-fixture.ts
  • jans-cedarling/bindings/cedarling_js/tests/unit/engine-initialization-fixture.ts
  • jans-cedarling/bindings/cedarling_js/tests/unit/errors.test.ts
  • jans-cedarling/bindings/cedarling_js/tests/unit/index.ts
  • jans-cedarling/bindings/cedarling_js/tests/unit/issuers.test.ts
  • jans-cedarling/bindings/cedarling_js/tests/unit/lifecycle.test.ts
  • jans-cedarling/bindings/cedarling_js/tests/unit/loader-policy.test.ts
  • jans-cedarling/bindings/cedarling_js/tests/unit/logs.test.ts
  • jans-cedarling/bindings/cedarling_js/tests/unit/node-initialization.test.ts
  • jans-cedarling/bindings/cedarling_js/tests/unit/options.test.ts
  • jans-cedarling/bindings/cedarling_js/tests/unit/package-entry.test.ts
  • jans-cedarling/bindings/cedarling_js/tests/unit/publishable-manifest.test.ts
  • jans-cedarling/bindings/cedarling_js/tests/unit/url-policy.test.ts
  • jans-cedarling/bindings/cedarling_js/tests/unit/value-inspect.test.ts
  • jans-cedarling/bindings/cedarling_js/tests/unit/wasm-producer-contract.test.ts
  • jans-cedarling/bindings/cedarling_js/tests/unit/web-initialization.test.ts
  • jans-cedarling/bindings/cedarling_js/tests/unit/workerd-initialization.test.ts
  • jans-cedarling/bindings/cedarling_js/tsconfig.build.json
  • jans-cedarling/bindings/cedarling_js/tsconfig.json

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch jans-cedarling-14582

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.

@mo-auto

mo-auto commented Jul 27, 2026

Copy link
Copy Markdown
Member

Snyk checks have passed. No issues have been found so far.

Status Scan Engine Critical High Medium Low Total (0)
Open Source Security 0 0 0 0 0 issues

💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.

@mo-auto mo-auto added area-documentation Documentation needs to change as part of issue or PR comp-docs Touching folder /docs comp-jans-cedarling Touching folder /jans-cedarling kind-feature Issue or PR is a new feature request labels Jul 27, 2026
Signed-off-by: Justin Dah-kenangnon <dah.kenangnon@gmail.com>
Signed-off-by: Justin Dah-kenangnon <dah.kenangnon@gmail.com>
Signed-off-by: Justin Dah-kenangnon <dah.kenangnon@gmail.com>
…mples

Signed-off-by: Justin Dah-kenangnon <dah.kenangnon@gmail.com>
…ples

Signed-off-by: Justin Dah-kenangnon <dah.kenangnon@gmail.com>
@olehbozhok

Copy link
Copy Markdown
Contributor

coderabbit review

Signed-off-by: Justin Dah-kenangnon <dah.kenangnon@gmail.com>

@duttarnab duttarnab left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. There should be a section for build from source under installation:
    https://github.com/JanssenProject/jans/blob/jans-cedarling-14582/jans-cedarling/bindings/cedarling_js/README.md#installation

  2. Why this extra dangerouslyDisableSignatureValidation is required we already have bootstrap properties to control validation checks? Also logging.type is not required.

  3. How addition principal and resource attributes will be added .
    https://github.com/JanssenProject/jans/blob/jans-cedarling-14582/jans-cedarling/bindings/cedarling_js/README.md#clientauthorizeunsignedrequest

  4. How to access complete authz-result json containing diagnostics , reason , errors , 'request_id'.

  5. Describe about the test cases, how to run test cases for unsigned and multi-issuer.

  6. Regarding initialization, define how the other bootstrap properties will be defined in args for initialization.

@Dahkenangnon

Dahkenangnon commented Jul 29, 2026

Copy link
Copy Markdown
Author

Thanks for the review. I’ll update the README to address all five points and clarify how the JavaScript SDK maps to Cedarling’s existing bootstrap configuration.

  1. Build from source: Acknowledged. I’ll add a “Build from source” subsection under Installation, including prerequisites, building cedarling_wasm first, installing dependencies, building the SDK, and running the complete validation suite.

  2. Validation and logging configuration: jwt.dangerouslyDisableSignatureValidation is the typed JavaScript mapping for the existing CEDARLING_JWT_SIG_VALIDATION bootstrap property; it does not introduce another validation mechanism. Signature validation is enabled by default, so I’ll remove the redundant false value from the introductory example.

    Similarly, logging.type maps to CEDARLING_LOG_TYPE. The current mappings are offoff, memorymemory, and consolestd_out; Lock integration is configured separately through the SDK’s lock options. Cedarling’s four underlying logging modes are documented in the [Cedarling logging reference](https://docs.jans.io/nightly/cedarling/reference/cedarling-logs/#cedarling-audit-logs). Logging is optional, so I’ll move it out of the minimal initialization example and explain that memory logging is required only when using client.logs.

  3. Principal and resource attributes: Both principal and resource entities accept an attributes object:

    principal: {
      type: "TaskApp::User",
      id: "alice",
      attributes: {
        role: "editor",
        department: "engineering",
      },
    },
    resource: {
      type: "TaskApp::Task",
      id: "task_101",
      attributes: {
        ownerId: "alice",
        status: "open",
      },
    },

    I’ll add this example and explain that these attributes must conform to the policy-store schema. In multi-issuer authorization, principal attributes are derived from mapped token claims, while resource attributes are supplied in the request.

  4. Complete authorization result: The complete normalized result is available through authResult.value:

    if (authResult.ok) {
      const {
        decision,
        requestId,
        diagnostics: { reasons, errors },
      } = authResult.value;
    }

    The SDK uses JavaScript naming conventions: request_id becomes requestId, reason becomes reasons, and diagnostic { id, error } entries become { policyId, message }. I’ll document this result shape and show how to serialize it with JSON.stringify(authResult.value). The raw WASM response remains internal to preserve the SDK’s stable API boundary.

  5. Unsigned and multi-issuer tests: I’ll describe what the unit and real-WASM contract tests cover and add the focused commands:

    npm run test:unit -- authorize-unsigned
    npm run test:contract -- authorize-unsigned
    
    npm run test:unit -- authorize-multi-issuer
    npm run test:contract -- authorize-multi-issuer
    
    npm run check

    I’ll also clarify that the current multi-issuer contract tests use signed synthetic JWTs but disable external signature and status validation for deterministic offline execution. If end-to-end JWKS signature verification is required, that should be covered by an additional dedicated test.

  6. Initialization and remaining bootstrap properties: Acknowledged. I’ll add a configuration reference showing how the supported bootstrap properties are expressed through createCedarling() arguments, including their defaults and mappings. This will cover applicationName, policyStore, logging, authorization, jwt, contextStore, tokenCache, issuerLoading, http, and lock.

    For example:

    • applicationNameCEDARLING_APPLICATION_NAME
    • logging.*CEDARLING_LOG_*
    • jwt.*CEDARLING_JWT_*
    • authorization.* → schema-validation and decision-log properties
    • contextStore.*CEDARLING_DATA_STORE_*
    • tokenCache.*CEDARLING_TOKEN_CACHE_*
    • issuerLoading.*CEDARLING_TRUSTED_ISSUER_LOADER_*
    • http.*CEDARLING_HTTP_*
    • lock.*CEDARLING_LOCK_*

    The SDK intentionally uses typed JavaScript options instead of accepting unrestricted raw bootstrap objects. I’ll also identify any bootstrap properties that are unsupported or not applicable to WebAssembly runtimes, so consumers know exactly what can be configured during initialization.

@Dahkenangnon

Copy link
Copy Markdown
Author

These above will be implement with the following rules:

  • if really consumer facing, into the cedarling/README.md
  • if maintainer or developer facing, will go into cedarling_js/docs/README.md
    Because the reason of the existence of this sdk is to hide the internal dance of the wasm module while offering javascript native interfaces to the js ecosystem dev.

EX: Building from source will be in docs/, while the fix related to the jwt.dangerouslyDisableSignatureValidation and complete authz results in the root readme.

Does it sounds correct ?

@faisalsiddique4400 faisalsiddique4400 left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Blocking

Signature validation is untested, and the shipped example disables it

Every contract test that runs real WASM authorization disables it:

The rationale (deterministic offline runs) is already acknowledged in the thread. The gap that remains: if a change stopped verifying signatures, no test in this suite would fail.

The demo IdP at common/idp.js:115 already generates an RSA keypair and serves JWKS, so a valid-signature case and a tampered-signature case can both run offline.

The same defect appears at runtime: common/test-config.json:10-11 sets dangerouslyDisableSignatureValidation and dangerouslyDisableStatusValidation for every example, so the demos' "signed" path accepts forged tokens. Tests don't verify, and the shipped example turns verification off — those should be fixed together.

The publish job cannot authenticate

build_cedarling_js runs npm publish at build-packages.yml:750 with no NODE_AUTH_TOKEN, no .npmrc, and no registry-url: on setup-node at :622. The sibling build_cedarling_wasm job sets it at :445.

The job therefore depends entirely on npm OIDC trusted publishing, hence npm@11.9.0 at :629. Trusted publishing must be configured against a package that already exists on npm; @janssenproject/cedarling does not. The first release will fail until someone publishes manually and configures the trusted publisher for this exact workflow and job name.

The PR description states the SDK is published "using the existing npm publishing secret." No secret is referenced in the job — either the description or the implementation needs correcting.

npm ci runs against a swapped-in file: dependency

build-packages.yml:638 runs npm version "${WASM_VERSION}" after the downloaded artifact has replaced cedarling_wasm/pkg, then :687 runs npm ci against the committed lockfile. dependencies pins file:../cedarling_wasm/pkg, and npm validates linked-package versions against the lock, so a version-bumped artifact is likely to produce "package.json and package-lock.json are not in sync."

This passes in test-cedarling.yml only because wasm-pack there builds the unbumped Cargo.toml version. The workflow_dispatch dry run noted under Release path would confirm or rule this out.

Three call sites reject where their siblings do not

These re-throw when the caught error is not a recognized SDK code:

The issuer, context, and log helpers handle the same case by wrapping. See client.ts:302-315, which uses isSdkErrorCode(...) ? error : createSdkError(...).

The doc comment indicates the throw is intentional for unexpected failures. The issue is the asymmetry: authorize, close, and createCedarling can reject while structurally identical methods never do, and the API shape leads callers to check result.ok and stop there. That produces an unhandled rejection in production.

README.md:366 states the SDK "does not throw errors on expected operational failures". Accurate as written, but "expected" is load-bearing and easy to miss. Either wrap consistently or document the rejection path.

authz-middleware.js — unguarded dereference and an ownership fallback

authz-middleware.js:88 reads diagnostics.reasons unguarded, while :72 correctly guards the same value with if (!decision && diagnostics). A deny without diagnostics throws inside the error path.

:13 sets taskOwner = task ? task.owner : userId, so a missing resource defaults ownership to the caller and any owner-based policy allows. With x-user-id defaulting to 'bob' at :10, and signature validation off per the section above, this is the file consumers are most likely to copy. It needs an explicit "intentionally insecure, do not copy" banner at minimum.

Non-blocking

The guard at assert-publishable.mjs:28 checks name === "cedarling_wasm", but the dependency is @janssenproject/cedarling_wasm, so the branch never executes. Returning false would also mark it unsafe, which inverts the apparent intent. Staging rewrites the version first, so nothing breaks today.

With allowedAlgorithms omitted, all twelve algorithms are enabled: prepare.ts:24-36, applied at prepare.ts:503. none is absent, so this is not urgent. Defaulting to symmetric HS* alongside RS/ES/PS is the standard setup for algorithm confusion. Asymmetric by default, with HS* opt-in, would be safer.

prepare.ts:21 defines UINT32_MAX as "the largest integer representable by the generated unsigned 32-bit fields", but five fields bound to Number.MAX_SAFE_INTEGER instead — CEDARLING_DATA_STORE_MAX_TTL and _DEFAULT_TTL at :437-451, CEDARLING_HTTP_MAX_RESPONSE_SIZE_BYTES at :618, and the three CEDARLING_LOCK_*_INTERVAL values. Validation accepts values the WASM boundary will reject or wrap.

httpUrl() at prepare.ts:177 rejects credentials in the URL but accepts plaintext http:. It gates policyStore.url and lock.configurationUrl, the latter alongside CEDARLING_LOCK_SSA_JWT. Requiring https: outside loopback would match the algorithm-default reasoning above.

withAuthorizationShortcuts at client.ts:80 sets denied: false on the error branch, so if (result.denied) reject() fails open while if (!result.allowed) is safe. Since the shortcuts exist to encourage terse call sites, that asymmetry belongs in the type's doc comment.

selectAuthorizationRequest in authorization/dispatch.ts reads type and request and silently ignores unknown envelope fields, while every other boundary in the SDK calls rejectUnknown.

SDK and WASM versions are permanently coupled: build-packages.yml:680 runs npm version "${WASM_VERSION}" and stage-release.mjs:110 pins exactly. A WASM patch therefore forces an SDK republish, and the published cedarling_wasm version stops matching the Rust crate. Confirming this is the intended long-term behaviour would be useful.

query.ts:94 is unreachable. Given the present === 0 check above it and the id !== undefined early return, requestId and tag cannot both be undefined at that point.

stage-release.mjs:120 spreads ...sourceManifest, so all 10 devDependencies (electron, playwright, webpack, workerd) and 24 test:* scripts land in the published package.json. Consumers do not install devDeps, so the effect is cosmetic.

test-config.json declares expectedFailures: ["authorizeMultiIssuer"] described as a "known bug", echoed by a console.log in the demo's init.js. A linked tracking issue would be better than prose in a fixture.

The new cedarling_js_tests job builds the WASM crate and installs Bun, Deno, and three Playwright browsers to run eight runtime suites, with no timeout-minutes and no persist-credentials: false on checkout. The latter is set on the new build-packages.yml job.

Release path

build-packages.yml triggers on workflow_run and workflow_dispatch only, never on pull_request. The 257 lines of publish logic added here (version coordination, manifest staging, tarball verification, npm publish) have not executed. The green checks on this PR come from test-cedarling.yml. A workflow_dispatch dry run against nightly would validate it — and would settle the npm ci and npm-authentication questions above — before anything depends on it.

Note that the new SDK publish at build-packages.yml:750 fails loudly, whereas the existing WASM publish at line 501 continues on error. Since build_cedarling_js depends on that job and then polls npm view for five minutes, a silently failed WASM publish surfaces here as a confusing timeout.

Minor: the new collect-cedarling-js-digests tag step at :1977 interpolates inputs.target_tag and workflow_run.head_branch directly into run:. This matches the existing pattern used by the other collect-* jobs in the file, so it is not a regression, but build_cedarling_js itself uses the safer env: form and the new job could match it.

CodeRabbit skipped this PR ("249 files exceed the limit of 150"). With 29,181 lines of committed lockfiles and an Electron demo carrying its own webpack configs, the PR exceeds the bots' limits. Splitting the SDK from the demos would restore that coverage.

Checked, no findings

Publish security — injection and secret handling: actions are SHA-pinned, harden-runner present, persist-credentials: false, github.repository fork guard, --provenance with OIDC, SLSA provenance job, WASM package name and version asserted before publish. No injection or token-leak paths found. (Authentication is covered separately under Blocking.)

No committed secrets. The demo IdP generates its keypair at runtime with generateKeyPairSync. The Electron demo sets contextIsolation: true, sandbox: true, nodeIntegration: false, and routes external URLs through shell.openExternal.

Error model: errors.ts:229 produces frozen Error objects, strips URL credentials, and gates retained causes through a WeakSet allowlist. One trade-off: every message becomes a fixed generic string, so the underlying Cedar and WASM detail is discarded. This may make production debugging harder than expected; a debug flag preserving detail would address it.

Input validation is the strongest part of the SDK: inspectOwnProperty avoids invoking getters, rejectUnknown catches misspelled options deterministically, and values are snapshotted before crossing the WASM boundary. Lifecycle handling — in-flight accounting, a single memoized close promise, drain-before-shutdown — is careful. scripts/verify-consumer.mjs packs, installs offline into a scratch consumer, asserts the WASM dependency hoists rather than nests, and exercises both ESM and CJS entry points.

Archive bytes are copied during validation at prepare.ts:302, so the factory does not need to copy again. The SDK lockfile is committed so npm ci resolves in CI. The Cargo workspace exclusion is harmless, though bindings/cedarling_js contains no Cargo.toml, so the entry is a no-op.

```ts
import { createCedarling } from "@janssenproject/cedarling";

const result = await createCedarling({

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be better to avoid custom mapping to Bootstrap properties. Any changes in the core library would require corresponding updates in this library, which increases the maintenance burden.

I also like that every binding follows the same approach, with the official documentation serving as the single source of truth. Thanks for all the work you've put into this—it's a significant effort. That said, I think passing the values directly would be a simpler and more maintainable solution.

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

Labels

area-documentation Documentation needs to change as part of issue or PR comp-docs Touching folder /docs comp-jans-cedarling Touching folder /jans-cedarling kind-feature Issue or PR is a new feature request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(cedarling): add a stable JavaScript SDK over the WASM bindings

5 participants