Commit graph

720 commits

Author SHA1 Message Date
renovate[bot]
d489cfee13
chore(deps): update github actions 2026-09-28 19:28:25 +00:00
Alexandre Brandizzi
d3b6ba01c7
Merge pull request #193 from Sea-Haven-Industries/fix/ab/sh-403-reset-hardening-2
Some checks failed
Backend CI / Build and test (push) Has been cancelled
Backend CI / architecture (push) Has been cancelled
Backend CI / review (push) Has been cancelled
Backend CI / ci-complete (push) Has been cancelled
fix(auth): cap reset abuse per account, key reset-code hashes, send reset email off the request path
2026-09-25 23:11:26 +00:00
Alexandre Brandizzi
74d5aa17eb fix(auth): trace a reset email the provider rejects as an error
A send that the mail provider did not accept finished its background
transaction as ok, so rejected reset emails looked delivered in tracing.
It now finishes as an error with a fixed message that names no recipient.
2026-09-25 20:01:58 -03:00
Alexandre Brandizzi
1077d489a8
Merge pull request #197 from Sea-Haven-Industries/fix/ab/sh-407-cancel-wo-cancels-uplift
Cancelling a work order cancels its pending uplift
2026-09-25 23:01:24 +00:00
Alexandre Brandizzi
e941e055b7 Merge remote-tracking branch 'origin/main' into fix/ab/sh-407-cancel-wo-cancels-uplift 2026-09-25 19:49:50 -03:00
Alexandre Brandizzi
c985e9423d Merge remote-tracking branch 'origin/main' into fix/ab/sh-403-reset-hardening-2
# Conflicts:
#	Api.SeaHavenIndustries.Tests/AuthenticationServiceTests.cs
#	Api.SeaHavenIndustries.Tests/PasswordPolicyTests.cs
#	SeaHaven.Services/Implementation/AuthenticationService.cs
2026-09-25 19:49:24 -03:00
Alexandre Brandizzi
de0e767930 fix(auth): refuse a reset email when the queue is full instead of dropping it
The channel used DropWrite, under which TryWrite reports success and
discards the email, so a full queue still counted the request and never
sent the code. Wait makes TryWrite return false when the queue is full,
without blocking, so the request is released and the user can ask again.
2026-09-25 19:38:53 -03:00
Alexandre Brandizzi
63465cc083
Merge pull request #198 from Sea-Haven-Industries/fix/ab/sh-409-invalidate-sessions-on-reset
End earlier sign-in sessions after a password reset, password change, deactivation or deletion
2026-09-25 22:38:44 +00:00
Alexandre Brandizzi
a32471d4c0 Serialize sync cancels and vendor uplift requests on the work order lock
The legacy ingest batch holds the per-work-order lock, taken in id order,
for every work order it may cancel until the batch commits. A vendor
uplift request now runs under the same lock. Uplift creation on both
routes refuses a work order cancelled by either lifecycle or status text,
so a request can neither slip past a cancel nor land after one.
2026-09-25 19:37:08 -03:00
Alexandre Brandizzi
0298fc75bd Merge remote-tracking branch 'origin/main' into fix/ab/sh-403-reset-hardening-2 2026-09-25 19:27:01 -03:00
Alexandre Brandizzi
498f49a2d8 fix(auth): end earlier sessions when a user's role or account changes
A token carries the user's roles and account, so a demoted admin kept admin
claims until the token expired. The team member update and the admin user
edit now rotate the security stamp and evict the cached value when the role,
account or user name changes. Permission overrides are read per request and
are not in the token.
2026-09-25 19:26:25 -03:00
Alexandre Brandizzi
987ec455f2 Merge remote-tracking branch 'origin/main' into fix/ab/sh-409-invalidate-sessions-on-reset
# Conflicts:
#	Api.SeaHavenIndustries.Tests/AuthenticationServiceTests.cs
#	Api.SeaHavenIndustries.Tests/PasswordPolicyTests.cs
#	SeaHaven.Services/Implementation/AuthenticationService.cs
2026-09-25 19:22:33 -03:00
Alexandre Brandizzi
de8e283ee5
Merge pull request #192 from Sea-Haven-Industries/fix/ab/sh-403-reset-code-hardening
Some checks are pending
Backend CI / Build and test (push) Waiting to run
Backend CI / architecture (push) Waiting to run
Backend CI / review (push) Waiting to run
Backend CI / ci-complete (push) Blocked by required conditions
fix(auth): stop reset-code guessing and email enumeration in Forgot Password
2026-09-25 22:16:01 +00:00
Alexandre Brandizzi
410bf1b4ca
Merge pull request #195 from Sea-Haven-Industries/fix/ab/sh-408-has-uplift-live-status
fix(work-orders): count only live uplifts for Has uplift and the Uplift column
2026-09-25 22:15:57 +00:00
Alexandre Brandizzi
c8e4b8f3d5
Merge pull request #196 from Sea-Haven-Industries/fix/ab/sh-406-no-revoke-auto-approved
fix(uplifts): refuse admin revoke of an auto-approved uplift
2026-09-25 22:15:54 +00:00
Alexandre Brandizzi
77dc3d85c3 Serialize a CRM cancel with uplift creation on the work order lock
The per-work-order gate moves into a shared data-layer helper. A CRM
mutation that cancels an existing work order now runs under it, so a
create in flight either commits first and is cancelled, or sees the
cancelled work order.
2026-09-25 19:15:38 -03:00
Alexandre Brandizzi
cc46950254 test(auth): format the password change request 2026-09-25 19:10:46 -03:00
Alexandre Brandizzi
b7be07411e fix(auth): end earlier sessions when a password or account status changes
Tokens now carry a keyed hash of the account's security stamp, and every
authenticated request compares it with the stored stamp (cached for 60 s,
evicted in-process on change). A password reset or change, a deactivation
and a deletion all rotate or remove the stamp, so tokens issued before them
get 401. Tokens without the claim get 401 too.
2026-09-25 19:08:33 -03:00
Alexandre Brandizzi
306ab159cc Cancel pending uplifts when the legacy ingest cancels a work order
The ingest writes only the status text, so the shared helper gains a
status-text form of the same rule and the ingest stages the same
sync-attributed cancellation in its batch save.
2026-09-25 19:01:37 -03:00
Alexandre Brandizzi
e993e1b5fc refactor(auth): compose bearer authentication through one registration 2026-09-25 18:54:10 -03:00
Alexandre Brandizzi
99499c3281 Cancel pending uplifts when the CRM cancels a work order
The webhook and reconciliation saves now stage the same pending-uplift
cancellation, with its own sync audit row, as the board cancel. The rule
and the write live in one data-layer helper so the paths cannot drift.
2026-09-25 18:48:44 -03:00
Alexandre Brandizzi
9bad363930 fix(work-orders): cancelling from the board cancels the pending uplift
The board and slide-over cancel a work order through the lifecycle status
patch, which set Canceled without touching uplifts, so a pending uplift
stayed in the approval queue. A patch to Canceled now withdraws pending
uplifts in the same save, each with its own uplift_cancel audit entry, and
runs under the per-work-order gate uplift create uses.
2026-09-25 18:37:56 -03:00
Alexandre Brandizzi
ca9322fa60 fix(auth): queue the reset email only after its code is stored 2026-09-25 18:29:33 -03:00
Alexandre Brandizzi
2f23f6fadc test(team-members): register reset email delivery in the invite test host 2026-09-25 18:10:10 -03:00
Alexandre Brandizzi
185c84dd8c fix(uplifts): refuse admin revoke of an auto-approved uplift
An admin revoke overturns a human decision, so admins may revoke only
admin-approved uplifts. The work-order revoke path let an admin revoke an
auto-approved uplift they had requested themselves. Both revoke endpoints
now refuse it; dispatchers keep revoking their own auto-approved uplifts.
2026-09-25 18:07:33 -03:00
Alexandre Brandizzi
35e79a276d Merge branch 'fix/ab/sh-403-reset-code-hardening' into fix/ab/sh-403-reset-hardening-2 2026-09-25 17:54:13 -03:00
Alexandre Brandizzi
c860936d07 test(auth): give the reset test host's helpers names of their own 2026-09-25 17:52:14 -03:00
Alexandre Brandizzi
9198c5cd5d Merge remote-tracking branch 'origin/main' into fix/ab/sh-403-reset-code-hardening 2026-09-25 17:52:04 -03:00
Alexandre Brandizzi
92cd44c481 fix(work-orders): count only live uplifts for Has uplift and the Uplift column
A work order whose uplifts were all cancelled, withdrawn, expired or revoked no
longer matches the advanced-search Has uplift filter, and the board Uplift
column no longer reports it as having an uplift or shows the dead one as its
primary status. One shared live-status list backs both queries. Explicit
cancelled/revoked sub-filter values still find those work orders.
2026-09-25 17:51:47 -03:00
Alexandre Brandizzi
5eb1323419 test(auth): give the reset test host's helpers names of their own 2026-09-25 17:51:26 -03:00
Alexandre Brandizzi
f0dcba63fd fix(auth): give back reset check and request slots when a data call fails or is cancelled 2026-09-25 17:38:51 -03:00
Alexandre Brandizzi
cf32dd2698
Merge pull request #184 from Sea-Haven-Industries/feat/ab/sh-322-overdue-type
Some checks are pending
Backend CI / Build and test (push) Waiting to run
Backend CI / architecture (push) Waiting to run
Backend CI / review (push) Waiting to run
Backend CI / ci-complete (push) Blocked by required conditions
feat(work-orders): add Overdue work order type
2026-09-25 19:52:19 +00:00
Alexandre Brandizzi
c6dcad8395
Merge pull request #189 from Sea-Haven-Industries/feat/ab/sh-385-invite-registration
feat(team-members): invite registration with emailed code confirmation (SH-385)
2026-09-25 19:52:15 +00:00
Alexandre Brandizzi
1277642ede Merge branch 'fix/ab/sh-403-reset-code-hardening' into fix/ab/sh-403-reset-hardening-2
# Conflicts:
#	SeaHaven.Services/Implementation/AuthenticationService.cs
2026-09-25 16:48:57 -03:00
Alexandre Brandizzi
900e141bda fix(auth): delete only the checked code and older ones, so a code issued concurrently survives 2026-09-25 16:42:03 -03:00
Alexandre Brandizzi
9084b7f642 fix(team-members): answer invalid_invite when send-code finds the invite closed
SendCodeAsync validates the invite, then starts the code with a conditional
update that also requires the invite to still be open. When an admin revoked
the link (or it was used) between those two reads, the refusal was reported as
resend_too_soon with a Retry-After, although the link was already dead.

