gopass/docs/hacking.md
Dominik Schulz af9eec1de4
Readme cleanup (#2434)
This commit moves much of the content out of the overloaded
README with the goal of making it easier for new users to get
a first impression and start using gopass. Most information
is still retained inside the docs/ folder.

RELEASE_NOTES=n/a

Signed-off-by: Dominik Schulz <dominik.schulz@gauner.org>

Signed-off-by: Dominik Schulz <dominik.schulz@gauner.org>
2022-12-01 22:54:02 +01:00

113 lines
3.7 KiB
Markdown

# Hacking on gopass
Note: See [CONTRIBUTING.md](../CONTRIBUTING.md) for an overview.
This document provides an overview on how to develop on gopass.
## Development
This project uses [GitHub Flow](https://guides.github.com/introduction/flow/). In other words, create feature branches from master, open an PR against master, and rebase onto master if necessary.
We aim for compatibility with the [latest stable Go Release](https://golang.org/dl/) only.
While this project is maintained by volunteers in their free time we aim to triage issues weekly and release a new version at least every quarter.
## Setting up an isolated development environment
### With GPG
`gopass` should fully respect `GOPASS_HOMEDIR` overriding all gopass internal paths.
However it will still use your normal GPG keyring and configuration. To override this
you will need to set `GNUPGHOME` as well and possibly generate a new keyring.
```bash
$ export GOPASS_DEBUG_LOG=/tmp/gp1.log
$ export GOPASS_HOMEDIR=/tmp/gp1
$ mkdir -p $GOPASS_HOMEDIR
$ export GNUPGHOME=$GOPASS_HOMEDIR/.gnupg
# Make sure that you're using the correct keyring.
$ gpg -K
gpg: directory '/tmp/gp1/.gnupg' created
gpg: keybox '/tmp/gp1/.gnupg/pubring.kbx' created
gpg: /tmp/gp1/.gnupg/trustdb.gpg: trustdb created
$ gpg --gen-key
$ go build && ./gopass setup --crypto gpg --storage gitfs
```
### With age
Using `age` is recommended for development since it's easier to set up. Setting
`GOPASS_HOMEDIR` should be sufficient to ensure an isolated environment.
```bash
$ export GOPASS_DEBUG_LOG=/tmp/gp1.log
$ export GOPASS_HOMEDIR=/tmp/gp1
$ mkdir -p $GOPASS_HOMEDIR
$ go build && ./gopass setup --crypto age --storage gitfs
```
## Extending gopass
The main extension model are small binaries that use the [gopass API](https://pkg.go.dev/github.com/gopasspw/gopass/pkg/gopass/api) package. This package provides a small and easy to use API that should work with any up to date gopass setup.
This API encapsulates the exact same implementation that the CLI uses in a more nicely packaged format that's easier to use.
Note: The API is operating directly on the password store. It does not involve network operations or connecting to a gopass instance.
The API does not support setting up a new password store (yet). Users will need have an existing password store
or use `gopass setup` to create a new one. The API will attempt to load an existing configuration or use it's built-in
defaults. Then it initializes an existing password store and provides a simple set of CRUD operations.
Our API has some [examples](../pkg/gopass/api/api_test.go) on how to use the API. The [gopass-hibp](https://github.com/gopasspw/gopass-hibp/blob/master/main.go) binary should provide a more complete example that can be used as a blueprint.
```go
import (
"context"
"fmt"
"github.com/gopasspw/gopass/pkg/gopass/api"
"github.com/gopasspw/gopass/pkg/gopass/secrets"
)
ctx := context.Background()
gp, err := api.New(ctx)
if err != nil {
panic(err)
}
// Listing secrets by their names (path within the store).
ls, err := gp.List(ctx)
if err != nil {
panic(err)
}
for _, s := range ls {
fmt.Printf("Secret: %s", s)
}
// Writing secrets to a specific location (path) in the store.
sec := secrets.New()
sec.SetPassword("foobar")
if err := gp.Set(ctx, "my/new/secret", sec); err != nil {
panic(err)
}
// Reading secrets by their name and revision from within the store.
sec, err = gp.Get(ctx, "my/new/secret", "latest")
if err != nil {
panic(err)
}
fmt.Printf("content of %s: %s\n", "my/new/secret", string(sec.Bytes()))
// Removing a secret by their name.
if err := gp.Remove(ctx, "my/new/secret"); err != nil {
panic(err)
}
// Cleaning up (waiting for background processing to complete).
if err := gp.Close(ctx); err != nil {
panic(err)
}
```