Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 18 additions & 8 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
@@ -1,19 +1,29 @@
name: golangci-lint
on: push
on:
push:
pull_request:

permissions:
contents: read

jobs:
golangci:
strategy:
fail-fast: false
matrix:
go-version: [1.19]
os: [macos-latest, windows-latest, ubuntu-latest]
os:
- macos-latest
- windows-latest
- ubuntu-latest
name: lint
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v2
- uses: actions/setup-go@v2
- uses: actions/checkout@v6
- uses: actions/setup-go@v6
with:
go-version: 1.19
go-version: "1.26.x"
cache: true
- name: golangci-lint
uses: golangci/golangci-lint-action@v2
uses: golangci/golangci-lint-action@v9
with:
version: v1.50.1
version: v2.12.2
47 changes: 31 additions & 16 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -1,21 +1,36 @@
name: Continuous Integration
on: push
on:
push:
pull_request:

permissions:
contents: read

jobs:
linux:
runs-on: ubuntu-latest
test:
strategy:
fail-fast: false
matrix:
go-version:
- "1.25.x"
- "1.26.x"
os:
- ubuntu-latest
- macos-latest

name: ${{ matrix.os }} / Go ${{ matrix.go-version }}
runs-on: ${{ matrix.os }}

steps:
- uses: actions/setup-go@v2
- uses: actions/checkout@v6
- uses: actions/setup-go@v6
with:
go-version: 1.19
- run: sudo apt-get install pass gnome-keyring dbus-x11
- uses: actions/checkout@v2
- run: go test -race ./...
mac:
runs-on: macos-latest
steps:
- uses: actions/setup-go@v2
with:
go-version: 1.19
- run: brew install pass gnupg
- uses: actions/checkout@v2
go-version: ${{ matrix.go-version }}
cache: true
- name: Install Linux integration dependencies
if: runner.os == 'Linux'
run: sudo apt-get update && sudo apt-get install -y pass gnome-keyring dbus-x11
- name: Install macOS integration dependencies
if: runner.os == 'macOS'
run: brew install pass gnupg
- run: go test -race ./...
11 changes: 7 additions & 4 deletions .golangci.yml
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
version: "2"

linters:
enable:
- bodyclose
- contextcheck
- depguard
- durationcheck
- dupl
- errchkjson
- errname
- exhaustive
- exportloopref
- gocritic
- gofmt
- goimports
- makezero
- misspell
- nakedret
Expand All @@ -27,3 +25,8 @@ linters:
- unparam
# - wastedassign
- whitespace

