diff --git a/workspaces/ai-integrations/openspec/changes/ai-resource-catalog-entity-kind/.openspec.yaml b/workspaces/ai-integrations/openspec/changes/ai-resource-catalog-entity-kind/.openspec.yaml index 5af36643360..3c0001f07bc 100644 --- a/workspaces/ai-integrations/openspec/changes/ai-resource-catalog-entity-kind/.openspec.yaml +++ b/workspaces/ai-integrations/openspec/changes/ai-resource-catalog-entity-kind/.openspec.yaml @@ -1,3 +1,7 @@ schema: spec-driven created: 2026-07-06 +updated: 2026-07-22 status: draft +notes: >- + Retooled OCI support onto upstream backstage.io/source-location + (url:oci://…) per RHIDP-15739; removed spec.location model. diff --git a/workspaces/ai-integrations/openspec/changes/ai-resource-catalog-entity-kind/design.md b/workspaces/ai-integrations/openspec/changes/ai-resource-catalog-entity-kind/design.md index 0c129ef8ac5..862ca241a28 100644 --- a/workspaces/ai-integrations/openspec/changes/ai-resource-catalog-entity-kind/design.md +++ b/workspaces/ai-integrations/openspec/changes/ai-resource-catalog-entity-kind/design.md @@ -2,7 +2,9 @@ ## Canonical Touchpoints -- None +- RHDHPLAN-1113 — [Agentic] Agents & Skills (AIResource Kinds) in the RHDH Catalog (DP) +- RHIDP-13942 — AIResource: Catalog ingestion (OCI processor + git annotation path) +- RHIDP-15739 — Align OCI AIResource support with upstream source-location (`url:oci://…`); remove `spec.location` ## Context @@ -12,92 +14,126 @@ Backstage's catalog supports pluggable entity kinds through three main mechanism 2. Registering processors that validate or enrich entities during ingestion 3. Reusing existing catalog behavior where a new kind fits an established path -For AI assets, the two source types are materially different: +Upstream `AiResource` does **not** define `spec.location`. Skill and rule content is referenced via the standard `backstage.io/source-location` annotation, identical to other Backstage entity kinds. -- **`git`**: A source repository or other URL-reader-compatible location that can reuse existing Backstage ingestion behavior -- **`oci`**: An OCI artifact reference such as `oci://quay.io/org/skills:latest`, which requires explicit validation because existing catalog processors do not understand OCI references directly +For AI assets, two content reference shapes are needed: -The design must keep OCI ingestion air-gap safe. The catalog should validate the reference and index the entity, but it must not fetch manifests, pull layers, or contact registries during processing. +- **Git / HTTPS**: `backstage.io/source-location: url:https://…` (or other UrlReader-compatible URL) +- **OCI**: `backstage.io/source-location: url:oci://registry/repository[:tag|@digest]` + +In both cases, the **entity YAML** (`catalog-info.yaml`) is still registered through a normal catalog location (`url` / `file` / git discovery). The OCI reference is metadata on the entity; the catalog does not pull image content during ingest. + +The design must keep OCI ingest air-gap safe: validate the reference and index the entity, but do not fetch manifests, pull layers, or contact registries during processing. ## Goals / Non-Goals **Goals:** -- Implement the upstream-aligned `AIResource` kind in this workspace -- Use `spec.location.target` as the canonical location field -- Reuse existing catalog behavior for git-backed AIResource entities +- Implement the upstream-aligned `AIResource` / `AiResource` kind in this workspace +- Use `backstage.io/source-location` as the canonical content location +- Validate OCI source-location values in location-ref form `url:oci://…` +- Reuse existing catalog behavior for registering entity YAML from git/HTTPS/`file` - Add lightweight OCI validation with zero outbound network calls - Support standard entity page rendering, discovery, filtering, and search - Support RHDH-specific `spec.scope` validation +- Remove any RHDH `spec.location` field used for OCI/git asset location **Non-Goals:** -- Deep OCI content ingestion +- Deep OCI content ingestion / OCI `UrlReader` +- Catalog location type `oci` for discovering entities from registries - Private registry authentication - Separate frontend plugin or marketplace UI -- Additional asset source types beyond `git` and `oci` +- Additional RHDH location fields beyond upstream annotations + `spec.scope` ## Decisions -### D1 - Use upstream `AIResource`, not `AIContext` +### D1 - Use upstream `AiResource` / `AIResource`, not `AIContext` -**Choice**: Implement the upstream `AIResource` entity kind rather than maintaining the older `AIContext` naming. +**Choice**: Implement the upstream `AiResource` entity kind rather than maintaining the older `AIContext` naming. **Rationale**: Upstream alignment reduces migration cost and keeps this workspace compatible with the Backstage merge path. -### D2 - Use `spec.location.target` as the canonical location field +### D2 - Canonical location is `backstage.io/source-location` (no `spec.location`) + +**Choice**: Do not use an RHDH `spec.location` struct. Git/HTTPS and OCI content references both use `metadata.annotations["backstage.io/source-location"]`. + +**Rationale**: Matches upstream AIResource design and Backstage feedback. Keeps OCI skill support compatible with future consumers that resolve content via `UrlReader` against the source-location target. + +### D3 - OCI uses location-ref form `url:oci://…` + +**Choice**: OCI-backed entities MUST set: -**Choice**: Represent both git and OCI locations with `spec.location.target`, discriminated by `spec.location.type`. +```yaml +metadata: + annotations: + backstage.io/source-location: url:oci://quay.io/org/skills:latest +``` -**Rationale**: This matches the current RFC direction and avoids separate `url` / `uri` field shapes. +Backstage `parseLocationRef` splits on the first `:`, yielding `{ type: 'url', target: 'oci://quay.io/org/skills:latest' }`. -### D3 - Reuse `UrlReaderProcessor` for git-backed entities +**Rationale**: Bare `oci://…` as the annotation value parses as location type `oci` with a non-URL target (`//quay.io/…`), which breaks future UrlReader integration. Prefixing with `url:` keeps type `url` and preserves a parseable `oci://` target. -**Choice**: Git-backed AIResource entities use the standard `backstage.io/source-location` annotation and the existing `UrlReaderProcessor`. +### D4 - Reuse standard catalog registration for entity YAML -**Rationale**: This keeps the common path simple and avoids duplicating catalog logic that already exists in Backstage. +**Choice**: Entity descriptors are always fetched from normal catalog locations (`url` / `file` / git). No catalog location type `oci` and no OCI `UrlReader` are required to **register** OCI-referenced AIResources. -### D4 - OCI ingestion performs format validation only +**Rationale**: Registration indexes metadata. Fetching skill content from a registry is a separate, later capability. -**Choice**: OCI-backed AIResource entities are validated by a dedicated processor that checks `spec.location.target` format only. +**Verification**: Git/HTTPS-sourced AIResource ingestion via the existing `UrlReaderProcessor` and `backstage.io/source-location` annotation was verified in RHIDP-14557 (happy path, missing source-location warning, and standard catalog registration). That establishes the git skill path; OCI does not need a UrlReader for registration. + +### D5 - OCI ingestion performs format validation only + +**Choice**: When `backstage.io/source-location` has target scheme `oci://`, a dedicated processor validates format only (non-empty, no surrounding whitespace, well-formed `oci://registry/repository[:tag|@digest]`). **Rationale**: The catalog indexes the OCI reference as metadata. It should not fetch remote OCI content. This keeps ingestion stateless, air-gap safe, and free of registry dependency or rate-limit concerns. -### D5 - Preserve the `oci://` prefix convention +### D6 - Preserve the `oci://` scheme on the location target -**Choice**: OCI locations must retain the `oci://` scheme prefix. +**Choice**: The source-location **target** (after the `url:` prefix) must use the `oci://` scheme. -**Rationale**: This is the established RHDH convention and provides an unambiguous distinction from ordinary URLs. +**Rationale**: Unambiguous distinction from HTTPS/git URLs; matches established RHDH OCI URI convention. -### D6 - `spec.scope` is an RHDH extension +### D7 - `spec.scope` is an RHDH extension **Choice**: Support optional `spec.scope` values `organization`, `product`, and `team` as an RHDH-specific extension. **Rationale**: Scope is needed for RHDH use cases but is not part of the upstream core kind. Keeping it as an extension preserves alignment while meeting local requirements. -### D7 - Use the standard entity page +### D8 - Use the standard entity page **Choice**: Render AIResource entities through the existing `EntityPage` layout rather than creating a dedicated page. -**Rationale**: The standard entity page already provides metadata rendering, relationships, and TechDocs integration. A custom plugin would add unnecessary complexity for the initial release. +**Rationale**: The standard entity page already provides metadata rendering, relationships, and TechDocs integration. A custom AI catalog frontend is deferred to a future release. -### D8 - Discovery uses standard catalog APIs +### D9 - Discovery uses standard catalog APIs **Choice**: AIResource entities participate in the existing entity list, by-name lookup, filter, and full-text search APIs. **Rationale**: AIResource should behave like any other first-class catalog kind rather than requiring special endpoints. +### D10 - Deferred: OCI UrlReader + +**Choice**: Do not implement an OCI `UrlReader` in this change. + +**Rationale**: A UrlReader is only needed when a consumer must fetch content (or catalog YAML) from `oci://…`. Registration and format validation do not require it. When added later, it registers via `urlReaderFactoriesServiceRef` with `predicate: (url) => url.protocol === 'oci:'`. + +**Symmetry with git**: The existing Backstage URL readers already cover git/HTTPS skill sources; RHIDP-14557 confirmed that path for AIResource. Deferring an OCI UrlReader is therefore an intentional gap versus the verified git reader path, not an unverified assumption that “no reader is needed for either.” + ## Risks / Trade-offs -| Risk | Mitigation | -| -------------------------------------------- | ------------------------------------------------------------------------------------------ | -| Upstream AIResource evolves further | Keep the design aligned to upstream naming and field shapes; limit RHDH-specific additions | -| OCI target ambiguity causes weak validation | Enforce `spec.location.type`, `spec.location.target`, and `oci://` prefix rules explicitly | -| Users expect OCI content inspection | Document clearly that ingestion indexes metadata only and performs no registry I/O | -| RHDH extension behavior drifts from upstream | Keep `spec.scope` isolated as an extension and avoid additional spec divergence | +| Risk | Mitigation | +| ------------------------------------------------- | ---------------------------------------------------------------------------------------------- | +| Upstream AIResource evolves further | Keep the design aligned to upstream annotations; limit RHDH-specific additions to `spec.scope` | +| Wrong location-ref form (`oci://` without `url:`) | Validate `url:` prefix + `oci://` target; document examples clearly | +| Users expect OCI content inspection | Document clearly that ingestion indexes metadata only and performs no registry I/O | +| Stale `spec.location` examples confuse agents | Remove `spec.location` from schema, processor, docs, examples, and OpenSpec | +| RHDH extension behavior drifts from upstream | Keep `spec.scope` isolated as an extension and avoid additional spec divergence | ## Deferred Decisions +- OCI `UrlReader` for content fetch / broader import - Private OCI registry authentication -- OCI URI to registry-browse URL transformation on the entity page +- Catalog location type `oci` for discovering entities from registries +- OCI URI to registry-browse URL transformation on a custom entity page - Promotion of change-local specs into long-lived `openspec/specs/` diff --git a/workspaces/ai-integrations/openspec/changes/ai-resource-catalog-entity-kind/proposal.md b/workspaces/ai-integrations/openspec/changes/ai-resource-catalog-entity-kind/proposal.md index a2eef158d6f..3c0349309be 100644 --- a/workspaces/ai-integrations/openspec/changes/ai-resource-catalog-entity-kind/proposal.md +++ b/workspaces/ai-integrations/openspec/changes/ai-resource-catalog-entity-kind/proposal.md @@ -4,15 +4,17 @@ AI coding tools consume reusable assets such as skills, rules, prompts, and agent definitions that teams publish in source repositories or OCI images. There is no standard way in this workspace to register those assets as catalog entities, validate their location metadata safely, and make them discoverable through standard RHDH catalog APIs and entity pages. -Adding first-class `AIResource` catalog support closes that gap while staying aligned with the upstream Backstage `AIResource` kind. +Adding first-class `AIResource` catalog support closes that gap while staying aligned with the upstream Backstage `AiResource` kind. Upstream intentionally has no `spec.location` field — asset content is referenced via the standard `backstage.io/source-location` annotation. ## What Changes -- Introduce support for the upstream `AIResource` catalog kind in this workspace. -- Support two asset location types under `spec.location.type`: `git` and `oci`. -- Validate AIResource entities during ingestion, including RHDH-specific `spec.scope` support and `oci://` prefix rules. -- Reuse existing Backstage catalog behavior for git-backed entities. -- Add an OCI catalog processor that validates `spec.location.target` format only and makes zero outbound registry calls. +- Introduce support for the upstream `AiResource` / `AIResource` catalog kind in this workspace. +- Use `backstage.io/source-location` as the canonical asset location for both git/HTTPS and OCI-backed entities. +- Represent OCI-backed assets with the Backstage location-ref form `url:oci://…` (location type `url`, target scheme `oci://`). +- Validate AIResource entities during ingestion, including RHDH-specific `spec.scope` support and OCI source-location format rules. +- Reuse existing Backstage catalog behavior for entity YAML registration (git/HTTPS/`file` catalog locations). +- Add an OCI catalog processor that validates OCI `source-location` format only and makes zero outbound registry calls. +- Do **not** introduce RHDH `spec.location` (removed / not used for OCI skill support). - Render AIResource entities on the standard catalog entity page. - Expose AIResource entities through standard catalog search and filter APIs. - Add local workspace documentation and OpenSpec artifacts so implementation agents can work from this workspace directly. @@ -21,8 +23,8 @@ Adding first-class `AIResource` catalog support closes that gap while staying al ### New Capabilities -- `ai-resource-entity-schema`: Schema and validation rules for the `AIResource` kind, including `spec.scope` as an RHDH extension and `oci://` validation for OCI locations. -- `ai-resource-catalog-ingestion`: Catalog backend support for git-backed and OCI-backed AIResource ingestion. +- `ai-resource-entity-schema`: Schema and validation rules for the `AIResource` kind, including `spec.scope` as an RHDH extension and OCI `source-location` validation. +- `ai-resource-catalog-ingestion`: Catalog backend support for git/HTTPS-backed and OCI-referenced AIResource ingestion (format validation only for OCI). - `ai-resource-entity-page`: Standard entity page rendering for AIResource entities, including source-aware location display and TechDocs integration. - `ai-resource-discovery`: Catalog API, filtering, and full-text search support for AIResource entities. @@ -34,9 +36,11 @@ _(none - this is a net-new capability area in this workspace)_ - Parsing or indexing individual skills, rules, prompts, or agents inside an asset - OCI registry manifest fetching, layer inspection, or metadata enrichment +- An OCI `UrlReader` (deferred; needed only when something must fetch OCI content) +- A catalog location type `oci` / `readLocation` for discovering entities from registries - Private OCI registry authentication in the initial implementation -- HTTPS archive, ZIP, or TAR support as location types -- A dedicated AI marketplace or custom frontend plugin +- HTTPS archive, ZIP, or TAR support as catalog location types +- A dedicated AI marketplace or custom frontend plugin (future release) - Tool-runtime-specific integration with Cursor, Copilot, Claude Code, or other AI coding tools ## Canonical Touchpoints @@ -44,13 +48,14 @@ _(none - this is a net-new capability area in this workspace)_ - **PRDs**: None - **ADRs**: None - **Long-lived specs (`openspec/specs/`)**: None yet +- **Jira**: RHDHPLAN-1113, RHIDP-13942, RHIDP-15739 **Change type**: feature-spec ## Impact -- **Catalog backend**: Adds AIResource-specific ingestion and OCI validation behavior -- **Schema handling**: Extends upstream AIResource behavior with RHDH-specific validation +- **Catalog backend**: Adds AIResource-specific ingestion and OCI `source-location` validation behavior +- **Schema handling**: Extends upstream AIResource behavior with RHDH-specific `spec.scope` validation only (no `spec.location`) - **Frontend**: Reuses the standard entity page layout for AIResource entities - **Catalog API**: No breaking API changes; AIResource appears through standard entity and search endpoints - **Documentation**: Adds local OpenSpec materials to make the workspace self-contained for implementation diff --git a/workspaces/ai-integrations/openspec/changes/ai-resource-catalog-entity-kind/specs/ai-resource-catalog-ingestion/spec.md b/workspaces/ai-integrations/openspec/changes/ai-resource-catalog-entity-kind/specs/ai-resource-catalog-ingestion/spec.md index d6af65e745a..5de2fe3add6 100644 --- a/workspaces/ai-integrations/openspec/changes/ai-resource-catalog-entity-kind/specs/ai-resource-catalog-ingestion/spec.md +++ b/workspaces/ai-integrations/openspec/changes/ai-resource-catalog-entity-kind/specs/ai-resource-catalog-ingestion/spec.md @@ -1,68 +1,73 @@ ## ADDED Requirements -### Requirement: Git-backed entity ingestion via existing URL reader +### Requirement: Entity YAML ingested via standard catalog locations -AIResource entities with `spec.location.type: git` SHALL be ingested using the standard Backstage `UrlReaderProcessor`. The entity SHALL declare `metadata.annotations["backstage.io/source-location"]` pointing to the repository URL. +AIResource entity descriptors SHALL be registered through standard Backstage/RHDH catalog locations (`url`, `file`, or git discovery). Registration SHALL NOT require a catalog location type `oci` or an OCI `UrlReader`. -#### Scenario: Git entity with source-location annotation ingested +#### Scenario: Entity registered via standard URL registration flow -- **WHEN** an AIResource entity declares `spec.location.type: git` and the annotation `backstage.io/source-location` set to a valid repository URL -- **THEN** the catalog reads and ingests the entity using the existing URL reader without errors +- **WHEN** a user registers an AIResource `catalog-info.yaml` via the standard RHDH catalog URL registration UI +- **THEN** the entity is ingested and indexed within the normal catalog refresh cycle -#### Scenario: Missing source-location annotation produces warning +#### Scenario: Entity discovered through standard catalog-info flow -- **WHEN** an AIResource entity declares `spec.location.type: git` but omits the `backstage.io/source-location` annotation -- **THEN** the catalog ingests the entity but emits a processor warning indicating the annotation is missing +- **WHEN** an AIResource entity is declared in a standard catalog-info location reachable by the catalog +- **THEN** the catalog ingests it without requiring AIResource-specific registration logic --- -### Requirement: OCI-backed entity format validation +### Requirement: Git/HTTPS-backed content via source-location -AIResource entities with `spec.location.type: oci` SHALL be validated by an RHDH catalog processor for URI format only. The processor SHALL NOT make any network calls to a registry. +AIResource entities whose content lives in git/HTTPS SHALL declare `metadata.annotations["backstage.io/source-location"]` with a normal `url:https://…` (or other UrlReader-compatible) location-ref. Entity YAML ingestion continues to use the existing `UrlReaderProcessor` for catalog locations. -#### Scenario: Valid OCI reference accepted +#### Scenario: Git entity with source-location annotation ingested -- **WHEN** an AIResource entity declares `spec.location.type: oci` with a well-formed `oci://` URI in `spec.location.target` -- **THEN** the entity passes processor validation and is ingested without registry calls +- **WHEN** an AIResource entity declares `backstage.io/source-location: url:https://github.com/my-org/my-skills` +- **THEN** the catalog ingests the entity without errors -#### Scenario: Malformed OCI reference rejected +#### Scenario: Missing source-location annotation produces warning -- **WHEN** an AIResource entity declares `spec.location.type: oci` with a `spec.location.target` that does not match the expected `oci://` format -- **THEN** the processor rejects it with a validation error describing the expected format and makes no registry call +- **WHEN** an AIResource entity omits the `backstage.io/source-location` annotation +- **THEN** the catalog ingests the entity but emits a processor warning indicating the annotation is missing (standard catalog behavior) --- -### Requirement: AIResource entities registrable via standard catalog interfaces +### Requirement: OCI-backed source-location format validation -AIResource entities SHALL be registrable through standard RHDH catalog registration interfaces, including manual URL registration and catalog-info auto-discovery. +When an AIResource entity's `backstage.io/source-location` target uses the `oci://` scheme, an RHDH catalog processor SHALL validate URI/location-ref format only. The processor SHALL NOT make any network calls to a registry. -#### Scenario: AIResource entity registered via standard URL registration flow +#### Scenario: Valid OCI source-location accepted -- **WHEN** a user registers an AIResource entity via the standard RHDH catalog URL registration UI -- **THEN** the entity is ingested and indexed within the normal catalog refresh cycle +- **WHEN** an AIResource entity declares `backstage.io/source-location: url:oci://quay.io/org/skills:latest` +- **THEN** the entity passes processor validation and is ingested without registry calls -#### Scenario: AIResource entity discovered through standard catalog-info flow +#### Scenario: Malformed OCI source-location rejected -- **WHEN** an AIResource entity is declared in a standard catalog-info location reachable by the catalog -- **THEN** the catalog ingests it without requiring AIResource-specific registration logic +- **WHEN** an AIResource entity declares a malformed OCI `backstage.io/source-location` (including bare `oci://…` without the `url:` prefix) +- **THEN** the processor rejects it with a validation error describing the expected `url:oci://…` format and makes no registry call + +#### Scenario: Zero registry I/O during OCI validation + +- **WHEN** the OCI processor validates any OCI source-location value +- **THEN** it performs no HTTP or registry network calls --- ### Requirement: Schema validation with actionable error messages -The catalog processor SHALL validate every AIResource entity against the applicable schema before storing it. Validation errors SHALL include the field path, invalid value when applicable, and a human-readable description of the violated constraint. +The catalog processor SHALL validate every AIResource entity against the applicable schema before storing it. Validation errors SHALL include the field path (or annotation name), invalid value when applicable, and a human-readable description of the violated constraint. -#### Scenario: Missing required field produces field-specific error +#### Scenario: Missing required upstream field produces field-specific error -- **WHEN** an AIResource entity is missing a required field such as `spec.owner` +- **WHEN** an AIResource entity is missing a required upstream field such as `spec.owner` - **THEN** the validation error identifies the exact field path and states that it is required -#### Scenario: Invalid location type produces enumeration error +#### Scenario: Invalid `spec.scope` produces enumeration error -- **WHEN** an AIResource entity declares `spec.location.type: zip` -- **THEN** the validation error states the received value and lists the accepted values `git` and `oci` +- **WHEN** an AIResource entity declares an invalid `spec.scope` +- **THEN** the validation error states the received value and lists the accepted values `organization`, `product`, and `team` #### Scenario: Multiple validation errors reported together -- **WHEN** an AIResource entity has multiple invalid fields +- **WHEN** an AIResource entity has multiple invalid fields or annotations - **THEN** all validation errors are reported in a single response diff --git a/workspaces/ai-integrations/openspec/changes/ai-resource-catalog-entity-kind/specs/ai-resource-entity-page/spec.md b/workspaces/ai-integrations/openspec/changes/ai-resource-catalog-entity-kind/specs/ai-resource-entity-page/spec.md index c8ee7d7b854..52313a2b2a5 100644 --- a/workspaces/ai-integrations/openspec/changes/ai-resource-catalog-entity-kind/specs/ai-resource-entity-page/spec.md +++ b/workspaces/ai-integrations/openspec/changes/ai-resource-catalog-entity-kind/specs/ai-resource-entity-page/spec.md @@ -9,31 +9,31 @@ The system SHALL render a detail page for AIResource entities using the existing - **WHEN** a user navigates to the catalog URL of an AIResource entity - **THEN** the standard entity detail page renders with the entity metadata visible -#### Scenario: Entity page displays for both git and oci sourced entities +#### Scenario: Entity page displays for both git/HTTPS and OCI sourced entities -- **WHEN** an AIResource entity has `spec.location.type: git` or `spec.location.type: oci` +- **WHEN** an AIResource entity has a git/HTTPS or OCI `backstage.io/source-location` - **THEN** the same entity page layout renders for both and the location display adapts to the source type --- -### Requirement: Asset location rendered from `spec.location.target` +### Requirement: Asset location rendered from `backstage.io/source-location` -The entity detail page SHALL display the asset location from `spec.location.target` as either a clickable link for git sources or copyable text for OCI sources. +The entity detail page SHALL display the asset location from `backstage.io/source-location` as either a clickable link for git/HTTPS sources or copyable text for OCI sources. -#### Scenario: Git location displayed as clickable link +#### Scenario: Git/HTTPS location displayed as clickable link -- **WHEN** an AIResource entity has `spec.location.type: git` and a valid URL in `spec.location.target` -- **THEN** the entity page shows the URL as a clickable link labelled "Git Repository" +- **WHEN** an AIResource entity has `backstage.io/source-location: url:https://…` +- **THEN** the entity page shows the URL as a clickable link #### Scenario: OCI location displayed as copyable text -- **WHEN** an AIResource entity has `spec.location.type: oci` and a valid `oci://` URI in `spec.location.target` -- **THEN** the entity page displays the OCI URI as copyable text labelled "OCI Image" with a copy-to-clipboard affordance +- **WHEN** an AIResource entity has `backstage.io/source-location: url:oci://…` +- **THEN** the entity page displays the OCI URI as copyable text with a copy-to-clipboard affordance (not as a normal browser navigation link) #### Scenario: Location label indicates source type - **WHEN** the entity page renders the asset location -- **THEN** the display is labelled to indicate whether the source is a git repository or OCI image +- **THEN** the display indicates whether the source is a git/HTTPS URL or an OCI image reference --- diff --git a/workspaces/ai-integrations/openspec/changes/ai-resource-catalog-entity-kind/specs/ai-resource-entity-schema/spec.md b/workspaces/ai-integrations/openspec/changes/ai-resource-catalog-entity-kind/specs/ai-resource-entity-schema/spec.md index 4b42de8844a..ac2be999f1c 100644 --- a/workspaces/ai-integrations/openspec/changes/ai-resource-catalog-entity-kind/specs/ai-resource-entity-schema/spec.md +++ b/workspaces/ai-integrations/openspec/changes/ai-resource-catalog-entity-kind/specs/ai-resource-entity-schema/spec.md @@ -1,6 +1,8 @@ ## RHDH Extension Requirements for AIResource -RHDH extends the upstream `AIResource` entity kind with RHDH-specific validation behavior. This spec covers only what this workspace adds on top of the upstream kind definition. +RHDH extends the upstream `AiResource` / `AIResource` entity kind with RHDH-specific validation behavior. This spec covers only what this workspace adds on top of the upstream kind definition. + +Upstream has no `spec.location` field. Asset content location uses the standard `backstage.io/source-location` annotation. --- @@ -30,40 +32,71 @@ RHDH AIResource entities MAY declare `spec.scope` to indicate the intended audie --- -### Requirement: OCI location URI scheme +### Requirement: No RHDH `spec.location` field + +RHDH SHALL NOT require or validate a `spec.location` struct for AIResource asset location. Git/HTTPS and OCI content references use `backstage.io/source-location` only. + +#### Scenario: Entity without `spec.location` accepted + +- **WHEN** an AIResource entity omits `spec.location` and provides a valid `backstage.io/source-location` +- **THEN** the entity passes RHDH extension validation for location concerns + +#### Scenario: `spec.location` is not the OCI validation input + +- **WHEN** an AIResource entity includes a legacy `spec.location` field +- **THEN** RHDH OCI format validation does not treat `spec.location.target` as the source of truth (validation is based on `backstage.io/source-location`) + +--- + +### Requirement: OCI source-location URI scheme + +When an AIResource entity declares `backstage.io/source-location` whose location-ref target uses the `oci://` scheme, the annotation SHALL use the Backstage location-ref form `url:oci://…`, and the target SHALL be a well-formed OCI reference. + +#### Scenario: Valid OCI source-location accepted + +- **WHEN** an AIResource entity declares `backstage.io/source-location: url:oci://quay.io/myorg/my-skills:latest` +- **THEN** the entity passes OCI format validation + +#### Scenario: Valid OCI digest source-location accepted + +- **WHEN** an AIResource entity declares `backstage.io/source-location: url:oci://quay.io/myorg/my-skills@sha256:` +- **THEN** the entity passes OCI format validation + +#### Scenario: OCI target without `oci://` scheme rejected -When `spec.location.type` is `oci`, the `spec.location.target` value SHALL begin with the `oci://` scheme prefix. +- **WHEN** an AIResource entity declares `backstage.io/source-location: url:quay.io/myorg/my-skills:latest` intending an OCI asset +- **THEN** the catalog does not treat it as a valid OCI source-location (no `oci://` target scheme) -#### Scenario: Valid OCI target accepted +#### Scenario: Bare `oci://` annotation without `url:` prefix rejected -- **WHEN** an AIResource entity declares `spec.location.type: oci` and `spec.location.target: oci://quay.io/myorg/my-skills:latest` -- **THEN** the entity passes validation +- **WHEN** an AIResource entity declares `backstage.io/source-location: oci://quay.io/myorg/my-skills:latest` +- **THEN** the catalog rejects it with an actionable error stating that the location-ref form `url:oci://…` is required -#### Scenario: OCI target without prefix rejected +#### Scenario: Malformed OCI target rejected -- **WHEN** an AIResource entity declares `spec.location.type: oci` and `spec.location.target: quay.io/myorg/my-skills:latest` -- **THEN** the catalog rejects it with an error stating that the `oci://` prefix is required and shows the expected format +- **WHEN** an AIResource entity declares `backstage.io/source-location: url:oci://` or another malformed OCI reference +- **THEN** the catalog rejects it with an error describing the expected `oci://registry/repository[:tag|@digest]` format -#### Scenario: Git type is not subject to OCI prefix validation +#### Scenario: Non-OCI source-location is not subject to OCI validation -- **WHEN** an AIResource entity declares `spec.location.type: git` with a normal repository URL in `spec.location.target` -- **THEN** the `oci://` rule does not apply +- **WHEN** an AIResource entity declares `backstage.io/source-location: url:https://github.com/myorg/my-skills` +- **THEN** the OCI format rules do not apply --- ### Requirement: Validation error quality -RHDH-specific validation errors SHALL include the field path, the invalid value, and a human-readable description of the violated constraint. Errors SHALL NOT expose internal class names or stack traces. +RHDH-specific validation errors SHALL include the field path (or annotation name), the invalid value, and a human-readable description of the violated constraint. Errors SHALL NOT expose internal class names or stack traces. #### Scenario: `spec.scope` error is actionable - **WHEN** an AIResource entity declares an invalid `spec.scope` - **THEN** the error identifies `spec.scope`, the received value, and the accepted values -#### Scenario: OCI target error is actionable +#### Scenario: OCI source-location error is actionable -- **WHEN** an AIResource entity with `spec.location.type: oci` provides a malformed `spec.location.target` -- **THEN** the error states the expected `oci://` format without exposing internal implementation details +- **WHEN** an AIResource entity provides a malformed OCI `backstage.io/source-location` +- **THEN** the error states the expected `url:oci://…` format without exposing internal implementation details #### Scenario: Multiple extension errors reported together diff --git a/workspaces/ai-integrations/openspec/changes/ai-resource-catalog-entity-kind/tasks.md b/workspaces/ai-integrations/openspec/changes/ai-resource-catalog-entity-kind/tasks.md index 4b8e767448e..50385c67b5a 100644 --- a/workspaces/ai-integrations/openspec/changes/ai-resource-catalog-entity-kind/tasks.md +++ b/workspaces/ai-integrations/openspec/changes/ai-resource-catalog-entity-kind/tasks.md @@ -1,39 +1,43 @@ # Tasks: AIResource Catalog Entity Kind +Tracking note: schema/processor work originally landed against a `spec.location` model (RHIDP-14553/14554/14556). RHIDP-15739 retools OCI support onto upstream `backstage.io/source-location` (`url:oci://…`) and removes `spec.location`. + ## 1. Upstream Investigation & Schema Foundation -- [ ] 1.1 Investigate the upstream `AIResource` kind to confirm the merged model, schema shape, and extension points used by this workspace -- [ ] 1.2 Extend or wrap the AIResource schema to support optional `spec.scope` with allowed values `organization`, `product`, and `team` -- [ ] 1.3 Add validation for `spec.scope` that reports field path, received value, and accepted values -- [ ] 1.4 Add `oci://` prefix validation for `spec.location.target` when `spec.location.type` is `oci` -- [ ] 1.5 Ensure AIResource validation errors are actionable and can report multiple errors in one response -- [ ] 1.6 Add unit tests covering valid and invalid `spec.scope`, valid and invalid OCI targets, and multi-error reporting +- [x] 1.1 Investigate the upstream `AiResource` kind to confirm the merged model, schema shape, and extension points used by this workspace +- [x] 1.2 Extend or wrap the AIResource schema to support optional `spec.scope` with allowed values `organization`, `product`, and `team` +- [x] 1.3 Add validation for `spec.scope` that reports field path, received value, and accepted values +- [ ] 1.4 Remove RHDH `spec.location` (types, schema, docs, examples) from AIResource OCI/git asset location support +- [ ] 1.5 Retool OCI validation to enforce `backstage.io/source-location` location-ref form `url:oci://…` (type `url`, target starts with `oci://` and is a well-formed OCI reference) +- [ ] 1.6 Ensure AIResource validation errors are actionable and can report multiple errors in one response +- [ ] 1.7 Add/update unit tests covering valid and invalid `spec.scope`, valid and invalid OCI source-location values (including bare `oci://…` without `url:`), and multi-error reporting ## 2. Catalog Ingestion - OCI Processor -- [ ] 2.1 Implement `AIResourceOciProcessor` as a `CatalogProcessor` that validates `spec.location.target` format only -- [ ] 2.2 Ensure the OCI processor makes zero outbound HTTP or network calls -- [ ] 2.3 Register `AIResourceOciProcessor` in the catalog backend module -- [ ] 2.4 Add unit tests covering valid OCI targets, malformed targets, and zero-network behavior +- [x] 2.1 Implement `AIResourceOciProcessor` as a `CatalogProcessor` with format-only validation and zero network calls _(initial `spec.location` version)_ +- [ ] 2.2 Retool `AIResourceOciProcessor` to validate OCI `backstage.io/source-location` targets instead of `spec.location.target` +- [ ] 2.3 Ensure the OCI processor makes zero outbound HTTP or network calls +- [ ] 2.4 Register/keep `AIResourceOciProcessor` in the catalog backend module under the updated contract +- [ ] 2.5 Add/update unit tests covering valid `url:oci://…` annotations, malformed targets, missing/`url:`-prefix cases, and zero-network behavior ## 3. Catalog Ingestion - Git Path & Registration -- [ ] 3.1 Verify git-backed AIResource entities ingest correctly through the existing `UrlReaderProcessor` -- [ ] 3.2 Verify a missing `backstage.io/source-location` annotation on a git entity produces a warning rather than an error -- [ ] 3.3 Verify AIResource entities are registrable through standard catalog registration and discovery flows -- [ ] 3.4 Add integration tests covering both git-backed and OCI-backed ingestion paths +- [x] 3.1 Verify git-backed AIResource entities ingest correctly through the existing `UrlReaderProcessor` +- [x] 3.2 Verify a missing `backstage.io/source-location` annotation on a git entity produces a warning rather than an error +- [x] 3.3 Verify AIResource entities are registrable through standard catalog registration and discovery flows +- [ ] 3.4 Add/update integration tests covering git/HTTPS source-location entities and OCI `url:oci://…` source-location entities (registration still via normal catalog locations) ## 4. Entity Detail Page - [ ] 4.1 Add AIResource kind support to the workspace entity page routing -- [ ] 4.2 Add an AIResource location display that renders git targets as links and OCI targets as copyable text +- [ ] 4.2 Display asset location from `backstage.io/source-location`: HTTPS/git targets as links; `oci://` targets as copyable text - [ ] 4.3 Ensure the standard relationships graph is present for AIResource entities - [ ] 4.4 Show a TechDocs tab when `backstage.io/techdocs-ref` is present and hide it when absent - [ ] 4.5 Add frontend tests covering location rendering, graph presence, and conditional TechDocs display ## 5. Discovery & Filtering -- [ ] 5.1 Verify AIResource entities are returned by `GET /api/catalog/entities?filter=kind=AIResource` +- [ ] 5.1 Verify AIResource entities are returned by `GET /api/catalog/entities?filter=kind=AIResource` (or upstream kind spelling used by the workspace) - [ ] 5.2 Verify by-name lookup for AIResource entities - [ ] 5.3 Verify filtering by `spec.type`, `spec.scope`, `spec.owner`, and `spec.lifecycle` - [ ] 5.4 Verify entities without `spec.scope` are excluded when a scope filter is applied @@ -42,12 +46,18 @@ ## 6. Documentation & Examples -- [ ] 6.1 Add an example git-backed AIResource `catalog-info.yaml` -- [ ] 6.2 Add an example OCI-backed AIResource `catalog-info.yaml` -- [ ] 6.3 Document schema fields and registration guidance in the workspace -- [ ] 6.4 Document the OCI validation-only behavior and its air-gap rationale +- [x] 6.1 Update the example git-backed AIResource `catalog-info.yaml` (source-location only; no `spec.location`) +- [x] 6.2 Update the example OCI-backed AIResource `catalog-info.yaml` to use `backstage.io/source-location: url:oci://…` +- [ ] 6.3 Document schema fields and registration guidance in the workspace (including why `url:` prefix is required) +- [ ] 6.4 Document the OCI validation-only behavior, air-gap rationale, and that an OCI UrlReader is deferred ## 7. Final Verification - [ ] 7.1 Walk through each scenario in the local AIResource specs against the implementation - [ ] 7.2 Update release-facing documentation if the feature ships from this workspace + +## Explicitly out of scope (do not implement in this change) + +- OCI `UrlReader` / registry content fetch +- Catalog location type `oci` / `readLocation` for discovering entities from OCI +- Custom AI catalog frontend beyond standard entity page adaptations above