Repository navigation
test: cover device cleanup crons, team devices, MAC twins and re-pairing - #7600
Merged
Merged
Conversation
otavio
added this pull request to stack #7601
October 17, 2026 23:42
This comment has been minimized.
This comment has been minimized.
otavio
force-pushed
the
test/t243-devices
branch
from
October 18, 2026 20:03
4681281 to
632d257
Compare
Member
Author
|
/review |
This comment has been minimized.
This comment has been minimized.
otavio
force-pushed
the
test/t243-devices
branch
from
October 18, 2026 20:20
632d257 to
b4bb460
Compare
Member
Author
|
/review |
This comment has been minimized.
This comment has been minimized.
otavio
force-pushed
the
test/t243-devices
branch
from
October 18, 2026 20:49
b4bb460 to
867ca50
Compare
Member
Author
|
/review |
This comment has been minimized.
This comment has been minimized.
otavio
force-pushed
the
test/t243-devices
branch
from
October 18, 2026 23:11
867ca50 to
6c12365
Compare
Member
Author
|
/review |
|
Claude finished @otavio's task in 5m 13s —— View job Code Review CompleteI reviewed all 10 files for Standards (repo rules, Go conventions, tests, code smells) and Correctness (security and runtime defects) and found no new issues. The code looks good as it is. The Spec axis did not run because the PR closes no issue and its commits cite none, so there is nothing to review against. |
otavio
force-pushed
the
test/t243-devices
branch
from
October 19, 2026 00:36
6c12365 to
2ee350d
Compare
otavio
force-pushed
the
test/t243-devices
branch
from
October 19, 2026 00:41
2ee350d to
d6fa75c
Compare
otavio
force-pushed
the
test/t243-devices
branch
from
October 19, 2026 00:48
d6fa75c to
fccb558
Compare
otavio
force-pushed
the
test/t243-devices
branch
from
October 19, 2026 01:01
fccb558 to
6647727
Compare
otavio
force-pushed
the
test/t243-devices
branch
from
October 19, 2026 01:19
6647727 to
a486e1d
Compare
CreateDevicePairing reused the code cached for a public key for the whole code lifetime, including after the code was accepted, and then answered with the accepted status and tenant. An agent whose paired device is removed forgets its tenant and asks for a pairing again. If that happened within ten minutes of the pairing, it got the stale acceptance back, kept the tenant, authenticated, got 401 for the removed device, and started over: about 30 pairing and auth requests a second until the code expired. Only a pending code is reused now. AcceptDevicePairing now refuses a code that is no longer pending, the same not-found answer as an expired one. Without that, an accept page left open on the old code could put the removed device back in the namespace while the agent waits on its new code, which nobody accepts. The accepted code is also dropped from the cache when the new one is minted, but that alone does not close the hole: an accept already in flight on the old code writes it back after the drop. Refusing at accept time holds whichever side wins. Re-submitting an accepted code, a double click or a retry, now answers not found instead of succeeding again. The console's accept page resolves the code first, and the resolve used to answer for a pairing code whatever its status, so a reloaded or second-tab accept page offered the namespace picker and then failed with a generic error. The resolve now refuses a pairing code that is no longer pending too, and the page shows its usual "invalid or has expired" message. Dropping the accepted code made the accepted-device lookup load-bearing. Any lookup error used to read as "no accepted device", which was harmless while the cached code still answered accepted. Now it would discard a pairing that went through: an agent restarted before saving its tenant would be handed a fresh code nobody will accept, and it never asks again. Only a not-found result moves on to the cache; any other store error is returned, so the agent exits and retries. For the same reason, an accepted cached code triggers a second lookup before it is dropped: an accept can land between the first lookup and the cache read, as when `shellhub-agent login` runs while the daemon waits on the same code, and dropping it then would leave neither process with the tenant.
Both jobs are triggered through RunCron instead of waited for, and the stamp each one measures, disconnected_at or removed_at, is moved back in the database. Each case pairs a device past its window with one inside it, so a job that deleted too much fails as well as one that deleted nothing. The namespace counts are read before the stamp is moved: the server's own scheduler keeps running in the stack, and a tick landing after the move would delete the device before the snapshot. The ephemeral case also waits out the heartbeat flush interval after the device goes offline. A keep-alive queued before the disconnect is written later and clears disconnected_at once the moved stamp is older than the beat, so the device would never qualify for cleanup. Reading a namespace and waiting for a device by name move into the environment package, since other tests repeat both.
The twin is a real agent, so the server sees it online the way it does in production. The existing name-conflict test stops its agent first and never reaches this refusal. Each re-authentication of the pending newcomer ages its last enrollment attempt past the reconcile interval, which otherwise throttles the re-evaluation for a minute.
An agent that learned its tenant from pairing forgets it and pairs again without restarting. One given SHELLHUB_TENANT_ID exits. Reaching the second case needs a device enrolled by pairing and then served with a configured tenant, so a second container reuses the first one's key, identity and hostname, which gives it the same device UID. The test waits for the agent's own connected line instead of the API's online flag: right after a pairing accept the device reads online from its fresh last_seen before the agent has polled its code.
otavio
force-pushed
the
test/t243-devices
branch
from
October 19, 2026 01:27
a486e1d to
57b49e9
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
End-to-end coverage for five device behaviours from the shellhub-io/team#243 audit (Domains 7 and 9)
that only had unit or service tests, or none.
The crons run through
RunCroninstead of being waited for. The time each one measures is movedback in the database.
Evidence
Before: none of these paths had an e2e test. Aging both devices inside their windows fails
both
TestDeviceCleanupcases ("device … is still there"). Without the fix this PR stacks on,TestRemovedPairedDeviceAgent/an_agent_that_learned_its_tenant_from_pairing_pairs_againfailsbecause the agent immediately re-persists the stale tenant.
After:
Merge Danger
Door: two-way
Blast Radius: tests
Test-only. Adds about two minutes of stack time to the e2e job.