formatters:
enable:
- gofmt
- goimports
19 changes: 15 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Keyring
=======
[![Build Status](https://github.com/99designs/keyring/workflows/Continuous%20Integration/badge.svg)](https://github.com/99designs/keyring/actions)
[![Documentation](https://godoc.org/github.com/99designs/keyring?status.svg)](https://godoc.org/github.com/99designs/keyring)
[![CI](https://github.com/lox/keyring/actions/workflows/test.yml/badge.svg)](https://github.com/lox/keyring/actions/workflows/test.yml)
[![Go Reference](https://pkg.go.dev/badge/github.com/99designs/keyring.svg)](https://pkg.go.dev/github.com/99designs/keyring)

Keyring provides a common interface to a range of secure credential storage services. Originally developed as part of [AWS Vault](https://github.com/99designs/aws-vault), a command line tool for securely managing AWS access from developer workstations.

Expand Down Expand Up @@ -34,12 +34,23 @@ i, _ := ring.Get("foo")
fmt.Printf("%s", i.Data)
```

For more detail on the API please check [the keyring godocs](https://godoc.org/github.com/99designs/keyring)
For more detail on the API please check [the keyring package docs](https://pkg.go.dev/github.com/99designs/keyring)


## Testing

[Vagrant](https://www.vagrantup.com/) is used to create linux and windows test environments.
Most tests run with only Go:

```bash
go test ./...
go test -race ./...
go run github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.12.2 run
go run golang.org/x/vuln/cmd/govulncheck@latest ./...
```

The `pass` integration tests require `pass` and `gpg`; they are skipped when those tools are not installed. Secret Service tests require an interactive DBus-backed desktop session and are skipped in GitHub Actions.

[Vagrant](https://www.vagrantup.com/) can still be used to create linux and windows test environments.

```bash
# Start vagrant
Expand Down
3 changes: 2 additions & 1 deletion array.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,14 @@ func (k *ArrayKeyring) Remove(key string) error {

// Keys provides a slice of all Item keys on the Keyring.
func (k *ArrayKeyring) Keys() ([]string, error) {
var keys = []string{}
keys := make([]string, 0, len(k.items))
for key := range k.items {
keys = append(keys, key)
}
return keys, nil
}

// GetMetadata returns ErrMetadataNeedsCredentials for the in-memory backend.
func (k *ArrayKeyring) GetMetadata(_ string) (Metadata, error) {
return Metadata{}, ErrMetadataNeedsCredentials
}
1 change: 1 addition & 0 deletions cmd/keyring/main.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// Command keyring provides a small manual testing CLI for the keyring package.
package main

import (
Expand Down
30 changes: 21 additions & 9 deletions file.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,22 +33,25 @@ type fileKeyring struct {

func (k *fileKeyring) resolveDir() (string, error) {
if k.dir == "" {
return "", fmt.Errorf("No directory provided for file keyring")
return "", fmt.Errorf("no directory provided for file keyring")
}

dir, err := ExpandTilde(k.dir)
if err != nil {
return "", err
}

stat, err := os.Stat(dir)
if os.IsNotExist(err) {
err = os.MkdirAll(dir, 0700)
} else if err != nil && stat != nil && !stat.IsDir() {
err = fmt.Errorf("%s is a file, not a directory", dir)
info, err := os.Stat(dir)
switch {
case os.IsNotExist(err):
return dir, os.MkdirAll(dir, 0700)
case err != nil:
return "", err
case !info.IsDir():
return "", fmt.Errorf("%s is a file, not a directory", dir)
}

return dir, err
return dir, nil
}

func (k *fileKeyring) unlock() error {
Expand Down Expand Up @@ -161,7 +164,13 @@ func (k *fileKeyring) Remove(key string) error {
return err
}

return os.Remove(filename)
if err := os.Remove(filename); os.IsNotExist(err) {
return ErrKeyNotFound
} else if err != nil {
return err
}

return nil
}

func (k *fileKeyring) Keys() ([]string, error) {
Expand All @@ -171,7 +180,10 @@ func (k *fileKeyring) Keys() ([]string, error) {
}

var keys = []string{}
files, _ := os.ReadDir(dir)
files, err := os.ReadDir(dir)
if err != nil {
return nil, err
}
for _, f := range files {
keys = append(keys, filenameUnescape(f.Name()))
}
Expand Down
33 changes: 31 additions & 2 deletions file_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@ package keyring

import (
"os"
"path/filepath"
"testing"
)

func TestFileKeyringSetWhenEmpty(t *testing.T) {
k := &fileKeyring{
dir: os.TempDir(),
dir: t.TempDir(),
passwordFunc: FixedStringPrompt("no more secrets"),
}
item := Item{Key: "llamas", Data: []byte("llamas are great")}
Expand All @@ -32,7 +33,7 @@ func TestFileKeyringSetWhenEmpty(t *testing.T) {

func TestFileKeyringGetWithSlashes(t *testing.T) {
k := &fileKeyring{
dir: os.TempDir(),
dir: t.TempDir(),
passwordFunc: FixedStringPrompt("no more secrets"),
}

Expand All @@ -47,6 +48,34 @@ func TestFileKeyringGetWithSlashes(t *testing.T) {
}
}

func TestFileKeyringRemoveWhenEmpty(t *testing.T) {
k := &fileKeyring{
dir: t.TempDir(),
passwordFunc: FixedStringPrompt("no more secrets"),
}

err := k.Remove("no-such-key")
if err != ErrKeyNotFound {
t.Fatalf("expected ErrKeyNotFound, got: %v", err)
}
}

func TestFileKeyringRejectsFileDir(t *testing.T) {
path := filepath.Join(t.TempDir(), "keyring")
if err := os.WriteFile(path, []byte("not a directory"), 0600); err != nil {
t.Fatal(err)
}

k := &fileKeyring{
dir: path,
passwordFunc: FixedStringPrompt("no more secrets"),
}

if _, err := k.Keys(); err == nil {
t.Fatal("expected file keyring to reject a file path")
}
}

func TestFilenameWithBadChars(t *testing.T) {
a := `abc/.././123`
e := filenameEscape(a)
Expand Down
15 changes: 7 additions & 8 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,22 +1,21 @@
module github.com/99designs/keyring

go 1.19
go 1.25.0

require (
github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4
github.com/danieljoos/wincred v1.1.2
github.com/dvsekhvalnov/jose2go v1.5.0
github.com/danieljoos/wincred v1.2.3
github.com/dvsekhvalnov/jose2go v1.8.0
github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2
github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c
github.com/mtibben/percent v0.2.1
github.com/stretchr/testify v1.7.0
golang.org/x/sys v0.3.0
golang.org/x/term v0.3.0
github.com/stretchr/testify v1.11.1
golang.org/x/sys v0.46.0
golang.org/x/term v0.44.0
)

require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/stretchr/objx v0.3.0 // indirect
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
33 changes: 14 additions & 19 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 h1:/vQbFIOMbk2FiG/kXiLl8BRyzTWDw7gX/Hz7Dd5eDMs=
github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4/go.mod h1:hN7oaIRCjzsZ2dE+yG5k+rsdt3qcwykqK6HVGcKwsw4=
github.com/danieljoos/wincred v1.1.2 h1:QLdCxFs1/Yl4zduvBdcHB8goaYk9RARS2SgLLRuAyr0=
github.com/danieljoos/wincred v1.1.2/go.mod h1:GijpziifJoIBfYh+S7BbkdUTU4LfM+QnGqR5Vl2tAx0=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/danieljoos/wincred v1.2.3 h1:v7dZC2x32Ut3nEfRH+vhoZGvN72+dQ/snVXo/vMFLdQ=
github.com/danieljoos/wincred v1.2.3/go.mod h1:6qqX0WNrS4RzPZ1tnroDzq9kY3fu1KwE7MRLQK4X0bs=
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/dvsekhvalnov/jose2go v1.5.0 h1:3j8ya4Z4kMCwT5nXIKFSV84YS+HdqSSO0VsTQxaLAeM=
github.com/dvsekhvalnov/jose2go v1.5.0/go.mod h1:QsHjhyTlD/lAVqn/NSbVZmSCGeDehTB/mPZadG+mhXU=
github.com/dvsekhvalnov/jose2go v1.8.0 h1:LqkkVKAlHFfH9LOEl5fe4p/zL02OhWE7pCufMBG2jLA=
github.com/dvsekhvalnov/jose2go v1.8.0/go.mod h1:QsHjhyTlD/lAVqn/NSbVZmSCGeDehTB/mPZadG+mhXU=
github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 h1:ZpnhV/YsD2/4cESfV5+Hoeu/iUR3ruzNvZ+yQfO03a0=
github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4=
github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c h1:6rhixN/i8ZofjG1Y75iExal34USq5p+wiN1tpie8IrU=
Expand All @@ -20,20 +19,16 @@ github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWb
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
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/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.3.0 h1:NGXK3lHquSN08v5vWalVI/L8XU9hdzE/G6xsrze47As=
github.com/stretchr/objx v0.3.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
golang.org/x/sys v0.0.0-20210819135213-f52c844e1c1c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ=
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.3.0 h1:qoo4akIqOcDME5bhc/NgxUdovd6BSS2uMsVjB56q1xI=
golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA=
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
golang.org/x/sys v0.46.0 h1:noSf2Fq6F8DBgS+LysIkx7rIExoNHJsxOAtPp4rthXw=
golang.org/x/sys v0.46.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
golang.org/x/term v0.44.0 h1:0rLvDRCtNj0gZkyIXhCyOb2OAzEhLVqc4B+hrsBhrmc=
golang.org/x/term v0.44.0/go.mod h1:7ze4MdzUzLXpSAoFP1H0bOI9aXDqveSvatT5vKcFh2Y=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b h1:QRR6H1YWRnHb4Y/HeNFCTJLFVxaq6wH4YuVdsUOr75U=
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
Loading
Loading