feat(compose): resolve local profiles and providers in base harness (#5240) - #5461
Conversation
PR Summary by QodoResolve local profiles/providers when composing and running base harnesses
AI Description
Diagram
High-Level Assessment
Files changed (9)
|
|
🤖 Review · |
84d4a79 to
1daf9b1
Compare
|
🤖 Finished Review · ✅ Success · Started 1:43 PM UTC · Completed 2:01 PM UTC |
Site previewPreview: https://e7dd77dc-site.fullsend-ai.workers.dev Commit: |
Code Review by Qodo
1.
|
ReviewFindingsMedium
Low
Previous runReviewFindingsLow
Previous run (2)ReviewReason: stale-head The review agent reviewed commit Previous run (3)ReviewFindingsLow
Previous run (4)ReviewFindingsLow
Previous run (5)ReviewFindingsLow
Previous run (6)ReviewFindingsLow
Previous run (7)ReviewFindingsLow
Previous run (8)ReviewFindingsLow
Previous run (9)ReviewFindingsLow
Previous run (10)ReviewFindingsLow
Previous run (11)ReviewFindingsMedium
Low
Previous run (12)ReviewFindingsMedium
Low
Previous run (13)ReviewFindingsLow
Previous run (14)ReviewFindingsLow
Previous run (15)ReviewFindingsLow
Previous run (16)ReviewFindingsLow
Previous run (17)ReviewFindingsLow
Previous run (18)ReviewFindingsHigh
Medium
Low
|
|
Didn't read anything yet: make sure you allow for overriding by the same name. We detected that problem with skills, in which if you wanted to override an existing skill you got an error. |
Already handled — child entries override base entries by name/ID using last-wins semantics:
Tests covering the compose override scenario: |
|
🤖 Finished Review · ❌ Failure · Started 2:45 PM UTC · Completed 3:26 PM UTC |
waynesun09
left a comment
There was a problem hiding this comment.
Multi-agent review — MEDIUM+ findings
Parallel review (Claude + Gemini agents). Posting only MEDIUM-and-above findings that are not already covered by existing comments. The already-flagged local providers dropped in the lock path issue (qodo bot at run.go:481) is still unresolved — note that the mechanism it describes (gated by len(result.Profiles)==0) no longer matches the current code, but the underlying bug persists in the reworked gate; see the inline notes below for the current form.
Inline comments cover: duplicate base-composed profiles (High), the Accepted-ADR rewrite policy violation (High), the untested merge design (Medium), and the hasLocalProviders absolute-path assumption (Medium).
[MEDIUM] test-coverage — No internal/cli test for the lock ↔ second-pass merge seam
The added tests exercise ResolveHarness, IsProviderPath, parseProviderDef, and ValidateFilesExist in isolation, but the diff touches no internal/cli/run_test.go or internal/cli/lock_test.go. The correctness bugs in the inline comments all live specifically in the resolveFromLock → hasLocalProviders → merge composition, which has zero coverage. Please add internal/cli integration tests over the matrix {lock, no-lock} × {base-composed, child-local} × {profile, provider}, asserting exactly one resolved entry per resource and no dropped local providers — these would fail today and pin the fixes.
25258f1 to
893ec29
Compare
|
🤖 Finished Review · ✅ Success · Started 3:52 PM UTC · Completed 4:12 PM UTC |
Superseded by updated review
waynesun09
left a comment
There was a problem hiding this comment.
Re-review at 893ec298 — the round of fixes doesn't close the blockers
Verified the pushed fixes against the current code (multi-agent, Claude + Gemini). One new top-level finding below; I've also replied in-thread to the ADR, profile-strip, and second-pass comments where the fix is incomplete or the premise is contested. Out of scope but worth noting: dedupResolvedProfiles/Providers (pre-existing, not in this diff) silently collapse two distinct entries sharing an id/name with no warning — unlike mergeProviderDefs, which surfaces a shadowed list. Consider a warning on content mismatch in a follow-up.
893ec29 to
afce4d8
Compare
|
🤖 Finished Review · ✅ Success · Started 2:53 PM UTC · Completed 3:11 PM UTC |
waynesun09
left a comment
There was a problem hiding this comment.
No major issues beyond the ADR number collision (0074 duplicates the already-merged repos-command-consolidation ADR — confirmed live via git merge-base, and CI's own lint-adr-numbers check is failing on it right now). That's a required check, so the merge queue already blocks this from landing until it's renumbered (suggest 0082, next free slot) — not gating approval on it separately. Renumber-adr skill covers the workflow: update the file, its title, ADR 0070's cross-reference, and any doc mentions.
|
🤖 Finished Review · ✅ Success · Started 2:40 PM UTC · Completed 2:56 PM UTC |
Extend base composition to resolve local profile and provider paths relative to the base URL, matching existing behavior for agent, policy, skills, scripts, and host_files. - Add resolveBaseProfiles() to fetch and cache profiles from URL bases - Add resolveBaseProviders() to fetch and cache providers from URL bases - Wire both functions into loadBaseChain and LoadWithBase SourceURL path - Update validation to allow local profile paths (not just URLs) - Update provider validation to skip path validation for file paths - Fix HasRemoteResources to check profile URLs individually - Add comprehensive tests for profile and provider resolution Issue #5240 Signed-off-by: Marta Anon <manon@redhat.com>
Add profiles and providers to relative path resolution. Bare provider names (without "/" or .yaml/.yml suffix) are left unchanged. Issue #5240 Signed-off-by: Marta Anon <manon@redhat.com>
Update ResolveHarness to resolve local profile paths (reading content and extracting ID) and absolute-path providers (parsing ProviderDef). Bare provider names are kept for LoadProviderDefs. Issue #5240. Signed-off-by: Marta Anon <manon@redhat.com>
Fix two issues in harness resolution: 1. Local-only profiles were silently dropped when ResolveHarness wasn't called. Added a post-URL-references block in run.go to call ResolveHarness for local profiles/providers even when no URL references exist. Added hasLocalProviders helper to detect absolute path providers. 2. resolveBaseProviders in compose.go lacked bare-name heuristic, which could cause 404s when URL-fetched bases had bare provider names like "fullsend-github". Added skip logic matching the heuristic in ResolveRelativeTo (no "/" and no .yaml/.yml extension). Added TestLoadWithBase_URLBase_BareProviderNameSkipped to verify bare provider names are preserved while relative paths are fetched. Signed-off-by: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Marta Anon <manon@redhat.com>
The local-only ResolveHarness fallback was gated on len(result.Profiles)==0, skipping it when the lock-file already produced profiles, leaving absolute-path providers unresolved. - Remove the profile-count guard; run whenever local profiles or providers exist, merge all result fields - Strip absolute-path provider entries in resolveFromLock - Preserve local-path profiles in resolveFromLock instead of unconditionally niling them Signed-off-by: Marta Anon <manon@redhat.com>
Signed-off-by: Marta Anon <manon@redhat.com>
Signed-off-by: Marta Anon <manon@redhat.com>
The lock strip was removing all path entries (absolute paths and provider paths), which silently dropped local-path profiles/providers that had no corresponding lock deps. Now only URL entries are stripped in resolveFromLock; path entries survive for the second ResolveHarness pass. Path providers are stripped from h.Providers after resolution to keep sandboxProviderNames clean. Signed-off-by: Marta Anon <maruiz93@users.noreply.github.com> Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Marta Anon <manon@redhat.com>
ADR 0070 restricted profiles to URL-only. ADR 0074 extends both profiles and providers to accept local file paths, matching all other harness resource fields. Marks 0070 as superseded. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Marta Anon <manon@redhat.com>
- Add defense-in-depth containment check for local profile/provider file reads in ResolveHarness, verifying paths are under WorkspaceRoot before calling os.ReadFile - Fix misleading comment in Validate() that claimed provider paths are validated by ValidateResourceTypes (they are actually validated downstream by ResolveHarness/parseProviderDef) Addresses review feedback on #5461
Add tests for resolveBaseProfiles and resolveBaseProviders in compose.go covering all code paths: empty/nil inputs, URL/cache/empty skips, path traversal and null byte rejection, invalid base URL errors, and integration through LoadWithBase for both URL base and SourceURL flows. Add error-path tests for local profile/provider resolution in resolve.go: read failures, parse errors, and missing profile ID. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Marta Anon <manon@redhat.com>
Update cli-internals flowchart and architecture overview to reflect that profiles and providers can now be local file paths, not just URLs. Update ADR reference from 0070 to 0074. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Marta Anon <manon@redhat.com>
Local-path profiles from base composition lose the .yaml extension because fetchBaseFile stores cached files as extensionless "content" entries. The URL branch already applied CacheNamedSymlink, but the local-path branch did not. Add extension check and symlink creation for extensionless cache paths, with regression tests. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Marta Anon <manon@redhat.com>
- Resolve symlinks in isContainedPath to prevent escape via symlinked profile/provider paths; change empty-root from fail-open to fail-closed - Gate CacheNamedSymlink on cache-path check so extensionless local profiles don't get stray symlinks written into the user's repo - Remove unreachable ValidateFilesExist profile/provider loops (existence errors already surface via ResolveHarness's os.ReadFile) - Add local file-path examples to providers documentation - Make openshell test stub extension-aware (rejects --file without .yaml/.yml extension) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Marta Anon <manon@redhat.com>
- Add FromURL field to ResolvedProvider/ResolvedProfile to distinguish URL-resolved from local-path entries - Update checkProviderProfileIntegrity to skip local-path providers, preventing misleading errors for gateway-resident provider types - Add .yaml/.yml extension validation for local profile paths in ValidateResourceTypes (user-authored relative paths only) - Update ADR 0074 validation/security sections to reflect actual enforcement via isContainedPath and ResolveHarness Signed-off-by: Marta Anon <marta@fullsend.ai> Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Marta Anon <manon@redhat.com>
ADR 0074 was taken by repos-command-consolidation on main while this branch was in flight. Renumber our local-path-profiles-providers ADR to 0075 and update all cross-references. Signed-off-by: Marta Anon <manon@redhat.com>
|
/fs-review |
|
🤖 Review · |
|
🤖 Finished Review · ✅ Success · Started 3:04 PM UTC · Completed 3:25 PM UTC |
|
Re: validation relaxations (fail-open-validation profiles, fail-open providers) Intentional — |
|
Re: security defense-in-depth (TOCTOU in isContainedPath, resolve closure surface) Acknowledged. The TOCTOU window in |
With local-path profile support, profiles are no longer always URLs. The len() > 0 check from main's plugin merge incorrectly treated local-path profiles as URL references, breaking HasURLReferences for harnesses with only local profiles. Signed-off-by: Marta Anon <manon@redhat.com>
|
Addressed review findings in c23cdcb:
|
|
🤖 Finished Review · ✅ Success · Started 4:23 PM UTC · Completed 4:42 PM UTC |
|
🤖 Finished Retro · ✅ Success · Started 5:20 PM UTC · Completed 5:38 PM UTC |
|
PR #5461 added local file-path support for profiles and providers in harness resolution (issue #5240). Human-authored (maruiz93), reviewed over 14 days by waynesun09 (human) and fullsend-ai-review[bot]. 22 files changed, +1,726/−786 lines. Agents repo: Review qualityThe human reviewer found 5 HIGH-severity bugs the review agent missed across 22 successful passes: (1) symlink containment bypass in The review agent contributed findings the human did not raise: PR title Fix agentRan once (Jul 28), correctly addressed 2 review agent findings and declined 1 cosmetic rename. Its Token cost30 review runs over 14 days, triggered by every push (8+), every human review event, and manual Existing issue evidence (no new proposals — all gaps have existing coverage)
Autonomy readinessThis PR demonstrates the review agent should not be trusted for autonomous approval on complex Go PRs involving path operations, multi-pass resolution with field lifecycle management, or base composition with provenance tracking. The human reviewer was essential — 5 HIGH-severity bugs (including a security-relevant symlink bypass) would have shipped without human review. |
Summary
resolveBaseProfilesandresolveBaseProvidersto harness composition so local paths in base harnesses are fetched and cached, matching existing behavior for skills, agent, policy, and scriptsIsProviderPathhelper to distinguish bare provider names (e.g.fullsend-github) from file paths, consolidating a heuristic previously duplicated in 3 locationsparseProviderDefhelper to deduplicate provider YAML validation between local-path and URL branchesWarningsfield toResolveResultso credential warnings from local providers surface to the userrun.gowith result merging to preserve lock-file deps/providersFromURLorigin marker toResolvedProvider/ResolvedProfilesocheckProviderProfileIntegritycan distinguish URL-resolved from local-path providers.yaml/.ymlextension validation for local profile paths inValidateResourceTypesCloses #5240
Test plan
TestResolveBaseProfiles— 5 cases: URL, relative, absolute, mixed, emptyTestResolveBaseProviders— 6 cases: URL, bare name, relative path, absolute, mixed, emptyTestIsProviderPath— 9 cases covering bare names, slashes, YAML extensionsTestParseProviderDef— 7 cases: valid, missing name/type, invalid chars, credential warningTestResolveHarness_LocalProviderWarnings— end-to-end warning propagationTestValidateFilesExist_BareProviderNameSkipped— bare provider names not file-checkedTestResolveHarness_LocalProfileReadError/TestResolveHarness_LocalProviderReadError— missing-file errors fromResolveHarnessTestCheckProviderProfileIntegrity— local-path providers skipped, mixed URL+local, mismatchesTestValidateResourceTypes_ProfilesRequireYAMLExtension— extensionless profile paths rejectedgo test ./internal/harness/... ./internal/resolve/...)🤖 Generated with Claude Code