fix(erp-export): strict seit format, DB clock for settle window, movement index, one scope per key
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
This commit is contained in:
1 parent
53fab102f2
commit
25d95b0473
19 files changed
+426
-57
No files matched your search
@@ -322,6 +322,28 @@ describe('ApiKeysService.create', () => {
|
||||
expect(prisma.apiKey.create).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('refuses a new key with more than one scope, even if all of them read', async () => {
|
||||
await expect(
|
||||
service.create(
|
||||
{ name: 'Alles', scopes: ['shop-sync:read', 'erp-inventory:read'] },
|
||||
'user-1',
|
||||
),
|
||||
).rejects.toThrow(
|
||||
new BadRequestException(
|
||||
'Je Schlüssel nur eine Berechtigung - bitte getrennte Schlüssel anlegen',
|
||||
),
|
||||
);
|
||||
expect(prisma.apiKey.create).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('treats the same scope given twice as one', async () => {
|
||||
const created = await service.create(
|
||||
{ name: 'ERPNext', scopes: ['erp-inventory:read', 'erp-inventory:read'] },
|
||||
'user-1',
|
||||
);
|
||||
expect(created.apiKey.scopes).toEqual(['erp-inventory:read']);
|
||||
});
|
||||
|
||||
it.each(['shop-sync:read', 'shop-sync:write', 'erp-inventory:read'])(
|
||||
'still creates a key with only %s',
|
||||
async (scope) => {
|
||||
|
||||
@@ -104,14 +104,19 @@ export class ApiKeysService {
|
||||
dto: CreateApiKeyDto,
|
||||
actingUserId: string,
|
||||
): Promise<CreatedApiKey> {
|
||||
// Reading and booking are separate keys: a leaked read key cannot book,
|
||||
// a leaked booking key cannot read. Existing combined keys stay valid.
|
||||
// erp-inventory:read is a read scope too.
|
||||
// One scope per new key: a leaked read key cannot book, a leaked booking
|
||||
// key cannot read, and each connected system gets its own key.
|
||||
// Existing multi-scope keys stay valid (ARCHITECTURE.md, Annahme 14).
|
||||
if (combinesReadAndWrite(dto.scopes)) {
|
||||
throw new BadRequestException(
|
||||
'Lese- und Buchungsrecht bitte als getrennte Schlüssel anlegen',
|
||||
);
|
||||
}
|
||||
if (new Set(dto.scopes).size > 1) {
|
||||
throw new BadRequestException(
|
||||
'Je Schlüssel nur eine Berechtigung - bitte getrennte Schlüssel anlegen',
|
||||
);
|
||||
}
|
||||
// Nobody hands a machine more than they may do themselves.
|
||||
const callerPermissions =
|
||||
await this.permissionResolver.getPermissions(actingUserId);
|
||||
|
||||
Reference in new issue
Block a user