Skip to content
Merged

Jd 2000 #2001

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions api-docs/openapi.json
Original file line number Diff line number Diff line change
Expand Up @@ -3833,7 +3833,7 @@
"Registry Organization"
],
"summary": "Updates information about the organization specified by short name (accessible to Secretariat or same-organization Admin)",
"description": " <h2>Access Control</h2> <p>User must belong to an organization with the <b>Secretariat</b> role or be an <b>Admin</b> of the requested organization.</p> <p>With Joint Approval required for the following fields:</p> <h2>Expected Behavior</h2> <b>This endpoint expects a full organization object in the request body.</b> <p><b>Secretariat:</b> Updates any organization's information</p> <p><b>Organization Admin:</b> Requests changes to its organization's information</p> <ul> <li>short_name</li> <li>long_name</li> <li>authority</li> <li>aliases</li> <li>oversees</li> <li>top_level_root</li> <li>charter_or_scope</li> <li>product_list</li> <li>disclosure_policy</li> <li>contact_info.websites</li> <li>contact_info.emails</li> <li>partner_role_type</li> <li>partner_country</li> <li>advisory_locations</li> <li>advisory_location_require_credentials</li> <li>vulnerability_advisory_location_for_web_scraping</li> <li>industry</li> <li>tl_root_start_date</li> <li>is_cna_discussion_list</li> </ul>",
"description": " <h2>Access Control</h2> <p>User must belong to an organization with the <b>Secretariat</b> role or be an <b>Admin</b> of the requested organization.</p> <p>With Joint Approval required for the following fields:</p> <h2>Expected Behavior</h2> <b>This endpoint expects a full organization object in the request body.</b> <p><b>Secretariat:</b> Updates any organization's information</p> <p><b>Organization Admin:</b> Requests changes to its organization's information</p> <ul> <li>short_name</li> <li>long_name</li> <li>authority</li> <li>aliases</li> <li>oversees</li> <li>top_level_root</li> <li>is_top_level_root</li> <li>is_last_resort</li> <li>charter_or_scope</li> <li>product_list</li> <li>disclosure_policy</li> <li>contact_info.websites</li> <li>contact_info.emails</li> <li>partner_role_type</li> <li>partner_country</li> <li>advisory_locations</li> <li>advisory_location_require_credentials</li> <li>vulnerability_advisory_location_for_web_scraping</li> <li>industry</li> <li>tl_root_start_date</li> <li>is_cna_discussion_list</li> </ul>",
"operationId": "registryOrgUpdateSingle",
"parameters": [
{
Expand Down Expand Up @@ -8120,4 +8120,4 @@
}
}
}
}
}
7 changes: 1 addition & 6 deletions datadump/pre-population/orgs.json
Original file line number Diff line number Diff line change
Expand Up @@ -323,11 +323,6 @@
}
},
{
"authority": {
"active_roles": [
"CNA"
]
},
"name": "Chase, May and Jones",
"short_name": "sister_20",
"time": {
Expand All @@ -338,4 +333,4 @@
"id_quota": 1408
}
}
]
]
5 changes: 3 additions & 2 deletions docker/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,9 +89,9 @@ You should see the following:
> NODE_ENV=development node-dev src/scripts/populate.js

2022-06-07 19:58:32 [info]: "Successfully connected to database!"
Are you sure you wish to pre-populate the database for the development environment? Doing so will drop and rebuild the database, run migrations, and populate the Org, BaseOrg, User, BaseUser, Glossary collection(s) in the cve_dev database. (y/n) y
Are you sure you wish to pre-populate the database for the development environment? Doing so will drop and rebuild the database, populate the Org, BaseOrg, User, BaseUser, Glossary collection(s), and run migrations in the cve_dev database. (y/n) y

2022-06-07 19:58:37 [info]: "Dropping cve_dev database before running migrations..."
2022-06-07 19:58:37 [info]: "Dropping cve_dev database before population..."
2022-06-07 19:58:37 [info]: "Successfully dropped cve_dev database."
2022-06-07 19:58:37 [info]: "Populating Org collection..."
2022-06-07 19:58:37 [info]: "Org populated!"
Expand All @@ -103,6 +103,7 @@ Are you sure you wish to pre-populate the database for the development environme
2022-06-07 19:58:38 [info]: "BaseUser populated!"
2022-06-07 19:58:38 [info]: "Populating Glossary collection..."
2022-06-07 19:58:39 [info]: "Glossary populated!"
2022-06-07 19:58:39 [info]: "Successfully ran database migrations."
2022-06-07 19:58:39 [info]: "Successfully populated the database!"

