Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement plugin manager #37

Merged
merged 14 commits into from
May 4, 2022
Merged

Implement plugin manager #37

merged 14 commits into from
May 4, 2022

Conversation

qmuntal
Copy link
Contributor

@qmuntal qmuntal commented Apr 26, 2022

This PR implements the common code of the plugin-extensibility spec so it will be used by notary and others.

The Manager implementation will probably change once notaryproject/notation#167 is discussed.

It also contains unit test and integration tests with ad-hoc plugins. Coverage is around 95%.

@SteveLasker

Signed-off-by: qmuntal qmuntaldiaz@microsoft.com

Signed-off-by: qmuntal <qmuntaldiaz@microsoft.com>
@qmuntal qmuntal requested a review from a team April 26, 2022 18:54
Signed-off-by: qmuntal <qmuntaldiaz@microsoft.com>
Signed-off-by: qmuntal <qmuntaldiaz@microsoft.com>
Signed-off-by: qmuntal <qmuntaldiaz@microsoft.com>
Copy link
Contributor

@SteveLasker SteveLasker left a comment

Choose a reason for hiding this comment

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

Great to get the baseline in, as we continue to iterate.

@gokarnm
Copy link

gokarnm commented Apr 27, 2022

cc: @rgnote @shizhMSFT for review.

Description string `json:"description"`
Version string `json:"version"`
URL string `json:"url"`
SupportedContractVersions []string `json:"supported-contract-versions"`
Copy link
Contributor

Choose a reason for hiding this comment

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

supported-contract-versions

Should it be supportedContractVersions?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good catch!

Copy link
Contributor

@rgnote rgnote left a comment

Choose a reason for hiding this comment

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

Overall, looks solid

plugin/plugin.go Outdated
// MetadataSubcommandName is the name of the plugin subcommand
// which must be supported by every plugin and returns the
// plugin metadata.
MetadataSubcommandName = "get-plugin-metadata"
Copy link
Contributor

Choose a reason for hiding this comment

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

Isn't this discover?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We changed it to get-plugin-metadata in notaryproject/specifications#150

return cmd.Output()
}

type rootedFS struct {
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: doc comment

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done!

Signed-off-by: qmuntal <qmuntaldiaz@microsoft.com>
Signed-off-by: qmuntal <qmuntaldiaz@microsoft.com>
Signed-off-by: qmuntal <qmuntaldiaz@microsoft.com>
Signed-off-by: qmuntal <qmuntaldiaz@microsoft.com>
@SteveLasker SteveLasker requested review from shizhMSFT and removed request for iamsamirzon April 29, 2022 03:56
Signed-off-by: qmuntal <qmuntaldiaz@microsoft.com>
@qmuntal
Copy link
Contributor Author

qmuntal commented Apr 29, 2022

@jaredpar @SteveLasker as the review process is going slower than expected, I've pushed a new batch of commits since. They don't add new functionality but refine the API after the learnings I got using it in notaryproject/notation#168.

@SteveLasker
Copy link
Contributor

@qmuntal, question for how we can test a set of these changes.
Just an idea (might be a bad one), should we create a branch in notation, notation-go and azure/notation-azure-kv to test these changes?

@qmuntal
Copy link
Contributor Author

qmuntal commented Apr 30, 2022

@qmuntal, question for how we can test a set of these changes. Just an idea (might be a bad one), should we create a branch in notation, notation-go and azure/notation-azure-kv to test these changes?

I like the idea! I'll come with something and share it with you all.

Signed-off-by: qmuntal <qmuntaldiaz@microsoft.com>
Copy link

@gokarnm gokarnm left a comment

Choose a reason for hiding this comment

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

Overall structure and organization looks great, added some comments. Will make another pass tomorrow for some areas I skipped. I'm new to Go, some high level questions.

  1. Some of these error messages will be presented to users through the CLI, how do we differentiate them, and case and format them correctly with more context.
  2. We need to support verbose logging through out the library and CLI, is there a standard way to do that in Go? With verbose logging, we can return concise error messages to the user, and they can enable verbose logging for more details/troubleshooting.

plugin/errors.go Show resolved Hide resolved
plugin/errors.go Outdated
"fmt"
)

var ErrUnknownCommand = errors.New("not a plugin command")
Copy link

Choose a reason for hiding this comment

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

Do we need this exported variable? Plugin implementation should ideally return a custom error message that includes the unsupported command name.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Wops, this variable is an unused leftover, will remove it.

plugin/manager/manager.go Show resolved Hide resolved
plugin/manager/manager.go Show resolved Hide resolved
plugin/plugin.go Outdated Show resolved Hide resolved
plugin/plugin.go Show resolved Hide resolved
plugin/manager/manager.go Outdated Show resolved Hide resolved
Comment on lines +204 to +207
if fsys, ok := fsys.(rootedFS); ok {
return filepath.Join(fsys.root, name, base)
}
return filepath.Join(name, base)
Copy link

Choose a reason for hiding this comment

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

I didn't understand what this code achieves, specially line 204. I'm new to Go.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

