From 664aea56a604b242e68a67257c3b3959d6f9cd6b Mon Sep 17 00:00:00 2001
From: Jack Flores
Date: Wed, 24 Jul 2024 15:58:19 -0400
Subject: [PATCH 01/21] 1258 first draft, one test failing
---
src/controller/org.controller/index.js | 2 +-
.../org.controller/org.controller.js | 105 ++++++++++--------
src/middleware/middleware.js | 32 ++++++
src/model/org.js | 3 +-
test/integration-tests/org/putOrgTest.js | 58 ++++++++++
5 files changed, 152 insertions(+), 48 deletions(-)
create mode 100644 test/integration-tests/org/putOrgTest.js
diff --git a/src/controller/org.controller/index.js b/src/controller/org.controller/index.js
index 15a160a62..abbac143f 100644
--- a/src/controller/org.controller/index.js
+++ b/src/controller/org.controller/index.js
@@ -309,7 +309,7 @@ router.put('/org/:shortname',
}
*/
mw.validateUser,
- mw.onlySecretariat,
+ mw.validateOrg,
query().custom((query) => { return mw.validateQueryParameterNames(query, ['new_short_name', 'id_quota', 'name', 'active_roles.add', 'active_roles.remove']) }),
query(['new_short_name', 'id_quota', 'name', 'active_roles.add', 'active_roles.remove']).custom((val) => { return mw.containsNoInvalidCharacters(val) }),
param(['shortname']).isString().trim().isLength({ min: CONSTANTS.MIN_SHORTNAME_LENGTH, max: CONSTANTS.MAX_SHORTNAME_LENGTH }),
diff --git a/src/controller/org.controller/org.controller.js b/src/controller/org.controller/org.controller.js
index d1a094b57..fd87893c2 100644
--- a/src/controller/org.controller/org.controller.js
+++ b/src/controller/org.controller/org.controller.js
@@ -322,6 +322,7 @@ async function createOrg (req, res, next) {
* Called by PUT /api/org/{shortname}
**/
async function updateOrg (req, res, next) {
+ console.log("in controller") // todo: delete
try {
const shortName = req.ctx.params.shortname
const newOrg = new Org()
@@ -329,67 +330,77 @@ async function updateOrg (req, res, next) {
const addRoles = []
const orgRepo = req.ctx.repositories.getOrgRepository()
const org = await orgRepo.findOneByShortName(shortName)
+ const orgMakingChanges = req.ctx.org
let agt = setAggregateOrgObj({ short_name: shortName })
+ logger.info({uuid: req.ctx.uuid, message: 'UPDATING AN ORG'})
+
+
// org doesn't exist
if (!org) {
logger.info({ uuid: req.ctx.uuid, message: shortName + ' organization could not be updated in MongoDB because it does not exist.' })
return res.status(404).json(error.orgDnePathParam(shortName))
}
- Object.keys(req.ctx.query).forEach(k => {
- const key = k.toLowerCase()
-
- if (key === 'new_short_name') {
- newOrg.short_name = req.ctx.query.new_short_name
- agt = setAggregateOrgObj({ short_name: newOrg.short_name })
- } else if (key === 'name') {
- newOrg.name = req.ctx.query.name
- } else if (key === 'id_quota') {
- newOrg.policies.id_quota = req.ctx.query.id_quota
- } else if (key === 'active_roles.add') {
- if (Array.isArray(req.ctx.query['active_roles.add'])) {
- req.ctx.query['active_roles.add'].forEach(r => {
- addRoles.push(r)
- })
- }
- } else if (key === 'active_roles.remove') {
- if (Array.isArray(req.ctx.query['active_roles.remove'])) {
- req.ctx.query['active_roles.remove'].forEach(r => {
- removeRoles.push(r)
- })
+ newOrg.last_active = Date.now()
+
+ const isSec = await orgRepo.isSecretariat(orgMakingChanges)
+
+ if (isSec) {
+ Object.keys(req.ctx.query).forEach(k => {
+ const key = k.toLowerCase()
+
+ if (key === 'new_short_name') {
+ newOrg.short_name = req.ctx.query.new_short_name
+ agt = setAggregateOrgObj({ short_name: newOrg.short_name })
+ } else if (key === 'name') {
+ newOrg.name = req.ctx.query.name
+ } else if (key === 'id_quota') {
+ newOrg.policies.id_quota = req.ctx.query.id_quota
+ } else if (key === 'active_roles.add') {
+ if (Array.isArray(req.ctx.query['active_roles.add'])) {
+ req.ctx.query['active_roles.add'].forEach(r => {
+ addRoles.push(r)
+ })
+ }
+ } else if (key === 'active_roles.remove') {
+ if (Array.isArray(req.ctx.query['active_roles.remove'])) {
+ req.ctx.query['active_roles.remove'].forEach(r => {
+ removeRoles.push(r)
+ })
+ }
}
- }
- })
+ })
- // updating the org's roles
- if (org) {
- const roles = org.authority.active_roles
+ // updating the org's roles
+ if (org) {
+ const roles = org.authority.active_roles
- // adding roles
- addRoles.forEach(role => {
- if (!roles.includes(role)) {
- roles.push(role)
- }
- })
+ // adding roles
+ addRoles.forEach(role => {
+ if (!roles.includes(role)) {
+ roles.push(role)
+ }
+ })
- // removing roles
- removeRoles.forEach(role => {
- const index = roles.indexOf(role)
+ // removing roles
+ removeRoles.forEach(role => {
+ const index = roles.indexOf(role)
- if (index > -1) {
- roles.splice(index, 1)
- }
- })
+ if (index > -1) {
+ roles.splice(index, 1)
+ }
+ })
- newOrg.authority.active_roles = roles
- }
+ newOrg.authority.active_roles = roles
+ }
- if (newOrg.short_name) {
- const result = await orgRepo.findOneByShortName(newOrg.short_name)
+ if (newOrg.short_name) {
+ const result = await orgRepo.findOneByShortName(newOrg.short_name)
- if (result) {
- return res.status(403).json(error.duplicateShortname(newOrg.short_name))
+ if (result) {
+ return res.status(403).json(error.duplicateShortname(newOrg.short_name))
+ }
}
}
@@ -420,6 +431,7 @@ async function updateOrg (req, res, next) {
logger.info(JSON.stringify(payload))
return res.status(200).json(responseMessage)
} catch (err) {
+ console.log("err in congtroller: " + err) // todo: delete
next(err)
}
}
@@ -819,7 +831,8 @@ function setAggregateOrgObj (query) {
name: true,
'authority.active_roles': true,
'policies.id_quota': true,
- time: true
+ time: true,
+ last_active: true
}
}
]
diff --git a/src/middleware/middleware.js b/src/middleware/middleware.js
index ed4972195..d83f19927 100644
--- a/src/middleware/middleware.js
+++ b/src/middleware/middleware.js
@@ -107,23 +107,27 @@ async function validateUser (req, res, next) {
logger.info({ uuid: req.ctx.uuid, message: 'Authenticating user: ' + user }) // userUUID may be null if user does not exist
const orgUUID = await orgRepo.getOrgUUID(org)
if (!orgUUID) {
+ console.log("401 1: " + org + " is was not in db ") // todo: delete
logger.info({ uuid: req.ctx.uuid, message: org + ' organization does not exist. User authentication FAILED for ' + user })
return res.status(401).json(error.unauthorized())
}
const result = await userRepo.findOneByUserNameAndOrgUUID(user, orgUUID)
if (!result) {
+ console.log("401 2") // todo: delete
logger.warn(JSON.stringify({ uuid: req.ctx.uuid, message: 'User not found. User authentication FAILED for ' + user }))
return res.status(401).json(error.unauthorized())
}
if (!result.active) {
+ console.log("401 3") // todo: delete
logger.warn(JSON.stringify({ uuid: req.ctx.uuid, message: 'User deactivated. Authentication failed for ' + user }))
return res.status(401).json(error.unauthorized())
}
const isPwd = await argon2.verify(result.secret, key)
if (!isPwd) {
+ console.log("401 4") // todo: delete
logger.warn(JSON.stringify({ uuid: req.ctx.uuid, message: 'Incorrect apikey. User authentication FAILED for ' + user }))
return res.status(401).json(error.unauthorized())
}
@@ -135,6 +139,33 @@ async function validateUser (req, res, next) {
}
}
+async function validateOrg (req, res, next) {
+ console.log("in middleware") // todo: delete
+ const org = req.ctx.org
+ const reqOrg = req.params.shortname
+ const orgRepo = req.ctx.repositories.getOrgRepository()
+ const CONSTANTS = getConstants()
+
+ try {
+ logger.info({ uuid: req.ctx.uuid, message: 'Authenticating org: ' + org })
+
+ const isSec = await orgRepo.isSecretariat(org)
+ if (!isSec) {
+ if (!(org == reqOrg)) {
+ console.log(org + " is not a sec and is not equal to " + reqOrg) // todo: delete
+ logger.info({ uuid: req.ctx.uuid, message: org + ' is not a ' + CONSTANTS.AUTH_ROLE_ENUM.SECRETARIAT + ' or the same as ' + reqOrg + ' and is not allowed to make these changes.' })
+ return res.status(401).json(error.unauthorized())
+ }
+ }
+
+ logger.info({ uuid: req.ctx.uuid, message: 'Confirmed ' + org + ' has the authority to make changes to ' + reqOrg })
+ next()
+ } catch (err) {
+ console.log("err in middle: " + err) // todo: delete
+ next(err)
+ }
+}
+
// Checks that the requester belongs to an org that has the 'BULK_DOWNLOAD' role
async function onlySecretariatOrBulkDownload (req, res, next) {
const org = req.ctx.org
@@ -483,6 +514,7 @@ module.exports = {
setCacheControl,
optionallyValidateUser,
validateUser,
+ validateOrg,
onlySecretariat,
onlySecretariatOrBulkDownload,
onlySecretariatOrAdmin,
diff --git a/src/model/org.js b/src/model/org.js
index 48f3b226c..2c0964dc1 100644
--- a/src/model/org.js
+++ b/src/model/org.js
@@ -24,7 +24,8 @@ const schema = {
created: Date,
modified: Date
},
- inUse: Boolean
+ inUse: Boolean,
+ last_active: Date
}
const OrgSchema = new mongoose.Schema(schema, { collection: 'Org', timestamps: { createdAt: 'time.created', updatedAt: 'time.modified' } })
diff --git a/test/integration-tests/org/putOrgTest.js b/test/integration-tests/org/putOrgTest.js
new file mode 100644
index 000000000..6924eeb6a
--- /dev/null
+++ b/test/integration-tests/org/putOrgTest.js
@@ -0,0 +1,58 @@
+const chai = require('chai')
+chai.use(require('chai-http'))
+const expect = chai.expect
+
+const constants = require('../constants.js')
+const app = require('../../../src/index.js')
+
+const params = {new_short_name: 'test_org', name: 'Test Organization', id_quota: '100000'}
+
+describe('Testing org put endpoint', () => {
+ context('Positive Tests', () => {
+ it('Allows update made by a secretariat to itself', async () => {
+ await chai.request(app)
+ .put('/api/org/mitre')
+ .set({ ...constants.headers })
+ .query(params)
+ .send()
+ .then((res, err) => {
+ console.log(res.text)
+ expect(res).to.have.status(200)
+ expect(res.body.updated.short_name).to.equal(constants.testOrg.short_name)
+ expect(err).to.be.undefined
+ })
+ })
+ it('Allows update made by a secretariat to another org', async () => {
+ await chai.request(app)
+ .put('/api/org/cause_8')
+ .set({ ...constants.headers })
+ .send()
+ .then((res, err) => {
+ expect(res).to.have.status(200)
+ expect(err).to.be.undefined
+ })
+ })
+ it('Allows update made by non secretariat org to itself', async () => {
+ await chai.request(app)
+ .put('/api/org/win_5')
+ .set({ ...constants.nonSecretariatUserHeaders })
+ .send()
+ .then((res, err) => {
+ expect(res).to.have.status(200)
+ expect(err).to.be.undefined
+ })
+ })
+ })
+ context('Negative Tests', () => {
+ it('Fails update made by a non-secretariat org to a different org', async () => {
+ await chai.request(app)
+ .put('/api/org/cause_8')
+ .set({ ...constants.nonSecretariatUserHeaders })
+ .send()
+ .then((res, err) => {
+ expect(res).to.have.status(401)
+ expect(err).to.be.undefined
+ })
+ })
+ })
+})
\ No newline at end of file
From a85cbb9e5826b1e674fdbf00ff9e13c886613ee3 Mon Sep 17 00:00:00 2001
From: jack-flores
Date: Fri, 26 Jul 2024 14:33:33 -0400
Subject: [PATCH 02/21] all tests passing, more tests to write
---
package-lock.json | 46 ++++++++++++------------
package.json | 1 +
src/middleware/middleware.js | 5 ---
test/integration-tests/org/putOrgTest.js | 6 ++--
4 files changed, 27 insertions(+), 31 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index ac792daf1..0aa408138 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "cve-services",
- "version": "2.3.3",
+ "version": "2.3.1",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "cve-services",
- "version": "2.3.3",
+ "version": "2.3.1",
"license": "(CC0)",
"dependencies": {
"ajv": "^8.6.2",
@@ -2023,12 +2023,12 @@
}
},
"node_modules/braces": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
- "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
+ "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
"dev": true,
"dependencies": {
- "fill-range": "^7.0.1"
+ "fill-range": "^7.1.1"
},
"engines": {
"node": ">=8"
@@ -3882,9 +3882,9 @@
}
},
"node_modules/fill-range": {
- "version": "7.0.1",
- "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
- "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
+ "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
"dev": true,
"dependencies": {
"to-regex-range": "^5.0.1"
@@ -4212,9 +4212,9 @@
}
},
"node_modules/get-func-name": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz",
- "integrity": "sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==",
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz",
+ "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==",
"dev": true,
"engines": {
"node": "*"
@@ -11906,12 +11906,12 @@
}
},
"braces": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
- "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
+ "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
"dev": true,
"requires": {
- "fill-range": "^7.0.1"
+ "fill-range": "^7.1.1"
}
},
"browser-stdout": {
@@ -13288,9 +13288,9 @@
}
},
"fill-range": {
- "version": "7.0.1",
- "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
- "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
+ "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
"dev": true,
"requires": {
"to-regex-range": "^5.0.1"
@@ -13534,9 +13534,9 @@
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="
},
"get-func-name": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz",
- "integrity": "sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==",
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz",
+ "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==",
"dev": true
},
"get-intrinsic": {
@@ -18194,4 +18194,4 @@
"dev": true
}
}
-}
\ No newline at end of file
+}
diff --git a/package.json b/package.json
index 2bc2cb1c1..e733d223a 100644
--- a/package.json
+++ b/package.json
@@ -96,6 +96,7 @@
"swagger-autogen": "node src/swagger.js",
"test": "NODE_ENV=test mocha --recursive --exit || true",
"test:integration": "NODE_ENV=test node-dev src/scripts/populate.js y; NODE_ENV=test mocha test/integration-tests --recursive --exit",
+ "test:put-org": "NODE_ENV=test node-dev src/scripts/populate.js y; NODE_ENV=test mocha test/integration-tests/org/putOrgTest.js --recursive --exit",
"test:unit-tests": "NODE_ENV=test mocha test/unit-tests --recursive --exit || true",
"test:coverage": "NODE_ENV=test nyc --reporter=text mocha src/* --recursive --exit || true",
"test:coverage-html": "NODE_ENV=test nyc --reporter=html mocha src/* --recursive --exit || true",
diff --git a/src/middleware/middleware.js b/src/middleware/middleware.js
index d83f19927..8b0d67dab 100644
--- a/src/middleware/middleware.js
+++ b/src/middleware/middleware.js
@@ -114,20 +114,17 @@ async function validateUser (req, res, next) {
const result = await userRepo.findOneByUserNameAndOrgUUID(user, orgUUID)
if (!result) {
- console.log("401 2") // todo: delete
logger.warn(JSON.stringify({ uuid: req.ctx.uuid, message: 'User not found. User authentication FAILED for ' + user }))
return res.status(401).json(error.unauthorized())
}
if (!result.active) {
- console.log("401 3") // todo: delete
logger.warn(JSON.stringify({ uuid: req.ctx.uuid, message: 'User deactivated. Authentication failed for ' + user }))
return res.status(401).json(error.unauthorized())
}
const isPwd = await argon2.verify(result.secret, key)
if (!isPwd) {
- console.log("401 4") // todo: delete
logger.warn(JSON.stringify({ uuid: req.ctx.uuid, message: 'Incorrect apikey. User authentication FAILED for ' + user }))
return res.status(401).json(error.unauthorized())
}
@@ -140,7 +137,6 @@ async function validateUser (req, res, next) {
}
async function validateOrg (req, res, next) {
- console.log("in middleware") // todo: delete
const org = req.ctx.org
const reqOrg = req.params.shortname
const orgRepo = req.ctx.repositories.getOrgRepository()
@@ -161,7 +157,6 @@ async function validateOrg (req, res, next) {
logger.info({ uuid: req.ctx.uuid, message: 'Confirmed ' + org + ' has the authority to make changes to ' + reqOrg })
next()
} catch (err) {
- console.log("err in middle: " + err) // todo: delete
next(err)
}
}
diff --git a/test/integration-tests/org/putOrgTest.js b/test/integration-tests/org/putOrgTest.js
index 6924eeb6a..d865d231a 100644
--- a/test/integration-tests/org/putOrgTest.js
+++ b/test/integration-tests/org/putOrgTest.js
@@ -5,7 +5,7 @@ const expect = chai.expect
const constants = require('../constants.js')
const app = require('../../../src/index.js')
-const params = {new_short_name: 'test_org', name: 'Test Organization', id_quota: '100000'}
+const params = {new_short_name: 'test_org', name: 'Test Organization', id_quota: 100000}
describe('Testing org put endpoint', () => {
context('Positive Tests', () => {
@@ -13,12 +13,12 @@ describe('Testing org put endpoint', () => {
await chai.request(app)
.put('/api/org/mitre')
.set({ ...constants.headers })
- .query(params)
+ .query({id_quota: '100000'})
.send()
.then((res, err) => {
console.log(res.text)
expect(res).to.have.status(200)
- expect(res.body.updated.short_name).to.equal(constants.testOrg.short_name)
+ expect(res.body.updated.policies.id_quota).to.equal(params.id_quota)
expect(err).to.be.undefined
})
})
From f967daa4570567bd77c1718640041252f1f6d3c4 Mon Sep 17 00:00:00 2001
From: jack-flores
Date: Mon, 29 Jul 2024 14:29:15 -0400
Subject: [PATCH 03/21] #1258 all tests passing
---
.../org.controller/org.controller.js | 2 -
src/middleware/middleware.js | 2 -
test/integration-tests/org/putOrgTest.js | 57 +++++++++++++++++--
3 files changed, 52 insertions(+), 9 deletions(-)
diff --git a/src/controller/org.controller/org.controller.js b/src/controller/org.controller/org.controller.js
index fd87893c2..69e7a1ede 100644
--- a/src/controller/org.controller/org.controller.js
+++ b/src/controller/org.controller/org.controller.js
@@ -322,7 +322,6 @@ async function createOrg (req, res, next) {
* Called by PUT /api/org/{shortname}
**/
async function updateOrg (req, res, next) {
- console.log("in controller") // todo: delete
try {
const shortName = req.ctx.params.shortname
const newOrg = new Org()
@@ -431,7 +430,6 @@ async function updateOrg (req, res, next) {
logger.info(JSON.stringify(payload))
return res.status(200).json(responseMessage)
} catch (err) {
- console.log("err in congtroller: " + err) // todo: delete
next(err)
}
}
diff --git a/src/middleware/middleware.js b/src/middleware/middleware.js
index 8b0d67dab..dcbd6b6f4 100644
--- a/src/middleware/middleware.js
+++ b/src/middleware/middleware.js
@@ -107,7 +107,6 @@ async function validateUser (req, res, next) {
logger.info({ uuid: req.ctx.uuid, message: 'Authenticating user: ' + user }) // userUUID may be null if user does not exist
const orgUUID = await orgRepo.getOrgUUID(org)
if (!orgUUID) {
- console.log("401 1: " + org + " is was not in db ") // todo: delete
logger.info({ uuid: req.ctx.uuid, message: org + ' organization does not exist. User authentication FAILED for ' + user })
return res.status(401).json(error.unauthorized())
}
@@ -148,7 +147,6 @@ async function validateOrg (req, res, next) {
const isSec = await orgRepo.isSecretariat(org)
if (!isSec) {
if (!(org == reqOrg)) {
- console.log(org + " is not a sec and is not equal to " + reqOrg) // todo: delete
logger.info({ uuid: req.ctx.uuid, message: org + ' is not a ' + CONSTANTS.AUTH_ROLE_ENUM.SECRETARIAT + ' or the same as ' + reqOrg + ' and is not allowed to make these changes.' })
return res.status(401).json(error.unauthorized())
}
diff --git a/test/integration-tests/org/putOrgTest.js b/test/integration-tests/org/putOrgTest.js
index d865d231a..a9ef2c3a2 100644
--- a/test/integration-tests/org/putOrgTest.js
+++ b/test/integration-tests/org/putOrgTest.js
@@ -5,7 +5,9 @@ const expect = chai.expect
const constants = require('../constants.js')
const app = require('../../../src/index.js')
-const params = {new_short_name: 'test_org', name: 'Test Organization', id_quota: 100000}
+const params = { name: 'Test Organization', id_quota: 100 }
+const secretariat_params = { name: 'MITRE Corporation', id_quota: 100000 }
+const cna_params = { name: 'Adams, Nielsen and Hensley', id_quota: 1309 }
describe('Testing org put endpoint', () => {
context('Positive Tests', () => {
@@ -13,32 +15,67 @@ describe('Testing org put endpoint', () => {
await chai.request(app)
.put('/api/org/mitre')
.set({ ...constants.headers })
- .query({id_quota: '100000'})
+ .query(params)
.send()
.then((res, err) => {
- console.log(res.text)
expect(res).to.have.status(200)
+ expect(res.body.updated.name).to.equal(params.name)
expect(res.body.updated.policies.id_quota).to.equal(params.id_quota)
expect(err).to.be.undefined
})
+ await chai.request(app)
+ .put(`/api/org/mitre`)
+ .set({ ...constants.headers })
+ .query(secretariat_params)
+ .send()
+ .then((res, err) => {
+ expect(res).to.have.status(200)
+ expect(res.body.updated.name).to.equal(secretariat_params.name)
+ expect(res.body.updated.policies.id_quota).to.equal(secretariat_params.id_quota)
+ expect(err).to.be.undefined
+ })
})
it('Allows update made by a secretariat to another org', async () => {
await chai.request(app)
- .put('/api/org/cause_8')
+ .put('/api/org/win_5')
.set({ ...constants.headers })
+ .query(params)
.send()
.then((res, err) => {
expect(res).to.have.status(200)
+ expect(res.body.updated.name).to.equal(params.name)
+ expect(res.body.updated.policies.id_quota).to.equal(params.id_quota)
+ expect(err).to.be.undefined
+ })
+ await chai.request(app)
+ .put('/api/org/win_5')
+ .set({ ...constants.headers })
+ .query(cna_params)
+ .send()
+ .then((res, err) => {
+ expect(res).to.have.status(200)
+ expect(res.body.updated.name).to.equal(cna_params.name)
+ expect(res.body.updated.policies.id_quota).to.equal(cna_params.id_quota)
expect(err).to.be.undefined
})
})
- it('Allows update made by non secretariat org to itself', async () => {
+ it('Update made by non secretariat org to itself ONLY updates last_active field', async () => {
+ let now = Date.now()
await chai.request(app)
.put('/api/org/win_5')
.set({ ...constants.nonSecretariatUserHeaders })
+ .query(params)
.send()
.then((res, err) => {
+ // Assert that that the last_active field was updated under 2 seconds ago
+ let last_active = Date.parse(res.body.updated.last_active)
+ let diff = Math.abs(now - last_active)
+ let within_two_seconds = diff < 2000
+ expect(within_two_seconds).to.be.true
+ // Assert no other fields were changed
expect(res).to.have.status(200)
+ expect(res.body.updated.name).to.equal(cna_params.name)
+ expect(res.body.updated.policies.id_quota).to.equal(cna_params.id_quota)
expect(err).to.be.undefined
})
})
@@ -54,5 +91,15 @@ describe('Testing org put endpoint', () => {
expect(err).to.be.undefined
})
})
+ it('Fails update made by a non-secretariat org to a secretariat', async () => {
+ await chai.request(app)
+ .put('/api/org/mitre')
+ .set({ ...constants.nonSecretariatUserHeaders })
+ .send()
+ .then((res, err) => {
+ expect(res).to.have.status(401)
+ expect(err).to.be.undefined
+ })
+ })
})
})
\ No newline at end of file
From f98b83d730ed9a6d056fb63b3e42d0296db8b082 Mon Sep 17 00:00:00 2001
From: jack-flores
Date: Mon, 29 Jul 2024 14:38:42 -0400
Subject: [PATCH 04/21] #1258 all tests passing
---
package.json | 1 -
src/controller/org.controller/org.controller.js | 3 ---
2 files changed, 4 deletions(-)
diff --git a/package.json b/package.json
index e733d223a..2bc2cb1c1 100644
--- a/package.json
+++ b/package.json
@@ -96,7 +96,6 @@
"swagger-autogen": "node src/swagger.js",
"test": "NODE_ENV=test mocha --recursive --exit || true",
"test:integration": "NODE_ENV=test node-dev src/scripts/populate.js y; NODE_ENV=test mocha test/integration-tests --recursive --exit",
- "test:put-org": "NODE_ENV=test node-dev src/scripts/populate.js y; NODE_ENV=test mocha test/integration-tests/org/putOrgTest.js --recursive --exit",
"test:unit-tests": "NODE_ENV=test mocha test/unit-tests --recursive --exit || true",
"test:coverage": "NODE_ENV=test nyc --reporter=text mocha src/* --recursive --exit || true",
"test:coverage-html": "NODE_ENV=test nyc --reporter=html mocha src/* --recursive --exit || true",
diff --git a/src/controller/org.controller/org.controller.js b/src/controller/org.controller/org.controller.js
index 69e7a1ede..b31c673b6 100644
--- a/src/controller/org.controller/org.controller.js
+++ b/src/controller/org.controller/org.controller.js
@@ -331,9 +331,6 @@ async function updateOrg (req, res, next) {
const org = await orgRepo.findOneByShortName(shortName)
const orgMakingChanges = req.ctx.org
let agt = setAggregateOrgObj({ short_name: shortName })
-
- logger.info({uuid: req.ctx.uuid, message: 'UPDATING AN ORG'})
-
// org doesn't exist
if (!org) {
From a660d9719eaf9ed76bcecce9494a169a64931187 Mon Sep 17 00:00:00 2001
From: jack-flores
Date: Mon, 29 Jul 2024 16:25:44 -0400
Subject: [PATCH 05/21] #1258 small changes to negative tests
---
test/integration-tests/org/putOrgTest.js | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/test/integration-tests/org/putOrgTest.js b/test/integration-tests/org/putOrgTest.js
index a9ef2c3a2..006335c0e 100644
--- a/test/integration-tests/org/putOrgTest.js
+++ b/test/integration-tests/org/putOrgTest.js
@@ -89,6 +89,8 @@ describe('Testing org put endpoint', () => {
.then((res, err) => {
expect(res).to.have.status(401)
expect(err).to.be.undefined
+ expect(res.body).to.haveOwnProperty('error')
+ expect(res.body.error).to.equal('UNAUTHORIZED')
})
})
it('Fails update made by a non-secretariat org to a secretariat', async () => {
@@ -99,6 +101,8 @@ describe('Testing org put endpoint', () => {
.then((res, err) => {
expect(res).to.have.status(401)
expect(err).to.be.undefined
+ expect(res.body).to.haveOwnProperty('error')
+ expect(res.body.error).to.equal('UNAUTHORIZED')
})
})
})
From b94e2c251694dad5b8037b4a54fc0b2223e2e9df Mon Sep 17 00:00:00 2001
From: jack-flores
Date: Wed, 31 Jul 2024 12:01:20 -0400
Subject: [PATCH 06/21] #1258 fixes for pr pipeline
---
.../org.controller/org.controller.js | 49 +++--
src/middleware/middleware.js | 4 +-
test/integration-tests/org/putOrgTest.js | 184 +++++++++---------
test/unit-tests/org/orgUpdateTest.js | 19 +-
4 files changed, 134 insertions(+), 122 deletions(-)
diff --git a/src/controller/org.controller/org.controller.js b/src/controller/org.controller/org.controller.js
index b31c673b6..929c4853c 100644
--- a/src/controller/org.controller/org.controller.js
+++ b/src/controller/org.controller/org.controller.js
@@ -331,7 +331,7 @@ async function updateOrg (req, res, next) {
const org = await orgRepo.findOneByShortName(shortName)
const orgMakingChanges = req.ctx.org
let agt = setAggregateOrgObj({ short_name: shortName })
-
+
// org doesn't exist
if (!org) {
logger.info({ uuid: req.ctx.uuid, message: shortName + ' organization could not be updated in MongoDB because it does not exist.' })
@@ -339,7 +339,6 @@ async function updateOrg (req, res, next) {
}
newOrg.last_active = Date.now()
-
const isSec = await orgRepo.isSecretariat(orgMakingChanges)
if (isSec) {
@@ -367,36 +366,36 @@ async function updateOrg (req, res, next) {
}
}
})
+ }
- // updating the org's roles
- if (org) {
- const roles = org.authority.active_roles
+ // updating the org's roles
+ if (org) {
+ const roles = org.authority.active_roles
- // adding roles
- addRoles.forEach(role => {
- if (!roles.includes(role)) {
- roles.push(role)
- }
- })
+ // adding roles
+ addRoles.forEach(role => {
+ if (!roles.includes(role)) {
+ roles.push(role)
+ }
+ })
- // removing roles
- removeRoles.forEach(role => {
- const index = roles.indexOf(role)
+ // removing roles
+ removeRoles.forEach(role => {
+ const index = roles.indexOf(role)
- if (index > -1) {
- roles.splice(index, 1)
- }
- })
+ if (index > -1) {
+ roles.splice(index, 1)
+ }
+ })
- newOrg.authority.active_roles = roles
- }
+ newOrg.authority.active_roles = roles
+ }
- if (newOrg.short_name) {
- const result = await orgRepo.findOneByShortName(newOrg.short_name)
+ if (newOrg.short_name) {
+ const result = await orgRepo.findOneByShortName(newOrg.short_name)
- if (result) {
- return res.status(403).json(error.duplicateShortname(newOrg.short_name))
- }
+ if (result) {
+ return res.status(403).json(error.duplicateShortname(newOrg.short_name))
}
}
diff --git a/src/middleware/middleware.js b/src/middleware/middleware.js
index dcbd6b6f4..829a90d20 100644
--- a/src/middleware/middleware.js
+++ b/src/middleware/middleware.js
@@ -142,11 +142,11 @@ async function validateOrg (req, res, next) {
const CONSTANTS = getConstants()
try {
- logger.info({ uuid: req.ctx.uuid, message: 'Authenticating org: ' + org })
+ logger.info({ uuid: req.ctx.uuid, message: 'Authenticating org: ' + org })
const isSec = await orgRepo.isSecretariat(org)
if (!isSec) {
- if (!(org == reqOrg)) {
+ if (!(org === reqOrg)) {
logger.info({ uuid: req.ctx.uuid, message: org + ' is not a ' + CONSTANTS.AUTH_ROLE_ENUM.SECRETARIAT + ' or the same as ' + reqOrg + ' and is not allowed to make these changes.' })
return res.status(401).json(error.unauthorized())
}
diff --git a/test/integration-tests/org/putOrgTest.js b/test/integration-tests/org/putOrgTest.js
index 006335c0e..8b9dde5c5 100644
--- a/test/integration-tests/org/putOrgTest.js
+++ b/test/integration-tests/org/putOrgTest.js
@@ -6,104 +6,104 @@ const constants = require('../constants.js')
const app = require('../../../src/index.js')
const params = { name: 'Test Organization', id_quota: 100 }
-const secretariat_params = { name: 'MITRE Corporation', id_quota: 100000 }
-const cna_params = { name: 'Adams, Nielsen and Hensley', id_quota: 1309 }
+const secretariatParams = { name: 'MITRE Corporation', id_quota: 100000 }
+const cnaParams = { name: 'Adams, Nielsen and Hensley', id_quota: 1309 }
describe('Testing org put endpoint', () => {
- context('Positive Tests', () => {
- it('Allows update made by a secretariat to itself', async () => {
- await chai.request(app)
- .put('/api/org/mitre')
- .set({ ...constants.headers })
- .query(params)
- .send()
- .then((res, err) => {
- expect(res).to.have.status(200)
- expect(res.body.updated.name).to.equal(params.name)
- expect(res.body.updated.policies.id_quota).to.equal(params.id_quota)
- expect(err).to.be.undefined
- })
- await chai.request(app)
- .put(`/api/org/mitre`)
- .set({ ...constants.headers })
- .query(secretariat_params)
- .send()
- .then((res, err) => {
- expect(res).to.have.status(200)
- expect(res.body.updated.name).to.equal(secretariat_params.name)
- expect(res.body.updated.policies.id_quota).to.equal(secretariat_params.id_quota)
- expect(err).to.be.undefined
- })
+ context('Positive Tests', () => {
+ it('Allows update made by a secretariat to itself', async () => {
+ await chai.request(app)
+ .put('/api/org/mitre')
+ .set({ ...constants.headers })
+ .query(params)
+ .send()
+ .then((res, err) => {
+ expect(res).to.have.status(200)
+ expect(res.body.updated.name).to.equal(params.name)
+ expect(res.body.updated.policies.id_quota).to.equal(params.id_quota)
+ expect(err).to.be.undefined
})
- it('Allows update made by a secretariat to another org', async () => {
- await chai.request(app)
- .put('/api/org/win_5')
- .set({ ...constants.headers })
- .query(params)
- .send()
- .then((res, err) => {
- expect(res).to.have.status(200)
- expect(res.body.updated.name).to.equal(params.name)
- expect(res.body.updated.policies.id_quota).to.equal(params.id_quota)
- expect(err).to.be.undefined
- })
- await chai.request(app)
- .put('/api/org/win_5')
- .set({ ...constants.headers })
- .query(cna_params)
- .send()
- .then((res, err) => {
- expect(res).to.have.status(200)
- expect(res.body.updated.name).to.equal(cna_params.name)
- expect(res.body.updated.policies.id_quota).to.equal(cna_params.id_quota)
- expect(err).to.be.undefined
- })
+ await chai.request(app)
+ .put('/api/org/mitre')
+ .set({ ...constants.headers })
+ .query(secretariatParams)
+ .send()
+ .then((res, err) => {
+ expect(res).to.have.status(200)
+ expect(res.body.updated.name).to.equal(secretariatParams.name)
+ expect(res.body.updated.policies.id_quota).to.equal(secretariatParams.id_quota)
+ expect(err).to.be.undefined
})
- it('Update made by non secretariat org to itself ONLY updates last_active field', async () => {
- let now = Date.now()
- await chai.request(app)
- .put('/api/org/win_5')
- .set({ ...constants.nonSecretariatUserHeaders })
- .query(params)
- .send()
- .then((res, err) => {
- // Assert that that the last_active field was updated under 2 seconds ago
- let last_active = Date.parse(res.body.updated.last_active)
- let diff = Math.abs(now - last_active)
- let within_two_seconds = diff < 2000
- expect(within_two_seconds).to.be.true
- // Assert no other fields were changed
- expect(res).to.have.status(200)
- expect(res.body.updated.name).to.equal(cna_params.name)
- expect(res.body.updated.policies.id_quota).to.equal(cna_params.id_quota)
- expect(err).to.be.undefined
- })
+ })
+ it('Allows update made by a secretariat to another org', async () => {
+ await chai.request(app)
+ .put('/api/org/win_5')
+ .set({ ...constants.headers })
+ .query(params)
+ .send()
+ .then((res, err) => {
+ expect(res).to.have.status(200)
+ expect(res.body.updated.name).to.equal(params.name)
+ expect(res.body.updated.policies.id_quota).to.equal(params.id_quota)
+ expect(err).to.be.undefined
+ })
+ await chai.request(app)
+ .put('/api/org/win_5')
+ .set({ ...constants.headers })
+ .query(cnaParams)
+ .send()
+ .then((res, err) => {
+ expect(res).to.have.status(200)
+ expect(res.body.updated.name).to.equal(cnaParams.name)
+ expect(res.body.updated.policies.id_quota).to.equal(cnaParams.id_quota)
+ expect(err).to.be.undefined
})
})
- context('Negative Tests', () => {
- it('Fails update made by a non-secretariat org to a different org', async () => {
- await chai.request(app)
- .put('/api/org/cause_8')
- .set({ ...constants.nonSecretariatUserHeaders })
- .send()
- .then((res, err) => {
- expect(res).to.have.status(401)
- expect(err).to.be.undefined
- expect(res.body).to.haveOwnProperty('error')
- expect(res.body.error).to.equal('UNAUTHORIZED')
- })
+ it('Update made by non secretariat org to itself ONLY updates last_active field', async () => {
+ const now = Date.now()
+ await chai.request(app)
+ .put('/api/org/win_5')
+ .set({ ...constants.nonSecretariatUserHeaders })
+ .query(params)
+ .send()
+ .then((res, err) => {
+ // Assert that that the last_active field was updated under 2 seconds ago
+ const lastActive = Date.parse(res.body.updated.last_active)
+ const diff = Math.abs(now - lastActive)
+ const withinTwoSeconds = diff < 2000
+ expect(withinTwoSeconds).to.be.true
+ // Assert no other fields were changed
+ expect(res).to.have.status(200)
+ expect(res.body.updated.name).to.equal(cnaParams.name)
+ expect(res.body.updated.policies.id_quota).to.equal(cnaParams.id_quota)
+ expect(err).to.be.undefined
})
- it('Fails update made by a non-secretariat org to a secretariat', async () => {
- await chai.request(app)
- .put('/api/org/mitre')
- .set({ ...constants.nonSecretariatUserHeaders })
- .send()
- .then((res, err) => {
- expect(res).to.have.status(401)
- expect(err).to.be.undefined
- expect(res.body).to.haveOwnProperty('error')
- expect(res.body.error).to.equal('UNAUTHORIZED')
- })
+ })
+ })
+ context('Negative Tests', () => {
+ it('Fails update made by a non-secretariat org to a different org', async () => {
+ await chai.request(app)
+ .put('/api/org/cause_8')
+ .set({ ...constants.nonSecretariatUserHeaders })
+ .send()
+ .then((res, err) => {
+ expect(res).to.have.status(401)
+ expect(err).to.be.undefined
+ expect(res.body).to.haveOwnProperty('error')
+ expect(res.body.error).to.equal('UNAUTHORIZED')
+ })
+ })
+ it('Fails update made by a non-secretariat org to a secretariat', async () => {
+ await chai.request(app)
+ .put('/api/org/mitre')
+ .set({ ...constants.nonSecretariatUserHeaders })
+ .send()
+ .then((res, err) => {
+ expect(res).to.have.status(401)
+ expect(err).to.be.undefined
+ expect(res.body).to.haveOwnProperty('error')
+ expect(res.body.error).to.equal('UNAUTHORIZED')
})
})
-})
\ No newline at end of file
+ })
+})
diff --git a/test/unit-tests/org/orgUpdateTest.js b/test/unit-tests/org/orgUpdateTest.js
index f978d6f96..05e696f79 100644
--- a/test/unit-tests/org/orgUpdateTest.js
+++ b/test/unit-tests/org/orgUpdateTest.js
@@ -48,6 +48,10 @@ class OrgUpdatedAddingRole {
async getOrgUUID () {
return null
}
+
+ async isSecretariat () {
+ return true
+ }
}
class OrgUpdatedRemovingRole {
@@ -66,6 +70,10 @@ class OrgUpdatedRemovingRole {
async getOrgUUID () {
return null
}
+
+ async isSecretariat () {
+ return true
+ }
}
describe('Testing the PUT /org/:shortname endpoint in Org Controller', () => {
@@ -102,8 +110,11 @@ describe('Testing the PUT /org/:shortname endpoint in Org Controller', () => {
async findOneByShortName () {
return orgFixtures.existentOrg
}
- }
+ async isSecretariat () {
+ return true
+ }
+ }
app.route('/org-not-updated-shortname-exists/:shortname')
.put((req, res, next) => {
const factory = {
@@ -112,7 +123,6 @@ describe('Testing the PUT /org/:shortname endpoint in Org Controller', () => {
req.ctx.repositories = factory
next()
}, orgParams.parsePostParams, orgController.ORG_UPDATE_SINGLE)
-
chai.request(app)
.put(`/org-not-updated-shortname-exists/${orgFixtures.existentOrg.short_name}?new_short_name=cisco`)
.set(orgFixtures.secretariatHeader)
@@ -120,7 +130,6 @@ describe('Testing the PUT /org/:shortname endpoint in Org Controller', () => {
if (err) {
done(err)
}
-
expect(res).to.have.status(403)
expect(res).to.have.property('body').and.to.be.a('object')
const errObj = error.duplicateShortname('cisco')
@@ -288,6 +297,10 @@ describe('Testing the PUT /org/:shortname endpoint in Org Controller', () => {
async aggregate () {
return [orgFixtures.existentOrg]
}
+
+ async isSecretariat () {
+ return true
+ }
}
app.route('/org-not-updated-no-query-parameters/:shortname')
From 53c9fb17a136f84dbe2bfaa4e3b298ea77b39b3b Mon Sep 17 00:00:00 2001
From: jack-flores
Date: Wed, 31 Jul 2024 12:21:50 -0400
Subject: [PATCH 07/21] quieting bad eslint error
---
test/integration-tests/org/putOrgTest.js | 1 +
1 file changed, 1 insertion(+)
diff --git a/test/integration-tests/org/putOrgTest.js b/test/integration-tests/org/putOrgTest.js
index 8b9dde5c5..0b47f8646 100644
--- a/test/integration-tests/org/putOrgTest.js
+++ b/test/integration-tests/org/putOrgTest.js
@@ -1,3 +1,4 @@
+/* eslint-disable no-unused-expressions */
const chai = require('chai')
chai.use(require('chai-http'))
const expect = chai.expect
From 403b3bf417cbad7f950e7860b0c4ee659b5c8284 Mon Sep 17 00:00:00 2001
From: jack-flores
Date: Wed, 31 Jul 2024 15:53:52 -0400
Subject: [PATCH 08/21] #1258 now rejects non-sec requests with params
---
.../org.controller/org.controller.js | 4 +++
src/middleware/middleware.js | 6 +++--
test/integration-tests/org/putOrgTest.js | 27 ++++++++++++++-----
3 files changed, 28 insertions(+), 9 deletions(-)
diff --git a/src/controller/org.controller/org.controller.js b/src/controller/org.controller/org.controller.js
index 929c4853c..b4e1873f4 100644
--- a/src/controller/org.controller/org.controller.js
+++ b/src/controller/org.controller/org.controller.js
@@ -409,6 +409,10 @@ async function updateOrg (req, res, next) {
result = await orgRepo.aggregate(agt)
result = result.length > 0 ? result[0] : null
+ if (!isSec) {
+ result = { last_active: result.last_active }
+ }
+
const responseMessage = {
message: shortName + ' organization was successfully updated.',
updated: result
diff --git a/src/middleware/middleware.js b/src/middleware/middleware.js
index 829a90d20..35e505103 100644
--- a/src/middleware/middleware.js
+++ b/src/middleware/middleware.js
@@ -146,9 +146,11 @@ async function validateOrg (req, res, next) {
const isSec = await orgRepo.isSecretariat(org)
if (!isSec) {
- if (!(org === reqOrg)) {
+ if (org !== reqOrg) {
logger.info({ uuid: req.ctx.uuid, message: org + ' is not a ' + CONSTANTS.AUTH_ROLE_ENUM.SECRETARIAT + ' or the same as ' + reqOrg + ' and is not allowed to make these changes.' })
- return res.status(401).json(error.unauthorized())
+ return res.status(403).json(error.secretariatOnly())
+ } else if (Object.keys(req.query).length > 0) {
+ return res.status(403).json(error.secretariatOnly())
}
}
diff --git a/test/integration-tests/org/putOrgTest.js b/test/integration-tests/org/putOrgTest.js
index 0b47f8646..dec0a2b05 100644
--- a/test/integration-tests/org/putOrgTest.js
+++ b/test/integration-tests/org/putOrgTest.js
@@ -65,7 +65,6 @@ describe('Testing org put endpoint', () => {
await chai.request(app)
.put('/api/org/win_5')
.set({ ...constants.nonSecretariatUserHeaders })
- .query(params)
.send()
.then((res, err) => {
// Assert that that the last_active field was updated under 2 seconds ago
@@ -75,8 +74,9 @@ describe('Testing org put endpoint', () => {
expect(withinTwoSeconds).to.be.true
// Assert no other fields were changed
expect(res).to.have.status(200)
- expect(res.body.updated.name).to.equal(cnaParams.name)
- expect(res.body.updated.policies.id_quota).to.equal(cnaParams.id_quota)
+ expect(res.body.updated.active_roles).to.be.undefined
+ expect(res.body.updated.name).to.be.undefined
+ expect(res.body.updated.policies).to.be.undefined
expect(err).to.be.undefined
})
})
@@ -88,10 +88,23 @@ describe('Testing org put endpoint', () => {
.set({ ...constants.nonSecretariatUserHeaders })
.send()
.then((res, err) => {
- expect(res).to.have.status(401)
+ expect(res).to.have.status(403)
+ expect(err).to.be.undefined
+ expect(res.body).to.haveOwnProperty('error')
+ expect(res.body.error).to.equal('SECRETARIAT_ONLY')
+ })
+ })
+ it('Fails update to fields made by a non-secretariat org to itself', async () => {
+ await chai.request(app)
+ .put('/api/org/win_5')
+ .set({ ...constants.nonSecretariatUserHeaders })
+ .query(params)
+ .send()
+ .then((res, err) => {
+ expect(res).to.have.status(403)
expect(err).to.be.undefined
expect(res.body).to.haveOwnProperty('error')
- expect(res.body.error).to.equal('UNAUTHORIZED')
+ expect(res.body.error).to.equal('SECRETARIAT_ONLY')
})
})
it('Fails update made by a non-secretariat org to a secretariat', async () => {
@@ -100,10 +113,10 @@ describe('Testing org put endpoint', () => {
.set({ ...constants.nonSecretariatUserHeaders })
.send()
.then((res, err) => {
- expect(res).to.have.status(401)
+ expect(res).to.have.status(403)
expect(err).to.be.undefined
expect(res.body).to.haveOwnProperty('error')
- expect(res.body.error).to.equal('UNAUTHORIZED')
+ expect(res.body.error).to.equal('SECRETARIAT_ONLY')
})
})
})
From 03cc6185f85439c34b50b735dd8938f71c5883f6 Mon Sep 17 00:00:00 2001
From: jack-flores
Date: Fri, 2 Aug 2024 15:11:45 -0400
Subject: [PATCH 09/21] #1258 updated swagger documentation
---
src/controller/org.controller/index.js | 1 +
.../org.controller/org.controller.js | 3 +-
test/unit-tests/org/orgUpdateTest.js | 96 ++++++++++++++++++-
3 files changed, 96 insertions(+), 4 deletions(-)
diff --git a/src/controller/org.controller/index.js b/src/controller/org.controller/index.js
index abbac143f..598cb0550 100644
--- a/src/controller/org.controller/index.js
+++ b/src/controller/org.controller/index.js
@@ -247,6 +247,7 @@ router.put('/org/:shortname',
Access Control
User must belong to an organization with the Secretariat role
Expected Behavior
+ CNA: Updates 'last_active' timestamp to show that a CNA is still active
Secretariat: Updates any organization's information
"
#swagger.parameters['shortname'] = { description: 'The shortname of the organization' }
#swagger.parameters['$ref'] = [
diff --git a/src/controller/org.controller/org.controller.js b/src/controller/org.controller/org.controller.js
index b4e1873f4..0e82f640d 100644
--- a/src/controller/org.controller/org.controller.js
+++ b/src/controller/org.controller/org.controller.js
@@ -338,7 +338,6 @@ async function updateOrg (req, res, next) {
return res.status(404).json(error.orgDnePathParam(shortName))
}
- newOrg.last_active = Date.now()
const isSec = await orgRepo.isSecretariat(orgMakingChanges)
if (isSec) {
@@ -399,6 +398,8 @@ async function updateOrg (req, res, next) {
}
}
+ newOrg.last_active = Date.now()
+
// update org
let result = await orgRepo.updateByOrgUUID(org.UUID, newOrg)
if (result.n === 0) {
diff --git a/test/unit-tests/org/orgUpdateTest.js b/test/unit-tests/org/orgUpdateTest.js
index 05e696f79..61a4502ad 100644
--- a/test/unit-tests/org/orgUpdateTest.js
+++ b/test/unit-tests/org/orgUpdateTest.js
@@ -1,3 +1,4 @@
+/* eslint-disable no-unused-expressions */
const express = require('express')
const app = express()
const chai = require('chai')
@@ -38,7 +39,9 @@ class OrgUpdatedAddingRole {
}
async aggregate () {
- return [orgFixtures.owningOrg]
+ const org = orgFixtures.owningOrg
+ org.last_active = Date.now()
+ return [org]
}
async updateByOrgUUID () {
@@ -60,7 +63,9 @@ class OrgUpdatedRemovingRole {
}
async aggregate () {
- return [orgFixtures.owningOrg]
+ const org = orgFixtures.owningOrg
+ org.last_active = Date.now()
+ return [org]
}
async updateByOrgUUID () {
@@ -172,6 +177,11 @@ describe('Testing the PUT /org/:shortname endpoint in Org Controller', () => {
expect(res.body.updated.name).to.equal(orgFixtures.owningOrg.name)
expect(res.body.updated.UUID).to.equal(orgFixtures.owningOrg.UUID)
expect(res.body.updated.policies.id_quota).to.equal(orgFixtures.owningOrg.policies.id_quota)
+ const now = Date.now()
+ const lastActive = res.body.updated.last_active
+ const diff = Math.abs(now - lastActive)
+ const withinTwoSeconds = diff < 500
+ expect(withinTwoSeconds).to.be.true
done()
})
})
@@ -207,6 +217,11 @@ describe('Testing the PUT /org/:shortname endpoint in Org Controller', () => {
expect(res.body.updated.name).to.equal(orgFixtures.owningOrg.name)
expect(res.body.updated.UUID).to.equal(orgFixtures.owningOrg.UUID)
expect(res.body.updated.policies.id_quota).to.equal(orgFixtures.owningOrg.policies.id_quota)
+ const now = Date.now()
+ const lastActive = res.body.updated.last_active
+ const diff = Math.abs(now - lastActive)
+ const withinTwoSeconds = diff < 500
+ expect(withinTwoSeconds).to.be.true
done()
})
})
@@ -241,6 +256,11 @@ describe('Testing the PUT /org/:shortname endpoint in Org Controller', () => {
expect(res.body.updated.name).to.equal(orgFixtures.owningOrg.name)
expect(res.body.updated.UUID).to.equal(orgFixtures.owningOrg.UUID)
expect(res.body.updated.policies.id_quota).to.equal(orgFixtures.owningOrg.policies.id_quota)
+ const now = Date.now()
+ const lastActive = res.body.updated.last_active
+ const diff = Math.abs(now - lastActive)
+ const withinTwoSeconds = diff < 500
+ expect(withinTwoSeconds).to.be.true
done()
})
})
@@ -275,6 +295,11 @@ describe('Testing the PUT /org/:shortname endpoint in Org Controller', () => {
expect(res.body.updated.name).to.equal(orgFixtures.owningOrg.name)
expect(res.body.updated.UUID).to.equal(orgFixtures.owningOrg.UUID)
expect(res.body.updated.policies.id_quota).to.equal(orgFixtures.owningOrg.policies.id_quota)
+ const now = Date.now()
+ const lastActive = res.body.updated.last_active
+ const diff = Math.abs(now - lastActive)
+ const withinTwoSeconds = diff < 500
+ expect(withinTwoSeconds).to.be.true
done()
})
})
@@ -295,7 +320,9 @@ describe('Testing the PUT /org/:shortname endpoint in Org Controller', () => {
}
async aggregate () {
- return [orgFixtures.existentOrg]
+ const org = orgFixtures.existentOrg
+ org.last_active = Date.now()
+ return [org]
}
async isSecretariat () {
@@ -328,6 +355,69 @@ describe('Testing the PUT /org/:shortname endpoint in Org Controller', () => {
expect(res.body.updated.name).to.equal(orgFixtures.existentOrg.name)
expect(res.body.updated.short_name).to.equal(orgFixtures.existentOrg.short_name)
expect(res.body.updated.UUID).to.equal(orgFixtures.existentOrg.UUID)
+ const now = Date.now()
+ const lastActive = res.body.updated.last_active
+ const diff = Math.abs(now - lastActive)
+ const withinTwoSeconds = diff < 500
+ expect(withinTwoSeconds).to.be.true
+ })
+
+ it('Non-secretariat only last_active field updated', (done) => {
+ class NonSecretariat {
+ async findOneByShortName () {
+ return orgFixtures.owningOrg
+ }
+
+ async aggregate () {
+ const org = orgFixtures.owningOrg
+ org.last_active = Date.now()
+ return [org]
+ }
+
+ async updateByOrgUUID () {
+ return { n: 1 }
+ }
+
+ async getOrgUUID () {
+ return null
+ }
+
+ async isSecretariat () {
+ return false
+ }
+ }
+ app.route('/org-non-secretariat-updates-last-active-field/:shortname')
+ .put((req, res, next) => {
+ const factory = {
+ getOrgRepository: () => { return new NonSecretariat() },
+ getUserRepository: () => { return new NullUserRepo() }
+ }
+ req.ctx.repositories = factory
+ next()
+ }, orgParams.parsePostParams, orgController.ORG_UPDATE_SINGLE)
+
+ chai.request(app)
+ .put(`/org-non-secretariat-updates-last-active-field/${orgFixtures.owningOrg.short_name}?name=TestOrg`)
+ .set(orgFixtures.owningOrgHeader)
+ .end((err, res) => {
+ if (err) {
+ done(err)
+ }
+ expect(res).to.have.status(200)
+ expect(res).to.have.property('body').and.to.be.a('object')
+ expect(res.body).to.have.property('updated').and.to.be.a('object')
+ // Assert that that the last_active field was updated under 0.5 seconds ago
+ const now = Date.now()
+ const lastActive = res.body.updated.last_active
+ const diff = Math.abs(now - lastActive)
+ const withinTwoSeconds = diff < 500
+ expect(withinTwoSeconds).to.be.true
+ // Assert no other fields were changed
+ expect(res.body.updated.active_roles).to.be.undefined
+ expect(res.body.updated.name).to.be.undefined
+ expect(res.body.updated.policies).to.be.undefined
+ done()
+ })
})
})
})
From c082fb52ac9ee90c4fbd0fe5d5839f05d4ccaa22 Mon Sep 17 00:00:00 2001
From: jack-flores
Date: Fri, 2 Aug 2024 15:39:39 -0400
Subject: [PATCH 10/21] test to see if my username shows up
---
test/unit-tests/org/orgUpdateTest.js | 1 +
1 file changed, 1 insertion(+)
diff --git a/test/unit-tests/org/orgUpdateTest.js b/test/unit-tests/org/orgUpdateTest.js
index 61a4502ad..312cf0b9f 100644
--- a/test/unit-tests/org/orgUpdateTest.js
+++ b/test/unit-tests/org/orgUpdateTest.js
@@ -386,6 +386,7 @@ describe('Testing the PUT /org/:shortname endpoint in Org Controller', () => {
return false
}
}
+
app.route('/org-non-secretariat-updates-last-active-field/:shortname')
.put((req, res, next) => {
const factory = {
From cfb89119a2c744a610b351337528daf619b0fba9 Mon Sep 17 00:00:00 2001
From: jack-flores
Date: Mon, 5 Aug 2024 09:40:41 -0400
Subject: [PATCH 11/21] #1258 added schema for am-i-alive
---
api-docs/openapi.json | 2 +-
schemas/org/am-i-alive-response.json | 20 ++++++++++++++++++++
2 files changed, 21 insertions(+), 1 deletion(-)
create mode 100644 schemas/org/am-i-alive-response.json
diff --git a/api-docs/openapi.json b/api-docs/openapi.json
index 1a7ebad46..f6974fb06 100644
--- a/api-docs/openapi.json
+++ b/api-docs/openapi.json
@@ -2099,7 +2099,7 @@
"Organization"
],
"summary": "Updates information about the organization specified by short name (accessible to Secretariat)",
- "description": " Access Control
User must belong to an organization with the Secretariat role
Expected Behavior
Secretariat: Updates any organization's information
",
+ "description": " Access Control
User must belong to an organization with the Secretariat role
Expected Behavior
CNA: Updates 'last_active' timestamp to show that a CNA is still active
Secretariat: Updates any organization's information
",
"operationId": "orgUpdateSingle",
"parameters": [
{
diff --git a/schemas/org/am-i-alive-response.json b/schemas/org/am-i-alive-response.json
new file mode 100644
index 000000000..b9b3d55b0
--- /dev/null
+++ b/schemas/org/am-i-alive-response.json
@@ -0,0 +1,20 @@
+{
+ "$schema": "http://json-schema.org/draft-04/schema",
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "description": "Success description"
+ },
+ "updated": {
+ "type": "object",
+ "properties": {
+ "last_active": {
+ "type": "string",
+ "format": "date-time",
+ "description": "The time the organization was last active."
+ }
+ }
+ }
+ }
+ }
\ No newline at end of file
From fcc7fc48901581242b535dd3bff32da74d02aa93 Mon Sep 17 00:00:00 2001
From: "Daigneau, Jeremy T"
Date: Mon, 5 Aug 2024 10:59:55 -0400
Subject: [PATCH 12/21] Updated github actions to use docker compose instead of
docker-compose
---
.github/workflows/test-http.yml | 14 +++++++-------
.github/workflows/test-integration.yml | 6 +++---
2 files changed, 10 insertions(+), 10 deletions(-)
diff --git a/.github/workflows/test-http.yml b/.github/workflows/test-http.yml
index 1a3d66788..0ced6fc48 100644
--- a/.github/workflows/test-http.yml
+++ b/.github/workflows/test-http.yml
@@ -14,22 +14,22 @@ jobs:
- name: Build and Run Services and Mongo Containers
run: |
cp docker/.docker-env.example docker/.docker-env
- docker-compose --file docker/docker-compose.yml build
- docker-compose --file docker/docker-compose.yml up -d
+ docker compose --file docker/docker-compose.yml build
+ docker compose --file docker/docker-compose.yml up -d
- name: Build Test Container
run: |
cp test-http/docker/.docker-env.example test-http/docker/.docker-env
- docker-compose --file test-http/docker/docker-compose.yml build
+ docker compose --file test-http/docker/docker-compose.yml build
- name: Run Test Container
run: |
- docker-compose --file test-http/docker/docker-compose.yml up -d
+ docker compose --file test-http/docker/docker-compose.yml up -d
- name: Sleep
run: bash -c "while ! docker-compose --file docker/docker-compose.yml logs --tail=10 cveawg | grep -q 'Serving on port'; do sleep 1; done"
- name: Load Data into MongoDb
- run: docker-compose -f docker/docker-compose.yml exec -T cveawg npm run populate:dev y
+ run: docker compose -f docker/docker-compose.yml exec -T cveawg npm run populate:dev y
- name: Run Black Box Tests
run: |
- docker-compose --file test-http/docker/docker-compose.yml exec -T demon pytest src/ | tee test-http/src/testOutput.txt
+ docker compose --file test-http/docker/docker-compose.yml exec -T demon pytest src/ | tee test-http/src/testOutput.txt
- name: Archive Test Results
uses: actions/upload-artifact@v2
with:
@@ -37,7 +37,7 @@ jobs:
path: test-http/src/testOutput.txt
retention-days: 1
- name: Extract Tests Results
- run: docker-compose --file test-http/docker/docker-compose.yml exec -T demon /bin/bash src/parse_tests_output.sh | (read foo; echo "##[set-output name=result;]$(echo $foo)")
+ run: docker compose --file test-http/docker/docker-compose.yml exec -T demon /bin/bash src/parse_tests_output.sh | (read foo; echo "##[set-output name=result;]$(echo $foo)")
id: tests_result
- name: Evaluate Tests Results
if: ${{ steps.tests_result.outputs.result == 'Tests failed' }}
diff --git a/.github/workflows/test-integration.yml b/.github/workflows/test-integration.yml
index b7569a79c..48f54d04c 100644
--- a/.github/workflows/test-integration.yml
+++ b/.github/workflows/test-integration.yml
@@ -14,10 +14,10 @@ jobs:
- name: Build and Run Services and Mongo Containers
run: |
cp docker/.docker-env.test-example docker/.docker-env
- docker-compose --file docker/docker-compose.yml build
- docker-compose --file docker/docker-compose.yml up -d
+ docker compose --file docker/docker-compose.yml build
+ docker compose --file docker/docker-compose.yml up -d
- name: Sleep
run: bash -c "while ! docker-compose --file docker/docker-compose.yml logs --tail=10 cveawg | grep -q 'Serving on port'; do sleep 1; done"
- name: Run Tests
- run: docker-compose -f docker/docker-compose.yml exec -T cveawg npm run test:integration
+ run: docker compose -f docker/docker-compose.yml exec -T cveawg npm run test:integration
continue-on-error: false
\ No newline at end of file
From 45db2a8eed1ba2d8eb353a15f279ea5f63d73ec2 Mon Sep 17 00:00:00 2001
From: "Daigneau, Jeremy T"
Date: Mon, 5 Aug 2024 11:22:01 -0400
Subject: [PATCH 13/21] More docker-compose fixes
---
.github/workflows/test-http.yml | 2 +-
.github/workflows/test-integration.yml | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/.github/workflows/test-http.yml b/.github/workflows/test-http.yml
index 0ced6fc48..5f56c1b09 100644
--- a/.github/workflows/test-http.yml
+++ b/.github/workflows/test-http.yml
@@ -24,7 +24,7 @@ jobs:
run: |
docker compose --file test-http/docker/docker-compose.yml up -d
- name: Sleep
- run: bash -c "while ! docker-compose --file docker/docker-compose.yml logs --tail=10 cveawg | grep -q 'Serving on port'; do sleep 1; done"
+ run: bash -c "while ! docker compose --file docker/docker-compose.yml logs --tail=10 cveawg | grep -q 'Serving on port'; do sleep 1; done"
- name: Load Data into MongoDb
run: docker compose -f docker/docker-compose.yml exec -T cveawg npm run populate:dev y
- name: Run Black Box Tests
diff --git a/.github/workflows/test-integration.yml b/.github/workflows/test-integration.yml
index 48f54d04c..1f5efbd64 100644
--- a/.github/workflows/test-integration.yml
+++ b/.github/workflows/test-integration.yml
@@ -17,7 +17,7 @@ jobs:
docker compose --file docker/docker-compose.yml build
docker compose --file docker/docker-compose.yml up -d
- name: Sleep
- run: bash -c "while ! docker-compose --file docker/docker-compose.yml logs --tail=10 cveawg | grep -q 'Serving on port'; do sleep 1; done"
+ run: bash -c "while ! docker compose --file docker/docker-compose.yml logs --tail=10 cveawg | grep -q 'Serving on port'; do sleep 1; done"
- name: Run Tests
run: docker compose -f docker/docker-compose.yml exec -T cveawg npm run test:integration
continue-on-error: false
\ No newline at end of file
From a45d63a543ee465967211cba85124a5a8f8be6c9 Mon Sep 17 00:00:00 2001
From: jack-flores
Date: Thu, 8 Aug 2024 15:20:04 -0400
Subject: [PATCH 14/21] #1258 more unit tests
---
test/unit-tests/middleware/validateOrgTest.js | 172 ++++++++++++++++++
.../unit-tests/org/orgUpdateLastActiveTest.js | 136 ++++++++++++++
test/unit-tests/org/orgUpdateTest.js | 100 +---------
3 files changed, 314 insertions(+), 94 deletions(-)
create mode 100644 test/unit-tests/middleware/validateOrgTest.js
create mode 100644 test/unit-tests/org/orgUpdateLastActiveTest.js
diff --git a/test/unit-tests/middleware/validateOrgTest.js b/test/unit-tests/middleware/validateOrgTest.js
new file mode 100644
index 000000000..af239880f
--- /dev/null
+++ b/test/unit-tests/middleware/validateOrgTest.js
@@ -0,0 +1,172 @@
+/* eslint-disable no-unused-expressions */
+const chai = require('chai')
+const sinon = require('sinon')
+const { validateOrg } = require('../../../src/middleware/middleware.js')
+const OrgRepository = require('../../../src/repositories/orgRepository.js')
+const expect = chai.expect
+
+const secretariat = {
+ short_name: 'mitre',
+ name: 'MITRE Corporation',
+ authority: {
+ active_roles: [
+ 'SECRETARIAT',
+ 'CNA'
+ ]
+ },
+ policies: {
+ id_quota: 1248
+ }
+}
+
+const nonSecretariat = {
+ short_name: 'win_5',
+ name: 'test_org',
+ authority: {
+ active_roles: [
+ 'CNA'
+ ]
+ },
+ policies: {
+ id_quota: 200
+ }
+}
+
+const nonSecretariat2 = {
+ short_name: 'cause_8',
+ name: 'test_org2',
+ authority: {
+ active_roles: [
+ 'CNA'
+ ]
+ },
+ policies: {
+ id_quota: 888
+ }
+}
+
+describe('Testing the validateOrg function', () => {
+ let status, json, res, next, getOrgRepository, orgRepo
+ beforeEach(() => {
+ status = sinon.stub()
+ json = sinon.spy()
+ res = { json, status }
+ next = sinon.stub()
+ status.returns(res)
+
+ orgRepo = new OrgRepository()
+ getOrgRepository = sinon.stub()
+ getOrgRepository.returns(orgRepo)
+ })
+ context('Positive Tests', () => {
+ it('Secretariat can update itself', async () => {
+ sinon.stub(orgRepo, 'isSecretariat').returns(true)
+
+ const req = {
+ ctx: {
+ org: secretariat.short_name,
+ repositories: {
+ getOrgRepository
+ }
+ },
+ params: {
+ shortname: secretariat.short_name
+ },
+ query: {
+ id_quota: 111
+ }
+ }
+ await validateOrg(req, res, next)
+
+ expect(next.calledOnce).to.be.true
+ expect(next.firstCall.args).to.be.empty
+ })
+ it('Secretariat can update another org', async () => {
+ sinon.stub(orgRepo, 'isSecretariat').returns(true)
+
+ const req = {
+ ctx: {
+ org: secretariat.short_name,
+ repositories: {
+ getOrgRepository
+ }
+ },
+ params: {
+ shortname: nonSecretariat.short_name
+ },
+ query: {
+ id_quota: 999
+ }
+ }
+ await validateOrg(req, res, next)
+
+ expect(next.calledOnce).to.be.true
+ expect(next.firstCall.args).to.be.empty
+ })
+ it('Non-secretariat can update itself', async () => {
+ sinon.stub(orgRepo, 'isSecretariat').returns(true)
+
+ const req = {
+ ctx: {
+ org: nonSecretariat.short_name,
+ repositories: {
+ getOrgRepository
+ }
+ },
+ params: {
+ shortname: nonSecretariat.short_name
+ }
+ }
+ await validateOrg(req, res, next)
+
+ expect(next.calledOnce).to.be.true
+ expect(next.firstCall.args).to.be.empty
+ })
+ })
+ context('Negative Tests', () => {
+ it('Non-secretariat cannot update its fields other than last_active', async () => {
+ sinon.stub(orgRepo, 'isSecretariat').returns(false)
+
+ const req = {
+ ctx: {
+ org: nonSecretariat.short_name,
+ repositories: {
+ getOrgRepository
+ }
+ },
+ params: {
+ shortname: nonSecretariat.short_name
+ },
+ query: {
+ id_quota: 999
+ }
+ }
+ await validateOrg(req, res, next)
+
+ expect(status.calledWith(403)).to.be.true
+ expect(next.calledOnce).to.be.false
+ })
+ it('Non-secretariat cannot update another org', async () => {
+ sinon.stub(orgRepo, 'isSecretariat').returns(false)
+
+ const req = {
+ ctx: {
+ org: nonSecretariat.short_name,
+ repositories: {
+ getOrgRepository
+ }
+ },
+ params: {
+ shortname: nonSecretariat2.short_name
+ },
+ query: {
+ id_quota: 999
+ }
+ }
+ await validateOrg(req, res, next)
+
+ expect(status.calledWith(403)).to.be.true
+ expect(next.calledOnce).to.be.false
+ })
+ })
+})
diff --git a/test/unit-tests/org/orgUpdateLastActiveTest.js b/test/unit-tests/org/orgUpdateLastActiveTest.js
new file mode 100644
index 000000000..1bffe773a
--- /dev/null
+++ b/test/unit-tests/org/orgUpdateLastActiveTest.js
@@ -0,0 +1,136 @@
+/* eslint-disable no-unused-expressions */
+const chai = require('chai')
+const sinon = require('sinon')
+const { ORG_UPDATE_SINGLE } = require('../../../src/controller/org.controller/org.controller.js')
+const OrgRepository = require('../../../src/repositories/orgRepository.js')
+const UserRepository = require('../../../src/repositories/userRepository.js')
+const expect = chai.expect
+
+const secretariat = {
+ short_name: 'mitre',
+ name: 'MITRE Corporation',
+ authority: {
+ active_roles: [
+ 'SECRETARIAT',
+ 'CNA'
+ ]
+ },
+ policies: {
+ id_quota: 1248
+ }
+}
+
+const nonSecretariat = {
+ short_name: 'win_5',
+ name: 'test_org',
+ authority: {
+ active_roles: [
+ 'CNA'
+ ]
+ },
+ policies: {
+ id_quota: 200
+ }
+}
+
+describe('Testing the updateOrg function', () => {
+ let status, json, res, next, getOrgRepository, orgRepo, getUserRepository,
+ userRepo, updateOrg
+ beforeEach(() => {
+ status = sinon.stub()
+ json = sinon.spy()
+ res = { json, status }
+ next = sinon.spy()
+ status.returns(res)
+
+ orgRepo = new OrgRepository()
+ getOrgRepository = sinon.stub()
+ getOrgRepository.returns(orgRepo)
+
+ userRepo = new UserRepository()
+ getUserRepository = sinon.stub()
+ getUserRepository.returns(userRepo)
+
+ updateOrg = sinon.stub(orgRepo, 'updateByOrgUUID').returns(true)
+ sinon.stub(orgRepo, 'getOrgUUID').returns(true)
+ sinon.stub(userRepo, 'getUserUUID').returns(true)
+ })
+ context('Positive Tests', () => {
+ it('Secretariat updates itself', async () => {
+ sinon.stub(orgRepo, 'isSecretariat').returns(true)
+ sinon.stub(orgRepo, 'findOneByShortName').returns(secretariat)
+ sinon.stub(orgRepo, 'aggregate').returns([secretariat])
+
+ const req = {
+ ctx: {
+ org: secretariat.short_name,
+ repositories: {
+ getOrgRepository,
+ getUserRepository
+ },
+ params: {
+ shortname: secretariat.short_name
+ },
+ query: {
+ id_quota: 111
+ }
+ }
+ }
+ await ORG_UPDATE_SINGLE(req, res, next)
+
+ expect(status.args[0][0]).to.equal(200)
+ expect(updateOrg.args[0][1].policies.id_quota).to.equal(req.ctx.query.id_quota)
+ })
+ it('Secretariat updates a different org', async () => {
+ sinon.stub(orgRepo, 'isSecretariat').returns(true)
+ sinon.stub(orgRepo, 'findOneByShortName').returns(nonSecretariat)
+ sinon.stub(orgRepo, 'aggregate').returns([nonSecretariat])
+
+ const req = {
+ ctx: {
+ org: secretariat.short_name,
+ repositories: {
+ getOrgRepository,
+ getUserRepository
+ },
+ params: {
+ shortname: nonSecretariat.short_name
+ },
+ query: {
+ id_quota: 999
+ }
+ }
+ }
+ await ORG_UPDATE_SINGLE(req, res, next)
+
+ expect(status.args[0][0]).to.equal(200)
+ expect(updateOrg.args[0][1].policies.id_quota).to.equal(req.ctx.query.id_quota)
+ })
+ it('Non-secretariat no params only updates last_active field', async () => {
+ sinon.stub(orgRepo, 'isSecretariat').returns(false)
+ sinon.stub(orgRepo, 'findOneByShortName').returns(nonSecretariat)
+ sinon.stub(orgRepo, 'aggregate').returns([nonSecretariat])
+
+ const req = {
+ ctx: {
+ org: nonSecretariat.short_name,
+ repositories: {
+ getOrgRepository,
+ getUserRepository
+ },
+ params: {
+ shortname: nonSecretariat.short_name
+ }
+ }
+ }
+ await ORG_UPDATE_SINGLE(req, res, next)
+
+ expect(status.args[0][0]).to.equal(200)
+ const now = Date.now()
+ const lastActive = updateOrg.args[0][1].last_active
+ const diff = Math.abs(now - lastActive)
+ const withinHalfASecond = diff < 500
+ expect(withinHalfASecond).to.be.true
+ })
+ })
+})
diff --git a/test/unit-tests/org/orgUpdateTest.js b/test/unit-tests/org/orgUpdateTest.js
index 312cf0b9f..4e5f00b76 100644
--- a/test/unit-tests/org/orgUpdateTest.js
+++ b/test/unit-tests/org/orgUpdateTest.js
@@ -1,4 +1,3 @@
-/* eslint-disable no-unused-expressions */
const express = require('express')
const app = express()
const chai = require('chai')
@@ -39,9 +38,7 @@ class OrgUpdatedAddingRole {
}
async aggregate () {
- const org = orgFixtures.owningOrg
- org.last_active = Date.now()
- return [org]
+ return [orgFixtures.owningOrg]
}
async updateByOrgUUID () {
@@ -63,9 +60,7 @@ class OrgUpdatedRemovingRole {
}
async aggregate () {
- const org = orgFixtures.owningOrg
- org.last_active = Date.now()
- return [org]
+ return [orgFixtures.owningOrg]
}
async updateByOrgUUID () {
@@ -120,6 +115,7 @@ describe('Testing the PUT /org/:shortname endpoint in Org Controller', () => {
return true
}
}
+
app.route('/org-not-updated-shortname-exists/:shortname')
.put((req, res, next) => {
const factory = {
@@ -128,6 +124,7 @@ describe('Testing the PUT /org/:shortname endpoint in Org Controller', () => {
req.ctx.repositories = factory
next()
}, orgParams.parsePostParams, orgController.ORG_UPDATE_SINGLE)
+
chai.request(app)
.put(`/org-not-updated-shortname-exists/${orgFixtures.existentOrg.short_name}?new_short_name=cisco`)
.set(orgFixtures.secretariatHeader)
@@ -135,6 +132,7 @@ describe('Testing the PUT /org/:shortname endpoint in Org Controller', () => {
if (err) {
done(err)
}
+
expect(res).to.have.status(403)
expect(res).to.have.property('body').and.to.be.a('object')
const errObj = error.duplicateShortname('cisco')
@@ -177,11 +175,6 @@ describe('Testing the PUT /org/:shortname endpoint in Org Controller', () => {
expect(res.body.updated.name).to.equal(orgFixtures.owningOrg.name)
expect(res.body.updated.UUID).to.equal(orgFixtures.owningOrg.UUID)
expect(res.body.updated.policies.id_quota).to.equal(orgFixtures.owningOrg.policies.id_quota)
- const now = Date.now()
- const lastActive = res.body.updated.last_active
- const diff = Math.abs(now - lastActive)
- const withinTwoSeconds = diff < 500
- expect(withinTwoSeconds).to.be.true
done()
})
})
@@ -217,11 +210,6 @@ describe('Testing the PUT /org/:shortname endpoint in Org Controller', () => {
expect(res.body.updated.name).to.equal(orgFixtures.owningOrg.name)
expect(res.body.updated.UUID).to.equal(orgFixtures.owningOrg.UUID)
expect(res.body.updated.policies.id_quota).to.equal(orgFixtures.owningOrg.policies.id_quota)
- const now = Date.now()
- const lastActive = res.body.updated.last_active
- const diff = Math.abs(now - lastActive)
- const withinTwoSeconds = diff < 500
- expect(withinTwoSeconds).to.be.true
done()
})
})
@@ -256,11 +244,6 @@ describe('Testing the PUT /org/:shortname endpoint in Org Controller', () => {
expect(res.body.updated.name).to.equal(orgFixtures.owningOrg.name)
expect(res.body.updated.UUID).to.equal(orgFixtures.owningOrg.UUID)
expect(res.body.updated.policies.id_quota).to.equal(orgFixtures.owningOrg.policies.id_quota)
- const now = Date.now()
- const lastActive = res.body.updated.last_active
- const diff = Math.abs(now - lastActive)
- const withinTwoSeconds = diff < 500
- expect(withinTwoSeconds).to.be.true
done()
})
})
@@ -295,11 +278,6 @@ describe('Testing the PUT /org/:shortname endpoint in Org Controller', () => {
expect(res.body.updated.name).to.equal(orgFixtures.owningOrg.name)
expect(res.body.updated.UUID).to.equal(orgFixtures.owningOrg.UUID)
expect(res.body.updated.policies.id_quota).to.equal(orgFixtures.owningOrg.policies.id_quota)
- const now = Date.now()
- const lastActive = res.body.updated.last_active
- const diff = Math.abs(now - lastActive)
- const withinTwoSeconds = diff < 500
- expect(withinTwoSeconds).to.be.true
done()
})
})
@@ -320,9 +298,7 @@ describe('Testing the PUT /org/:shortname endpoint in Org Controller', () => {
}
async aggregate () {
- const org = orgFixtures.existentOrg
- org.last_active = Date.now()
- return [org]
+ return [orgFixtures.existentOrg]
}
async isSecretariat () {
@@ -355,70 +331,6 @@ describe('Testing the PUT /org/:shortname endpoint in Org Controller', () => {
expect(res.body.updated.name).to.equal(orgFixtures.existentOrg.name)
expect(res.body.updated.short_name).to.equal(orgFixtures.existentOrg.short_name)
expect(res.body.updated.UUID).to.equal(orgFixtures.existentOrg.UUID)
- const now = Date.now()
- const lastActive = res.body.updated.last_active
- const diff = Math.abs(now - lastActive)
- const withinTwoSeconds = diff < 500
- expect(withinTwoSeconds).to.be.true
- })
-
- it('Non-secretariat only last_active field updated', (done) => {
- class NonSecretariat {
- async findOneByShortName () {
- return orgFixtures.owningOrg
- }
-
- async aggregate () {
- const org = orgFixtures.owningOrg
- org.last_active = Date.now()
- return [org]
- }
-
- async updateByOrgUUID () {
- return { n: 1 }
- }
-
- async getOrgUUID () {
- return null
- }
-
- async isSecretariat () {
- return false
- }
- }
-
- app.route('/org-non-secretariat-updates-last-active-field/:shortname')
- .put((req, res, next) => {
- const factory = {
- getOrgRepository: () => { return new NonSecretariat() },
- getUserRepository: () => { return new NullUserRepo() }
- }
- req.ctx.repositories = factory
- next()
- }, orgParams.parsePostParams, orgController.ORG_UPDATE_SINGLE)
-
- chai.request(app)
- .put(`/org-non-secretariat-updates-last-active-field/${orgFixtures.owningOrg.short_name}?name=TestOrg`)
- .set(orgFixtures.owningOrgHeader)
- .end((err, res) => {
- if (err) {
- done(err)
- }
- expect(res).to.have.status(200)
- expect(res).to.have.property('body').and.to.be.a('object')
- expect(res.body).to.have.property('updated').and.to.be.a('object')
- // Assert that that the last_active field was updated under 0.5 seconds ago
- const now = Date.now()
- const lastActive = res.body.updated.last_active
- const diff = Math.abs(now - lastActive)
- const withinTwoSeconds = diff < 500
- expect(withinTwoSeconds).to.be.true
- // Assert no other fields were changed
- expect(res.body.updated.active_roles).to.be.undefined
- expect(res.body.updated.name).to.be.undefined
- expect(res.body.updated.policies).to.be.undefined
- done()
- })
})
})
})
From 278065c94a3aeb500232fa1b1028b18666bd1335 Mon Sep 17 00:00:00 2001
From: jack-flores
Date: Thu, 15 Aug 2024 11:41:43 -0400
Subject: [PATCH 15/21] #1258 secretariat update to another org no longer
updates last_active
---
.../org.controller/org.controller.js | 10 ++-
test/integration-tests/org/putOrgTest.js | 80 ++++++++++++++++++-
.../unit-tests/org/orgUpdateLastActiveTest.js | 4 +-
3 files changed, 90 insertions(+), 4 deletions(-)
diff --git a/src/controller/org.controller/org.controller.js b/src/controller/org.controller/org.controller.js
index 0e82f640d..5b94b2d2a 100644
--- a/src/controller/org.controller/org.controller.js
+++ b/src/controller/org.controller/org.controller.js
@@ -364,7 +364,12 @@ async function updateOrg (req, res, next) {
})
}
}
+ if (shortName === orgMakingChanges) {
+ newOrg.last_active = Date.now()
+ }
})
+ } else {
+ newOrg.last_active = Date.now()
}
// updating the org's roles
@@ -398,8 +403,6 @@ async function updateOrg (req, res, next) {
}
}
- newOrg.last_active = Date.now()
-
// update org
let result = await orgRepo.updateByOrgUUID(org.UUID, newOrg)
if (result.n === 0) {
@@ -411,6 +414,9 @@ async function updateOrg (req, res, next) {
result = result.length > 0 ? result[0] : null
if (!isSec) {
+ if (!result.last_active) {
+ return res.status(500).json(error.serverError())
+ }
result = { last_active: result.last_active }
}
diff --git a/test/integration-tests/org/putOrgTest.js b/test/integration-tests/org/putOrgTest.js
index dec0a2b05..28c3a0625 100644
--- a/test/integration-tests/org/putOrgTest.js
+++ b/test/integration-tests/org/putOrgTest.js
@@ -60,7 +60,37 @@ describe('Testing org put endpoint', () => {
expect(err).to.be.undefined
})
})
- it('Update made by non secretariat org to itself ONLY updates last_active field', async () => {
+ it('Update made by a secretariat to another org does NOT update last_active field', async () => {
+ await chai.request(app)
+ .put('/api/org/win_5')
+ .set({ ...constants.headers })
+ .query(params)
+ .send()
+ .then((res, err) => {
+ expect(res.body.updated.last_active).to.be.undefined
+ expect(res).to.have.status(200)
+ expect(err).to.be.undefined
+ })
+ })
+ it('Update made by a secretariat to itself DOES update last_active field', async () => {
+ const now = Date.now()
+ await chai.request(app)
+ .put('/api/org/mitre')
+ .set({ ...constants.headers })
+ .query(params)
+ .send()
+ .then((res, err) => {
+ expect(res.body.updated.last_active).to.not.be.null
+ // Assert that that the last_active field was updated under 2 seconds ago
+ const lastActive = Date.parse(res.body.updated.last_active)
+ const diff = Math.abs(now - lastActive)
+ const withinTwoSeconds = diff < 2000
+ expect(withinTwoSeconds).to.be.true
+ expect(res).to.have.status(200)
+ expect(err).to.be.undefined
+ })
+ })
+ it('Update made by non-secretariat org to itself ONLY updates last_active field', async () => {
const now = Date.now()
await chai.request(app)
.put('/api/org/win_5')
@@ -80,6 +110,54 @@ describe('Testing org put endpoint', () => {
expect(err).to.be.undefined
})
})
+ it('Request body ignored in update made by non-secretariat org to itself', async () => {
+ const requestBody = {
+ key1: 'value1',
+ key2: 'value2',
+ key3: 'value3',
+ key4: 'value4',
+ key5: 'value5',
+ key6: 'value6',
+ key7: 'value7',
+ key8: 'value8'
+ }
+ await chai.request(app)
+ .put('/api/org/win_5')
+ .set({ ...constants.nonSecretariatUserHeaders })
+ .send(requestBody)
+ .then((res, err) => {
+ expect(res).to.have.status(200)
+ expect(res.body.updated.last_active).to.not.be.null
+ expect(res.body.updated.active_roles).to.be.undefined
+ expect(res.body.updated.name).to.be.undefined
+ expect(res.body.updated.policies).to.be.undefined
+ expect(err).to.be.undefined
+ })
+ })
+ it('Request body ignored in update made by secretariat to itself', async () => {
+ const requestBody = {
+ key1: 'value1',
+ key2: 'value2',
+ key3: 'value3',
+ key4: 'value4',
+ key5: 'value5',
+ key6: 'value6',
+ key7: 'value7',
+ key8: 'value8'
+ }
+ await chai.request(app)
+ .put('/api/org/mitre')
+ .set({ ...constants.headers })
+ .query(params)
+ .send(requestBody)
+ .then((res, err) => {
+ expect(res).to.have.status(200)
+ expect(res.body.updated.last_active).to.not.be.null
+ expect(res.body.updated.name).to.equal(params.name)
+ expect(res.body.updated.policies.id_quota).to.equal(params.id_quota)
+ expect(err).to.be.undefined
+ })
+ })
})
context('Negative Tests', () => {
it('Fails update made by a non-secretariat org to a different org', async () => {
diff --git a/test/unit-tests/org/orgUpdateLastActiveTest.js b/test/unit-tests/org/orgUpdateLastActiveTest.js
index 1bffe773a..33fa5bc0c 100644
--- a/test/unit-tests/org/orgUpdateLastActiveTest.js
+++ b/test/unit-tests/org/orgUpdateLastActiveTest.js
@@ -109,7 +109,9 @@ describe('Testing the updateOrg function', () => {
it('Non-secretariat no params only updates last_active field', async () => {
sinon.stub(orgRepo, 'isSecretariat').returns(false)
sinon.stub(orgRepo, 'findOneByShortName').returns(nonSecretariat)
- sinon.stub(orgRepo, 'aggregate').returns([nonSecretariat])
+ const nonSecretariatAgt = nonSecretariat
+ nonSecretariatAgt.last_active = Date.now()
+ sinon.stub(orgRepo, 'aggregate').returns([nonSecretariatAgt])
const req = {
ctx: {
From 20c159611b10bb7afcbbb50105315b37b98348b9 Mon Sep 17 00:00:00 2001
From: Noah Jaffe
Date: Fri, 16 Aug 2024 08:46:35 -0400
Subject: [PATCH 16/21] Update swagger.js to reflect changes from
https://github.com/CVEProject/cve-schema/commit/b83c668. Fixes #1246
---
src/swagger.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/swagger.js b/src/swagger.js
index 4f77c388f..0dc9cc1f0 100644
--- a/src/swagger.js
+++ b/src/swagger.js
@@ -34,7 +34,7 @@ const doc = {
or MITRE) to request credentials \
\
CVE data is to be in the JSON 5.1 CVE Record format. Details of the JSON 5.1 schema are \
- located here.
\
+ located here.
\
Contact the CVE Services team",
contact: {
name: 'CVE Services Overview',
From 0efc8aa8e5cbee6831e691afedabb22605bbb3f7 Mon Sep 17 00:00:00 2001
From: jack-flores
Date: Mon, 19 Aug 2024 15:27:16 -0400
Subject: [PATCH 17/21] #1258 addressing comments from team
---
api-docs/openapi.json | 2 +-
package-lock.json | 46 +++++++++----------
src/controller/org.controller/index.js | 2 +-
.../org.controller/org.controller.js | 6 ++-
4 files changed, 29 insertions(+), 27 deletions(-)
diff --git a/api-docs/openapi.json b/api-docs/openapi.json
index f6974fb06..c01ef610c 100644
--- a/api-docs/openapi.json
+++ b/api-docs/openapi.json
@@ -2099,7 +2099,7 @@
"Organization"
],
"summary": "Updates information about the organization specified by short name (accessible to Secretariat)",
- "description": " Access Control
User must belong to an organization with the Secretariat role
Expected Behavior
CNA: Updates 'last_active' timestamp to show that a CNA is still active
Secretariat: Updates any organization's information
",
+ "description": " Access Control
User must belong to an organization with the Secretariat or CNA role
Expected Behavior
CNA: Updates 'last_active' timestamp to show that a CNA is still active
Secretariat: Updates any organization's information
",
"operationId": "orgUpdateSingle",
"parameters": [
{
diff --git a/package-lock.json b/package-lock.json
index 0aa408138..ac792daf1 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "cve-services",
- "version": "2.3.1",
+ "version": "2.3.3",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "cve-services",
- "version": "2.3.1",
+ "version": "2.3.3",
"license": "(CC0)",
"dependencies": {
"ajv": "^8.6.2",
@@ -2023,12 +2023,12 @@
}
},
"node_modules/braces": {
- "version": "3.0.3",
- "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
- "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
+ "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
"dev": true,
"dependencies": {
- "fill-range": "^7.1.1"
+ "fill-range": "^7.0.1"
},
"engines": {
"node": ">=8"
@@ -3882,9 +3882,9 @@
}
},
"node_modules/fill-range": {
- "version": "7.1.1",
- "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
- "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
+ "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
"dev": true,
"dependencies": {
"to-regex-range": "^5.0.1"
@@ -4212,9 +4212,9 @@
}
},
"node_modules/get-func-name": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz",
- "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==",
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz",
+ "integrity": "sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==",
"dev": true,
"engines": {
"node": "*"
@@ -11906,12 +11906,12 @@
}
},
"braces": {
- "version": "3.0.3",
- "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
- "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
+ "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
"dev": true,
"requires": {
- "fill-range": "^7.1.1"
+ "fill-range": "^7.0.1"
}
},
"browser-stdout": {
@@ -13288,9 +13288,9 @@
}
},
"fill-range": {
- "version": "7.1.1",
- "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
- "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
+ "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
"dev": true,
"requires": {
"to-regex-range": "^5.0.1"
@@ -13534,9 +13534,9 @@
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="
},
"get-func-name": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz",
- "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==",
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz",
+ "integrity": "sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==",
"dev": true
},
"get-intrinsic": {
@@ -18194,4 +18194,4 @@
"dev": true
}
}
-}
+}
\ No newline at end of file
diff --git a/src/controller/org.controller/index.js b/src/controller/org.controller/index.js
index 598cb0550..ab3b76b6e 100644
--- a/src/controller/org.controller/index.js
+++ b/src/controller/org.controller/index.js
@@ -310,10 +310,10 @@ router.put('/org/:shortname',
}
*/
mw.validateUser,
+ param(['shortname']).isString().trim().isLength({ min: CONSTANTS.MIN_SHORTNAME_LENGTH, max: CONSTANTS.MAX_SHORTNAME_LENGTH }),
mw.validateOrg,
query().custom((query) => { return mw.validateQueryParameterNames(query, ['new_short_name', 'id_quota', 'name', 'active_roles.add', 'active_roles.remove']) }),
query(['new_short_name', 'id_quota', 'name', 'active_roles.add', 'active_roles.remove']).custom((val) => { return mw.containsNoInvalidCharacters(val) }),
- param(['shortname']).isString().trim().isLength({ min: CONSTANTS.MIN_SHORTNAME_LENGTH, max: CONSTANTS.MAX_SHORTNAME_LENGTH }),
query(['new_short_name']).optional().isString().trim().notEmpty().isLength({ min: CONSTANTS.MIN_SHORTNAME_LENGTH, max: CONSTANTS.MAX_SHORTNAME_LENGTH }),
query(['id_quota']).optional().not().isArray().isInt({ min: CONSTANTS.MONGOOSE_VALIDATION.Org_policies_id_quota_min, max: CONSTANTS.MONGOOSE_VALIDATION.Org_policies_id_quota_max }).withMessage(errorMsgs.ID_QUOTA),
query(['name']).optional().isString().trim().notEmpty(),
diff --git a/src/controller/org.controller/org.controller.js b/src/controller/org.controller/org.controller.js
index 5b94b2d2a..566781265 100644
--- a/src/controller/org.controller/org.controller.js
+++ b/src/controller/org.controller/org.controller.js
@@ -368,7 +368,9 @@ async function updateOrg (req, res, next) {
newOrg.last_active = Date.now()
}
})
- } else {
+ }
+
+ if (shortName === orgMakingChanges) {
newOrg.last_active = Date.now()
}
@@ -414,7 +416,7 @@ async function updateOrg (req, res, next) {
result = result.length > 0 ? result[0] : null
if (!isSec) {
- if (!result.last_active) {
+ if (!result || !result.last_active) {
return res.status(500).json(error.serverError())
}
result = { last_active: result.last_active }
From 9d1e931dd084ed9d220e5bf33b3927cc463ee032 Mon Sep 17 00:00:00 2001
From: jack-flores
Date: Mon, 19 Aug 2024 17:21:03 -0400
Subject: [PATCH 18/21] #1258 update openapi.json
---
api-docs/openapi.json | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/api-docs/openapi.json b/api-docs/openapi.json
index c01ef610c..7eed055b3 100644
--- a/api-docs/openapi.json
+++ b/api-docs/openapi.json
@@ -2142,7 +2142,14 @@
"content": {
"application/json": {
"schema": {
- "$ref": "../schemas/org/update-org-response.json"
+ "oneOf": [
+ {
+ "$ref": "../schemas/org/update-org-response.json"
+ },
+ {
+ "$ref": "../schemas/org/update-org-response.json"
+ }
+ ]
}
}
}
From 13cc2b2be0d769c8c7a943d4ea490fa4e6194675 Mon Sep 17 00:00:00 2001
From: jack-flores
Date: Tue, 20 Aug 2024 11:36:51 -0400
Subject: [PATCH 19/21] reverting openapi.json to most recent correct ver
---
api-docs/openapi.json | 11 ++---------
1 file changed, 2 insertions(+), 9 deletions(-)
diff --git a/api-docs/openapi.json b/api-docs/openapi.json
index 7eed055b3..1a7ebad46 100644
--- a/api-docs/openapi.json
+++ b/api-docs/openapi.json
@@ -2099,7 +2099,7 @@
"Organization"
],
"summary": "Updates information about the organization specified by short name (accessible to Secretariat)",
- "description": " Access Control
User must belong to an organization with the Secretariat or CNA role
Expected Behavior
CNA: Updates 'last_active' timestamp to show that a CNA is still active
Secretariat: Updates any organization's information
",
+ "description": " Access Control
User must belong to an organization with the Secretariat role
Expected Behavior
Secretariat: Updates any organization's information
",
"operationId": "orgUpdateSingle",
"parameters": [
{
@@ -2142,14 +2142,7 @@
"content": {
"application/json": {
"schema": {
- "oneOf": [
- {
- "$ref": "../schemas/org/update-org-response.json"
- },
- {
- "$ref": "../schemas/org/update-org-response.json"
- }
- ]
+ "$ref": "../schemas/org/update-org-response.json"
}
}
}
From 85a407610a274975c9d8cce3e7969abbfd396d2d Mon Sep 17 00:00:00 2001
From: jack-flores
Date: Tue, 20 Aug 2024 11:43:52 -0400
Subject: [PATCH 20/21] #1258 addressing comments from team
---
api-docs/openapi.json | 11 +++++++++--
src/controller/org.controller/index.js | 13 +++++++++----
src/controller/org.controller/org.controller.js | 3 ---
3 files changed, 18 insertions(+), 9 deletions(-)
diff --git a/api-docs/openapi.json b/api-docs/openapi.json
index 1a7ebad46..34fb3cedf 100644
--- a/api-docs/openapi.json
+++ b/api-docs/openapi.json
@@ -2099,7 +2099,7 @@
"Organization"
],
"summary": "Updates information about the organization specified by short name (accessible to Secretariat)",
- "description": " Access Control
User must belong to an organization with the Secretariat role
Expected Behavior
Secretariat: Updates any organization's information
",
+ "description": " Access Control
User must belong to an organization with the Secretariat role, or user must belong to the organization specified by short name
Expected Behavior
Secretariat: Updates any organization's information
Non-secretariat: Updates 'last_active' timestamp to show that an org is still active
",
"operationId": "orgUpdateSingle",
"parameters": [
{
@@ -2142,7 +2142,14 @@
"content": {
"application/json": {
"schema": {
- "$ref": "../schemas/org/update-org-response.json"
+ "oneOf": [
+ {
+ "$ref": "../schemas/org/update-org-response.json"
+ },
+ {
+ "$ref": "../schemas/org/am-i-alive-response.json"
+ }
+ ]
}
}
}
diff --git a/src/controller/org.controller/index.js b/src/controller/org.controller/index.js
index ab3b76b6e..2c9279835 100644
--- a/src/controller/org.controller/index.js
+++ b/src/controller/org.controller/index.js
@@ -245,10 +245,10 @@ router.put('/org/:shortname',
#swagger.summary = "Updates information about the organization specified by short name (accessible to Secretariat)"
#swagger.description = "
Access Control
- User must belong to an organization with the Secretariat role
+ User must belong to an organization with the Secretariat role, or user must belong to the organization specified by short name
Expected Behavior
- CNA: Updates 'last_active' timestamp to show that a CNA is still active
- Secretariat: Updates any organization's information
"
+ Secretariat: Updates any organization's information
+ Non-secretariat: Updates 'last_active' timestamp to show that an org is still active
"
#swagger.parameters['shortname'] = { description: 'The shortname of the organization' }
#swagger.parameters['$ref'] = [
'#/components/parameters/id_quota',
@@ -264,7 +264,12 @@ router.put('/org/:shortname',
description: 'Returns information about the organization updated',
content: {
"application/json": {
- schema: { $ref: '../schemas/org/update-org-response.json' }
+ schema: {
+ oneOf: [
+ { $ref: '../schemas/org/update-org-response.json' },
+ { $ref: '../schemas/org/am-i-alive-response.json' }
+ ]
+ }
}
}
}
diff --git a/src/controller/org.controller/org.controller.js b/src/controller/org.controller/org.controller.js
index 566781265..7803da44c 100644
--- a/src/controller/org.controller/org.controller.js
+++ b/src/controller/org.controller/org.controller.js
@@ -364,9 +364,6 @@ async function updateOrg (req, res, next) {
})
}
}
- if (shortName === orgMakingChanges) {
- newOrg.last_active = Date.now()
- }
})
}
From f4a125bc57b4c4af05d75ca1b7f12958e531e809 Mon Sep 17 00:00:00 2001
From: "Daigneau, Jeremy T"
Date: Mon, 26 Aug 2024 11:01:02 -0400
Subject: [PATCH 21/21] updated version number to 2.4.0
---
api-docs/openapi.json | 4 ++--
package-lock.json | 4 ++--
src/swagger.js | 2 +-
3 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/api-docs/openapi.json b/api-docs/openapi.json
index 34fb3cedf..1fb6cb8fe 100644
--- a/api-docs/openapi.json
+++ b/api-docs/openapi.json
@@ -1,9 +1,9 @@
{
"openapi": "3.0.2",
"info": {
- "version": "2.3.3",
+ "version": "2.4.0",
"title": "CVE Services API",
- "description": "The CVE Services API supports automation tooling for the CVE Program. Credentials are required for most service endpoints. Representatives of CVE Numbering Authorities (CNAs) should use one of the methods below to obtain credentials: - If your organization already has an Organizational Administrator (OA) account for the CVE Services, ask your admin for credentials
- Contact your Root (Google, INCIBE, JPCERT/CC, or Red Hat) or Top-Level Root (CISA ICS or MITRE) to request credentials
CVE data is to be in the JSON 5.1 CVE Record format. Details of the JSON 5.1 schema are located here.
Contact the CVE Services team",
+ "description": "The CVE Services API supports automation tooling for the CVE Program. Credentials are required for most service endpoints. Representatives of CVE Numbering Authorities (CNAs) should use one of the methods below to obtain credentials: - If your organization already has an Organizational Administrator (OA) account for the CVE Services, ask your admin for credentials
- Contact your Root (Google, INCIBE, JPCERT/CC, or Red Hat) or Top-Level Root (CISA ICS or MITRE) to request credentials
CVE data is to be in the JSON 5.1 CVE Record format. Details of the JSON 5.1 schema are located here.
Contact the CVE Services team",
"contact": {
"name": "CVE Services Overview",
"url": "https://cveproject.github.io/automation-cve-services#services-overview"
diff --git a/package-lock.json b/package-lock.json
index ac792daf1..f061baaba 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "cve-services",
- "version": "2.3.3",
+ "version": "2.4.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "cve-services",
- "version": "2.3.3",
+ "version": "2.4.0",
"license": "(CC0)",
"dependencies": {
"ajv": "^8.6.2",
diff --git a/src/swagger.js b/src/swagger.js
index 0dc9cc1f0..c9ea656a1 100644
--- a/src/swagger.js
+++ b/src/swagger.js
@@ -18,7 +18,7 @@ const fullCnaContainerRequest = require('../schemas/cve/create-cve-record-cna-re
/* eslint-disable no-multi-str */
const doc = {
info: {
- version: '2.3.3',
+ version: '2.4.0',
title: 'CVE Services API',
description: "The CVE Services API supports automation tooling for the CVE Program. Credentials are \
required for most service endpoints. Representatives of \