From b1a04033115a2bb73d61e9f6a68bfff65f9b70d9 Mon Sep 17 00:00:00 2001 From: Flatlogic Bot Date: Fri, 10 Apr 2026 01:31:18 +0000 Subject: [PATCH] Autosave: 20260410-013118 --- backend/src/config.js | 12 +- backend/src/db/api/access_review_items.js | 19 +- backend/src/db/api/access_reviews.js | 19 +- backend/src/db/api/artifact_type_catalog.js | 19 +- backend/src/db/api/artifacts.js | 19 +- backend/src/db/api/audit_logs.js | 19 +- backend/src/db/api/connected_systems.js | 19 +- backend/src/db/api/control_frameworks.js | 19 +- backend/src/db/api/control_requirements.js | 19 +- backend/src/db/api/evidence_models.js | 19 +- backend/src/db/api/exceptions.js | 19 +- backend/src/db/api/identity_workflows.js | 19 +- backend/src/db/api/notifications.js | 19 +- backend/src/db/api/organization_settings.js | 19 +- backend/src/db/api/organizations.js | 19 +- backend/src/db/api/proof_packets.js | 19 +- backend/src/db/api/remediation_items.js | 19 +- backend/src/db/api/sampled_subjects.js | 19 +- backend/src/db/api/tenantAccess.js | 121 +++++ backend/src/db/api/user_invitations.js | 19 +- backend/src/db/api/users.js | 19 +- backend/src/db/api/workflow_templates.js | 19 +- .../20260410120000-role-model-alignment.js | 442 ++++++++++++++++++ backend/src/routes/access_review_items.js | 8 +- backend/src/routes/access_reviews.js | 8 +- backend/src/routes/artifact_type_catalog.js | 8 +- backend/src/routes/artifacts.js | 8 +- backend/src/routes/audit_logs.js | 8 +- backend/src/routes/connected_systems.js | 8 +- backend/src/routes/control_frameworks.js | 8 +- backend/src/routes/control_requirements.js | 8 +- backend/src/routes/evidence_models.js | 8 +- backend/src/routes/exceptions.js | 8 +- backend/src/routes/identity_workflows.js | 8 +- backend/src/routes/notifications.js | 8 +- backend/src/routes/organization_settings.js | 8 +- backend/src/routes/organizations.js | 8 +- backend/src/routes/proof_packets.js | 8 +- backend/src/routes/remediation_items.js | 8 +- backend/src/routes/sampled_subjects.js | 8 +- backend/src/routes/user_invitations.js | 8 +- backend/src/routes/users.js | 12 +- backend/src/routes/workflow_templates.js | 8 +- backend/src/services/access_review_items.js | 7 +- backend/src/services/access_reviews.js | 7 +- backend/src/services/artifact_type_catalog.js | 7 +- backend/src/services/artifacts.js | 7 +- backend/src/services/audit_logs.js | 7 +- backend/src/services/connected_systems.js | 7 +- backend/src/services/control_frameworks.js | 7 +- backend/src/services/control_requirements.js | 7 +- backend/src/services/evidence_models.js | 7 +- backend/src/services/exceptions.js | 7 +- backend/src/services/identity_workflows.js | 7 +- backend/src/services/notifications.js | 7 +- backend/src/services/organization_settings.js | 7 +- backend/src/services/organizations.js | 7 +- backend/src/services/proof_packets.js | 7 +- backend/src/services/remediation_items.js | 7 +- backend/src/services/sampled_subjects.js | 7 +- backend/src/services/user_invitations.js | 7 +- backend/src/services/users.js | 7 +- backend/src/services/workflow_templates.js | 7 +- 63 files changed, 848 insertions(+), 411 deletions(-) create mode 100644 backend/src/db/api/tenantAccess.js create mode 100644 backend/src/db/seeders/20260410120000-role-model-alignment.js diff --git a/backend/src/config.js b/backend/src/config.js index b5fd0a3..bf75ee9 100644 --- a/backend/src/config.js +++ b/backend/src/config.js @@ -51,15 +51,9 @@ const config = { } }, roles: { - - super_admin: 'Super Administrator', - - admin: 'Administrator', - - - - user: 'audit_viewer', - + super_admin: 'super_admin', + admin: 'org_admin', + user: 'read_only_client', }, project_uuid: '5d25cc2f-a5bf-478e-a796-9053fc72e5d9', diff --git a/backend/src/db/api/access_review_items.js b/backend/src/db/api/access_review_items.js index 7f283d2..030eee4 100644 --- a/backend/src/db/api/access_review_items.js +++ b/backend/src/db/api/access_review_items.js @@ -3,6 +3,7 @@ const db = require('../models'); const FileDBApi = require('./file'); const crypto = require('crypto'); const Utils = require('../utils'); +const TenantAccess = require('./tenantAccess'); @@ -166,7 +167,7 @@ module.exports = class Access_review_itemsDBApi { const transaction = (options && options.transaction) || undefined; const globalAccess = currentUser.app_role?.globalAccess; - const access_review_items = await db.access_review_items.findByPk(id, {}, {transaction}); + const access_review_items = await TenantAccess.findByPkOrThrow(db.access_review_items, id, options); @@ -237,14 +238,7 @@ module.exports = class Access_review_itemsDBApi { const currentUser = (options && options.currentUser) || { id: null }; const transaction = (options && options.transaction) || undefined; - const access_review_items = await db.access_review_items.findAll({ - where: { - id: { - [Op.in]: ids, - }, - }, - transaction, - }); + const access_review_items = await TenantAccess.findAllByIds(db.access_review_items, ids, options); await db.sequelize.transaction(async (transaction) => { for (const record of access_review_items) { @@ -266,7 +260,7 @@ module.exports = class Access_review_itemsDBApi { const currentUser = (options && options.currentUser) || {id: null}; const transaction = (options && options.transaction) || undefined; - const access_review_items = await db.access_review_items.findByPk(id, options); + const access_review_items = await TenantAccess.findByPkOrThrow(db.access_review_items, id, options); await access_review_items.update({ deletedBy: currentUser.id @@ -284,10 +278,7 @@ module.exports = class Access_review_itemsDBApi { static async findBy(where, options) { const transaction = (options && options.transaction) || undefined; - const access_review_items = await db.access_review_items.findOne( - { where }, - { transaction }, - ); + const access_review_items = await TenantAccess.findOne(db.access_review_items, where, options); if (!access_review_items) { return access_review_items; diff --git a/backend/src/db/api/access_reviews.js b/backend/src/db/api/access_reviews.js index 2605248..4ad1686 100644 --- a/backend/src/db/api/access_reviews.js +++ b/backend/src/db/api/access_reviews.js @@ -3,6 +3,7 @@ const db = require('../models'); const FileDBApi = require('./file'); const crypto = require('crypto'); const Utils = require('../utils'); +const TenantAccess = require('./tenantAccess'); @@ -154,7 +155,7 @@ module.exports = class Access_reviewsDBApi { const transaction = (options && options.transaction) || undefined; const globalAccess = currentUser.app_role?.globalAccess; - const access_reviews = await db.access_reviews.findByPk(id, {}, {transaction}); + const access_reviews = await TenantAccess.findByPkOrThrow(db.access_reviews, id, options); @@ -222,14 +223,7 @@ module.exports = class Access_reviewsDBApi { const currentUser = (options && options.currentUser) || { id: null }; const transaction = (options && options.transaction) || undefined; - const access_reviews = await db.access_reviews.findAll({ - where: { - id: { - [Op.in]: ids, - }, - }, - transaction, - }); + const access_reviews = await TenantAccess.findAllByIds(db.access_reviews, ids, options); await db.sequelize.transaction(async (transaction) => { for (const record of access_reviews) { @@ -251,7 +245,7 @@ module.exports = class Access_reviewsDBApi { const currentUser = (options && options.currentUser) || {id: null}; const transaction = (options && options.transaction) || undefined; - const access_reviews = await db.access_reviews.findByPk(id, options); + const access_reviews = await TenantAccess.findByPkOrThrow(db.access_reviews, id, options); await access_reviews.update({ deletedBy: currentUser.id @@ -269,10 +263,7 @@ module.exports = class Access_reviewsDBApi { static async findBy(where, options) { const transaction = (options && options.transaction) || undefined; - const access_reviews = await db.access_reviews.findOne( - { where }, - { transaction }, - ); + const access_reviews = await TenantAccess.findOne(db.access_reviews, where, options); if (!access_reviews) { return access_reviews; diff --git a/backend/src/db/api/artifact_type_catalog.js b/backend/src/db/api/artifact_type_catalog.js index ffd92a1..f9fc88a 100644 --- a/backend/src/db/api/artifact_type_catalog.js +++ b/backend/src/db/api/artifact_type_catalog.js @@ -3,6 +3,7 @@ const db = require('../models'); const FileDBApi = require('./file'); const crypto = require('crypto'); const Utils = require('../utils'); +const TenantAccess = require('./tenantAccess'); @@ -102,7 +103,7 @@ module.exports = class Artifact_type_catalogDBApi { const transaction = (options && options.transaction) || undefined; const globalAccess = currentUser.app_role?.globalAccess; - const artifact_type_catalog = await db.artifact_type_catalog.findByPk(id, {}, {transaction}); + const artifact_type_catalog = await TenantAccess.findByPkOrThrow(db.artifact_type_catalog, id, options); @@ -146,14 +147,7 @@ module.exports = class Artifact_type_catalogDBApi { const currentUser = (options && options.currentUser) || { id: null }; const transaction = (options && options.transaction) || undefined; - const artifact_type_catalog = await db.artifact_type_catalog.findAll({ - where: { - id: { - [Op.in]: ids, - }, - }, - transaction, - }); + const artifact_type_catalog = await TenantAccess.findAllByIds(db.artifact_type_catalog, ids, options); await db.sequelize.transaction(async (transaction) => { for (const record of artifact_type_catalog) { @@ -175,7 +169,7 @@ module.exports = class Artifact_type_catalogDBApi { const currentUser = (options && options.currentUser) || {id: null}; const transaction = (options && options.transaction) || undefined; - const artifact_type_catalog = await db.artifact_type_catalog.findByPk(id, options); + const artifact_type_catalog = await TenantAccess.findByPkOrThrow(db.artifact_type_catalog, id, options); await artifact_type_catalog.update({ deletedBy: currentUser.id @@ -193,10 +187,7 @@ module.exports = class Artifact_type_catalogDBApi { static async findBy(where, options) { const transaction = (options && options.transaction) || undefined; - const artifact_type_catalog = await db.artifact_type_catalog.findOne( - { where }, - { transaction }, - ); + const artifact_type_catalog = await TenantAccess.findOne(db.artifact_type_catalog, where, options); if (!artifact_type_catalog) { return artifact_type_catalog; diff --git a/backend/src/db/api/artifacts.js b/backend/src/db/api/artifacts.js index 54b2385..70a71ac 100644 --- a/backend/src/db/api/artifacts.js +++ b/backend/src/db/api/artifacts.js @@ -3,6 +3,7 @@ const db = require('../models'); const FileDBApi = require('./file'); const crypto = require('crypto'); const Utils = require('../utils'); +const TenantAccess = require('./tenantAccess'); @@ -232,7 +233,7 @@ module.exports = class ArtifactsDBApi { const transaction = (options && options.transaction) || undefined; const globalAccess = currentUser.app_role?.globalAccess; - const artifacts = await db.artifacts.findByPk(id, {}, {transaction}); + const artifacts = await TenantAccess.findByPkOrThrow(db.artifacts, id, options); @@ -358,14 +359,7 @@ module.exports = class ArtifactsDBApi { const currentUser = (options && options.currentUser) || { id: null }; const transaction = (options && options.transaction) || undefined; - const artifacts = await db.artifacts.findAll({ - where: { - id: { - [Op.in]: ids, - }, - }, - transaction, - }); + const artifacts = await TenantAccess.findAllByIds(db.artifacts, ids, options); await db.sequelize.transaction(async (transaction) => { for (const record of artifacts) { @@ -387,7 +381,7 @@ module.exports = class ArtifactsDBApi { const currentUser = (options && options.currentUser) || {id: null}; const transaction = (options && options.transaction) || undefined; - const artifacts = await db.artifacts.findByPk(id, options); + const artifacts = await TenantAccess.findByPkOrThrow(db.artifacts, id, options); await artifacts.update({ deletedBy: currentUser.id @@ -405,10 +399,7 @@ module.exports = class ArtifactsDBApi { static async findBy(where, options) { const transaction = (options && options.transaction) || undefined; - const artifacts = await db.artifacts.findOne( - { where }, - { transaction }, - ); + const artifacts = await TenantAccess.findOne(db.artifacts, where, options); if (!artifacts) { return artifacts; diff --git a/backend/src/db/api/audit_logs.js b/backend/src/db/api/audit_logs.js index c0209d0..e3919d8 100644 --- a/backend/src/db/api/audit_logs.js +++ b/backend/src/db/api/audit_logs.js @@ -3,6 +3,7 @@ const db = require('../models'); const FileDBApi = require('./file'); const crypto = require('crypto'); const Utils = require('../utils'); +const TenantAccess = require('./tenantAccess'); @@ -164,7 +165,7 @@ module.exports = class Audit_logsDBApi { const transaction = (options && options.transaction) || undefined; const globalAccess = currentUser.app_role?.globalAccess; - const audit_logs = await db.audit_logs.findByPk(id, {}, {transaction}); + const audit_logs = await TenantAccess.findByPkOrThrow(db.audit_logs, id, options); @@ -235,14 +236,7 @@ module.exports = class Audit_logsDBApi { const currentUser = (options && options.currentUser) || { id: null }; const transaction = (options && options.transaction) || undefined; - const audit_logs = await db.audit_logs.findAll({ - where: { - id: { - [Op.in]: ids, - }, - }, - transaction, - }); + const audit_logs = await TenantAccess.findAllByIds(db.audit_logs, ids, options); await db.sequelize.transaction(async (transaction) => { for (const record of audit_logs) { @@ -264,7 +258,7 @@ module.exports = class Audit_logsDBApi { const currentUser = (options && options.currentUser) || {id: null}; const transaction = (options && options.transaction) || undefined; - const audit_logs = await db.audit_logs.findByPk(id, options); + const audit_logs = await TenantAccess.findByPkOrThrow(db.audit_logs, id, options); await audit_logs.update({ deletedBy: currentUser.id @@ -282,10 +276,7 @@ module.exports = class Audit_logsDBApi { static async findBy(where, options) { const transaction = (options && options.transaction) || undefined; - const audit_logs = await db.audit_logs.findOne( - { where }, - { transaction }, - ); + const audit_logs = await TenantAccess.findOne(db.audit_logs, where, options); if (!audit_logs) { return audit_logs; diff --git a/backend/src/db/api/connected_systems.js b/backend/src/db/api/connected_systems.js index 1329a64..d3b2939 100644 --- a/backend/src/db/api/connected_systems.js +++ b/backend/src/db/api/connected_systems.js @@ -3,6 +3,7 @@ const db = require('../models'); const FileDBApi = require('./file'); const crypto = require('crypto'); const Utils = require('../utils'); +const TenantAccess = require('./tenantAccess'); @@ -172,7 +173,7 @@ module.exports = class Connected_systemsDBApi { const transaction = (options && options.transaction) || undefined; const globalAccess = currentUser.app_role?.globalAccess; - const connected_systems = await db.connected_systems.findByPk(id, {}, {transaction}); + const connected_systems = await TenantAccess.findByPkOrThrow(db.connected_systems, id, options); @@ -237,14 +238,7 @@ module.exports = class Connected_systemsDBApi { const currentUser = (options && options.currentUser) || { id: null }; const transaction = (options && options.transaction) || undefined; - const connected_systems = await db.connected_systems.findAll({ - where: { - id: { - [Op.in]: ids, - }, - }, - transaction, - }); + const connected_systems = await TenantAccess.findAllByIds(db.connected_systems, ids, options); await db.sequelize.transaction(async (transaction) => { for (const record of connected_systems) { @@ -266,7 +260,7 @@ module.exports = class Connected_systemsDBApi { const currentUser = (options && options.currentUser) || {id: null}; const transaction = (options && options.transaction) || undefined; - const connected_systems = await db.connected_systems.findByPk(id, options); + const connected_systems = await TenantAccess.findByPkOrThrow(db.connected_systems, id, options); await connected_systems.update({ deletedBy: currentUser.id @@ -284,10 +278,7 @@ module.exports = class Connected_systemsDBApi { static async findBy(where, options) { const transaction = (options && options.transaction) || undefined; - const connected_systems = await db.connected_systems.findOne( - { where }, - { transaction }, - ); + const connected_systems = await TenantAccess.findOne(db.connected_systems, where, options); if (!connected_systems) { return connected_systems; diff --git a/backend/src/db/api/control_frameworks.js b/backend/src/db/api/control_frameworks.js index d04fb66..9c4447f 100644 --- a/backend/src/db/api/control_frameworks.js +++ b/backend/src/db/api/control_frameworks.js @@ -3,6 +3,7 @@ const db = require('../models'); const FileDBApi = require('./file'); const crypto = require('crypto'); const Utils = require('../utils'); +const TenantAccess = require('./tenantAccess'); @@ -112,7 +113,7 @@ module.exports = class Control_frameworksDBApi { const transaction = (options && options.transaction) || undefined; const globalAccess = currentUser.app_role?.globalAccess; - const control_frameworks = await db.control_frameworks.findByPk(id, {}, {transaction}); + const control_frameworks = await TenantAccess.findByPkOrThrow(db.control_frameworks, id, options); @@ -159,14 +160,7 @@ module.exports = class Control_frameworksDBApi { const currentUser = (options && options.currentUser) || { id: null }; const transaction = (options && options.transaction) || undefined; - const control_frameworks = await db.control_frameworks.findAll({ - where: { - id: { - [Op.in]: ids, - }, - }, - transaction, - }); + const control_frameworks = await TenantAccess.findAllByIds(db.control_frameworks, ids, options); await db.sequelize.transaction(async (transaction) => { for (const record of control_frameworks) { @@ -188,7 +182,7 @@ module.exports = class Control_frameworksDBApi { const currentUser = (options && options.currentUser) || {id: null}; const transaction = (options && options.transaction) || undefined; - const control_frameworks = await db.control_frameworks.findByPk(id, options); + const control_frameworks = await TenantAccess.findByPkOrThrow(db.control_frameworks, id, options); await control_frameworks.update({ deletedBy: currentUser.id @@ -206,10 +200,7 @@ module.exports = class Control_frameworksDBApi { static async findBy(where, options) { const transaction = (options && options.transaction) || undefined; - const control_frameworks = await db.control_frameworks.findOne( - { where }, - { transaction }, - ); + const control_frameworks = await TenantAccess.findOne(db.control_frameworks, where, options); if (!control_frameworks) { return control_frameworks; diff --git a/backend/src/db/api/control_requirements.js b/backend/src/db/api/control_requirements.js index a371a79..8e7e6f8 100644 --- a/backend/src/db/api/control_requirements.js +++ b/backend/src/db/api/control_requirements.js @@ -3,6 +3,7 @@ const db = require('../models'); const FileDBApi = require('./file'); const crypto = require('crypto'); const Utils = require('../utils'); +const TenantAccess = require('./tenantAccess'); @@ -136,7 +137,7 @@ module.exports = class Control_requirementsDBApi { const transaction = (options && options.transaction) || undefined; const globalAccess = currentUser.app_role?.globalAccess; - const control_requirements = await db.control_requirements.findByPk(id, {}, {transaction}); + const control_requirements = await TenantAccess.findByPkOrThrow(db.control_requirements, id, options); @@ -198,14 +199,7 @@ module.exports = class Control_requirementsDBApi { const currentUser = (options && options.currentUser) || { id: null }; const transaction = (options && options.transaction) || undefined; - const control_requirements = await db.control_requirements.findAll({ - where: { - id: { - [Op.in]: ids, - }, - }, - transaction, - }); + const control_requirements = await TenantAccess.findAllByIds(db.control_requirements, ids, options); await db.sequelize.transaction(async (transaction) => { for (const record of control_requirements) { @@ -227,7 +221,7 @@ module.exports = class Control_requirementsDBApi { const currentUser = (options && options.currentUser) || {id: null}; const transaction = (options && options.transaction) || undefined; - const control_requirements = await db.control_requirements.findByPk(id, options); + const control_requirements = await TenantAccess.findByPkOrThrow(db.control_requirements, id, options); await control_requirements.update({ deletedBy: currentUser.id @@ -245,10 +239,7 @@ module.exports = class Control_requirementsDBApi { static async findBy(where, options) { const transaction = (options && options.transaction) || undefined; - const control_requirements = await db.control_requirements.findOne( - { where }, - { transaction }, - ); + const control_requirements = await TenantAccess.findOne(db.control_requirements, where, options); if (!control_requirements) { return control_requirements; diff --git a/backend/src/db/api/evidence_models.js b/backend/src/db/api/evidence_models.js index 73dc592..b181e23 100644 --- a/backend/src/db/api/evidence_models.js +++ b/backend/src/db/api/evidence_models.js @@ -3,6 +3,7 @@ const db = require('../models'); const FileDBApi = require('./file'); const crypto = require('crypto'); const Utils = require('../utils'); +const TenantAccess = require('./tenantAccess'); @@ -164,7 +165,7 @@ module.exports = class Evidence_modelsDBApi { const transaction = (options && options.transaction) || undefined; const globalAccess = currentUser.app_role?.globalAccess; - const evidence_models = await db.evidence_models.findByPk(id, {}, {transaction}); + const evidence_models = await TenantAccess.findByPkOrThrow(db.evidence_models, id, options); @@ -250,14 +251,7 @@ module.exports = class Evidence_modelsDBApi { const currentUser = (options && options.currentUser) || { id: null }; const transaction = (options && options.transaction) || undefined; - const evidence_models = await db.evidence_models.findAll({ - where: { - id: { - [Op.in]: ids, - }, - }, - transaction, - }); + const evidence_models = await TenantAccess.findAllByIds(db.evidence_models, ids, options); await db.sequelize.transaction(async (transaction) => { for (const record of evidence_models) { @@ -279,7 +273,7 @@ module.exports = class Evidence_modelsDBApi { const currentUser = (options && options.currentUser) || {id: null}; const transaction = (options && options.transaction) || undefined; - const evidence_models = await db.evidence_models.findByPk(id, options); + const evidence_models = await TenantAccess.findByPkOrThrow(db.evidence_models, id, options); await evidence_models.update({ deletedBy: currentUser.id @@ -297,10 +291,7 @@ module.exports = class Evidence_modelsDBApi { static async findBy(where, options) { const transaction = (options && options.transaction) || undefined; - const evidence_models = await db.evidence_models.findOne( - { where }, - { transaction }, - ); + const evidence_models = await TenantAccess.findOne(db.evidence_models, where, options); if (!evidence_models) { return evidence_models; diff --git a/backend/src/db/api/exceptions.js b/backend/src/db/api/exceptions.js index f5c44c5..bfdaac9 100644 --- a/backend/src/db/api/exceptions.js +++ b/backend/src/db/api/exceptions.js @@ -3,6 +3,7 @@ const db = require('../models'); const FileDBApi = require('./file'); const crypto = require('crypto'); const Utils = require('../utils'); +const TenantAccess = require('./tenantAccess'); @@ -180,7 +181,7 @@ module.exports = class ExceptionsDBApi { const transaction = (options && options.transaction) || undefined; const globalAccess = currentUser.app_role?.globalAccess; - const exceptions = await db.exceptions.findByPk(id, {}, {transaction}); + const exceptions = await TenantAccess.findByPkOrThrow(db.exceptions, id, options); @@ -258,14 +259,7 @@ module.exports = class ExceptionsDBApi { const currentUser = (options && options.currentUser) || { id: null }; const transaction = (options && options.transaction) || undefined; - const exceptions = await db.exceptions.findAll({ - where: { - id: { - [Op.in]: ids, - }, - }, - transaction, - }); + const exceptions = await TenantAccess.findAllByIds(db.exceptions, ids, options); await db.sequelize.transaction(async (transaction) => { for (const record of exceptions) { @@ -287,7 +281,7 @@ module.exports = class ExceptionsDBApi { const currentUser = (options && options.currentUser) || {id: null}; const transaction = (options && options.transaction) || undefined; - const exceptions = await db.exceptions.findByPk(id, options); + const exceptions = await TenantAccess.findByPkOrThrow(db.exceptions, id, options); await exceptions.update({ deletedBy: currentUser.id @@ -305,10 +299,7 @@ module.exports = class ExceptionsDBApi { static async findBy(where, options) { const transaction = (options && options.transaction) || undefined; - const exceptions = await db.exceptions.findOne( - { where }, - { transaction }, - ); + const exceptions = await TenantAccess.findOne(db.exceptions, where, options); if (!exceptions) { return exceptions; diff --git a/backend/src/db/api/identity_workflows.js b/backend/src/db/api/identity_workflows.js index d89ee0d..b71bd73 100644 --- a/backend/src/db/api/identity_workflows.js +++ b/backend/src/db/api/identity_workflows.js @@ -3,6 +3,7 @@ const db = require('../models'); const FileDBApi = require('./file'); const crypto = require('crypto'); const Utils = require('../utils'); +const TenantAccess = require('./tenantAccess'); @@ -178,7 +179,7 @@ module.exports = class Identity_workflowsDBApi { const transaction = (options && options.transaction) || undefined; const globalAccess = currentUser.app_role?.globalAccess; - const identity_workflows = await db.identity_workflows.findByPk(id, {}, {transaction}); + const identity_workflows = await TenantAccess.findByPkOrThrow(db.identity_workflows, id, options); @@ -251,14 +252,7 @@ module.exports = class Identity_workflowsDBApi { const currentUser = (options && options.currentUser) || { id: null }; const transaction = (options && options.transaction) || undefined; - const identity_workflows = await db.identity_workflows.findAll({ - where: { - id: { - [Op.in]: ids, - }, - }, - transaction, - }); + const identity_workflows = await TenantAccess.findAllByIds(db.identity_workflows, ids, options); await db.sequelize.transaction(async (transaction) => { for (const record of identity_workflows) { @@ -280,7 +274,7 @@ module.exports = class Identity_workflowsDBApi { const currentUser = (options && options.currentUser) || {id: null}; const transaction = (options && options.transaction) || undefined; - const identity_workflows = await db.identity_workflows.findByPk(id, options); + const identity_workflows = await TenantAccess.findByPkOrThrow(db.identity_workflows, id, options); await identity_workflows.update({ deletedBy: currentUser.id @@ -298,10 +292,7 @@ module.exports = class Identity_workflowsDBApi { static async findBy(where, options) { const transaction = (options && options.transaction) || undefined; - const identity_workflows = await db.identity_workflows.findOne( - { where }, - { transaction }, - ); + const identity_workflows = await TenantAccess.findOne(db.identity_workflows, where, options); if (!identity_workflows) { return identity_workflows; diff --git a/backend/src/db/api/notifications.js b/backend/src/db/api/notifications.js index bff555f..7c1cf67 100644 --- a/backend/src/db/api/notifications.js +++ b/backend/src/db/api/notifications.js @@ -3,6 +3,7 @@ const db = require('../models'); const FileDBApi = require('./file'); const crypto = require('crypto'); const Utils = require('../utils'); +const TenantAccess = require('./tenantAccess'); @@ -166,7 +167,7 @@ module.exports = class NotificationsDBApi { const transaction = (options && options.transaction) || undefined; const globalAccess = currentUser.app_role?.globalAccess; - const notifications = await db.notifications.findByPk(id, {}, {transaction}); + const notifications = await TenantAccess.findByPkOrThrow(db.notifications, id, options); @@ -237,14 +238,7 @@ module.exports = class NotificationsDBApi { const currentUser = (options && options.currentUser) || { id: null }; const transaction = (options && options.transaction) || undefined; - const notifications = await db.notifications.findAll({ - where: { - id: { - [Op.in]: ids, - }, - }, - transaction, - }); + const notifications = await TenantAccess.findAllByIds(db.notifications, ids, options); await db.sequelize.transaction(async (transaction) => { for (const record of notifications) { @@ -266,7 +260,7 @@ module.exports = class NotificationsDBApi { const currentUser = (options && options.currentUser) || {id: null}; const transaction = (options && options.transaction) || undefined; - const notifications = await db.notifications.findByPk(id, options); + const notifications = await TenantAccess.findByPkOrThrow(db.notifications, id, options); await notifications.update({ deletedBy: currentUser.id @@ -284,10 +278,7 @@ module.exports = class NotificationsDBApi { static async findBy(where, options) { const transaction = (options && options.transaction) || undefined; - const notifications = await db.notifications.findOne( - { where }, - { transaction }, - ); + const notifications = await TenantAccess.findOne(db.notifications, where, options); if (!notifications) { return notifications; diff --git a/backend/src/db/api/organization_settings.js b/backend/src/db/api/organization_settings.js index fd8e496..c35331d 100644 --- a/backend/src/db/api/organization_settings.js +++ b/backend/src/db/api/organization_settings.js @@ -3,6 +3,7 @@ const db = require('../models'); const FileDBApi = require('./file'); const crypto = require('crypto'); const Utils = require('../utils'); +const TenantAccess = require('./tenantAccess'); @@ -188,7 +189,7 @@ module.exports = class Organization_settingsDBApi { const transaction = (options && options.transaction) || undefined; const globalAccess = currentUser.app_role?.globalAccess; - const organization_settings = await db.organization_settings.findByPk(id, {}, {transaction}); + const organization_settings = await TenantAccess.findByPkOrThrow(db.organization_settings, id, options); @@ -260,14 +261,7 @@ module.exports = class Organization_settingsDBApi { const currentUser = (options && options.currentUser) || { id: null }; const transaction = (options && options.transaction) || undefined; - const organization_settings = await db.organization_settings.findAll({ - where: { - id: { - [Op.in]: ids, - }, - }, - transaction, - }); + const organization_settings = await TenantAccess.findAllByIds(db.organization_settings, ids, options); await db.sequelize.transaction(async (transaction) => { for (const record of organization_settings) { @@ -289,7 +283,7 @@ module.exports = class Organization_settingsDBApi { const currentUser = (options && options.currentUser) || {id: null}; const transaction = (options && options.transaction) || undefined; - const organization_settings = await db.organization_settings.findByPk(id, options); + const organization_settings = await TenantAccess.findByPkOrThrow(db.organization_settings, id, options); await organization_settings.update({ deletedBy: currentUser.id @@ -307,10 +301,7 @@ module.exports = class Organization_settingsDBApi { static async findBy(where, options) { const transaction = (options && options.transaction) || undefined; - const organization_settings = await db.organization_settings.findOne( - { where }, - { transaction }, - ); + const organization_settings = await TenantAccess.findOne(db.organization_settings, where, options); if (!organization_settings) { return organization_settings; diff --git a/backend/src/db/api/organizations.js b/backend/src/db/api/organizations.js index 000a91d..c0325d4 100644 --- a/backend/src/db/api/organizations.js +++ b/backend/src/db/api/organizations.js @@ -3,6 +3,7 @@ const db = require('../models'); const FileDBApi = require('./file'); const crypto = require('crypto'); const Utils = require('../utils'); +const TenantAccess = require('./tenantAccess'); @@ -76,7 +77,7 @@ module.exports = class OrganizationsDBApi { const transaction = (options && options.transaction) || undefined; const globalAccess = currentUser.app_role?.globalAccess; - const organizations = await db.organizations.findByPk(id, {}, {transaction}); + const organizations = await TenantAccess.findByPkOrThrow(db.organizations, id, options); @@ -105,14 +106,7 @@ module.exports = class OrganizationsDBApi { const currentUser = (options && options.currentUser) || { id: null }; const transaction = (options && options.transaction) || undefined; - const organizations = await db.organizations.findAll({ - where: { - id: { - [Op.in]: ids, - }, - }, - transaction, - }); + const organizations = await TenantAccess.findAllByIds(db.organizations, ids, options); await db.sequelize.transaction(async (transaction) => { for (const record of organizations) { @@ -134,7 +128,7 @@ module.exports = class OrganizationsDBApi { const currentUser = (options && options.currentUser) || {id: null}; const transaction = (options && options.transaction) || undefined; - const organizations = await db.organizations.findByPk(id, options); + const organizations = await TenantAccess.findByPkOrThrow(db.organizations, id, options); await organizations.update({ deletedBy: currentUser.id @@ -152,10 +146,7 @@ module.exports = class OrganizationsDBApi { static async findBy(where, options) { const transaction = (options && options.transaction) || undefined; - const organizations = await db.organizations.findOne( - { where }, - { transaction }, - ); + const organizations = await TenantAccess.findOne(db.organizations, where, options); if (!organizations) { return organizations; diff --git a/backend/src/db/api/proof_packets.js b/backend/src/db/api/proof_packets.js index 2aed480..61a9863 100644 --- a/backend/src/db/api/proof_packets.js +++ b/backend/src/db/api/proof_packets.js @@ -3,6 +3,7 @@ const db = require('../models'); const FileDBApi = require('./file'); const crypto = require('crypto'); const Utils = require('../utils'); +const TenantAccess = require('./tenantAccess'); @@ -164,7 +165,7 @@ module.exports = class Proof_packetsDBApi { const transaction = (options && options.transaction) || undefined; const globalAccess = currentUser.app_role?.globalAccess; - const proof_packets = await db.proof_packets.findByPk(id, {}, {transaction}); + const proof_packets = await TenantAccess.findByPkOrThrow(db.proof_packets, id, options); @@ -264,14 +265,7 @@ module.exports = class Proof_packetsDBApi { const currentUser = (options && options.currentUser) || { id: null }; const transaction = (options && options.transaction) || undefined; - const proof_packets = await db.proof_packets.findAll({ - where: { - id: { - [Op.in]: ids, - }, - }, - transaction, - }); + const proof_packets = await TenantAccess.findAllByIds(db.proof_packets, ids, options); await db.sequelize.transaction(async (transaction) => { for (const record of proof_packets) { @@ -293,7 +287,7 @@ module.exports = class Proof_packetsDBApi { const currentUser = (options && options.currentUser) || {id: null}; const transaction = (options && options.transaction) || undefined; - const proof_packets = await db.proof_packets.findByPk(id, options); + const proof_packets = await TenantAccess.findByPkOrThrow(db.proof_packets, id, options); await proof_packets.update({ deletedBy: currentUser.id @@ -311,10 +305,7 @@ module.exports = class Proof_packetsDBApi { static async findBy(where, options) { const transaction = (options && options.transaction) || undefined; - const proof_packets = await db.proof_packets.findOne( - { where }, - { transaction }, - ); + const proof_packets = await TenantAccess.findOne(db.proof_packets, where, options); if (!proof_packets) { return proof_packets; diff --git a/backend/src/db/api/remediation_items.js b/backend/src/db/api/remediation_items.js index 2df8cf6..c62852a 100644 --- a/backend/src/db/api/remediation_items.js +++ b/backend/src/db/api/remediation_items.js @@ -3,6 +3,7 @@ const db = require('../models'); const FileDBApi = require('./file'); const crypto = require('crypto'); const Utils = require('../utils'); +const TenantAccess = require('./tenantAccess'); @@ -170,7 +171,7 @@ module.exports = class Remediation_itemsDBApi { const transaction = (options && options.transaction) || undefined; const globalAccess = currentUser.app_role?.globalAccess; - const remediation_items = await db.remediation_items.findByPk(id, {}, {transaction}); + const remediation_items = await TenantAccess.findByPkOrThrow(db.remediation_items, id, options); @@ -274,14 +275,7 @@ module.exports = class Remediation_itemsDBApi { const currentUser = (options && options.currentUser) || { id: null }; const transaction = (options && options.transaction) || undefined; - const remediation_items = await db.remediation_items.findAll({ - where: { - id: { - [Op.in]: ids, - }, - }, - transaction, - }); + const remediation_items = await TenantAccess.findAllByIds(db.remediation_items, ids, options); await db.sequelize.transaction(async (transaction) => { for (const record of remediation_items) { @@ -303,7 +297,7 @@ module.exports = class Remediation_itemsDBApi { const currentUser = (options && options.currentUser) || {id: null}; const transaction = (options && options.transaction) || undefined; - const remediation_items = await db.remediation_items.findByPk(id, options); + const remediation_items = await TenantAccess.findByPkOrThrow(db.remediation_items, id, options); await remediation_items.update({ deletedBy: currentUser.id @@ -321,10 +315,7 @@ module.exports = class Remediation_itemsDBApi { static async findBy(where, options) { const transaction = (options && options.transaction) || undefined; - const remediation_items = await db.remediation_items.findOne( - { where }, - { transaction }, - ); + const remediation_items = await TenantAccess.findOne(db.remediation_items, where, options); if (!remediation_items) { return remediation_items; diff --git a/backend/src/db/api/sampled_subjects.js b/backend/src/db/api/sampled_subjects.js index 404a0fe..4265d17 100644 --- a/backend/src/db/api/sampled_subjects.js +++ b/backend/src/db/api/sampled_subjects.js @@ -3,6 +3,7 @@ const db = require('../models'); const FileDBApi = require('./file'); const crypto = require('crypto'); const Utils = require('../utils'); +const TenantAccess = require('./tenantAccess'); @@ -174,7 +175,7 @@ module.exports = class Sampled_subjectsDBApi { const transaction = (options && options.transaction) || undefined; const globalAccess = currentUser.app_role?.globalAccess; - const sampled_subjects = await db.sampled_subjects.findByPk(id, {}, {transaction}); + const sampled_subjects = await TenantAccess.findByPkOrThrow(db.sampled_subjects, id, options); @@ -248,14 +249,7 @@ module.exports = class Sampled_subjectsDBApi { const currentUser = (options && options.currentUser) || { id: null }; const transaction = (options && options.transaction) || undefined; - const sampled_subjects = await db.sampled_subjects.findAll({ - where: { - id: { - [Op.in]: ids, - }, - }, - transaction, - }); + const sampled_subjects = await TenantAccess.findAllByIds(db.sampled_subjects, ids, options); await db.sequelize.transaction(async (transaction) => { for (const record of sampled_subjects) { @@ -277,7 +271,7 @@ module.exports = class Sampled_subjectsDBApi { const currentUser = (options && options.currentUser) || {id: null}; const transaction = (options && options.transaction) || undefined; - const sampled_subjects = await db.sampled_subjects.findByPk(id, options); + const sampled_subjects = await TenantAccess.findByPkOrThrow(db.sampled_subjects, id, options); await sampled_subjects.update({ deletedBy: currentUser.id @@ -295,10 +289,7 @@ module.exports = class Sampled_subjectsDBApi { static async findBy(where, options) { const transaction = (options && options.transaction) || undefined; - const sampled_subjects = await db.sampled_subjects.findOne( - { where }, - { transaction }, - ); + const sampled_subjects = await TenantAccess.findOne(db.sampled_subjects, where, options); if (!sampled_subjects) { return sampled_subjects; diff --git a/backend/src/db/api/tenantAccess.js b/backend/src/db/api/tenantAccess.js new file mode 100644 index 0000000..859066a --- /dev/null +++ b/backend/src/db/api/tenantAccess.js @@ -0,0 +1,121 @@ +const db = require('../models'); + +const { Op } = db.Sequelize; + +class TenantAccess { + static getNotFoundError(message = 'Item not found') { + const error = new Error(message); + error.code = 404; + return error; + } + + static hasGlobalAccess(currentUser) { + return Boolean(currentUser?.app_role?.globalAccess); + } + + static getCurrentOrganizationId(currentUser) { + return ( + currentUser?.organization?.id || + currentUser?.organizations?.id || + currentUser?.organizationId || + currentUser?.organizationsId || + null + ); + } + + static getOwnershipField(model) { + if (model?.rawAttributes?.organizationId) { + return 'organizationId'; + } + + if (model?.rawAttributes?.organizationsId) { + return 'organizationsId'; + } + + if (model?.getTableName?.() === 'organizations') { + return 'id'; + } + + return null; + } + + static buildTenantWhere(model, where = {}, options = {}) { + const ownershipField = this.getOwnershipField(model); + + if (!ownershipField) { + return where; + } + + const currentUser = options.currentUser; + + if (!currentUser || this.hasGlobalAccess(currentUser)) { + return where; + } + + const organizationId = this.getCurrentOrganizationId(currentUser); + + if (!organizationId) { + throw this.getNotFoundError(); + } + + const tenantWhere = { [ownershipField]: organizationId }; + + if (!where || Object.keys(where).length === 0) { + return tenantWhere; + } + + return { + [Op.and]: [where, tenantWhere], + }; + } + + static async findOne(model, where = {}, options = {}) { + return model.findOne({ + where: this.buildTenantWhere(model, where, options), + transaction: options.transaction, + }); + } + + static async findByPk(model, id, options = {}) { + return this.findOne(model, { id }, options); + } + + static async findByPkOrThrow(model, id, options = {}) { + const record = await this.findByPk(model, id, options); + + if (!record) { + throw this.getNotFoundError(); + } + + return record; + } + + static async findAllByIds(model, ids = [], options = {}) { + const uniqueIds = [...new Set((ids || []).filter(Boolean))]; + + if (!uniqueIds.length) { + return []; + } + + const records = await model.findAll({ + where: this.buildTenantWhere( + model, + { + id: { + [Op.in]: uniqueIds, + }, + }, + options, + ), + transaction: options.transaction, + }); + + if (records.length !== uniqueIds.length) { + throw this.getNotFoundError(); + } + + return records; + } +} + +module.exports = TenantAccess; diff --git a/backend/src/db/api/user_invitations.js b/backend/src/db/api/user_invitations.js index 12fb4a5..c5b61a0 100644 --- a/backend/src/db/api/user_invitations.js +++ b/backend/src/db/api/user_invitations.js @@ -3,6 +3,7 @@ const db = require('../models'); const FileDBApi = require('./file'); const crypto = require('crypto'); const Utils = require('../utils'); +const TenantAccess = require('./tenantAccess'); @@ -154,7 +155,7 @@ module.exports = class User_invitationsDBApi { const transaction = (options && options.transaction) || undefined; const globalAccess = currentUser.app_role?.globalAccess; - const user_invitations = await db.user_invitations.findByPk(id, {}, {transaction}); + const user_invitations = await TenantAccess.findByPkOrThrow(db.user_invitations, id, options); @@ -222,14 +223,7 @@ module.exports = class User_invitationsDBApi { const currentUser = (options && options.currentUser) || { id: null }; const transaction = (options && options.transaction) || undefined; - const user_invitations = await db.user_invitations.findAll({ - where: { - id: { - [Op.in]: ids, - }, - }, - transaction, - }); + const user_invitations = await TenantAccess.findAllByIds(db.user_invitations, ids, options); await db.sequelize.transaction(async (transaction) => { for (const record of user_invitations) { @@ -251,7 +245,7 @@ module.exports = class User_invitationsDBApi { const currentUser = (options && options.currentUser) || {id: null}; const transaction = (options && options.transaction) || undefined; - const user_invitations = await db.user_invitations.findByPk(id, options); + const user_invitations = await TenantAccess.findByPkOrThrow(db.user_invitations, id, options); await user_invitations.update({ deletedBy: currentUser.id @@ -269,10 +263,7 @@ module.exports = class User_invitationsDBApi { static async findBy(where, options) { const transaction = (options && options.transaction) || undefined; - const user_invitations = await db.user_invitations.findOne( - { where }, - { transaction }, - ); + const user_invitations = await TenantAccess.findOne(db.user_invitations, where, options); if (!user_invitations) { return user_invitations; diff --git a/backend/src/db/api/users.js b/backend/src/db/api/users.js index e453ae8..869ac9c 100644 --- a/backend/src/db/api/users.js +++ b/backend/src/db/api/users.js @@ -3,6 +3,7 @@ const db = require('../models'); const FileDBApi = require('./file'); const crypto = require('crypto'); const Utils = require('../utils'); +const TenantAccess = require('./tenantAccess'); const bcrypt = require('bcrypt'); const config = require('../../config'); @@ -244,7 +245,7 @@ module.exports = class UsersDBApi { const transaction = (options && options.transaction) || undefined; - const users = await db.users.findByPk(id, {}, {transaction}); + const users = await TenantAccess.findByPkOrThrow(db.users, id, options); @@ -357,14 +358,7 @@ module.exports = class UsersDBApi { const currentUser = (options && options.currentUser) || { id: null }; const transaction = (options && options.transaction) || undefined; - const users = await db.users.findAll({ - where: { - id: { - [Op.in]: ids, - }, - }, - transaction, - }); + const users = await TenantAccess.findAllByIds(db.users, ids, options); await db.sequelize.transaction(async (transaction) => { for (const record of users) { @@ -386,7 +380,7 @@ module.exports = class UsersDBApi { const currentUser = (options && options.currentUser) || {id: null}; const transaction = (options && options.transaction) || undefined; - const users = await db.users.findByPk(id, options); + const users = await TenantAccess.findByPkOrThrow(db.users, id, options); await users.update({ deletedBy: currentUser.id @@ -404,10 +398,7 @@ module.exports = class UsersDBApi { static async findBy(where, options) { const transaction = (options && options.transaction) || undefined; - const users = await db.users.findOne( - { where }, - { transaction }, - ); + const users = await TenantAccess.findOne(db.users, where, options); if (!users) { return users; diff --git a/backend/src/db/api/workflow_templates.js b/backend/src/db/api/workflow_templates.js index 2614414..376717f 100644 --- a/backend/src/db/api/workflow_templates.js +++ b/backend/src/db/api/workflow_templates.js @@ -3,6 +3,7 @@ const db = require('../models'); const FileDBApi = require('./file'); const crypto = require('crypto'); const Utils = require('../utils'); +const TenantAccess = require('./tenantAccess'); @@ -150,7 +151,7 @@ module.exports = class Workflow_templatesDBApi { const transaction = (options && options.transaction) || undefined; const globalAccess = currentUser.app_role?.globalAccess; - const workflow_templates = await db.workflow_templates.findByPk(id, {}, {transaction}); + const workflow_templates = await TenantAccess.findByPkOrThrow(db.workflow_templates, id, options); @@ -209,14 +210,7 @@ module.exports = class Workflow_templatesDBApi { const currentUser = (options && options.currentUser) || { id: null }; const transaction = (options && options.transaction) || undefined; - const workflow_templates = await db.workflow_templates.findAll({ - where: { - id: { - [Op.in]: ids, - }, - }, - transaction, - }); + const workflow_templates = await TenantAccess.findAllByIds(db.workflow_templates, ids, options); await db.sequelize.transaction(async (transaction) => { for (const record of workflow_templates) { @@ -238,7 +232,7 @@ module.exports = class Workflow_templatesDBApi { const currentUser = (options && options.currentUser) || {id: null}; const transaction = (options && options.transaction) || undefined; - const workflow_templates = await db.workflow_templates.findByPk(id, options); + const workflow_templates = await TenantAccess.findByPkOrThrow(db.workflow_templates, id, options); await workflow_templates.update({ deletedBy: currentUser.id @@ -256,10 +250,7 @@ module.exports = class Workflow_templatesDBApi { static async findBy(where, options) { const transaction = (options && options.transaction) || undefined; - const workflow_templates = await db.workflow_templates.findOne( - { where }, - { transaction }, - ); + const workflow_templates = await TenantAccess.findOne(db.workflow_templates, where, options); if (!workflow_templates) { return workflow_templates; diff --git a/backend/src/db/seeders/20260410120000-role-model-alignment.js b/backend/src/db/seeders/20260410120000-role-model-alignment.js new file mode 100644 index 0000000..917134b --- /dev/null +++ b/backend/src/db/seeders/20260410120000-role-model-alignment.js @@ -0,0 +1,442 @@ +'use strict'; + +const bcrypt = require('bcrypt'); +const config = require('../../config'); + +const CRUD_OPERATIONS = ['CREATE', 'READ', 'UPDATE', 'DELETE']; +const ENTITY_NAMES = [ + 'users', + 'roles', + 'permissions', + 'organizations', + 'user_invitations', + 'connected_systems', + 'control_frameworks', + 'control_requirements', + 'identity_workflows', + 'evidence_models', + 'artifacts', + 'sampled_subjects', + 'proof_packets', + 'remediation_items', + 'access_reviews', + 'access_review_items', + 'exceptions', + 'audit_logs', + 'notifications', + 'organization_settings', + 'artifact_type_catalog', + 'workflow_templates', +]; + +const ROLE_RENAMES = { + 'Super Administrator': 'super_admin', + Administrator: 'org_admin', + org_governance_lead: 'compliance_manager', + platform_ops_manager: 'security_manager', + evidence_operations_lead: 'iam_operator', + audit_viewer: 'auditor', + platform_owner: 'read_only_client', +}; + +const SAMPLE_USER_EMAILS = { + org_admin: 'admin@flatlogic.com', + compliance_manager: 'john@doe.com', + read_only_client: 'client@hello.com', + security_manager: 'security.manager@flatlogic.com', + iam_operator: 'iam.operator@flatlogic.com', + auditor: 'auditor@flatlogic.com', +}; + +function getCrudPermissions(entityNames) { + return entityNames.flatMap((entityName) => + CRUD_OPERATIONS.map((operation) => `${operation}_${entityName.toUpperCase()}`), + ); +} + +function getReadPermissions(entityNames) { + return entityNames.map((entityName) => `READ_${entityName.toUpperCase()}`); +} + +module.exports = { + async up(queryInterface, Sequelize) { + const transaction = await queryInterface.sequelize.transaction(); + + try { + const [roleRows] = await queryInterface.sequelize.query( + `SELECT id, name FROM "roles" WHERE "deletedAt" IS NULL`, + { transaction }, + ); + + const roleIdsByName = roleRows.reduce((accumulator, role) => { + accumulator[role.name] = role.id; + return accumulator; + }, {}); + + for (const [legacyName, targetName] of Object.entries(ROLE_RENAMES)) { + const roleId = roleIdsByName[legacyName] || roleIdsByName[targetName]; + + if (!roleId) { + throw new Error(`Missing role row for '${legacyName}' -> '${targetName}' alignment.`); + } + + await queryInterface.bulkUpdate( + 'roles', + { + name: targetName, + globalAccess: targetName === 'super_admin', + updatedAt: new Date(), + }, + { id: roleId }, + { transaction }, + ); + + roleIdsByName[targetName] = roleId; + } + + const managedRoleNames = [ + 'super_admin', + 'org_admin', + 'compliance_manager', + 'security_manager', + 'iam_operator', + 'auditor', + 'read_only_client', + ]; + const managedRoleIds = managedRoleNames.map((roleName) => roleIdsByName[roleName]).filter(Boolean); + + const [permissionRows] = await queryInterface.sequelize.query( + `SELECT id, name FROM "permissions" WHERE "deletedAt" IS NULL`, + { transaction }, + ); + + const permissionIdsByName = permissionRows.reduce((accumulator, permission) => { + accumulator[permission.name] = permission.id; + return accumulator; + }, {}); + + const permissionMatrix = { + super_admin: [ + ...getCrudPermissions(ENTITY_NAMES), + 'READ_API_DOCS', + 'CREATE_SEARCH', + ], + org_admin: [ + 'READ_USERS', + 'CREATE_USERS', + 'UPDATE_USERS', + 'DELETE_USERS', + 'READ_ROLES', + 'READ_PERMISSIONS', + 'READ_ORGANIZATIONS', + 'UPDATE_ORGANIZATIONS', + 'READ_USER_INVITATIONS', + 'CREATE_USER_INVITATIONS', + 'UPDATE_USER_INVITATIONS', + 'DELETE_USER_INVITATIONS', + ...getCrudPermissions([ + 'connected_systems', + 'control_frameworks', + 'control_requirements', + 'identity_workflows', + 'evidence_models', + 'artifacts', + 'sampled_subjects', + 'proof_packets', + 'remediation_items', + 'access_reviews', + 'access_review_items', + 'exceptions', + 'notifications', + 'organization_settings', + 'artifact_type_catalog', + 'workflow_templates', + ]), + 'READ_AUDIT_LOGS', + 'READ_API_DOCS', + 'CREATE_SEARCH', + ], + compliance_manager: [ + ...getReadPermissions([ + 'users', + 'roles', + 'organizations', + 'user_invitations', + 'connected_systems', + 'sampled_subjects', + 'exceptions', + 'audit_logs', + 'notifications', + 'organization_settings', + 'artifact_type_catalog', + 'workflow_templates', + ]), + ...getCrudPermissions([ + 'control_frameworks', + 'control_requirements', + 'identity_workflows', + 'evidence_models', + 'proof_packets', + 'remediation_items', + 'access_reviews', + 'access_review_items', + ]), + 'READ_ARTIFACTS', + 'UPDATE_ARTIFACTS', + 'CREATE_SEARCH', + ], + security_manager: [ + ...getReadPermissions([ + 'users', + 'roles', + 'organizations', + 'control_frameworks', + 'control_requirements', + 'evidence_models', + 'proof_packets', + 'sampled_subjects', + 'notifications', + 'organization_settings', + 'artifact_type_catalog', + 'workflow_templates', + ]), + ...getCrudPermissions([ + 'connected_systems', + 'remediation_items', + 'exceptions', + ]), + 'READ_IDENTITY_WORKFLOWS', + 'UPDATE_IDENTITY_WORKFLOWS', + 'READ_ARTIFACTS', + 'UPDATE_ARTIFACTS', + 'READ_ACCESS_REVIEWS', + 'READ_ACCESS_REVIEW_ITEMS', + 'UPDATE_ACCESS_REVIEW_ITEMS', + 'READ_AUDIT_LOGS', + 'CREATE_SEARCH', + ], + iam_operator: [ + ...getReadPermissions([ + 'users', + 'roles', + 'organizations', + 'connected_systems', + 'control_frameworks', + 'control_requirements', + 'evidence_models', + 'notifications', + 'artifact_type_catalog', + 'workflow_templates', + ]), + 'READ_IDENTITY_WORKFLOWS', + 'UPDATE_IDENTITY_WORKFLOWS', + 'CREATE_ARTIFACTS', + 'READ_ARTIFACTS', + 'UPDATE_ARTIFACTS', + 'CREATE_SAMPLED_SUBJECTS', + 'READ_SAMPLED_SUBJECTS', + 'UPDATE_SAMPLED_SUBJECTS', + 'CREATE_PROOF_PACKETS', + 'READ_PROOF_PACKETS', + 'UPDATE_PROOF_PACKETS', + 'READ_ACCESS_REVIEWS', + 'READ_ACCESS_REVIEW_ITEMS', + 'UPDATE_ACCESS_REVIEW_ITEMS', + 'READ_EXCEPTIONS', + 'UPDATE_EXCEPTIONS', + 'CREATE_SEARCH', + ], + auditor: [ + ...getReadPermissions([ + 'users', + 'roles', + 'organizations', + 'control_frameworks', + 'control_requirements', + 'identity_workflows', + 'evidence_models', + 'artifacts', + 'proof_packets', + 'remediation_items', + 'access_reviews', + 'access_review_items', + 'exceptions', + 'audit_logs', + 'artifact_type_catalog', + 'workflow_templates', + ]), + 'CREATE_SEARCH', + ], + read_only_client: [ + ...getReadPermissions([ + 'organizations', + 'organization_settings', + 'proof_packets', + 'remediation_items', + 'access_reviews', + 'access_review_items', + ]), + 'CREATE_SEARCH', + ], + }; + + await queryInterface.bulkDelete( + 'rolesPermissionsPermissions', + { + roles_permissionsId: { + [Sequelize.Op.in]: managedRoleIds, + }, + }, + { transaction }, + ); + + const rolePermissionRows = []; + const createdAt = new Date(); + const updatedAt = new Date(); + + for (const [roleName, permissionNames] of Object.entries(permissionMatrix)) { + const roleId = roleIdsByName[roleName]; + const uniquePermissionNames = [...new Set(permissionNames)]; + + for (const permissionName of uniquePermissionNames) { + const permissionId = permissionIdsByName[permissionName]; + + if (!permissionId) { + throw new Error(`Missing permission '${permissionName}' while aligning '${roleName}'.`); + } + + rolePermissionRows.push({ + createdAt, + updatedAt, + roles_permissionsId: roleId, + permissionId, + }); + } + } + + await queryInterface.bulkInsert('rolesPermissionsPermissions', rolePermissionRows, { transaction }); + + const [organizationRows] = await queryInterface.sequelize.query( + `SELECT id, name FROM "organizations" WHERE "deletedAt" IS NULL ORDER BY "createdAt" ASC`, + { transaction }, + ); + + const primaryOrganizationId = organizationRows[0]?.id || null; + + if (!primaryOrganizationId) { + throw new Error('At least one organization is required to assign organization-scoped sample users.'); + } + + const adminHash = bcrypt.hashSync(config.admin_pass, config.bcrypt.saltRounds); + const userHash = bcrypt.hashSync(config.user_pass, config.bcrypt.saltRounds); + const [existingUsers] = await queryInterface.sequelize.query( + `SELECT id, email FROM "users" WHERE "deletedAt" IS NULL`, + { transaction }, + ); + const existingUsersByEmail = existingUsers.reduce((accumulator, user) => { + accumulator[user.email] = user; + return accumulator; + }, {}); + + const ensureUser = async ({ email, firstName, lastName, password, roleName }) => { + const roleId = roleIdsByName[roleName]; + const existingUser = existingUsersByEmail[email]; + + if (existingUser) { + await queryInterface.bulkUpdate( + 'users', + { + firstName, + lastName, + emailVerified: true, + provider: config.providers.LOCAL, + app_roleId: roleId, + organizationsId: roleName === 'super_admin' ? null : primaryOrganizationId, + updatedAt: new Date(), + }, + { id: existingUser.id }, + { transaction }, + ); + return; + } + + await queryInterface.bulkInsert( + 'users', + [ + { + id: Sequelize.Utils.toDefaultValue(Sequelize.UUIDV4()), + firstName, + lastName, + email, + emailVerified: true, + provider: config.providers.LOCAL, + password, + app_roleId: roleId, + organizationsId: roleName === 'super_admin' ? null : primaryOrganizationId, + createdAt: new Date(), + updatedAt: new Date(), + }, + ], + { transaction }, + ); + }; + + await ensureUser({ + email: 'super_admin@flatlogic.com', + firstName: 'Super', + lastName: 'Admin', + password: adminHash, + roleName: 'super_admin', + }); + await ensureUser({ + email: SAMPLE_USER_EMAILS.org_admin, + firstName: 'Organization', + lastName: 'Admin', + password: adminHash, + roleName: 'org_admin', + }); + await ensureUser({ + email: SAMPLE_USER_EMAILS.compliance_manager, + firstName: 'Compliance', + lastName: 'Manager', + password: userHash, + roleName: 'compliance_manager', + }); + await ensureUser({ + email: SAMPLE_USER_EMAILS.security_manager, + firstName: 'Security', + lastName: 'Manager', + password: userHash, + roleName: 'security_manager', + }); + await ensureUser({ + email: SAMPLE_USER_EMAILS.iam_operator, + firstName: 'IAM', + lastName: 'Operator', + password: userHash, + roleName: 'iam_operator', + }); + await ensureUser({ + email: SAMPLE_USER_EMAILS.auditor, + firstName: 'Audit', + lastName: 'Reviewer', + password: userHash, + roleName: 'auditor', + }); + await ensureUser({ + email: SAMPLE_USER_EMAILS.read_only_client, + firstName: 'Client', + lastName: 'Viewer', + password: userHash, + roleName: 'read_only_client', + }); + + await transaction.commit(); + } catch (error) { + await transaction.rollback(); + throw error; + } + }, + + async down() {}, +}; diff --git a/backend/src/routes/access_review_items.js b/backend/src/routes/access_review_items.js index 4132bb6..229d5f2 100644 --- a/backend/src/routes/access_review_items.js +++ b/backend/src/routes/access_review_items.js @@ -3,6 +3,7 @@ const express = require('express'); const Access_review_itemsService = require('../services/access_review_items'); const Access_review_itemsDBApi = require('../db/api/access_review_items'); +const TenantAccess = require('../db/api/tenantAccess'); const wrapAsync = require('../helpers').wrapAsync; const config = require('../config'); @@ -442,9 +443,12 @@ router.get('/autocomplete', async (req, res) => { router.get('/:id', wrapAsync(async (req, res) => { const payload = await Access_review_itemsDBApi.findBy( { id: req.params.id }, + { currentUser: req.currentUser }, ); - - + + if (!payload) { + throw TenantAccess.getNotFoundError(); + } res.status(200).send(payload); })); diff --git a/backend/src/routes/access_reviews.js b/backend/src/routes/access_reviews.js index e3229cc..b3dfc2b 100644 --- a/backend/src/routes/access_reviews.js +++ b/backend/src/routes/access_reviews.js @@ -3,6 +3,7 @@ const express = require('express'); const Access_reviewsService = require('../services/access_reviews'); const Access_reviewsDBApi = require('../db/api/access_reviews'); +const TenantAccess = require('../db/api/tenantAccess'); const wrapAsync = require('../helpers').wrapAsync; const config = require('../config'); @@ -439,9 +440,12 @@ router.get('/autocomplete', async (req, res) => { router.get('/:id', wrapAsync(async (req, res) => { const payload = await Access_reviewsDBApi.findBy( { id: req.params.id }, + { currentUser: req.currentUser }, ); - - + + if (!payload) { + throw TenantAccess.getNotFoundError(); + } res.status(200).send(payload); })); diff --git a/backend/src/routes/artifact_type_catalog.js b/backend/src/routes/artifact_type_catalog.js index cd465a8..a96e1af 100644 --- a/backend/src/routes/artifact_type_catalog.js +++ b/backend/src/routes/artifact_type_catalog.js @@ -3,6 +3,7 @@ const express = require('express'); const Artifact_type_catalogService = require('../services/artifact_type_catalog'); const Artifact_type_catalogDBApi = require('../db/api/artifact_type_catalog'); +const TenantAccess = require('../db/api/tenantAccess'); const wrapAsync = require('../helpers').wrapAsync; const config = require('../config'); @@ -431,9 +432,12 @@ router.get('/autocomplete', async (req, res) => { router.get('/:id', wrapAsync(async (req, res) => { const payload = await Artifact_type_catalogDBApi.findBy( { id: req.params.id }, + { currentUser: req.currentUser }, ); - - + + if (!payload) { + throw TenantAccess.getNotFoundError(); + } res.status(200).send(payload); })); diff --git a/backend/src/routes/artifacts.js b/backend/src/routes/artifacts.js index 5cb8c77..9ed9a92 100644 --- a/backend/src/routes/artifacts.js +++ b/backend/src/routes/artifacts.js @@ -3,6 +3,7 @@ const express = require('express'); const ArtifactsService = require('../services/artifacts'); const ArtifactsDBApi = require('../db/api/artifacts'); +const TenantAccess = require('../db/api/tenantAccess'); const wrapAsync = require('../helpers').wrapAsync; const config = require('../config'); @@ -448,9 +449,12 @@ router.get('/autocomplete', async (req, res) => { router.get('/:id', wrapAsync(async (req, res) => { const payload = await ArtifactsDBApi.findBy( { id: req.params.id }, + { currentUser: req.currentUser }, ); - - + + if (!payload) { + throw TenantAccess.getNotFoundError(); + } res.status(200).send(payload); })); diff --git a/backend/src/routes/audit_logs.js b/backend/src/routes/audit_logs.js index fdc4aa1..6a63cbc 100644 --- a/backend/src/routes/audit_logs.js +++ b/backend/src/routes/audit_logs.js @@ -3,6 +3,7 @@ const express = require('express'); const Audit_logsService = require('../services/audit_logs'); const Audit_logsDBApi = require('../db/api/audit_logs'); +const TenantAccess = require('../db/api/tenantAccess'); const wrapAsync = require('../helpers').wrapAsync; const config = require('../config'); @@ -445,9 +446,12 @@ router.get('/autocomplete', async (req, res) => { router.get('/:id', wrapAsync(async (req, res) => { const payload = await Audit_logsDBApi.findBy( { id: req.params.id }, + { currentUser: req.currentUser }, ); - - + + if (!payload) { + throw TenantAccess.getNotFoundError(); + } res.status(200).send(payload); })); diff --git a/backend/src/routes/connected_systems.js b/backend/src/routes/connected_systems.js index 4fc9983..60262b9 100644 --- a/backend/src/routes/connected_systems.js +++ b/backend/src/routes/connected_systems.js @@ -3,6 +3,7 @@ const express = require('express'); const Connected_systemsService = require('../services/connected_systems'); const Connected_systemsDBApi = require('../db/api/connected_systems'); +const TenantAccess = require('../db/api/tenantAccess'); const wrapAsync = require('../helpers').wrapAsync; const config = require('../config'); @@ -443,9 +444,12 @@ router.get('/autocomplete', async (req, res) => { router.get('/:id', wrapAsync(async (req, res) => { const payload = await Connected_systemsDBApi.findBy( { id: req.params.id }, + { currentUser: req.currentUser }, ); - - + + if (!payload) { + throw TenantAccess.getNotFoundError(); + } res.status(200).send(payload); })); diff --git a/backend/src/routes/control_frameworks.js b/backend/src/routes/control_frameworks.js index a6bd007..383a436 100644 --- a/backend/src/routes/control_frameworks.js +++ b/backend/src/routes/control_frameworks.js @@ -3,6 +3,7 @@ const express = require('express'); const Control_frameworksService = require('../services/control_frameworks'); const Control_frameworksDBApi = require('../db/api/control_frameworks'); +const TenantAccess = require('../db/api/tenantAccess'); const wrapAsync = require('../helpers').wrapAsync; const config = require('../config'); @@ -434,9 +435,12 @@ router.get('/autocomplete', async (req, res) => { router.get('/:id', wrapAsync(async (req, res) => { const payload = await Control_frameworksDBApi.findBy( { id: req.params.id }, + { currentUser: req.currentUser }, ); - - + + if (!payload) { + throw TenantAccess.getNotFoundError(); + } res.status(200).send(payload); })); diff --git a/backend/src/routes/control_requirements.js b/backend/src/routes/control_requirements.js index 739bb99..1b4b69c 100644 --- a/backend/src/routes/control_requirements.js +++ b/backend/src/routes/control_requirements.js @@ -3,6 +3,7 @@ const express = require('express'); const Control_requirementsService = require('../services/control_requirements'); const Control_requirementsDBApi = require('../db/api/control_requirements'); +const TenantAccess = require('../db/api/tenantAccess'); const wrapAsync = require('../helpers').wrapAsync; const config = require('../config'); @@ -440,9 +441,12 @@ router.get('/autocomplete', async (req, res) => { router.get('/:id', wrapAsync(async (req, res) => { const payload = await Control_requirementsDBApi.findBy( { id: req.params.id }, + { currentUser: req.currentUser }, ); - - + + if (!payload) { + throw TenantAccess.getNotFoundError(); + } res.status(200).send(payload); })); diff --git a/backend/src/routes/evidence_models.js b/backend/src/routes/evidence_models.js index c7c42ef..95c9496 100644 --- a/backend/src/routes/evidence_models.js +++ b/backend/src/routes/evidence_models.js @@ -3,6 +3,7 @@ const express = require('express'); const Evidence_modelsService = require('../services/evidence_models'); const Evidence_modelsDBApi = require('../db/api/evidence_models'); +const TenantAccess = require('../db/api/tenantAccess'); const wrapAsync = require('../helpers').wrapAsync; const config = require('../config'); @@ -438,9 +439,12 @@ router.get('/autocomplete', async (req, res) => { router.get('/:id', wrapAsync(async (req, res) => { const payload = await Evidence_modelsDBApi.findBy( { id: req.params.id }, + { currentUser: req.currentUser }, ); - - + + if (!payload) { + throw TenantAccess.getNotFoundError(); + } res.status(200).send(payload); })); diff --git a/backend/src/routes/exceptions.js b/backend/src/routes/exceptions.js index 8342430..3e51533 100644 --- a/backend/src/routes/exceptions.js +++ b/backend/src/routes/exceptions.js @@ -3,6 +3,7 @@ const express = require('express'); const ExceptionsService = require('../services/exceptions'); const ExceptionsDBApi = require('../db/api/exceptions'); +const TenantAccess = require('../db/api/tenantAccess'); const wrapAsync = require('../helpers').wrapAsync; const config = require('../config'); @@ -439,9 +440,12 @@ router.get('/autocomplete', async (req, res) => { router.get('/:id', wrapAsync(async (req, res) => { const payload = await ExceptionsDBApi.findBy( { id: req.params.id }, + { currentUser: req.currentUser }, ); - - + + if (!payload) { + throw TenantAccess.getNotFoundError(); + } res.status(200).send(payload); })); diff --git a/backend/src/routes/identity_workflows.js b/backend/src/routes/identity_workflows.js index de25703..15a0722 100644 --- a/backend/src/routes/identity_workflows.js +++ b/backend/src/routes/identity_workflows.js @@ -3,6 +3,7 @@ const express = require('express'); const Identity_workflowsService = require('../services/identity_workflows'); const Identity_workflowsDBApi = require('../db/api/identity_workflows'); +const TenantAccess = require('../db/api/tenantAccess'); const wrapAsync = require('../helpers').wrapAsync; const config = require('../config'); @@ -443,9 +444,12 @@ router.get('/autocomplete', async (req, res) => { router.get('/:id', wrapAsync(async (req, res) => { const payload = await Identity_workflowsDBApi.findBy( { id: req.params.id }, + { currentUser: req.currentUser }, ); - - + + if (!payload) { + throw TenantAccess.getNotFoundError(); + } res.status(200).send(payload); })); diff --git a/backend/src/routes/notifications.js b/backend/src/routes/notifications.js index 06f3fd5..61fa778 100644 --- a/backend/src/routes/notifications.js +++ b/backend/src/routes/notifications.js @@ -3,6 +3,7 @@ const express = require('express'); const NotificationsService = require('../services/notifications'); const NotificationsDBApi = require('../db/api/notifications'); +const TenantAccess = require('../db/api/tenantAccess'); const wrapAsync = require('../helpers').wrapAsync; const config = require('../config'); @@ -437,9 +438,12 @@ router.get('/autocomplete', async (req, res) => { router.get('/:id', wrapAsync(async (req, res) => { const payload = await NotificationsDBApi.findBy( { id: req.params.id }, + { currentUser: req.currentUser }, ); - - + + if (!payload) { + throw TenantAccess.getNotFoundError(); + } res.status(200).send(payload); })); diff --git a/backend/src/routes/organization_settings.js b/backend/src/routes/organization_settings.js index a03d9b4..b36662e 100644 --- a/backend/src/routes/organization_settings.js +++ b/backend/src/routes/organization_settings.js @@ -3,6 +3,7 @@ const express = require('express'); const Organization_settingsService = require('../services/organization_settings'); const Organization_settingsDBApi = require('../db/api/organization_settings'); +const TenantAccess = require('../db/api/tenantAccess'); const wrapAsync = require('../helpers').wrapAsync; const config = require('../config'); @@ -439,9 +440,12 @@ router.get('/autocomplete', async (req, res) => { router.get('/:id', wrapAsync(async (req, res) => { const payload = await Organization_settingsDBApi.findBy( { id: req.params.id }, + { currentUser: req.currentUser }, ); - - + + if (!payload) { + throw TenantAccess.getNotFoundError(); + } res.status(200).send(payload); })); diff --git a/backend/src/routes/organizations.js b/backend/src/routes/organizations.js index 6f96a1d..1e38816 100644 --- a/backend/src/routes/organizations.js +++ b/backend/src/routes/organizations.js @@ -3,6 +3,7 @@ const express = require('express'); const OrganizationsService = require('../services/organizations'); const OrganizationsDBApi = require('../db/api/organizations'); +const TenantAccess = require('../db/api/tenantAccess'); const wrapAsync = require('../helpers').wrapAsync; const config = require('../config'); @@ -428,9 +429,12 @@ router.get('/autocomplete', async (req, res) => { router.get('/:id', wrapAsync(async (req, res) => { const payload = await OrganizationsDBApi.findBy( { id: req.params.id }, + { currentUser: req.currentUser }, ); - - + + if (!payload) { + throw TenantAccess.getNotFoundError(); + } res.status(200).send(payload); })); diff --git a/backend/src/routes/proof_packets.js b/backend/src/routes/proof_packets.js index 3476350..5d2fca1 100644 --- a/backend/src/routes/proof_packets.js +++ b/backend/src/routes/proof_packets.js @@ -3,6 +3,7 @@ const express = require('express'); const Proof_packetsService = require('../services/proof_packets'); const Proof_packetsDBApi = require('../db/api/proof_packets'); +const TenantAccess = require('../db/api/tenantAccess'); const wrapAsync = require('../helpers').wrapAsync; const config = require('../config'); @@ -436,9 +437,12 @@ router.get('/autocomplete', async (req, res) => { router.get('/:id', wrapAsync(async (req, res) => { const payload = await Proof_packetsDBApi.findBy( { id: req.params.id }, + { currentUser: req.currentUser }, ); - - + + if (!payload) { + throw TenantAccess.getNotFoundError(); + } res.status(200).send(payload); })); diff --git a/backend/src/routes/remediation_items.js b/backend/src/routes/remediation_items.js index 42c9f33..3df9182 100644 --- a/backend/src/routes/remediation_items.js +++ b/backend/src/routes/remediation_items.js @@ -3,6 +3,7 @@ const express = require('express'); const Remediation_itemsService = require('../services/remediation_items'); const Remediation_itemsDBApi = require('../db/api/remediation_items'); +const TenantAccess = require('../db/api/tenantAccess'); const wrapAsync = require('../helpers').wrapAsync; const config = require('../config'); @@ -437,9 +438,12 @@ router.get('/autocomplete', async (req, res) => { router.get('/:id', wrapAsync(async (req, res) => { const payload = await Remediation_itemsDBApi.findBy( { id: req.params.id }, + { currentUser: req.currentUser }, ); - - + + if (!payload) { + throw TenantAccess.getNotFoundError(); + } res.status(200).send(payload); })); diff --git a/backend/src/routes/sampled_subjects.js b/backend/src/routes/sampled_subjects.js index 928f836..646b812 100644 --- a/backend/src/routes/sampled_subjects.js +++ b/backend/src/routes/sampled_subjects.js @@ -3,6 +3,7 @@ const express = require('express'); const Sampled_subjectsService = require('../services/sampled_subjects'); const Sampled_subjectsDBApi = require('../db/api/sampled_subjects'); +const TenantAccess = require('../db/api/tenantAccess'); const wrapAsync = require('../helpers').wrapAsync; const config = require('../config'); @@ -446,9 +447,12 @@ router.get('/autocomplete', async (req, res) => { router.get('/:id', wrapAsync(async (req, res) => { const payload = await Sampled_subjectsDBApi.findBy( { id: req.params.id }, + { currentUser: req.currentUser }, ); - - + + if (!payload) { + throw TenantAccess.getNotFoundError(); + } res.status(200).send(payload); })); diff --git a/backend/src/routes/user_invitations.js b/backend/src/routes/user_invitations.js index 0c84a05..021f134 100644 --- a/backend/src/routes/user_invitations.js +++ b/backend/src/routes/user_invitations.js @@ -3,6 +3,7 @@ const express = require('express'); const User_invitationsService = require('../services/user_invitations'); const User_invitationsDBApi = require('../db/api/user_invitations'); +const TenantAccess = require('../db/api/tenantAccess'); const wrapAsync = require('../helpers').wrapAsync; const config = require('../config'); @@ -436,9 +437,12 @@ router.get('/autocomplete', async (req, res) => { router.get('/:id', wrapAsync(async (req, res) => { const payload = await User_invitationsDBApi.findBy( { id: req.params.id }, + { currentUser: req.currentUser }, ); - - + + if (!payload) { + throw TenantAccess.getNotFoundError(); + } res.status(200).send(payload); })); diff --git a/backend/src/routes/users.js b/backend/src/routes/users.js index 69f227e..f87d15f 100644 --- a/backend/src/routes/users.js +++ b/backend/src/routes/users.js @@ -3,6 +3,7 @@ const express = require('express'); const UsersService = require('../services/users'); const UsersDBApi = require('../db/api/users'); +const TenantAccess = require('../db/api/tenantAccess'); const wrapAsync = require('../helpers').wrapAsync; const config = require('../config'); @@ -437,11 +438,14 @@ router.get('/autocomplete', async (req, res) => { router.get('/:id', wrapAsync(async (req, res) => { const payload = await UsersDBApi.findBy( { id: req.params.id }, + { currentUser: req.currentUser }, ); - - - delete payload.password; - + + if (!payload) { + throw TenantAccess.getNotFoundError(); + } + + delete payload.password; res.status(200).send(payload); })); diff --git a/backend/src/routes/workflow_templates.js b/backend/src/routes/workflow_templates.js index b62aa12..5b93ae1 100644 --- a/backend/src/routes/workflow_templates.js +++ b/backend/src/routes/workflow_templates.js @@ -3,6 +3,7 @@ const express = require('express'); const Workflow_templatesService = require('../services/workflow_templates'); const Workflow_templatesDBApi = require('../db/api/workflow_templates'); +const TenantAccess = require('../db/api/tenantAccess'); const wrapAsync = require('../helpers').wrapAsync; const config = require('../config'); @@ -439,9 +440,12 @@ router.get('/autocomplete', async (req, res) => { router.get('/:id', wrapAsync(async (req, res) => { const payload = await Workflow_templatesDBApi.findBy( { id: req.params.id }, + { currentUser: req.currentUser }, ); - - + + if (!payload) { + throw TenantAccess.getNotFoundError(); + } res.status(200).send(payload); })); diff --git a/backend/src/services/access_review_items.js b/backend/src/services/access_review_items.js index e589eb3..c9e3aa1 100644 --- a/backend/src/services/access_review_items.js +++ b/backend/src/services/access_review_items.js @@ -2,6 +2,7 @@ const db = require('../db/models'); const Access_review_itemsDBApi = require('../db/api/access_review_items'); const processFile = require("../middlewares/upload"); const ValidationError = require('./notifications/errors/validation'); +const TenantAccess = require('../db/api/tenantAccess'); const csv = require('csv-parser'); const axios = require('axios'); const config = require('../config'); @@ -70,13 +71,11 @@ module.exports = class Access_review_itemsService { try { let access_review_items = await Access_review_itemsDBApi.findBy( {id}, - {transaction}, + {transaction, currentUser}, ); if (!access_review_items) { - throw new ValidationError( - 'access_review_itemsNotFound', - ); + throw TenantAccess.getNotFoundError(); } const updatedAccess_review_items = await Access_review_itemsDBApi.update( diff --git a/backend/src/services/access_reviews.js b/backend/src/services/access_reviews.js index a50dca2..fcbe112 100644 --- a/backend/src/services/access_reviews.js +++ b/backend/src/services/access_reviews.js @@ -2,6 +2,7 @@ const db = require('../db/models'); const Access_reviewsDBApi = require('../db/api/access_reviews'); const processFile = require("../middlewares/upload"); const ValidationError = require('./notifications/errors/validation'); +const TenantAccess = require('../db/api/tenantAccess'); const csv = require('csv-parser'); const axios = require('axios'); const config = require('../config'); @@ -70,13 +71,11 @@ module.exports = class Access_reviewsService { try { let access_reviews = await Access_reviewsDBApi.findBy( {id}, - {transaction}, + {transaction, currentUser}, ); if (!access_reviews) { - throw new ValidationError( - 'access_reviewsNotFound', - ); + throw TenantAccess.getNotFoundError(); } const updatedAccess_reviews = await Access_reviewsDBApi.update( diff --git a/backend/src/services/artifact_type_catalog.js b/backend/src/services/artifact_type_catalog.js index 63e748f..818130d 100644 --- a/backend/src/services/artifact_type_catalog.js +++ b/backend/src/services/artifact_type_catalog.js @@ -2,6 +2,7 @@ const db = require('../db/models'); const Artifact_type_catalogDBApi = require('../db/api/artifact_type_catalog'); const processFile = require("../middlewares/upload"); const ValidationError = require('./notifications/errors/validation'); +const TenantAccess = require('../db/api/tenantAccess'); const csv = require('csv-parser'); const axios = require('axios'); const config = require('../config'); @@ -70,13 +71,11 @@ module.exports = class Artifact_type_catalogService { try { let artifact_type_catalog = await Artifact_type_catalogDBApi.findBy( {id}, - {transaction}, + {transaction, currentUser}, ); if (!artifact_type_catalog) { - throw new ValidationError( - 'artifact_type_catalogNotFound', - ); + throw TenantAccess.getNotFoundError(); } const updatedArtifact_type_catalog = await Artifact_type_catalogDBApi.update( diff --git a/backend/src/services/artifacts.js b/backend/src/services/artifacts.js index 6a1377e..a60f63d 100644 --- a/backend/src/services/artifacts.js +++ b/backend/src/services/artifacts.js @@ -2,6 +2,7 @@ const db = require('../db/models'); const ArtifactsDBApi = require('../db/api/artifacts'); const processFile = require("../middlewares/upload"); const ValidationError = require('./notifications/errors/validation'); +const TenantAccess = require('../db/api/tenantAccess'); const csv = require('csv-parser'); const axios = require('axios'); const config = require('../config'); @@ -70,13 +71,11 @@ module.exports = class ArtifactsService { try { let artifacts = await ArtifactsDBApi.findBy( {id}, - {transaction}, + {transaction, currentUser}, ); if (!artifacts) { - throw new ValidationError( - 'artifactsNotFound', - ); + throw TenantAccess.getNotFoundError(); } const updatedArtifacts = await ArtifactsDBApi.update( diff --git a/backend/src/services/audit_logs.js b/backend/src/services/audit_logs.js index 26f6285..9960c89 100644 --- a/backend/src/services/audit_logs.js +++ b/backend/src/services/audit_logs.js @@ -2,6 +2,7 @@ const db = require('../db/models'); const Audit_logsDBApi = require('../db/api/audit_logs'); const processFile = require("../middlewares/upload"); const ValidationError = require('./notifications/errors/validation'); +const TenantAccess = require('../db/api/tenantAccess'); const csv = require('csv-parser'); const axios = require('axios'); const config = require('../config'); @@ -70,13 +71,11 @@ module.exports = class Audit_logsService { try { let audit_logs = await Audit_logsDBApi.findBy( {id}, - {transaction}, + {transaction, currentUser}, ); if (!audit_logs) { - throw new ValidationError( - 'audit_logsNotFound', - ); + throw TenantAccess.getNotFoundError(); } const updatedAudit_logs = await Audit_logsDBApi.update( diff --git a/backend/src/services/connected_systems.js b/backend/src/services/connected_systems.js index 2b935b1..79ceaa7 100644 --- a/backend/src/services/connected_systems.js +++ b/backend/src/services/connected_systems.js @@ -2,6 +2,7 @@ const db = require('../db/models'); const Connected_systemsDBApi = require('../db/api/connected_systems'); const processFile = require("../middlewares/upload"); const ValidationError = require('./notifications/errors/validation'); +const TenantAccess = require('../db/api/tenantAccess'); const csv = require('csv-parser'); const axios = require('axios'); const config = require('../config'); @@ -70,13 +71,11 @@ module.exports = class Connected_systemsService { try { let connected_systems = await Connected_systemsDBApi.findBy( {id}, - {transaction}, + {transaction, currentUser}, ); if (!connected_systems) { - throw new ValidationError( - 'connected_systemsNotFound', - ); + throw TenantAccess.getNotFoundError(); } const updatedConnected_systems = await Connected_systemsDBApi.update( diff --git a/backend/src/services/control_frameworks.js b/backend/src/services/control_frameworks.js index 1a27fa0..ff2cec3 100644 --- a/backend/src/services/control_frameworks.js +++ b/backend/src/services/control_frameworks.js @@ -2,6 +2,7 @@ const db = require('../db/models'); const Control_frameworksDBApi = require('../db/api/control_frameworks'); const processFile = require("../middlewares/upload"); const ValidationError = require('./notifications/errors/validation'); +const TenantAccess = require('../db/api/tenantAccess'); const csv = require('csv-parser'); const axios = require('axios'); const config = require('../config'); @@ -70,13 +71,11 @@ module.exports = class Control_frameworksService { try { let control_frameworks = await Control_frameworksDBApi.findBy( {id}, - {transaction}, + {transaction, currentUser}, ); if (!control_frameworks) { - throw new ValidationError( - 'control_frameworksNotFound', - ); + throw TenantAccess.getNotFoundError(); } const updatedControl_frameworks = await Control_frameworksDBApi.update( diff --git a/backend/src/services/control_requirements.js b/backend/src/services/control_requirements.js index dcb6e13..c033987 100644 --- a/backend/src/services/control_requirements.js +++ b/backend/src/services/control_requirements.js @@ -2,6 +2,7 @@ const db = require('../db/models'); const Control_requirementsDBApi = require('../db/api/control_requirements'); const processFile = require("../middlewares/upload"); const ValidationError = require('./notifications/errors/validation'); +const TenantAccess = require('../db/api/tenantAccess'); const csv = require('csv-parser'); const axios = require('axios'); const config = require('../config'); @@ -70,13 +71,11 @@ module.exports = class Control_requirementsService { try { let control_requirements = await Control_requirementsDBApi.findBy( {id}, - {transaction}, + {transaction, currentUser}, ); if (!control_requirements) { - throw new ValidationError( - 'control_requirementsNotFound', - ); + throw TenantAccess.getNotFoundError(); } const updatedControl_requirements = await Control_requirementsDBApi.update( diff --git a/backend/src/services/evidence_models.js b/backend/src/services/evidence_models.js index 8b84d4e..20b95de 100644 --- a/backend/src/services/evidence_models.js +++ b/backend/src/services/evidence_models.js @@ -2,6 +2,7 @@ const db = require('../db/models'); const Evidence_modelsDBApi = require('../db/api/evidence_models'); const processFile = require("../middlewares/upload"); const ValidationError = require('./notifications/errors/validation'); +const TenantAccess = require('../db/api/tenantAccess'); const csv = require('csv-parser'); const axios = require('axios'); const config = require('../config'); @@ -70,13 +71,11 @@ module.exports = class Evidence_modelsService { try { let evidence_models = await Evidence_modelsDBApi.findBy( {id}, - {transaction}, + {transaction, currentUser}, ); if (!evidence_models) { - throw new ValidationError( - 'evidence_modelsNotFound', - ); + throw TenantAccess.getNotFoundError(); } const updatedEvidence_models = await Evidence_modelsDBApi.update( diff --git a/backend/src/services/exceptions.js b/backend/src/services/exceptions.js index 6872f91..abddcc2 100644 --- a/backend/src/services/exceptions.js +++ b/backend/src/services/exceptions.js @@ -2,6 +2,7 @@ const db = require('../db/models'); const ExceptionsDBApi = require('../db/api/exceptions'); const processFile = require("../middlewares/upload"); const ValidationError = require('./notifications/errors/validation'); +const TenantAccess = require('../db/api/tenantAccess'); const csv = require('csv-parser'); const axios = require('axios'); const config = require('../config'); @@ -70,13 +71,11 @@ module.exports = class ExceptionsService { try { let exceptions = await ExceptionsDBApi.findBy( {id}, - {transaction}, + {transaction, currentUser}, ); if (!exceptions) { - throw new ValidationError( - 'exceptionsNotFound', - ); + throw TenantAccess.getNotFoundError(); } const updatedExceptions = await ExceptionsDBApi.update( diff --git a/backend/src/services/identity_workflows.js b/backend/src/services/identity_workflows.js index c78b242..7c307bc 100644 --- a/backend/src/services/identity_workflows.js +++ b/backend/src/services/identity_workflows.js @@ -2,6 +2,7 @@ const db = require('../db/models'); const Identity_workflowsDBApi = require('../db/api/identity_workflows'); const processFile = require("../middlewares/upload"); const ValidationError = require('./notifications/errors/validation'); +const TenantAccess = require('../db/api/tenantAccess'); const csv = require('csv-parser'); const axios = require('axios'); const config = require('../config'); @@ -70,13 +71,11 @@ module.exports = class Identity_workflowsService { try { let identity_workflows = await Identity_workflowsDBApi.findBy( {id}, - {transaction}, + {transaction, currentUser}, ); if (!identity_workflows) { - throw new ValidationError( - 'identity_workflowsNotFound', - ); + throw TenantAccess.getNotFoundError(); } const updatedIdentity_workflows = await Identity_workflowsDBApi.update( diff --git a/backend/src/services/notifications.js b/backend/src/services/notifications.js index 0aa0f9c..28c0ed7 100644 --- a/backend/src/services/notifications.js +++ b/backend/src/services/notifications.js @@ -2,6 +2,7 @@ const db = require('../db/models'); const NotificationsDBApi = require('../db/api/notifications'); const processFile = require("../middlewares/upload"); const ValidationError = require('./notifications/errors/validation'); +const TenantAccess = require('../db/api/tenantAccess'); const csv = require('csv-parser'); const axios = require('axios'); const config = require('../config'); @@ -70,13 +71,11 @@ module.exports = class NotificationsService { try { let notifications = await NotificationsDBApi.findBy( {id}, - {transaction}, + {transaction, currentUser}, ); if (!notifications) { - throw new ValidationError( - 'notificationsNotFound', - ); + throw TenantAccess.getNotFoundError(); } const updatedNotifications = await NotificationsDBApi.update( diff --git a/backend/src/services/organization_settings.js b/backend/src/services/organization_settings.js index 825c62d..b375480 100644 --- a/backend/src/services/organization_settings.js +++ b/backend/src/services/organization_settings.js @@ -2,6 +2,7 @@ const db = require('../db/models'); const Organization_settingsDBApi = require('../db/api/organization_settings'); const processFile = require("../middlewares/upload"); const ValidationError = require('./notifications/errors/validation'); +const TenantAccess = require('../db/api/tenantAccess'); const csv = require('csv-parser'); const axios = require('axios'); const config = require('../config'); @@ -70,13 +71,11 @@ module.exports = class Organization_settingsService { try { let organization_settings = await Organization_settingsDBApi.findBy( {id}, - {transaction}, + {transaction, currentUser}, ); if (!organization_settings) { - throw new ValidationError( - 'organization_settingsNotFound', - ); + throw TenantAccess.getNotFoundError(); } const updatedOrganization_settings = await Organization_settingsDBApi.update( diff --git a/backend/src/services/organizations.js b/backend/src/services/organizations.js index 5dafbb9..2e121a1 100644 --- a/backend/src/services/organizations.js +++ b/backend/src/services/organizations.js @@ -2,6 +2,7 @@ const db = require('../db/models'); const OrganizationsDBApi = require('../db/api/organizations'); const processFile = require("../middlewares/upload"); const ValidationError = require('./notifications/errors/validation'); +const TenantAccess = require('../db/api/tenantAccess'); const csv = require('csv-parser'); const axios = require('axios'); const config = require('../config'); @@ -70,13 +71,11 @@ module.exports = class OrganizationsService { try { let organizations = await OrganizationsDBApi.findBy( {id}, - {transaction}, + {transaction, currentUser}, ); if (!organizations) { - throw new ValidationError( - 'organizationsNotFound', - ); + throw TenantAccess.getNotFoundError(); } const updatedOrganizations = await OrganizationsDBApi.update( diff --git a/backend/src/services/proof_packets.js b/backend/src/services/proof_packets.js index 6ef6819..76bc675 100644 --- a/backend/src/services/proof_packets.js +++ b/backend/src/services/proof_packets.js @@ -2,6 +2,7 @@ const db = require('../db/models'); const Proof_packetsDBApi = require('../db/api/proof_packets'); const processFile = require("../middlewares/upload"); const ValidationError = require('./notifications/errors/validation'); +const TenantAccess = require('../db/api/tenantAccess'); const csv = require('csv-parser'); const axios = require('axios'); const config = require('../config'); @@ -70,13 +71,11 @@ module.exports = class Proof_packetsService { try { let proof_packets = await Proof_packetsDBApi.findBy( {id}, - {transaction}, + {transaction, currentUser}, ); if (!proof_packets) { - throw new ValidationError( - 'proof_packetsNotFound', - ); + throw TenantAccess.getNotFoundError(); } const updatedProof_packets = await Proof_packetsDBApi.update( diff --git a/backend/src/services/remediation_items.js b/backend/src/services/remediation_items.js index db7a31e..54ea652 100644 --- a/backend/src/services/remediation_items.js +++ b/backend/src/services/remediation_items.js @@ -2,6 +2,7 @@ const db = require('../db/models'); const Remediation_itemsDBApi = require('../db/api/remediation_items'); const processFile = require("../middlewares/upload"); const ValidationError = require('./notifications/errors/validation'); +const TenantAccess = require('../db/api/tenantAccess'); const csv = require('csv-parser'); const axios = require('axios'); const config = require('../config'); @@ -70,13 +71,11 @@ module.exports = class Remediation_itemsService { try { let remediation_items = await Remediation_itemsDBApi.findBy( {id}, - {transaction}, + {transaction, currentUser}, ); if (!remediation_items) { - throw new ValidationError( - 'remediation_itemsNotFound', - ); + throw TenantAccess.getNotFoundError(); } const updatedRemediation_items = await Remediation_itemsDBApi.update( diff --git a/backend/src/services/sampled_subjects.js b/backend/src/services/sampled_subjects.js index fc2a474..16ed0d7 100644 --- a/backend/src/services/sampled_subjects.js +++ b/backend/src/services/sampled_subjects.js @@ -2,6 +2,7 @@ const db = require('../db/models'); const Sampled_subjectsDBApi = require('../db/api/sampled_subjects'); const processFile = require("../middlewares/upload"); const ValidationError = require('./notifications/errors/validation'); +const TenantAccess = require('../db/api/tenantAccess'); const csv = require('csv-parser'); const axios = require('axios'); const config = require('../config'); @@ -70,13 +71,11 @@ module.exports = class Sampled_subjectsService { try { let sampled_subjects = await Sampled_subjectsDBApi.findBy( {id}, - {transaction}, + {transaction, currentUser}, ); if (!sampled_subjects) { - throw new ValidationError( - 'sampled_subjectsNotFound', - ); + throw TenantAccess.getNotFoundError(); } const updatedSampled_subjects = await Sampled_subjectsDBApi.update( diff --git a/backend/src/services/user_invitations.js b/backend/src/services/user_invitations.js index 7186764..69b1ce4 100644 --- a/backend/src/services/user_invitations.js +++ b/backend/src/services/user_invitations.js @@ -2,6 +2,7 @@ const db = require('../db/models'); const User_invitationsDBApi = require('../db/api/user_invitations'); const processFile = require("../middlewares/upload"); const ValidationError = require('./notifications/errors/validation'); +const TenantAccess = require('../db/api/tenantAccess'); const csv = require('csv-parser'); const axios = require('axios'); const config = require('../config'); @@ -70,13 +71,11 @@ module.exports = class User_invitationsService { try { let user_invitations = await User_invitationsDBApi.findBy( {id}, - {transaction}, + {transaction, currentUser}, ); if (!user_invitations) { - throw new ValidationError( - 'user_invitationsNotFound', - ); + throw TenantAccess.getNotFoundError(); } const updatedUser_invitations = await User_invitationsDBApi.update( diff --git a/backend/src/services/users.js b/backend/src/services/users.js index 41f8220..9a47861 100644 --- a/backend/src/services/users.js +++ b/backend/src/services/users.js @@ -2,6 +2,7 @@ const db = require('../db/models'); const UsersDBApi = require('../db/api/users'); const processFile = require("../middlewares/upload"); const ValidationError = require('./notifications/errors/validation'); +const TenantAccess = require('../db/api/tenantAccess'); const csv = require('csv-parser'); const axios = require('axios'); const config = require('../config'); @@ -114,13 +115,11 @@ module.exports = class UsersService { try { let users = await UsersDBApi.findBy( {id}, - {transaction}, + {transaction, currentUser}, ); if (!users) { - throw new ValidationError( - 'iam.errors.userNotFound', - ); + throw TenantAccess.getNotFoundError(); } const updatedUser = await UsersDBApi.update( diff --git a/backend/src/services/workflow_templates.js b/backend/src/services/workflow_templates.js index 75cbc96..5b35974 100644 --- a/backend/src/services/workflow_templates.js +++ b/backend/src/services/workflow_templates.js @@ -2,6 +2,7 @@ const db = require('../db/models'); const Workflow_templatesDBApi = require('../db/api/workflow_templates'); const processFile = require("../middlewares/upload"); const ValidationError = require('./notifications/errors/validation'); +const TenantAccess = require('../db/api/tenantAccess'); const csv = require('csv-parser'); const axios = require('axios'); const config = require('../config'); @@ -70,13 +71,11 @@ module.exports = class Workflow_templatesService { try { let workflow_templates = await Workflow_templatesDBApi.findBy( {id}, - {transaction}, + {transaction, currentUser}, ); if (!workflow_templates) { - throw new ValidationError( - 'workflow_templatesNotFound', - ); + throw TenantAccess.getNotFoundError(); } const updatedWorkflow_templates = await Workflow_templatesDBApi.update(