Commit 7ff30a31 authored by Dimitrios Gogos's avatar Dimitrios Gogos
Browse files

docs: update decision records and implementation guides with recent amendments and clarifications

parent d9a97818
Loading
Loading
Loading
Loading
+1 −1
Changes for decisions/0051-oeg-fronts-federation-lifecycle-ewbi-byte-for-byte.md: 1 added line, 1 removed line.
Original line number Diff line number Diff line
@@ -10,7 +10,7 @@ status: "accepted"
# ADR-0051: OEG fronts eight GSMA federation-lifecycle operations on its own platform namespace, scoped by partner id, forwarding the raw payload byte-for-byte to FM (operator-triggered outbound only)

**Status:** accepted — amended 2026-09-15 after FM-side review of the first version, and 2026-09-24 to add partner registration to the OEG proxy (see "Partner registration and our identity"), 2026-10-13 to add the identity read, and 2026-10-15 to add agreements and our zone list (see "Agreements and our zones"), and 2026-10-16 so a partner's one agreement is edited in place (the `PATCH` row there). Originally drafted as ADR-0048 (and its error-model companion as ADR-0047); renumbered to 0051/0050 at 2026-09-16 to clear the collision with `develop`'s ADR-0047 (terminal-record-read) and `docs/platform-roles`'s ADR-0048 (platform-roles) — content unchanged by the renumbering.
**Date:** 2026-09-08 (amended 2026-09-15, 2026-09-24, 2026-10-13, 2026-10-15)
**Date:** 2026-09-08 (amended 2026-09-15, 2026-09-24, 2026-10-13, 2026-10-15, 2026-10-16)
**Affects:** [oeg/architecture.md](/oeg/architecture.md), [oeg/interface-contract.md](/oeg/interface-contract.md), [fm/requirements-and-design.md](/fm/requirements-and-design.md), [fm/implementation-and-delivery.md](/fm/implementation-and-delivery.md), [fm/overview-and-architecture.md](/fm/overview-and-architecture.md), [platform/architecture.md](/platform/architecture.md), amends this ADR's own first version, restores the namespace part of [ADR-0046](/decisions/0046-oeg-fronts-federation-lifecycle-ewbi-as-sync-proxy.md) it had superseded, builds on [ADR-0050](/decisions/0050-oeg-federation-lifecycle-proxy-errors-are-gsma-problem-json.md), [ADR-0042](/decisions/0042-ewbi-oauth2-client-credentials-mtls-deferred.md)

## Context
+3 −2
Changes for decisions/0053-srm-fm-federated-lifecycle-handoff-over-the-databus.md: 3 added lines, 2 removed lines.
Original line number Diff line number Diff line
@@ -9,7 +9,7 @@ status: "proposed"

# ADR-0053: SRM hands federated deploys and terminates to FM over the DataBus, and FM reports the outcome the same way

