Skip to main content

LeaseDto

Namespace: Meshmakers.Octo.Communication.Contracts.DataTransferObjects

One lease of an adapter pool member to a borrowing tenant (AB#4924, concept ยง4).

public record LeaseDto : IEquatable<LeaseDto>

Inheritance Object โ†’ LeaseDto
Implements IEquatable<LeaseDto>

Remarks:

A lease binds a pool member โ€” a process that belongs to no tenant โ€” to exactly one borrowing tenant for the duration of one work item. The member loads that tenant, executes, reports the outcome through IAdapterPoolHub.ReleaseLeaseAsync and drops every tenant-scoped thing it built. The isolation invariant is a property of time: the process serves exactly one tenant at any instant.

๐Ÿ”ด This object carries a client secret. Concept ยง8 Q6 decided the borrower identity: the lease carries the borrower's ownPipelineServiceAccount credential (AB#5027), so the member logs in and acts exactly as the borrower's own adapter would. No standing grant is created in any borrower tenant and the whole AB#5027 identity chain is reused unchanged. RFC 8693 token exchange does not cover this case โ€” it rejects a subject token without sub/tenant_id, which is precisely the shape of a client-credentials token, and it mints an xt_ shadow user, which is not what a service identity wants.

Two consequences the implementation must honour and which are pinned by tests on both sides: LeaseDto.ClientSecret is TTL-scoped and never persisted by the member, and it must never reach a log target. LeaseDto.ToString() is overridden here for that reason โ€” a record's generated ToString prints every property, and structured logging a LeaseDto would otherwise put the secret in the log the first time somebody adds a diagnostic line.

๐Ÿ”ด Since AB#4924 a SECOND secret travels here: . The lease is what gives a pool member access to the borrower's data, not only to its identity. The operator deliberately withholds the cluster's shared data-store credentials from an adapter pool (WorkloadReconciler.AppendClusterSecrets), on the stated ground that "tenant-scoped data access arrives with the lease and leaves with it" โ€” a sentence that only became true when LeaseDto.DatabaseName, LeaseDto.DatabaseUser and LeaseDto.DatabasePassword existed. Every rule written above for LeaseDto.ClientSecret applies to LeaseDto.DatabasePassword unchanged, and the assertions on both sides name it explicitly rather than trusting the older one to cover it: a test that would still pass if only LeaseDto.ClientSecret were redacted proves nothing about the second secret.

๐Ÿ”ด Since AB#4924 ยง9.9 / D4 the same rule covers the work the lease carries.LeaseDto.PipelineInput is the borrowing tenant's payload, and LeaseDto.Pipeline carries that pipeline's resolved configuration entries, which since AB#5027 include a service-account credential of their own. Neither is rendered: LeaseDto.ToString() names identifiers only, and the assertions on both sides now cover the enlarged object rather than only LeaseDto.ClientSecret.

Propertiesโ€‹

LeaseIdโ€‹

Identifier of this lease. Echoed back on ReleaseLeaseAsync so a release that arrives after the controller already expired the lease can be recognised as stale rather than released against whatever lease the member holds now.

public string LeaseId { get; set; }

Property Valueโ€‹

String

TenantIdโ€‹

The borrowing tenant. This is the tenant the member acts for while the lease is held: the tenant repository it loads, the CK model it caches, and the tenant_id of the token it presents.

public string TenantId { get; set; }

Property Valueโ€‹

String

PoolTenantIdโ€‹

The lending tenant โ€” the owner of the AdapterPool the member belongs to. Recorded on the borrower's execution as LeasedFromTenantId.

public string PoolTenantId { get; set; }

Property Valueโ€‹

String

PoolRtIdโ€‹

RtId of the AdapterPool in LeaseDto.PoolTenantId. Bare 24-character hex.

public string PoolRtId { get; set; }

Property Valueโ€‹

String

AdapterRtIdโ€‹

RtId of the borrowing tenant's Adapter entity (the one whose LifecycleMode is Leased). The member registers under this identity for the duration of the lease, so the pipelines it loads and the executions it reports are the ones that adapter owns.

public string AdapterRtId { get; set; }

Property Valueโ€‹

String

AdapterCkTypeIdโ€‹

CkTypeId of the borrowing tenant's Adapter entity. Adapter is polymorphic, so the bare RtId is not enough to build an RtEntityId.

public string AdapterCkTypeId { get; set; }

Property Valueโ€‹

String

ExecutionIdโ€‹

The pipeline execution this lease was granted for, when the lease is tied to one. Empty while leasing is driven by hand (increment 6); the scheduler (increment 7) always sets it.

public string ExecutionId { get; set; }

Property Valueโ€‹

String

Remarks:

๐Ÿ”ด This id names an execution entity that already exists. The controller created it Queued at enqueue and moved it to Running when it claimed it for this lease. The member executes against it and must never report an execution start for it: the start-report path (PipelineExecutionService.StartExecutionAsync) inserts a new entity with a new RtId and never looks an existing one up by ExecutionId, so a member that reported a start would produce a second entity for one piece of work โ€” two billing spans (concept ยง4b) and a queue history that no longer joins up (AB#4924 ยง9.9 / D4).

PipelineRtIdโ€‹

RtId of the pipeline the member is to run, bare 24-character hex. Empty when the lease carries no work โ€” a hand-driven lease (increment 6) still exists and is still valid.

public string PipelineRtId { get; set; }

Property Valueโ€‹

String

Remarks:

AB#4924 ยง9.9 / D4: increment 7 queued, rotated, granted and reaped correctly, and a member that received a lease still had nothing to run. The lease names the work explicitly rather than the member inferring it โ€” the scheduler decided which queued item this lease serves, and a member re-deriving that from the tenant's queue could pick a different one.

PipelineInputโ€‹

The pipeline input of the queued work item โ€” RtPipelineExecution.InputData, verbatim. Null when the trigger supplied none.

public string PipelineInput { get; set; }

Property Valueโ€‹

String

Remarks:

๐Ÿ”ด Never rendered by LeaseDto.ToString(). It is caller-supplied payload of the borrowing tenant and has no business in a log line of a process that serves another tenant a second later.

Pipelineโ€‹

What the member needs in order to run that pipeline: the same PipelineConfigurationDto element a dedicated adapter receives in its AdapterConfigurationDto.Pipelines โ€” the node definition plus the pipeline's resolved configuration entries. Null when the lease carries no work.

public PipelineConfigurationDto Pipeline { get; set; }

Property Valueโ€‹

PipelineConfigurationDto

Remarks:

๐Ÿ”ด The lease carries it because only the controller can produce it. The projection (AdapterService.CreatePipelineConfigurationAsync) injects the adapter's default pipeline service account, projects the tenant's Signal channel and resolves the deploy-time {{service.authority}} token. A member rebuilding that from the borrower's entities would be a second implementation of a projection that already exists, free to drift from it silently.

Size. This travels controller โ†’ member, which is a SignalR server-to-client send; HubOptions.MaximumReceiveMessageSize governs what the server receives, and the controller raises it to 100 MiB anyway (Program.cs). The identical shape already ships in production: IAdapterHubCallbacks.AdapterConfigurationUpdatedAsync pushes a whole AdapterConfigurationDto โ€” every deployed pipeline of an adapter โ€” down the same kind of channel. One pipeline is strictly less than that.

๐Ÿ”ด Like LeaseDto.ClientSecret, the configuration entries can carry credential material โ€” AB#5027 puts the pipeline service account in exactly here โ€” so this property is not rendered by LeaseDto.ToString() either.

ClientIdโ€‹

Client id of the borrower's PipelineServiceAccount (AB#5027).

public string ClientId { get; set; }

Property Valueโ€‹

String

ClientSecretโ€‹

๐Ÿ”ด Client secret of the borrower's PipelineServiceAccount, in plaintext. Lease-scoped: the member uses it to obtain a token with acr_values=tenant:{TenantId} and must drop it โ€” and the token โ€” on release. It must never be written to disk, to configuration, or to a log.

public string ClientSecret { get; set; }

Property Valueโ€‹

String

DatabaseNameโ€‹

Name of the borrowing tenant's database โ€” the scope the credential below is valid for, and nothing else.

public string DatabaseName { get; set; }

Property Valueโ€‹

String

Remarks:

๐Ÿ”ด Not a credential, and not decoration. A pool member has to know which database LeaseDto.DatabaseUser may be presented to, because it also opens databases that are not the borrower's โ€” the installation's tenant registry above all. Presenting the borrower's datasource user there would fail, and presenting a shared one to the borrower's database is exactly what this whole mechanism removes. So the credential is installed for one named database and is invisible everywhere else.

It comes from the controller rather than from the member for one reason: resolving tenant โ†’ database means reading the tenant registry, and on a pool member that read is itself gated by a credential the member does not have until the lease installs one. The controller is the only party that can break that circle.

DatabaseUserโ€‹

The MongoDB user of the borrowing tenant's database, resolved by the controller.

public string DatabaseUser { get; set; }

Property Valueโ€‹

String

Remarks:

๐Ÿ”ด Resolved, never derived here. The installation names its per-tenant datasource users by a format over the database name (octo-system-ds-user-{0}), and the temptation is to send only the password and let the member format the name. That would put a second copy of the naming rule in a process that must not be able to name any database but the one it was lent โ€” one edit away from a member that constructs a user for a neighbour tenant and finds the shared password still fits. The user and the password are therefore two independent fields, both filled by the controller.

DatabasePasswordโ€‹

๐Ÿ”ด Password of LeaseDto.DatabaseUser, in plaintext. Same rules as LeaseDto.ClientSecret: lease-scoped, never persisted, never logged, and deliberately not rendered by LeaseDto.ToString().

public string DatabasePassword { get; set; }

Property Valueโ€‹

String

Remarks:

Today this value is installation-wide โ€” one password behind every per-database user โ€” and the controller's resolver says so at the line that reads it. That is a property of where the password comes from, not of this contract: AB#5255 gives each database its own password and changes only that resolver. Nothing on this wire and nothing on the member may assume the two are the same value, or the follow-up becomes a second migration instead of a one-line change.

GrantedAtUtcโ€‹

When the controller granted the lease (UTC). Together with the release it is the span the member was held for this borrower โ€” the billing input of concept ยง4b.

public DateTime GrantedAtUtc { get; set; }

Property Valueโ€‹

DateTime

ExpiresAtUtcโ€‹

When the lease expires (UTC). After this instant the controller may re-queue the work and drain the member, because its post-lease cleanliness is unproven (concept ยง6).

public DateTime ExpiresAtUtc { get; set; }

Property Valueโ€‹

DateTime

Constructorsโ€‹

LeaseDto()โ€‹

public LeaseDto()

Methodsโ€‹

ToString()โ€‹

๐Ÿ”ด Deliberately prints neither LeaseDto.ClientSecret nor LeaseDto.DatabasePassword. See the remarks on the type.

public string ToString()

Returnsโ€‹

String

Remarks:

The two identities are printed โ€” LeaseDto.ClientId and the database this lease opens, as which user โ€” because that is what makes a lease log line diagnosable at all. Their secrets are not.