On a refused start the invite is now read again: a closed invite gets the same
generic invalid_invite response as any other dead link, and a cooldown or send
limit refusal is computed from the fresh row.
2026-09-25 16:40:54 -03:00
Alexandre Brandizzi
fc3a29f399 Merge remote-tracking branch 'origin/main' into HEAD
# Conflicts:
#	SeaHaven.Services/Implementation/WorkOrderCompletionService.cs
2026-09-25 16:40:36 -03:00
Alexandre Brandizzi
fe5f27c8e1 test(auth): build the password-policy service with the reset queue, throttle and keyed hash 2026-09-25 14:08:30 -03:00
Alexandre Brandizzi
613bfa48d8 Merge branch 'fix/ab/sh-403-reset-code-hardening' into fix/ab/sh-403-reset-hardening-2 2026-09-25 14:04:17 -03:00
Alexandre Brandizzi
ea1370847f test(auth): move the password-policy reset case onto hashed, attempt-counted codes 2026-09-25 13:46:37 -03:00
Alexandre Brandizzi
9bd22e9a74 Merge remote-tracking branch 'origin/main' into fix/ab/sh-403-reset-code-hardening 2026-09-25 13:44:34 -03:00
Alexandre Brandizzi
47060f6a73 fix(work-orders): never return a severity on an Overdue board row
A standalone severity patch on an Overdue WO still stores the value,
because the board patches severity before type when correcting Overdue
to Emergency/Reactive and that write must not be dropped or rejected.
Project the severity as null for Overdue in the board row mapping, which
also feeds the PATCH response, search results and the detail view, so a
stored value never surfaces on a type that carries no severity.
2026-09-25 13:41:19 -03:00
Alexandre Brandizzi
bb41bfd8ed Merge remote-tracking branch 'origin/main' into HEAD 2026-09-25 13:40:06 -03:00
Alexandre Brandizzi
57af8a1206 fix(auth): store an unmatchable code when the reset email cannot be queued, keeping data calls identical 2026-09-25 13:38:11 -03:00
Alexandre Brandizzi
77e54e64e3
Merge pull request #194 from Sea-Haven-Industries/feat/ab/sh-389-rejected-uplift-queue
Some checks are pending
Backend CI / Build and test (push) Waiting to run
Backend CI / architecture (push) Waiting to run
Backend CI / review (push) Waiting to run
Backend CI / ci-complete (push) Blocked by required conditions
feat(uplifts): order the rejected queue by decision time (SH-389)
2026-09-25 16:29:12 +00:00
Alexandre Brandizzi
a8d05776a8
Merge pull request #186 from Sea-Haven-Industries/feat/ab/sh-386-password-policy
feat(auth): enforce one password policy on every password-setting path
2026-09-25 16:27:36 +00:00
Alexandre Brandizzi
5353899418 feat(uplifts): order the rejected queue by decision time and include legacy denied rows 2026-09-25 13:18:06 -03:00
Alexandre Brandizzi
cc328ce22a fix(team-members): do not report an invite email for a deactivated member 2026-09-25 13:13:50 -03:00
Alexandre Brandizzi
a6dd40b972 fix(auth): only count real guesses, drop codes that cannot be emailed, trace reset email sends 2026-09-25 13:12:49 -03:00
Alexandre Brandizzi
afc2330184 fix(team-members): report only password-rule failures at finish as a rejected password 2026-09-25 13:05:35 -03:00