if fsys, ok := fsys.(rootedFS); ok { this is an interface type cast, being ok a flag which is true when fsys can be casted to rootedFS.

In production fsys type is always rootedFS, as this is what NewManager instantiates, but for testing purposes I'm also supporting generic fsys types, aka fs.FS, which are mostly instantiated from testing/fstest package.

Copy link

Choose a reason for hiding this comment

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

Got it. Should we add a code comment here to make this clearer, that the alternate path is to support testing?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done!

Signed-off-by: qmuntal <qmuntaldiaz@microsoft.com>
@qmuntal
Copy link
Contributor Author

qmuntal commented May 3, 2022

Overall structure and organization looks great, added some comments. Will make another pass tomorrow for some areas I skipped. I'm new to Go, some high level questions.

  1. Some of these error messages will be presented to users through the CLI, how do we differentiate them, and case and format them correctly with more context.
  2. We need to support verbose logging through out the library and CLI, is there a standard way to do that in Go? With verbose logging, we can return concise error messages to the user, and they can enable verbose logging for more details/troubleshooting.

Thanks for the review @gokarnm. My take is that notation-go should provide fine-grained error messaged which are good for displaying but also can be captured programmatically. If an error is missing some context, then we should add it.

What I wouldn't support is verbose levels in the returned errors. It either returns an error or not, leaving to the caller to decide if it should be logged as a debug, info, warning or whatever other level.

The build-in log package does not have support for using log levels, but there are multiple well-known packages with does support it, e.g. github.com/sirupsen/logrus.

@qmuntal qmuntal requested a review from gokarnm May 3, 2022 06:47
Signed-off-by: qmuntal <qmuntaldiaz@microsoft.com>
Signed-off-by: qmuntal <qmuntaldiaz@microsoft.com>
@gokarnm
Copy link

gokarnm commented May 4, 2022

Thanks for the review @gokarnm. My take is that notation-go should provide fine-grained error messaged which are good for displaying but also can be captured programmatically. If an error is missing some context, then we should add it.

What about the error message casing, error messages which are returned to CLI users should be correctly cased. It seems to be a convention to use small case error messages in Go?

What I wouldn't support is verbose levels in the returned errors. It either returns an error or not, leaving to the caller to decide if it should be logged as a debug, info, warning or whatever other level.

Agreed, I wasn't clear enough. I meant verbose level should log to stdout so that it's visible to in CLI or an upstream caller if they enable verbose logging. The verbose logging will need to be supported in notation-go and notation-core-go, as that's where bulk of the decision paths and validations will be. This need not be implemented right away.

Copy link

@gokarnm gokarnm left a comment

Choose a reason for hiding this comment

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

LGTM for this iteration. Added a couple of comments to not allow symlinks for plugin dir, that can be addressed in next revision, when we add support for describe-key.

Comment on lines 220 to 223
if fi.Mode().Type() != 0 {
// Ignore non-regular files.
return false
}
Copy link

Choose a reason for hiding this comment

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

We should additionally check if the containing dir ~/.notation/plugins/{plugin-name}/notation-{plugin-name} is also not a symlink, something that was missed in the spec.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is exactly what it is being checked here. Non-regular files include symlinks and directories.

Copy link

Choose a reason for hiding this comment

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

I'm bit confused here. Isn't this code only checking that the plugin executable (notation-{plugin-name}) itself is not a symlink, and not that additionally the enclosing directory is also not a symlink (~/.notation/plugins/{plugin-name} dir)?

Comment on lines 102 to 104
if dir == "." || !d.IsDir() {
return nil
}
Copy link

Choose a reason for hiding this comment

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

We should skip over plugin dirs that are symlinks, something that was missed in the spec.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done!

@qmuntal
Copy link
Contributor Author

qmuntal commented May 4, 2022

What about the error message casing, error messages which are returned to CLI users should be correctly cased. It seems to be a convention to use small case error messages in Go?

There are multiple options to transform and localize text, being https://pkg.go.dev/golang.org/x/text the most common.

Agreed, I wasn't clear enough. I meant verbose level should log to stdout so that it's visible to in CLI or an upstream caller if they enable verbose logging. The verbose logging will need to be supported in notation-go and notation-core-go, as that's where bulk of the decision paths and validations will be. This need not be implemented right away.

If we need to log something from those libraries, which is still not clear to me if we should, we will find the way. For example, http.Server logs error into the optional http.Server.ErrorLog property.

Signed-off-by: qmuntal <qmuntaldiaz@microsoft.com>
@SteveLasker SteveLasker merged commit 182873b into notaryproject:main May 4, 2022
@gokarnm
Copy link

gokarnm commented May 5, 2022

If we need to log something from those libraries, which is still not clear to me if we should, we will find the way. For example, http.Server logs error into the optional http.Server.ErrorLog property.

Yes, that's what I'm looking for, similar to libraries that support emitting verbose logs to aid debugging issues. It would be useful for us to debug user reported errors as the logic in many of these areas, plugin and signature verification logic, is quite complex.

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.

5 participants