refactor(backend): collapse entitlement provider abstraction back to LicenseService (#889)

Removes backend/src/entitlements/ (registry, loadProvider,
CommunityEntitlementProvider, types, headers, normalize) and the two
abstraction-only tests. Relocates headers/normalize/types to
services/license-*.ts. Swaps 22 consumer call sites from
getEntitlementProvider() to LicenseService.getInstance(). Drops the
Dockerfile install step plus PRO_PACKAGE_VERSION build-arg and
github_token BuildKit secret in docker-publish.yml. Removes the now
stale no-restricted-imports rule in backend/eslint.config.mjs.

Net: 37 files changed, ~700 lines removed, no behavior change. Local
dev no longer requires GitHub Packages auth to start the backend.

Rationale and revisit conditions in
docs/internal/adrs/2026-05-02-collapse-entitlement-provider.md.
This commit is contained in:
Anso
2026-05-02 23:45:44 -04:00
committed by GitHub
parent 6929dad540
commit e5b1c7b22b
39 changed files with 150 additions and 735 deletions
+7 -14
View File
@@ -54,22 +54,15 @@ export async function setupTestDb(): Promise<string> {
// path-traversal or 404 on missing files. Realign here.
db.getDb().prepare('UPDATE nodes SET compose_dir = ? WHERE is_default = 1').run(composeDir);
// Register the in-tree LicenseService as the active EntitlementProvider
// so tier-gated middleware can resolve a provider during the test. In
// Force the LicenseService singleton to materialize on the test DB. In
// production this is wired by `bootstrap/startup.ts`; tests bypass that
// path by importing modules directly, so the registry would otherwise
// throw on first tier check. The mocking pattern many tests use
// (`vi.spyOn(LicenseService.getInstance(), 'getTier')`) continues to
// work because LicenseService.getInstance() and getEntitlementProvider()
// return the same singleton in Phase 1.
//
// The registry binding is module-scope and survives across test files
// within the same Vitest worker. Avoid `vi.resetModules()` in this
// codebase; it would drop the binding and cause subsequent tier
// checks to throw with "EntitlementProvider not initialized."
// path by importing modules directly. Without this prime, the first
// tier check in a test runs `LicenseService.getInstance()` against a
// singleton whose lazy-init never ran. The mocking pattern many tests
// use (`vi.spyOn(LicenseService.getInstance(), 'getTier')`) continues
// to work against the same singleton.
const { LicenseService } = await import('../../services/LicenseService');
const { setEntitlementProvider } = await import('../../entitlements/registry');
setEntitlementProvider(LicenseService.getInstance());
LicenseService.getInstance();
return tmpDir;
}