**Status:** proposed (amended 2026-09-25: SRM keeps instance rows for partner targets, superseded on 2026-10-08; 2026-09-29: `partner_not_found`; 2026-10-08: order-local `federated_handoff` instead of partner inventory)
**Status:** proposed (amended 2026-09-25: SRM keeps instance rows for partner targets, superseded on 2026-10-08; 2026-09-29: `partner_not_found`; 2026-10-08: order-local `federated_handoff` instead of partner inventory; 2026-10-15: SRM reads FM's instance before a federated terminate)
**Date:** 2026-09-22
**Affects:** [fm/overview-and-architecture.md](/fm/overview-and-architecture.md) (open item G4, UC-FM-07), [fm/requirements-and-design.md](/fm/requirements-and-design.md) (the SRM→FM hand-off section §L.3a, FM's DataBus sections §K.2 and §M), [srm/interface-contract.md](/srm/interface-contract.md) (stream configuration §D, the federated hand-off flow §F.4a), [srm/persistence-model.md](/srm/persistence-model.md) (`service_order.federated_handoff`), [platform/architecture.md](/platform/architecture.md) (DataBus configuration)
**Amends:** ADR-0001 and ADR-0022, where they make SRM the only consumer of `OOP_TASKS`; ADR-0046, where it keeps the DataBus to `command.srm.*` / `event.srm.*`
@@ -126,7 +126,8 @@ its own `federation_transactions` records.
**2026-10-15 amendment:** before accepting a terminate for an instance absent locally, SRM
reads `GET /internal/federated-service-instances/{service_instance_id}` to retain its `zone_id`
in the order-local hand-off. This lets the terminal SRM event satisfy §C.2 without a partner
`service_instance` row. If FM doesn't know the instance, SRM fails before starting. The order's
`service_instance` row. If FM doesn't know the instance, SRM fails before starting; if FM can't be reached, the command
is redelivered, not failed. The order's
`target_service_instance_id` stays null because that column references local inventory. The
request to FM remains the original command; SRM does not select an EWBI target or store partner
inventory.
+3 −2
Changes for fm/implementation-and-delivery.md: 3 added lines, 2 removed lines.
Original line number Diff line number Diff line
@@ -70,13 +70,14 @@ Settings are environment variables with the `FM_` prefix (`core/config.py`; a `.
| `FM_SRM_INTERNAL_URL` | `http://localhost:8081` | SRM internal HTTP base URL |
| `FM_KEYCLOAK_ISSUER` | `http://localhost:8090/realms/federation` | Issuer partners' tokens must carry |
| `FM_KEYCLOAK_JWKS_URL` | unset | Where FM fetches the signing keys when it can't reach the issuer URL; unset means the issuer's JWKS |
| `FM_KEYCLOAK_AUDIENCE` | `federation-manager` | Audience partner tokens must carry in `aud` |
| `FM_KEYCLOAK_AUDIENCE` | `federation-manager` | Audience partner tokens must carry in `aud`. Not built yet |
| `FM_FEDERATION_ID`, `FM_COUNTRY_CODE`, `FM_MCC`, `FM_MNCS` | `oop-local`, `ES`, `214`, `07` | Our OPG.04 identity, sent on `CreateFederation` and served on `GET /internal/identity` |
| `FM_PLATFORM_CAPS` | `serviceAPIs` | Platform capabilities we advertise |
| `FM_PARTNER_STATUS_LINK` | `http://127.0.0.1:8082/operatorplatform/federation/v1/callbacks/partner-status` | Callback URL handed to partners; a deployment sets the URL partners can reach |
| `FM_INSTANCE_STATUS_LINK` | `http://127.0.0.1:8082/operatorplatform/federation/v1/callbacks/instance-status` | Same, for `onInstanceStatusEvent` after our `InstallApp` |
| `FM_AVAIL_ZONE_NOTIF_LINK` | unset | `availZoneNotifLink` for zone notifications |
| `FM_ALLOW_INSECURE_PARTNER_ENDPOINTS` | `false` | Allow plain-HTTP partner endpoints; development only |
| `FM_ZONE_OFFER_SWEEP_SECONDS` | `600` | How often every federated partner's zone offer is re-checked, besides each agreement write and each `valid_from`/`valid_until` (REQ-FED-04). Not built yet |
| `FM_BOOTSTRAP_FEDERATION` | `false` | At startup, federate with every active partner that has no outbound context (ADR-0043) |
| `FM_PARTNER_SECRET_KEY` | unset | Key (base64url, 32 bytes) that encrypts typed-in partner secrets; unset, FM accepts only secret files (ADR-0067) |

@@ -116,7 +117,7 @@ database (`adapters/database/`) and DataBus (`adapters/databus/`) modules.

FM authorizes E/WBI requests with OAuth2 Client-Credentials + signed JWT. Our Keycloak `federation` realm issues tokens for inbound partner calls; each partner's Authorization Server issues tokens for calls from our FM to that partner. FastAPI dependencies validate inbound Bearer tokens; `httpx` fetches and caches outbound tokens.

**Inbound:** a FastAPI dependency (`api/security.py`) reads the `Authorization: Bearer` header and `PartnerAuthenticator` validates the JWT signature against Keycloak's JWKS endpoint (cached, refreshed on `kid` miss), and checks issuer, expiry, audience (`FM_KEYCLOAK_AUDIENCE`) and the `fed-mgmt` scope. The validated token's client identity resolves to a partner via `partner_ops`.
**Inbound:** a FastAPI dependency (`api/security.py`) reads the `Authorization: Bearer` header and `PartnerAuthenticator` validates the JWT signature against Keycloak's JWKS endpoint (cached, refreshed on `kid` miss), and checks issuer, expiry, audience (`FM_KEYCLOAK_AUDIENCE`, not built yet) and the `fed-mgmt` scope. The validated token's client identity resolves to a partner via `partner_ops`.

**Outbound:** Callers depend only on `PartnerTokenProviderPort`. The current adapter reads the partner secret from the mounted file named by `our_client_secret_ref` or, when the operator typed the secret in through the registry, decrypts it from `partner_op_secrets` (ADR-0067); it then requests a token from `token_endpoint`, caches it until near expiry, and the EWBI client attaches it as a Bearer header:

+3 −2
Changes for fm/overview-and-architecture.md: 3 added lines, 2 removed lines.
Original line number Diff line number Diff line
@@ -403,12 +403,12 @@ sequenceDiagram

An operator onboards, updates, or decommissions a federation partner.

- **Actor:** Operator, via OEG's synchronous proxy on `/platform/v1/federation/partners/...` (§N.7, §L.3b; ADR-0051) — partner registration plus the eight federation-lifecycle operations. Agreements and routing rules stay on FM's own internal admin API (L.2).
- **Actor:** Operator, via OEG's synchronous proxy on `/platform/v1/federation/partners/...` (§N.7, §L.3b; ADR-0051) — partner registration, agreements, and the eight federation-lifecycle operations. Routing rules stay on FM's own internal admin API (L.2).
- **Trigger:** New bilateral agreement signed, OAuth2 credential rotation, endpoint change, or partner decommission — or FM's own bootstrap configuration at startup (ADR-0043).
- **Main flow:**
  1. **Register the partner.** The operator calls `POST /platform/v1/federation/partners`; OEG forwards the L.2 partner body byte-for-byte to `POST /internal/partners`. Profile fields: name, MCC-MNC, the partner's EWBI base URL, the client ID we issued the partner, and for outbound calls our client ID at the partner, its secret (a mounted-file reference, or the value itself, stored encrypted; ADR-0067) and the partner's token endpoint.
  2. FM stores the profile in `partner_ops`; the id it assigns is the `partnerOpId`.
  3. Agreements and routing rules are not proxied: they stay on L.2 (not built in FM yet) and are not needed to establish a federation.
  3. **Grant zones.** The operator records the partner's one agreement with `POST /platform/v1/federation/agreements`, picking zones from `GET /platform/v1/federation/local-zones`, and changes it later with `PATCH .../agreements/{agreementId}`; OEG forwards both to L.2. It can come before or after the federation: FM tells an already federated partner when its zones change (REQ-FED-04). Routing rules are not proxied and not built yet.
  4. **Establish the federation.** The operator calls `POST /platform/v1/federation/partners/{partnerOpId}/federations` with the raw GSMA `FederationRequestData`, its identity fields read from `GET /platform/v1/federation/identity` (§L.3b); OEG forwards it byte-for-byte to FM, which runs the outbound OPG.04 `CreateFederation` with the partner, stores the partner-issued `federationContextId`, and returns `FederationResponseData` on the same call. FM's bootstrap configuration (ADR-0043) runs this step itself at startup for every active registered partner without an outbound federation; it does not register partners. Zone subscription follows the same way (`.../zones`).
  5. **Later changes** go through OEG too: `PATCH /platform/v1/federation/partners/{partnerOpId}` for credential rotation, endpoint changes, or retiring the partner (`status` → `suspended`/`decommissioned`; there is no delete), and `DELETE .../federations/{federationContextId}` to end a federation.

@@ -599,3 +599,4 @@ goes through OEG at all — see G4.
| 2.0 | 2026-10-13 | G4: the 30-minute deploy-callback wait is marked not built yet (ADR-0053). |
| 2.0 | 2026-10-13 | UC-FM-01, -03, -06 and -07 rewritten, text and diagrams, to match FM `develop`: `InstallApp` answers `202` and reports through `onInstanceStatusEvent`; the zones we offer are computed on request and partner zones come from `CreateFederation` and operator subscriptions; partner registration and federation go through OEG; the SRM hand-off runs over the DataBus with onboarding before `InstallApp`. Capacity check, rate limit and catalogue re-sync are marked not built yet. UC-FM-02, -04 and -05 (federated Device Location, Device Status and network capabilities such as QoS) are marked proposed, to be discussed in the next releases. |
| 2.0 | 2026-10-13 | Mental model, diagram, A.1, scope and assumptions match FM `develop`: the SRM hand-off goes over the DataBus; FM consumes only `event.srm.operation.completed`; the zones we offer are computed on request; no `oop-commons` dependency. Periodic partner health checks, `operation.status` consumption and the agreement/routing admin API marked not built yet; Service API capabilities and queries marked proposed |
| 2.0 | 2026-10-19 | UC-FM-06: agreements are proxied by OEG like partner registration, with `GET /local-zones` to pick zones; routing rules alone stay on L.2 (ADR-0051, amended 2026-10-15). |
+3 −3
Changes for fm/persistence-model.md: 3 added lines, 3 removed lines.
Original line number Diff line number Diff line
@@ -212,7 +212,7 @@ Constraint: `UNIQUE (partner_op_id, direction, federation_context_id)`.
**Indexes:**
- `idx_federation_agreements_partner` on `partner_op_id`
- `idx_federation_agreements_status_validity` on `(status, valid_from, valid_until)`
- `uq_federation_agreements_one_per_partner`, unique on `partner_op_id` where `status <> 'expired'`: one live agreement per partner; older ones stay as `expired` history
- `uq_federation_agreements_one_per_partner`, unique on `partner_op_id` where `status <> 'expired'`: one live agreement per partner; older ones stay as `expired` history (not built yet)

#### `routing_rules`

@@ -354,9 +354,9 @@ What FM `develop` has today; update as the schema changes.

| Table | In code | Notes |
|---|---|---|
| `partner_ops` | Yes, except `sla_config`, `last_health_check_at` and `partner_ca_cert_path` (not built yet) | |
| `partner_ops` | Yes, except `supported_apis`, `sla_config`, `last_health_check_at` and `partner_ca_cert_path` (not built yet) | |
| `partner_op_secrets` | Yes | ADR-0067 |
| `federation_contexts` | Yes | |
| `federation_contexts` | Yes, except `offered_zone_ids` (not built yet) | |
| `federation_agreements` | Yes | `service_spec_mappings` is the `InstallApp` fallback after EWBI onboarding (ADR-0068) |
| `routing_rules` | Yes | |
| `shared_resource_catalogues` | Yes | Zones, zone subscriptions and application onboardings (ADR-0068) |
Loading