# Verifying the integrity of third party plugins

**URL:** <https://forum.buildkite.community/t/verifying-the-integrity-of-third-party-plugins/158>\
**Category:** General\
**Created:** [December 12, 2018, 2:29am UTC](https://forum.buildkite.community/t/verifying-the-integrity-of-third-party-plugins/158 "2018-12-12T02:29:45Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![mipearson\_envato](https://avatars.discourse-cdn.com/v4/letter/m/35a633/32.png) [@mipearson\_envato](https://forum.buildkite.community/u/mipearson_envato)\
**Post date:** [December 12, 2018, 2:29am UTC](https://forum.buildkite.community/t/verifying-the-integrity-of-third-party-plugins/158/1 "2018-12-12T02:29:46Z")

</div>

We use several plugins provided by buildkite in our builds and pin them to versions. We also have started using third-party plugins provided by other organisations, like CultureAmp’s [aws-assume-role](https://github.com/cultureamp/aws-assume-role-buildite-plugin) plugin.

Pinning versions is not entirely sufficient to ensure that we’re always running the same plugin code between builds: the pin is based on a git tag or branch, which can easily be reset by the repository maintainer. Worse, if a bad actor gains access to the third party repository, they could add their own malicious code and reset the tags for existing versions.

We’ve worked around this by forking plugins to our own repository, but is there a better way to ensure the plugins we run don’t change over time and remain secure?

---

<div class="post-metadata">

**Author:** ![anon46008679](https://avatars.discourse-cdn.com/v4/letter/a/da6949/32.png) [@anon46008679](https://forum.buildkite.community/u/anon46008679)\
**Post date:** [December 14, 2018, 11:49am UTC](https://forum.buildkite.community/t/verifying-the-integrity-of-third-party-plugins/158/2 "2018-12-14T11:49:39Z")

</div>

Would pinning the plugin to the full commit SHA be sufficient? You can put any commitish reference where you’d normally place the tag/branch.

---

<div class="post-metadata">

**Author:** ![anon18197598](https://avatars.discourse-cdn.com/v4/letter/a/9d8465/32.png) [@anon18197598](https://forum.buildkite.community/u/anon18197598)\
**Post date:** [December 14, 2018, 9:43pm UTC](https://forum.buildkite.community/t/verifying-the-integrity-of-third-party-plugins/158/3 "2018-12-14T21:43:22Z")

</div>

The other option we’ve been discussing is allowing plugins to be vendored. For instance, we could support `.buildkite/plugins`, which if it existed would be the only place the agent would load plugins from for that build.

The `bk` tool could be used to read a pipeline.yml and download linked plugins:

```auto
bk plugins vendor
> Downloading cultureamp/aws-assume-role into ~/.buildkite/plugins/cultureamp/aws-assume-role

```

The only issues I can foresee with this is that it would preclude hooks that fire before checkout.

---

<div class="post-metadata">

**Author:** ![mipearson\_envato](https://avatars.discourse-cdn.com/v4/letter/m/35a633/32.png) [@mipearson\_envato](https://forum.buildkite.community/u/mipearson_envato)\
**Post date:** [December 15, 2018, 3:26am UTC](https://forum.buildkite.community/t/verifying-the-integrity-of-third-party-plugins/158/4 "2018-12-15T03:26:08Z")

</div>

With sha’s it’s not obvious which "version’ you’re using, and whether it’s the latest, although it does solve my immediate problem.

With plugins there’s a lot of copy/paste already, and I’m wondering whether some of that can/should be moved to the top of the pipeline file, etc:

```auto
plugins:
  docker-compose#1.1.1#ab01df
    # verifies that 1.1.1 has this sha - so you get both version / lock
    config-file: docker-compose.buildkite.yml
steps:
  plugins:
    docker-compose:
      # inherits version/sha lock, and plugin defaults, from above
      run: ruby

```

---

<div class="post-metadata">

**Author:** ![mipearson\_envato](https://avatars.discourse-cdn.com/v4/letter/m/35a633/32.png) [@mipearson\_envato](https://forum.buildkite.community/u/mipearson_envato)\
**Post date:** [December 15, 2018, 3:27am UTC](https://forum.buildkite.community/t/verifying-the-integrity-of-third-party-plugins/158/5 "2018-12-15T03:27:49Z")

</div>

@anon18197598 I would _love_ to be able to vendor plugins, but for a different reason: I want to work on customising / making small changes to plugins without having to do so in a different git repository to the build I’m testing the plugin in.

---

<div class="post-metadata">

**Author:** ![anon18197598](https://avatars.discourse-cdn.com/v4/letter/a/9d8465/32.png) [@anon18197598](https://forum.buildkite.community/u/anon18197598)\
**Post date:** [December 15, 2018, 4:48am UTC](https://forum.buildkite.community/t/verifying-the-integrity-of-third-party-plugins/158/6 "2018-12-15T04:48:29Z")

</div>

Yup, I hear ya! I’ve often wanted that too. I’d also like [https://github.com/buildkite/agent/issues/422](https://github.com/buildkite/agent/issues/422) for that too. Maybe I will build that now.

---

<div class="post-metadata">

**Author:** ![anon18197598](https://avatars.discourse-cdn.com/v4/letter/a/9d8465/32.png) [@anon18197598](https://forum.buildkite.community/u/anon18197598)\
**Post date:** [December 15, 2018, 4:53am UTC](https://forum.buildkite.community/t/verifying-the-integrity-of-third-party-plugins/158/7 "2018-12-15T04:53:22Z")

</div>

I wrote a very-similar looking gist on the top-level plugin block a while back: [https://gist.github.com/lox/1dd425819b4e3874ba394346cb56a74c](https://gist.github.com/lox/1dd425819b4e3874ba394346cb56a74c)

I think the difficulty it runs into is that inheritance is really hard to reason about, especially when you are trying to merge complex yaml structures. I think docker-compose’s extends support is a really good example of how badly this can work.

In the meantime, you could use yaml anchors for exactly that functionality if you wanted it! They are also diabolically complicated 😅

---

<div class="post-metadata">

**Author:** ![anon46008679](https://avatars.discourse-cdn.com/v4/letter/a/da6949/32.png) [@anon46008679](https://forum.buildkite.community/u/anon46008679)\
**Post date:** [December 16, 2018, 12:31am UTC](https://forum.buildkite.community/t/verifying-the-integrity-of-third-party-plugins/158/8 "2018-12-16T00:31:25Z")

</div>

Nice! We’ve thrown around some ideas like this before, but I don’t think we thought of pinning both the version and sha. 👌🏼

Now we have the agents block, this mirrors it quite nicely:  
[https://forum.buildkite.community/t/setting-default-agents-for-a-build/111](https://forum.buildkite.community/t/setting-default-agents-for-a-build/111)

(@anon18197598 I think the same overriding rules would apply there, where a specific step just wholesale overrides the plugin config defined at the top?)

---

<div class="post-metadata">

**Author:** ![anon46008679](https://avatars.discourse-cdn.com/v4/letter/a/da6949/32.png) [@anon46008679](https://forum.buildkite.community/u/anon46008679)\
**Post date:** [December 16, 2018, 12:34am UTC](https://forum.buildkite.community/t/verifying-the-integrity-of-third-party-plugins/158/9 "2018-12-16T00:34:18Z")

</div>

(We’d probably use arrays instead of a map now though, as it’s the new recommended default:  
[https://buildkite.com/docs/pipelines/plugins](https://buildkite.com/docs/pipelines/plugins))

---

<div class="post-metadata">

**Author:** ![mipearson\_envato](https://avatars.discourse-cdn.com/v4/letter/m/35a633/32.png) [@mipearson\_envato](https://forum.buildkite.community/u/mipearson_envato)\
**Post date:** [December 16, 2018, 1:47am UTC](https://forum.buildkite.community/t/verifying-the-integrity-of-third-party-plugins/158/10 "2018-12-16T01:47:44Z")

</div>

@anon18197598 yep, agree re YAML/inheritance weirdness being confusing.

How about something a bit more lightweight?

```auto
plugin-versions:
  - docker-compose#1.1.1#ab01df
  - ecr#1.1.0#3301df
steps:
  plugins:
    - ecr:
       ...
    - docker-compose:
       ...

```

Bonus round: if you specify plugins without versions, or with versions but without a commit sha, Buildkite prints a security warning _and_ generations the `plugin-versions` section for you for you to copy/paste to your pipeline.

---

<div class="post-metadata">

**Author:** ![anon18197598](https://avatars.discourse-cdn.com/v4/letter/a/9d8465/32.png) [@anon18197598](https://forum.buildkite.community/u/anon18197598)\
**Post date:** [December 16, 2018, 2:43am UTC](https://forum.buildkite.community/t/verifying-the-integrity-of-third-party-plugins/158/11 "2018-12-16T02:43:15Z")

</div>

I think I’m probably leaning towards vendored plugins as a first port of call for this stuff. It doesn’t solve the problem of de-duplicating config, but it’s fast, efficient and has the best security profile out of the options we’ve looked at.

Makes for a great way to prototype plugins too!

---

<div class="post-metadata">

**Author:** ![mipearson\_envato](https://avatars.discourse-cdn.com/v4/letter/m/35a633/32.png) [@mipearson\_envato](https://forum.buildkite.community/u/mipearson_envato)\
**Post date:** [December 16, 2018, 2:46am UTC](https://forum.buildkite.community/t/verifying-the-integrity-of-third-party-plugins/158/12 "2018-12-16T02:46:22Z")

</div>

Yep, reasonable.

(blah blah blah 20 character minimum)

---

<div class="post-metadata">

**Author:** ![anon18197598](https://avatars.discourse-cdn.com/v4/letter/a/9d8465/32.png) [@anon18197598](https://forum.buildkite.community/u/anon18197598)\
**Post date:** [December 16, 2018, 6:31am UTC](https://forum.buildkite.community/t/verifying-the-integrity-of-third-party-plugins/158/13 "2018-12-16T06:31:39Z")

</div>

We will try and remove the 20 char minimum!

The first major obstacle to vendored plugins is that we’d have to drop support for checkout related hooks: `pre-checkout`, `checkout` and also `environment`, or at least change the semantics of the `environment` to run after the bootstrap checkout phase.

---

<div class="post-metadata">

**Author:** ![anon85971592](https://avatars.discourse-cdn.com/v4/letter/a/dfb087/32.png) [@anon85971592](https://forum.buildkite.community/u/anon85971592)\
**Post date:** [December 17, 2018, 12:19am UTC](https://forum.buildkite.community/t/verifying-the-integrity-of-third-party-plugins/158/14 "2018-12-17T00:19:38Z")

</div>

> [@mipearson\_envato](#):
>
> (blah blah blah 20 character minimum)

(just made it 10!)

---

<div class="post-metadata">

**Author:** ![anon18197598](https://avatars.discourse-cdn.com/v4/letter/a/9d8465/32.png) [@anon18197598](https://forum.buildkite.community/u/anon18197598)\
**Post date:** [December 17, 2018, 5:19am UTC](https://forum.buildkite.community/t/verifying-the-integrity-of-third-party-plugins/158/15 "2018-12-17T05:19:54Z")

</div>

The top-level plugin block brings with it a whole lot of questions, so for the moment let’s leave it aside and focus on the two things that bring integrity and also development easy. This is what I ended up with

```auto
steps:
  - name: ":hammer: :linux:"
    command: ".buildkite/steps/tests.sh"
    plugins:
      - "docker-compose#v2.5.1@51cc6ca5c1b1cc01ccd1d628efa6132f540119de":
          config: .buildkite/docker-compose.yml
          run: agent
      - "./.buildkite/plugins/my-vendored-plugin":
          blah: true

```

---

<div class="post-metadata">

**Author:** ![zsims](https://sea2.discourse-cdn.com/flex016/user_avatar/forum.buildkite.community/zsims/32/388_2.png) [@zsims](https://forum.buildkite.community/u/zsims)\
**Post date:** [December 18, 2018, 12:01am UTC](https://forum.buildkite.community/t/verifying-the-integrity-of-third-party-plugins/158/16 "2018-12-18T00:01:11Z")

</div>

Agree that vendored plugins would solve this for us quite nicely. Also means it’s a lot easier to use “private” plugins without having to push them to a repo (e.g. for testing).

Do you see that plugins via submodules would also be supported? And would the `plugin.yml` drive things like the plugin name for variables? e.g. `BUILDKITE_PLUGIN_MY_VENDORED_PLUGIN`?

---

<div class="post-metadata">

**Author:** ![anon85971592](https://avatars.discourse-cdn.com/v4/letter/a/dfb087/32.png) [@anon85971592](https://forum.buildkite.community/u/anon85971592)\
**Post date:** [December 18, 2018, 12:46am UTC](https://forum.buildkite.community/t/verifying-the-integrity-of-third-party-plugins/158/17 "2018-12-18T00:46:08Z")

</div>

> [@zsims](#):
>
> Do you see that plugins via submodules would also be supported?

I think they should mostly just work since you define a vendored plugin via a path, you should just be able to point the path at a submodule:

```yaml
steps:
  - name: ":hammer: :linux:"
    command: ".buildkite/steps/tests.sh"
    plugins:
      - "./.buildkite/submodules/my-plugin":
          blah: true

```

The code checkout/submodule phase would have already happened by the time we start running vendored plugins.

> [@zsims](#):
>
> And would the `plugin.yml` drive things like the plugin name for variables? e.g. `BUILDKITE_PLUGIN_MY_VENDORED_PLUGIN` ?

Hrmm…just to confirm what you mean here…are you thinking that a vendored plugin my have a different config name prefix to one that’s pulled in globally? It’s not something we discussed, but we’re keen to hear what problems you think it’d solve!

---

<div class="post-metadata">

**Author:** ![zsims](https://sea2.discourse-cdn.com/flex016/user_avatar/forum.buildkite.community/zsims/32/388_2.png) [@zsims](https://forum.buildkite.community/u/zsims)\
**Post date:** [December 18, 2018, 1:09am UTC](https://forum.buildkite.community/t/verifying-the-integrity-of-third-party-plugins/158/18 "2018-12-18T01:09:39Z")

</div>

> [@anon85971592](#):
>
> Hrmm…just to confirm what you mean here…are you thinking that a vendored plugin my have a different config name prefix to one that’s pulled in globally? It’s not something we discussed, but we’re keen to hear what problems you think it’d solve!

From what I understood the plugin derived its name from the reference? Which is no longer controlled by the plugin author if the plugin is vendored (e.g. the folder could be renamed). Not major, I’m just trying to get my head around if this would be derived from `plugin.yml` or from the plugin reference?

---

<div class="post-metadata">

**Author:** ![anon18197598](https://avatars.discourse-cdn.com/v4/letter/a/9d8465/32.png) [@anon18197598](https://forum.buildkite.community/u/anon18197598)\
**Post date:** [December 18, 2018, 4:14am UTC](https://forum.buildkite.community/t/verifying-the-integrity-of-third-party-plugins/158/19 "2018-12-18T04:14:03Z")

</div>

@zsims we use the plugin name for that, which is basically the basename of the plugin directory.

---

<div class="post-metadata">

**Author:** ![anon18197598](https://avatars.discourse-cdn.com/v4/letter/a/9d8465/32.png) [@anon18197598](https://forum.buildkite.community/u/anon18197598)\
**Post date:** [December 18, 2018, 4:14am UTC](https://forum.buildkite.community/t/verifying-the-integrity-of-third-party-plugins/158/20 "2018-12-18T04:14:17Z")

</div>

I’ve got a PR ready for vendored plugins: [https://github.com/buildkite/agent/pull/878](https://github.com/buildkite/agent/pull/878)
