Skip to content

Commit 12f2180

Browse files
authored
Merge branch 'main' into CAT-FR-CO-03_part3_trust-framework-bundle-overrides
Signed-off-by: Eric Nowak <eric.nowak@msg.group>
2 parents 1686adf + 26ca4b9 commit 12f2180

6 files changed

Lines changed: 95 additions & 4 deletions

File tree

federated-catalogue/src/docs/architecture/chapters/04_solution_strategy.adoc

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,9 @@ Non-RDF schemas are uploaded and managed through the same `/schemas` endpoint as
126126
* **RDF content types** (`application/rdf+xml`, `application/ld+json`, `text/turtle`) are processed by the `SchemaStore` — parsed as RDF, type-detected, and subject to the integrity constraints described above.
127127
* **Non-RDF content types** (`application/schema+json`, `application/xml`) bypass RDF parsing entirely. The raw file is stored in the schema File Store, and metadata (content type, upload timestamp) is persisted in the Metadata Store. An auto-generated identifier (`urn:schema:sha256:<hash>`) is assigned based on content hash, providing deduplication.
128128

129-
Non-RDF schemas appear in the schema listing (`GET /schemas`) under their own type categories (`jsonSchemas`, `xmlSchemas`) and can be retrieved, replaced, and deleted through the standard schema CRUD endpoints. However, they are **not used for automatic SHACL verification** of credentials — they serve as stored reference schemas for external tooling or manual validation.
129+
Non-RDF schemas appear in the schema listing (`GET /schemas`) under their own type categories (`jsonSchemas`, `xmlSchemas`) and can be retrieved, replaced, and deleted through the standard schema CRUD endpoints. They are **not used for automatic SHACL verification** of credentials, but the on-demand validation endpoint (`POST /assets/validate`) does invoke the corresponding validator for non-RDF assets — JSON Schema for `application/json` assets, XML Schema for `application/xml` assets — when the caller selects a matching schema.
130+
131+
Each of the four schema languages exposed through `/schemas` (SHACL, JSON Schema, XML Schema, OWL) has an administrative on/off toggle managed through the admin schema-modules page; see ADR 16 for the toggle semantics and the asymmetric role of the OWL toggle (which gates role resolution rather than a validator).
130132

131133
==== Schema Validation Checks
132134
Each schema before adding it, will be analysed. The Analysis process should check first

federated-catalogue/src/docs/architecture/chapters/05_building_block_view.adoc

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1549,6 +1549,8 @@ flowchart TB
15491549
style EXT fill:#e3f2fd,stroke:#42a5f5
15501550
....
15511551

1552+
NOTE: The `Schema validation enabled?` branch combines two gates. The caller's `verifySchema` request parameter selects whether SHACL runs at all; the administrative SHACL module toggle (see ADR 16) then gates that branch independently. When `verifySchema=true` and SHACL is administratively disabled, the request short-circuits with `400 Bad Request` body `module_disabled:SHACL` before reaching the SHACL composite. The same pattern applies on the on-demand validation endpoint via `AssetValidationServiceImpl`.
1553+
15521554
===== Docker Compose configuration
15531555

