Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions .changeset/better-auth-exact-family-pin.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
"@objectstack/plugin-auth": patch
---

`@objectstack/plugin-auth` pins the `better-auth` family to an exact `1.7.2`, so a fresh install of a published `@objectstack/*` release loads the auth plugin again — and with it creates the system tables and seeds the admin.

Published 17.1.0, 17.2.0 and 17.3.0 declared `"@better-auth/core": "^1.7.2"` and imported `createLocalAccountIssuer` / `createOAuthAccountIssuer` from `@better-auth/core/db`. `@better-auth/core@1.7.3` — a **patch** — deleted both names, and the `account.issuer` column behind them, because upstream rolled the issuer-scoped account identity back to opt-in (better-auth/better-auth#10909). A static ESM named import of a missing export is a link-time `SyntaxError`, so the plugin could not load at all. Every symptom followed from that one failure and every one of them was quiet: the scaffolded project's CLI printed the `SyntaxError` as a scrollable oclif warning and carried on, the server printed `✓ Server is ready` on the broken boot, `sys_user` / `sys_organization` / `sys_permission_set` / `sys_position` were never created, the seeded admin sign-in never answered, and the Console's sign-in form answered `Auth request failed with status 404`.

**This is a stopgap, deliberately, and it is labelled as one.** Upstream removed the export on purpose; adopting 1.7.3 means dropping `sys_account.issuer` — a required column with a unique `(issuer, accountId)` index — from the platform object, retiring the boot-time backfill that stamps it, and migrating every existing deployment. That is its own change with its own decision to make; this one restores a working install today.

All five members `plugin-auth` declares move together (`better-auth`, `@better-auth/core`, `@better-auth/oauth-provider`, `@better-auth/scim`, `@better-auth/sso`), because they are only correct as one line: `@better-auth/core@1.7.2` and `@better-auth/kysely-adapter@1.7.3` are mutually incompatible in both directions. `better-auth@1.7.2` declares its own siblings exactly, so pinning those five resolves all twelve family members to 1.7.2 — measured on a fresh `npm install` with no lockfile.

The workspace `overrides` move to the same exact target in step, so the version this repository tests is the version a consumer resolves. In-repo resolutions are unchanged: the lockfile already held 1.7.2 for all eleven overridden members.
18 changes: 18 additions & 0 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2615,6 +2615,24 @@ jobs:
- name: Auth mount-vs-ledger guard
run: pnpm check:auth-mount-ledger

# Vendor export contract (#16186). `@better-auth/core@1.7.3` deleted
# `createLocalAccountIssuer` in a PATCH; plugin-auth imports it statically
# through a caret range, so published 17.1.0-17.3.0 could not load at all
# on a fresh install -- while every job here stayed green, because
# pnpm-lock.yaml held 1.7.2. The lockfile protected the producer from the
# defect it was shipping. This gate asserts that a governed vendor's
# DECLARED range is exact, that the installed version IS that version, and
# that importing it really yields every symbol our shipped source takes
# from it -- so "what CI imported" and "what a consumer resolves" are the
# same string. Cheap and offline: it imports what `pnpm install` already
# put on disk. The network half (`--resolve`, which enumerates every
# registry version the range admits) runs in validate-deps.yml, which
# already installs from the registry. No `paths:` filter: a manifest edit,
# a lockfile refresh and a new vendor import can each move it. Runs its
# own --self-test first.
- name: Vendor export contract
run: pnpm check:vendor-export-contract

# Optional-`error` sink contract (#9754, wired by #10608). A sink TYPE that
# declares `error` as OPTIONAL must also declare `warn` as NON-optional, so
# every value of that type has somewhere to put a durability report —
Expand Down
26 changes: 26 additions & 0 deletions .github/workflows/validate-deps.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ on:
- 'pnpm-workspace.yaml'
- 'scripts/check-changeset-fixed.mjs'
- 'scripts/check-override-consistency.mjs'
# The consumer-resolution half of the same question (#16186) — an edit to
# the gate must be exercised on the PR that makes it.
- 'scripts/check-vendor-export-contract.mjs'
# The OSV exemption ledger and its check: a PR that touches either must
# run this workflow, or an exemption could be added without the gate
# that governs it ever running on the PR that adds it.
Expand Down Expand Up @@ -83,6 +86,29 @@ jobs:
- name: Verify overrides are reflected in published manifests
run: pnpm check:override-consistency

# The half check-override-consistency structurally cannot cover (#16186).
# It asks whether the override TARGET is reachable from the declared
# range; `^1.7.2` and `^1.7.2` agreed perfectly while both floated onto
# `@better-auth/core@1.7.3`, a PATCH that deleted the export plugin-auth
# imports statically. Three published releases could not load on a fresh
# install and nothing here went red, because pnpm-lock.yaml held 1.7.2.
#
# `--resolve` deliberately ignores the lockfile: for every version the
# DECLARED range admits on the registry -- the way a downstream project
# resolves -- it installs that version outside this workspace and checks
# the export surface. It fails if ANY admitted version is missing a symbol
# we import. With the ranges pinned exact that is one small install per
# vendor; under a caret it is one per published version, which is the cost
# of the risk being taken.
#
# It lives HERE rather than in the lint farm because it needs the network,
# which this job already has, and because the daily schedule is what turns
# "a vendor published something today" into a red in this repo instead of
# in a customer's install. An unreachable registry exits 3
# (PREREQUISITE NOT MET), never a green.
- name: Verify the declared ranges cannot resolve past our import surface
run: pnpm check:vendor-export-contract-resolve

# Fail the workflow if known vulnerabilities are found — enforces
# security compliance before merging.
#
Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,8 @@
"check:adr-0087-registration": "node scripts/check-adr-0087-registration.mjs --self-test && node scripts/check-adr-0087-registration.mjs",
"check:changeset-gate-self-tests": "node scripts/check-empty-changeset.mjs --self-test && node scripts/check-adr-0087-registration.mjs --self-test && node scripts/check-changeset-no-major.mjs --self-test",
"check:override-consistency": "node scripts/check-override-consistency.mjs --self-test && node scripts/check-override-consistency.mjs",
"check:vendor-export-contract": "node scripts/check-vendor-export-contract.mjs --self-test && node scripts/check-vendor-export-contract.mjs",
"check:vendor-export-contract-resolve": "node scripts/check-vendor-export-contract.mjs --self-test && node scripts/check-vendor-export-contract.mjs --resolve",
"check:release-notes": "node scripts/check-release-notes.mjs",
"check:release-page-status": "node scripts/check-release-page-status.mjs --self-test && node scripts/check-release-page-status.mjs",
"check:release-body": "node scripts/release-github-releases.mjs --self-test",
Expand Down
10 changes: 5 additions & 5 deletions packages/plugins/plugin-auth/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,18 +26,18 @@
"gen:test-typecheck-debt": "tsx ../../../scripts/check-test-typecheck.mts --update --package packages/plugins/plugin-auth --project tsconfig.test.json"
},
"dependencies": {
"@better-auth/core": "^1.7.2",
"@better-auth/oauth-provider": "^1.7.2",
"@better-auth/scim": "^1.7.2",
"@better-auth/sso": "^1.7.2",
"@better-auth/core": "1.7.2",
"@better-auth/oauth-provider": "1.7.2",
"@better-auth/scim": "1.7.2",
"@better-auth/sso": "1.7.2",
"@noble/hashes": "^2.3.0",
"@objectstack/core": "workspace:*",
"@objectstack/platform-objects": "workspace:*",
"@objectstack/rest": "workspace:*",
"@objectstack/service-messaging": "workspace:*",
"@objectstack/spec": "workspace:*",
"@objectstack/types": "workspace:*",
"better-auth": "^1.7.2",
"better-auth": "1.7.2",
"jose": "^6.2.8"
},
"devDependencies": {
Expand Down
56 changes: 28 additions & 28 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading