Merge origin/main into wilm: dashboard/fleet console, vuln upgrades, colours

This commit is contained in:
benjamin.baker
2026-08-30 14:41:56 -04:00
53 changed files with 3671 additions and 483 deletions

View File

@@ -104,3 +104,50 @@ def test_relationships_row_carries_isdirectional(client, db, auth_headers):
ctrl_rows = [r for r in data['outgoing']
if r['relationshiptypename'] == 'controls']
assert ctrl_rows and all(r['isdirectional'] is True for r in ctrl_rows)
def test_the_controlled_asset_sees_the_link_from_its_own_page(client, db, auth_headers):
"""The target of a directional edge must receive it in `incoming`.
A PC controls a machine, and the row is stored once, source=PC. The PC's
page reads it from `outgoing`; the machine's page can only ever see it in
`incoming`. Nothing asserted that second half, and a UI was shipped that
rendered the link on the PC page and showed the machine page nothing - the
reciprocal-links defect. The endpoint was correct all along, which is
exactly why this assertion is worth having: it pins the contract the
frontend depends on, so the next such bug cannot be blamed on the API.
"""
atype_machine = AssetType(assettype='machine')
atype_computer = AssetType(assettype='computer')
db.session.add_all([atype_machine, atype_computer])
db.session.flush()
controls = RelationshipType(relationshiptype='controls', isdirectional=True)
db.session.add(controls)
db.session.flush()
pc = _make_asset('PC-1', atype_computer.assettypeid)
machine = _make_asset('M-1', atype_machine.assettypeid)
# Stored ONCE, in the canonical direction only.
db.session.add(AssetRelationship(sourceassetid=pc.assetid,
targetassetid=machine.assetid,
relationshiptypeid=controls.relationshiptypeid))
db.session.commit()
resp = client.get(f'/api/assets/{machine.assetid}/relationships',
headers=auth_headers)
assert resp.status_code == 200
data = resp.get_json()['data']
assert data['outgoing'] == [], 'the machine controls nothing'
assert len(data['incoming']) == 1, 'the machine must see the PC that controls it'
row = data['incoming'][0]
assert row['relationshiptypename'] == 'controls'
# The peer has to arrive with the fields the UI routes on. assetid alone
# is not enough: the detail routes key on pluginid, and the type name
# chooses the route base.
peer = row['sourceasset']
assert peer is not None
assert peer['assetid'] == pc.assetid
assert peer['assettypename'] == 'computer'