Skip to content

Commit

Permalink
Merge pull request #1182 from CVEProject/dev
Browse files Browse the repository at this point in the history
Updating Int from Dev
  • Loading branch information
david-rocca authored Feb 14, 2024
2 parents cf65762 + f91d651 commit cdc60d0
Show file tree
Hide file tree
Showing 8 changed files with 151 additions and 9 deletions.
2 changes: 1 addition & 1 deletion api-docs/openapi.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"openapi": "3.0.2",
"info": {
"version": "2.2.0",
"version": "2.2.1",
"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 <a href='https://www.cve.org/ProgramOrganization/CNAs'>CVE Numbering Authorities (CNAs)</a> should use one of the methods below to obtain credentials: <ul><li>If your organization already has an Organizational Administrator (OA) account for the CVE Services, ask your admin for credentials</li> <li>Contact your Root (<a href='https://www.cve.org/PartnerInformation/ListofPartners/partner/Google'>Google</a>, <a href='https://www.cve.org/PartnerInformation/ListofPartners/partner/INCIBE'>INCIBE</a>, <a href='https://www.cve.org/PartnerInformation/ListofPartners/partner/jpcert'>JPCERT/CC</a>, or <a href='https://www.cve.org/PartnerInformation/ListofPartners/partner/redhat'>Red Hat</a>) or Top-Level Root (<a href='https://www.cve.org/PartnerInformation/ListofPartners/partner/icscert'>CISA ICS</a> or <a href='https://www.cve.org/PartnerInformation/ListofPartners/partner/mitre'>MITRE</a>) to request credentials </ul> <p>CVE data is to be in the JSON 5.0 CVE Record format. Details of the JSON 5.0 schema are located <a href='https://github.com/CVEProject/cve-schema/tree/master/schema/v5.0' target='_blank'>here</a>.</p> <a href='https://cveform.mitre.org/' class='link' target='_blank'>Contact the CVE Services team</a>",
"contact": {
Expand Down
6 changes: 3 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "cve-services",
"author": "Automation Working Group",
"version": "2.2.0",
"version": "2.2.1",
"license": "(CC0)",
"devDependencies": {
"@faker-js/faker": "^7.6.0",
Expand Down Expand Up @@ -100,4 +100,4 @@
"test:coverage-html": "NODE_ENV=test nyc --reporter=html mocha src/* --recursive --exit || true",
"test:scripts": "NODE_ENV=development node-dev src/scripts/templateScript.js"
}
}
}
29 changes: 28 additions & 1 deletion src/controller/cve-id.controller/cve-id.controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,14 @@ async function getFilteredCveId (req, res, next) {
const users = await userRepo.getAllUsers()

const orgMap = {}
const userMap = {}

orgs.forEach(org => {
orgMap[org.UUID] = { shortname: org.short_name, users: {} }
})

users.forEach(user => {
userMap[user.UUID] = user.username
if (!orgMap[user.org_UUID]) {
orgMap[user.org_UUID] = { shortname: `MISSING ORG ${user.org_UUID}`, users: {} }
}
Expand Down Expand Up @@ -122,7 +125,31 @@ async function getFilteredCveId (req, res, next) {
cve_ids: pg.itemsList.map((i) => {
const cnaid = i.requested_by.cna
i.requested_by.cna = orgMap[cnaid].shortname
i.requested_by.user = orgMap[cnaid].users[i.requested_by.user]

// User value is redacted in certain cases
// Checks if requested_by.user is in requested_by.cna org
if (!orgMap[cnaid].users[i.requested_by.user]) {
// Never redact for secretariat users
if (isSecretariat) {
i.requested_by.user = userMap[i.requested_by.user]
} else {
// Redact because requested_by.user is not in requested_by.cna org
i.requested_by.user = 'REDACTED'
}
// Check is current owning_cna is also requested_by.cna (if a CVE-ID changes orgs)
} else if (cnaid !== i.owning_cna) {
// Never redact for secretariat
if (isSecretariat) {
i.requested_by.user = userMap[i.requested_by.user]
} else {
// Redact because current owner is not requested_by.cna and shouldn't see requested_by.user
i.requested_by.user = 'REDACTED'
}
} else {
// No redaction, original requested_by.user is in requested_by.cna and owning_cna
i.requested_by.user = orgMap[cnaid].users[i.requested_by.user]
}

i.owning_cna = orgMap[i.owning_cna].shortname
return i
})
Expand Down
2 changes: 1 addition & 1 deletion src/swagger.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ const rejectedCreateCVERecord = require('../schemas/cve/rejected-create-cve-exam
/* eslint-disable no-multi-str */
const doc = {
info: {
version: '2.2.0',
version: '2.2.1',
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 \
Expand Down
14 changes: 14 additions & 0 deletions test/integration-tests/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,18 @@ const nonSecretariatUserHeaders = {
'CVE-API-USER': 'jasminesmith@win_5.com'
}

const nonSecretariatUserHeaders2 = {
'CVE-API-ORG': 'win_5',
'CVE-API-Key': 'TCF25YM-39C4H6D-KA32EGF-V5XSHN3',
'CVE-API-USER': 'win_5_admin@win_5.com'
}

const nonSecretariatUserHeaders3 = {
'CVE-API-ORG': 'evidence_15',
'CVE-API-Key': 'TCF25YM-39C4H6D-KA32EGF-V5XSHN3',
'CVE-API-USER': 'timothymyers@evidence_15.com'
}

const nonSecretariatUserHeadersWithAdp2 = {
'CVE-API-ORG': 'range_4',
'CVE-API-Key': 'TCF25YM-39C4H6D-KA32EGF-V5XSHN3',
Expand Down Expand Up @@ -272,6 +284,8 @@ const existingOrg = {
module.exports = {
headers,
nonSecretariatUserHeaders,
nonSecretariatUserHeaders2,
nonSecretariatUserHeaders3,
badNonSecretariatUserHeaders,
nonSecretariatUserHeadersWithAdp2,
testCve,
Expand Down
79 changes: 79 additions & 0 deletions test/integration-tests/cve-id/getCveIdTest.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ const _ = require('lodash')
const expect = chai.expect

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

describe('Testing Get CVE-ID endpoint', () => {
Expand Down Expand Up @@ -109,6 +110,84 @@ describe('Testing Get CVE-ID endpoint', () => {
expect(res).to.have.status(200)
})
})
it('For non Secretariat users, should redact requested_by.user values not in requested_by.cna org', async () => {
const cveId = await helpers.cveIdReserveHelper(1, '2023', constants.nonSecretariatUserHeaders['CVE-API-ORG'], 'non-sequential')

// change users org for testing
await helpers.userOrgUpdateAsSecHelper(constants.nonSecretariatUserHeaders['CVE-API-USER'], constants.nonSecretariatUserHeaders['CVE-API-ORG'], 'mitre')

await chai.request(app)
.get('/api/cve-id?state=RESERVED')
.set(constants.nonSecretariatUserHeaders2)
.then(async (res, err) => {
const cveIdObject = _.find(res.body.cve_ids, obj => {
return obj.cve_id === cveId
})
expect(err).to.be.undefined
expect(res).to.have.status(200)
expect(cveIdObject.requested_by.user).to.equal('REDACTED')

// Reset user to original org
await helpers.userOrgUpdateAsSecHelper(constants.nonSecretariatUserHeaders['CVE-API-USER'], 'mitre', 'win_5')
})
})
it('For non Secretariat users, should redact requested_by.user values when requested_by.cna is not owning_cna', async () => {
const cveId = await helpers.cveIdReserveHelper(1, '2023', constants.nonSecretariatUserHeaders['CVE-API-ORG'], 'non-sequential')

// change cve-id's owning_org for testing
await helpers.updateOwningOrgAsSecHelper(cveId, constants.nonSecretariatUserHeaders3['CVE-API-ORG'])

await chai.request(app)
.get('/api/cve-id?state=RESERVED')
.set(constants.nonSecretariatUserHeaders3)
.then(async (res, err) => {
const cveIdObject = _.find(res.body.cve_ids, obj => {
return obj.cve_id === cveId
})
expect(err).to.be.undefined
expect(res).to.have.status(200)
expect(cveIdObject.requested_by.user).to.equal('REDACTED')
})
})
it('For Secretariat users, should redact requested_by.user values not in requested_by.cna org', async () => {
const cveId = await helpers.cveIdReserveHelper(1, '2023', constants.nonSecretariatUserHeaders['CVE-API-ORG'], 'non-sequential')

// change users org for testing
await helpers.userOrgUpdateAsSecHelper(constants.nonSecretariatUserHeaders['CVE-API-USER'], constants.nonSecretariatUserHeaders['CVE-API-ORG'], 'mitre')

await chai.request(app)
.get('/api/cve-id?state=RESERVED')
.set(constants.headers)
.then(async (res, err) => {
const cveIdObject = _.find(res.body.cve_ids, obj => {
return obj.cve_id === cveId
})
expect(err).to.be.undefined
expect(res).to.have.status(200)
expect(cveIdObject.requested_by.user).to.equal(constants.nonSecretariatUserHeaders['CVE-API-USER'])

// Reset user to original org
await helpers.userOrgUpdateAsSecHelper(constants.nonSecretariatUserHeaders['CVE-API-USER'], 'mitre', 'win_5')
})
})
it('For Secretariat users, should redact requested_by.user values when requested_by.cna is not owning_cna', async () => {
const cveId = await helpers.cveIdReserveHelper(1, '2023', constants.nonSecretariatUserHeaders['CVE-API-ORG'], 'non-sequential')

// change cve-id's owning_org for testing
await helpers.updateOwningOrgAsSecHelper(cveId, constants.nonSecretariatUserHeaders3['CVE-API-ORG'])

await chai.request(app)
.get('/api/cve-id?state=RESERVED')
.set(constants.headers)
.then(async (res, err) => {
const cveIdObject = _.find(res.body.cve_ids, obj => {
return obj.cve_id === cveId
})
expect(err).to.be.undefined
expect(res).to.have.status(200)
expect(cveIdObject.requested_by.user).to.equal(constants.nonSecretariatUserHeaders['CVE-API-USER'])
})
})
})
context('negative tests', () => {
it('Feb 29 2100 should not be valid', async () => {
Expand Down
24 changes: 23 additions & 1 deletion test/integration-tests/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,26 @@ async function cveUpdateAsCnaHelperWithAdpContainer (cveId, adpContainer) {
})
}

async function userOrgUpdateAsSecHelper (userName, orgShortName, newOrgShortName) {
await chai.request(app)
.put(`/api/org/${orgShortName}/user/${userName}?org_short_name=${newOrgShortName}`)
.set(constants.headers)
.then((res, err) => {
// Safety Expect
expect(res).to.have.status(200)
})
}

async function updateOwningOrgAsSecHelper (cveId, newOrgShortName) {
await chai.request(app)
.put(`/api/cve-id/${cveId}?org=${newOrgShortName}`)
.set(constants.headers)
.then((res, err) => {
// Safety Expect
expect(res).to.have.status(200)
})
}

module.exports = {
cveIdReserveHelper,
cveIdBulkReserveHelper,
Expand All @@ -104,5 +124,7 @@ module.exports = {
cveRequestAsSecHelper,
cveUpdatetAsCnaHelperWithCnaContainer,
cveUpdateAsSecHelper,
cveUpdateAsCnaHelperWithAdpContainer
cveUpdateAsCnaHelperWithAdpContainer,
userOrgUpdateAsSecHelper,
updateOwningOrgAsSecHelper
}

0 comments on commit cdc60d0

Please sign in to comment.