Skip to content

Commit

Permalink
Add file based configuration. (#121)
Browse files Browse the repository at this point in the history
This adds [git-config](https://git-scm.com/docs/git-config) based
configuration for gitsign values.

Caveats:
- GITSIGN_CREDENTIAL_CACHE intentionally not supported since this is
  likely changing soon.
- We do not use subsections (i.e. we use gitsign.issuer instead of gitsign.oidc.issuer).
  This gives us some wiggle room to add host based config later on
  similar to https://git-scm.com/docs/gitcredentials

Signed-off-by: Billy Lynch <billy@chainguard.dev>

Signed-off-by: Billy Lynch <billy@chainguard.dev>
  • Loading branch information
wlynch committed Aug 25, 2022
1 parent 7916a8b commit f215bd8
Show file tree
Hide file tree
Showing 12 changed files with 289 additions and 39 deletions.
42 changes: 42 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,27 @@ git config --global gpg.format x509 # gitsign expects x509 args
To learn more about these options, see
[`git-config`](https://git-scm.com/docs/git-config#Documentation/git-config.txt).

### File config

Gitsign can be configured with a standard
[git-config](https://git-scm.com/docs/git-config) file. For example, to set the
Fulcio option for a single repo:

```sh
$ git config --local gitsign.fulcio https://fulcio.example.com
```

The following config options are supported:

| Option | Default | Description |
| ----------- | -------------------------------- | --------------------------------------------------------------------------------------------- |
| fulcio | https://fulcio.sigstore.dev | Address of Fulcio server |
| logPath | | Path to log status output. Helpful for debugging when no TTY is available in the environment. |
| clientID | sigstore | OIDC client ID for application |
| issuer | https://oauth2.sigstore.dev/auth | OIDC provider to be used to issue ID token |
| redirectURL | | OIDC Redirect URL |
| rekor | https://rekor.sigstore.dev | Address of Rekor server |

### Environment Variables

| Environment Variable | Default | Description |
Expand Down Expand Up @@ -131,6 +152,27 @@ Validated Rekor entry: true

## Debugging

### Configuration

If `gitsign` is running with unexpected configs, you can validate the config
values that are being ran by running `gitsign -v`:

```sh
$ gitsign -v
gitsign version devel
env:
GITSIGN_LOG=/tmp/log.txt
parsed config:
{
"Fulcio": "https://fulcio.sigstore.dev",
"Rekor": "https://rekor.sigstore.dev",
"ClientID": "sigstore",
"RedirectURL": "",
"Issuer": "https://oauth2.sigstore.dev/auth",
"LogPath": "/tmp/log.txt"
}
```

### Signing

If there is an error during signing, you may see an error like:
Expand Down
8 changes: 3 additions & 5 deletions clients.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,11 @@
package main

import (
"github.com/sigstore/gitsign/internal"
gitrekor "github.com/sigstore/gitsign/pkg/rekor"
rekor "github.com/sigstore/rekor/pkg/client"
)

// newRekorClient returns a new Rekor client respecting gitsign environment
// variables, or using the default if not set.
func newRekorClient() (*gitrekor.Client, error) {
return gitrekor.New(internal.EnvOrValue("GITSIGN_REKOR_URL", "https://rekor.sigstore.dev"), rekor.WithUserAgent("gitsign"))
// newRekorClient returns a new Rekor client with common client options set.
func newRekorClient(url string) (*gitrekor.Client, error) {
return gitrekor.New(url, rekor.WithUserAgent("gitsign"))
}
7 changes: 4 additions & 3 deletions command_sign.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,15 @@ import (
"io"
"os"

"github.com/sigstore/gitsign/internal/config"
"github.com/sigstore/gitsign/internal/fulcio"
"github.com/sigstore/gitsign/internal/git"
"github.com/sigstore/gitsign/internal/signature"
)

func commandSign() error {
func commandSign(cfg *config.Config) error {
ctx := context.Background()
userIdent, err := fulcio.NewIdentity(ctx, ttyin, ttyout)
userIdent, err := fulcio.NewIdentity(ctx, cfg, ttyin, ttyout)
if err != nil {
return fmt.Errorf("failed to get identity: %w", err)
}
Expand All @@ -55,7 +56,7 @@ func commandSign() error {
return fmt.Errorf("failed to read message from stdin: %w", err)
}

rekor, err := newRekorClient()
rekor, err := newRekorClient(cfg.Rekor)
if err != nil {
return fmt.Errorf("failed to create rekor client: %w", err)
}
Expand Down
5 changes: 3 additions & 2 deletions command_verify.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,11 @@ import (
"os"

"github.com/sigstore/gitsign/internal"
"github.com/sigstore/gitsign/internal/config"
"github.com/sigstore/gitsign/pkg/git"
)

func commandVerify() error {
func commandVerify(cfg *config.Config) error {
ctx := context.Background()
sNewSig.emit()

Expand All @@ -44,7 +45,7 @@ func commandVerify() error {
return fmt.Errorf("failed to read signature data (detached: %T): %w", detached, err)
}

rekor, err := newRekorClient()
rekor, err := newRekorClient(cfg.Rekor)
if err != nil {
return fmt.Errorf("failed to create rekor client: %w", err)
}
Expand Down
11 changes: 10 additions & 1 deletion command_version.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,15 @@
package main

import (
"encoding/json"
"fmt"
"os"

"github.com/sigstore/gitsign/internal/config"
"github.com/sigstore/gitsign/pkg/version"
)

func commandVersion() error {
func commandVersion(cfg *config.Config) error {
v := version.GetVersionInfo()
fmt.Println("gitsign version", v.GitVersion)
if len(v.Env) > 0 {
Expand All @@ -30,6 +33,12 @@ func commandVersion() error {
fmt.Println("\t", e)
}
}
fmt.Println("parsed config:")
enc := json.NewEncoder(os.Stdout)
enc.SetIndent("", " ")
if err := enc.Encode(cfg); err != nil {
return err
}

return nil
}
3 changes: 3 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -90,13 +90,15 @@ require (
github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0 // indirect
github.com/hashicorp/golang-lru v0.5.4 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/imdario/mergo v0.3.12 // indirect
github.com/in-toto/in-toto-golang v0.3.4-0.20220709202702-fa494aaa0add // indirect
github.com/inconshreveable/mousetrap v1.0.0 // indirect
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
github.com/jedisct1/go-minisign v0.0.0-20211028175153-1c139d1cc84b // indirect
github.com/jhump/protoreflect v1.12.0 // indirect
github.com/jonboulle/clockwork v0.3.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351 // indirect
github.com/klauspost/compress v1.15.8 // indirect
github.com/leodido/go-urn v1.2.1 // indirect
github.com/letsencrypt/boulder v0.0.0-20220723181115-27de4befb95e // indirect
Expand Down Expand Up @@ -148,6 +150,7 @@ require (
github.com/transparency-dev/merkle v0.0.1 // indirect
github.com/urfave/cli v1.22.7 // indirect
github.com/vbatts/tar-split v0.11.2 // indirect
github.com/xanzy/ssh-agent v0.3.0 // indirect
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 // indirect
github.com/zeebo/errs v1.2.2 // indirect
go.etcd.io/bbolt v1.3.6 // indirect
Expand Down
3 changes: 3 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,7 @@ github.com/alexflint/go-filemutex v0.0.0-20171022225611-72bdc8eae2ae/go.mod h1:C
github.com/alexkohler/prealloc v1.0.0/go.mod h1:VetnK3dIgFBBKmg0YnD9F9x6Icjd+9cvfHR56wJVlKE=
github.com/andybalholm/brotli v1.0.2/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y=
github.com/andybalholm/brotli v1.0.3/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA=
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
github.com/antihax/optional v0.0.0-20180407024304-ca021399b1a6/go.mod h1:V8iCPQYkqmusNa815XgQio277wI47sdRh1dUOLdyC6Q=
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
Expand All @@ -221,6 +222,7 @@ github.com/armon/go-metrics v0.3.9/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4
github.com/armon/go-metrics v0.3.10/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc=
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A=
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
Expand Down Expand Up @@ -575,6 +577,7 @@ github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/github/smimesign v0.2.0 h1:Hho4YcX5N1I9XNqhq0fNx0Sts8MhLonHd+HRXVGNjvk=
github.com/github/smimesign v0.2.0/go.mod h1:iZiiwNT4HbtGRVqCQu7uJPEZCuEE5sfSSttcnePkDl4=
github.com/gliderlabs/ssh v0.2.2 h1:6zsha5zo/TWhRhwqCD3+EarCAgZ2yN28ipRnGPnwkI0=
github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
github.com/go-asn1-ber/asn1-ber v1.3.1/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
github.com/go-chi/chi v4.1.2+incompatible h1:fGFk2Gmi/YKXk0OmGfBh0WgmN3XB8lVnEyNz34tQRec=
Expand Down
113 changes: 113 additions & 0 deletions internal/config/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
// Copyright 2022 The Sigstore Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package config

import (
"os"

"github.com/go-git/go-git/v5"
"github.com/go-git/go-git/v5/config"
format "github.com/go-git/go-git/v5/plumbing/format/config"
)

// Config represents configuration options for gitsign.
type Config struct {
// Address of Fulcio server
Fulcio string
// Address of Rekor server
Rekor string

// OIDC client ID for application
ClientID string
// OIDC Redirect URL
RedirectURL string
// OIDC provider to be used to issue ID token
Issuer string

// Path to log status output. Helpful for debugging when no TTY is available in the environment.
LogPath string
}

// Get fetches the gitsign config options for the repo in the current working
// directory.
func Get() (*Config, error) {
repo, err := git.PlainOpenWithOptions(".", &git.PlainOpenOptions{DetectDotGit: true})
if err != nil {
return nil, err
}
return getWithRepo(repo)
}

// getWithRepo fetches a config for a given repository. This is separated out
// from Get so that we can create in-memory repos for testing.
func getWithRepo(repo *git.Repository) (*Config, error) {
cfg, err := repo.ConfigScoped(config.GlobalScope)
if err != nil {
return nil, err
}

out := &Config{
Fulcio: "https://fulcio.sigstore.dev",
Rekor: "https://rekor.sigstore.dev",
ClientID: "sigstore",
Issuer: "https://oauth2.sigstore.dev/auth",
}

// Get values from config file.
for _, s := range cfg.Raw.Sections {
if s.IsName("gitsign") {
applyGitOptions(out, s.Options)
}
}

// Get values from env vars
out.Fulcio = envOrValue("GITSIGN_FULCIO_URL", out.Fulcio)
out.Rekor = envOrValue("GITSIGN_REKOR_URL", out.Rekor)
out.ClientID = envOrValue("GITSIGN_OIDC_CLIENT_ID", out.ClientID)
out.RedirectURL = envOrValue("GITSIGN_OIDC_REDIRECT_URL", out.RedirectURL)
out.Issuer = envOrValue("GITSIGN_OIDC_ISSUER", out.Issuer)
out.LogPath = envOrValue("GITSIGN_LOG", out.LogPath)

return out, nil
}

func applyGitOptions(out *Config, opts format.Options) {
// Iterate over options once instead of using Get (which itself iterates
// over options until a matching key is found).
for _, o := range opts {
switch o.Key {
case "fulcio":
out.Fulcio = o.Value
case "rekor":
out.Rekor = o.Value
case "clientID":
out.ClientID = o.Value
case "redirectURL":
out.RedirectURL = o.Value
case "issuer":
out.Issuer = o.Value
case "logPath":
out.LogPath = o.Value
}
}
}

func envOrValue(env, value string) string {
// Only override values if the environment variable is set.
if v, ok := os.LookupEnv(env); ok {
return v
}
return value
}
Loading

0 comments on commit f215bd8

Please sign in to comment.