Skip to content
Merged
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
3 changes: 3 additions & 0 deletions schemas/registry-org/CNAOrg.json
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,9 @@
"minimum": 0,
"maximum": 100000
},
"is_last_resort": {
"type": "boolean"
},
"oversees": {
"type": "array",
"uniqueItems": true,
Expand Down
9 changes: 9 additions & 0 deletions schemas/registry-org/RootOrg.json
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,15 @@
},
"top_level_root": {
"$ref": "/BaseOrg#/properties/top_level_root"
},
"is_top_level_root": {
"type": "boolean"
},
"charter_or_scope": {
"type": "string"
},
"disclosure_policy": {
"type": "string"
}
},
"required": [
Expand Down
8 changes: 8 additions & 0 deletions schemas/registry-org/create-registry-org-request.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,14 @@
"type": "string",
"description": "Indicates if the organization is a root or top-level root"
},
"is_top_level_root": {
"type": "boolean",
"description": "Indicates whether a ROOT organization is top-level"
},
"is_last_resort": {
"type": "boolean",
"description": "Indicates whether a CNA organization is a CNA of last resort."
},
"users": {
"type": "array",
"items": {
Expand Down
8 changes: 8 additions & 0 deletions schemas/registry-org/create-registry-org-response.json
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,14 @@
"type": "string",
"description": "Indicates if the organization is a root or top-level root"
},
"is_top_level_root": {
"type": "boolean",
"description": "Indicates whether a ROOT organization is top-level"
},
"is_last_resort": {
"type": "boolean",
"description": "Indicates whether a CNA organization is a CNA of last resort"
},
"users": {
"type": "array",
"items": {
Expand Down
8 changes: 8 additions & 0 deletions schemas/registry-org/get-registry-org-response.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,14 @@
"type": "string",
"description": "Indicates if the organization is a root or top-level root"
},
"is_top_level_root": {
"type": "boolean",
"description": "Indicates whether a ROOT organization is top-level"
},
"is_last_resort": {
"type": "boolean",
"description": "Indicates whether a CNA organization is a CNA of last resort"
},
"reports_to": {
"type": [
"string",
Expand Down
8 changes: 8 additions & 0 deletions schemas/registry-org/list-registry-orgs-response.json
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,14 @@
"type": "string",
"description": "Indicates if the organization is a root or top-level root"
},
"is_top_level_root": {
"type": "boolean",
"description": "Indicates whether a ROOT organization is top-level"
},
"is_last_resort": {
"type": "boolean",
"description": "Indicates whether a CNA organization is a CNA of last resort"
},
"reports_to": {
"type": [
"string",
Expand Down
8 changes: 8 additions & 0 deletions schemas/registry-org/update-registry-org-request.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,14 @@
"type": "string",
"description": "Indicates if the organization is a root or top-level root"
},
"is_top_level_root": {
"type": "boolean",
"description": "Indicates whether a ROOT organization is top-level"
},
"is_last_resort": {
"type": "boolean",
"description": "Indicates whether a CNA organization is a CNA of last resort"
},
"users": {
"type": "array",
"items": {
Expand Down
8 changes: 8 additions & 0 deletions schemas/registry-org/update-registry-org-response.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,14 @@
"type": "string",
"description": "Indicates if the organization is a root or top-level root"
},
"is_top_level_root": {
"type": "boolean",
"description": "Indicates whether a ROOT organization is top-level"
},
"is_last_resort": {
"type": "boolean",
"description": "Indicates whether a CNA organization is a CNA of last resort"
},
"users": {
"type": "array",
"items": {
Expand Down
2 changes: 2 additions & 0 deletions src/constants/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ function getConstants () {
'program_data.cve_website_update_needed',
'program_data.status',
'top_level_root',
'is_top_level_root',
'is_last_resort',
'oversees'
],
USER_ROLE_ENUM: {
Expand Down
1 change: 1 addition & 0 deletions src/model/cnaorg.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ const validate = ajv.compile(CnaOrgSchema)
const schema = {
oversees: [String],
id_quota: Number,
is_last_resort: Boolean,
charter_or_scope: String,
disclosure_policy: String,
product_list: String
Expand Down
5 changes: 4 additions & 1 deletion src/model/rootorg.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@ ajv.addSchema(BaseOrgSchema)
const validate = ajv.compile(RootOrgSchema)

const schema = {
oversees: [String]
oversees: [String],
is_top_level_root: Boolean,
charter_or_scope: String,
disclosure_policy: String
}

const options = { discriminatorKey: 'kind' }
Expand Down
19 changes: 17 additions & 2 deletions test/integration-tests/registry-org/registryOrgCRUDTest.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ const testRegistryOrg = {
partner_number: 'Initial Partner Number',
partner_country: 'US',
advisory_locations: ['https://example.com/advisories'],
charter_or_scope: 'This is a normal string, not a URI'
charter_or_scope: 'This is a normal string, not a URI',
is_last_resort: true
}
let createdOrg

Expand Down Expand Up @@ -82,6 +83,9 @@ describe('Testing /registry/org endpoints', () => {
expect(res.body.created).to.haveOwnProperty('charter_or_scope')
expect(res.body.created.charter_or_scope).to.equal(testRegistryOrg.charter_or_scope)

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

expect(res.body.created).to.haveOwnProperty('program_data')
expect(res.body.created.program_data.status).to.equal('inactive')
expect(res.body.created.program_data).to.haveOwnProperty('partner_inactive_date')
Expand Down Expand Up @@ -671,7 +675,8 @@ describe('Testing /registry/org endpoints', () => {
partner_role_type: ['Researcher', 'Vendor'],
partner_number: 'Updated Partner Number',
partner_country: 'UK',
advisory_locations: ['https://example.com/updated_advisories']
advisory_locations: ['https://example.com/updated_advisories'],
is_last_resort: false
})
.then((res, err) => {
expect(err).to.be.undefined
Expand Down Expand Up @@ -708,6 +713,16 @@ describe('Testing /registry/org endpoints', () => {

expect(res.body.updated).to.haveOwnProperty('advisory_locations')
expect(res.body.updated.advisory_locations).to.deep.equal(['https://example.com/updated_advisories'])
expect(res.body.updated.is_last_resort).to.equal(false)
})
})
it('Retrieves the CNA last-resort flag', async () => {
await chai.request(app)
.get('/api/registry/org/registry_org_test')
.set(secretariatHeaders)
.then((res) => {
expect(res).to.have.status(200)
expect(res.body.is_last_resort).to.equal(false)
})
})
it('Allows Secretariat to update program_data', async () => {
Expand Down
58 changes: 55 additions & 3 deletions test/integration-tests/registry-org/rootOrgTest.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@ let rootAdminHeaders
const testRootOrg = {
short_name: 'root_org_test_4',
long_name: 'Root Org Test',
authority: ['ROOT']
authority: ['ROOT'],
is_top_level_root: true,
charter_or_scope: 'Coordinates CVE Numbering Authorities.',
disclosure_policy: 'Discloses vulnerabilities after coordinated remediation.'
}
let createdOrg
let reportingOrg
Expand All @@ -31,6 +34,9 @@ describe('Testing ROOT Organization Type', () => {
expect(res).to.have.status(200)
expect(res.body.message).to.equal(testRootOrg.short_name + ' organization was successfully created.')
expect(res.body.created.authority).to.deep.equal(['ROOT'])
expect(res.body.created.is_top_level_root).to.equal(true)
expect(res.body.created.charter_or_scope).to.equal(testRootOrg.charter_or_scope)
expect(res.body.created.disclosure_policy).to.equal(testRootOrg.disclosure_policy)
createdOrg = res.body.created
delete createdOrg.created
delete createdOrg.last_updated
Expand All @@ -55,6 +61,34 @@ describe('Testing ROOT Organization Type', () => {
expect(res.body.message).to.equal('Parameters were invalid')
})
})

it('Secretariat can update and retrieve ROOT-specific fields', async () => {
await chai.request(app)
.put(`/api/registry/org/${testRootOrg.short_name}`)
.set(secretariatHeaders)
.send({
...createdOrg,
is_top_level_root: false,
charter_or_scope: 'Updated ROOT charter.',
disclosure_policy: 'Updated ROOT disclosure policy.'
})
.then((res) => {
expect(res).to.have.status(200)
expect(res.body.updated.is_top_level_root).to.equal(false)
expect(res.body.updated.charter_or_scope).to.equal('Updated ROOT charter.')
expect(res.body.updated.disclosure_policy).to.equal('Updated ROOT disclosure policy.')
})

await chai.request(app)
.get(`/api/registry/org/${testRootOrg.short_name}`)
.set(secretariatHeaders)
.then((res) => {
expect(res).to.have.status(200)
expect(res.body.is_top_level_root).to.equal(false)
expect(res.body.charter_or_scope).to.equal('Updated ROOT charter.')
expect(res.body.disclosure_policy).to.equal('Updated ROOT disclosure policy.')
})
})
})

context('Managing reports-to relationships', () => {
Expand Down Expand Up @@ -211,11 +245,13 @@ describe('Testing ROOT Organization Type', () => {
})

it('ROOT admin can update their own org', async () => {
const rootAdminPayload = { ...createdOrg }
delete rootAdminPayload.is_top_level_root
await chai.request(app)
.put(`/api/registry/org/${testRootOrg.short_name}`)
.set(rootAdminHeaders)
.send({
...createdOrg,
...rootAdminPayload,
long_name: 'Updated Root Org Test'
})
.then((res) => {
Expand All @@ -238,12 +274,28 @@ describe('Testing ROOT Organization Type', () => {
})
})

it('ROOT admin cannot set oversees through the standard PUT endpoint', async () => {
it('ROOT admin cannot edit is_top_level_root', async () => {
await chai.request(app)
.put(`/api/registry/org/${testRootOrg.short_name}`)
.set(rootAdminHeaders)
.send({
...createdOrg,
is_top_level_root: true
})
.then((res) => {
expect(res).to.have.status(403)
expect(res.body.error).to.equal('SECRETARIAT_ONLY')
})
})

it('ROOT admin cannot set oversees through the standard PUT endpoint', async () => {
const rootAdminPayload = { ...createdOrg }
delete rootAdminPayload.is_top_level_root
await chai.request(app)
.put(`/api/registry/org/${testRootOrg.short_name}`)
.set(rootAdminHeaders)
.send({
...rootAdminPayload,
oversees: [reportingOrg.UUID]
})
.then((res) => {
Expand Down
Loading