text:
# Tests in this file use an Org admin user provided by a Pytest fixture. The
# tests here should be a subset of the secretariat tests, since the CNA of last
# resort should always be able to perform any root CNA functionality in
# addition to functionality reserved for the CNA of last resort.
import json
import requests
import uuid
from src import env, utils
from src.test.org_user_tests.org import (ORG_URL, create_new_user_with_new_org_by_uuid,
                                         create_new_user_with_new_org_by_shortname,
                                         post_new_org_user, post_new_org)
from src.utils import response_contains, response_contains_json

MAX_SHORTNAME_LENGTH = 32

### GET /org ####

def test_org_admin_get_all_orgs(org_admin_headers):
    """ services api rejects requests for all orgs by non-secretariat users """
    res = requests.get(
        f'{env.AWG_BASE_URL}{ORG_URL}',
        headers=org_admin_headers
    )
    assert res.status_code == 403
    response_contains_json(res, 'error', 'SECRETARIAT_ONLY')

#### GET /org/:identifier ####
def test_org_admin_get_mitre_org(org_admin_headers):
    """ services api rejects requests for secretariat by non-secretariat users """
    res = requests.get(
        f'{env.AWG_BASE_URL}{ORG_URL}/mitre',  # the secretariat's org
        headers=org_admin_headers
    )
    assert res.status_code == 403
    response_contains_json(res, 'error', 'NOT_SAME_ORG_OR_SECRETARIAT')

def test_org_admin_get_another_org(org_admin_headers):
    """ services api rejects requests for any org by another org user """
    different_org = str(uuid.uuid4())[:MAX_SHORTNAME_LENGTH]  # name of an org
    res = post_new_org(different_org, different_org)  # create an org
    assert res.status_code == 200
    res = requests.get(
        f'{env.AWG_BASE_URL}{ORG_URL}/{different_org}',
        headers=org_admin_headers
    )
    assert res.status_code == 403
    response_contains_json(res, 'error', 'NOT_SAME_ORG_OR_SECRETARIAT')

def test_org_admin_get_own_org(org_admin_headers):
    """ services api allows org admins to get their own org's document """
    org = org_admin_headers["CVE-API-ORG"][:MAX_SHORTNAME_LENGTH]
    res = requests.get(
        f'{env.AWG_BASE_URL}{ORG_URL}/{org}',
        headers=org_admin_headers
    )
    assert res.status_code == 200
    response_contains(res, org)

#### GET /org/:shortname/id_quota ####
def test_org_admin_get_secretariat_id_quota_info(org_admin_headers):
    """ services api rejects requests for secretariat by non-secretariat users """
    res = requests.get(
        f'{env.AWG_BASE_URL}{ORG_URL}/mitre/id_quota',  # the secretariat's org
        headers=org_admin_headers
    )
    assert res.status_code == 403
    response_contains_json(res, 'error', 'NOT_SAME_ORG_OR_SECRETARIAT')

def test_org_admin_get_another_org_id_quota_info(org_admin_headers):
    """ services api rejects requests for any org by another org user """
    different_org = str(uuid.uuid4())[:MAX_SHORTNAME_LENGTH]  # name of an org
    res = post_new_org(different_org, different_org)  # create an org
    assert res.status_code == 200
    res = requests.get(
        f'{env.AWG_BASE_URL}{ORG_URL}/{different_org}/id_quota',
        headers=org_admin_headers
    )
    assert res.status_code == 403
    response_contains_json(res, 'error', 'NOT_SAME_ORG_OR_SECRETARIAT')

def test_org_admin_get_own_id_quota_info(org_admin_headers):
    """ services api allows org admins to get info about their org's quota """
    org = org_admin_headers["CVE-API-ORG"][:MAX_SHORTNAME_LENGTH]
    res = requests.get(
        f'{env.AWG_BASE_URL}{ORG_URL}/{org}/id_quota',
        headers=org_admin_headers
    )
    assert res.status_code == 200
    id_quota = json.loads(res.content.decode())['id_quota']
    assert id_quota >= 0
    assert id_quota <= 100000

#### GET /org/:shortname/user/:username ####
def test_org_admin_get_mitre_user_info(org_admin_headers):
    """ services api prevents org users from viewing secretariat user info """
    res = requests.get(
        f'{env.AWG_BASE_URL}{ORG_URL}/mitre/user/{env.AWG_USER_NAME}',
        headers=org_admin_headers
    )
    assert res.status_code == 403
    response_contains_json(res, 'error', 'NOT_SAME_ORG_OR_SECRETARIAT')

def test_org_admin_get_another_org_user_info(org_admin_headers):
    """ services api prevents org admin users from viewing another org user's info """
    org, user = create_new_user_with_new_org_by_uuid()
    res = requests.get(
        f'{env.AWG_BASE_URL}{ORG_URL}/{org}/user/{user}',
        headers=org_admin_headers
    )
    assert res.status_code == 403
    response_contains_json(res, 'error', 'NOT_SAME_ORG_OR_SECRETARIAT')

def test_org_admin_get_own_user_info(org_admin_headers):
    """ services api allows org admin to get its own user info """
    org = org_admin_headers["CVE-API-ORG"][:MAX_SHORTNAME_LENGTH]
    user = org_admin_headers['CVE-API-USER']
    res = requests.get(
        f'{env.AWG_BASE_URL}{ORG_URL}/{org}/user/{user}',
        headers=org_admin_headers
    )
    assert res.status_code == 200
    response_contains(res, user)

#### GET /org/:shortname/users ####
def test_org_admin_get_mitre_users_info(org_admin_headers):
    """ services api prevents org users from viewing secretariat users info """
    res = requests.get(
        f'{env.AWG_BASE_URL}{ORG_URL}/mitre/users',
        headers=org_admin_headers
    )
    assert res.status_code == 403
    response_contains_json(res, 'error', 'NOT_SAME_ORG_OR_SECRETARIAT')

def test_org_admin_get_another_org_users_info(org_admin_headers):
    """ services api prevents org admin users from viewing all other org's user info """
    org = str(uuid.uuid4())[:MAX_SHORTNAME_LENGTH]
    res = post_new_org(org, org)
    assert res.status_code == 200
    res = requests.get(
        f'{env.AWG_BASE_URL}{ORG_URL}/{org}/users',
        headers=org_admin_headers
    )
    assert res.status_code == 403
    response_contains_json(res, 'error', 'NOT_SAME_ORG_OR_SECRETARIAT')

def test_org_admin_get_own_users_info(org_admin_headers):
    """ services api allows org admin to get its own users info """
    org = org_admin_headers["CVE-API-ORG"][:MAX_SHORTNAME_LENGTH]
    user = org_admin_headers['CVE-API-USER']
    res = requests.get(
        f'{env.AWG_BASE_URL}{ORG_URL}/{org}/users',
        headers=org_admin_headers
    )
    assert res.status_code == 200
    assert len(json.loads(res.content.decode())['users']) >= 1
    response_contains(res, user)

def test_org_get_user_page(org_admin_headers):
    """ page must be a positive int """
    org = org_admin_headers["CVE-API-ORG"][:MAX_SHORTNAME_LENGTH]
    res = requests.get(
        f'{env.AWG_BASE_URL}{ORG_URL}/{org}/users',
        headers=org_admin_headers,
        params={
            'page': '1',
        }
    )
    assert res.status_code == 200

def test_org_get_bad_user_page(org_admin_headers):
    """ page must be a positive int """

    # test negative
    org = org_admin_headers["CVE-API-ORG"][:MAX_SHORTNAME_LENGTH]
    res = requests.get(
        f'{env.AWG_BASE_URL}{ORG_URL}/{org}/users',
        headers=org_admin_headers,
        params={
            'page': -1,
        }
    )
    assert res.status_code == 400
    response_contains_json(res, 'error', 'BAD_INPUT')
    response_contains_json(res, 'details', utils.BAD_PAGE_ERROR_DETAILS)

    # test strings
    res = requests.get(
        f'{env.AWG_BASE_URL}{ORG_URL}/{org}/users',
        headers=org_admin_headers,
        params={
            'page': 'abc',
        }
    )
    assert res.status_code == 400
    response_contains_json(res, 'error', 'BAD_INPUT')
    response_contains_json(res, 'details', utils.BAD_PAGE_ERROR_DETAILS)

#### POST /org ####

def test_org_admin_cannot_create_another_org(org_admin_headers):
    """ services api does not allow org admins to create other orgs """
    res = requests.post(
        f'{env.AWG_BASE_URL}{ORG_URL}',
        headers=org_admin_headers,
        params={'short_name': str(uuid.uuid4())[:MAX_SHORTNAME_LENGTH]}
    )
    assert res.status_code == 403
    response_contains_json(res, 'error', 'SECRETARIAT_ONLY')

def test_org_admin_cannot_update_org(org_admin_headers):
    """ services api does not allow org admins to update their own orgs """
    res = requests.post(
        f'{env.AWG_BASE_URL}{ORG_URL}',
        headers=org_admin_headers,
        params={'name': str(uuid.uuid4())}
    )
    assert res.status_code == 403
    response_contains_json(res, 'error', 'SECRETARIAT_ONLY')

#### POST /org/:shortname/user ####
def test_org_admin_cannot_create_user_for_another_org(org_admin_headers):
    """ services api prevents org admins from creating a user with conflicts in the organization the user belongs to (org in path is diff from org in json body)  """
    org = str(uuid.uuid4())[:MAX_SHORTNAME_LENGTH]
    res = post_new_org(org, org)
    assert res.status_code == 200
    res = requests.post(
        f'{env.AWG_BASE_URL}{ORG_URL}/{org}/user',
        headers=org_admin_headers,
        json={'username': 'BLARG', 'org_UUID': 'test'}
    )
    assert res.status_code == 400
    response_contains_json(res, 'error', 'SHORTNAME_MISMATCH')

def test_org_admin_cannot_create_user_for_another_org(org_admin_headers):
    """ services api prevents org admins from creating users for other orgs """
    org = str(uuid.uuid4())[:MAX_SHORTNAME_LENGTH]
    res = post_new_org(org, org)
    assert res.status_code == 200
    res = requests.post(
        f'{env.AWG_BASE_URL}{ORG_URL}/{org}/user',
        headers=org_admin_headers,
        json={'username': 'BLARG'}
    )
    assert res.status_code == 403
    response_contains_json(res, 'error', 'NOT_ORG_ADMIN_OR_SECRETARIAT')

def test_org_admin_cannot_create_existen_user(org_admin_headers):
    """ services api prevents org admins from creating existing users """
    user = str(uuid.uuid4())
    org = org_admin_headers["CVE-API-ORG"][:MAX_SHORTNAME_LENGTH]
    res = post_new_org_user(org, user)
    assert res.status_code == 200
    res = requests.post(
        f'{env.AWG_BASE_URL}{ORG_URL}/{org}/user',
        headers=org_admin_headers,
        json={'username': user}
    )
    assert res.status_code == 400
    response_contains_json(res, 'error', 'USER_EXISTS')

#### PUT /org/:shortname/user/:username ####
def test_org_admin_cannot_update_user_org_dne(org_admin_headers):
    """ services api prevents org admins from updating a user from an org that doesn't exist """
    user = org_admin_headers['CVE-API-USER']
    org = str(uuid.uuid4())[:MAX_SHORTNAME_LENGTH]
    res = requests.put(
        f'{env.AWG_BASE_URL}{ORG_URL}/{org}/user/{user}',
        headers=org_admin_headers
    )
    assert res.status_code == 404
    response_contains_json(res, 'error', 'ORG_DNE_PARAM')

def test_org_admin_cannot_update_user_dne(org_admin_headers):
    """ services api prevents org admins from updating a user that doesn't exist """
    user = str(uuid.uuid4())
    org = org_admin_headers["CVE-API-ORG"][:MAX_SHORTNAME_LENGTH]
    res = requests.put(
        f'{env.AWG_BASE_URL}{ORG_URL}/{org}/user/{user}',
        headers=org_admin_headers
    )
    assert res.status_code == 404
    response_contains_json(res, 'error', 'USER_DNE')

def test_org_admin_cannot_update_user_for_another_org(org_admin_headers):
    """ services api prevents org admins from updating a user from a diff org """
    org, user = create_new_user_with_new_org_by_uuid()
    res = requests.put(
        f'{env.AWG_BASE_URL}{ORG_URL}/{org}/user/{user}',
        headers=org_admin_headers
    )
    assert res.status_code == 403
    response_contains_json(res, 'error', 'NOT_SAME_ORG_OR_SECRETARIAT')

# Admins can't change user's org
# def test_org_admin_cannot_update_user_new_shortname_dne(org_admin_headers):
#     """ services api prevents org admins from updating a user's org that doesn't exist """
#     org = org_admin_headers['CVE-API-ORG']
#     user = org_admin_headers['CVE-API-USER']
#     org_short_name = str(uuid.uuid4())
#     res = requests.put(
#         f'{env.AWG_BASE_URL}{ORG_URL}/{org}/user/{user}?org_short_name={org_short_name}',
#         headers=org_admin_headers
#     )
#     assert res.status_code == 404
#     response_contains_json(res, 'error', 'ORG_DNE')

# Admins can't change user's org
# def test_org_admin_cannot_update_duplicate_user_with_new_shortname_and_username(org_admin_headers):
#     """ services api prevents org admins from updating a user's org and username if that user already exist """
#     org1 = org_admin_headers['CVE-API-ORG']
#     user1 = org_admin_headers['CVE-API-USER']
#     org2, user2 = create_new_user_with_new_org_by_uuid()
#     res = requests.put(
#         f'{env.AWG_BASE_URL}{ORG_URL}/{org1}/user/{user1}?org_short_name={org2}&new_username={user2}',
#         headers=org_admin_headers
#     )
#     assert res.status_code == 403
#     response_contains_json(res, 'error', 'DUPLICATE_USERNAME')

def test_org_admin_cannot_update_duplicate_user_with_new_username(org_admin_headers):
    """ services api prevents org admins from updating a user's username if that user already exist """
    org = org_admin_headers["CVE-API-ORG"][:MAX_SHORTNAME_LENGTH]
    user1 = org_admin_headers['CVE-API-USER']
    user2 = str(uuid.uuid4())
    # creating a user with same org as admin org user
    res = post_new_org_user(org, user2)
    assert res.status_code == 200
    res = requests.put(
        f'{env.AWG_BASE_URL}{ORG_URL}/{org}/user/{user1}?new_username={user2}',
        headers=org_admin_headers
    )
    assert res.status_code == 403
    response_contains_json(res, 'error', 'DUPLICATE_USERNAME')

# Admin users aren't able to update a users org
# def test_org_admin_cannot_update_duplicate_user_with_new_shortname(org_admin_headers):
#     """ services api prevents org admins from updating a user's org if that user already exist """
#     user = org_admin_headers['CVE-API-USER']
#     org1 = org_admin_headers['CVE-API-ORG']
#     org2 = str(uuid.uuid4())
#     res = create_new_user_with_new_org_by_shortname(org2, user) # creating a user with same username as org admin user's username
#     res = requests.put(
#         f'{env.AWG_BASE_URL}{ORG_URL}/{org1}/user/{user}?org_short_name={org2}',
#         headers=org_admin_headers
#     )
#     assert res.status_code == 403
#     response_contains_json(res, 'error', 'NOT_ALLOWED_TO_CHANGE_ORGANIZATION')

def test_org_admin_update_same_org_user_state_sn_un(org_admin_headers):
    """  allows admin users to update a user's active state and user username """
    org = org_admin_headers["CVE-API-ORG"][:MAX_SHORTNAME_LENGTH]
    user = str(uuid.uuid4())
    # creating a user with same org as admin org user
    res = post_new_org_user(org, user)
    assert res.status_code == 200
    new_shortname = str(uuid.uuid4())[:MAX_SHORTNAME_LENGTH]   # used in query
    new_username = str(uuid.uuid4())    # used in query
    res = post_new_org(new_shortname, new_shortname)  # create new org
    assert res.status_code == 200
    res = requests.put(
        f'{env.AWG_BASE_URL}{ORG_URL}/{org}/user/{user}?new_username={new_username}&active=false',
        headers=org_admin_headers
    )
    assert res.status_code == 200
    assert json.loads(res.content.decode())['updated']['active'] == False
    assert json.loads(res.content.decode())[
        'updated']['username'] == new_username
    assert json.loads(res.content.decode())['updated']['username'] is not None

def test_org_admin_update_same_org_user_roles_name(org_admin_headers):
    """  allows admin users to update a user's name, add role, and remove role """
    org = org_admin_headers["CVE-API-ORG"][:MAX_SHORTNAME_LENGTH]
    user = str(uuid.uuid4())
    # creating a user with same org as admin org user
    res = post_new_org_user(org, user)
    assert res.status_code == 200
    res = requests.put(
        # adding role
        f'{env.AWG_BASE_URL}{ORG_URL}/{org}/user/{user}?active_roles.add=admin',
        headers=org_admin_headers
    )
    assert res.status_code == 200
    assert json.loads(res.content.decode())[
        'updated']['authority']['active_roles'] == ["ADMIN"]
    res = requests.put(
        # removing role
        f'{env.AWG_BASE_URL}{ORG_URL}/{org}/user/{user}?active_roles.remove=admin',
        headers=org_admin_headers
    )
    assert res.status_code == 200
    assert json.loads(res.content.decode())[
        'updated']['authority']['active_roles'] == []
    res = requests.put(
        # updating name
        f'{env.AWG_BASE_URL}{ORG_URL}/{org}/user/{user}?name.first=t&name.last=e&name.middle=s&name.suffix=t',
        headers=org_admin_headers
    )
    assert res.status_code == 200
    assert json.loads(res.content.decode())['updated']['name']['first'] == 't'
    assert json.loads(res.content.decode())['updated']['name']['last'] == 'e'
    assert json.loads(res.content.decode())['updated']['name']['middle'] == 's'
    assert json.loads(res.content.decode())['updated']['name']['suffix'] == 't'

# Admin users can't change org?
# def test_org_admin_update_own_user_state_sn_un(org_admin_headers):
#     """  allows admin users to update its own active state, org shortname, and user username """
#     org = org_admin_headers['CVE-API-ORG']
#     user = org_admin_headers['CVE-API-USER']
#     new_shortname = str(uuid.uuid4())   # used in query
#     new_username = str(uuid.uuid4())    # used in query
#     res = post_new_org(new_shortname, new_shortname)  # create new org
#     assert res.status_code == 200
#     res = requests.put(
#         f'{env.AWG_BASE_URL}{ORG_URL}/{org}/user/{user}?org_short_name={new_shortname}&new_username={new_username}&active=false',
#         headers=org_admin_headers
#     )
#     assert res.status_code == 200
#     assert json.loads(res.content.decode())['updated']['active'] == False
#     assert json.loads(res.content.decode())['updated']['username'] == new_username
#     assert json.loads(res.content.decode())['updated']['username'] is not None

def test_org_admin_update_own_user_roles_name(org_admin_headers):
    """  allows admin users to update its own name and remove role """
    org = org_admin_headers["CVE-API-ORG"][:MAX_SHORTNAME_LENGTH]
    user = org_admin_headers['CVE-API-USER']
    res = requests.put(
        # removing role
        f'{env.AWG_BASE_URL}{ORG_URL}/{org}/user/{user}?active_roles.remove=admin',
        headers=org_admin_headers
    )
    assert res.status_code == 403
    response_contains_json(res, 'error', 'NOT_ALLOWED_TO_SELF_DEMOTE')

    res = requests.put(
        # updating name
        f'{env.AWG_BASE_URL}{ORG_URL}/{org}/user/{user}?name.first=t&name.last=e&name.middle=s&name.suffix=t',
        headers=org_admin_headers
    )
    assert res.status_code == 200
    assert json.loads(res.content.decode())['updated']['name']['first'] == 't'
    assert json.loads(res.content.decode())['updated']['name']['last'] == 'e'
    assert json.loads(res.content.decode())['updated']['name']['middle'] == 's'
    assert json.loads(res.content.decode())['updated']['name']['suffix'] == 't'

#### PUT /org/:shortname/user/:username/reset_secret ####
def test_org_admin_reset_secret_org_dne(org_admin_headers):
    org = str(uuid.uuid4())[:MAX_SHORTNAME_LENGTH]
    user = str(uuid.uuid4())
    res = requests.put(
        f'{env.AWG_BASE_URL}{ORG_URL}/{org}/user/{user}/reset_secret',
        headers=org_admin_headers
    )
    assert res.status_code == 404
    response_contains_json(res, 'error', 'ORG_DNE_PARAM')

def test_org_admin_reset_secret_org_dne(org_admin_headers):
    org = org_admin_headers["CVE-API-ORG"][:MAX_SHORTNAME_LENGTH]
    user = str(uuid.uuid4())
    res = requests.put(
        f'{env.AWG_BASE_URL}{ORG_URL}/{org}/user/{user}/reset_secret',
        headers=org_admin_headers
    )
    assert res.status_code == 404
    response_contains_json(res, 'error', 'USER_DNE')

def test_org_admin_reset_diff_org_secret(org_admin_headers):
    """ services api prevents admin users to reset the secret of users of different org"""
    org, user = create_new_user_with_new_org_by_uuid()
    res = requests.put(
        f'{env.AWG_BASE_URL}{ORG_URL}/{org}/user/{user}/reset_secret',
        headers=org_admin_headers
    )
    assert res.status_code == 403
    response_contains_json(res, 'error', 'NOT_SAME_ORG_OR_SECRETARIAT')

def test_org_admin_reset_same_org_secret(org_admin_headers):
    """ services api allows admin users to reset the secret of users of same org"""
    org = org_admin_headers["CVE-API-ORG"][:MAX_SHORTNAME_LENGTH]
    user = str(uuid.uuid4())
    res = post_new_org_user(org, user)
    assert res.status_code == 200
    res = requests.put(
        f'{env.AWG_BASE_URL}{ORG_URL}/{org}/user/{user}/reset_secret',
        headers=org_admin_headers
    )
    assert res.status_code == 200
    response_contains(res, 'API-secret')

def test_org_admin_reset_own_secret(org_admin_headers):
    """ services api allows admin users to reset their own secret """
    org = org_admin_headers["CVE-API-ORG"][:MAX_SHORTNAME_LENGTH]
    user = org_admin_headers['CVE-API-USER']
    res = requests.put(
        f'{env.AWG_BASE_URL}{ORG_URL}/{org}/user/{user}/reset_secret',
        headers=org_admin_headers
    )
    assert res.status_code == 200
    response_contains(res, 'API-secret')

def test_admin_role_preserved_after_resetting_own_secret(org_admin_headers):
    """ admin user's role remains after resetting own secret """
    org = org_admin_headers["CVE-API-ORG"][:MAX_SHORTNAME_LENGTH]
    user = org_admin_headers['CVE-API-USER']
    res = requests.put(
        f'{env.AWG_BASE_URL}{ORG_URL}/{org}/user/{user}/reset_secret',
        headers=org_admin_headers
    )
    secret = json.loads(res.content.decode())["API-secret"]
    assert res.status_code == 200

    headers2 = org_admin_headers
    headers2['CVE-API-KEY'] = secret
    response_contains(res, 'API-secret')
    res2 = requests.get(
        f'{env.AWG_BASE_URL}{ORG_URL}/{org}/user/{user}',
        headers=headers2
    )
    assert res2.status_code == 200
    # admin role still remains after changing secret
    assert json.loads(res2.content.decode())[
        "authority"]["active_roles"][0] == "ADMIN"


text:
# Tests in this file use an Org admin user provided by a Pytest fixture. The
# tests here should be a subset of the secretariat tests, since the CNA of last
# resort should always be able to perform any root CNA functionality in
# addition to functionality reserved for the CNA of last resort.
import json
import requests
import uuid
from src import env, utils
from src.test.org_user_tests.org import (ORG_URL, create_new_user_with_new_org_by_uuid,
                                         create_new_user_with_new_org_by_shortname,
                                         post_new_org_user, post_new_org)
from src.utils import (assert_contains, ok_response_contains,
                       ok_response_contains_json, response_contains,
                       response_contains_json)

MAX_SHORTNAME_LENGTH = 32
#### PUT /org/:shortname/user/:username ####

def test_regular_user_update_name_and_username(reg_user_headers):
    """  regular users can update their name & username """
    org = reg_user_headers['CVE-API-ORG']
    user = reg_user_headers['CVE-API-USER']
    new_username = str(uuid.uuid4())  # used in query
    res = requests.put(
        f'{env.AWG_BASE_URL}{ORG_URL}/{org}/user/{user}?name.first=aaa&name.last=bbb&name.middle=ccc&name.suffix=ddd',
        headers=reg_user_headers
    )
    assert res.status_code == 200
    assert json.loads(res.content.decode())[
        'updated']['name']['first'] == 'aaa'
    assert json.loads(res.content.decode())['updated']['name']['last'] == 'bbb'
    assert json.loads(res.content.decode())[
        'updated']['name']['middle'] == 'ccc'
    assert json.loads(res.content.decode())[
        'updated']['name']['suffix'] == 'ddd'
    res = requests.put(
        f'{env.AWG_BASE_URL}{ORG_URL}/{org}/user/{user}?new_username={new_username}',
        headers=reg_user_headers
    )
    assert res.status_code == 403
    response_contains_json(res, 'error', 'NOT_ORG_ADMIN_OR_SECRETARIAT_UPDATE')

def test_regular_user_cannot_update_for_another_user(reg_user_headers):
    """ regular users cannot update information of another user of the same organization """
    org = reg_user_headers['CVE-API-ORG']
    user = reg_user_headers['CVE-API-USER']
    user2 = str(uuid.uuid4())
    # creating a user with same org as regular user
    res = post_new_org_user(org, user2)
    assert res.status_code == 200
    user_name = str(uuid.uuid4())  # create a new name to give to second user
    res = requests.put(
        f'{env.AWG_BASE_URL}{ORG_URL}/{org}/user/{user2}?new_username={user_name}',
        headers=reg_user_headers
    )
    assert res.status_code == 403
    response_contains_json(res, 'error', 'NOT_SAME_USER_OR_SECRETARIAT')

def test_regular_user_cannot_update_duplicate_user_with_new_username(reg_user_headers):
    """ regular users cannot update a user's username if that user already exist """
    org = reg_user_headers['CVE-API-ORG']
    user1 = reg_user_headers['CVE-API-USER']
    user2 = str(uuid.uuid4())
    # creating a user with same org as regular user
    res = post_new_org_user(org, user2)
    assert res.status_code == 200
    res = requests.put(
        f'{env.AWG_BASE_URL}{ORG_URL}/{org}/user/{user1}?new_username={user2}',
        headers=reg_user_headers
    )
    assert res.status_code == 403
    response_contains_json(res, 'error', 'NOT_ORG_ADMIN_OR_SECRETARIAT_UPDATE')

def test_regular_user_cannot_update_organization_with_new_shortname(reg_user_headers):
    """ regular users cannot update organization """
    user = reg_user_headers['CVE-API-USER']
    org1 = reg_user_headers['CVE-API-ORG']
    org2 = str(uuid.uuid4())[:MAX_SHORTNAME_LENGTH]
    res = requests.put(
        f'{env.AWG_BASE_URL}{ORG_URL}/{org1}/user/{user}?org_short_name={org2}',
        headers=reg_user_headers
    )
    assert res.status_code == 403
    response_contains_json(res, 'error', 'NOT_ALLOWED_TO_CHANGE_ORGANIZATION')

def test_regular_user_cannot_update_active_state(reg_user_headers):
    """ regular user cannot change its own active state """
    org = reg_user_headers['CVE-API-ORG']
    user = reg_user_headers['CVE-API-USER']
    res = requests.put(
        f'{env.AWG_BASE_URL}{ORG_URL}/{org}/user/{user}?active=false',
        headers=reg_user_headers
    )
    assert res.status_code == 403
    response_contains_json(res, 'error', 'NOT_ORG_ADMIN_OR_SECRETARIAT_UPDATE')

def test_regular_user_cannot_add_role(reg_user_headers):
    """  regular users cannot add role """
    org = reg_user_headers['CVE-API-ORG']
    user = reg_user_headers['CVE-API-USER']
    res = requests.put(
        # adding role
        f'{env.AWG_BASE_URL}{ORG_URL}/{org}/user/{user}?active_roles.add=admin',
        headers=reg_user_headers
    )
    assert res.status_code == 403
    response_contains_json(res, 'error', 'NOT_ORG_ADMIN_OR_SECRETARIAT_UPDATE')

def test_regular_user_cannot_remove_role(reg_user_headers):
    """  regular users cannot remove role """
    org = reg_user_headers['CVE-API-ORG']
    user = reg_user_headers['CVE-API-USER']
    res = requests.put(
        # removing role
        f'{env.AWG_BASE_URL}{ORG_URL}/{org}/user/{user}?active_roles.remove=admin',
        headers=reg_user_headers
    )
    assert res.status_code == 403
    response_contains_json(res, 'error', 'NOT_ORG_ADMIN_OR_SECRETARIAT_UPDATE')

def test_regular_user_cannot_update_user_org_dne(reg_user_headers):
    """ regular user cannot update a user from an org that doesn't exist """
    org = str(uuid.uuid4())[:MAX_SHORTNAME_LENGTH]
    user = reg_user_headers['CVE-API-USER']
    res = requests.put(
        f'{env.AWG_BASE_URL}{ORG_URL}/{org}/user/{user}',
        headers=reg_user_headers
    )
    assert res.status_code == 404
    response_contains_json(res, 'error', 'ORG_DNE_PARAM')

def test_reg_user_cannot_update_user_dne(reg_user_headers):
    """ regular user cannot update a user that doesn't exist """
    org = reg_user_headers['CVE-API-ORG']
    user = str(uuid.uuid4())
    res = requests.put(
        f'{env.AWG_BASE_URL}{ORG_URL}/{org}/user/{user}',
        headers=reg_user_headers
    )
    assert res.status_code == 404
    response_contains_json(res, 'error', 'USER_DNE')

#### POST /org/:shortname/user ###
def test_reg_user_cannot_create_user(reg_user_headers):
    """ regular user cannot create another user """
    org = reg_user_headers['CVE-API-ORG']
    user_name = str(uuid.uuid4())
    res = requests.post(
        f'{env.AWG_BASE_URL}{ORG_URL}/{org}/user',
        headers=reg_user_headers,
        json={'username': user_name}
    )
    assert res.status_code == 403
    response_contains_json(res, 'error', 'NOT_ORG_ADMIN_OR_SECRETARIAT')

#### PUT /org/:shortname ####
def test_reg_user_cannot_update_org(reg_user_headers):
    """ regular user cannot update an organization """
    org = str(uuid.uuid4())[:MAX_SHORTNAME_LENGTH]
    res = requests.put(
        f'{env.AWG_BASE_URL}{ORG_URL}/{org}',
        headers=reg_user_headers
    )
    assert res.status_code == 403
    response_contains_json(res, 'error', 'SECRETARIAT_ONLY')

#### GET /org/:identifier ####
def test_reg_user_can_view_same_org(reg_user_headers):
    """ regular users can view the organization they belong to """
    org = reg_user_headers['CVE-API-ORG']
    res = requests.get(
        f'{env.AWG_BASE_URL}{ORG_URL}/{org}',
        headers=reg_user_headers
    )
    ok_response_contains_json(res, 'short_name', org)

def test_reg_user_cannot_view_another_org(reg_user_headers):
    """ regular users cannot view an organization they don't belong to """
    org = str(uuid.uuid4())[:MAX_SHORTNAME_LENGTH]
    res = requests.get(
        f'{env.AWG_BASE_URL}{ORG_URL}/{org}',
        headers=reg_user_headers
    )
    assert res.status_code == 403
    response_contains_json(res, 'error', 'NOT_SAME_ORG_OR_SECRETARIAT')

#### GET /org ####
def test_reg_user_cannot_view_orgs(reg_user_headers):
    """ regular users cannot view all organizations """
    res = requests.get(
        f'{env.AWG_BASE_URL}{ORG_URL}',
        headers=reg_user_headers
    )
    assert res.status_code == 403
    response_contains_json(res, 'error', 'SECRETARIAT_ONLY')

#### GET /org/:shortname/users ####
def test_reg_user_can_view_users_same_org(reg_user_headers):
    """ regular users can view users of the same organization """
    org = reg_user_headers['CVE-API-ORG']
    res = requests.get(
        f'{env.AWG_BASE_URL}{ORG_URL}/{org}/users',
        headers=reg_user_headers
    )
    assert res.status_code == 200
    assert len(json.loads(res.content.decode())['users']) > 0

def test_reg_user_cannot_view_users_org_dne(reg_user_headers):
    """ regular users cannot view users of an organization that doesn't exist """
    org = str(uuid.uuid4())[:MAX_SHORTNAME_LENGTH]
    res = requests.get(
        f'{env.AWG_BASE_URL}{ORG_URL}/{org}/users',
        headers=reg_user_headers
    )
    assert res.status_code == 404
    response_contains_json(res, 'error', 'ORG_DNE_PARAM')

def test_reg_user_cannot_view_users_another_org(reg_user_headers):
    """ regular users cannot view users of another organization """
    org = str(uuid.uuid4())[:MAX_SHORTNAME_LENGTH]
    res = post_new_org(org, org)
    assert res.status_code == 200
    res = requests.get(
        f'{env.AWG_BASE_URL}{ORG_URL}/{org}/users',
        headers=reg_user_headers
    )
    assert res.status_code == 403
    response_contains_json(res, 'error', 'NOT_SAME_ORG_OR_SECRETARIAT')

#### GET /org/:shortname/user/:username ####
def test_reg_user_can_view_users_same_org(reg_user_headers):
    """ regular users can view users of the same organization """
    org = reg_user_headers['CVE-API-ORG']
    user = str(uuid.uuid4())
    res = post_new_org_user(org, user)
    assert res.status_code == 200
    res = requests.get(
        f'{env.AWG_BASE_URL}{ORG_URL}/{org}/user/{user}',
        headers=reg_user_headers
    )
    ok_response_contains_json(res, 'username', user)

def test_reg_user_cannot_view_user_from_another_org(reg_user_headers):
    """ regular users cannot view users from another organization """
    org, user = create_new_user_with_new_org_by_uuid()
    res = requests.get(
        f'{env.AWG_BASE_URL}{ORG_URL}/{org}/user/{user}',
        headers=reg_user_headers
    )
    assert res.status_code == 403
    response_contains_json(res, 'error', 'NOT_SAME_ORG_OR_SECRETARIAT')

def test_reg_user_cannot_view_user_dne(reg_user_headers):
    """ regular user cannot view user that doesn't exist """
    org = reg_user_headers['CVE-API-ORG']
    user = str(uuid.uuid4())
    res = requests.get(
        f'{env.AWG_BASE_URL}{ORG_URL}/{org}/user/{user}',
        headers=reg_user_headers
    )
    assert res.status_code == 404
    response_contains_json(res, 'error', 'USER_DNE')

#### GET /org/:shortname/id_quota ####
def test_reg_user_can_get_org_id_quota(reg_user_headers):
    """ regular users can see their organization's cve id quota """
    org = reg_user_headers['CVE-API-ORG']
    res = requests.get(
        f'{env.AWG_BASE_URL}{ORG_URL}/{org}/id_quota',
        headers=reg_user_headers
    )
    ok_response_contains(res, 'id_quota')
    ok_response_contains(res, 'total_reserved')
    ok_response_contains(res, 'available')

def test_reg_user_cannot_get_another_org_id_quota(reg_user_headers):
    """ regular users cannot see an organization's cve id quota they don't belong to """
    org = str(uuid.uuid4())[:MAX_SHORTNAME_LENGTH]
    user = str(uuid.uuid4())
    create_new_user_with_new_org_by_shortname(org, user)
    res = requests.get(
        f'{env.AWG_BASE_URL}{ORG_URL}/{org}/id_quota',
        headers=reg_user_headers
    )
    assert res.status_code == 403
    response_contains_json(res, 'error', 'NOT_SAME_ORG_OR_SECRETARIAT')

#### PUT /org/:shortname/user/:username/reset_secret ####
def test_regular_user_reset_secret(reg_user_headers):
    """ regular users can update their secret """
    org = reg_user_headers['CVE-API-ORG']
    user = reg_user_headers['CVE-API-USER']
    res = requests.put(
        f'{env.AWG_BASE_URL}{ORG_URL}/{org}/user/{user}/reset_secret',
        headers=reg_user_headers
    )
    ok_response_contains(res, 'API-secret')

def test_regular_user_cannot_reset_secret_of_another_user(reg_user_headers):
    """ regular user cannot update the secret of another user """
    org = reg_user_headers['CVE-API-ORG']
    user = str(uuid.uuid4())
    res = post_new_org_user(org, user)  # creating a user
    assert res.status_code == 200
    res = requests.put(
        f'{env.AWG_BASE_URL}{ORG_URL}/{org}/user/{user}/reset_secret',
        headers=reg_user_headers
    )
    assert res.status_code == 403
    response_contains_json(res, 'error', 'NOT_SAME_USER_OR_SECRETARIAT')

def test_regular_user_cannot_reset_secret_user_org_dne(reg_user_headers):
    """ regular user cannot reset the secret of a user from an org that doesn't exist """
    org = str(uuid.uuid4())[:MAX_SHORTNAME_LENGTH]
    user = reg_user_headers['CVE-API-USER']
    res = requests.put(
        f'{env.AWG_BASE_URL}{ORG_URL}/{org}/user/{user}/reset_secret',
        headers=reg_user_headers
    )
    assert res.status_code == 404
    response_contains_json(res, 'error', 'ORG_DNE_PARAM')

def test_regular_user_cannot_reset_secret_user_dne(reg_user_headers):
    """ regular user cannot reset the secret of a user that doesn't exist """
    org = reg_user_headers['CVE-API-ORG']
    user = str(uuid.uuid4())
    res = requests.put(
        f'{env.AWG_BASE_URL}{ORG_URL}/{org}/user/{user}/reset_secret',
        headers=reg_user_headers
    )
    assert res.status_code == 404
    response_contains_json(res, 'error', 'USER_DNE')

def test_regular_user_cannot_reset_admin_user_secret(reg_user_headers, org_admin_headers):
    """ regular user tries resetting admin user's secret, fails and admin user's role remains preserved """
    reg_org = reg_user_headers['CVE-API-ORG']
    user = org_admin_headers['CVE-API-USER']
    res = post_new_org_user(reg_org, user)  # creating the user
    assert res.status_code == 200
    res = requests.put(
        f'{env.AWG_BASE_URL}{ORG_URL}/{reg_org}/user/{user}/reset_secret',
        headers=reg_user_headers
    )
    assert res.status_code == 403
    response_contains_json(res, 'error', 'NOT_SAME_USER_OR_SECRETARIAT')
    # Check that user's admin role is preserved
    admin_org = org_admin_headers['CVE-API-ORG']
    res2 = requests.get(
        f'{env.AWG_BASE_URL}{ORG_URL}/{admin_org}/user/{user}',
        headers=org_admin_headers
    )
    assert res2.status_code == 200
    # admin role still remains after attempting to change secret
    assert json.loads(res2.content.decode())[
        "authority"]["active_roles"][0] == "ADMIN"

#### POST /org ####
def test_reg_user_cannot_post_new_org(reg_user_headers):
    """ regular users cannot create new org """
    res = requests.post(
        f'{env.AWG_BASE_URL}{ORG_URL}',
        headers=reg_user_headers
    )
    assert res.status_code == 403
    response_contains_json(res, 'error', 'SECRETARIAT_ONLY')

repo_name: CVEProject/cve-services

repo_language: JavaScript

file_name: Dockerfile

mime_type: text/plain


text:
# Tests in this file use the secretariat credentials and exercise the org
# endpoint as defined by ORG_URL. This endpoint includes Org and User
# functionality, if it becomes unwieldy it should be broken down between Org-
# and User-focused tests.
import copy
import json
import random
import requests
import uuid
from urllib.parse import urlencode
from src import env, utils
from src.utils import (assert_contains, ok_response_contains,
                       ok_response_contains_json, response_contains,
                       response_contains_json)

ORG_URL = '/api/org'
MAX_SHORTNAME_LENGTH = 32
#### GET /org ####

ROLES_BAD_VALUES = [
    # sending an object / assoc array
    # username=bob&authority.active_roles[a]=b
    { 'a': 'ADMIN' },

    # sending multi-dimensional arrays
    # username=bob&authority.active_roles[][a]=b
    [{ 'a': 'ADMIN' }],
    [[ 'ADMIN' ]]
]

ROLES_BAD_QUERY_VALUES = [
    # valid: single value
    # "active_roles.add=CNA",

    # valid: ['CNA']
    # "active_roles.add[]=CNA",

    # valid: ['CNA']
    # "active_roles.add[][]=CNA",

    # valid: ['CNA']
    # "active_roles.add[8]=CNA"

    # valid: ['CNA', 'CNA']
    # "active_roles.add[]=CNA&active_roles.add=CNA"

    # bad assoc arrays are caught by valid param checks
    # "active_roles.add[a]=CNA",

    # invalid: [{'a': 'CNA'}]
    "active_roles.add[][a]=CNA"

    # invalid: [{'CNA': null}]
    "active_roles.add[][CNA]"
]

def test_get_all_orgs():
    """ secretariat users can request a list of all organizations """
    res = requests.get(
        f'{env.AWG_BASE_URL}{ORG_URL}',
        headers=utils.BASE_HEADERS
    )
    ok_response_contains(res, '"active_roles":["SECRETARIAT","CNA"]')
    assert len(json.loads(res.content.decode())['organizations']) >= 1

#### GET /org/:identifier ####
def test_get_mitre_cna():
    """ the cve services api contains the mitre cna """
    res = requests.get(
        f'{env.AWG_BASE_URL}{ORG_URL}/mitre',
        headers=utils.BASE_HEADERS
    )
    ok_response_contains(res, 'SECRETARIAT')
    ok_response_contains_json(res, 'name', 'MITRE Corporation')
    ok_response_contains_json(res, 'short_name', 'mitre')

#### GET /org/:identifier ####
def test_get_mitre_by_org_uuid():
    """ look up org info by org uuid"""
    #  Look up an org to obtain uuid
    res = requests.get(
        f'{env.AWG_BASE_URL}{ORG_URL}/mitre',
        headers=utils.BASE_HEADERS
    )
    ok_response_contains_json(res, 'short_name', 'mitre')
    # obtain the org uuid to filter by
    uuid = json.loads(res.content.decode())['UUID']

    #  Look up org info by the org uuid found above
    res2 = requests.get(
        f'{env.AWG_BASE_URL}{ORG_URL}/{uuid}',
        headers=utils.BASE_HEADERS,
    )
    ok_response_contains(res2, 'SECRETARIAT')
    ok_response_contains_json(res2, 'name', 'MITRE Corporation')
    ok_response_contains_json(
        res2, 'UUID', json.loads(res.content.decode())['UUID'])

#### GET /org/:identifier ####
def test_get_mitre_by_nonexistent_org_uuid():
    """ look up org info by org uuid that cannot be found"""
    uuid = 'nonexistent123'
    res = requests.get(
        f'{env.AWG_BASE_URL}{ORG_URL}/{uuid}',
        headers=utils.BASE_HEADERS,
    )
    assert res.status_code == 404
    response_contains_json(res, 'error', 'ORG_DNE')

#### GET /org/:shortname/id_quota ####
def test_get_mitre_id_quota():
    """ the cve services api's mitre cna has a valid id quota """
    res = get_org_id_data('mitre')
    ok_response_contains(res, 'id_quota')

    body = json.loads(res.content.decode())
    quota = body['id_quota']
    available = body['available']
    reserved = body['total_reserved']

    assert quota >= 0
    assert available >= 0
    assert reserved >= 0

    assert quota <= 100000
    assert quota == available + reserved

#### PUT /org/:shortname ####
def test_update_mitre_id_quota():
    """ a secretariat user can update its own ID quota """
    # NOTE: this test makes sure MITRE can reserve IDs for reservation tests
    res = requests.put(
        f'{env.AWG_BASE_URL}{ORG_URL}/mitre?id_quota=100000',
        headers=utils.BASE_HEADERS)
    assert res.status_code == 200
    response_contains_json(
        res, 'message',
        'mitre organization was successfully updated.')

#### GET /org/:shortname/user/:username ####
def test_get_mitre_demon_user():
    """ the user we're ... using, exists under the mitre cna """
    # although this is a bit tautological, it still exercises the endpoint
    res = requests.get(
        f'{env.AWG_BASE_URL}{ORG_URL}/mitre/user/{env.AWG_USER_NAME}',
        headers=utils.BASE_HEADERS
    )
    ok_response_contains_json(res, 'username', env.AWG_USER_NAME)
    ok_response_contains_json(res, 'active', True)

#### POST /org ####
def test_post_new_org_empty_body():
    """ an empty new org body is invalid for name and short name """
    res = requests.post(
        f'{env.AWG_BASE_URL}{ORG_URL}',
        headers=utils.BASE_HEADERS,
        json={}
    )
    assert res.status_code == 400
    assert 'name' in res.content.decode()
    assert 'short_name' in res.content.decode()
    # One error for each reason 'name' and 'short_name' is invalid. 5
    assert len(json.loads(res.content.decode())['details']) == 5
    response_contains_json(res, 'message', 'Parameters were invalid')

def test_post_new_org_empty_params():
    """ empty new org name and short name parameters is a bad request """
    res = requests.post(
        f'{env.AWG_BASE_URL}{ORG_URL}',
        headers=utils.BASE_HEADERS,
        json={
            'name': '',
            'short_name': ''
        }
    )
    assert res.status_code == 400
    assert 'name' in res.content.decode()
    assert 'short_name' in res.content.decode()
    assert len(json.loads(res.content.decode())['details']) == 3
    response_contains_json(res, 'message', 'Parameters were invalid')

def test_post_new_org_already_exists():
    """ cve services org endpoint rejects duplicate org creation """
    res = requests.post(
        f'{env.AWG_BASE_URL}{ORG_URL}',
        headers=utils.BASE_HEADERS,
        json={
            'name': 'MITRE Corporation',
            'short_name': 'mitre'
        }
    )
    assert res.status_code == 400
    response_contains_json(
        res, 'message', "The \'mitre\' organization already exists.")

def test_post_new_org():
    """ cve services new org endpoint works for unique data """
    uid = str(uuid.uuid4())[:MAX_SHORTNAME_LENGTH]
    quota = random.randint(0, 100000)
    res = post_new_org(uid, uid, quota)
    ok_response_contains(res, f'{uid} organization was successfully created')

def test_post_new_org_duplicate_parameter():
    """ cve services new org endpoint rejects duplicate parameter requests """
    uid = str(uuid.uuid4())[:MAX_SHORTNAME_LENGTH]
    res = requests.post(
        f'{env.AWG_BASE_URL}{ORG_URL}',
        headers=utils.BASE_HEADERS,
        json={
            'short_name': uid,
            'short_name': uid
        }
    )

    # NOTE: this isn't any different from the missing parameters case
    # but maybe it should be, if the services could be updated to return
    # more meaningful error responses
    assert res.status_code == 400
    assert 'name' in res.content.decode()
    assert 'short_name' not in res.content.decode()
    assert len(json.loads(res.content.decode())['details']) == 2
    response_contains_json(res, 'message', 'Parameters were invalid')

def test_post_new_org_uuid_parameter():
    """ should reject creating new orgs with uuid param """
    uid = str(uuid.uuid4())[:MAX_SHORTNAME_LENGTH]
    res = requests.post(
        f'{env.AWG_BASE_URL}{ORG_URL}',
        headers=utils.BASE_HEADERS,
        json={
            'short_name': uid,
            'name': uid,
            'uuid': str(uuid.uuid4())
        }
    )

    json_content = json.loads(res.content.decode())
    assert res.status_code == 400
    assert 'error' in json_content
    assert json_content['error'] == 'UUID_PROVIDED'
    assert 'message' in json_content
    response_contains_json(res, 'message', 'Providing UUIDs for org creation or update is not allowed.')

    # check that it didn't actually create the org:
    # https://github.com/CVEProject/cve-services/issues/887
    res = requests.get(
        f'{env.AWG_BASE_URL}{ORG_URL}/{uid}',
        headers=utils.BASE_HEADERS
    )

    assert res.status_code == 404

def test_post_new_org_malformed_roles():
    """ service should return useful error message for malformed roles """

    for data in ROLES_BAD_VALUES:
        uid = str(uuid.uuid4())[:MAX_SHORTNAME_LENGTH]

        res = requests.post(
            f'{env.AWG_BASE_URL}{ORG_URL}',
            headers=utils.BASE_HEADERS,
            json={
                'short_name': uid,
                'name': uid,
                'uuid': str(uuid.uuid4()),
                'authority': {
                    'active_roles': data
                }
            }
        )

        assert res.status_code == 400
        response_contains_json(res, 'message', 'Parameters were invalid')

        assert res.json()['details'][0]['msg'] == 'Parameter must be a one-dimensional array of strings'
        assert res.json()['details'][0]['param'] == 'authority.active_roles'
        assert res.json()['details'][0]['location'] == 'body'

#### POST /org/:shortname/user ####
def test_post_new_org_user():
    """ secretariat user can create a new user without active roles """
    uid = str(uuid.uuid4())[:MAX_SHORTNAME_LENGTH]
    res = post_new_org_user('mitre', uid)
    assert res.status_code == 200
    response_contains_json(res, 'message', f'{uid} was successfully created.')

def test_post_new_org_bad_role_blarg():
    """ service creates user in spite of erroneous data in body """
    uid = str(uuid.uuid4())[:MAX_SHORTNAME_LENGTH]
    res = requests.post(
        f'{env.AWG_BASE_URL}{ORG_URL}/mitre/user',
        headers=utils.BASE_HEADERS,
        json={
            'username': uid,
            'ubiquitous': 'mendacious'
        }
    )
    assert res.status_code == 200
    response_contains_json(res, 'message', f'{uid} was successfully created.')

def test_post_new_org_user_malformed_roles():
    """ service should return useful error message for malformed roles """
    uid = str(uuid.uuid4())[:MAX_SHORTNAME_LENGTH]

    for data in ROLES_BAD_VALUES:
        res = requests.post(
            f'{env.AWG_BASE_URL}{ORG_URL}/mitre/user',
            headers=utils.BASE_HEADERS,
            json={
                'username': uid,
                'authority': {
                    'active_roles': data
                }
            }
        )

        assert res.status_code == 400
        response_contains_json(res, 'message', 'Parameters were invalid')

        assert res.json()['details'][0]['msg'] == 'Parameter must be a one-dimensional array of strings'
        assert res.json()['details'][0]['param'] == 'authority.active_roles'
        assert res.json()['details'][0]['location'] == 'body'

def test_post_new_org_user_empty_body():
    """ an empty new org user body is invalid for username """
    res = requests.post(
        f'{env.AWG_BASE_URL}{ORG_URL}/mitre/user',
        headers=utils.BASE_HEADERS,
        json={}
    )
    assert res.status_code == 400
    assert 'username' in res.content.decode()
    assert len(json.loads(res.content.decode())['details']) == 3
    response_contains_json(res, 'message', 'Parameters were invalid')

