Skip to content

Commit 4235db1

Browse files
fix: don't mix async/await w/ .then in populate script
This fixes a race condition present in the existing populate script caused by missing `await`. For consistency, it transitions the entire file to an ECMAScript module, which permits top-level await, and then updates all uses of Mongoose APIs to 1) make sure we're always `await`-ing any Promises, and 2) only use `await` rather than any alternative callback-oriented APIs. This appears to have resolved the race locally, which previously permitted early-closure of the connection to the MongoDB database. Signed-off-by: Andrew Lilley Brinker <abrinker@mitre.org>
1 parent 0aa7a4d commit 4235db1

3 files changed

Lines changed: 176 additions & 153 deletions

File tree

package.json

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -82,10 +82,10 @@
8282
"migrate:dev": "NODE_ENV=development MONGO_CONN_STRING=mongodb://localhost:27017 MONGO_DB_NAME=cve_dev node-dev src/scripts/migrate.js",
8383
"migrate:test-black-box": "NODE_ENV=development MONGO_CONN_STRING=mongodb://docdb:27017 MONGO_DB_NAME=cve_dev node-dev src/scripts/migrate.js",
8484
"migrate:test": "NODE_ENV=test MONGO_CONN_STRING=mongodb://localhost:27017 MONGO_DB_NAME=cve_test node-dev src/scripts/migrate.js",
85-
"populate:dev": "NODE_ENV=development node-dev src/scripts/populate.js",
86-
"populate:stage": "NODE_ENV=staging node src/scripts/populate.js",
87-
"populate:int": "NODE_ENV=integration node src/scripts/populate.js",
88-
"populate:prd": "NODE_ENV=production node src/scripts/populate.js",
85+
"populate:dev": "NODE_ENV=development node-dev src/scripts/populate.mjs",
86+
"populate:stage": "NODE_ENV=staging node src/scripts/populate.mjs",
87+
"populate:int": "NODE_ENV=integration node src/scripts/populate.mjs",
88+
"populate:prd": "NODE_ENV=production node src/scripts/populate.mjs",
8989
"populate-cve:dev": "NODE_ENV=development node-dev src/scripts/populate-cve.js",
9090
"populate-cve:stage": "NODE_ENV=staging node src/scripts/populate-cve.js",
9191
"populate-cve:int": "NODE_ENV=integration node src/scripts/populate-cve.js",
@@ -96,7 +96,8 @@
9696
"start:prd": "node src/swagger.js && NODE_ENV=production node src/scripts/updateOpenapiHost.js && NODE_ENV=production node src/index.js",
9797
"swagger-autogen": "node src/swagger.js",
9898
"test": "NODE_ENV=test mocha --recursive --exit || true",
99-
"test:integration": "NODE_ENV=test node-dev src/scripts/populate.js y; NODE_ENV=test MONGO_CONN_STRING=mongodb://docdb:27017 MONGO_DB_NAME=cve_test node-dev src/scripts/migrate.js; NODE_ENV=test mocha test/integration-tests --recursive --exit",
99+
"test:integration": "NODE_ENV=test node-dev src/scripts/populate.mjs y; NODE_ENV=test MONGO_CONN_STRING=mongodb://docdb:27017 MONGO_DB_NAME=cve_test node-dev src/scripts/migrate.js; NODE_ENV=test mocha test/integration-tests --recursive --exit",
100+
"test:integration-local": "NODE_ENV=test node-dev src/scripts/populate.mjs y; NODE_ENV=test MONGO_CONN_STRING=mongodb://localhost:27017 MONGO_DB_NAME=cve_test node-dev src/scripts/migrate.js; NODE_ENV=test mocha test/integration-tests --recursive --exit",
100101
"test:unit-tests": "NODE_ENV=test mocha test/unit-tests --recursive --exit || true",
101102
"test:coverage": "NODE_ENV=test nyc --reporter=text mocha src/* --recursive --exit || true",
102103
"test:coverage-html": "NODE_ENV=test nyc --reporter=html mocha src/* --recursive --exit || true",

src/scripts/populate.js

Lines changed: 0 additions & 148 deletions
This file was deleted.

