cadrumo.application.auth.acquisition_lock module

Crash-recoverable auth acquisition locks.

The lock protects live auth flows that can create external state, especially Cl@ve Movil push petitions. It is intentionally filesystem-backed so separate CLI processes share the same guard. The lock file stores an AuthAcquisitionLockRecord and reports operator-safe state through AuthAcquisitionLockStatus.

Removal goes through unlink_lockfile(): every peer that finds the lock taken opens the file to read the record, and on Windows that open refuses the owner’s delete. An abandoned delete would leave a record naming a live process, blocking acquisition until the record’s TTL expires, so the removal retries. It never raises – the release runs in a finally where a raise would mask the auth flow’s own outcome, and the TTL is the backstop.

class AuthAcquisitionLockState(*values)[source]

Bases: StrEnum

Observable states for the auth acquisition lock file.

ABSENT
HELD
STALE
CORRUPT
class AuthAcquisitionLockRecord(**data)[source]

Bases: BaseModel

Metadata written into an auth acquisition lock file.

Parameters:

data (Any)

provider_kind: AuthProviderKind
profile_name: str
pid: int
hostname: str
created_at: datetime
expires_at: datetime
operation: str
class AuthAcquisitionLockStatus(**data)[source]

Bases: BaseModel

Safe health/status view of an auth acquisition lock.

Parameters:

data (Any)

state: AuthAcquisitionLockState
path: Path
record: AuthAcquisitionLockRecord | None
reason: str | None
recoverable: bool
property locked: bool

Return True when another live process should block auth acquisition.

exception AuthAcquisitionLockedError(*, status, translated_message)[source]

Bases: CadrumoError

Raised when another process is already acquiring AEAT auth.

Parameters:
Return type:

None

property terminal_precondition_verdict: PreconditionVerdict

Expose the application-owned lock conflict to the generic CLI boundary.

code
auth_acquisition_lock_path(settings, kind, *, bucket_id=None)[source]

Return the profile/provider-scoped lock path.

Return type:

Path

Parameters:
inspect_auth_acquisition_lock(settings, kind, *, now=None, bucket_id=None)[source]

Describe the current acquisition-lock health without mutating it.

Returns an AuthAcquisitionLockStatus.

Return type:

AuthAcquisitionLockStatus

Parameters:
clear_auth_acquisition_lock(settings, kind, *, reason='operator-reset', bucket_id=None, allow_held=False)[source]

Remove the acquisition lock and return the pre-reset status.

Returns an AuthAcquisitionLockStatus reflecting the state observed immediately before the file was removed.

A HELD lock refuses unless the caller passes allow_held. This function used to delete on any state but ABSENT, so a live holder’s record was removed under the reason stale_reclaim and the next acquisition succeeded while the first holder was still authenticating – two processes each believing they held the lock, which is a second petition to AEAT and a second prompt on the taxpayer’s phone. The compare-and-delete below does not catch it: it guards against the bytes CHANGING, and a live holder’s bytes are unchanged.

Only a caller that is destroying the profile wholesale may pass allow_held: there the lock is going with everything else, and refusing would strand the erase. A caller whose profile SURVIVES – an auth reset, or login --reset-lock – must not, because nothing there compensates for the aborted acquisition and the duplicate petition follows immediately.

Return type:

AuthAcquisitionLockStatus

Parameters:
acquire_auth_acquisition_lock(settings, kind, *, ttl_seconds, operation='auth-login')[source]

Acquire a crash-recoverable auth lock or raise a typed conflict.

Yields an AuthAcquisitionLockRecord while the lock is held.

Stale/corrupt locks are removed automatically before a second atomic-create attempt. A live lock is never waited on or retried: callers fail early so they do not issue a duplicate Cl@ve petition.

Return type:

Generator[AuthAcquisitionLockRecord]

Parameters:
auth_lock_ttl_seconds(settings, kind)[source]

Return the acquisition-lock TTL for a provider.

Return type:

int

Parameters: