feat(resolve): portable provider and profile definitions via URL references#3062
feat(resolve): portable provider and profile definitions via URL references#3062maruiz93 wants to merge 9 commits into
Conversation
|
🤖 Review · |
653f391 to
dcf40a7
Compare
PR Summary by QodoPortable provider/profile definitions via URL references (sha256-pinned)
AI Description
Diagram
High-Level Assessment
Files changed (13)
|
|
🤖 Finished Review · ✅ Success · Started 10:41 AM UTC · Completed 10:56 AM UTC |
Site previewPreview: https://98ff1f10-site.fullsend-ai.workers.dev Commit: |
ReviewThe branch was rebased since the prior review (SHA 8def383); all production code is unchanged. The prior HIGH finding (Validate() rejecting URL-based providers) remains fixed — the The Two medium-severity defense-in-depth gaps persist unchanged from prior reviews. Neither blocks the feature. FindingsMedium
Low
Previous runReviewThe only change since the prior review (SHA 215edb0) is commit 8def383 which adds unit tests for The prior HIGH finding (Validate() rejecting URL-based providers) remains fixed — the Two medium-severity defense-in-depth gaps persist unchanged from the prior review. Neither blocks the feature. FindingsMedium
Low
Previous runReviewThe only change since the prior review (SHA 215edb0) is commit 8def383 which adds unit tests for The prior HIGH finding (Validate() rejecting URL-based providers) remains fixed — the Two medium-severity defense-in-depth gaps persist unchanged from the prior review. Neither blocks the feature. FindingsMedium
Low
Previous run (2)ReviewThe prior HIGH finding (Validate() rejecting URL-based providers) remains fixed — the The persistent medium-severity defense-in-depth gap from prior reviews (missing validProviderName regex on URL-fetched providers) remains unchanged. One new medium finding was identified regarding FindingsMedium
Low
Previous run (3)ReviewThe prior HIGH finding (Validate() rejecting URL-based providers) remains fixed — the The persistent medium-severity defense-in-depth gap from prior reviews (missing validProviderName regex on URL-fetched providers) remains unchanged. One new medium finding was identified regarding FindingsMedium
Low
Previous run (4)ReviewThe two medium-severity defense-in-depth gaps from the prior review persist unchanged. No new blocking findings. The HIGH finding from earlier reviews (Validate() rejecting URL-based providers) remains fixed. The One new low-severity finding: the FindingsMedium
Low
Previous run (5)ReviewThe blocking HIGH finding from prior reviews — The deny-by-default enforcement in Two medium-severity defense-in-depth gaps remain from the prior review. Neither blocks the feature, but both should be tracked for follow-up. FindingsMedium
Low
Previous run (6)ReviewThe blocking HIGH finding from prior reviews — The deny-by-default enforcement in Two medium-severity defense-in-depth gaps remain from the prior review. Neither blocks the feature, but both should be tracked for follow-up. FindingsMedium
Low
Previous run (7)ReviewThe deny-by-default enforcement in However, the blocking validation bug that prevents URL-based providers from working end-to-end persists, URL-fetched provider definitions are still not validated against the FindingsHigh
Medium
Low
Previous run (8)ReviewThe deny-by-default enforcement in However, the blocking validation bug that prevents URL-based providers from working end-to-end persists, and URL-fetched provider definitions are still not validated against the FindingsHigh
Medium
Low
Previous run (9)ReviewThe deny-by-default enforcement in However, the blocking validation bug that prevents URL-based providers from working end-to-end persists, and URL-fetched provider definitions are still not validated against the FindingsHigh
Medium
Low
Previous run (10)ReviewThe doc-code-mismatch finding from the prior review has been fixed — user documentation now correctly shows the nested However, the blocking validation bug that prevents URL-based providers from working end-to-end persists, URL-fetched provider definitions are still not validated against the FindingsHigh
Medium
Low
|
|
Keeping warn-only as designed for Regarding All other findings addressed in 5bcc974:
|
dcf40a7 to
5bcc974
Compare
|
🤖 Finished Review · ❌ Failure · Started 3:45 PM UTC · Completed 4:00 PM UTC |
waynesun09
left a comment
There was a problem hiding this comment.
Review Squad Report — #3062
Agents dispatched: 5 (claude-coder ×2, claude-researcher, gemini-code-review, cursor-code-review)
Models used: Claude, Gemini, Codex
Total findings: 14 (after dedup + verification) — 6 posted inline (MEDIUM+)
False positives removed: 5
Summary
Solid, well-structured PR that cleanly extends the existing resolution system. The strongest finding is the incomplete reserved credential key blocklist (missing LD_AUDIT and TLS trust chain variables), which 4/5 agents flagged independently. The h.Profiles not being cleared after resolution is a real asymmetry with h.Providers that should be fixed for consistency. Remaining findings are hardening opportunities around error message clarity and warning-vs-error enforcement for literal credentials.
Assisted-by: Claude (review), Gemini (review), Codex (review)
|
Addressed findings from this review in 401384a:
Remaining low findings are either already addressed (ImportProfile duplicate check, ADR cross-refs) or intentional per ADR 0066 (WarnLiteralCredentials warn-only, checkProviderProfileIntegrity warn for no-profiles case, lock deps[len-1] pattern). |
|
🤖 Review · |
401384a to
5a56f20
Compare
|
🤖 Finished Review · ✅ Success · Started 10:06 AM UTC · Completed 10:20 AM UTC |
|
🤖 Finished Review · ✅ Success · Started 7:14 AM UTC · Completed 7:24 AM UTC |
6fab326 to
215edb0
Compare
|
🤖 Finished Review · ✅ Success · Started 7:32 AM UTC · Completed 7:46 AM UTC |
|
🤖 Finished Review · ✅ Success · Started 9:34 AM UTC · Completed 9:48 AM UTC |
Add Profiles []string field to Harness struct for URL-referenced openshell profile definitions. Extend ValidateResourceTypes to require integrity hashes on profile and provider URLs. Local provider names pass through unchanged. Signed-off-by: Marta Anon <manon@redhat.com>
Add profiles to mergeBaseIntoChild using the same concatenation pattern as skills and providers (base + child). Signed-off-by: Marta Anon <manon@redhat.com>
Add profile and provider URL resolution to ResolveHarness.
Profiles are fetched, cached, and validated for a non-empty id.
Provider URLs are fetched, cached, parsed as ProviderDef, and
removed from h.Providers (leaving only local names). Credential
values that don't look like ${VAR} references produce a warning.
Changes:
- Add ResolveResult struct containing Deps, Profiles, Providers
- Add ResolvedProfile and ResolvedProvider types
- Change ResolveHarness return type from ([]Dependency, error) to (ResolveResult, error)
- Add profile resolution loop that validates id field
- Add provider resolution loop that validates name/type and checks credentials
- Update all callers in internal/cli/run.go and internal/cli/lock.go
- Update all tests to use new return type
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Marta Anon <manon@redhat.com>
Add ImportProfile function that imports an openshell provider profile from a YAML file path. Treats 'already exists' as success for idempotent imports. Signed-off-by: Marta Anon <manon@redhat.com>
Import URL-resolved profiles to the gateway before provider creation. Merge URL-resolved providers with local definitions (local wins on name collision). Validate referential integrity: every provider type must match a declared profile id. Signed-off-by: Marta Anon <manon@redhat.com>
Extends ADR 0038 (URL harness access) and ADR 0065 (provider composition) with URL-resolvable profiles and providers. Adds profiles field, extends providers to accept URLs, defines referential integrity validation and base merge semantics. Signed-off-by: Marta Anon <manon@redhat.com>
- Rename profiles → openshell-profiles (YAML field, error messages, tests, ADR 0066) to disambiguate from overloaded "profile" term - Extend reservedCredentialKeys with IFS, CDPATH, DYLD_INSERT_LIBRARIES, JAVA_TOOL_OPTIONS, RUBYOPT, PERL5OPT - Add TestResolveHarness_ProviderURLMissingType for untested validation - Fix ImportProfile duplicate check: "profile already exists" instead of overly broad "duplicate" substring - Add ADR cross-references from 0024 and 0038 to 0066 - Clarify "policy" as "openshell policy" in ADR 0066 - Document openshell-profiles and URL-based providers in user guide - Add ImportProfile step to sandbox lifecycle in cli-internals.md 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>
- Pass URL-resolved provider names to CreateWithRetry so sandboxes can actually use them (critical bug fix) - Extend reservedCredentialKeys with LD_AUDIT, TLS trust chain vars, HOSTALIASES, PYTHONSTARTUP, GIT_CONFIG_GLOBAL, GIT_EXEC_PATH - Clear h.Profiles after resolution for consistency with h.Providers - Report all provider-profile integrity mismatches (not just first) with improved error message for gateway-resident profiles - Lock resolution now validates URLs against allowed_remote_resources Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Marta Anon <manon@redhat.com>
Cover three gaps found during test coverage review: - dedupResolvedProviders: empty, single, no-dups, last-wins (mirrors dedupResolvedProfiles) - ImportProfile: success, idempotent "already exists", other-error propagation - ParseProfileID: valid, missing id, invalid YAML, empty input Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Marta Anon <manon@redhat.com>
8def383 to
f839bdf
Compare
|
🤖 Finished Review · ✅ Success · Started 10:14 AM UTC · Completed 10:29 AM UTC |
waynesun09
left a comment
There was a problem hiding this comment.
Multi-agent review at HEAD f839bdf9. Findings were cross-checked against existing review threads; only unique MEDIUM+ items are posted inline below.
| for _, rp := range result.Profiles { | ||
| profileStart := time.Now() | ||
| printer.StepStart("Importing profile: " + rp.ID) | ||
| if err := sandbox.ImportProfile(ctx, rp.LocalPath); err != nil { |
There was a problem hiding this comment.
[HIGH] URL-resolved profiles are imported here (step 2c) before EnableProvidersV2() runs in step 2d. The pre-existing directory-profile import (ImportProfiles) deliberately runs after v2 is enabled inside the guarded block, and profiles are a providers-v2 concept (ADR 0065). Additionally, because the step 2d block is gated on len(h.Providers) > 0 || len(result.Providers) > 0, a harness that declares only openshell.profiles and no providers never enables providers-v2 at all — yet its profiles were already imported here.
Suggestion: Move EnableProvidersV2() ahead of this profile-import loop and extend the gate with || len(result.Profiles) > 0 so profiles-only harnesses still enable v2. A runAgent-level test for the profiles-only path would catch this ordering.
| // openshell exits non-zero when the profile already exists; | ||
| // treat this as success (idempotent import). | ||
| outStr := strings.ToLower(string(out)) | ||
| if strings.Contains(outStr, "profile already exists") { |
There was a problem hiding this comment.
[MEDIUM] ImportProfile treats "profile already exists" as success without updating. Since the cache is content-addressed by SHA-256, a changed profile with the same id is fetched to a new local path, but the gateway silently keeps the stale definition (old credential schema/endpoints). The directory flow (ImportProfiles) deletes by id and re-imports so content changes propagate; the URL flow does not. Low impact on fresh CI gateways, but a hard-to-diagnose staleness bug on persistent/local gateways.
Suggestion: Mirror the directory flow (delete by id, then re-import), or document that URL profile content changes require a gateway reset. Note also the idempotency substring here ("profile already exists") is narrower than the "already exists" match used by ImportProfiles.
| if reservedCredentialKeys[strings.ToUpper(k)] { | ||
| return fmt.Errorf("provider %q: credential key %q is a reserved environment variable name", name, k) | ||
| } | ||
| } |
There was a problem hiding this comment.
[MEDIUM] This reserved-credential-key rejection applies to all providers, not just URL-fetched ones — local providers/*.yaml definitions also flow through EnsureProvider (via mergeProviderDefs in run.go), and the check is case-insensitive. An existing local provider using a key like ENV, PATH, or HTTP_PROXY as a credential name now hard-fails where it previously worked, which contradicts ADR 0068's "Fully backwards-compatible" claim (the doc comment above frames the threat model as URL-fetched definitions).
Suggestion: Either scope the check to URL-resolved providers only, or keep the broader hardening and call it out in ADR 0068 / the changelog as an intentional behavior change with the list of blocked key names.
Summary
Closes #2672
Implements portable provider and profile definitions that can be referenced by URL with SHA-256 integrity hashing, extending the existing resource resolution system (ADRs 0038, 0045) to cover the full harness surface.
profilesfield (URL-only) and extendprovidersto accept mixed local/URL entries in harness schemafullsend run, withParseProfileIDvalidation andWarnLiteralCredentialsfor credential hygienesandbox.ImportProfileand create/update providers viasandbox.EnsureProviderwith reserved credential key validationTest plan
go test ./internal/resolve/— profile/provider resolution,ParseProfileID,WarnLiteralCredentialsgo test ./internal/harness/— profiles field validation,HasURLReferences, base composition mergego test ./internal/sandbox/—ImportProfile, reserved credential key rejectiongo test ./internal/cli/—dedupResolvedProfiles,mergeProviderDefs,checkProviderProfileIntegrity, lock file reconstructionmake lintpasses🤖 Generated with Claude Code