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

Check index or plugin name safety in cmd #583

Merged
merged 4 commits into from
Apr 4, 2020

Conversation

ahmetb
Copy link
Member

@ahmetb ahmetb commented Apr 1, 2020

tl;dr: Some krew cmds are currently susceptible to path manipulation through positional arguments. Low-level machinery isn't responsible for this, so move them to cmd + add tests.

Moving plugin name or index name safety checks to cmd/ where they are given by
the user to the program. This way we shift the need for validation from being
unit tests of low-level machinery to the integration_test which tests
user-facing concerns.

Note: Checks will fail until #582 is merged and this patch is rebased on it.

Fixes #581
/assign @corneliusweig
/assign @chriskim06

@k8s-ci-robot k8s-ci-robot added the cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. label Apr 1, 2020
@k8s-ci-robot k8s-ci-robot added approved Indicates a PR has been approved by an approver from all required OWNERS files. size/L Denotes a PR that changes 100-499 lines, ignoring generated files. labels Apr 1, 2020
Comment on lines 100 to 103
for _, name := range pluginNames {
if !validation.IsSafePluginName(name) {
return unsafePluginNameErr(name)
}
Copy link
Contributor

Choose a reason for hiding this comment

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

I'd feel better if we validate plugin names in batch upfront. One way we could achieve this is by changing the API to

func IsSafePluginName(names ...string) bool { .. }

(same in several other places)

Also, it seems that unsafePluginNameErr() could be returned from this function (making it obsolete), so that we have instead:

func CheckSafePluginName(names ...string) error { .. }

Copy link
Member Author

Choose a reason for hiding this comment

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

yeah although there's another method in validation.go that's geared towards plugin authors (and therefore it prints a regexp) as it runs during manifest validation tests.

return errors.Errorf("the plugin name %q is not allowed, must match %q", name, safePluginRegexp.String())

that's why I kept it like this.

Copy link
Contributor

Choose a reason for hiding this comment

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

I understand that you want to keep the API in validation consistent.

Maybe this helper can be put in cmd/internal instead? Just an idea. It's fine as it stands, but validating upfront would be even better IMO.

Comment on lines +92 to +93
`../receipts/` + validPlugin,
`..\receipts\` + validPlugin,
Copy link
Contributor

Choose a reason for hiding this comment

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

How is /receipt/ different from /default/? Why is this needed?
Otherwise, let's remove it.

Copy link
Member Author

Choose a reason for hiding this comment

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

receipt/ is needed because we need to point this to a receipt file. and at the moment all these paths parseable as a Receipt

Comment on lines +59 to +65
cases := []string{
`../index/` + validPlugin,
`..\index\` + validPlugin,
`../default/` + validPlugin,
`..\default\` + validPlugin,
`index-name/sub-directory/plugin-name`,
}
Copy link
Contributor

Choose a reason for hiding this comment

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

The list of test cases is repeated 3 times (if my question about receipt applies). Should we extract this to a central place?

Copy link
Member

Choose a reason for hiding this comment

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

Also the test unsafe functions are all relatively similar (some of the error messaging is slightly different). The cases, expected error string, and arguments to test.Krew are the only differences. I think this could be useful as a testutil function like test.AssertFailureWithUnsafeName (not really sure what a good name would be)

Copy link
Member Author

Choose a reason for hiding this comment

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

I think duplication in tests aren't as bad, and each test actually has a slightly different things it's looking at, so I'm not entirely sure if the de-duplication helps.

Copy link
Contributor

Choose a reason for hiding this comment

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

It would be nice to have the unsafe names in a variable, so that it is easily re-used without the need to copy. But let's merge as-is and iterate from there.

@corneliusweig
Copy link
Contributor

Test failure seems legit:

You used fmt.Errorf; use pkg/errors.Errorf instead to preserve stack traces:
cmd/krew/cmd/uninstall.go:58:func unsafePluginNameErr(n string) error { return fmt.Errorf("plugin name %q not allowed", n) }

integration_test/index_test.go Show resolved Hide resolved
integration_test/index_test.go Outdated Show resolved Hide resolved
@ahmetb
Copy link
Member Author

ahmetb commented Apr 2, 2020

Another round of reviews please. 🙏

@corneliusweig
Copy link
Contributor

@ahmetb Can you take a final look and rebase? Then I'll lgtm.

Moving plugin name or index name safety checks to cmd/ where they are given by
the user to the program. This way we shift the need for validation from being
unit tests of low-level machinery to the integration_test which tests
user-facing concerns.

Signed-off-by: Ahmet Alp Balkan <ahmetb@google.com>
Signed-off-by: Ahmet Alp Balkan <ahmetb@google.com>
Signed-off-by: Ahmet Alp Balkan <ahmetb@google.com>
Signed-off-by: Ahmet Alp Balkan <ahmetb@google.com>
@ahmetb
Copy link
Member Author

ahmetb commented Apr 3, 2020

Rebased + test run https://github.com/ahmetb/krew/runs/559418218 actually has captured a legitimate bug. Posted a fix.

@corneliusweig
Copy link
Contributor

/lgtm
/approve
Thanks for finding and fixing this loophole!

@k8s-ci-robot k8s-ci-robot added the lgtm "Looks good to me", indicates that a PR is ready to be merged. label Apr 4, 2020
@k8s-ci-robot
Copy link
Contributor

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: ahmetb, corneliusweig

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Needs approval from an approver in each of these files:
  • OWNERS [ahmetb,corneliusweig]

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@k8s-ci-robot k8s-ci-robot merged commit da05925 into kubernetes-sigs:master Apr 4, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
approved Indicates a PR has been approved by an approver from all required OWNERS files. cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. lgtm "Looks good to me", indicates that a PR is ready to be merged. size/L Denotes a PR that changes 100-499 lines, ignoring generated files.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Some Krew commands susceptible to path manipulation
4 participants