Skip to content

RHIDP-15776: Align inherit matching with the operator - #4808

Merged
subhashkhileri merged 5 commits into
redhat-developer:mainfrom
subhashkhileri:rhidp-15776-operator-aligned-inherit
Sep 18, 2026
Merged

subhashkhileri merged 5 commits into
redhat-developer:mainfrom
subhashkhileri:rhidp-15776-operator-aligned-inherit

Conversation

@subhashkhileri

@subhashkhileri subhashkhileri commented Sep 16, 2026

Copy link
Copy Markdown
Member

Summary

This PR ports the operator's name-based OCI {{inherit}} lookup to the dynamic-plugins init container.

  • Resolve {{inherit}} by the final OCI image name, independent of registry host and namespace.
  • Replace the reference with the selected catalog entry's concrete registry, image, and version before normal merging.
  • Continue using the full resolved OCI identity for merge and enable/disable behavior; name-only identity is limited to reference lookup and ambiguity validation.
  • Reject ambiguous enabled images at the same merge level with an error that identifies both entries.
  • Prefer enabled candidates over disabled candidates with the same final image name.
  • Keep a unique disabled catalog entry eligible for a higher-precedence {{inherit}} entry to re-enable.
  • Preserve explicit !plugin-path behavior. Removing that syntax remains separate work in RHIDP-16807.

Problem

The init container previously keyed OCI plugins by their full registry URL. That made inheritance depend on the registry used at each deployment stage.

For example, a catalog might contain:

- package: oci://quay.io/rhdh/backstage-plugin-catalog:1.10.0!catalog-backend

while the deployment configuration contains:

- package: oci://registry.redhat.io/rhdh/backstage-plugin-catalog:{{inherit}}!catalog-backend

Both packages describe backstage-plugin-catalog, but the old full-URL lookup treated them as unrelated and failed with no existing plugin configuration found. This could abort the init container even though the catalog already provided the version to inherit.

Resolution behavior

The new flow mirrors the operator:

  1. Load the unfiltered included plugin catalogs.
  2. Extract the final OCI path segment from the {{inherit}} reference—for example, backstage-plugin-catalog.
  3. Find the matching included candidate by that name.
  4. Resolve the reference to the catalog candidate's concrete image and version.
  5. Apply the user's explicit !plugin-path, when present.
  6. Resume the existing merge and enable/disable processing using the resolved concrete OCI package.

For the example above, the main entry becomes:

- package: oci://quay.io/rhdh/backstage-plugin-catalog:1.10.0!catalog-backend

The registry written on the {{inherit}} reference is therefore only a lookup hint. The selected catalog entry remains the source of the concrete registry and version installed by the init container.

Candidate selection and ambiguity

Candidate selection is deterministic and follows the accepted compatibility rules:

  • Identical catalog candidates are deduplicated before ambiguity checks.
  • If one same-name candidate is enabled and another is disabled, the disabled candidate is ignored and the enabled candidate is selected.
  • If every same-name candidate is disabled, a single unambiguous candidate remains eligible so a higher-precedence entry can re-enable it.
  • Two enabled images with the same final OCI name at the same merge level are rejected because {{inherit}} cannot select one safely. The error names both conflicting packages and their source files.
  • An unresolved disabled pathless {{inherit}} entry remains a no-op and is removed by disabled filtering instead of aborting startup.
  • A disabled pathless reference that resolves to one concrete repository is resolved first, allowing it to disable all matching version and plugin-path variants across registries.

Explicit !plugin-path behavior

Existing explicit-path support is preserved:

  • Multiple entries from the same image remain distinct when their paths differ, such as bundle:1.0!plugin-a and bundle:1.0!plugin-b.
  • An explicit path on the user entry takes precedence over the included path.
  • If the requested custom path is not present in the catalog but the image match is otherwise unique, the resolved image/version is combined with the requested path, matching the operator.
  • In that custom-path case, the new path is a distinct plugin entry; the original included path remains unless it is separately disabled.

Example:

# Included catalog
- package: oci://quay.io/rhdh/plugin-bundle:1.0!plugin-a