```
Expand Down
29 changes: 29 additions & 0 deletions migrations/20260903-01-set-registry-org-disabled.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
const ACTIVE_ROLE_PATH = 'authority.active_roles.0'

module.exports = {
async up (db) {
const baseOrgCollection = db.collection('BaseOrg')
const orgCollection = db.collection('Org')

await baseOrgCollection.updateMany(
{},
{ $set: { disabled: true } }
)

const enabledOrgUUIDs = (await orgCollection.distinct(
'UUID',
{ [ACTIVE_ROLE_PATH]: { $exists: true } }
)).filter(UUID => typeof UUID === 'string' && UUID.length > 0)

if (enabledOrgUUIDs.length > 0) {
await baseOrgCollection.updateMany(
{ UUID: { $in: enabledOrgUUIDs } },
{ $set: { disabled: false } }
)
}
},

async down () {
// Existing migration values cannot be distinguished from later Secretariat updates.
}
}
5 changes: 5 additions & 0 deletions schemas/registry-org/BaseOrg.json
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,11 @@
"long_name": {
"$ref": "#/definitions/longName"
},
"disabled": {
"type": "boolean",
"default": true,
"description": "Indicates whether the organization is disabled."
},
"new_short_name": {
"$ref": "#/definitions/shortName"
},
Expand Down
3 changes: 3 additions & 0 deletions schemas/registry-org/CNAOrg.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@
"long_name": {
"$ref": "/BaseOrg#/definitions/longName"
},
"disabled": {
"$ref": "/BaseOrg#/properties/disabled"
},
"new_short_name": {
"description": "Used to rename an organization's short name during an update.",
"type": "string",
Expand Down
3 changes: 3 additions & 0 deletions schemas/registry-org/RootOrg.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@
"long_name": {
"$ref": "/BaseOrg#/definitions/longName"
},
"disabled": {
"$ref": "/BaseOrg#/properties/disabled"
},
"new_short_name": {
"description": "Used to rename an organization's short name during an update.",
"type": "string",
Expand Down
5 changes: 5 additions & 0 deletions schemas/registry-org/create-registry-org-request.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@
"type": "string",
"description": "Full name of the organization"
},
"disabled": {
"type": "boolean",
"default": true,
"description": "Indicates whether the organization is disabled. This field can only be modified by the Secretariat."
},
"short_name": {
"type": "string",
"description": "Short name or acronym of the organization"
Expand Down
4 changes: 4 additions & 0 deletions schemas/registry-org/create-registry-org-response.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@
"type": "string",
"description": "Full name of the organization"
},
"disabled": {
"type": "boolean",
"description": "Indicates whether the organization is disabled"
},
"short_name": {
"type": "string",
"description": "Short name or acronym of the organization"
Expand Down
4 changes: 4 additions & 0 deletions schemas/registry-org/get-registry-org-response.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@
"type": "string",
"description": "Full name of the organization"
},
"disabled": {
"type": "boolean",
"description": "Indicates whether the organization is disabled"
},
"aliases": {
"type": "array",
"items": {
Expand Down
4 changes: 4 additions & 0 deletions schemas/registry-org/list-registry-orgs-response.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@
"type": "string",
"description": "Full name of the organization"
},
"disabled": {
"type": "boolean",
"description": "Indicates whether the organization is disabled"
},
"aliases": {
"type": "array",
"items": {
Expand Down
4 changes: 4 additions & 0 deletions schemas/registry-org/update-registry-org-request.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@
"type": "string",
"description": "Full name of the organization"
},
"disabled": {
"type": "boolean",
"description": "Indicates whether the organization is disabled. This field can only be modified by the Secretariat."
},
"short_name": {
"type": "string",
"description": "Short name or acronym of the organization"
Expand Down
4 changes: 4 additions & 0 deletions schemas/registry-org/update-registry-org-response.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@
"type": "string",
"description": "Full name of the organization"
},
"disabled": {
"type": "boolean",
"description": "Indicates whether the organization is disabled"
},
"short_name": {
"type": "string",
"description": "Short name or acronym of the organization"
Expand Down
1 change: 1 addition & 0 deletions src/constants/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ function getConstants () {
ORG_EXCLUDED_FIELDS: ['__t', '__v', '_id', 'inUse', 'in_use'],
ORG_RESTRICTED_FIELDS: ['program_data'],
SECRETARIAT_ONLY_FIELDS: [
'disabled',
'partner_number',
'program_data',
'program_data.cve_website_update_date',
Expand Down
1 change: 1 addition & 0 deletions src/model/baseorg.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ const schema = {
UUID: String,
long_name: String,
short_name: String,
disabled: { type: Boolean, default: true },
aliases: [String],
authority: [String],
top_level_root: String,
Expand Down
4 changes: 3 additions & 1 deletion src/repositories/baseOrgRepositoryHelpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,9 @@ async function processJointApprovalAndMerge (registryOrg, legacyOrg, registryObj
const protectedFields = ['_id', 'UUID', '__v', '__t', 'created', 'last_updated', 'createdAt', 'updatedAt', 'users', 'admins', 'inUse', 'in_use']
let registryProtectedFields = [...protectedFields]
if (!isSecretariat) {
registryProtectedFields = [...registryProtectedFields, ...getConstants().ORG_RESTRICTED_FIELDS]
// disabled is publicly visible but can only be supplied by the Secretariat.
// Preserve its stored value when a non-Secretariat full update omits it.
registryProtectedFields = [...registryProtectedFields, ...getConstants().ORG_RESTRICTED_FIELDS, 'disabled']
}

let updatedRegistryOrg = null
Expand Down
10 changes: 5 additions & 5 deletions src/scripts/populate.js
Original file line number Diff line number Diff line change
Expand Up @@ -211,11 +211,10 @@ async function populateBaseUserCollection () {
logger.info('BaseUser populated!')
}

async function resetDatabaseAndRunMigrations () {
logger.info(`Dropping ${migrationConfig.mongodb.databaseName} database before running migrations...`)
async function resetDatabase () {
logger.info(`Dropping ${migrationConfig.mongodb.databaseName} database before population...`)
await db.db.dropDatabase()
logger.info(`Successfully dropped ${migrationConfig.mongodb.databaseName} database.`)
await runDatabaseMigrations()
}

async function populateSeedCollections () {
Expand Down Expand Up @@ -273,13 +272,14 @@ async function populateDatabase () {
} else {
userInput = dataUtils.getUserPopulateInput(
Object.keys(populateTheseCollections),
`drop and rebuild the database, run migrations, and populate the ${Object.keys(populateTheseCollections).join(', ')} collection(s)`
`drop and rebuild the database, populate the ${Object.keys(populateTheseCollections).join(', ')} collection(s), and run migrations`
)
}

if (userInput.toLowerCase() === 'y') {
await resetDatabaseAndRunMigrations()
await resetDatabase()
await populateSeedCollections()
await runDatabaseMigrations()
logger.info('Successfully populated the database!')
console.log('Successfully populated the database!')
}
Expand Down
14 changes: 14 additions & 0 deletions test/integration-tests/conversation/editConversationTest.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ const orgAdminHeaders = {

describe('Testing Conversation edit by index endpoint', () => {
let org
let disabled

before(async () => {
await chai
Expand All @@ -26,13 +27,15 @@ describe('Testing Conversation edit by index endpoint', () => {
expect(err).to.be.undefined
expect(res).to.have.status(200)
org = res.body
disabled = org.disabled
delete org.created
delete org.last_updated
delete org.admins
delete org.users
delete org.top_level_root
delete org.oversees
delete org.program_data
delete org.disabled
})

await chai
Expand Down Expand Up @@ -86,6 +89,17 @@ describe('Testing Conversation edit by index endpoint', () => {
})

context('Positive Tests', () => {
it('Preserves disabled when omitted from an org admin update', async () => {
await chai.request(app)
.get('/api/registry/org/activity_6')
.set(constants.headers)
.then((res, err) => {
expect(err).to.be.undefined
expect(res).to.have.status(200)
expect(res.body.disabled).to.equal(disabled)
})
})

it('Should update own conversation as org admin', async () => {
await chai.request(app)
.put('/api/registry/org/activity_6/conversation/0')
Expand Down
38 changes: 38 additions & 0 deletions test/integration-tests/registry-org/registryOrgCRUDTest.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@ describe('Testing /registry/org endpoints', () => {
expect(res.body.created).to.haveOwnProperty('authority')
expect(res.body.created.authority).to.deep.equal(['CNA'])

expect(res.body.created).to.haveOwnProperty('disabled')
expect(res.body.created.disabled).to.equal(true)

expect(res.body.created).to.haveOwnProperty('id_quota')
expect(res.body.created.id_quota).to.equal(testRegistryOrg.id_quota)

Expand Down Expand Up @@ -676,6 +679,7 @@ describe('Testing /registry/org endpoints', () => {
partner_number: 'Updated Partner Number',
partner_country: 'UK',
advisory_locations: ['https://example.com/updated_advisories'],
disabled: false,
is_last_resort: false
})
.then((res, err) => {
Expand All @@ -699,6 +703,10 @@ describe('Testing /registry/org endpoints', () => {
expect(res.body.updated).to.haveOwnProperty('authority')
expect(res.body.updated.authority).to.deep.equal(['CNA'])

expect(res.body.updated).to.haveOwnProperty('disabled')
expect(res.body.updated.disabled).to.equal(false)
createdOrg.disabled = false

expect(res.body.updated).to.haveOwnProperty('id_quota')
expect(res.body.updated.id_quota).to.equal(createdOrg.id_quota)

Expand All @@ -723,6 +731,7 @@ describe('Testing /registry/org endpoints', () => {
.then((res) => {
expect(res).to.have.status(200)
expect(res.body.is_last_resort).to.equal(false)
expect(res.body.disabled).to.equal(false)
})
})
it('Allows Secretariat to update program_data', async () => {
Expand Down Expand Up @@ -1135,6 +1144,35 @@ describe('Testing /registry/org endpoints', () => {
expect(res.body.message).to.equal('The following fields can only be modified by the Secretariat: program_data, program_data.status.')
})
})
it('Fails to allow an admin to change the disabled flag', async () => {
await chai.request(app)
.put('/api/registry/org/win_5')
.set(constants.nonSecretariatUserHeaders2)
.send({ disabled: true })
.then((res) => {
expect(res).to.have.status(403)
expect(res.body.message).to.equal('The following fields can only be modified by the Secretariat: disabled.')
})
})
it('Fails to allow an admin to supply the unchanged disabled flag', async () => {
let disabled
await chai.request(app)
.get('/api/registry/org/win_5')
.set(secretariatHeaders)
.then((res) => {
expect(res).to.have.status(200)
disabled = res.body.disabled
})

await chai.request(app)
.put('/api/registry/org/win_5')
.set(constants.nonSecretariatUserHeaders2)
.send({ disabled })
.then((res) => {
expect(res).to.have.status(403)
expect(res.body.message).to.equal('The following fields can only be modified by the Secretariat: disabled.')
})
})
it('Fails to update a registry organization providing an erroneous key not found in the schema', async () => {
await chai.request(app)
.put('/api/registry/org/registry_org_test')
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/* eslint-disable no-unused-expressions */
const chai = require('chai')
const expect = chai.expect
chai.use(require('chai-http'))

const constants = require('../constants.js')
const app = require('../../../src/index.js')

const secretariatHeaders = { ...constants.headers, 'content-type': 'application/json' }

describe('Registry organization disabled migration', () => {
it('enables a seeded registry organization whose legacy organization has an active authority', async () => {
const res = await chai.request(app)
.get('/api/registry/org/interesting_19')
.set(secretariatHeaders)

expect(res).to.have.status(200)
expect(res.body.disabled).to.equal(false)
})

it('disables the seeded registry organization whose legacy organization has no authority', async () => {
const res = await chai.request(app)
.get('/api/registry/org/sister_20')
.set(secretariatHeaders)

expect(res).to.have.status(200)
expect(res.body.disabled).to.equal(true)
})
})
3 changes: 3 additions & 0 deletions test/integration-tests/registry-org/rootOrgTest.js
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,9 @@ describe('Testing ROOT Organization Type', () => {

context('ROOT admin permissions', () => {
before(async () => {
// Non-Secretariat callers must omit Secretariat-only fields from PUT payloads.
delete createdOrg.disabled

// Create a Root Admin user
await chai.request(app)
.post(`/api/registry/org/${testRootOrg.short_name}/user`)
Expand Down
Loading