Pulp Engine Document Rendering
Get started
Release v0.82.0

Release v0.82.0 — Post-audit follow-ups (security, API contract, editor safety)

This release closes the highest-leverage cluster from the post-hardening quality audit: an OIDC token-replay path that contradicted the security docs, a tenant-isolation guarantee the code did not enforce, a spreadsheet formula-injection gap in CSV/XLSX exports, an inconsistent validation error contract, a deployment footgun around NODE_ENV, and an unconfirmed destructive editor action. It also restores trustworthy review-time and local-dev signals.

Security

  • OIDC id_token is no longer accepted as a raw Authorization: Bearer API credential (SEC-A1). The per-request OIDC provider was removed from the auth chain. Previously a raw id_token presented as a Bearer token authenticated every protected route, bypassing the 5-minute freshness and Origin checks that POST /auth/oidc/exchange enforces and that the OIDC guide documents. Breaking change: SSO integrations must exchange the id_token at /auth/oidc/exchange (browser/embed → short-lived editor token); machine-to-machine callers use scoped API keys (API_KEY_*). The login/callback/complete/exchange/logout flows are unchanged.

  • CSV / XLSX exports neutralize spreadsheet formula injection (SEC-R1). Data-derived cell values that begin with = + - @ (or tab/CR/LF) are prefixed with a literal-text apostrophe so they are not evaluated as formulas when the export is opened in Excel/LibreOffice/Sheets. Applies to table and pivot-table CSV/XLSX, including pivot row-dimension values, column keys, and subtotal labels. Numeric values (e.g. negative numbers, currency formatted from a number) are never altered, and author-defined column/measure labels are unaffected.

  • ALLOW_NO_AUTH backstop closes the NODE_ENV footgun (SEC-A3). Credential and hardening enforcement previously keyed entirely off NODE_ENV (default development), so a bare node dist that forgot NODE_ENV=production would run with authentication silently disabled. Now, when authentication resolves to fully disabled (no API_KEY_* and no named-user registry), the server refuses to boot unless ALLOW_NO_AUTH=true is set explicitly — independent of NODE_ENV. The boot error leads with the real remedies (configure a credential or a named-user registry); ALLOW_NO_AUTH=true is documented as a development/testing-only opt-out and emits an unmissable startup banner. The NODE_ENV=test path is exempt so the test suite is unaffected.

API

  • Unified validation error contract (API-1/API-2). RenderValidationError (render data fails the template inputSchema) is now serialized identically on every route — the canonical { error: "Validation Failed", code: "validation_failed", issues: [...], requestId } envelope from the global error handler. Previously the production DOCX/PPTX routes emitted a divergent { error: "ValidationError", message } shape and every /render/preview/* route emitted a RenderError envelope for the same failure. All preview 422 responses now declare the same RenderError | ValidationError union as production, so generated SDKs and /docs/json see one consistent contract.

Editor

  • “Restore to this version” now asks for confirmation (UX-2). Restoring is an irreversible live-template mutation (the render API and any labels pointing at the live version immediately serve the restored content). Both entry points — the version-list row and the compare-view footer — now open a confirmation dialog naming the target version before the restore runs.

Operability & CI

  • test-file-mode now runs on pull requests (OPS-2/EV-1). The file-mode integration suite needs no service container, Playwright, or Docker, so it is now a required-on-PR smoke alongside the core ci job. The heavier matrix (Docker build+smoke, SQL Server, e2e, Windows) remains gated to push/release to conserve Actions minutes.
  • Explicit pnpm typecheck step on the core CI job (EV-5). The PR gate now runs a repo-wide typecheck, matching the workflow’s self-description.
  • Release workflows retroactively strip stale -latest aliases (REL-1). When a release becomes latest, release.yml and release-mirror.yml now sweep every superseded release and delete its PulpEngine-Setup-latest.exe / pulp-engine-eval-latest.tar.gz aliases, so exactly one release ever serves the -latest download URLs the website links to. Previously the per-tag cleanup only fired on a rerun of the same tag, so old releases kept serving outdated “latest” builds — an evaluator pulling …/releases/download/<old-tag>/pulp-engine-eval-latest.tar.gz would get a stale bundle. A one-time backfill removed the pre-existing aliases from all prior releases on both the private repo and the public mirror.

Documentation

  • Tenant-isolation guarantees corrected (SEC-A2). The doc previously claimed filesystem asset binaries were “rejected at startup” under multi-tenant mode. In fact they are tenant-path-prefixed ({tenantId}/…) and work; the doc now says so, recommends ASSET_BINARY_STORE=s3 for multi-instance/HA and storage-enforced isolation, and a non-fatal startup advisory is logged for the filesystem + multi-tenant combination. (The STORAGE_MODE=file backend is still rejected under MULTI_TENANT_ENABLED=true.)
  • OIDC and API guides updated for the v0.81.0 DB-backed editor registry (DOC-1/DOC-2). The OIDC guide and the API guide’s named-user section now describe DB-backed persistence (EDITOR_USERS_DB, the editor_users table) for postgres/sqlserver mode instead of only the file path, and the OIDC guide documents that raw id_token Bearer is not accepted (see SEC-A1).
  • ALLOW_NO_AUTH added to the deployment-guide environment reference; the editor guide notes the restore confirmation step.

Upgrade notes

  • If any integration authenticated to the API by sending an OIDC id_token as Authorization: Bearer, switch it to POST /auth/oidc/exchange (then use the returned editor token) or to a scoped API key. No first-party client used the direct path.
  • If you run the published artifact directly (not via the Docker image) without NODE_ENV=production and without any credentials, set a credential / named-user registry (recommended) or ALLOW_NO_AUTH=true for local development.