# User configuration
- package: oci://registry.redhat.io/rhdh/plugin-bundle:{{inherit}}!custom-path

The result contains both:

- package: oci://quay.io/rhdh/plugin-bundle:1.0!plugin-a
- package: oci://quay.io/rhdh/plugin-bundle:1.0!custom-path

Compatibility

The following existing behavior is unchanged:

  • Ordinary non-{{inherit}} OCI entries continue to use their concrete registry, image, version, and plugin path for merging.
  • A higher-precedence main entry can still override an included entry after both resolve to the same concrete plugin identity.
  • Same-image entries with different explicit plugin paths remain supported.
  • NPM, local-package, integrity, image-download, and ref:// behavior is unaffected.

The intentional validation change required by RHIDP-15776 is that two enabled images at the same merge level cannot share the same final OCI image name, even when their registry hosts or namespaces differ. Such a catalog is ambiguous for host-independent {{inherit}} lookup and now fails with a diagnostic instead of relying on input order.

Acceptance criteria coverage

  • Derive the inheritance lookup name from the final OCI path segment.
  • Resolve {{inherit}} across registry host and namespace differences.
  • Detect same-level enabled name collisions and identify both entries.
  • Preserve explicit !plugin-path overrides and multi-plugin image entries.
  • Install from the concrete registry selected from the included catalog.
  • Document name-based lookup and the unique enabled-name requirement.
  • Cover cross-registry lookup, ambiguity, disabled candidates, overrides, digests, duplicate candidates, and custom paths with unit tests.

Validation

  • CI=true yarn test --runInBand — 20 suites, 275 tests passed
  • yarn tsc
  • yarn lint:all
  • yarn prettier:check
  • yarn workspace @red-hat-developer-hub/cli-module-install-dynamic-plugins build
  • yarn build:api-reports:only --ci

Related work

@subhashkhileri
subhashkhileri requested review from a team as code owners September 16, 2026 12:22
@rhdh-gh-app

rhdh-gh-app Bot commented Sep 16, 2026

Copy link
Copy Markdown

Important

This PR includes changes that affect public-facing API. Please ensure you are adding/updating documentation for new features or behavior.

Changed Packages

Package Name Package Path Changeset Bump Current Version
@red-hat-developer-hub/cli-module-install-dynamic-plugins workspaces/install-dynamic-plugins/packages/install-dynamic-plugins minor v0.5.0

@codecov

codecov Bot commented Sep 16, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 95.42484% with 7 lines in your changes missing coverage. Please review.
✅ Project coverage is 63.29%. Comparing base (d477924) to head (1334885).
⚠️ Report is 33 commits behind head on main.
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #4808      +/-   ##
==========================================
+ Coverage   63.26%   63.29%   +0.03%     
==========================================
  Files        2675     2675              
  Lines      106439   106553     +114     
  Branches    29767    29815      +48     
==========================================
+ Hits        67340    67447     +107     
- Misses      37320    37327       +7     
  Partials     1779     1779              
