Skip to content
This repository was archived by the owner on Feb 16, 2023. It is now read-only.

Commit 815b5d1

Browse files
Merge pull request #198 from secrethub/release/v0.30.0
Release v0.30.0
2 parents 29fddd0 + 0a0c685 commit 815b5d1

70 files changed

Lines changed: 632 additions & 150 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.circleci/config.yml

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,20 @@
11
version: 2
22
jobs:
3-
build:
3+
test:
44
docker:
55
- image: circleci/golang:1.12
66
steps:
77
- checkout
88
- run: make test
9+
verify-goreleaser:
10+
docker:
11+
- image: goreleaser/goreleaser:v0.117
12+
steps:
13+
- checkout
14+
- run: goreleaser check
15+
workflows:
16+
version: 2
17+
pipeline:
18+
jobs:
19+
- test
20+
- verify-goreleaser

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@
1212
[![Version]( https://img.shields.io/github/release/secrethub/secrethub-cli.svg)][latest-version]
1313
[![Discord](https://img.shields.io/badge/chat-on%20discord-7289da.svg?logo=discord)][discord]
1414

15-
The SecretHub CLI provides the command-line interface to interact with SecretHub.
15+
The SecretHub CLI provides the command-line interface to interact with the SecretHub API.
1616

17-
> [SecretHub][secrethub] is a developer tool to help you keep database passwords, API tokens, and other secrets out of IT automation scripts.
17+
> [SecretHub][secrethub] is an end-to-end encrypted secret management service that helps developers keep database passwords, API keys, and other secrets out of source code.
1818
1919
## Usage
2020

go.mod

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ go 1.12
44

55
require (
66
bitbucket.org/zombiezen/cardcpx v0.0.0-20150417151802-902f68ff43ef
7-
github.com/alecthomas/kingpin v0.0.0-20190705085659-95eb9edaa399
7+
github.com/alecthomas/kingpin v0.0.0-20190930021037-0a108b7f5563
88
github.com/atotto/clipboard v0.1.2
99
github.com/aws/aws-sdk-go v1.19.38
1010
github.com/danieljoos/wincred v1.0.2 // indirect
@@ -25,5 +25,3 @@ require (
2525
golang.org/x/text v0.3.0
2626
gopkg.in/yaml.v2 v2.2.2
2727
)
28-
29-
replace github.com/alecthomas/kingpin => github.com/secrethub/kingpin v0.0.0-20190920111600-67b1cb231087

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ github.com/ChrisTrenkamp/goxpath v0.0.0-20170922090931-c385f95c6022 h1:y8Gs8CzNf
66
github.com/ChrisTrenkamp/goxpath v0.0.0-20170922090931-c385f95c6022/go.mod h1:nuWgzSkT5PnyOd+272uUmV0dnAnAn42Mk7PiQC5VzN4=
77
github.com/alecthomas/kingpin v0.0.0-20190705085659-95eb9edaa399 h1:NoJOfPUP5uDdYYuWS/+I6UQDH4+Fo1wDlaw4CUEeHmk=
88
github.com/alecthomas/kingpin v0.0.0-20190705085659-95eb9edaa399/go.mod h1:idxgS9pV6OOpAhZvx+gcoGRMX9/tt0iqkw/pNxI0C14=
9+
github.com/alecthomas/kingpin v0.0.0-20190930021037-0a108b7f5563 h1:YT8l7Flq7VNXnjqwtjCF9bzffTPGgedBC+xyj88lVe4=
10+
github.com/alecthomas/kingpin v0.0.0-20190930021037-0a108b7f5563/go.mod h1:idxgS9pV6OOpAhZvx+gcoGRMX9/tt0iqkw/pNxI0C14=
911
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc h1:cAKDfWh5VpdgMhJosfJnn5/FoN2SRZ4p7fJNX58YPaU=
1012
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
1113
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf h1:qet1QNfXsQxTZqLG4oE62mJzwPIB8+Tee4RNCL9ulrY=

internals/cli/masker/writer_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,7 @@ func TestNewMaskedWriter(t *testing.T) {
271271
}
272272
}
273273

274-
func TestNewMaskedWriter_OnlyFlushingOnTimeoutBug(t *testing.T) {
274+
func TestNewMaskedWriter_FlushBeforeTimeout(t *testing.T) {
275275
// There was a bug in MaskedWriter where it was only flushed on a timeout when a secret was found in the middle
276276
// of write. This test assures this bug is not present by writing a secret in the middle of a Write and
277277
// checking whether Flush() returns before the timeout of the MaskedWriter.

internals/demo/app/page.go

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
package app
2+
3+
const page = `
4+
<!doctype html>
5+
<html lang="en">
6+
<head>
7+
<meta charset="utf-8">
8+
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
9+
<meta name="description" content="">
10+
<meta name="author" content="">
11+
<link rel="icon" href="https://secrethub.io/img/favicon/favicon.ico">
12+
13+
<title>SecretHub Example App</title>
14+
15+
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.10.2/css/all.min.css" integrity="sha256-zmfNZmXoNWBMemUOo1XUGFfc0ihGGLYdgtJS3KCr/l0=" crossorigin="anonymous" />
16+
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
17+
18+
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js" integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo=" crossorigin="anonymous"></script>
19+
20+
<style>
21+
html,
22+
body {
23+
height: 100%;
24+
}
25+
26+
body {
27+
display: -ms-flexbox;
28+
display: -webkit-box;
29+
display: flex;
30+
-ms-flex-align: center;
31+
-ms-flex-pack: center;
32+
-webkit-box-align: center;
33+
align-items: center;
34+
-webkit-box-pack: center;
35+
justify-content: center;
36+
padding-top: 40px;
37+
padding-bottom: 40px;
38+
background-color: #f5f5f5;
39+
}
40+
41+
.container {
42+
width: 100%;
43+
max-width: 400px;
44+
padding: 15px;
45+
margin: 0 auto;
46+
}
47+
</style>
48+
49+
<script>
50+
function processResult(status, icon, color, result){
51+
$("#status").html(status);
52+
$("#animation").attr("class", "fas fa-"+icon+" fa-5x");
53+
$("#animation").css("color", color);
54+
if(result !== "") {
55+
$(".result-container").attr("hidden",false);
56+
try {
57+
j = JSON.parse(result);
58+
$("#result").html(j['message']);
59+
} catch (e) {
60+
$("#result").html(result);
61+
}
62+
}
63+
}
64+
65+
function processError(message){
66+
processResult("An error occurred!", "times", "red", message);
67+
}
68+
69+
$(function(){
70+
$.get("/api", {}, function(res, status, xhr){
71+
if(xhr.status === 200) {
72+
processResult("Successfully connected to https://demo.secrethub.io/api!", "check", "green", res);
73+
} else {
74+
console.log(res, status, xhr);
75+
processError(res);
76+
}
77+
}).catch(function(res){
78+
processError(res.responseText);
79+
});
80+
});
81+
</script>
82+
</head>
83+
84+
<body class="text-center">
85+
<div class="container">
86+
<img class="mb-4" src="https://secrethub.io/img/secrethub-logo-rgb-shield-square.png" alt="SecretHub logo" width="60" height="60">
87+
<h1 class="h3 mb-3 font-weight-normal">Demo App</h1>
88+
<i id="animation" class="fas fa-spinner fa-spin fa-3x"> </i>
89+
<p id="status">Trying to connect to https://demo.secrethub.io/api...</p>
90+
<div class="result-container mt-3 card" hidden>
91+
<div class="card-header">
92+
Result
93+
</div>
94+
<div class="card-body" id="result">
95+
</div>
96+
</div>
97+
<p class="mt-5 mb-3 text-muted">Read the <a href="https://secrethub.io/docs/reference/cli/demo/" target="_blank">documentation</a> for this app</p>
98+
</div>
99+
</body>
100+
</html>
101+
`

internals/demo/app/serve.go

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
package app
2+
3+
import (
4+
"fmt"
5+
"io"
6+
"net/http"
7+
"os"
8+
)
9+
10+
type Server struct {
11+
host string
12+
port int
13+
14+
appUsername string
15+
appPassword string
16+
}
17+
18+
func NewServer(host string, port int) *Server {
19+
username := os.Getenv("DEMO_USERNAME")
20+
password := os.Getenv("DEMO_PASSWORD")
21+
22+
return &Server{
23+
host: host,
24+
port: port,
25+
appUsername: username,
26+
appPassword: password,
27+
}
28+
}
29+
30+
func (s *Server) Serve() error {
31+
http.HandleFunc("/", s.ServeIndex)
32+
http.HandleFunc("/api", s.ServeAPI)
33+
34+
addr := fmt.Sprintf("%s:%d", s.host, s.port)
35+
return http.ListenAndServe(addr, nil)
36+
}
37+
38+
func (s *Server) ServeIndex(w http.ResponseWriter, r *http.Request) {
39+
_, err := w.Write([]byte(page))
40+
if err != nil {
41+
w.WriteHeader(http.StatusInternalServerError)
42+
}
43+
}
44+
45+
func (s *Server) ServeAPI(w http.ResponseWriter, r *http.Request) {
46+
w.Header().Add("Access-Control-Allow-Origin", "*")
47+
48+
if s.appUsername == "" {
49+
writeServerError(w, "DEMO_USERNAME environment variable not set")
50+
return
51+
}
52+
53+
if s.appPassword == "" {
54+
writeServerError(w, "DEMO_PASSWORD environment variable not set")
55+
return
56+
}
57+
58+
req, err := http.NewRequest("GET", "https://demo.secrethub.io/api/v1/basic-auth", nil)
59+
if err != nil {
60+
writeServerError(w, err.Error())
61+
return
62+
}
63+
64+
req.SetBasicAuth(s.appUsername, s.appPassword)
65+
resp, err := http.DefaultClient.Do(req)
66+
if err != nil {
67+
writeServerError(w, err.Error())
68+
return
69+
}
70+
w.WriteHeader(resp.StatusCode)
71+
_, err = io.Copy(w, resp.Body)
72+
if err != nil {
73+
panic(err)
74+
}
75+
}
76+
77+
func writeServerError(w http.ResponseWriter, message string) {
78+
w.WriteHeader(http.StatusInternalServerError)
79+
fmt.Fprint(w, message)
80+
}

internals/demo/command.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package demo
2+
3+
import (
4+
"github.com/secrethub/secrethub-cli/internals/cli/ui"
5+
"github.com/secrethub/secrethub-cli/internals/secrethub/command"
6+
)
7+
8+
// Command is a command to run the secrethub example app.
9+
type Command struct {
10+
io ui.IO
11+
newClient newClientFunc
12+
}
13+
14+
// NewCommand creates a new example app command.
15+
func NewCommand(io ui.IO, newClient newClientFunc) *Command {
16+
return &Command{
17+
io: io,
18+
newClient: newClient,
19+
}
20+
}
21+
22+
// Register registers the command, arguments and flags on the provided Registerer.
23+
func (cmd *Command) Register(r command.Registerer) {
24+
clause := r.Command("demo", "Manage the demo application.")
25+
clause.Hidden()
26+
27+
NewInitCommand(cmd.io, cmd.newClient).Register(clause)
28+
NewServeCommand(cmd.io).Register(clause)
29+
}

internals/demo/init.go

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
package demo
2+
3+
import (
4+
"crypto/hmac"
5+
"crypto/sha256"
6+
"encoding/base64"
7+
"fmt"
8+
9+
"github.com/secrethub/secrethub-cli/internals/cli/ui"
10+
"github.com/secrethub/secrethub-cli/internals/secrethub/command"
11+
12+
"github.com/secrethub/secrethub-go/internals/api"
13+
"github.com/secrethub/secrethub-go/pkg/secrethub"
14+
"github.com/secrethub/secrethub-go/pkg/secretpath"
15+
)
16+
17+
type newClientFunc func() (secrethub.ClientInterface, error)
18+
19+
const defaultDemoRepo = "demo"
20+
21+
type InitCommand struct {
22+
repo api.RepoPath
23+
24+
io ui.IO
25+
newClient newClientFunc
26+
}
27+
28+
func NewInitCommand(io ui.IO, newClient newClientFunc) *InitCommand {
29+
return &InitCommand{
30+
io: io,
31+
newClient: newClient,
32+
}
33+
}
34+
35+
// Register registers the command, arguments and flags on the provided Registerer.
36+
func (cmd *InitCommand) Register(r command.Registerer) {
37+
clause := r.Command("init", "Create the secrets necessary to connect with the demo application.")
38+
clause.HelpLong("demo init creates a repository with the username and password needed to connect to the demo API.")
39+
40+
clause.Flag("repo", "The path of the repository to create. Defaults to a "+defaultDemoRepo+" repo in your personal namespace.").SetValue(&cmd.repo)
41+
42+
command.BindAction(clause, cmd.Run)
43+
}
44+
45+
// Run handles the command with the options as specified in the command.
46+
func (cmd *InitCommand) Run() error {
47+
client, err := cmd.newClient()
48+
if err != nil {
49+
return err
50+
}
51+
52+
var repoPath string
53+
var username string
54+
if cmd.repo == "" {
55+
me, err := client.Me().GetUser()
56+
if err != nil {
57+
return err
58+
}
59+
username = me.Username
60+
repoPath = secretpath.Join(me.Username, defaultDemoRepo)
61+
} else {
62+
username = secretpath.Namespace(cmd.repo.Value())
63+
repoPath = cmd.repo.Value()
64+
}
65+
66+
_, err = client.Repos().Create(repoPath)
67+
if err == api.ErrRepoAlreadyExists && cmd.repo == "" {
68+
return fmt.Errorf("demo repo %s already exists, use --repo to specify another repo to use", repoPath)
69+
} else if err != nil {
70+
return err
71+
}
72+
73+
usernamePath := secretpath.Join(repoPath, "username")
74+
_, err = client.Secrets().Write(usernamePath, []byte(username))
75+
if err != nil {
76+
return err
77+
}
78+
79+
h := hmac.New(sha256.New, []byte("this-is-no-good-way-to-generate-a-password-that-is-why-we-only-use-it-for-demo-purposes"))
80+
password := base64.RawStdEncoding.EncodeToString(h.Sum([]byte(username)))[:20]
81+
82+
passwordPath := secretpath.Join(repoPath, "password")
83+
_, err = client.Secrets().Write(passwordPath, []byte(password))
84+
if err != nil {
85+
return err
86+
}
87+
88+
fmt.Printf("Created the following secrets:\n%s\n%s\n", usernamePath, passwordPath)
89+
90+
return nil
91+
}

0 commit comments

Comments
 (0)