15541556
The default profile uses `docker-compose.yml` with `dev.env`. The strict profile adds the `docker-compose.strict.yml` overlay, which sets all verification flags to `true`:
@@ -1725,7 +1727,7 @@ Five delegate services in `fc-service-server` implement the admin endpoints, eac
17251727
| Service | Implements | Endpoints
17261728
| `AdminDashboardService` | `AdminApiDelegate` | `GET /admin/me` (access check), `GET /admin/stats` (metrics), `GET /admin/health` (component health), `GET /admin/keycloak-url`
17271729
| `TrustFrameworkAdminService` | `TrustFrameworkAdminApiDelegate` | List, toggle, and update trust frameworks; checks live connectivity per framework on list
1728-
| `SchemaValidationAdminService` | `SchemaValidationAdminApiDelegate` | List schema modules (SHACL, JSON Schema, XML Schema, OWL) with toggle and schema counts. SHACL, JSON Schema, and XML Schema toggles are enforced by on-demand validation (`POST /assets/validate`) via `AssetValidationService`; in upload verification, only SHACL is consulted. OWL toggles persist to `admin_config` but are not yet wired to any validation pipeline
1730+
| `SchemaValidationAdminService` | `SchemaValidationAdminApiDelegate` | List schema modules (SHACL, JSON Schema, XML Schema, OWL) with toggle and schema counts; toggle each module on/off; expose the per-ontology subclass contribution to each registered role for the OWL module. SHACL, JSON Schema, and XML Schema toggles are enforced by on-demand validation (`POST /assets/validate`) via `AssetValidationService` and return `400 module_disabled:<MODULE>` when off; in upload verification only SHACL is consulted, with the same error contract. The OWL toggle gates the runtime composite-ontology subclass walk in `CredentialVerificationStrategy.resolveRole` (see ADR 16)
17291731
| `GraphDatabaseAdminService` | `GraphDatabaseAdminApiDelegate` | Return current graph DB status; persist preferred backend to `admin_config` (switch takes effect on restart)
17301732
|===
17311733

@@ -1735,14 +1737,30 @@ These components in `fc-service-core` read admin-controlled settings during norm
17351737
|===
17361738
| Component | Triggered by | Effect of admin configuration
17371739
| `LoirePolicyEnforcer` | Loire envelope processing (per request, via `LoireCredentialProcessor`) | Consults `TrustFrameworkService.isEnabled("gaia-x")` to decide whether Loire-specific policies (issuer `did:web` restriction, trust-chain validation) apply at all; reads `trust_anchor_url` from the bundle's `properties` for `x5u` trust-chain validation
1738-
| `AssetValidationServiceImpl` | On-demand asset validation (`POST /assets/validate`) | Checks module state via `SchemaModuleConfigService` for `SHACL`, `JSON_SCHEMA`, and `XML_SCHEMA`. If a module is disabled, the corresponding validator path is skipped or rejected.
1739-
| `CredentialVerificationStrategy` | Credential verification | Reads SHACL module state via `SchemaModuleConfigService` (cached with `@Cacheable` — hot path). Disabling SHACL returns HTTP 400 on schema validation requests. JSON Schema, XML Schema, and OWL toggles are persisted but not yet wired to the verification pipeline. The Gaia-X enabled flag is consulted via `TrustFrameworkService` (see `LoirePolicyEnforcer` above)
1740+
| `AssetValidationServiceImpl` | On-demand asset validation (`POST /assets/validate`) | Checks module state via `SchemaModuleConfigService` for `SHACL`, `JSON_SCHEMA`, and `XML_SCHEMA`. If a module is disabled, the request is rejected with `ClientException` → `400 Bad Request`, body `module_disabled:<MODULE>` (see ADR 16).
1741+
| `CredentialVerificationStrategy` | Credential verification | Reads SHACL and OWL module state via `SchemaModuleConfigService` (cached with `@Cacheable` — hot path). Disabling SHACL returns the same `400 module_disabled:SHACL` contract on requests with `verifySchema=true`. Disabling OWL bypasses the runtime composite-ontology subclass walk in `resolveRole`; credentials whose type is only reachable through that walk fall through to `ResolvedRole.UNKNOWN` and are rejected by the verification entry point with `400 Bad Request` (see ADR 16). JSON Schema and XML Schema toggles do not bite on this path today — every credential is JSON-LD or JWT-wrapped JSON-LD and routes to SHACL. The Gaia-X enabled flag is consulted via `TrustFrameworkService`.
17401742
|===
17411743

17421744
NOTE: The graph backend switch (`graphstore.preferred.backend`) is not yet implemented in the Admin UI — the preference is persisted to `admin_config` but switching backends currently requires a manual config update and service restart.
17431745

