# Waldur Project acquisition This owner adaptor implements `ExternalProjectSource` for one explicitly enrolled Waldur installation and customer. It supplies complete acquisition evidence to Project's application workflow. Provider account references remain opaque bindings; Project and Party identities are assigned by their canonical owners. REST uses verified HTTPS with an explicit provider CA, a separate customer-scoped read token, bounded responses and no redirects. Each collection requires an unchanged `X-Result-Count`, complete `Link` pagination and the same origin, resource and query filters. Repeated permission identities, missing pages, malformed state, foreign customers, removed Projects, ambiguous 404s and permission failures leave the prior owner state unchanged. Membership and Project metadata are read twice. This detects changes during acquisition; Waldur 8.1.3 supplies no atomic read revision, so this does not establish a transactional provider snapshot. `PROJECT.MANAGER` maps to `project-administrator`; `PROJECT.MEMBER` maps to `developer`. Other native roles remain unsupported evidence and confer no additional access. Member and role bounds are applied after grouping. An oversized collection fails completely. Successful unchanged content retains its fingerprint but receives a fresh acquisition ID and completion time. Inventory reads feed the application's periodic reconciliation; disappearance never closes a Project in this iteration. STOMP 1.2 uses verified TLS on port 61614 and the existing registered consumer queue. Native role notices contain a Project UUID without its customer. `ScopeOf` reads that Project's metadata over the same verified REST transport, checks its UUID and returns its actual customer. A successful read identifying a foreign customer commits an `ignored` receipt with that customer's scope. The chart's non-staff `pharos-project-reader` has `CUSTOMER_READER` access only to the enrolled customer, so foreign Projects are expected to return HTTP 404. HTTP 404 commits an `unavailable` receipt with `source_not_found`; HTTP 403 uses `source_access_denied`. Both leave `scope_ref` unset and commit before ACK, so missing or inaccessible Projects allow following notices to progress. HTTP 401/429/5xx, transport failures and malformed scope responses remain retryable. Receipt replay precedes provider I/O. Scope qualification supplies no membership or lifecycle authority. In-scope notices request a fresh complete REST acquisition. Their broker delivery IDs remain distinct from body fingerprints, including grant/revoke/ regrant sequences with equal grant bodies. RabbitMQ's STOMP `message-id` changes on reconnect. Waldur 8.1.3's `x-message-id` is a content hash, so neither supplies a stable, distinct native occurrence identity. Receipts therefore identify each transport delivery; redelivery can schedule an additional complete acquisition. See the [Waldur publisher](https://github.com/waldur/waldur-mastermind/blob/8.1.3/src/waldur_core/logging/utils.py#L240) and [RabbitMQ STOMP properties](https://www.rabbitmq.com/docs/4.1/stomp). Canonical state still comes from the complete read. `client-individual` acknowledgement follows the durable accepted/ignored/unavailable receipt and any refresh intent. Invalid Project notices require durable quarantine first. Persistence or connection failure leaves delivery unacknowledged. Frames, headers, bodies and handshake deadlines are bounded; cancellation closes the connection and reconnect attempts use bounded backoff. The Beto composition owns worker startup, periodic reconciliation and drain. The committed development overlay sets `PROJECT_WALDUR_ENABLED=true`, so a Project made in Waldur reaches Source Control and its GitLab group. Activation requires the exact installation, customer, management generation, read credential, source broker binding, provider CA and Party binding scope. The runtime identity is `app: beto` in namespace `pharos`, with the separate `beto-project-source` secret. Metallo receives no Project acquisition worker, database, credentials or direct Waldur Project/member access. ## Source and qualification The provider behaviour and infrastructure are adapted from [`39e5221cd`](https://github.com/pharos-ai-factory/pharos-platform/tree/39e5221cd8cbb086da3dde89cd33662fbda78fd5): `3636595ff` introduced the qualified Waldur 8.1.3 REST/STOMP boundary; `c0a34596b`, `064e674bd`, `a7bdc0b47`, `2626868fd` and `0845b5c44` corrected container selection, restored TLS trust, management routing, native publication and configuration rollouts. The [chart notes](../../../../../../gitops/manifests/waldur/patches/README.md) retain the release/patch attribution and rollback archive. The Go tests preserve the source's complete/empty/partial pagination, repeated permission, changing read, foreign scope, unknown role, distinct delivery and bounded STOMP cases. They add canonical role mapping, fresh acquisition evidence, duplicate JSON rejection, real verified TLS, cancellation, wrong subscriptions and acknowledgement after durable intake or quarantine. Infrastructure tests preserve restricted registration, existing credential reuse, lost/restored TLS authority, exact management port, same-Pod HTTPS, native role publication and all-process configuration rollout checks. Additional negative fixtures forbid Project credentials and source broker access in Metallo. ```sh PHAROS_GO_PROJECT=services/beto python3 scripts/go.py test -race ./contexts/project/adaptors/waldur python3 -m unittest discover -s scripts -p test_project_acquisition_deployment.py python3 -m unittest discover -s scripts -p test_register_waldur_project_consumer.py python3 -m unittest discover -s dx/common/tests -p test_provider_tls.py python3 -m unittest discover -s dx/common/tests -p test_project_source_runtime.py python3 scripts/smoke_waldur_provider_tls.py python3 scripts/project_source_integration.py ``` The source integration lane creates an isolated RabbitMQ 4.1.4 container and ephemeral TLS authority. It uses Waldur's native STOMP publishing headers, checks exact queue permissions and certificate rejection, then injects receipt and quarantine failures to verify redelivery. Its sink is an in-memory failure fixture; Project's PostgreSQL lane separately qualifies durable intake and recording. It also preserves distinct grant/revoke/regrant deliveries when the two grant bodies have equal native content hashes. Live Alice/Bob login, native manager/member grant, revoke and regrant, permission loss, source outage, fresh inventory recovery and independent subscriber delivery remain deployment qualification scenarios. The source branch's live evidence does not qualify this Go replacement. No shared environment was deployed while implementing these adaptors. Retained Themelio login/AUP and Waldur SSO must pass against the selected release before enabling acquisition. ## Project invitation read `InvitationReader` calls the existing Waldur provider actor's private `/internal/compat/v1/waldur/invitations/project` route over verified HTTPS. Beto receives a distinct `WALDUR_PROJECT_INVITATION_READ_KEY`; the staff token and recipient acceptance capability stay in the compatibility integration. The Project source must be enabled and the actor URL, trust and key enrolled. An unenrolled read returns unavailable. Composition closes idle connections after workers drain. The actor validates Project UUID/customer before and after acquisition. Waldur's Project filters on user invitations are unreliable, so it reads all pending pages with stable `X-Result-Count`, same-origin/same-filter links, cycle and size bounds, then selects exact Project scope. Matching rows require actual expiry, recipient email and supported native role (`PROJECT.MANAGER` or `PROJECT.MEMBER`). Expired and nonpending rows are excluded. Duplicate IDs, missing pages, changing counts, malformed fields and more than 256 resulting invitations fail the read. The actor derives a stable SHA-256 reference from the instance, Project and provider invitation ID. The browser never receives the provider ID used by native acceptance URLs. The private response echoes instance/Project/customer and explicit completeness; Beto validates that envelope before returning any data. The API-auth credential reconciler adds this capability without rotating existing values. It projects the key only to Beto and the Waldur actor, and adds a Beto to actor HTTPS network rule. Apply credential reconciliation and the actor release before Beto/API, then enable frontend use. Fixture verification does not qualify the installed provider or its live pagination; record the deployed revision when running the live Project administrator journey.