Act on the wj architectural review: races, limits, pool and contract gaps
Findings F2, F4, F5, F6, F7, F8, F9, F10, F11 and F13 from wj-architectural-review.md. F1/F1a (the non-sargable LOWER pattern) and F3 (the warranty sync holding a pooled connection) are being handled separately and are untouched here. - A collector check-in that raced another for the same PC lost everything: the unique index on the application fingerprint raised, nothing caught it, and the whole check-in rolled back, discarding state, events and hardware, answering the agent with form copy meant for a person. The insert now runs in a savepoint, reconciles what the other transaction already wrote, one row per savepoint so a second collision skips a row rather than the batch, and the check-in commits with a warning. This is the shape the delete side of the same function already had. - Enrollment is deliberately unauthenticated, so it now carries a per-address rate limit and a cap on pending requests, and the cap is a setting an admin can see and change. A flood can no longer bury the approval queue or grow the table without bound. - The fleet alert poll no longer formats debug strings on every request. - BusinessUnit is on the contract surface (0.34.0), so the endpoints plugin stops reaching into a core table with raw SQL. - A test walks every asset type descriptor and proves the endpoint it names really refuses a caller without the declared permission. - The plugin settings routes now need a permission; they were telling anyone which modules a site runs and where its components live. - The connection pool is sized explicitly with a short timeout, and the arithmetic against the server's connection ceiling is written next to the worker count instead of being left to defaults nobody chose. - Fleet alerts carry both the correct lowercase keys and the old camelCase pair. Trays older than 1.7.0 match keys case-sensitively and would have gone quiet on every PC not yet upgraded; the old pair goes when they are. - The dev server proxy points at localhost again, with environment variables for the remote-box workflow, and one developer's address is out of the server certificate page.
This commit is contained in:
@@ -107,18 +107,42 @@ def test_agent_polls_its_active_fleet_alerts(client, db, app):
|
||||
|
||||
assert resp.status_code == 200, resp.get_data(as_text=True)
|
||||
alerts = resp.get_json()['data']
|
||||
assert [a['notificationId'] for a in alerts] == [alert.notificationid]
|
||||
assert [a['notificationid'] for a in alerts] == [alert.notificationid]
|
||||
assert alerts[0]['message'] == 'Line 3 is down'
|
||||
assert alerts[0]['timeout'] == 60
|
||||
# The tray renders the type colour, so it has to come down with the alert
|
||||
# rather than being guessed client side.
|
||||
assert alerts[0]['typeColor'] == '#d93f3f'
|
||||
assert alerts[0]['typecolor'] == '#d93f3f'
|
||||
|
||||
|
||||
def test_the_feed_still_carries_the_legacy_camelcase_keys(client, db, app):
|
||||
"""TRANSITION for trays older than 1.7.0.
|
||||
|
||||
A deployed 1.6.x tray fetches this feed itself and deserializes
|
||||
case-sensitively, so serving only the lowercase keys would make every alert
|
||||
disappear on those PCs with no error anywhere. Both spellings go down, with
|
||||
identical values, until the fleet is upgraded - then this test and the two
|
||||
camelCase keys go together.
|
||||
"""
|
||||
_computer(db, 'BAY-01')
|
||||
alert = _fleet_alert(db, message='Line 3 is down')
|
||||
|
||||
resp = client.get(f'{ALERTS_URL}?hostname=BAY-01',
|
||||
headers=_collector_headers(app))
|
||||
|
||||
row = resp.get_json()['data'][0]
|
||||
assert row['notificationId'] == row['notificationid'] == alert.notificationid
|
||||
assert row['typeColor'] == row['typecolor'] == '#d93f3f'
|
||||
|
||||
|
||||
def test_poll_requires_the_collector_key(client, db, app):
|
||||
"""The alert feed is agent-facing, not anonymous."""
|
||||
_computer(db, 'BAY-01')
|
||||
_fleet_alert(db)
|
||||
# Configure the key here rather than inheriting it from whichever test ran
|
||||
# first: under xdist this file is split across workers, and an unconfigured
|
||||
# key answers 500 instead of the 401 the test is about.
|
||||
app.config['COLLECTOR_API_KEY'] = COLLECTOR_KEY
|
||||
|
||||
resp = client.get(f'{ALERTS_URL}?hostname=BAY-01')
|
||||
|
||||
@@ -251,7 +275,7 @@ def test_one_bay_cannot_acknowledge_for_another(client, db, app):
|
||||
# And BAY-02's alert is untouched by the attempt.
|
||||
feed = client.get(f'{ALERTS_URL}?hostname=BAY-02',
|
||||
headers=_collector_headers(app))
|
||||
assert [a['notificationId'] for a in feed.get_json()['data']] == [
|
||||
assert [a['notificationid'] for a in feed.get_json()['data']] == [
|
||||
alert.notificationid]
|
||||
|
||||
|
||||
@@ -267,7 +291,7 @@ def test_acknowledging_one_bay_leaves_the_others_alerted(client, db, app):
|
||||
headers=headers)
|
||||
|
||||
still = client.get(f'{ALERTS_URL}?hostname=BAY-02', headers=headers)
|
||||
assert [a['notificationId'] for a in still.get_json()['data']] == [
|
||||
assert [a['notificationid'] for a in still.get_json()['data']] == [
|
||||
alert.notificationid]
|
||||
|
||||
|
||||
@@ -323,7 +347,7 @@ def _ids(client, app, hostname):
|
||||
resp = client.get(f'{ALERTS_URL}?hostname={hostname}',
|
||||
headers=_collector_headers(app))
|
||||
assert resp.status_code == 200, resp.get_data(as_text=True)
|
||||
return [a['notificationId'] for a in resp.get_json()['data']]
|
||||
return [a['notificationid'] for a in resp.get_json()['data']]
|
||||
|
||||
|
||||
def test_no_scope_still_means_the_whole_fleet(client, db, app):
|
||||
|
||||
Reference in New Issue
Block a user