def test_post_new_org_user_empty_params():
    """ an empty new org user parameters is invalid for username """
    res = requests.post(
        f'{env.AWG_BASE_URL}{ORG_URL}/mitre/user',
        headers=utils.BASE_HEADERS,
        json={'username': ''}
    )
    assert res.status_code == 400
    assert 'username' in res.content.decode()
    assert len(json.loads(res.content.decode())['details']) == 2
    response_contains_json(res, 'message', 'Parameters were invalid')

def test_post_new_org_user_duplicate():
    """ cve services new org user endpoint fails for a duplicate user """
    res = requests.post(
        f'{env.AWG_BASE_URL}{ORG_URL}/mitre/user',
        headers=utils.BASE_HEADERS,
        json={'username': env.AWG_USER_NAME}
    )
    assert res.status_code == 400
    response_contains_json(
        res, 'message',
        f"The user \'{env.AWG_USER_NAME}\' already exists.")

#### PUT /org/:shortname ####
def test_put_update_org_that_does_not_exist():
    """ cve services api will not update orgs that don't exist """
    uid = 'nonexistant_org'
    res = requests.put(
        f'{env.AWG_BASE_URL}{ORG_URL}/{uid}?id_quota=100',
        headers=utils.BASE_HEADERS
    )
    assert res.status_code == 404
    response_contains_json(res, 'error', 'ORG_DNE_PARAM')
    assert_contains(res, 'by the shortname path parameter does not exist')

def test_put_update_mitre_org_malformed_roles():
    """ service should return useful error message for malformed roles """

    for data in ROLES_BAD_QUERY_VALUES:
        res = requests.put(
            f'{env.AWG_BASE_URL}{ORG_URL}/mitre',
            headers=utils.BASE_HEADERS,
            params=data
        )

        assert res.status_code == 400, str(data)
        response_contains_json(res, 'message', 'Parameters were invalid')

        assert res.json()['details'][0]['msg'] == 'Parameter must be a one-dimensional array of strings'
        assert res.json()['details'][0]['param'] == 'active_roles.add'
        assert res.json()['details'][0]['location'] == 'query'

def test_put_update_mitre_org_nonexistent_user():
    """ cve services api will fail requests from users that don't exist """
    uid = str(uuid.uuid4())[:MAX_SHORTNAME_LENGTH]
    tmp = copy.deepcopy(utils.BASE_HEADERS)
    tmp['CVE-API-ORG'] = uid
    tmp['CVE-API-USER'] = uid
    res = requests.get(
        f'{env.AWG_BASE_URL}{ORG_URL}/mitre',
        headers=tmp
    )
    assert res.status_code == 401
    assert res.reason == 'Unauthorized'
    response_contains_json(res, 'error', 'UNAUTHORIZED')
    response_contains_json(res, 'message', 'Unauthorized')

#### PUT /org/:shortname/user/:username ####
def test_put_update_user_username():
    """ services api allows user usernames to be updated by secretariat """
    org, user = create_new_user_with_new_org_by_uuid()
    new_user_uid = str(uuid.uuid4())

    # finally, we can update that user
    res = requests.put(
        f'{env.AWG_BASE_URL}{ORG_URL}/{org}/user/{user}',
        headers=utils.BASE_HEADERS,
        params={'new_username': new_user_uid}
    )
    assert res.status_code == 200
    response_contains_json(res, 'message', f'{user} was successfully updated.')

    # we can't try again because the user doesn't exist anymore
    res = requests.put(
        f'{env.AWG_BASE_URL}{ORG_URL}/{org}/user/{user}',
        headers=utils.BASE_HEADERS,
        params={'new_username': new_user_uid}
    )
    assert res.status_code == 404
    response_contains(
        res, 'designated by the username parameter does not exist.')
    response_contains_json(res, 'error', 'USER_DNE')

def test_put_update_user_org_short_name():
    """ services api allows users org to be updated by secretariat """
    org, user = create_new_user_with_new_org_by_uuid()
    new_org = 'new_org_name'
    new_org_res = post_new_org(new_org, new_org)
    assert new_org_res.status_code == 200

    res = requests.put(
        f'{env.AWG_BASE_URL}{ORG_URL}/{org}/user/{user}',
        headers=utils.BASE_HEADERS,
        params={'org_short_name': new_org}
    )
    assert res.status_code == 200
    response_contains_json(res, 'message', f'{user} was successfully updated.')

    # user doesn't exist at this endpoint because its under a new org
    res = requests.put(
        f'{env.AWG_BASE_URL}{ORG_URL}/{org}/user/{user}',
        headers=utils.BASE_HEADERS,
        params={'org_short_name': new_org}
    )
    assert res.status_code == 404
    response_contains(
        res, 'designated by the username parameter does not exist.')
    response_contains_json(res, 'error', 'USER_DNE')

    # but we can get the new user
    res = requests.get(
        f'{env.AWG_BASE_URL}{ORG_URL}/{new_org}/user/{user}',
        headers=utils.BASE_HEADERS
    )
    ok_response_contains(res, user)

def test_put_update_user_personal_info():
    """ services api allows user personal info to be updated by secretariat """
    org, user = create_new_user_with_new_org_by_uuid()
    name_uid = str(uuid.uuid4())
    res = requests.put(
        f'{env.AWG_BASE_URL}{ORG_URL}/{org}/user/{user}',
        headers=utils.BASE_HEADERS,
        params={
            'name.first': name_uid,
            'name.last': name_uid,
            'name.middle': name_uid,
            'name.suffix': name_uid,
        }
    )
    assert res.status_code == 200
    assert_contains(res, name_uid, count=4)

def test_put_update_user_add_admin_role():
    """ services api allows user active roles to be updated by secretariat """
    org, user = create_new_user_with_new_org_by_uuid()
    res = requests.put(
        f'{env.AWG_BASE_URL}{ORG_URL}/{org}/user/{user}',
        headers=utils.BASE_HEADERS,
        params={'active_roles.add': 'ADMIN'}
    )
    assert res.status_code == 200
    response_contains_json(res, 'message', f'{user} was successfully updated.')
    assert json.loads(res.content.decode())['updated']['authority'] == {
        'active_roles': ['ADMIN']}

def test_put_update_user_add_empty_role():
    """ services api rejects request to add roles that do not exist """
    org, user = create_new_user_with_new_org_by_uuid()
    res = requests.put(
        f'{env.AWG_BASE_URL}{ORG_URL}/{org}/user/{user}',
        headers=utils.BASE_HEADERS,
        params={'active_roles.add': 'MAGNANIMOUS'}
    )
    assert res.status_code == 400
    assert 'MAGNANIMOUS' not in res.content.decode()
    response_contains_json(res, 'error', 'BAD_INPUT')
    response_contains_json(res, 'message', 'Parameters were invalid')
    response_contains(res, 'Invalid role. Valid role')

def test_put_update_user_remove_admin_role():
    """ services api allows user active roles to be updated by secretariat """
    org, user = create_new_user_with_new_org_by_uuid()
    res = requests.put(
        f'{env.AWG_BASE_URL}{ORG_URL}/{org}/user/{user}',
        headers=utils.BASE_HEADERS,
        params={'active_roles.add': 'ADMIN'}
    )
    assert res.status_code == 200
    res = requests.put(
        f'{env.AWG_BASE_URL}{ORG_URL}/{org}/user/{user}',
        headers=utils.BASE_HEADERS,
        params={'active_roles.remove': 'ADMIN'}
    )
    assert res.status_code == 200
    response_contains_json(res, 'message', f'{user} was successfully updated.')
    assert json.loads(res.content.decode())[
        'updated']['authority'] == {'active_roles': []}

def test_put_update_user_remove_admin_role():
    """ services api rejects requests to remove user roles that don't exist """
    org, user = create_new_user_with_new_org_by_uuid()

    res = requests.put(
        f'{env.AWG_BASE_URL}{ORG_URL}/{org}/user/{user}',
        headers=utils.BASE_HEADERS,
        params={'active_roles.add': 'ADMIN'}
    )
    assert res.status_code == 200

    res = requests.put(
        f'{env.AWG_BASE_URL}{ORG_URL}/{org}/user/{user}',
        headers=utils.BASE_HEADERS,
        params={'active_roles.remove': 'FELLOE'}
    )
    assert res.status_code == 400
    assert 'FELLOE' not in res.content.decode()
    response_contains_json(res, 'error', 'BAD_INPUT')
    response_contains_json(res, 'message', 'Parameters were invalid')
    response_contains(res, 'Invalid role. Valid role')

def test_put_update_user_malformed_roles():
    """ service should return useful error message for malformed roles """

    org, user = create_new_user_with_new_org_by_uuid()

    res = requests.put(
        f'{env.AWG_BASE_URL}{ORG_URL}/{org}/user/{user}',
        headers=utils.BASE_HEADERS,
        params={'active_roles.add': 'ADMIN'}
    )
    assert res.status_code == 200

    for data in ROLES_BAD_QUERY_VALUES:
        res = requests.put(
            f'{env.AWG_BASE_URL}{ORG_URL}/{org}/user/{user}',
            headers=utils.BASE_HEADERS,
            params=data
        )

        assert res.status_code == 400, str(data)
        response_contains_json(res, 'message', 'Parameters were invalid')

        assert res.json()['details'][0]['msg'] == 'Parameter must be a one-dimensional array of strings'
        assert res.json()['details'][0]['param'] == 'active_roles.add'
        assert res.json()['details'][0]['location'] == 'query'

#### PUT /org/:shortname/user/:username/reset_secret ####
def test_put_update_user_reset_secret():
    """ services api allows the secretariat to reset user secrets """
    org, user = create_new_user_with_new_org_by_uuid()
    res = requests.put(
        f'{env.AWG_BASE_URL}{ORG_URL}/{org}/user/{user}/reset_secret',
        headers=utils.BASE_HEADERS
    )
    assert res.status_code == 200
    response_contains(res, 'API-secret')

# ORG ENDPOINT UTILITIES
# ==============================================================================
# these are unique to the `{ORG_URL}` endpoint for the AWG system

def get_org(cna_short_name):
    return requests.get(
        f'{env.AWG_BASE_URL}{ORG_URL}/{cna_short_name}',
        headers=utils.BASE_HEADERS
    )

def get_org_id_data(cna_short_name):
    return requests.get(
        f'{env.AWG_BASE_URL}{ORG_URL}/{cna_short_name}/id_quota',
        headers=utils.BASE_HEADERS
    )

def post_new_org(name, short_name, id_quota=1000, is_secretariat=False):
    """ create an organization with the services api """
    roles = ['CNA']
    if is_secretariat:
        roles = ['SECRETARIAT'] + roles
    return requests.post(
        f'{env.AWG_BASE_URL}{ORG_URL}',
        headers=utils.BASE_HEADERS,
        json={
            'name': name,
            'short_name': short_name,
            'authority': {'active_roles': roles},
            'policies': {'id_quota': id_quota}
        }
    )

def post_new_org_user(org_short_name, user_name):
    """ create a user for the organization defined by its short name """
    return requests.post(
        f'{env.AWG_BASE_URL}{ORG_URL}/{org_short_name}/user',
        headers=utils.BASE_HEADERS,
        json={'username': user_name}
    )

def create_new_user_with_new_org_by_shortname(org_short_name, user_name):
    """ create an organization, and a user under that org """
    org_res = post_new_org(org_short_name, org_short_name)
    assert org_res.status_code == 200
    user_res = post_new_org_user(org_short_name, user_name)
    assert user_res.status_code == 200
    return org_short_name, user_name

def create_new_user_with_new_org_by_uuid():
    """ create an organization, and a user under that org, using uuid """
    user_name = str(uuid.uuid4())
    org_short_name = str(uuid.uuid4())[:MAX_SHORTNAME_LENGTH]

    org_res = post_new_org(org_short_name, org_short_name)
    assert org_res.status_code == 200
    user_res = post_new_org_user(org_short_name, user_name)
    assert user_res.status_code == 200

    return org_short_name, user_name


text:
import json
import requests
from src import env
from src.utils import response_contains_json

CVE_URL = '/api/cve'
cve_id = 'CVE-1999-0001'
update_cve_id = create_cve_id = 'CVE-2000-0008'

#Also need to update with new permissions

# #### GET /cve ####
# def test_get_all_cves(org_admin_headers):
#     """ services api rejects requests for admin orgs """
#     res = requests.get(
#         f'{env.AWG_BASE_URL}{CVE_URL}/',
#         headers=org_admin_headers
#     )
#     assert res.status_code == 403
#     response_contains_json(res, 'error', 'SECRETARIAT_ONLY')

# #### GET /cve/:id ####
# def test_get_cve(org_admin_headers):
#     """ services api rejects requests for admin orgs """
#     res = requests.get(
#         f'{env.AWG_BASE_URL}{CVE_URL}/{cve_id}',
#         headers=org_admin_headers
#     )
#     assert res.status_code == 403
#     response_contains_json(res, 'error', 'SECRETARIAT_ONLY')

# #### POST /cve/:id ####
# def test_create_cve(org_admin_headers):
#     """ services api rejects requests for admin orgs """
#     with open('./src/test/cve_tests/cve_record_fixtures/CVE-2000-0008_published.json') as json_file:
#         data = json.load(json_file)
#         res = requests.post(
#             f'{env.AWG_BASE_URL}{CVE_URL}/{create_cve_id}',
#             headers=org_admin_headers,
#             json=data
#         )
#         assert res.status_code == 403
#         response_contains_json(res, 'error', 'SECRETARIAT_ONLY')

# #### PUT /cve/:id ####
# def test_update_cve_record(org_admin_headers):
#     """ services api rejects requests for admin orgs """
#     with open('./src/test/cve_tests/cve_record_fixtures/CVE-2000-0008_published.json') as json_file:
#         data = json.load(json_file)
#         res = requests.put(
#             f'{env.AWG_BASE_URL}{CVE_URL}/{update_cve_id}',
#             headers=org_admin_headers,
#             json=data
#         )
#         assert res.status_code == 403
#         response_contains_json(res, 'error', 'SECRETARIAT_ONLY')


text:
import copy
import datetime as dt
import json
import pytest
import requests
import time
import uuid
from pathlib import Path

from requests.models import Response
from src import env, utils
from src.utils import ok_response_contains, response_contains_json, ok_response_contains, ok_response_contains_json

CVE_URL = '/api/cve'
cve_id = 'CVE-1999-0001'
cve_id_dne = 'CVE-3000-0001'
curr_cve_id = 'CVE-2021-0005'
update_cve_id = create_cve_id = 'CVE-2000-0008'
reserved_cve_id = 'CVE-2017-5833'
reject_cve_id = 'CVE-2009-0009'
cve_f = 'CVE-2000-0008'

ORG_URL = '/api/org'

### GET /cve ####

def test_get_all_cves_secretariat():
    """ services api accepts requests for all CVEs for secretariat and bulk_download users """
    res = requests.get(
        f'{env.AWG_BASE_URL}{CVE_URL}/',
        headers=utils.BASE_HEADERS
    )
    assert res.status_code == utils.HTTP_OK
    assert len(json.loads(res.content.decode())['cveRecords']) >= 1

def test_get_all_cves_bulk_download(bulk_download_user_headers):
    """ services api accepts requests for all CVEs for secretariat and bulk_download users """
    res = requests.get(
        f'{env.AWG_BASE_URL}{CVE_URL}/',
        headers=bulk_download_user_headers
    )
    assert res.status_code == utils.HTTP_OK
    assert len(json.loads(res.content.decode())['cveRecords']) >= 1

def test_get_cve_by_time_modified():
    # @todo - These records are created by the populate scripts on the node side
    # Creating them again here throws 400 errors, which are ignored in this test

    # create CVE records if they don't exist
    post_cve('CVE-2021-0004_published', 'CVE-2021-0004')
    post_cve('CVE-2021-0005_published', 'CVE-2021-0005')

    # grab current timestamp for gt value, then sleep long enough
    # for imprecise second resolution and update the CVE records
    dt_before_update = dt.datetime.now(tz=dt.timezone.utc)
    time.sleep(3)

    update_cve('CVE-2021-0004_published', 'CVE-2021-0004')
    update_cve('CVE-2021-0005_published', 'CVE-2021-0005')

    # wait again, then grab after timestamp for lt value
    time.sleep(3)
    dt_after_update = dt.datetime.now(tz=dt.timezone.utc)

    # check for ISO dates with and without timezone offsets
    date_fmt = '%Y-%m-%dT%H:%M:%S'
    date_fmt_tz = '%Y-%m-%dT%H:%M:%S+00:00'

    # without tz
    res = requests.get(
        f'{env.AWG_BASE_URL}{CVE_URL}/',
        headers=utils.BASE_HEADERS,
        params={
            'time_modified.lt': dt_after_update.strftime(date_fmt),
            'time_modified.gt': dt_before_update.strftime(date_fmt)
        }
    )

    assert res.status_code == utils.HTTP_OK
    assert len(json.loads(res.content.decode())['cveRecords']) == 2

    # with tz
    res_alt = requests.get(
        f'{env.AWG_BASE_URL}{CVE_URL}/',
        headers=utils.BASE_HEADERS,
        params={
            'time_modified.lt': dt_after_update.strftime(date_fmt_tz),
            'time_modified.gt': dt_before_update.strftime(date_fmt_tz)
        }
    )

    assert res_alt.status_code == utils.HTTP_OK
    assert len(json.loads(res_alt.content.decode())['cveRecords']) == 2

def test_get_cve_by_count_only_true():
    """
    count_only set to True using number 1

    WARNING: Requires pristine database
    """
    res = requests.get(
        f'{env.AWG_BASE_URL}{CVE_URL}/',
        headers=utils.BASE_HEADERS,
        params={
            'count_only': 1
        }

    )
    assert len(json.loads(res.content.decode())) == 1  # only count is returned
    assert json.loads(res.content.decode())['totalCount'] == 114
    assert res.status_code == 200

def test_get_cve_by_count_only_false():
    """
    count_only set to False using number 0, returns all records

    WARNING: Requires pristine database
    """
    res = requests.get(
        f'{env.AWG_BASE_URL}{CVE_URL}/',
        headers=utils.BASE_HEADERS,
        params={
            'count_only': 0
        }

    )
    assert len(json.loads(res.content.decode())[
               'cveRecords']) == 114  # all records are returned
    assert res.status_code == 200

def test_get_cve_invalid_count_number():
    """ count_only can only be set to 0 or 1 """
    res = requests.get(
        f'{env.AWG_BASE_URL}{CVE_URL}/',
        headers=utils.BASE_HEADERS,
        params={
            'count_only': 11
        }
    )
    assert res.status_code == 400
    response_contains_json(res, 'error', 'BAD_INPUT')

def test_get_cve_invalid_count_value():
    """ count_only can only be set to 0,1,true,false,yes,no """
    res = requests.get(
        f'{env.AWG_BASE_URL}{CVE_URL}/',
        headers=utils.BASE_HEADERS,
        params={
            'count_only': 'Maybe'
        }
    )
    assert res.status_code == 400
    response_contains_json(res, 'error', 'BAD_INPUT')

def test_get_cve_filter_by_published_state():
    """ CVE ID filter endpoint with state 'PUBLISHED' """
    res = requests.get(
        f'{env.AWG_BASE_URL}{CVE_URL}/',
        headers=utils.BASE_HEADERS,
        params={
            'state': 'PUBLISHED'
        }
    )
    assert res.status_code == 200
    recordsLength = len(json.loads(res.content.decode())['cveRecords'])
    assert recordsLength >= 61
    for i in range(recordsLength):
        assert json.loads(res.content.decode())[
            'cveRecords'][i]['cveMetadata']['state'] == 'PUBLISHED'

def test_get_cve_filter_by_rejected_state():
    """ CVE ID filter endpoint with state 'REJECTED' """
    res = requests.get(
        f'{env.AWG_BASE_URL}{CVE_URL}/',
        headers=utils.BASE_HEADERS,
        params={
            'state': 'REJECTED'
        }
    )
    assert res.status_code == 200
    recordsLength = len(json.loads(res.content.decode())['cveRecords'])
    assert recordsLength >= 52
    for i in range(recordsLength):
        assert json.loads(res.content.decode())[
            'cveRecords'][i]['cveMetadata']['state'] == 'REJECTED'

def test_get_cve_filter_by_unrecognized_state_reserved():
    """ CVE ID filter endpoint does not recognize RESERVED state """
    res = requests.get(
        f'{env.AWG_BASE_URL}{CVE_URL}/',
        headers=utils.BASE_HEADERS,
        params={
            'state': 'RESERVED'
        }
    )
    assert res.status_code == 400
    assert 'RESERVED' not in res.content.decode()

def test_get_cve_filter_by_unrecognized_state_available():
    """ CVE ID filter endpoint does not recognize AVAILABLE state """
    res = requests.get(
        f'{env.AWG_BASE_URL}{CVE_URL}/',
        headers=utils.BASE_HEADERS,
        params={
            'state': 'AVAILABLE'
        }
    )
    assert res.status_code == 400
    assert 'AVAILABLE' not in res.content.decode()

def test_get_cve_filter_by_assignerShortName():
    """ Filter CVE collection by assigner_short_name"""
    res2 = requests.get(
        f'{env.AWG_BASE_URL}{CVE_URL}/',
        headers=utils.BASE_HEADERS,
        params={
            'assigner_short_name': 'mitre'  # use org uuid as assigner
        }
    )
    assert res2.status_code == 200
    recordsLength = len(json.loads(res2.content.decode())['cveRecords'])
    assert recordsLength >= 1
    for i in range(recordsLength):
        assert json.loads(res2.content.decode())[
            'cveRecords'][i]['cveMetadata']['assigner'] == json.loads(res.content.decode())['UUID']

def test_get_cve_filter_by_assigner_empty():
    """ Filtering CVE collection by nonexistent assigner succeeds and returns empty array"""
    res = requests.get(
        f'{env.AWG_BASE_URL}{CVE_URL}/',
        headers=utils.BASE_HEADERS,
        params={
            'assigner': '12b746bd-357f-483d-8cda-ed822fecf731'
        }
    )
    assert res.status_code == 200
    recordsLength = len(json.loads(res.content.decode())['cveRecords'])
    assert recordsLength >= 0  # this assigner has zero occurences

def test_get_cve_filter_by_assignerShortName():
    """ Filter CVE collection by assigner_short_name that has 5 occurences"""
    res = requests.get(
        f'{env.AWG_BASE_URL}{CVE_URL}/',
        headers=utils.BASE_HEADERS,
        params={
            'assigner_short_name': 'admit_9'
        }
    )
    assert res.status_code == 200
    recordsLength = len(json.loads(res.content.decode())['cveRecords'])
    assert recordsLength == 5
    for i in range(recordsLength):
        assert json.loads(res.content.decode())[
            'cveRecords'][i]['cveMetadata']['assignerShortName'] == 'admit_9'

def test_get_cve_filter_by_assignerShortName_empty():
    """ Filtering CVE collection by nonexistent assigner_short_name succeeds and returns empty array"""
    res = requests.get(
        f'{env.AWG_BASE_URL}{CVE_URL}/',
        headers=utils.BASE_HEADERS,
        params={
            'assigner_short_name': 'cisco'
        }
    )
    assert res.status_code == 200
    recordsLength = len(json.loads(res.content.decode())['cveRecords'])
    assert recordsLength >= 0  # this assignerShortName has zero occurences

#### GET /cve/:id ####
def test_get_cve():
    res = requests.get(
        f'{env.AWG_BASE_URL}{CVE_URL}/{cve_id}',
        headers=utils.BASE_HEADERS
    )
    ok_response_contains(res, cve_id)

def test_get_cve_dne():
    res = requests.get(
        f'{env.AWG_BASE_URL}{CVE_URL}/{cve_id_dne}',
        headers=utils.BASE_HEADERS
    )
    assert res.status_code == 404
    response_contains_json(res, 'error', 'CVE_RECORD_DNE')

#### POST /cve/:id ####
def test_create_cve():
    """ publish a cve in the PUBLISHED state """
    with open('./src/test/cve_tests/cve_record_fixtures/CVE-2000-0008_published.json') as json_file:
        data = json.load(json_file)
        res = requests.post(
            f'{env.AWG_BASE_URL}{CVE_URL}/{create_cve_id}',
            headers=utils.BASE_HEADERS,
            json=data
        )
        try:
            ok_response_contains(res, create_cve_id)
        except AssertionError:
            assert res.status_code == 400
            response_contains_json(res, 'error', 'CVE_RECORD_EXISTS')

def test_create_cve_mismatch():
    """ the cve id in the json body does not match the cve id in the path parameter """
    with open('./src/test/cve_tests/cve_record_fixtures/CVE-2000-0008_published.json') as json_file:
        data = json.load(json_file)
        res = requests.post(
            f'{env.AWG_BASE_URL}{CVE_URL}/{curr_cve_id}',
            headers=utils.BASE_HEADERS,
            json=data
        )
        assert res.status_code == 400
        response_contains_json(res, 'error', 'CVEID_MISMATCH')

def test_create_cve_reserved_state():
    """ the cve record cannot be created in the RESERVED state """
    with open('./src/test/cve_tests/cve_record_fixtures/CVE-2017-5833_reserved.json') as json_file:
        data = json.load(json_file)
        res = requests.post(
            f'{env.AWG_BASE_URL}{CVE_URL}/{reserved_cve_id}',
            headers=utils.BASE_HEADERS,
            json=data
        )
        assert res.status_code == 400
        response_contains_json(res, 'error', 'INVALID_JSON_SCHEMA')

def test_create_nonexistent_cveid():
    """ the cve record cannot be created because the CVE ID doesn't exist """
    with open('./src/test/cve_tests/cve_record_fixtures/CVE-3000-0001_nonexistent.json') as json_file:
        data = json.load(json_file)
        res = requests.post(
            f'{env.AWG_BASE_URL}{CVE_URL}/{cve_id_dne}',
            headers=utils.BASE_HEADERS,
            json=data
        )
        assert res.status_code == 403
        response_contains_json(res, 'error', 'CVEID_DNE')

def test_create_existent_cve():
    """ the cve record cannot be created because it already exists """
    with open('./src/test/cve_tests/cve_record_fixtures/CVE-2021-0004_published.json') as json_file:
        data = json.load(json_file)
        res = requests.post(
            f'{env.AWG_BASE_URL}{CVE_URL}/CVE-2021-0004',
            headers=utils.BASE_HEADERS,
            json=data
        )
        assert res.status_code == 400
        response_contains_json(res, 'error', 'CVE_RECORD_EXISTS')

def test_create_unique_eng_cve():
    """ the cve record cannot be created because it already exists """
    with open('./src/test/cve_tests/cve_record_fixtures/CVE-2021-0004_published.json') as json_file:
        data = json.load(json_file)
        data['containers']['cna']['descriptions'].append({
            "lang": "en",
            "value": "A second en entry"
        })

        res = requests.post(
            f'{env.AWG_BASE_URL}{CVE_URL}/CVE-2021-0004',
            headers=utils.BASE_HEADERS,
            json=data
        )

        res_json = json.loads(res.content.decode())

        response_contains_json(res, 'error', 'BAD_INPUT')
        assert res_json['details'][0]['param'] == "containers.cna.descriptions"
        assert res_json['details'][0]['msg'] == "Cannot have more than one English language entry in 'containers.cna.descriptions'"

#### POST /cve/:id/reject ####

def test_submit_record_rejection():
    """ submit a reject request with a descriptions and replacedBy arrays """
    res = requests.post(
        f'{env.AWG_BASE_URL}/api/cve-id',
        headers=utils.BASE_HEADERS,
        params={
            'amount': 1,
            'cve_year': 2000,
            'short_name': 'mitre'
        }
    )
    id_num = json.loads(res.content.decode())[
        'cve_ids'][0]['cve_id']  # obtain id number
    with open('./src/test/cve_tests/cve_record_fixtures/rejectBody.json') as json_file:
        data = json.load(json_file)
        res = requests.post(
            f'{env.AWG_BASE_URL}{CVE_URL}/{id_num}/reject',
            headers=utils.BASE_HEADERS,
            json=data
        )
        assert res.status_code == 200

def test_submit_record_rejection_id_dne():
    """ submit a reject request with descriptions and replacedBy arrays for id that dne """
    fake_id = "CVE-0000-0000"
    with open('./src/test/cve_tests/cve_record_fixtures/rejectBody.json') as json_file:
        data = json.load(json_file)
        res = requests.post(
            f'{env.AWG_BASE_URL}{CVE_URL}/{fake_id}/reject',
            headers=utils.BASE_HEADERS,
            json=data
        )
        assert res.status_code == 403

def test_submit_record_rejection_multiple_different_english_values():
    """ submit a reject request with descriptions array that has multiple different English values (ex: "en" and "en-Ca") """
    res = requests.post(
        f'{env.AWG_BASE_URL}/api/cve-id/',
        headers=utils.BASE_HEADERS,
        params={
            'amount': 1,
            'cve_year': 2000,
            'short_name': 'mitre'
        }
    )
    id_num = json.loads(res.content.decode())[
        'cve_ids'][0]['cve_id']  # obtain id number
    with open('./src/test/cve_tests/cve_record_fixtures/rejectBodyMultipleDiffEngValues.json') as json_file:
        data = json.load(json_file)
        res = requests.post(
            f'{env.AWG_BASE_URL}{CVE_URL}/{id_num}/reject',
            headers=utils.BASE_HEADERS,
            json=data
        )
        assert res.status_code == 200  # lang values are unique

def test_submit_record_rejection_multiple_non_English_values():
    """ submit a reject request with descriptions array that has multiple non English values (ex: "fr" and "fr") """
    res = requests.post(
        f'{env.AWG_BASE_URL}/api/cve-id/',
        headers=utils.BASE_HEADERS,
        params={
            'amount': 1,
            'cve_year': 2000,
            'short_name': 'mitre'
        }
    )
    id_num = json.loads(res.content.decode())[
        'cve_ids'][0]['cve_id']  # obtain id number
    with open('./src/test/cve_tests/cve_record_fixtures/rejectBodyMultipleNonEngValues.json') as json_file:
        data = json.load(json_file)
        res = requests.post(
            f'{env.AWG_BASE_URL}{CVE_URL}/{id_num}/reject',
            headers=utils.BASE_HEADERS,
            json=data
        )
        assert res.status_code == 400  # lang values aren't unique

def test_submit_record_rejection_multiple_same_lang_values():
    """
    submit a reject request with descriptions array that has multiple
    identical lang and value entries.
    """
    res = requests.post(
        f'{env.AWG_BASE_URL}/api/cve-id/',
        headers=utils.BASE_HEADERS,
        params={
            'amount': 1,
            'cve_year': 2000,
            'short_name': 'mitre'
        }
    )
    id_num = json.loads(res.content.decode())['cve_ids'][0]['cve_id']
    with open('./src/test/cve_tests/cve_record_fixtures/rejectBodyMultipleSameEngValues.json') as json_file:
        data = json.load(json_file)
        res = requests.post(
            f'{env.AWG_BASE_URL}{CVE_URL}/{id_num}/reject',
            headers=utils.BASE_HEADERS,
            json=data
        )

        res_json = json.loads(res.content.decode())

        assert res.status_code == 400

        response_contains_json(res, 'error', 'INVALID_JSON_SCHEMA')
        assert res_json['details']['errors'][0]['instancePath'] == '/cnaContainer/rejectedReasons'
        assert res_json['details']['errors'][0]['schemaPath'] == '#/uniqueItems'

def test_update_record_rejection_multiple_same_English_values():
    """
    update a reject request with descriptions array that has multiple
    identical English lang and value entries.
    """
    res = requests.post(
        f'{env.AWG_BASE_URL}/api/cve-id/',
        headers=utils.BASE_HEADERS,
        params={
            'amount': 1,
            'cve_year': 2000,
            'short_name': 'mitre'
        }
    )
    id_num = json.loads(res.content.decode())['cve_ids'][0]['cve_id']
    with open('./src/test/cve_tests/cve_record_fixtures/rejectBody.json') as json_file:
        data = json.load(json_file)
        res = requests.post(
            f'{env.AWG_BASE_URL}{CVE_URL}/{id_num}/reject',
            headers=utils.BASE_HEADERS,
            json=data
        )

        assert res.status_code == 200

    with open('./src/test/cve_tests/cve_record_fixtures/rejectBodyMultipleSameEngValues.json') as json_file:
        data = json.load(json_file)
        res = requests.put(
            f'{env.AWG_BASE_URL}{CVE_URL}/{id_num}/reject',
            headers=utils.BASE_HEADERS,
            json=data
        )

        res_json = json.loads(res.content.decode())

        assert res.status_code == 400

        response_contains_json(res, 'error', 'INVALID_JSON_SCHEMA')
        assert res_json['details']['errors'][0]['instancePath'] == '/cnaContainer/rejectedReasons'
        assert res_json['details']['errors'][0]['schemaPath'] == '#/uniqueItems'

def test_submit_record_rejection_multiple_English_lang_entries():
    """ submit a reject request with descriptions array that contains multiple English lang entries """
    res = requests.post(
        f'{env.AWG_BASE_URL}/api/cve-id/',
        headers=utils.BASE_HEADERS,
        params={
            'amount': 1,
            'cve_year': 2000,
            'short_name': 'mitre'
        }
    )
    id_num = json.loads(res.content.decode())['cve_ids'][0]['cve_id']
    with open('./src/test/cve_tests/cve_record_fixtures/rejectBodyMultipleEngLangs.json') as json_file:
        data = json.load(json_file)
        res = requests.post(
            f'{env.AWG_BASE_URL}{CVE_URL}/{id_num}/reject',
            headers=utils.BASE_HEADERS,
            json=data
        )

        res_json = json.loads(res.content.decode())

        assert res.status_code == 400

        # example of how to validate when eventually using Avj extensions
        # response_contains_json(res, 'error', 'INVALID_JSON_SCHEMA')
        # assert res_json['details']['errors'][0]['instancePath'] == '/cnaContainer/rejectedReasons'
        # assert res_json['details']['errors'][0]['message'] == 'Cannot have more than one English language entry: en-gb.'
        response_contains_json(res, 'error', 'BAD_INPUT')
        assert res_json['details'][0]['param'] == "cnaContainer.rejectedReasons"
        assert res_json['details'][0]['msg'] == "Cannot have more than one English language entry in 'cnaContainer.rejectedReasons'"

def test_update_record_rejection_multiple_English_lang_entries():
    """
    update a reject request with descriptions array that has multiple
    identical English lang entries.
    """
    res = requests.post(
        f'{env.AWG_BASE_URL}/api/cve-id/',
        headers=utils.BASE_HEADERS,
        params={
            'amount': 1,
            'cve_year': 2000,
            'short_name': 'mitre'
        }
    )
    id_num = json.loads(res.content.decode())['cve_ids'][0]['cve_id']
    with open('./src/test/cve_tests/cve_record_fixtures/rejectBody.json') as json_file:
        data = json.load(json_file)
        res = requests.post(
            f'{env.AWG_BASE_URL}{CVE_URL}/{id_num}/reject',
            headers=utils.BASE_HEADERS,
            json=data
        )

        assert res.status_code == 200

    with open('./src/test/cve_tests/cve_record_fixtures/rejectBodyMultipleEngLangs.json') as json_file:
        data = json.load(json_file)
        res = requests.put(
            f'{env.AWG_BASE_URL}{CVE_URL}/{id_num}/reject',
            headers=utils.BASE_HEADERS,
            json=data
        )

        res_json = json.loads(res.content.decode())

        assert res.status_code == 400

        response_contains_json(res, 'error', 'BAD_INPUT')
        assert res_json['details'][0]['param'] == "cnaContainer.rejectedReasons"
        assert res_json['details'][0]['msg'] == "Cannot have more than one English language entry in 'cnaContainer.rejectedReasons'"

#### PUT /cve/:id ####
def test_update_cve_record():
    with open('./src/test/cve_tests/cve_record_fixtures/CVE-2021-0005_published.json') as json_file:
        data = json.load(json_file)
        res = requests.put(
            f'{env.AWG_BASE_URL}{CVE_URL}/{curr_cve_id}',
            headers=utils.BASE_HEADERS,
            json=data
        )
        ok_response_contains(res, curr_cve_id)

def test_update_cve_mismatch():
    """ the cve id in the json body does not match the cve id in the path parameter """
    with open('./src/test/cve_tests/cve_record_fixtures/CVE-2000-0008_published.json') as json_file:
        data = json.load(json_file)
        res = requests.put(
            f'{env.AWG_BASE_URL}{CVE_URL}/{curr_cve_id}',
            headers=utils.BASE_HEADERS,
            json=data
        )
        assert res.status_code == 400
        response_contains_json(res, 'error', 'CVEID_MISMATCH')

def test_update_cve_reserved_state():
    """ the cve record cannot be changed to the RESERVED state """
    with open('./src/test/cve_tests/cve_record_fixtures/CVE-2017-5833_reserved.json') as json_file:
        data = json.load(json_file)
        res = requests.put(
            f'{env.AWG_BASE_URL}{CVE_URL}/{reserved_cve_id}',
            headers=utils.BASE_HEADERS,
            json=data
        )
        assert res.status_code == 400
        response_contains_json(res, 'error', 'INVALID_JSON_SCHEMA')

def test_update_nonexistent_cve_id():
    """ the cve record cannot be updated because the CVE ID doesn't exist """
    with open('./src/test/cve_tests/cve_record_fixtures/CVE-3000-0001_nonexistent.json') as json_file:
        data = json.load(json_file)
        res = requests.put(
            f'{env.AWG_BASE_URL}{CVE_URL}/{cve_id_dne}',
            headers=utils.BASE_HEADERS,
            json=data
        )
        assert res.status_code == 403
        response_contains_json(res, 'error', 'CVEID_DNE')

def test_update_nonexistent_cve():
    """ the cve record cannot be updated because it doesn't exist """
    with open('./src/test/cve_tests/cve_record_fixtures/CVE-2009-0009_rejected.json') as json_file:
        data = json.load(json_file)
        res = requests.put(
            f'{env.AWG_BASE_URL}{CVE_URL}/{reject_cve_id}',
            headers=utils.BASE_HEADERS,
            json=data
        )
        assert res.status_code == 403
        response_contains_json(res, 'error', 'CVE_RECORD_DNE')