17441746
The `trust_frameworks` and `admin_config` tables that back this configuration layer are documented under <<section-concepts,Cross-cutting Concepts — Admin Configuration Persistence>>.
17451747

1748+
===== Schema-module admin toggles
1749+
1750+
The admin schema-modules page (proxied from the demo portal to `GET /admin/schema-validation` on the catalogue) lists four toggleable modules — SHACL, JSON Schema, XML Schema, OWL — and surfaces an additional read-only endpoint, `GET /admin/schema-validation/ontologies`, backed by `OntologyImpactService`.
1751+
1752+
The four toggles fall into two semantic classes (ADR 16):
1753+
1754+
* **Validators (SHACL, JSON Schema, XML Schema)** gate the corresponding validator wherever the catalogue would otherwise run it (on-demand validation, and credential verification with `verifySchema=true`). When off, the affected request returns `400 Bad Request` body `module_disabled:<MODULE>`. Stored schemas remain queryable regardless of toggle state.
1755+
1756+
* **OWL** gates the third tier of role resolution. When off, the runtime composite-ontology subclass walk in `CredentialVerificationStrategy.resolveRole` is skipped; only the registry index and `additional_roots` (ADR 10) are consulted. Credentials whose type is only reachable through the subclass walk fall through to `ResolvedRole.UNKNOWN` and are rejected by the verification entry point with `400 Bad Request`. Registry-direct types are unaffected.
1757+
1758+
`OntologyImpactService` parses each `ONTOLOGY`-type schema row with Jena and counts the `rdfs:subClassOf+` descendants reachable from each registered role's root URI (plus any `additional_roots`), aggregated across active trust-framework bundles. The result is a read-only map of *(ontology id, role name) → subclass count* so operators can see what the OWL toggle is gating before flipping it off.
1759+
1760+
The result surfaces two signals the UI uses to keep the toggle decision honest. Each ontology row carries a `parseError` flag — true when the ontology fails to parse or the per-root subclass walk exceeds its two-second SPARQL timeout. The UI shows a warning row in that case so an admin does not read "zero contributions" as "safe to disable OWL"; an unparseable ontology and a parseable-but-irrelevant ontology look identical in the contributions map otherwise. A top-level `noActiveBundles` flag is set when `TrustFrameworkRegistry.getActiveBundles()` returns empty, i.e. when no trust-framework bundle was loaded from the classpath at boot; the flag does *not* track the runtime trust-framework enabled toggle (the toggle flips the `trust_frameworks.enabled` DB row but does not unload bundles from the registry), so disabling every bundle through the admin page does not raise `noActiveBundles`. The two-second timeout is per registered role root, not per ontology, so a deeply cyclic `subClassOf` graph in one ontology cannot block the rest of the listing.
1761+
1762+
The SHACL toggle additionally gates the background revalidation sweep (see ADR 16): when SHACL is off, `RevalidationServiceImpl.handleTask` skips per-asset validation rather than revoke previously-conforming assets. The periodic sweep is not actively wired in the default production configuration today; the gate is pre-positioned for when it is. Re-queueing chunks skipped while SHACL was off lands together with production wiring of the sweep.
1763+
17461764
=== Level 3: Shared data structures
17471765

17481766
==== VerificationResults

federated-catalogue/src/docs/architecture/chapters/07_deployment_view.adoc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,3 +66,9 @@ Replace `<portal-origin>` with your portal URL (e.g., `http://localhost:8088` fo
6666
==== Admin Console URL
6767

6868
The demo portal auto-derives the Admin Console URL from `keycloak.auth-server-url` and `keycloak.realm` (aliased as `admin.dashboard.keycloak-auth-server-url` / `admin.dashboard.keycloak-realm`). Override with `KEYCLOAK_ADMIN_CONSOLE_URL` (or `admin.dashboard.keycloak-admin-console-url`) if Keycloak is behind a different hostname.
69+
70+
=== Runtime Admin Configuration
71+
72+
Most catalogue features that an operator can flip at runtime are persisted in the `admin_config` PostgreSQL table — including the four schema-module toggles (`schema.module.SHACL.enabled`, `schema.module.JSON_SCHEMA.enabled`, `schema.module.XML_SCHEMA.enabled`, `schema.module.OWL.enabled`) and the per-framework enabled flag in `trust_frameworks`. Values written through the admin endpoints survive restarts; no new environment variables are introduced by this layer.
73+
74+
`federated-catalogue.verification.schema` (start-up boolean) and the four `schema.module.*.enabled` rows (admin-controlled booleans) operate at different layers. The start-up flag selects whether SHACL is consulted at all during credential upload; the admin module toggles then gate the corresponding validator wherever it would otherwise run. See ADR 16 for the toggle semantics, including the asymmetric role of the OWL toggle.

federated-catalogue/src/docs/architecture/chapters/08_concepts.adoc

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,23 @@ properties:
9595
trust_anchor_url: "https://did-server/api/trustAnchor/chain/file"
9696
----
9797

98+
==== Type Dispatch and the OWL Toggle
99+
100+
When a credential arrives, the catalogue maps its `credentialSubject` type URI to a trust-framework role through three tiers, in order:
101+
102+
1. **`TrustFrameworkRegistry.typeIndex`** — a hash lookup populated at boot by walking each bundle's `ontology.ttl` from every declared role down via `rdfs:subClassOf*`. Hits here cover every class statically reachable from a role at startup.
103+
2. **`additional_roots`** — sibling URIs declared in `framework.yaml` for cases where the ontology's class graph does not connect the sibling to the role (see ADR 10 for the `gx:DigitalServiceOffering` example). Also indexed at boot.
104+
3. **Composite-ontology subclass walk** — `ClaimValidator.resolveSubjectRole` runs a SPARQL `rdfs:subClassOf+` query against the runtime composite ontology assembled from `ONTOLOGY`-type schema rows. This is the only tier that consults schemas uploaded *after* boot.
105+
106+
The OWL administrative toggle (ADR 16) controls whether the catalogue admits **runtime extensions** to its registered type vocabulary.
107+
With OWL on, custom subclasses introduced through runtime-uploaded ontologies are recognised and routed to the registered role they extend.
108+
With OWL off, the catalogue accepts only the types statically known at boot — credentials whose type was introduced via a runtime ontology upload are rejected at the verification entry point with `400 Bad Request`.
109+
Tiers 1 and 2 continue to run in either state; only tier 3 (the subclass walk over the runtime composite ontology) is gated.
110+
The admin UI labels the toggle accordingly, so operators see the user-facing effect rather than the implementation tier it gates.
111+
112+
Disabling OWL therefore has a *narrow* but *strict* effect: framework-direct types (Participant, ServiceOffering, Resource for the Gaia-X 2511 bundle, and equivalents in any other bundle's `framework.yaml`) keep resolving and keep being accepted; custom subclasses defined exclusively in a runtime-uploaded ontology stop resolving and are rejected.
113+
Gating role resolution is the most visible effect a toggle on a type-vocabulary input can have, and the one that satisfies the demonstrable-effect requirement for runtime toggles.
114+
98115
=== Admin Configuration Persistence
99116

100117
Admin configuration is backed by two PostgreSQL tables. The `trust_frameworks` table holds structured trust framework definitions (columns: `id`, `name`, `service_url`, `api_version`, `timeout_seconds`, `enabled`, `created_at`, `updated_at`), seeded with a single Gaia-X entry. The `admin_config` table is a generic key-value store (`config_key` PK, `config_value`) for all other runtime settings:

federated-catalogue/src/docs/architecture/chapters/09_architecture_decisions.adoc

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -551,3 +551,39 @@ Routing on `content_kind` is unambiguous and preserves backward compatibility
551551
Overwrite semantics simplify the data model: no partial-merge conflicts, no ordering dependencies between enrichment uploads.
552552

553553
**Related:** ADR 4, ADR 7.
554+
555+
=== ADR 16: Schema-module admin toggles, with OWL gating role resolution
556+
557+
**Related:** ADR 10.
558+
559+
**Context:** Four schema languages — SHACL, JSON Schema, XML Schema, OWL — must each be enable/disable-able at runtime through the administration UI, and every toggle must have a demonstrable effect.
560+
561+
SHACL, JSON Schema, and XML Schema all fit a uniform validator shape: input runs against stored schemas of the matching type and a conformance verdict is returned.
562+
OWL is different — uploaded ontologies extend the type vocabulary the role resolver consults via `rdfs:subClassOf+`; OWL has no validation step of its own.
563+
A uniform `module_disabled` semantic therefore does not fit OWL: without separate semantics, the OWL toggle would persist in the database with no observable effect, which violates the demonstrable-effect requirement.
564+
565+
**Decision:** Expose all four toggles on the admin schema-modules page, but treat them as two semantic classes. The admin UI splits the two classes into separate sections so the asymmetry is visible to operators.
566+
567+
* **Validators (SHACL, JSON Schema, XML Schema):** the toggle gates the validator wherever the catalogue would otherwise run it — on-demand validation, and credential verification when the caller requests a schema check.
568+
When off, the affected endpoint returns `400 Bad Request` with body `module_disabled:<MODULE>`.
569+
Schema storage is unaffected; schemas remain queryable through the schema endpoints regardless of toggle state.
570+
571+
* **OWL:** the toggle gates the third tier of role resolution — the `rdfs:subClassOf+` walk over runtime-uploaded ontologies, on top of the registry index and `additional_roots` defined by ADR 10.
572+
When off, only tiers 1 and 2 are consulted; credentials whose type is only reachable through the subclass walk resolve to `ResolvedRole.UNKNOWN`, and the verification entry point rejects them with `400 Bad Request`.
573+
Registry-direct types (Participant, ServiceOffering, Resource for the Gaia-X 2511 bundle, and equivalents in any other bundle's `framework.yaml`) are unaffected.
574+
575+
**Consequences:**
576+
577+
* Disabling a validator is *permissive* (a check is skipped); disabling OWL is *restrictive* (the catalogue stops recognising custom subclasses).
578+
The asymmetry is intentional: gating role resolution is the strongest demonstrable effect for a type-vocabulary input, and a uniform "skip a check" semantic does not exist for OWL.
579+
580+
* The OWL toggle is independent of the caller's `verifySchema` and `verifySemantics` flags.
581+
Type dispatch is a configuration of the catalogue's type system, not a per-request validation step, so disabling OWL affects every internal caller of the verification path — asset upload, provenance ingest, asset metadata flow, base subscriber, and on-demand role resolution — independent of how those callers parameterise their request.
582+
583+
* The SHACL toggle also gates the periodic revalidation sweep over the existing claims graph.
584+
When SHACL is administratively disabled, `RevalidationServiceImpl.handleTask` short-circuits — the sweep skips per-asset validation rather than revoke previously-conforming assets against shapes the operator has explicitly silenced.
585+
The periodic sweep is not actively wired in the default production configuration today; the gate is pre-positioned for when it is.
586+
Re-sweeping the backlog of chunks skipped while SHACL was off (re-queueing them on the false→true transition) is a follow-up that lands together with production wiring of the sweep — it is a one-liner against `RevalidationService.startValidating()` at that point.
587+
588+
* On-demand validation (`POST /assets/validate`) rejects with `400 Bad Request` not only for `module_disabled:<MODULE>` but also for the broader "no validation module is enabled or applicable" case.
589+
Both are administrative-configuration mismatches under operator control, not server-side processing failures, so `ClientException` (400) is the appropriate mapping rather than `VerificationException` (422). 422 remains reserved for assets whose type is not validatable at all (not RDF, unsupported content type).

0 commit comments

Comments
 (0)