Flag Coverage Δ *Carryforward flag
adoption-insights 84.77% <ø> (ø) Carriedforward from ffa423b
ai-integrations 78.80% <ø> (ø) Carriedforward from ffa423b
app-defaults 54.82% <ø> (ø) Carriedforward from ffa423b
augment 46.67% <ø> (ø) Carriedforward from ffa423b
boost 84.97% <ø> (ø) Carriedforward from ffa423b
bulk-import 73.12% <ø> (ø) Carriedforward from ffa423b
cost-management 13.53% <ø> (ø) Carriedforward from ffa423b
dcm 73.47% <ø> (ø) Carriedforward from ffa423b
e2e-adoption-insights 60.00% <ø> (ø) Carriedforward from ffa423b
e2e-extensions 62.31% <ø> (ø) Carriedforward from ffa423b
e2e-global-header 49.71% <ø> (ø) Carriedforward from ffa423b
e2e-homepage 61.11% <ø> (ø) Carriedforward from ffa423b
e2e-intelligent-assistant 46.01% <ø> (ø) Carriedforward from ffa423b
e2e-orchestrator 49.49% <ø> (ø) Carriedforward from ffa423b
e2e-orchestrator-plugin 49.48% <ø> (ø) Carriedforward from ffa423b
e2e-quickstart 55.21% <ø> (ø) Carriedforward from ffa423b
e2e-scorecard 50.05% <ø> (ø) Carriedforward from ffa423b
e2e-theme 16.36% <ø> (ø) Carriedforward from ffa423b
extensions 58.30% <ø> (ø) Carriedforward from ffa423b
global-floating-action-button 71.18% <ø> (ø) Carriedforward from ffa423b
global-header 67.88% <ø> (ø) Carriedforward from ffa423b
homepage 48.39% <ø> (ø) Carriedforward from ffa423b
install-dynamic-plugins 73.52% <95.42%> (+1.74%) ⬆️
intelligent-assistant 77.99% <ø> (ø) Carriedforward from ffa423b
konflux 91.98% <ø> (ø) Carriedforward from ffa423b
lightspeed 69.02% <ø> (ø) Carriedforward from ffa423b
mcp-integrations 84.46% <ø> (ø) Carriedforward from ffa423b
orchestrator 77.32% <ø> (ø) Carriedforward from ffa423b
quickstart 63.74% <ø> (ø) Carriedforward from ffa423b
sandbox 79.56% <ø> (ø) Carriedforward from ffa423b
scorecard 88.48% <ø> (ø) Carriedforward from ffa423b
theme 87.91% <ø> (ø) Carriedforward from ffa423b
translations 5.12% <ø> (ø) Carriedforward from ffa423b
x2a 78.44% <ø> (ø) Carriedforward from ffa423b

*This pull request uses carry forward flags. Click here to find out more.


Continue to review full report in Codecov by Harness.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update d477924...1334885. Read the comment docs.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@subhashkhileri

Copy link
Copy Markdown
Member Author

/fs-review

@fullsend-ai-review

fullsend-ai-review Bot commented Sep 16, 2026

Copy link
Copy Markdown

🤖 Finished Review · ❌ Failure (agent timed out after 20m0s without completing (timeout: 20m0s)) · Started 12:42 PM UTC · Completed 1:04 PM UTC

Commit: 1e1c39a · View workflow run →

Runtime: claude · Model: opus → claude-opus-4-6

@subhashkhileri

Copy link
Copy Markdown
Member Author

/fs-review

@fullsend-ai-review

fullsend-ai-review Bot commented Sep 16, 2026

Copy link
Copy Markdown

🤖 Finished Review · ❌ Failure (agent timed out after 20m0s without completing (timeout: 20m0s)) · Started 2:53 PM UTC · Completed 3:16 PM UTC

Commit: 30dbd15 · View workflow run →

Runtime: claude · Model: opus → claude-opus-4-6

@subhashkhileri

Copy link
Copy Markdown
Member Author

/fs-review

@fullsend-ai-review

fullsend-ai-review Bot commented Sep 17, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 5:38 AM UTC · Completed 6:16 AM UTC

Commit: 30dbd15 · View workflow run →

Runtime: claude · Model: opus → claude-opus-4-6 · Cost: $13.38

subhashkhileri added a commit to subhashkhileri/rhdh-plugins that referenced this pull request Sep 17, 2026
Our code/fix/review harnesses pinned fullsend-ai/agents@4bbe4f50e, set
once in redhat-developer#4496 and never bumped — 794 commits behind main. Move to the
agents@v0 tag (7ab05564b, 794 commits later) to pick up two fixes
relevant to the /fs-review timeout on PR redhat-developer#4808 (run 35097265739):

- fullsend-ai/agents#1116 (PR redhat-developer#1181): sonnet-tier review sub-agents now
  request the bare `sonnet` alias, pinned via
  ANTHROPIC_DEFAULT_SONNET_MODEL=claude-sonnet-4-6 in env/gcp-vertex.env,
  instead of the hardcoded `claude-sonnet-4-6@default` literal our pin
  still carries. That literal was falling through the CLI's own alias
  resolution to claude-sonnet-4 (Sonnet 4.5 not available on our Vertex
  project), landing on a base model with a 120k output-tokens/min quota
  vs. 300k for sonnet-4-6 — three parallel sonnet sub-agents blew
  through it and all failed with 429 RESOURCE_EXHAUSTED.