def test_record_submission_too_large():
    """ the cve record cannot be submitted because it is 16 mb"""
    with open('./src/test/cve_tests/cve_record_fixtures/CVE-2021-0004_largeInput.json') as json_file:
        data = json.load(json_file)
        res = requests.post(
            f'{env.AWG_BASE_URL}{CVE_URL}/CVE-2021-0004',
            headers=utils.BASE_HEADERS,
            json=data
        )
        assert res.status_code == 413  # payload is too large
        response_contains_json(res, 'error', 'RECORD_TOO_LARGE')

def test_record_update_too_large():
    """ the cve record cannot be updated because it is 16 mb"""
    with open('./src/test/cve_tests/cve_record_fixtures/CVE-2021-0004_largeInput.json') as json_file:
        data = json.load(json_file)
        res = requests.put(
            f'{env.AWG_BASE_URL}{CVE_URL}/CVE-2021-0004',
            headers=utils.BASE_HEADERS,
            json=data
        )
        assert res.status_code == 413  # payload is too large
        response_contains_json(res, 'error', 'RECORD_TOO_LARGE')

### POST cve/:id/cna ###
def test_post_cna_container():
    """ the cve record is created from provided cna container """
    with open('./src/test/cve_tests/cve_record_fixtures/CVE-2000-0008_published.json') as json_file:
        data = json.load(json_file)
        data = {'cnaContainer': data['containers']['cna']}
        res = requests.post(
            f'{env.AWG_BASE_URL}{CVE_URL}/CVE-2021-0004/cna',
            headers=utils.BASE_HEADERS,
            json=data
        )

        try:
            assert res.status_code == 200
        except AssertionError:
            assert res.status_code == 403
            response_contains_json(res, 'error', 'CVE_RECORD_EXISTS')

def test_post_cna_container_langs():
    """
    tests all permutations of the language fields for cna containers

    NB: This currently checks only the cna.descriptions field and not
    cna.problemTypes.descriptions because it's unclear if it has the same restrictions

    """

    pos = [
        "cna_descriptions-multipleEnLangsDifferentLocale.json",
        "cna_descriptions-multipleSameLangs.json",
        # "cna_problemTypes_descriptions-multipleEnLangsDifferentLocale.json",
        # "cna_problemTypes_descriptions-multipleSameLangs.json",
    ]

    neg = [
        "cna_descriptions-multipleEnLangs.json",
        "cna_descriptions-multipleIdenticalEntries.json",
        # "cna_problemTypes_descriptions-multipleEnLangs.json",
        # "cna_problemTypes_descriptions-multipleIdenticalEntries.json",
    ]

    def get_res(test_filename):
        test_path = Path(
            './src/test/cve_tests/cve_record_fixtures',
            'CVE-2000-0008_published_langs',
            test_filename
        )

        with open(test_path) as json_file:
            data = json.load(json_file)
            data = {'cnaContainer': data['containers']['cna']}
            return requests.post(
                f'{env.AWG_BASE_URL}{CVE_URL}/CVE-2021-0004/cna',
                headers=utils.BASE_HEADERS,
                json=data
            )

    for test_filename in pos:
        res = get_res(test_filename)

        # these records already exist and it's outside scope to create new ones here.
        # we only want to test that validation passes for the language fields,
        # so the expected error should be a duplicate entry, NOT language related
        assert res.status_code == 403, test_filename
        response_contains_json(res, 'error', 'CVE_RECORD_EXISTS')

    for test_filename in neg :
        res = get_res(test_filename)
        res_json = json.loads(res.content.decode())

        assert res.status_code == 400, test_filename

        # temp fix for a special case because language validation happens
        # separately from schema validation, and these are caught
        # by the avj schema validation
        if test_filename.endswith('multipleIdenticalEntries.json'):
            response_contains_json(res, 'error', 'INVALID_JSON_SCHEMA', test_filename)
        else:
            response_contains_json(res, 'error', 'BAD_INPUT', test_filename)
            assert res_json['details'][0]['param'] == "cnaContainer.descriptions"
            assert res_json['details'][0]['msg'] == "Cannot have more than one English language entry in 'cnaContainer.descriptions'"

def test_put_cna_container():
    """ the cve record is updated from provided cna container """
    with open('./src/test/cve_tests/cve_record_fixtures/CVE-2000-0008_published.json') as json_file:
        data = json.load(json_file)
        data = {'cnaContainer': data['containers']['cna']}
        res = requests.put(
            f'{env.AWG_BASE_URL}{CVE_URL}/CVE-2021-0004/cna',
            headers=utils.BASE_HEADERS,
            json=data
        )
        assert res.status_code == 200

def test_put_cna_container_langs():
    """
    tests all permutations of the language fields for put cna containers

    NB: This currently checks only the cna.descriptions field and not
    cna.problemTypes.descriptions because it's unclear if it has the same restrictions

    """

    pos = [
        "cna_descriptions-multipleEnLangsDifferentLocale.json",
        "cna_descriptions-multipleSameLangs.json",
        # "cna_problemTypes_descriptions-multipleEnLangsDifferentLocale.json",
        # "cna_problemTypes_descriptions-multipleSameLangs.json",
    ]

    neg = [
        "cna_descriptions-multipleEnLangs.json",
        "cna_descriptions-multipleIdenticalEntries.json",

        # throws a 500 instead of 40X
        # "cna_descriptions-multipleSameLangsNoEn.json",

        # "cna_problemTypes_descriptions-multipleEnLangs.json",
        # "cna_problemTypes_descriptions-multipleIdenticalEntries.json",
    ]

    def get_res(test_filename):
        test_path = Path(
            './src/test/cve_tests/cve_record_fixtures',
            'CVE-2000-0008_published_langs',
            test_filename
        )

        with open(test_path) as json_file:
            data = json.load(json_file)
            data = {'cnaContainer': data['containers']['cna']}
            return requests.put(
                f'{env.AWG_BASE_URL}{CVE_URL}/CVE-2021-0004/cna',
                headers=utils.BASE_HEADERS,
                json=data
            )

    for test_filename in pos:
        res = get_res(test_filename)
        assert res.status_code == 200, test_filename

    for test_filename in neg :
        res = get_res(test_filename)
        res_json = json.loads(res.content.decode())

        assert res.status_code == 400, test_filename

        # temp fix for a special case because language validation happens
        # separately from schema validation, and these are caught
        # by the avj schema validation
        if test_filename.endswith('multipleIdenticalEntries.json'):
            response_contains_json(res, 'error', 'INVALID_JSON_SCHEMA', test_filename)
        else:
            response_contains_json(res, 'error', 'BAD_INPUT', test_filename)
            assert res_json['details'][0]['param'] == "cnaContainer.descriptions"
            assert res_json['details'][0]['msg'] == "Cannot have more than one English language entry in 'cnaContainer.descriptions'"

# PUT cve/:id/reject ###
def test_record_rejection_in_published_state():
    """ reject an existing record from PUBLISHED state """
    with open('./src/test/cve_tests/cve_record_fixtures/rejectExisting.json') as json_file:
        data = json.load(json_file)
        res = requests.put(
            f'{env.AWG_BASE_URL}{CVE_URL}/CVE-1999-0003/reject',
            headers=utils.BASE_HEADERS,
            json=data
        )
    assert res.status_code == 200

def test_record_rejection_in_rejected_state():
    """ reject an existing record from REJECTED state with optional replacedBy"""
    with open('./src/test/cve_tests/cve_record_fixtures/rejectExisting.json') as json_file:
        data = json.load(json_file)
        res = requests.put(
            f'{env.AWG_BASE_URL}{CVE_URL}/CVE-1999-0001/reject',
            headers=utils.BASE_HEADERS,
            json=data
        )
    assert res.status_code == 200

def test_record_rejection_in_rejected_state_no_replacedBy():
    """ reject an existing record from REJECTED state with no optional replacedBy """
    with open('./src/test/cve_tests/cve_record_fixtures/rejectExisting.json') as json_file:
        data = json.load(json_file)
        res = requests.put(
            f'{env.AWG_BASE_URL}{CVE_URL}/CVE-1999-0008/reject',
            headers=utils.BASE_HEADERS,
            json=data
        )
    assert res.status_code == 200

# CVE ENDPOINT UTILITIES
# ==============================================================================
# these are unique to the `{CVE_URL}` endpoint for the AWG system

def update_cve(filename, cveid):
    with open(f'./src/test/cve_tests/cve_record_fixtures/{filename}.json') as json_file:
        data = json.load(json_file)
        res = requests.put(
            f'{env.AWG_BASE_URL}{CVE_URL}/{cveid}',
            headers=utils.BASE_HEADERS,
            json=data
        )

def post_cve(filename, cveid):
    with open(f'./src/test/cve_tests/cve_record_fixtures/{filename}.json') as json_file:
        data = json.load(json_file)
        res = requests.post(
            f'{env.AWG_BASE_URL}{CVE_URL}/{cveid}',
            headers=utils.BASE_HEADERS,
            json=data
        )

def test_cve_get_page():
    """ page must be a positive int """
    res = requests.get(
        f'{env.AWG_BASE_URL}{CVE_URL}',
        headers=utils.BASE_HEADERS,
        params={
            'page': '1',
        }
    )
    assert res.status_code == 200

def test_cve_get_bad_page():
    """ page must be a positive int """

    # test negative
    res = requests.get(
        f'{env.AWG_BASE_URL}{CVE_URL}',
        headers=utils.BASE_HEADERS,
        params={
            'page': -1,
        }
    )
    assert res.status_code == 400
    response_contains_json(res, 'error', 'BAD_INPUT')
    response_contains_json(res, 'details', utils.BAD_PAGE_ERROR_DETAILS)

    # test strings
    res = requests.get(
        f'{env.AWG_BASE_URL}{CVE_URL}',
        headers=utils.BASE_HEADERS,
        params={
            'page': 'abc',
        }
    )
    assert res.status_code == 400
    response_contains_json(res, 'error', 'BAD_INPUT')
    response_contains_json(res, 'details', utils.BAD_PAGE_ERROR_DETAILS)

def test_get_cve_ensure_sorted():
    """ Should be ordered by CVE ID asc. """
    res = requests.get(
        f'{env.AWG_BASE_URL}{CVE_URL}/',
        headers=utils.BASE_HEADERS,
    )

    assert res.status_code == 200
    records = json.loads(res.content.decode())['cveRecords']

    prev_id = "CVE-1900-0000"
    for record in records:
        assert record['cveMetadata']['cveId'] > prev_id
        prev_id = record['cveMetadata']['cveId']


text:
import json
import requests
from src import env
from src.utils import response_contains_json

CVE_URL = '/api/cve'
cve_id = 'CVE-1999-0001'
update_cve_id = create_cve_id = 'CVE-2000-0008'

# Need to change all of these to test new expected access.
# Anyone can GET, and any user tied to a CNA can create and update.

# #### GET /cve ####
# def test_get_all_cves(reg_user_headers):
#     """ services api rejects requests for regular users """
#     res = requests.get(
#         f'{env.AWG_BASE_URL}{CVE_URL}/',
#         headers=reg_user_headers
#     )
#     assert res.status_code == 403
#     response_contains_json(res, 'error', 'SECRETARIAT_ONLY')

# #### GET /cve/:id ####
# def test_get_cve(reg_user_headers):
#     """ services api rejects requests for regular users """
#     res = requests.get(
#         f'{env.AWG_BASE_URL}{CVE_URL}/{cve_id}',
#         headers=reg_user_headers
#     )
#     assert res.status_code == 403
#     response_contains_json(res, 'error', 'SECRETARIAT_ONLY')

# #### POST /cve/:id ####
# def test_create_cve(reg_user_headers):
#     """ services api rejects requests for regular users """
#     with open('./src/test/cve_tests/cve_record_fixtures/CVE-2000-0008_published.json') as json_file:
#         data = json.load(json_file)
#         res = requests.post(
#             f'{env.AWG_BASE_URL}{CVE_URL}/{create_cve_id}',
#             headers=reg_user_headers,
#             json=data
#         )
#         assert res.status_code == 403
#         response_contains_json(res, 'error', 'SECRETARIAT_ONLY')

# #### PUT /cve/:id ####
# def test_update_cve_record(reg_user_headers):
#     """ services api rejects requests for admin orgs """
#     with open('./src/test/cve_tests/cve_record_fixtures/CVE-2000-0008_published.json') as json_file:
#         data = json.load(json_file)
#         res = requests.put(
#             f'{env.AWG_BASE_URL}{CVE_URL}/{update_cve_id}',
#             headers=reg_user_headers,
#             json=data
#         )
#         assert res.status_code == 403
#         response_contains_json(res, 'error', 'SECRETARIAT_ONLY')


text:
pytest
requests


text:
version: '3'
services:
  demon:
    container_name: demon
    build:
      context: ../
      dockerfile: docker/Dockerfile
    env_file: .docker-env
    network_mode: host
    volumes:
      - ../src:/app/src


text:
#!/bin/bash
# Do not exit the container
# - Instead, wait to run tests using `docker exec -it`
# - This enables capturing of Python's debugger and re-running tests
#   without restarting the container

echo "Waiting."
sleep 99999