Skip to content

Commit

Permalink
Validate remote PluginConfigs are present in buf.lock
Browse files Browse the repository at this point in the history
  • Loading branch information
emcfarlane committed Dec 10, 2024
1 parent 3843927 commit be1fc43
Show file tree
Hide file tree
Showing 6 changed files with 57 additions and 22 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
file. Only WebAssembly check plugins are supported at this time.
- Add `buf registry plugin commit {add-label,info,list,resolve}` to manage BSR plugin commits.
- Add `buf registry plugin label {archive,info,list,unarchive}` to manage BSR plugin commits.
- Support remote check plugins in `buf lint` and `buf breaking` commands.

## [v1.47.2] - 2024-11-14

Expand Down
53 changes: 44 additions & 9 deletions private/buf/bufctl/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,8 +133,9 @@ type Controller interface {
// GetCheckRunnerProvider gets a CheckRunnerProvider for the given input.
//
// The returned RunnerProvider will be able to run lint and breaking checks
// using the PluginConfigs from the input. The input provided will resolve
// the PluginKeys from the related buf.lock file.
// using the PluginConfigs declared in the input buf.yaml. The input
// provided will resolve to a Workspace, and the remote PluginConfigs
// Refs will be resolved to the PluginKeys from the buf.lock file.
GetCheckRunnerProvider(
ctx context.Context,
input string,
Expand Down Expand Up @@ -1201,32 +1202,44 @@ Declare %q in the deps key in your buf.yaml.`,

// getPluginKeyProviderForRef create a new PluginKeyProvider for the Ref.
//
// Remote plugins Refs are resolved to PluginKeys from the workspace buf.lock file.
// If the Ref is a MessageRef, we use the current directory buf.lock file.
// The Ref is resolved to a Workspace. The Workspaces PluginConfigs from the
// buf.yaml file and the PluginKeys from the buf.lock are resolved to create the
// PluginKeyProvider.
// If the Ref is a MessageRef, the current directory buf.lock file is used.
//
// PluginConfigs are validated to ensure that all remote PluginConfigs are
// pinned in the buf.lock file.
func (c *controller) getPluginKeyProviderForRef(
ctx context.Context,
ref buffetch.Ref,
functionOptions *functionOptions,
) (_ bufplugin.PluginKeyProvider, retErr error) {
var (
pluginConfigs []bufconfig.PluginConfig
pluginKeys []bufplugin.PluginKey
)
switch t := ref.(type) {
case buffetch.ProtoFileRef:
workspace, err := c.getWorkspaceForProtoFileRef(ctx, t, functionOptions)
if err != nil {
return nil, err
}
return bufplugin.NewStaticPluginKeyProvider(workspace.RemotePluginKeys())
pluginConfigs = workspace.PluginConfigs()
pluginKeys = workspace.RemotePluginKeys()
case buffetch.SourceRef:
workspace, err := c.getWorkspaceForSourceRef(ctx, t, functionOptions)
if err != nil {
return nil, err
}
return bufplugin.NewStaticPluginKeyProvider(workspace.RemotePluginKeys())
pluginConfigs = workspace.PluginConfigs()
pluginKeys = workspace.RemotePluginKeys()
case buffetch.ModuleRef:
workspace, err := c.getWorkspaceForModuleRef(ctx, t, functionOptions)
if err != nil {
return nil, err
}
return bufplugin.NewStaticPluginKeyProvider(workspace.RemotePluginKeys())
pluginConfigs = workspace.PluginConfigs()
pluginKeys = workspace.RemotePluginKeys()
case buffetch.MessageRef:
bucket, err := c.storageosProvider.NewReadWriteBucket(
".",
Expand All @@ -1247,10 +1260,11 @@ func (c *controller) getPluginKeyProviderForRef(
}
// We did not find a buf.yaml in our current directory,
// and there was no config override.
// Remote plugins are not available.
return bufplugin.NopPluginKeyProvider, nil
}
var pluginKeys []bufplugin.PluginKey
if bufYAMLFile.FileVersion() == bufconfig.FileVersionV2 {
pluginConfigs = bufYAMLFile.PluginConfigs()
bufLockFile, err := bufconfig.GetBufLockFileForPrefix(
ctx,
bucket,
Expand All @@ -1267,11 +1281,32 @@ func (c *controller) getPluginKeyProviderForRef(
}
pluginKeys = bufLockFile.RemotePluginKeys()
}
return bufplugin.NewStaticPluginKeyProvider(pluginKeys)
default:
// This is a system error.
return nil, syserror.Newf("invalid Ref: %T", ref)
}
// Validate that all remote PluginConfigs are present in the buf.lock file.
pluginKeysByFullName, err := slicesext.ToUniqueValuesMap(pluginKeys, func(pluginKey bufplugin.PluginKey) string {
return pluginKey.FullName().String()
})
if err != nil {
return nil, fmt.Errorf("failed to validate remote PluginKeys: %w", err)
}
// Remote PluginConfig Refs are any PluginConfigs that have a Ref.
remotePluginRefs := slicesext.Filter(
slicesext.Map(pluginConfigs, func(pluginConfig bufconfig.PluginConfig) bufparse.Ref {
return pluginConfig.Ref()
}),
func(pluginRef bufparse.Ref) bool {
return pluginRef != nil
},
)
for _, remotePluginRef := range remotePluginRefs {
if _, ok := pluginKeysByFullName[remotePluginRef.FullName().String()]; !ok {
return nil, fmt.Errorf(`remote plugin %q is not in the buf.lock file, use "buf plugin update" to pin remote refs`, remotePluginRef)
}
}
return bufplugin.NewStaticPluginKeyProvider(pluginKeys)
}

// handleFileAnnotationSetError will attempt to handle the error as a FileAnnotationSet, and if so, print
Expand Down
3 changes: 2 additions & 1 deletion private/buf/buflsp/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import (
"github.com/bufbuild/buf/private/bufpkg/bufcheck"
"github.com/bufbuild/buf/private/bufpkg/bufimage"
"github.com/bufbuild/buf/private/bufpkg/bufmodule"
"github.com/bufbuild/buf/private/bufpkg/bufplugin"

Check failure on line 35 in private/buf/buflsp/file.go

View workflow job for this annotation

GitHub Actions / buf-binary-size

"github.com/bufbuild/buf/private/bufpkg/bufplugin" imported and not used

Check failure on line 35 in private/buf/buflsp/file.go

View workflow job for this annotation

GitHub Actions / test-previous (1.22.x)

"github.com/bufbuild/buf/private/bufpkg/bufplugin" imported and not used

Check failure on line 35 in private/buf/buflsp/file.go

View workflow job for this annotation

GitHub Actions / test

"github.com/bufbuild/buf/private/bufpkg/bufplugin" imported and not used

Check failure on line 35 in private/buf/buflsp/file.go

View workflow job for this annotation

GitHub Actions / lint

"github.com/bufbuild/buf/private/bufpkg/bufplugin" imported and not used

Check failure on line 35 in private/buf/buflsp/file.go

View workflow job for this annotation

GitHub Actions / test

"github.com/bufbuild/buf/private/bufpkg/bufplugin" imported and not used
"github.com/bufbuild/buf/private/pkg/git"
"github.com/bufbuild/buf/private/pkg/ioext"
"github.com/bufbuild/buf/private/pkg/normalpath"
Expand Down Expand Up @@ -373,7 +374,7 @@ func (f *file) FindModule(ctx context.Context) {
}

// Get the check runner provider for this file. The client is scoped to
// the input Buf lock file, so we need to get the check runner provider
// the inputs buf.lock file, so we need to get the check runner provider
// for the workspace that contains this file.
checkRunnerProvider, err := f.lsp.controller.GetCheckRunnerProvider(ctx, f.uri.Filename(), f.lsp.wasmRuntime)
if err != nil {
Expand Down
4 changes: 2 additions & 2 deletions private/buf/bufworkspace/workspace_provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -405,8 +405,8 @@ func (w *workspaceProvider) getWorkspaceForBucketAndModuleDirPathsV1Beta1OrV1(
return w.getWorkspaceForBucketModuleSet(
moduleSet,
v1WorkspaceTargeting.bucketIDToModuleConfig,
nil, // No plugin configs for v1
nil, // No remote plugin keys for v1
nil, // No PluginConfigs for v1
nil, // No remote PluginKeys for v1
v1WorkspaceTargeting.allConfiguredDepModuleRefs,
false,
)
Expand Down
2 changes: 1 addition & 1 deletion private/bufpkg/bufcheck/runner_provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ func newRemoteWasmPluginRunner(
) (*remoteWasmPluginRunner, error) {
pluginRef := pluginConfig.Ref()
if pluginRef == nil {
return nil, syserror.Newf("Ref nil on PluginConfig of type %v", bufconfig.PluginConfigTypeRemoteWasm)
return nil, syserror.Newf("Ref nil on PluginConfig of type %v", pluginConfig.Type())
}
return &remoteWasmPluginRunner{
wasmRuntime: wasmRuntime,
Expand Down
16 changes: 7 additions & 9 deletions private/bufpkg/bufplugin/plugin_key_provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,13 +59,8 @@ func NewStaticPluginKeyProvider(pluginKeys []PluginKey) (PluginKeyProvider, erro
if err != nil {
return nil, err
}
digetType, err := UniqueDigestTypeForPluginKeys(pluginKeys)
if err != nil {
return nil, err
}
return staticPluginKeyProvider{
pluginKeysByFullName: pluginKeysByFullName,
digestType: digetType,
}, nil
}

Expand All @@ -83,17 +78,13 @@ func (nopPluginKeyProvider) GetPluginKeysForPluginRefs(

type staticPluginKeyProvider struct {
pluginKeysByFullName map[string]PluginKey
digestType DigestType
}

func (s staticPluginKeyProvider) GetPluginKeysForPluginRefs(
_ context.Context,
refs []bufparse.Ref,
digestType DigestType,
) ([]PluginKey, error) {
if digestType != s.digestType {
return nil, fmt.Errorf("expected DigestType %v, got %v", s.digestType, digestType)
}
pluginKeys := make([]PluginKey, len(refs))
for i, ref := range refs {
// Only the FullName is used to match the PluginKey. The Ref is not
Expand All @@ -103,6 +94,13 @@ func (s staticPluginKeyProvider) GetPluginKeysForPluginRefs(
if !ok {
return nil, fs.ErrNotExist
}
digest, err := pluginKey.Digest()
if err != nil {
return nil, err
}
if digest.Type() != digestType {
return nil, fmt.Errorf("expected DigestType %v, got %v", digestType, digest.Type())
}
pluginKeys[i] = pluginKey
}
return pluginKeys, nil
Expand Down

0 comments on commit be1fc43

Please sign in to comment.