First commit.

master
Thomas BELLEMBOIS 2 years ago
commit 3cf5788f13

@ -0,0 +1,22 @@
kind: pipeline
type: docker
name: default
steps:
- name: build
image: golang
commands:
- go build
- go test ./...
- name: docker-build
image: plugins/docker
settings:
dockerfile: Dockerfile
context: .
registry: hub.codefirst.iut.uca.fr
repo: hub.codefirst.iut.uca.fr/thomas.bellembois/drone-secret-plugin
username:
from_secret: SECRET_REGISTRY_USERNAME
password:
from_secret: SECRET_REGISTRY_PASSWORD

2
.gitignore vendored

@ -0,0 +1,2 @@
.env
drone-secret-plugin

@ -0,0 +1,7 @@
FROM debian:bookworm
EXPOSE 3000
ENV GODEBUG netdns=go
ADD drone-secret-plugin /bin/
ENTRYPOINT ["/bin/drone-secret-plugin"]

@ -0,0 +1,2 @@
[Polyform-Small-Business-1.0.0](https://polyformproject.org/licenses/small-business/1.0.0) OR
[Polyform-Free-Trial-1.0.0](https://polyformproject.org/licenses/free-trial/1.0.0)

@ -0,0 +1,43 @@
This extension provides global secrets for use in your pipelines. This extension is a direct port of the global secret file in Drone 0.8. _Please note this project requires Drone server version 1.4 or higher._
## Secret File
Secrets are loaded from a yaml configuration file. Example secrets configuration file:
```text
- name: docker_username
value: octocat
- name: docker_password
value: correct-horse-battery-staple
repos: [ octocat/hello-world, github/* ]
events: [ push, tag ]
```
## Installation
Create a shared secret:
```console
$ openssl rand -hex 16
bea26a2221fd8090ea38720fc445eca6
```
Download and run the plugin:
```console
$ docker run -d \
--publish=3000:3000 \
--env=DRONE_DEBUG=true \
--env=DRONE_SECRET=bea26a2221fd8090ea38720fc445eca6 \
--env=DRONE_SECRET_FILE=/etc/secrets.yml \
--restart=always \
--volume=/etc/secrets.yml:/etc/secrets.yml \
--name=secrets drone/secret-plugin
```
Update your Drone __runner__ configuration to include the extension address and the shared secret.
```text
DRONE_SECRET_PLUGIN_ENDPOINT=http://1.2.3.4:3000
DRONE_SECRET_PLUGIN_SECRET=bea26a2221fd8090ea38720fc445eca6

@ -0,0 +1,12 @@
module github.com/drone/drone-secret-plugin
go 1.12
require (
github.com/drone/drone-go v1.0.6
github.com/google/go-cmp v0.2.0
github.com/joho/godotenv v1.3.0
github.com/kelseyhightower/envconfig v1.4.0
github.com/sirupsen/logrus v1.4.2
gopkg.in/yaml.v2 v2.2.7
)

@ -0,0 +1,48 @@
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
github.com/99designs/httpsignatures-go v0.0.0-20170731043157-88528bf4ca7e h1:rl2Aq4ZODqTDkeSqQBy+fzpZPamacO1Srp8zq7jf2Sc=
github.com/99designs/httpsignatures-go v0.0.0-20170731043157-88528bf4ca7e/go.mod h1:Xa6lInWHNQnuWoF0YPSsx+INFA9qk7/7pTjwb3PInkY=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/drone/drone-go v1.0.6 h1:YbMwEwlE3HC4InN0bT21EDvzImct5dGG1I56dSdUhjI=
github.com/drone/drone-go v1.0.6/go.mod h1:GxyeGClYohaKNYJv/ZpsmVHtMJ7WhoT+uDaJNcDIrk4=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
github.com/google/go-jsonnet v0.13.0/go.mod h1:gNwctc8xrpXNs749bjRLO58rjIBVrWz+pgsRoOCh5Vs=
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc=
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8=
github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
go.starlark.net v0.0.0-20190820173200-988906f77f65 h1:0766L84ADcyJQKl+NsKSJC8JBEuer/2RxL37StWfsx4=
go.starlark.net v0.0.0-20190820173200-988906f77f65/go.mod h1:c1/X6cHgvdXj6pUlmWKMkuqRnW4K8x2vwt6JAaaircg=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894 h1:Cz4ceDQGXuKRnVBDTS23GTn/pU5OE2C0WrNTOYK1Uuc=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.7 h1:VUgggvou5XRW9mHwD/yXxIYSMtY0zoKQf/v226p2nyo=
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

@ -0,0 +1,93 @@
# Polyform Free Trial License 1.0.0
<https://polyformproject.org/licenses/free-trial/1.0.0>
## Acceptance
In order to get any license under these terms, you must agree
to them as both strict obligations and conditions to all
your licenses.
## Copyright License
The licensor grants you a copyright license for the software
to do everything you might do with the software that would
otherwise infringe the licensor's copyright in it for any
permitted purpose. However, you may only make changes or
new works based on the software according to [Changes and New
Works License](#changes-and-new-works-license), and you may
not distribute copies of the software.
## Changes and New Works License
The licensor grants you an additional copyright license to
make changes and new works based on the software for any
permitted purpose.
## Patent License
The licensor grants you a patent license for the software that
covers patent claims the licensor can license, or becomes able
to license, that you would infringe by using the software.
## Fair Use
You may have "fair use" rights for the software under the
law. These terms do not limit them.
## Free Trial
Use to evaluate whether the software suits a particular
application for less than 32 consecutive calendar days, on
behalf of you or your company, is use for a permitted purpose.
## No Other Rights
These terms do not allow you to sublicense or transfer any of
your licenses to anyone else, or prevent the licensor from
granting licenses to anyone else. These terms do not imply
any other licenses.
## Patent Defense
If you make any written claim that the software infringes or
contributes to infringement of any patent, your patent license
for the software granted under these terms ends immediately. If
your company makes such a claim, your patent license ends
immediately for work on behalf of your company.
## Violations
If you violate any of these terms, or do anything with the
software not covered by your licenses, all your licenses
end immediately.
## No Liability
***As far as the law allows, the software comes as is, without
any warranty or condition, and the licensor will not be liable
to you for any damages arising out of these terms or the use
or nature of the software, under any kind of legal claim.***
## Definitions
The **licensor** is the individual or entity offering these
terms, and the **software** is the software the licensor makes
available under these terms.
**You** refers to the individual or entity agreeing to these
terms.
**Your company** is any legal entity, sole proprietorship,
or other kind of organization that you work for, plus all
organizations that have control over, are under the control of,
or are under common control with that organization. **Control**
means ownership of substantially all the assets of an entity,
or the power to direct its management and policies by vote,
contract, or otherwise. Control can be direct or indirect.
**Your licenses** are all the licenses granted to you for the
software under these terms.
**Use** means anything you do with the software requiring one
of your licenses.

@ -0,0 +1,121 @@
# Polyform Small Business License 1.0.0
<https://polyformproject.org/licenses/small-business/1.0.0>
## Acceptance
In order to get any license under these terms, you must agree
to them as both strict obligations and conditions to all
your licenses.
## Copyright License
The licensor grants you a copyright license for the
software to do everything you might do with the software
that would otherwise infringe the licensor's copyright
in it for any permitted purpose. However, you may
only distribute the software according to [Distribution
License](#distribution-license) and make changes or new works
based on the software according to [Changes and New Works
License](#changes-and-new-works-license).
## Distribution License
The licensor grants you an additional copyright license
to distribute copies of the software. Your license
to distribute covers distributing the software with
changes and new works permitted by [Changes and New Works
License](#changes-and-new-works-license).
## Notices
You must ensure that anyone who gets a copy of any part of
the software from you also gets a copy of these terms or the
URL for them above, as well as copies of any plain-text lines
beginning with `Required Notice:` that the licensor provided
with the software. For example:
> Required Notice: Copyright Yoyodyne, Inc. (http://example.com)
## Changes and New Works License
The licensor grants you an additional copyright license to
make changes and new works based on the software for any
permitted purpose.
## Patent License
The licensor grants you a patent license for the software that
covers patent claims the licensor can license, or becomes able
to license, that you would infringe by using the software.
## Fair Use
You may have "fair use" rights for the software under the
law. These terms do not limit them.
## Small Business
Use of the software for the benefit of your company is use for
a permitted purpose if your company has fewer than 100 total
individuals working as employees and independent contractors,
and less than 1,000,000 USD (2019) total revenue in the prior
tax year. Adjust this revenue threshold for inflation according
to the United States Bureau of Labor Statistics' consumer price
index for all urban consumers, U.S. city average, for all items,
not seasonally adjusted, with 19821984=100 reference base.
## No Other Rights
These terms do not allow you to sublicense or transfer any of
your licenses to anyone else, or prevent the licensor from
granting licenses to anyone else. These terms do not imply
any other licenses.
## Patent Defense
If you make any written claim that the software infringes or
contributes to infringement of any patent, your patent license
for the software granted under these terms ends immediately. If
your company makes such a claim, your patent license ends
immediately for work on behalf of your company.
## Violations
The first time you are notified in writing that you have
violated any of these terms, or done anything with the software
not covered by your licenses, your licenses can nonetheless
continue if you come into full compliance with these terms,
and take practical steps to correct past violations, within
32 days of receiving notice. Otherwise, all your licenses
end immediately.
## No Liability
***As far as the law allows, the software comes as is, without
any warranty or condition, and the licensor will not be liable
to you for any damages arising out of these terms or the use
or nature of the software, under any kind of legal claim.***
## Definitions
The **licensor** is the individual or entity offering these
terms, and the **software** is the software the licensor makes
available under these terms.
**You** refers to the individual or entity agreeing to these
terms.
**Your company** is any legal entity, sole proprietorship,
or other kind of organization that you work for, plus all
organizations that have control over, are under the control of,
or are under common control with that organization. **Control**
means ownership of substantially all the assets of an entity,
or the power to direct its management and policies by vote,
contract, or otherwise. Control can be direct or indirect.
**Your licenses** are all the licenses granted to you for the
software under these terms.
**Use** means anything you do with the software requiring one
of your licenses.

@ -0,0 +1,68 @@
// Copyright 2019 the Drone Authors. All rights reserved.
// Use of this source code is governed by the Polyform License
// that can be found in the LICENSE file.
package main
import (
"io/ioutil"
"net/http"
"github.com/drone/drone-go/plugin/secret"
"github.com/drone/drone-secret-plugin/plugin"
"gopkg.in/yaml.v2"
_ "github.com/joho/godotenv/autoload"
"github.com/kelseyhightower/envconfig"
"github.com/sirupsen/logrus"
)
// spec provides the plugin settings.
type spec struct {
Bind string `envconfig:"DRONE_BIND"`
Debug bool `envconfig:"DRONE_DEBUG"`
Secret string `envconfig:"DRONE_SECRET"`
File string `envconfig:"DRONE_SECRET_FILE"`
}
func main() {
spec := new(spec)
err := envconfig.Process("", spec)
if err != nil {
logrus.Fatal(err)
}
if spec.Debug {
logrus.SetLevel(logrus.DebugLevel)
}
if spec.Secret == "" {
logrus.Fatalln("missing secret key")
}
if spec.Bind == "" {
spec.Bind = ":3000"
}
if spec.File == "" {
spec.File = "/etc/secrets.yml"
}
raw, err := ioutil.ReadFile(spec.File)
if err != nil {
logrus.WithError(err).Fatalln("Cannot read secrets file")
}
var secrets []*plugin.Secret
if err := yaml.Unmarshal(raw, &secrets); err != nil {
logrus.WithError(err).Fatalln("Cannot unmarshal secrets file")
}
handler := secret.Handler(
spec.Secret,
plugin.New(secrets),
logrus.StandardLogger(),
)
logrus.Infof("server listening on address %s", spec.Bind)
http.Handle("/", handler)
logrus.Fatal(http.ListenAndServe(spec.Bind, nil))
}

@ -0,0 +1,72 @@
// Copyright 2019 the Drone Authors. All rights reserved.
// Use of this source code is governed by the Polyform License
// that can be found in the LICENSE file.
package plugin
import (
"context"
"path/filepath"
"strings"
"github.com/drone/drone-go/drone"
"github.com/drone/drone-go/plugin/secret"
)
// New returns a new secret plugin.
func New(secrets []*Secret) secret.Plugin {
return &plugin{
secrets: secrets,
}
}
type plugin struct {
secrets []*Secret
}
// Find returns the named plugin from the static list of secrets,
// if an only if the name, repository, branch and event match.
func (p *plugin) Find(ctx context.Context, req *secret.Request) (*drone.Secret, error) {
for _, secret := range p.secrets {
// if the secret does not match the name, continue
if !strings.EqualFold(secret.Name, req.Name) {
continue
}
// if the secret does not match the repository name,
// build event, or branch, skip.
if !match(req.Build.Event, secret.Events) {
continue
}
if !match(req.Repo.Slug, secret.Repos) {
continue
}
return &drone.Secret{
Name: secret.Name,
Data: secret.Value,
Pull: true,
Fork: true,
}, nil
}
return nil, nil
}
// helper function returns true if string s matches a
// string in the index.
func match(s string, patterns []string) bool {
// if the patterns matching list is empty the
// string is considered a match.
if len(patterns) == 0 {
return true
}
// if the string matches any pattern in the
// list it is considered a match.
for _, pattern := range patterns {
matched, _ := filepath.Match(pattern, s)
if matched {
return true
}
}
return false
}

@ -0,0 +1,191 @@
// Copyright 2019 the Drone Authors. All rights reserved.
// Use of this source code is governed by the Polyform License
// that can be found in the LICENSE file.
package plugin
import (
"context"
"testing"
"github.com/drone/drone-go/drone"
"github.com/drone/drone-go/plugin/secret"
"github.com/google/go-cmp/cmp"
)
var noContext = context.Background()
func TestPlugin(t *testing.T) {
secrets := []*Secret{
{
Name: "username",
Value: "root",
Repos: []string{},
Events: []string{},
},
{
Name: "password",
Value: "correct-horse-battery-staple",
Repos: []string{},
Events: []string{},
},
}
req := &secret.Request{
Name: "username",
Repo: drone.Repo{},
Build: drone.Build{},
}
plugin := New(secrets)
got, err := plugin.Find(noContext, req)
if err != nil {
t.Error(err)
return
}
want := &drone.Secret{
Name: "username",
Data: "root",
Pull: true,
Fork: true,
}
if diff := cmp.Diff(got, want); diff != "" {
t.Errorf("Unexpected secret")
t.Logf(diff)
}
}
func TestPlugin_Match(t *testing.T) {
secrets := []*Secret{
{
Name: "username",
Value: "root",
Repos: []string{"octocat/*"},
Events: []string{},
},
}
req := &secret.Request{
Name: "username",
Repo: drone.Repo{Slug: "octocat/hello-world"},
Build: drone.Build{Event: "push"},
}
plugin := New(secrets)
got, err := plugin.Find(noContext, req)
if err != nil {
t.Error(err)
return
}
want := &drone.Secret{
Name: "username",
Data: "root",
Pull: true,
Fork: true,
}
if diff := cmp.Diff(got, want); diff != "" {
t.Errorf("Unexpected secret")
t.Logf(diff)
}
}
func TestPlugin_NoMatch(t *testing.T) {
secrets := []*Secret{
{
Name: "username",
Value: "root",
},
}
req := &secret.Request{
Name: "password",
Repo: drone.Repo{Slug: "octocat/hello-world"},
Build: drone.Build{Event: "push"},
}
plugin := New(secrets)
got, err := plugin.Find(noContext, req)
if err != nil {
t.Error(err)
return
}
if got != nil {
t.Errorf("Expect nil secret due to event mismatch")
}
}
func TestPlugin_NoMatch_Repo(t *testing.T) {
secrets := []*Secret{
{
Name: "username",
Value: "root",
Repos: []string{"octocat/*"},
Events: []string{},
},
}
req := &secret.Request{
Name: "username",
Repo: drone.Repo{Slug: "spaceghost/hello-world"},
Build: drone.Build{Event: "push"},
}
plugin := New(secrets)
got, err := plugin.Find(noContext, req)
if err != nil {
t.Error(err)
return
}
if got != nil {
t.Errorf("Expect nil secret due to repository mismatch")
}
}
func TestPlugin_NoMatch_Event(t *testing.T) {
secrets := []*Secret{
{
Name: "username",
Value: "root",
Repos: []string{"octocat/*"},
Events: []string{"pull_request"},
},
}
req := &secret.Request{
Name: "username",
Repo: drone.Repo{Slug: "octocat/hello-world"},
Build: drone.Build{Event: "push"},
}
plugin := New(secrets)
got, err := plugin.Find(noContext, req)
if err != nil {
t.Error(err)
return
}
if got != nil {
t.Errorf("Expect nil secret due to event mismatch")
}
}
func TestMatch(t *testing.T) {
tests := []struct {
match string
patterns []string
matched bool
}{
// event matching
{"push", []string{"pull_request", "push"}, true},
{"tag", []string{"pull_request", "push"}, false},
{"tag", []string{}, true},
// repo matching
{"octocat/hello-world", []string{"octocat/hello-world", "octocat/spoon-fork"}, true},
{"octocat/hello-world", []string{"octocat/*", "octocat/spoon-fork"}, true},
{"octocat/hello-world", []string{}, true},
{"octocat/hello-world", []string{"spaceghost/*"}, false},
{"octocat/hello-world", []string{"spaceghost/hello-world"}, false},
}
for _, test := range tests {
got, want := match(test.match, test.patterns), test.matched
if got != want {
t.Errorf("Want matched %v for string %q and patterns %v",
test.matched,
test.match,
test.patterns,
)
}
}
}

@ -0,0 +1,15 @@
// Copyright 2019 the Drone Authors. All rights reserved.
// Use of this source code is governed by the Polyform License
// that can be found in the LICENSE file.
package plugin
// Secret represents a secret and its matching rules that
// determine whether or not a pipeline should be granted
// access to the secret value.
type Secret struct {
Name string
Value string
Repos []string
Events []string
}
Loading…
Cancel
Save