| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476 |
- import { DefaultLogger, LogLevel, mergeConfig, Permission } from '@vendure/core';
- import { createTestEnvironment, type SimpleGraphQLClient } from '@vendure/testing';
- import { graphql } from 'gql.tada';
- import path from 'node:path';
- import { afterAll, beforeAll, describe, expect, it } from 'vitest';
- import { initialData } from '../../../e2e-common/e2e-initial-data';
- import { TEST_SETUP_TIMEOUT_MS, testConfig } from '../../../e2e-common/test-config';
- import {
- dashboardSavedViewsPermission,
- SettingsStoreRwPermissionsPlugin,
- } from './fixtures/test-plugins/settings-store-rw-permissions-plugin';
- import { createAdministratorDocument, createRoleDocument } from './graphql/shared-definitions';
- const getSettingsStoreValueDocument = graphql(`
- query GetSettingsStoreValue($key: String!) {
- getSettingsStoreValue(key: $key)
- }
- `);
- const setSettingsStoreValueDocument = graphql(`
- mutation SetSettingsStoreValue($input: SettingsStoreInput!) {
- setSettingsStoreValue(input: $input) {
- key
- result
- error
- }
- }
- `);
- describe('Settings Store Read/Write Permissions', () => {
- const { server, adminClient } = createTestEnvironment(
- mergeConfig(testConfig(), {
- logger: new DefaultLogger({ level: LogLevel.Warn }),
- plugins: [SettingsStoreRwPermissionsPlugin],
- }),
- );
- let admins: Awaited<ReturnType<typeof setupTestAdmins>>;
- beforeAll(async () => {
- await server.init({
- initialData,
- productsCsvPath: path.join(__dirname, 'fixtures/e2e-products-minimal.csv'),
- customerCount: 1,
- });
- await adminClient.asSuperAdmin();
- admins = await setupTestAdmins(adminClient);
- // Set up initial test data as super admin
- await adminClient.asSuperAdmin();
- await adminClient.query(setSettingsStoreValueDocument, {
- input: { key: 'rwtest.separateReadWrite', value: 'initial-separate-value' },
- });
- await adminClient.query(setSettingsStoreValueDocument, {
- input: { key: 'rwtest.dashboardSavedViews', value: { viewName: 'Test View', filters: [] } },
- });
- await adminClient.query(setSettingsStoreValueDocument, {
- input: { key: 'rwtest.multipleReadPermissions', value: 'multi-read-value' },
- });
- await adminClient.query(setSettingsStoreValueDocument, {
- input: { key: 'rwtest.backwardCompatible', value: 'backward-compatible-value' },
- });
- await adminClient.query(setSettingsStoreValueDocument, {
- input: { key: 'rwtest.publicRead', value: 'public-read-value' },
- });
- }, TEST_SETUP_TIMEOUT_MS);
- afterAll(async () => {
- await server.destroy();
- });
- describe('Separate read/write permissions (object syntax)', () => {
- it('user with read permission can read but not write', async () => {
- await adminClient.asUserWithCredentials(admins.readCatalogAdmin.emailAddress, 'test');
- // Should be able to read
- const { getSettingsStoreValue } = await adminClient.query(getSettingsStoreValueDocument, {
- key: 'rwtest.separateReadWrite',
- });
- expect(getSettingsStoreValue).toBe('initial-separate-value');
- // Should not be able to write
- const { setSettingsStoreValue } = await adminClient.query(setSettingsStoreValueDocument, {
- input: {
- key: 'rwtest.separateReadWrite',
- value: 'test-value',
- },
- });
- expect(setSettingsStoreValue.result).toBe(false);
- expect(setSettingsStoreValue.error).toContain('permissions');
- });
- it('user with write permission can write but not read', async () => {
- await adminClient.asUserWithCredentials(admins.updateCatalogAdmin.emailAddress, 'test');
- // Should not be able to read
- const { getSettingsStoreValue } = await adminClient.query(getSettingsStoreValueDocument, {
- key: 'rwtest.separateReadWrite',
- });
- expect(getSettingsStoreValue).toBeNull();
- // Should be able to write
- const { setSettingsStoreValue } = await adminClient.query(setSettingsStoreValueDocument, {
- input: {
- key: 'rwtest.separateReadWrite',
- value: 'write-only-value',
- },
- });
- expect(setSettingsStoreValue.result).toBe(true);
- expect(setSettingsStoreValue.error).toBeNull();
- });
- it('user with both permissions can read and write', async () => {
- await adminClient.asUserWithCredentials(admins.readWriteCatalogAdmin.emailAddress, 'test');
- // Should be able to write
- const { setSettingsStoreValue } = await adminClient.query(setSettingsStoreValueDocument, {
- input: {
- key: 'rwtest.separateReadWrite',
- value: 'read-write-value',
- },
- });
- expect(setSettingsStoreValue.result).toBe(true);
- // Should be able to read
- const { getSettingsStoreValue } = await adminClient.query(getSettingsStoreValueDocument, {
- key: 'rwtest.separateReadWrite',
- });
- expect(getSettingsStoreValue).toBe('read-write-value');
- });
- });
- describe('Custom RwPermissionDefinition', () => {
- it('user with custom read permission can only read', async () => {
- await adminClient.asUserWithCredentials(admins.customReadAdmin.emailAddress, 'test');
- // Should be able to read
- const { getSettingsStoreValue } = await adminClient.query(getSettingsStoreValueDocument, {
- key: 'rwtest.dashboardSavedViews',
- });
- expect(getSettingsStoreValue).toEqual({ viewName: 'Test View', filters: [] });
- // Should not be able to write
- const { setSettingsStoreValue } = await adminClient.query(setSettingsStoreValueDocument, {
- input: {
- key: 'rwtest.dashboardSavedViews',
- value: { viewName: 'Modified View', filters: [] },
- },
- });
- expect(setSettingsStoreValue.result).toBe(false);
- expect(setSettingsStoreValue.error).toContain('permissions');
- });
- it('user with custom write permission can only write', async () => {
- await adminClient.asUserWithCredentials(admins.customWriteAdmin.emailAddress, 'test');
- // Should not be able to read
- const { getSettingsStoreValue } = await adminClient.query(getSettingsStoreValueDocument, {
- key: 'rwtest.dashboardSavedViews',
- });
- expect(getSettingsStoreValue).toBeNull();
- // Should be able to write
- const { setSettingsStoreValue } = await adminClient.query(setSettingsStoreValueDocument, {
- input: {
- key: 'rwtest.dashboardSavedViews',
- value: { viewName: 'Write-Only View', filters: [] },
- },
- });
- expect(setSettingsStoreValue.result).toBe(true);
- });
- it('user with both custom permissions can read and write', async () => {
- await adminClient.asUserWithCredentials(admins.customReadWriteAdmin.emailAddress, 'test');
- // Should be able to write
- const { setSettingsStoreValue } = await adminClient.query(setSettingsStoreValueDocument, {
- input: {
- key: 'rwtest.dashboardSavedViews',
- value: { viewName: 'Custom RW View', filters: ['filter1'] },
- },
- });
- expect(setSettingsStoreValue.result).toBe(true);
- // Should be able to read
- const { getSettingsStoreValue } = await adminClient.query(getSettingsStoreValueDocument, {
- key: 'rwtest.dashboardSavedViews',
- });
- expect(getSettingsStoreValue).toEqual({ viewName: 'Custom RW View', filters: ['filter1'] });
- });
- it('user without custom permissions cannot access', async () => {
- await adminClient.asUserWithCredentials(admins.authenticatedOnlyAdmin.emailAddress, 'test');
- // Should not be able to read
- const { getSettingsStoreValue } = await adminClient.query(getSettingsStoreValueDocument, {
- key: 'rwtest.dashboardSavedViews',
- });
- expect(getSettingsStoreValue).toBeNull();
- // Should not be able to write
- const { setSettingsStoreValue } = await adminClient.query(setSettingsStoreValueDocument, {
- input: {
- key: 'rwtest.dashboardSavedViews',
- value: { viewName: 'Unauthorized View', filters: [] },
- },
- });
- expect(setSettingsStoreValue.result).toBe(false);
- expect(setSettingsStoreValue.error).toContain('permissions');
- });
- it('demonstrates that RwPermissionDefinition generates correct permission names', () => {
- // This test documents how to use the new RwPermissionDefinition
- expect(dashboardSavedViewsPermission.Read).toBe('ReadDashboardSavedViews');
- expect(dashboardSavedViewsPermission.Write).toBe('WriteDashboardSavedViews');
- });
- });
- describe('Multiple read permissions (OR logic)', () => {
- it('user with one of the read permissions can read', async () => {
- await adminClient.asUserWithCredentials(admins.readSettingsAdmin.emailAddress, 'test');
- // Can read with ReadSettings permission (one of the allowed)
- const { getSettingsStoreValue } = await adminClient.query(getSettingsStoreValueDocument, {
- key: 'rwtest.multipleReadPermissions',
- });
- expect(getSettingsStoreValue).toBe('multi-read-value');
- // Cannot write (needs UpdateSettings)
- const { setSettingsStoreValue } = await adminClient.query(setSettingsStoreValueDocument, {
- input: {
- key: 'rwtest.multipleReadPermissions',
- value: 'unauthorized-write',
- },
- });
- expect(setSettingsStoreValue.result).toBe(false);
- expect(setSettingsStoreValue.error).toContain('permissions');
- });
- it('user with the other read permission can also read', async () => {
- await adminClient.asUserWithCredentials(admins.readCatalogAdmin.emailAddress, 'test');
- // Can read with ReadCatalog permission (the other allowed)
- const { getSettingsStoreValue } = await adminClient.query(getSettingsStoreValueDocument, {
- key: 'rwtest.multipleReadPermissions',
- });
- expect(getSettingsStoreValue).toBe('multi-read-value');
- });
- it('user with write permission can write', async () => {
- await adminClient.asUserWithCredentials(admins.updateSettingsAdmin.emailAddress, 'test');
- // Should not be able to read (doesn't have ReadCatalog or ReadSettings)
- const { getSettingsStoreValue } = await adminClient.query(getSettingsStoreValueDocument, {
- key: 'rwtest.multipleReadPermissions',
- });
- expect(getSettingsStoreValue).toBeNull();
- // Should be able to write
- const { setSettingsStoreValue } = await adminClient.query(setSettingsStoreValueDocument, {
- input: {
- key: 'rwtest.multipleReadPermissions',
- value: 'write-authorized-value',
- },
- });
- expect(setSettingsStoreValue.result).toBe(true);
- });
- });
- describe('Backward compatibility', () => {
- it('user without required permission cannot read or write', async () => {
- await adminClient.asUserWithCredentials(admins.readCatalogAdmin.emailAddress, 'test');
- // Cannot read (needs UpdateSettings)
- const { getSettingsStoreValue } = await adminClient.query(getSettingsStoreValueDocument, {
- key: 'rwtest.backwardCompatible',
- });
- expect(getSettingsStoreValue).toBeNull();
- // Cannot write (needs UpdateSettings)
- const { setSettingsStoreValue } = await adminClient.query(setSettingsStoreValueDocument, {
- input: {
- key: 'rwtest.backwardCompatible',
- value: 'unauthorized-value',
- },
- });
- expect(setSettingsStoreValue.result).toBe(false);
- expect(setSettingsStoreValue.error).toContain('permissions');
- });
- it('user with required permission can read and write', async () => {
- await adminClient.asUserWithCredentials(admins.updateSettingsAdmin.emailAddress, 'test');
- // Should be able to read
- const { getSettingsStoreValue } = await adminClient.query(getSettingsStoreValueDocument, {
- key: 'rwtest.backwardCompatible',
- });
- expect(getSettingsStoreValue).toBe('backward-compatible-value');
- // Should be able to write
- const { setSettingsStoreValue } = await adminClient.query(setSettingsStoreValueDocument, {
- input: {
- key: 'rwtest.backwardCompatible',
- value: 'authorized-backward-value',
- },
- });
- expect(setSettingsStoreValue.result).toBe(true);
- });
- });
- describe('Public read with restricted write', () => {
- it('authenticated user can read but not write', async () => {
- await adminClient.asUserWithCredentials(admins.authenticatedOnlyAdmin.emailAddress, 'test');
- // Should be able to read (only requires Authenticated)
- const { getSettingsStoreValue } = await adminClient.query(getSettingsStoreValueDocument, {
- key: 'rwtest.publicRead',
- });
- expect(getSettingsStoreValue).toBe('public-read-value');
- // Should not be able to write (requires CreateAdministrator)
- const { setSettingsStoreValue } = await adminClient.query(setSettingsStoreValueDocument, {
- input: {
- key: 'rwtest.publicRead',
- value: 'unauthorized-public-write',
- },
- });
- expect(setSettingsStoreValue.result).toBe(false);
- expect(setSettingsStoreValue.error).toContain('permissions');
- });
- it('super admin can write', async () => {
- await adminClient.asSuperAdmin();
- // Should be able to write
- const { setSettingsStoreValue } = await adminClient.query(setSettingsStoreValueDocument, {
- input: {
- key: 'rwtest.publicRead',
- value: 'super-admin-write-value',
- },
- });
- expect(setSettingsStoreValue.result).toBe(true);
- });
- });
- describe('Read-only fields with permissions', () => {
- it('read-only field prevents writes even with correct permissions', async () => {
- await adminClient.asUserWithCredentials(admins.readSettingsAdmin.emailAddress, 'test');
- // Should be able to read
- const { getSettingsStoreValue } = await adminClient.query(getSettingsStoreValueDocument, {
- key: 'rwtest.readOnlyAccess',
- });
- expect(getSettingsStoreValue).toBeNull(); // No initial value set for this field
- // Should fail to write because field is readonly
- const { setSettingsStoreValue } = await adminClient.query(setSettingsStoreValueDocument, {
- input: {
- key: 'rwtest.readOnlyAccess',
- value: 'readonly-attempt',
- },
- });
- expect(setSettingsStoreValue.result).toBe(false);
- expect(setSettingsStoreValue.error).toContain('readonly');
- });
- it('user without read permission cannot read readonly field', async () => {
- await adminClient.asUserWithCredentials(admins.authenticatedOnlyAdmin.emailAddress, 'test');
- // Should not be able to read (needs ReadSettings)
- const { getSettingsStoreValue } = await adminClient.query(getSettingsStoreValueDocument, {
- key: 'rwtest.readOnlyAccess',
- });
- expect(getSettingsStoreValue).toBeNull();
- });
- });
- });
- async function createAdminWithPermissions(input: {
- adminClient: SimpleGraphQLClient;
- name: string;
- permissions: Array<Permission | string>;
- }) {
- const { adminClient, name, permissions } = input;
- // All permissions are standard - use the typed mutation
- const { createRole } = await adminClient.query(createRoleDocument, {
- input: {
- code: name,
- description: name,
- permissions: permissions as Permission[],
- },
- });
- const { createAdministrator } = await adminClient.query(createAdministratorDocument, {
- input: {
- firstName: name,
- lastName: 'LastName',
- emailAddress: `${name}@test.com`,
- roleIds: [createRole.id],
- password: 'test',
- },
- });
- return createAdministrator;
- }
- async function setupTestAdmins(adminClient: SimpleGraphQLClient) {
- const readCatalogAdmin = await createAdminWithPermissions({
- adminClient,
- name: 'ReadCatalog',
- permissions: [Permission.ReadCatalog],
- });
- const updateCatalogAdmin = await createAdminWithPermissions({
- adminClient,
- name: 'UpdateCatalog',
- permissions: [Permission.UpdateCatalog],
- });
- const readWriteCatalogAdmin = await createAdminWithPermissions({
- adminClient,
- name: 'ReadWriteCatalog',
- permissions: [Permission.ReadCatalog, Permission.UpdateCatalog],
- });
- const customReadAdmin = await createAdminWithPermissions({
- adminClient,
- name: 'CustomRead',
- permissions: ['ReadDashboardSavedViews'],
- });
- const customWriteAdmin = await createAdminWithPermissions({
- adminClient,
- name: 'CustomWrite',
- permissions: ['WriteDashboardSavedViews'],
- });
- const customReadWriteAdmin = await createAdminWithPermissions({
- adminClient,
- name: 'CustomReadWrite',
- permissions: ['ReadDashboardSavedViews', 'WriteDashboardSavedViews'],
- });
- const readSettingsAdmin = await createAdminWithPermissions({
- adminClient,
- name: 'ReadSettings',
- permissions: [Permission.ReadSettings],
- });
- const updateSettingsAdmin = await createAdminWithPermissions({
- adminClient,
- name: 'UpdateSettings',
- permissions: [Permission.UpdateSettings],
- });
- const authenticatedOnlyAdmin = await createAdminWithPermissions({
- adminClient,
- name: 'AuthenticatedOnly',
- permissions: [Permission.Authenticated],
- });
- return {
- readCatalogAdmin,
- updateCatalogAdmin,
- readWriteCatalogAdmin,
- customReadAdmin,
- customWriteAdmin,
- customReadWriteAdmin,
- readSettingsAdmin,
- updateSettingsAdmin,
- authenticatedOnlyAdmin,
- };
- }
|