src/scripts/populate.mjs

Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
/**
2+
* Populate script, used to either populate or re-populate a MongoDB-compatible
3+
* document database with static fixtures defined at
4+
* `cve-services/datadump/pre-population`.
5+
*/
6+
7+
// ===========================================================================
8+
// Imports
9+
// ---------------------------------------------------------------------------
10+
11+
// Deps
12+
import express from 'express'
13+
import mongoose from 'mongoose'
14+
import dataUtils from '../utils/data.js'
15+
import dbUtils from '../utils/db.js'
16+
17+
// Models
18+
import CveIdRange from '../model/cve-id-range.js'
19+
import CveId from '../model/cve-id.js'
20+
import Cve from '../model/cve.js'
21+
import Org from '../model/org.js'
22+
import User from '../model/user.js'
23+
import BaseOrg from '../model/baseorg.js'
24+
import BaseUser from '../model/baseuser.js'
25+
import ReviewObject from '../model/reviewobject.js'
26+
import Conversation from '../model/conversation.js'
27+
import Audit from '../model/audit.js'
28+
29+
// ===========================================================================
30+
// Models to Populate
31+
// ---------------------------------------------------------------------------
32+
33+
const populateTargets = {
34+
'Cve': Cve,
35+
'Cve-Id-Range': CveIdRange,
36+
'Cve-Id': CveId,
37+
'User': User,
38+
'Org': Org,
39+
'BaseOrg': BaseOrg,
40+
'BaseUser': BaseUser,
41+
'ReviewObject': ReviewObject,
42+
'Conversation': Conversation,
43+
'Audit': Audit
44+
}
45+
46+
const indexTargets = {
47+
'Cve': [
48+
{ 'cve.cveMetadata.cveId': 1 },
49+
{ 'cve.cveMetadata.dateUpdated': 1 }
50+
],
51+
'Cve-Id': [
52+
{ 'cve_id': 1 },
53+
{ 'owning_cna': 1, 'state': 1 },
54+
{ 'reserved': 1 }
55+
],
56+
'User': [
57+
{ 'UUID': 1 }
58+
],
59+
'Org': [
60+
{ 'UUID': 1 },
61+
{ 'authority.active_roles': 1 }
62+
]
63+
}
64+
65+
// ===========================================================================
66+
// App Setup
67+
// ---------------------------------------------------------------------------
68+
69+
// Create the app, make sure it supports JSON and URL-encoded data.
70+
const app = express()
71+
app.use(express.json())
72+
app.use(express.urlencoded({ extended: false }))
73+
74+
// ===========================================================================
75+
// Database Setup
76+
// ---------------------------------------------------------------------------
77+
78+
// Connect to MongoDB database
79+
const dbConnectionStr = dbUtils.getMongoConnectionString()
80+
81+
const db = await mongoose.connect(dbConnectionStr, {
82+
useNewUrlParser: true,
83+
useUnifiedTopology: false,
84+
autoIndex: false
85+
})
86+
87+
console.log('Successfully connected to database!')
88+
89+
// ===========================================================================
90+
// Parse User Input
91+
// ---------------------------------------------------------------------------
92+
93+
let userInput
94+
if (process.argv.length > 2 && process.argv.slice(2)[0] === 'y') {
95+
userInput = process.argv.slice(2)[0]
96+
} else {
97+
// script runner (currently) needs to agree to an action that drops collections
98+
userInput = dataUtils.getUserPopulateInput(Object.keys(populateTargets))
99+
}
100+
101+
// ===========================================================================
102+
// Populate Database
103+
// ---------------------------------------------------------------------------
104+
105+
// Drop and re-populate collections.
106+
if (userInput.toLowerCase() === 'y') {
107+
const collections = await db.connection.db.listCollections().toArray()
108+
const names = collections.map(collection => collection.name)
109+
110+
for (const name in populateTargets) {
111+
if (names.includes(name) && db.connection.collections[name]) {
112+
console.log(`Dropping ${name} collection indexes!!!`)
113+
await db.connection.collections[name].dropIndexes()
114+
115+
console.log(`Dropping ${name} collection !!!`)
116+
await db.connection.dropCollection(name)
117+
}
118+
}
119+
120+
// Org
121+
await dataUtils.populateCollection(
122+
'./datadump/pre-population/orgs.json',
123+
Org, dataUtils.newOrgTransform
124+
)
125+
126+
// User, depends on Org
127+
const hash = await dataUtils.preprocessUserSecrets()
128+
await dataUtils.populateCollection(
129+
'./datadump/pre-population/users.json',
130+
User, dataUtils.newUserTransform, hash
131+
)
132+
133+
const populatePromises = []
134+
135+
// CVE ID Range
136+
populatePromises.push(dataUtils.populateCollection(
137+
'./datadump/pre-population/cve-ids-range.json',
138+
CveIdRange
139+
))
140+
141+
// CVE
142+
if (process.env.NODE_ENV === 'development' || process.env.NODE_ENV === 'test') {
143+
populatePromises.push(dataUtils.populateCollection(
144+
'./datadump/pre-population/cves.json',
145+
Cve, dataUtils.newCveTransform
146+
))
147+
}
148+
149+
// CVE ID, depends on User and Org
150+
populatePromises.push(dataUtils.populateCollection(
151+
'./datadump/pre-population/cve-ids.json',
152+
CveId, dataUtils.newCveIdTransform
153+
))
154+
155+
// Wait for all populate promises to resolve.
156+
await Promise.all(populatePromises)
157+
158+
console.log('Successfully populated the database data!')
159+
160+
// Create all the indices.
161+
for (const col of Object.keys(indexTargets)) {
162+
for (const index of indexTargets[col]) {
163+
await db.connection.collections[col].createIndex(index)
164+
}
165+
}
166+
167+
console.log('Successfully created all the indices!')
168+
}
169+
170+
await db.connection.close()

0 commit comments

Comments
 (0)