Files
shopdb-flask/tests/test_plugins/test_computers_audit.py

105 lines
4.1 KiB
Python

"""Changing how a PC is reached has to leave a record.
Editing a computer wrote an audit entry for its named fields and nothing at all
for two changes that matter most to anybody investigating later:
* the primary IP address - how the PC is found on the network
* the remote-access protocols and their ports - how somebody connects to it
Both are set on the same form, in the same request, and both were invisible
afterwards. A PC that moved address had no history of moving, and a PC that
gained a VNC listener had no record of gaining one.
"""
import pytest
from shopdb.api import db
@pytest.fixture
def pc(client, db, auth_headers):
from shopdb.core.models import AssetType, AssetStatus
if not AssetType.query.filter_by(assettype='computer').first():
db.session.add(AssetType(assettype='computer'))
if not AssetStatus.query.first():
db.session.add(AssetStatus(status='In Use'))
db.session.commit()
created = client.post('/api/computers', headers=auth_headers, json={
'assetnumber': 'AUDIT-PC-1',
'hostname': 'auditpc1',
'ipaddress': '10.20.30.40',
})
assert created.status_code == 201, created.get_json()
data = created.get_json()['data']
return data.get('computerid') or data['computer']['computerid']
def _entries(entityid):
from shopdb.core.models import AuditLog
return (AuditLog.query
.filter_by(entitytype='Computer', entityid=entityid)
.order_by(AuditLog.auditlogid.desc()).all())
def test_moving_a_pc_to_another_address_is_recorded(client, auth_headers, pc):
response = client.put('/api/computers/%d' % pc, headers=auth_headers,
json={'ipaddress': '10.20.30.99'})
assert response.status_code == 200, response.get_json()
latest = _entries(pc)[0]
assert 'ipaddress' in (latest.changes or {}), latest.changes
assert latest.changes['ipaddress']['old'] == '10.20.30.40'
assert latest.changes['ipaddress']['new'] == '10.20.30.99'
def test_an_unchanged_address_records_nothing(client, auth_headers, pc):
"""A PUT that re-sends the same value is not a change, and an audit log
full of non-events is one nobody reads."""
before = len(_entries(pc))
response = client.put('/api/computers/%d' % pc, headers=auth_headers,
json={'ipaddress': '10.20.30.40'})
assert response.status_code == 200
assert len(_entries(pc)) == before
def test_changing_the_remote_access_protocols_is_recorded(client, db,
auth_headers, pc):
from plugins.computers.models import AccessProtocol
rdp = AccessProtocol(name='RDP', scheme='rdp', linktemplate='rdp://{host}')
vnc = AccessProtocol(name='VNC', scheme='vnc', linktemplate='vnc://{host}')
db.session.add_all([rdp, vnc])
db.session.commit()
client.put('/api/computers/%d' % pc, headers=auth_headers,
json={'accessmethods': [{'protocolid': rdp.protocolid}]})
response = client.put('/api/computers/%d' % pc, headers=auth_headers,
json={'accessmethods': [
{'protocolid': vnc.protocolid,
'portoverride': 5999}]})
assert response.status_code == 200, response.get_json()
latest = _entries(pc)[0]
assert 'accessmethods' in (latest.changes or {}), latest.changes
change = latest.changes['accessmethods']
assert change['old'] == ['%d:default' % rdp.protocolid]
assert change['new'] == ['%d:5999' % vnc.protocolid]
def test_resending_the_same_protocols_records_nothing(client, db,
auth_headers, pc):
from plugins.computers.models import AccessProtocol
ssh = AccessProtocol(name='SSH', scheme='ssh', linktemplate='ssh://{host}')
db.session.add(ssh)
db.session.commit()
client.put('/api/computers/%d' % pc, headers=auth_headers,
json={'accessmethods': [{'protocolid': ssh.protocolid}]})
before = len(_entries(pc))
client.put('/api/computers/%d' % pc, headers=auth_headers,
json={'accessmethods': [{'protocolid': ssh.protocolid}]})
assert len(_entries(pc)) == before