longcelot-sheet-db
Version:
Google Sheets-backed staging database adapter for Node.js with schema-first design
60 lines • 2.88 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.hasPermission = hasPermission;
exports.resolveNonAdminTenantKey = resolveNonAdminTenantKey;
const PermissionError_1 = require("../errors/PermissionError");
/**
* Cross-actor permission matrix enforcement — extracted verbatim from SheetAdapter's former
* private hasPermission() (Phase 16.3) so a non-Sheets DatabaseAdapter enforces identical
* semantics instead of reimplementing this branching logic.
*/
function hasPermission(schema, context, permissions) {
if (!context)
return false;
if (context.role === 'admin')
return true;
// Same actor accessing their own tables
if (schema.actor === context.role && !context.targetActor)
return true;
// Admin tables: non-admin cannot access unless it's the users table on create
if (schema.actor === 'admin')
return false;
// Cross-actor: check permission matrix
const targetActor = context.targetActor;
if (!targetActor || targetActor === context.role)
return schema.actor === context.role;
if (schema.actor !== targetActor)
return false;
const perm = permissions?.[context.role];
if (!perm) {
throw new PermissionError_1.PermissionError(`'${context.role}' has no cross-actor permissions configured`, context.role);
}
if (!perm.canAccess.includes(targetActor)) {
throw new PermissionError_1.PermissionError(`'${context.role}' cannot access '${targetActor}' sheets`, context.role);
}
if (perm.tables && !perm.tables.includes(schema.name)) {
throw new PermissionError_1.PermissionError(`Table '${schema.name}' is not allowed for '${context.role}' → '${targetActor}' access`, context.role);
}
return true;
}
/**
* Resolves the tenant-scoping key for a non-admin schema — extracted verbatim from
* SheetAdapter's former private resolveSpreadsheetId() minus the admin branch (Phase 16.3).
* Callers handle schema.actor === 'admin' themselves: "admin" means a fixed global store for
* SheetAdapter (adminSheetId) but "no tenant filter at all" for SQL adapters, so there's no
* single generic admin behavior to encode here.
*/
function resolveNonAdminTenantKey(schema, context) {
const isCrossActor = context?.targetActor && context.targetActor !== context?.role;
if (isCrossActor && schema.actor === context?.targetActor) {
if (!context?.targetSheetId) {
throw new PermissionError_1.PermissionError(`targetSheetId required for cross-actor access to '${schema.actor}' tables`, context?.role);
}
return context.targetSheetId;
}
if (context?.actorSheetId) {
return context.actorSheetId;
}
throw new PermissionError_1.PermissionError('Actor sheet ID not provided in context', context?.role);
}
//# sourceMappingURL=accessControl.js.map