Skip to content

Add extensible source providers - #429

Merged
ashutosh-narkar merged 1 commit into
open-policy-agent:mainfrom
ashutosh-narkar:ext-source-provider
Sep 30, 2026
Merged

ashutosh-narkar merged 1 commit into
open-policy-agent:mainfrom
ashutosh-narkar:ext-source-provider

Conversation

@ashutosh-narkar

@ashutosh-narkar ashutosh-narkar commented Sep 28, 2026 •

Copy link
Copy Markdown
Member

Why

OCP's source types are hard-coded. Projects that embed OCP as a
library and need to build bundles from other kinds of sources currently
have to fork OCP or upstream every new type.

This adds a way to register custom source types programmatically. Providers are
Go code registered through the public API of pkg/service. They then work like
the built-in sources: they're configured on a source, synced by the bundle workers,
and built into the same bundles.

Some changes

  • pkg/sync: SourceProvider and SourceProviderRegistry. A provider
    declares its Type, a JSON Schema for its configuration, Parse for
    validation, and New to create a Synchronizer. Its synchronizer can
    optionally implement BundleContributor to add manifest metadata, claim
    roots it has no files for, or set the Rego version of its content.
  • Config: a providers: list on sources. name and type are
    required; path optionally prefixes the entry's content; all other keys
    go to the provider.
  • Persistence: a new sources_providers table (migration 29). As with
    requirements, a source without providers leaves stored entries in place,
    and providers: [] removes them.
  • Breaking change: pkg/sync.Synchronizer.Execute now returns
    (map[string]any, error) instead of error.

Example

Registering a provider:

reg := pkgsync.NewSourceProviderRegistry()
if err := reg.Register(myprovider.New()); err != nil { // Type() == "my-source"
    return err
}

svc := service.New().
    WithConfig(cfg).
    WithSourceProviders(reg)

Using it in a source:

sources:
  app:
    git:
      repo: https://github.com/example/policies.git
    providers:
      - name: users
        type: my-source
        path: users          # data files go under data.users
        endpoint: https://example.com/users

bundles:
  app:
    requirements:
      - source: app
    revision: $"{input.sources.app.git.commit}-{input.sources.app.providers.users.version}"

Fixes: #361

@ashutosh-narkar
ashutosh-narkar marked this pull request as ready for review September 28, 2026 22:08

@srenatus srenatus left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Small fry only, thanks!

providers:
- name: users
type: example.custom-source
param1: value

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Would it be possible to have a provider registered for E2E test purposes? So we could have a positive tests here, too.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Added tests.

Comment thread internal/migrations/migrations.go Outdated
@@ -46,6 +46,7 @@ func Migrations(dialect string) (fs.FS, error) {
addSourcesGitCredentialsName(25, dialect),
addBundlesStatuses(26, dialect),
addBundlesStatusesUpdatedAt(27, dialect), // adds 2, next is 29.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
addBundlesStatusesUpdatedAt(27, dialect), // adds 2, next is 29.
addBundlesStatusesUpdatedAt(27, dialect),

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Done.

Comment thread pkg/builder/contribution_test.go Outdated
return config.Requirement{Source: &name, Path: path, Prefix: prefix}
}

func intPtr(i int) *int { return &i }

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[nit] So we still need this these days? new(10) might do the same 🤔

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Updated.

Comment thread pkg/builder/builder.go

// If any source manifest specifies roots, use those. Log if they differ from computed.
for _, m := range sourceManifests {
manifestRootsFrom := "" // source whose .manifest roots replaced the computed ones

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

nested claimed roots fail when a .manifest sets roots. One provider claims ["lazy/users", "lazy"], and another source's .manifest sets roots: ["app"]. The build fails with:

source "provider" claims root "lazy", which overlaps root "lazy/users" from the .manifest of source "git"

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Good catch. Fixed and added tests to cover this.

@srenatus srenatus left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thanks!

OCP's source types are hard-coded. Projects that embed OCP as a
library and need to build bundles from other kinds of sources currently
have to fork OCP or upstream every new type.

This adds a way to register custom source types programmatically. Providers are
Go code registered through the public API of pkg/service. They then work like
the built-in sources: they're configured on a source, synced by the bundle workers,
and built into the same bundles.

Fixes: open-policy-agent#361

Signed-off-by: Ashutosh Narkar <anarkar4387@gmail.com>
@ashutosh-narkar
ashutosh-narkar merged commit a8aed0b into open-policy-agent:main Sep 30, 2026
13 of 14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Extensible Source Providers

2 participants