- review harness timeout_minutes raised 20 -> 45, which independently
  would have absorbed the degraded run instead of hard-timing-out.

Scope: base: URL + content sha256 only. Our rhdh/policies/*.yaml
overrides are left as-is for now — upstream moved network policy from
policy: to composable providers:/openshell: profiles: in the interim
(ADR 0065), which likely makes the claude.exe allowlist in our policy
fork redundant (profiles/fullsend-vertex-ai.yaml already allowlists it
upstream), but retiring that fork is deferred to a follow-up so this
change stays a minimal, low-risk version bump.
subhashkhileri added a commit to subhashkhileri/rhdh-plugins that referenced this pull request Sep 17, 2026
Our code/fix/review harnesses pinned fullsend-ai/agents@4bbe4f50e, set
once in redhat-developer#4496 and never bumped — 794 commits behind main. Move to the
agents@v0 tag (7ab05564b, 794 commits later) to pick up two fixes
relevant to the /fs-review timeout on PR redhat-developer#4808 (run 35097265739):

- fullsend-ai/agents#1116 (PR redhat-developer#1181): sonnet-tier review sub-agents now
  request the bare `sonnet` alias, pinned via
  ANTHROPIC_DEFAULT_SONNET_MODEL=claude-sonnet-4-6 in env/gcp-vertex.env,
  instead of the hardcoded `claude-sonnet-4-6@default` literal our pin
  still carries. That literal was falling through the CLI's own alias
  resolution to claude-sonnet-4 (Sonnet 4.5 not available on our Vertex
  project), landing on a base model with a 120k output-tokens/min quota
  vs. 300k for sonnet-4-6 — three parallel sonnet sub-agents blew
  through it and all failed with 429 RESOURCE_EXHAUSTED.
- review harness timeout_minutes raised 20 -> 45, which independently
  would have absorbed the degraded run instead of hard-timing-out.

Scope: base: URL + content sha256 only. Our rhdh/policies/*.yaml
overrides are left as-is for now — upstream moved network policy from
policy: to composable providers:/openshell: profiles: in the interim
(ADR 0065), which likely makes the claude.exe allowlist in our policy
fork redundant (profiles/fullsend-vertex-ai.yaml already allowlists it
upstream), but retiring that fork is deferred to a follow-up so this
change stays a minimal, low-risk version bump.
@fullsend-ai-review

fullsend-ai-review Bot commented Sep 17, 2026

Copy link
Copy Markdown

Review

Findings

Medium

  • [scope-creep] workspaces/install-dynamic-plugins/packages/install-dynamic-plugins/src/merger.ts:582 — The new recordNameAtLevel function introduces same-level image-name collision detection for ALL OCI entries at every merge level, not only for {{inherit}} entries. Any existing configuration where two different registries contribute an entry whose final path segment matches (e.g., quay.io/team-a/catalog and registry.redhat.io/team-b/catalog both named catalog at the same level) will now receive a hard InstallException rather than proceeding silently. RHIDP-15776 is scoped to aligning {{inherit}} with the operator; the name-collision constraint expands the blast radius to all OCI configurations, including those that do not use {{inherit}}.
    Remediation: Confirm with the RHIDP-15776 ticket owner whether breaking existing non-inherit OCI configurations is an accepted consequence. If not, consider scoping recordNameAtLevel to only check packages that participate in {{inherit}} resolution, or gating the error behind a warning first.

Low

  • [edge-case] workspaces/install-dynamic-plugins/packages/install-dynamic-plugins/src/merger.ts:389 — In the preservePathless branch of resolveInheritPackage, same-registry candidates with different versions and different explicit paths trigger the ambiguity error with a misleading "must identify a single image" message rather than a version-specific message. Extremely contrived scenario requiring conflicting versions of the same image in an include list.

  • [missing-authorization] — No GitHub issue is linked. Authorization flows through Jira RHIDP-15776, which is not fetchable via the GitHub API, so the authorized scope cannot be independently verified.

  • [scope-creep] workspaces/install-dynamic-plugins/packages/install-dynamic-plugins/src/merger.ts:208 — The enabledReplacesDisabledAtSameLevel logic changes same-level duplicate handling for all OCI merging: an enabled entry can now silently replace a disabled one at the same level. This is logically required for the cross-registry re-enable use case but is a behavioral change to the core merge path that applies to all plugins.

  • [error-ordering] workspaces/install-dynamic-plugins/packages/install-dynamic-plugins/src/merger.ts:641processOciEntry calls recordNameAtLevel for all OCI entries including {{inherit}} tags in include files (level 0), so a name collision throws before the more specific "Cannot use {{inherit}} in included plugin configuration" error. Very unlikely configuration.

  • [test-coverage] workspaces/install-dynamic-plugins/packages/install-dynamic-plugins/src/resolve-inherit-plugins.test.ts:98 — Tests for disabled pathless {{inherit}} scenarios call preMergeOciDisabledState without the 4th mainPackagesForNameCollision argument, missing the pre-resolution package snapshot used in production.
    Remediation: Pass mainPackagesForNameCollision with pre-resolution package values in these tests to match the production calling convention.

  • [naming-convention] workspaces/install-dynamic-plugins/packages/install-dynamic-plugins/src/merger.ts:324 — New code uses a null byte (\0) as the delimiter in composite map keys, but the established entryKeyOf helper at line 490 uses a space. Inconsistent within the same file.
    Remediation: Use the same space separator established by entryKeyOf, or introduce a shared compositeKey(...parts) helper.

  • [code-organization] workspaces/install-dynamic-plugins/packages/install-dynamic-plugins/src/oci-key.ts:160isOciInherit mixes optional chaining (m?.[2]) with bare access (m[3]) in the same expression, unlike every other function in this file which uses an explicit if (!m) guard.
    Remediation: Use an explicit null guard: if (!m) return false; return m[2] === INHERIT_TAG && m[3] === undefined;


Next steps:

  • /fs-fix — agent addresses review findings automatically
  • /fs-fix <your instruction> — agent fixes with your specific guidance
  • Push commits directly — review re-runs automatically on push
  • /fs-fix-stop — disable automatic fix runs for this PR
Previous run

Review

Reason: stale-head

The review agent reviewed commit 4e545bd658c7e9bf5146c424101a19bd0ba15545 but the PR HEAD is now 30dbd15b1f3cd2f4c6216b9460df6d195356daf2. This review was discarded to avoid approving unreviewed code.

Previous run (2)

Review — comment

PR: RHIDP-15776: Align inherit matching with the operator
Scope: All 9 changed files are within workspaces/install-dynamic-plugins/, directly implementing the Jira intent. No scope creep detected.

Summary

This PR replaces the old same-registry {{inherit}} resolution with name-based lookup (final OCI path segment), aligning with the operator's behavior. The architectural approach is sound: separating pre-merge resolution (resolveInheritPlugins) from the merge pass, snapshotting user-declared packages before rewriting for collision detection, and adding recordNameAtLevel for same-level name collision detection.

The changeset bump level (minor) is correct for a user-visible behavioral change. Tests are comprehensive — the new resolve-inherit-plugins.test.ts provides integration-level coverage, and the rewritten merger-inherit.test.ts covers the core name-based lookup scenarios. The trust model change (include files as inheritance sources across registries) is adequately documented in the README and is consistent with the existing trust boundary (include files are already operator-controlled).

No critical or high findings. One medium observation about code maintainability, and several low-severity style/coverage notes.

Findings

Medium

1. Dual resolution path with divergent candidate sets (merger.ts)

resolveInheritPackage is callable from two sites with different candidate populations:

  • resolveInheritPlugins (installer.ts) — candidates from raw include lists, with sourceFile metadata
  • mergeOciPlugin (merger.ts) — candidates from Object.values(allPlugins), without sourceFile

In the normal loadAllPlugins flow, resolveInheritPlugins runs first and rewrites the package to a concrete URL, so mergeOciPlugin never sees parsed.inherit=true. The safety-net path in mergeOciPlugin is only reachable by direct mergePlugin callers (tests). This works correctly because includes are merged before main entries, but the candidate sets differ (merged entries vs. raw entries) and error messages lose sourceFile context.

Recommendation: Consider documenting the precondition that resolveInheritPlugins must run before mergePlugin for level > 0 inherit entries, or make the safety-net path throw a clear error stating pre-resolution was skipped.

Low

2. Missing test coverage for cross-version explicit-path inherit (merger-inherit.test.ts)

When candidates from the same registry have different versions (e.g., :1.0!plugin-a and :2.0!plugin-b), the image values differ, causing an ambiguity error when using {{inherit}}!custom-path. This is correct behavior but has no explicit test.

3. Dropped same-registry explicit override test (merger-inherit.test.ts)

The old test verifying that a main entry with an explicit tag correctly overrides an include's version on the same registry was removed without a direct replacement. The normal merge path is unmodified, so the risk is low, but the interaction boundary is worth covering.

4. ambiguousInheritError returns instead of throwing (merger.ts)

Every other error site in this file throws inline with throw new InstallException(...). The factory-return pattern diverges from the codebase idiom and is fragile — a caller omitting throw silently discards the error.

5. readonly T[] vs ReadonlyArray<T> inconsistency (merger.ts)

resolveInheritPackage uses readonly InheritCandidate[] while all other functions in the file use ReadonlyArray<T>.

6. Architecture table incomplete (README.md)

The architecture table does not mention plugin-name.ts (now critical to inheritance lookup) or the new resolveInheritPackage export in merger.ts.

Positive observations

  • Defense-in-depth: Explicit rejection of {{inherit}} in include files (level 0) narrows the attack surface.
  • Cross-registry collision detection correctly handles disabled/enabled ordering and avoids hiding enabled collisions behind disabled entries.
  • Pre-resolution snapshot (mainPackagesForNameCollision) correctly prevents synthetic collisions from inherit resolution rewriting the registry.
  • No cross-repo contract breakage: All new exports are module-internal. The preMergeOciDisabledState signature change is backward-compatible (optional parameter with default).
  • No stale references: All resolveInherit references are updated within the diff.
  • No security concerns: Include files are already trusted. The collision detection is sound defense-in-depth.
Previous run (3)

Review

This PR refactors {{inherit}} resolution from registry-based matching (full OCI URL) to name-based matching (final OCI path segment), aligning the CLI with the RHDH operator's behavior. The implementation is well-structured: resolveInheritPlugins cleanly mirrors the existing resolveRefPlugins pattern, the pre-merge collision detection adds necessary safety, and the test suite comprehensively covers the new behavior — including integration tests, cross-registry resolution, ambiguity detection, and disabled-base re-enabling.

The minor changeset classification is appropriate for a 0.x package. The removed tests are genuinely obsolete under the new matching semantics. Documentation updates in README.md accurately describe the new behavior.

Findings

Medium

1. False name-collision when mixing {{inherit}} and explicit-version entries (src/merger.ts, src/installer.ts)

resolveInheritPlugins() mutates plugin.package in place before preMergeOciDisabledState() runs. If the main config contains both a {{inherit}} entry and an explicit-version entry for the same image name from the same user-facing registry, the inherit resolution changes one entry's registry to the include's registry. Then recordNameAtLevel() sees two different registries with the same plugin name at level 1 and throws a spurious "Duplicate OCI plugin configurations" error — referencing a registry the user never wrote.

Example:

# Include
- package: oci://quay.io/rhdh/my-plugin:1.0!plugin-a

# Main
- package: oci://registry.redhat.io/rhdh/my-plugin:{{inherit}}!plugin-a  # resolves to quay.io
- package: oci://registry.redhat.io/rhdh/my-plugin:2.0!plugin-b          # stays registry.redhat.io
# → false collision: quay.io vs registry.redhat.io for name 'my-plugin'

Remediation: Either snapshot the original main packages before resolveInheritPlugins for the name-collision check, or skip recordNameAtLevel for entries whose package was rewritten by inherit resolution.

2. Name-based matching reduces registry isolation (by design) (src/merger.ts)

The old code scoped {{inherit}} resolution to the exact registry URL. The new code matches by image name across registries, allowing any same-named image in an include file to participate in resolution. This is an intentional design choice that aligns with the operator and the existing resolveRefPlugins pattern. The risk is mitigated by the fact that operators control include file contents and recordNameAtLevel detects same-level ambiguity. Noting for visibility since it changes the trust boundary of {{inherit}}.

Remediation: Document in operator-facing docs that include file contents directly influence cross-registry {{inherit}} resolution, and ensure only trusted include sources are configured.

Low

3. Stale reference to renamed function (src/installer-oci.ts:48)

Comment references the old function name resolveInherit, which this PR renames to resolveInheritPackage. The file is not in the diff.

4. Stale comment about matching semantics (src/oci-key.ts:80)

Comment says "The merger will match against an earlier included plugin from the same image" but matching is now by plugin name across registries, not by "same image."

5. Disabled-candidate asymmetry (src/merger.ts)

resolveInheritPackage() does not receive disabled/enabled status of candidates. When two include files provide the same-named plugin from different registries (one disabled), it throws an ambiguity error. By contrast, recordNameAtLevel() only warns in the same scenario. Passing the disabled flag through InheritCandidate would align the two checks.

6. Collision detection applies beyond {{inherit}} (src/merger.ts)

recordNameAtLevel() rejects same-level, same-name OCI images from different registries even when no {{inherit}} entry references them. This is a necessary consequence of name-based lookup but tightens the accepted input contract. Configurations with two different-registry images sharing a final name (previously valid) will now fail even without {{inherit}}.


Labels: PR modifies the install-dynamic-plugins workspace with a feature-level change to {{inherit}} resolution

fullsend-ai-review[bot]

This comment was marked as outdated.

@fullsend-ai-review fullsend-ai-review Bot added requires-manual-review Review requires human judgment install-dynamic-plugins enhancement New feature or request labels Sep 17, 2026
@subhashkhileri

Copy link
Copy Markdown
Member Author

/fs-review

@fullsend-ai-review

fullsend-ai-review Bot commented Sep 17, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 7:49 AM UTC · Completed 8:10 AM UTC

Commit: 84b8264 · View workflow run →

Runtime: claude · Model: opus → claude-opus-4-6 · Cost: $8.53

fullsend-ai-review[bot]

This comment was marked as outdated.

fullsend-ai-review[bot]

This comment was marked as outdated.

@fullsend-ai-review fullsend-ai-review Bot added requires-manual-review Review requires human judgment and removed requires-manual-review Review requires human judgment labels Sep 17, 2026
@subhashkhileri

Copy link
Copy Markdown
Member Author

/fs-review

@fullsend-ai-review

fullsend-ai-review Bot commented Sep 17, 2026

Copy link
Copy Markdown

🤖 Finished Review · ❌ Failure (agent timed out after 20m0s without completing (timeout: 20m0s)) · Started 8:21 AM UTC · Completed 8:43 AM UTC

Commit: 84b8264 · View workflow run →

Runtime: claude · Model: opus → claude-opus-4-6

@subhashkhileri subhashkhileri changed the title RHIDP-15776: Align inherit matching with the operator [WIP] RHIDP-15776: Align inherit matching with the operator Sep 17, 2026
durandom pushed a commit that referenced this pull request Sep 17, 2026
…4843)

Our code/fix/review harnesses pinned fullsend-ai/agents@4bbe4f50e, set
once in #4496 and never bumped — 794 commits behind main. Move to the
agents@v0 tag (7ab05564b, 794 commits later) to pick up two fixes
relevant to the /fs-review timeout on PR #4808 (run 35097265739):

- fullsend-ai/agents#1116 (PR #1181): sonnet-tier review sub-agents now
  request the bare `sonnet` alias, pinned via
  ANTHROPIC_DEFAULT_SONNET_MODEL=claude-sonnet-4-6 in env/gcp-vertex.env,
  instead of the hardcoded `claude-sonnet-4-6@default` literal our pin
  still carries. That literal was falling through the CLI's own alias
  resolution to claude-sonnet-4 (Sonnet 4.5 not available on our Vertex
  project), landing on a base model with a 120k output-tokens/min quota
  vs. 300k for sonnet-4-6 — three parallel sonnet sub-agents blew
  through it and all failed with 429 RESOURCE_EXHAUSTED.
- review harness timeout_minutes raised 20 -> 45, which independently
  would have absorbed the degraded run instead of hard-timing-out.

Scope: base: URL + content sha256 only. Our rhdh/policies/*.yaml
overrides are left as-is for now — upstream moved network policy from
policy: to composable providers:/openshell: profiles: in the interim
(ADR 0065), which likely makes the claude.exe allowlist in our policy
fork redundant (profiles/fullsend-vertex-ai.yaml already allowlists it
upstream), but retiring that fork is deferred to a follow-up so this
change stays a minimal, low-risk version bump.
@subhashkhileri

Copy link
Copy Markdown
Member Author

/fs-review

@fullsend-ai-review

fullsend-ai-review Bot commented Sep 17, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 12:03 PM UTC · Completed 12:35 PM UTC

Commit: 4e545bd · View workflow run →

Runtime: claude · Model: opus → claude-opus-4-6 · Effort: high · Cost: $10.73

@subhashkhileri
subhashkhileri force-pushed the rhidp-15776-operator-aligned-inherit branch from 4e545bd to 30dbd15 Compare September 17, 2026 12:30
@fullsend-ai-review fullsend-ai-review Bot added the risk/moderate PR risk: moderate label Sep 17, 2026
@fullsend-ai-review

fullsend-ai-review Bot commented Sep 17, 2026

Copy link
Copy Markdown

Risk Assessment: moderate (2/5)

Details

The PR is large in raw size (1301 lines, large blast radius across 9 files) but is well-mitigated by a 0.33 test file ratio, no protected paths, no security-sensitive or CI/dependency changes, low file churn, and minimal regression history, yielding a moderate composite risk.

Previous run

Risk Assessment: moderate (2/5)

Details

The PR touches 9 files with 1234 lines changed and a large blast radius within the install-dynamic-plugins workspace, but risk is moderated by good test coverage (ratio 0.33), no security-sensitive or protected-path changes, no CI modifications, low churn, and a familiar non-first-time author; three recent fix commits on core files in the past 90 days add a small regression signal.

@fullsend-ai-review

Copy link
Copy Markdown

/fs-review

@subhashkhileri
subhashkhileri force-pushed the rhidp-15776-operator-aligned-inherit branch from 4e545bd to 84b8264 Compare September 17, 2026 12:39
@subhashkhileri

Copy link
Copy Markdown
Member Author

/fs-review

@fullsend-ai-review

fullsend-ai-review Bot commented Sep 17, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 1:23 PM UTC · Completed 1:53 PM UTC

Commit: ffa423b · View workflow run →

Runtime: claude · Model: opus → claude-opus-4-6 · Effort: high · Cost: $10.36

@fullsend-ai-review fullsend-ai-review Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See the review comment for full details.

@fullsend-ai-review fullsend-ai-review Bot removed the requires-manual-review Review requires human judgment label Sep 17, 2026
@sonarqubecloud

Copy link
Copy Markdown

@subhashkhileri subhashkhileri changed the title [WIP] RHIDP-15776: Align inherit matching with the operator RHIDP-15776: Align inherit matching with the operator Sep 17, 2026
@subhashkhileri
subhashkhileri enabled auto-merge (squash) September 18, 2026 13:05
@subhashkhileri
subhashkhileri merged commit 8c84e6f into redhat-developer:main Sep 18, 2026
22 of 24 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request install-dynamic-plugins risk/moderate PR risk: moderate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants