You've already forked goreleaser
mirror of
https://github.com/goreleaser/goreleaser.git
synced 2025-07-17 01:42:37 +02:00
feat: sign with env and output certificate (#2662)
* feat: sign with env and output certificate * fix: test * fix: prop name * test: blob upload * test: http upload * test: exec * test: sign
This commit is contained in:
committed by
GitHub
parent
52cf951c30
commit
312e52a760
@ -48,6 +48,8 @@ const (
|
|||||||
Checksum
|
Checksum
|
||||||
// Signature is a signature file.
|
// Signature is a signature file.
|
||||||
Signature
|
Signature
|
||||||
|
// Certificate is a signing certificate file
|
||||||
|
Certificate
|
||||||
// UploadableSourceArchive is the archive with the current commit source code.
|
// UploadableSourceArchive is the archive with the current commit source code.
|
||||||
UploadableSourceArchive
|
UploadableSourceArchive
|
||||||
// BrewTap is an uploadable homebrew tap recipe file.
|
// BrewTap is an uploadable homebrew tap recipe file.
|
||||||
@ -80,6 +82,8 @@ func (t Type) String() string {
|
|||||||
return "Checksum"
|
return "Checksum"
|
||||||
case Signature:
|
case Signature:
|
||||||
return "Signature"
|
return "Signature"
|
||||||
|
case Certificate:
|
||||||
|
return "Certificate"
|
||||||
case UploadableSourceArchive:
|
case UploadableSourceArchive:
|
||||||
return "Source"
|
return "Source"
|
||||||
case BrewTap:
|
case BrewTap:
|
||||||
|
@ -359,6 +359,7 @@ func TestTypeToString(t *testing.T) {
|
|||||||
DockerManifest,
|
DockerManifest,
|
||||||
Checksum,
|
Checksum,
|
||||||
Signature,
|
Signature,
|
||||||
|
Certificate,
|
||||||
UploadableSourceArchive,
|
UploadableSourceArchive,
|
||||||
BrewTap,
|
BrewTap,
|
||||||
GoFishRig,
|
GoFishRig,
|
||||||
|
@ -114,7 +114,7 @@ func filterArtifacts(artifacts artifact.Artifacts, publisher config.Publisher) [
|
|||||||
}
|
}
|
||||||
|
|
||||||
if publisher.Signature {
|
if publisher.Signature {
|
||||||
filters = append(filters, artifact.ByType(artifact.Signature))
|
filters = append(filters, artifact.ByType(artifact.Signature), artifact.ByType(artifact.Certificate))
|
||||||
}
|
}
|
||||||
|
|
||||||
filter := artifact.Or(filters...)
|
filter := artifact.Or(filters...)
|
||||||
|
@ -41,6 +41,7 @@ func TestExecute(t *testing.T) {
|
|||||||
{"ubinary", "ubi", artifact.UploadableBinary},
|
{"ubinary", "ubi", artifact.UploadableBinary},
|
||||||
{"checksum", "sum", artifact.Checksum},
|
{"checksum", "sum", artifact.Checksum},
|
||||||
{"signature", "sig", artifact.Signature},
|
{"signature", "sig", artifact.Signature},
|
||||||
|
{"signature", "pem", artifact.Certificate},
|
||||||
} {
|
} {
|
||||||
file := filepath.Join(folder, "a."+a.ext)
|
file := filepath.Join(folder, "a."+a.ext)
|
||||||
require.NoError(t, os.WriteFile(file, []byte("lorem ipsum"), 0o644))
|
require.NoError(t, os.WriteFile(file, []byte("lorem ipsum"), 0o644))
|
||||||
@ -172,6 +173,7 @@ func TestExecute(t *testing.T) {
|
|||||||
{ExpectedArgs: []string{"a.ubi"}, ExitCode: 0, ExpectedEnv: osEnv()},
|
{ExpectedArgs: []string{"a.ubi"}, ExitCode: 0, ExpectedEnv: osEnv()},
|
||||||
{ExpectedArgs: []string{"a.tar"}, ExitCode: 0, ExpectedEnv: osEnv()},
|
{ExpectedArgs: []string{"a.tar"}, ExitCode: 0, ExpectedEnv: osEnv()},
|
||||||
{ExpectedArgs: []string{"a.sig"}, ExitCode: 0, ExpectedEnv: osEnv()},
|
{ExpectedArgs: []string{"a.sig"}, ExitCode: 0, ExpectedEnv: osEnv()},
|
||||||
|
{ExpectedArgs: []string{"a.pem"}, ExitCode: 0, ExpectedEnv: osEnv()},
|
||||||
{ExpectedArgs: []string{"foo/bar"}, ExitCode: 0, ExpectedEnv: osEnv()},
|
{ExpectedArgs: []string{"foo/bar"}, ExitCode: 0, ExpectedEnv: osEnv()},
|
||||||
{ExpectedArgs: []string{"foo/bar:amd64"}, ExitCode: 0, ExpectedEnv: osEnv()},
|
{ExpectedArgs: []string{"foo/bar:amd64"}, ExitCode: 0, ExpectedEnv: osEnv()},
|
||||||
},
|
},
|
||||||
|
@ -149,7 +149,7 @@ func Upload(ctx *context.Context, uploads []config.Upload, kind string, check Re
|
|||||||
filters = append(filters, artifact.ByType(artifact.Checksum))
|
filters = append(filters, artifact.ByType(artifact.Checksum))
|
||||||
}
|
}
|
||||||
if upload.Signature {
|
if upload.Signature {
|
||||||
filters = append(filters, artifact.ByType(artifact.Signature))
|
filters = append(filters, artifact.ByType(artifact.Signature), artifact.ByType(artifact.Certificate))
|
||||||
}
|
}
|
||||||
// We support two different modes
|
// We support two different modes
|
||||||
// - "archive": Upload all artifacts
|
// - "archive": Upload all artifacts
|
||||||
|
@ -249,6 +249,7 @@ func TestUpload(t *testing.T) {
|
|||||||
{"ubi", artifact.UploadableBinary},
|
{"ubi", artifact.UploadableBinary},
|
||||||
{"sum", artifact.Checksum},
|
{"sum", artifact.Checksum},
|
||||||
{"sig", artifact.Signature},
|
{"sig", artifact.Signature},
|
||||||
|
{"pem", artifact.Certificate},
|
||||||
} {
|
} {
|
||||||
file := filepath.Join(folder, "a."+a.ext)
|
file := filepath.Join(folder, "a."+a.ext)
|
||||||
require.NoError(t, os.WriteFile(file, []byte("lorem ipsum"), 0o644))
|
require.NoError(t, os.WriteFile(file, []byte("lorem ipsum"), 0o644))
|
||||||
@ -438,6 +439,7 @@ func TestUpload(t *testing.T) {
|
|||||||
check{"/blah/2.1.0/a.tar", "u3", "x", content, map[string]string{}},
|
check{"/blah/2.1.0/a.tar", "u3", "x", content, map[string]string{}},
|
||||||
check{"/blah/2.1.0/a.sum", "u3", "x", content, map[string]string{}},
|
check{"/blah/2.1.0/a.sum", "u3", "x", content, map[string]string{}},
|
||||||
check{"/blah/2.1.0/a.sig", "u3", "x", content, map[string]string{}},
|
check{"/blah/2.1.0/a.sig", "u3", "x", content, map[string]string{}},
|
||||||
|
check{"/blah/2.1.0/a.pem", "u3", "x", content, map[string]string{}},
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -58,10 +58,14 @@ func TestMinioUpload(t *testing.T) {
|
|||||||
tgzpath := filepath.Join(folder, "bin.tar.gz")
|
tgzpath := filepath.Join(folder, "bin.tar.gz")
|
||||||
debpath := filepath.Join(folder, "bin.deb")
|
debpath := filepath.Join(folder, "bin.deb")
|
||||||
checkpath := filepath.Join(folder, "check.txt")
|
checkpath := filepath.Join(folder, "check.txt")
|
||||||
|
sigpath := filepath.Join(folder, "f.sig")
|
||||||
|
certpath := filepath.Join(folder, "f.pem")
|
||||||
require.NoError(t, os.WriteFile(checkpath, []byte("fake checksums"), 0o744))
|
require.NoError(t, os.WriteFile(checkpath, []byte("fake checksums"), 0o744))
|
||||||
require.NoError(t, os.WriteFile(srcpath, []byte("fake\nsrc"), 0o744))
|
require.NoError(t, os.WriteFile(srcpath, []byte("fake\nsrc"), 0o744))
|
||||||
require.NoError(t, os.WriteFile(tgzpath, []byte("fake\ntargz"), 0o744))
|
require.NoError(t, os.WriteFile(tgzpath, []byte("fake\ntargz"), 0o744))
|
||||||
require.NoError(t, os.WriteFile(debpath, []byte("fake\ndeb"), 0o744))
|
require.NoError(t, os.WriteFile(debpath, []byte("fake\ndeb"), 0o744))
|
||||||
|
require.NoError(t, os.WriteFile(sigpath, []byte("fake\nsig"), 0o744))
|
||||||
|
require.NoError(t, os.WriteFile(certpath, []byte("fake\ncert"), 0o744))
|
||||||
ctx := context.New(config.Project{
|
ctx := context.New(config.Project{
|
||||||
Dist: folder,
|
Dist: folder,
|
||||||
ProjectName: "testupload",
|
ProjectName: "testupload",
|
||||||
@ -86,6 +90,22 @@ func TestMinioUpload(t *testing.T) {
|
|||||||
Name: "checksum.txt",
|
Name: "checksum.txt",
|
||||||
Path: checkpath,
|
Path: checkpath,
|
||||||
})
|
})
|
||||||
|
ctx.Artifacts.Add(&artifact.Artifact{
|
||||||
|
Type: artifact.Signature,
|
||||||
|
Name: "checksum.txt.sig",
|
||||||
|
Path: sigpath,
|
||||||
|
Extra: map[string]interface{}{
|
||||||
|
artifact.ExtraID: "foo",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
ctx.Artifacts.Add(&artifact.Artifact{
|
||||||
|
Type: artifact.Certificate,
|
||||||
|
Name: "checksum.pem",
|
||||||
|
Path: certpath,
|
||||||
|
Extra: map[string]interface{}{
|
||||||
|
artifact.ExtraID: "foo",
|
||||||
|
},
|
||||||
|
})
|
||||||
ctx.Artifacts.Add(&artifact.Artifact{
|
ctx.Artifacts.Add(&artifact.Artifact{
|
||||||
Type: artifact.UploadableSourceArchive,
|
Type: artifact.UploadableSourceArchive,
|
||||||
Name: "source.tar.gz",
|
Name: "source.tar.gz",
|
||||||
@ -119,6 +139,8 @@ func TestMinioUpload(t *testing.T) {
|
|||||||
"testupload/v1.0.0/bin.deb",
|
"testupload/v1.0.0/bin.deb",
|
||||||
"testupload/v1.0.0/bin.tar.gz",
|
"testupload/v1.0.0/bin.tar.gz",
|
||||||
"testupload/v1.0.0/checksum.txt",
|
"testupload/v1.0.0/checksum.txt",
|
||||||
|
"testupload/v1.0.0/checksum.txt.sig",
|
||||||
|
"testupload/v1.0.0/checksum.pem",
|
||||||
"testupload/v1.0.0/source.tar.gz",
|
"testupload/v1.0.0/source.tar.gz",
|
||||||
"testupload/v1.0.0/file.golden",
|
"testupload/v1.0.0/file.golden",
|
||||||
})
|
})
|
||||||
|
@ -81,6 +81,7 @@ func doUpload(ctx *context.Context, conf config.Blob) error {
|
|||||||
artifact.ByType(artifact.UploadableSourceArchive),
|
artifact.ByType(artifact.UploadableSourceArchive),
|
||||||
artifact.ByType(artifact.Checksum),
|
artifact.ByType(artifact.Checksum),
|
||||||
artifact.ByType(artifact.Signature),
|
artifact.ByType(artifact.Signature),
|
||||||
|
artifact.ByType(artifact.Certificate),
|
||||||
artifact.ByType(artifact.LinuxPackage),
|
artifact.ByType(artifact.LinuxPackage),
|
||||||
)
|
)
|
||||||
if len(conf.IDs) > 0 {
|
if len(conf.IDs) > 0 {
|
||||||
|
11
internal/pipe/env/env.go
vendored
11
internal/pipe/env/env.go
vendored
@ -7,7 +7,6 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/apex/log"
|
"github.com/apex/log"
|
||||||
"github.com/goreleaser/goreleaser/internal/tmpl"
|
"github.com/goreleaser/goreleaser/internal/tmpl"
|
||||||
@ -45,16 +44,16 @@ func setDefaultTokenFiles(ctx *context.Context) {
|
|||||||
// Run the pipe.
|
// Run the pipe.
|
||||||
func (Pipe) Run(ctx *context.Context) error {
|
func (Pipe) Run(ctx *context.Context) error {
|
||||||
templ := tmpl.New(ctx).WithEnvS(os.Environ())
|
templ := tmpl.New(ctx).WithEnvS(os.Environ())
|
||||||
|
tEnv := []string{}
|
||||||
for i := range ctx.Config.Env {
|
for i := range ctx.Config.Env {
|
||||||
env, err := templ.Apply(ctx.Config.Env[i])
|
env, err := templ.Apply(ctx.Config.Env[i])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// XXX: this has no risk of panicking because it would already have
|
tEnv = append(tEnv, env)
|
||||||
// panicked at `context.go`'s `splitEnv` method.
|
}
|
||||||
// Need to properly handle this at some point.
|
for k, v := range context.ToEnv(tEnv) {
|
||||||
parts := strings.SplitN(env, "=", 2)
|
ctx.Env[k] = v
|
||||||
ctx.Env[parts[0]] = parts[1]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setDefaultTokenFiles(ctx)
|
setDefaultTokenFiles(ctx)
|
||||||
|
@ -153,6 +153,7 @@ func doPublish(ctx *context.Context, client client.Client) error {
|
|||||||
artifact.ByType(artifact.UploadableSourceArchive),
|
artifact.ByType(artifact.UploadableSourceArchive),
|
||||||
artifact.ByType(artifact.Checksum),
|
artifact.ByType(artifact.Checksum),
|
||||||
artifact.ByType(artifact.Signature),
|
artifact.ByType(artifact.Signature),
|
||||||
|
artifact.ByType(artifact.Certificate),
|
||||||
artifact.ByType(artifact.LinuxPackage),
|
artifact.ByType(artifact.LinuxPackage),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -18,23 +18,24 @@ func TestPipeDescription(t *testing.T) {
|
|||||||
require.NotEmpty(t, Pipe{}.String())
|
require.NotEmpty(t, Pipe{}.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func createTmpFile(tb testing.TB, folder, path string) string {
|
||||||
|
tb.Helper()
|
||||||
|
f, err := os.Create(filepath.Join(folder, path))
|
||||||
|
require.NoError(tb, err)
|
||||||
|
require.NoError(tb, f.Close())
|
||||||
|
return f.Name()
|
||||||
|
}
|
||||||
|
|
||||||
func TestRunPipeWithoutIDsThenDoesNotFilter(t *testing.T) {
|
func TestRunPipeWithoutIDsThenDoesNotFilter(t *testing.T) {
|
||||||
folder := t.TempDir()
|
folder := t.TempDir()
|
||||||
tarfile, err := os.Create(filepath.Join(folder, "bin.tar.gz"))
|
tarfile := createTmpFile(t, folder, "bin.tar.gz")
|
||||||
require.NoError(t, err)
|
srcfile := createTmpFile(t, folder, "source.tar.gz")
|
||||||
require.NoError(t, tarfile.Close())
|
debfile := createTmpFile(t, folder, "bin.deb")
|
||||||
srcfile, err := os.Create(filepath.Join(folder, "source.tar.gz"))
|
checksumfile := createTmpFile(t, folder, "checksum")
|
||||||
require.NoError(t, err)
|
checksumsigfile := createTmpFile(t, folder, "checksum.sig")
|
||||||
require.NoError(t, srcfile.Close())
|
checksumpemfile := createTmpFile(t, folder, "checksum.pem")
|
||||||
debfile, err := os.Create(filepath.Join(folder, "bin.deb"))
|
filteredtarfile := createTmpFile(t, folder, "filtered.tar.gz")
|
||||||
require.NoError(t, err)
|
filtereddebfile := createTmpFile(t, folder, "filtered.deb")
|
||||||
require.NoError(t, debfile.Close())
|
|
||||||
filteredtarfile, err := os.Create(filepath.Join(folder, "filtered.tar.gz"))
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.NoError(t, filteredtarfile.Close())
|
|
||||||
filtereddebfile, err := os.Create(filepath.Join(folder, "filtered.deb"))
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.NoError(t, filtereddebfile.Close())
|
|
||||||
|
|
||||||
config := config.Project{
|
config := config.Project{
|
||||||
Dist: folder,
|
Dist: folder,
|
||||||
@ -50,7 +51,7 @@ func TestRunPipeWithoutIDsThenDoesNotFilter(t *testing.T) {
|
|||||||
ctx.Artifacts.Add(&artifact.Artifact{
|
ctx.Artifacts.Add(&artifact.Artifact{
|
||||||
Type: artifact.UploadableArchive,
|
Type: artifact.UploadableArchive,
|
||||||
Name: "bin.tar.gz",
|
Name: "bin.tar.gz",
|
||||||
Path: tarfile.Name(),
|
Path: tarfile,
|
||||||
Extra: map[string]interface{}{
|
Extra: map[string]interface{}{
|
||||||
artifact.ExtraID: "foo",
|
artifact.ExtraID: "foo",
|
||||||
},
|
},
|
||||||
@ -58,7 +59,7 @@ func TestRunPipeWithoutIDsThenDoesNotFilter(t *testing.T) {
|
|||||||
ctx.Artifacts.Add(&artifact.Artifact{
|
ctx.Artifacts.Add(&artifact.Artifact{
|
||||||
Type: artifact.LinuxPackage,
|
Type: artifact.LinuxPackage,
|
||||||
Name: "bin.deb",
|
Name: "bin.deb",
|
||||||
Path: debfile.Name(),
|
Path: debfile,
|
||||||
Extra: map[string]interface{}{
|
Extra: map[string]interface{}{
|
||||||
artifact.ExtraID: "foo",
|
artifact.ExtraID: "foo",
|
||||||
},
|
},
|
||||||
@ -66,7 +67,7 @@ func TestRunPipeWithoutIDsThenDoesNotFilter(t *testing.T) {
|
|||||||
ctx.Artifacts.Add(&artifact.Artifact{
|
ctx.Artifacts.Add(&artifact.Artifact{
|
||||||
Type: artifact.UploadableArchive,
|
Type: artifact.UploadableArchive,
|
||||||
Name: "filtered.tar.gz",
|
Name: "filtered.tar.gz",
|
||||||
Path: filteredtarfile.Name(),
|
Path: filteredtarfile,
|
||||||
Extra: map[string]interface{}{
|
Extra: map[string]interface{}{
|
||||||
artifact.ExtraID: "bar",
|
artifact.ExtraID: "bar",
|
||||||
},
|
},
|
||||||
@ -74,7 +75,7 @@ func TestRunPipeWithoutIDsThenDoesNotFilter(t *testing.T) {
|
|||||||
ctx.Artifacts.Add(&artifact.Artifact{
|
ctx.Artifacts.Add(&artifact.Artifact{
|
||||||
Type: artifact.LinuxPackage,
|
Type: artifact.LinuxPackage,
|
||||||
Name: "filtered.deb",
|
Name: "filtered.deb",
|
||||||
Path: filtereddebfile.Name(),
|
Path: filtereddebfile,
|
||||||
Extra: map[string]interface{}{
|
Extra: map[string]interface{}{
|
||||||
artifact.ExtraID: "bar",
|
artifact.ExtraID: "bar",
|
||||||
},
|
},
|
||||||
@ -82,11 +83,36 @@ func TestRunPipeWithoutIDsThenDoesNotFilter(t *testing.T) {
|
|||||||
ctx.Artifacts.Add(&artifact.Artifact{
|
ctx.Artifacts.Add(&artifact.Artifact{
|
||||||
Type: artifact.UploadableSourceArchive,
|
Type: artifact.UploadableSourceArchive,
|
||||||
Name: "source.tar.gz",
|
Name: "source.tar.gz",
|
||||||
Path: srcfile.Name(),
|
Path: srcfile,
|
||||||
Extra: map[string]interface{}{
|
Extra: map[string]interface{}{
|
||||||
artifact.ExtraFormat: "tar.gz",
|
artifact.ExtraFormat: "tar.gz",
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
ctx.Artifacts.Add(&artifact.Artifact{
|
||||||
|
Type: artifact.Checksum,
|
||||||
|
Name: "checksum",
|
||||||
|
Path: checksumfile,
|
||||||
|
Extra: map[string]interface{}{
|
||||||
|
artifact.ExtraID: "bar",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
ctx.Artifacts.Add(&artifact.Artifact{
|
||||||
|
Type: artifact.Signature,
|
||||||
|
Name: "checksum.sig",
|
||||||
|
Path: checksumsigfile,
|
||||||
|
Extra: map[string]interface{}{
|
||||||
|
artifact.ExtraID: "bar",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
ctx.Artifacts.Add(&artifact.Artifact{
|
||||||
|
Type: artifact.Certificate,
|
||||||
|
Name: "checksum.pem",
|
||||||
|
Path: checksumpemfile,
|
||||||
|
Extra: map[string]interface{}{
|
||||||
|
artifact.ExtraID: "bar",
|
||||||
|
},
|
||||||
|
})
|
||||||
client := &client.Mock{}
|
client := &client.Mock{}
|
||||||
require.NoError(t, doPublish(ctx, client))
|
require.NoError(t, doPublish(ctx, client))
|
||||||
require.True(t, client.CreatedRelease)
|
require.True(t, client.CreatedRelease)
|
||||||
@ -96,6 +122,9 @@ func TestRunPipeWithoutIDsThenDoesNotFilter(t *testing.T) {
|
|||||||
require.Contains(t, client.UploadedFileNames, "bin.tar.gz")
|
require.Contains(t, client.UploadedFileNames, "bin.tar.gz")
|
||||||
require.Contains(t, client.UploadedFileNames, "filtered.deb")
|
require.Contains(t, client.UploadedFileNames, "filtered.deb")
|
||||||
require.Contains(t, client.UploadedFileNames, "filtered.tar.gz")
|
require.Contains(t, client.UploadedFileNames, "filtered.tar.gz")
|
||||||
|
require.Contains(t, client.UploadedFileNames, "checksum")
|
||||||
|
require.Contains(t, client.UploadedFileNames, "checksum.pem")
|
||||||
|
require.Contains(t, client.UploadedFileNames, "checksum.sig")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRunPipeWithIDsThenFilters(t *testing.T) {
|
func TestRunPipeWithIDsThenFilters(t *testing.T) {
|
||||||
|
@ -101,34 +101,44 @@ func (Pipe) Run(ctx *context.Context) error {
|
|||||||
|
|
||||||
func sign(ctx *context.Context, cfg config.Sign, artifacts []*artifact.Artifact) error {
|
func sign(ctx *context.Context, cfg config.Sign, artifacts []*artifact.Artifact) error {
|
||||||
for _, a := range artifacts {
|
for _, a := range artifacts {
|
||||||
artifact, err := signone(ctx, cfg, a)
|
artifacts, err := signone(ctx, cfg, a)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if artifact != nil {
|
for _, artifact := range artifacts {
|
||||||
ctx.Artifacts.Add(artifact)
|
ctx.Artifacts.Add(artifact)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func signone(ctx *context.Context, cfg config.Sign, a *artifact.Artifact) (*artifact.Artifact, error) {
|
func signone(ctx *context.Context, cfg config.Sign, art *artifact.Artifact) ([]*artifact.Artifact, error) {
|
||||||
env := ctx.Env.Copy()
|
env := ctx.Env.Copy()
|
||||||
env["artifact"] = a.Path
|
env["artifactName"] = art.Name
|
||||||
env["artifactID"] = a.ID()
|
env["artifact"] = art.Path
|
||||||
|
env["artifactID"] = art.ID()
|
||||||
|
for k, v := range context.ToEnv(cfg.Env) {
|
||||||
|
env[k] = v
|
||||||
|
}
|
||||||
|
|
||||||
name, err := tmpl.New(ctx).WithEnv(env).Apply(expand(cfg.Signature, env))
|
name, err := tmpl.New(ctx).WithEnv(env).Apply(expand(cfg.Signature, env))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("sign failed: %s: invalid template: %w", a, err)
|
return nil, fmt.Errorf("sign failed: %s: %w", art.Name, err)
|
||||||
}
|
}
|
||||||
env["signature"] = name
|
env["signature"] = name
|
||||||
|
|
||||||
|
cert, err := tmpl.New(ctx).WithEnv(env).Apply(expand(cfg.Certificate, env))
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("sign failed: %s: %w", art.Name, err)
|
||||||
|
}
|
||||||
|
env["certificate"] = cert
|
||||||
|
|
||||||
// nolint:prealloc
|
// nolint:prealloc
|
||||||
var args []string
|
var args []string
|
||||||
for _, a := range cfg.Args {
|
for _, a := range cfg.Args {
|
||||||
arg, err := tmpl.New(ctx).WithEnv(env).Apply(expand(a, env))
|
arg, err := tmpl.New(ctx).WithEnv(env).Apply(expand(a, env))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("sign failed: %s: invalid template: %w", a, err)
|
return nil, fmt.Errorf("sign failed: %s: %w", art.Name, err)
|
||||||
}
|
}
|
||||||
args = append(args, arg)
|
args = append(args, arg)
|
||||||
}
|
}
|
||||||
@ -150,7 +160,7 @@ func signone(ctx *context.Context, cfg config.Sign, a *artifact.Artifact) (*arti
|
|||||||
stdin = f
|
stdin = f
|
||||||
}
|
}
|
||||||
|
|
||||||
fields := log.Fields{"cmd": cfg.Cmd, "artifact": a.Name}
|
fields := log.Fields{"cmd": cfg.Cmd, "artifact": art.Name}
|
||||||
|
|
||||||
// The GoASTScanner flags this as a security risk.
|
// The GoASTScanner flags this as a security risk.
|
||||||
// However, this works as intended. The nosec annotation
|
// However, this works as intended. The nosec annotation
|
||||||
@ -164,6 +174,7 @@ func signone(ctx *context.Context, cfg config.Sign, a *artifact.Artifact) (*arti
|
|||||||
if stdin != nil {
|
if stdin != nil {
|
||||||
cmd.Stdin = stdin
|
cmd.Stdin = stdin
|
||||||
}
|
}
|
||||||
|
cmd.Env = append(env.Strings(), cfg.Env...)
|
||||||
log.WithFields(fields).Info("signing")
|
log.WithFields(fields).Info("signing")
|
||||||
if err := cmd.Run(); err != nil {
|
if err := cmd.Run(); err != nil {
|
||||||
return nil, fmt.Errorf("sign: %s failed: %w: %s", cfg.Cmd, err, b.String())
|
return nil, fmt.Errorf("sign: %s failed: %w: %s", cfg.Cmd, err, b.String())
|
||||||
@ -173,22 +184,37 @@ func signone(ctx *context.Context, cfg config.Sign, a *artifact.Artifact) (*arti
|
|||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
env["artifact"] = a.Name
|
env["artifact"] = art.Name
|
||||||
name, err = tmpl.New(ctx).WithEnv(env).Apply(expand(cfg.Signature, env))
|
name, err = tmpl.New(ctx).WithEnv(env).Apply(expand(cfg.Signature, env))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("sign failed: %s: invalid template: %w", a, err)
|
return nil, fmt.Errorf("sign failed: %s: invalid template: %w", art.Name, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
artifactPathBase, _ := filepath.Split(a.Path)
|
artifactPathBase, _ := filepath.Split(art.Path)
|
||||||
sigFilename := filepath.Base(env["signature"])
|
sigFilename := filepath.Base(env["signature"])
|
||||||
return &artifact.Artifact{
|
result := []*artifact.Artifact{
|
||||||
Type: artifact.Signature,
|
{
|
||||||
Name: name,
|
Type: artifact.Signature,
|
||||||
Path: filepath.Join(artifactPathBase, sigFilename),
|
Name: name,
|
||||||
Extra: map[string]interface{}{
|
Path: filepath.Join(artifactPathBase, sigFilename),
|
||||||
artifact.ExtraID: cfg.ID,
|
Extra: map[string]interface{}{
|
||||||
|
artifact.ExtraID: cfg.ID,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}, nil
|
}
|
||||||
|
|
||||||
|
if cert != "" {
|
||||||
|
result = append(result, &artifact.Artifact{
|
||||||
|
Type: artifact.Certificate,
|
||||||
|
Name: cert,
|
||||||
|
Path: filepath.Join(artifactPathBase, cert),
|
||||||
|
Extra: map[string]interface{}{
|
||||||
|
artifact.ExtraID: cfg.ID,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func expand(s string, env map[string]string) string {
|
func expand(s string, env map[string]string) string {
|
||||||
|
@ -129,6 +129,7 @@ func TestDockerSignArtifacts(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
// TODO: keyless test?
|
||||||
} {
|
} {
|
||||||
t.Run(name, func(t *testing.T) {
|
t.Run(name, func(t *testing.T) {
|
||||||
ctx := context.New(config.Project{})
|
ctx := context.New(config.Project{})
|
||||||
|
@ -83,12 +83,13 @@ func TestSignArtifacts(t *testing.T) {
|
|||||||
stdin := passwordUser
|
stdin := passwordUser
|
||||||
tmplStdin := passwordUserTmpl
|
tmplStdin := passwordUserTmpl
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
desc string
|
desc string
|
||||||
ctx *context.Context
|
ctx *context.Context
|
||||||
signaturePaths []string
|
signaturePaths []string
|
||||||
signatureNames []string
|
signatureNames []string
|
||||||
expectedErrMsg string
|
certificateNames []string
|
||||||
user string
|
expectedErrMsg string
|
||||||
|
user string
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
desc: "sign errors",
|
desc: "sign errors",
|
||||||
@ -105,9 +106,39 @@ func TestSignArtifacts(t *testing.T) {
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
desc: "invalid certificate template",
|
||||||
|
expectedErrMsg: `sign failed: artifact1: template: tmpl:1:3: executing "tmpl" at <.blah>: map has no entry for key "blah"`,
|
||||||
|
ctx: context.New(
|
||||||
|
config.Project{
|
||||||
|
Signs: []config.Sign{
|
||||||
|
{
|
||||||
|
Artifacts: "all",
|
||||||
|
Cmd: "exit",
|
||||||
|
Certificate: "{{ .blah }}",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "invalid signature template",
|
||||||
|
expectedErrMsg: `sign failed: artifact1: template: tmpl:1:3: executing "tmpl" at <.blah>: map has no entry for key "blah"`,
|
||||||
|
ctx: context.New(
|
||||||
|
config.Project{
|
||||||
|
Signs: []config.Sign{
|
||||||
|
{
|
||||||
|
Artifacts: "all",
|
||||||
|
Cmd: "exit",
|
||||||
|
Signature: "{{ .blah }}",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
desc: "invalid args template",
|
desc: "invalid args template",
|
||||||
expectedErrMsg: `sign failed: ${FOO}-{{ .foo }{{}}{: invalid template: template: tmpl:1: unexpected "}" in operand`,
|
expectedErrMsg: `sign failed: artifact1: template: tmpl:1: unexpected "}" in operand`,
|
||||||
ctx: context.New(
|
ctx: context.New(
|
||||||
config.Project{
|
config.Project{
|
||||||
Signs: []config.Sign{
|
Signs: []config.Sign{
|
||||||
@ -282,6 +313,21 @@ func TestSignArtifacts(t *testing.T) {
|
|||||||
signaturePaths: []string{"artifact5.tar.gz.sig"},
|
signaturePaths: []string{"artifact5.tar.gz.sig"},
|
||||||
signatureNames: []string{"artifact5.tar.gz.sig"},
|
signatureNames: []string{"artifact5.tar.gz.sig"},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
desc: "sign only source filter by id",
|
||||||
|
ctx: context.New(
|
||||||
|
config.Project{
|
||||||
|
Signs: []config.Sign{
|
||||||
|
{
|
||||||
|
Artifacts: "source",
|
||||||
|
IDs: []string{"should-not-be-used"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
),
|
||||||
|
signaturePaths: []string{"artifact5.tar.gz.sig"},
|
||||||
|
signatureNames: []string{"artifact5.tar.gz.sig"},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
desc: "sign all artifacts with env",
|
desc: "sign all artifacts with env",
|
||||||
ctx: context.New(
|
ctx: context.New(
|
||||||
@ -441,6 +487,39 @@ func TestSignArtifacts(t *testing.T) {
|
|||||||
),
|
),
|
||||||
expectedErrMsg: `sign failed: cannot open file /tmp/non-existing-file: open /tmp/non-existing-file: no such file or directory`,
|
expectedErrMsg: `sign failed: cannot open file /tmp/non-existing-file: open /tmp/non-existing-file: no such file or directory`,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
desc: "sign creating certificate",
|
||||||
|
ctx: context.New(
|
||||||
|
config.Project{
|
||||||
|
Signs: []config.Sign{
|
||||||
|
{
|
||||||
|
Certificate: "${artifactName}.pem",
|
||||||
|
Artifacts: "checksum",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
),
|
||||||
|
signaturePaths: []string{"checksum.sig", "checksum2.sig"},
|
||||||
|
signatureNames: []string{"checksum.sig", "checksum2.sig"},
|
||||||
|
certificateNames: []string{"checksum.pem", "checksum2.pem"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "sign all artifacts with env and certificate",
|
||||||
|
ctx: context.New(
|
||||||
|
config.Project{
|
||||||
|
Signs: []config.Sign{
|
||||||
|
{
|
||||||
|
Env: []string{"HONK=honk"},
|
||||||
|
Certificate: `{{ trimsuffix (trimsuffix .Env.artifactName ".tar.gz") ".deb" }}_${HONK}.pem`,
|
||||||
|
Artifacts: "all",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
),
|
||||||
|
signaturePaths: []string{"artifact1.sig", "artifact2.sig", "artifact3.sig", "checksum.sig", "checksum2.sig", "linux_amd64/artifact4.sig", "artifact5.tar.gz.sig", "package1.deb.sig"},
|
||||||
|
signatureNames: []string{"artifact1.sig", "artifact2.sig", "artifact3_1.0.0_linux_amd64.sig", "checksum.sig", "checksum2.sig", "artifact4_1.0.0_linux_amd64.sig", "artifact5.tar.gz.sig", "package1.deb.sig"},
|
||||||
|
certificateNames: []string{"artifact1_honk.pem", "artifact2_honk.pem", "artifact3_1.0.0_linux_amd64_honk.pem", "checksum_honk.pem", "checksum2_honk.pem", "artifact4_1.0.0_linux_amd64_honk.pem", "artifact5_honk.pem", "package1_honk.pem"},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
@ -449,12 +528,12 @@ func TestSignArtifacts(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
t.Run(test.desc, func(t *testing.T) {
|
t.Run(test.desc, func(t *testing.T) {
|
||||||
testSign(t, test.ctx, test.signaturePaths, test.signatureNames, test.user, test.expectedErrMsg)
|
testSign(t, test.ctx, test.certificateNames, test.signaturePaths, test.signatureNames, test.user, test.expectedErrMsg)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func testSign(tb testing.TB, ctx *context.Context, signaturePaths []string, signatureNames []string, user, expectedErrMsg string) {
|
func testSign(tb testing.TB, ctx *context.Context, certificateNames, signaturePaths, signatureNames []string, user, expectedErrMsg string) {
|
||||||
tb.Helper()
|
tb.Helper()
|
||||||
tmpdir := tb.TempDir()
|
tmpdir := tb.TempDir()
|
||||||
|
|
||||||
@ -548,10 +627,27 @@ func testSign(tb testing.TB, ctx *context.Context, signaturePaths []string, sign
|
|||||||
require.NoError(tb, Pipe{}.Run(ctx))
|
require.NoError(tb, Pipe{}.Run(ctx))
|
||||||
|
|
||||||
// ensure all artifacts have an ID
|
// ensure all artifacts have an ID
|
||||||
for _, arti := range ctx.Artifacts.Filter(artifact.ByType(artifact.Signature)).List() {
|
for _, arti := range ctx.Artifacts.Filter(
|
||||||
|
artifact.Or(
|
||||||
|
artifact.ByType(artifact.Signature),
|
||||||
|
artifact.ByType(artifact.Certificate),
|
||||||
|
),
|
||||||
|
).List() {
|
||||||
require.NotEmptyf(tb, arti.ID(), ".Extra.ID on %s", arti.Path)
|
require.NotEmptyf(tb, arti.ID(), ".Extra.ID on %s", arti.Path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
certificates := ctx.Artifacts.Filter(artifact.ByType(artifact.Certificate)).List()
|
||||||
|
certNames := []string{}
|
||||||
|
for _, cert := range certificates {
|
||||||
|
certNames = append(certNames, cert.Name)
|
||||||
|
}
|
||||||
|
sort.Strings(certificateNames)
|
||||||
|
sort.Strings(certNames)
|
||||||
|
require.Equal(tb, len(certificateNames), len(certificates))
|
||||||
|
if len(certificateNames) > 0 {
|
||||||
|
require.Equal(tb, certificateNames, certNames)
|
||||||
|
}
|
||||||
|
|
||||||
// verify that only the artifacts and the signatures are in the dist dir
|
// verify that only the artifacts and the signatures are in the dist dir
|
||||||
gotFiles := []string{}
|
gotFiles := []string{}
|
||||||
|
|
||||||
|
@ -605,14 +605,16 @@ type NFPMOverridables struct {
|
|||||||
|
|
||||||
// Sign config.
|
// Sign config.
|
||||||
type Sign struct {
|
type Sign struct {
|
||||||
ID string `yaml:"id,omitempty"`
|
ID string `yaml:"id,omitempty"`
|
||||||
Cmd string `yaml:"cmd,omitempty"`
|
Cmd string `yaml:"cmd,omitempty"`
|
||||||
Args []string `yaml:"args,omitempty"`
|
Args []string `yaml:"args,omitempty"`
|
||||||
Signature string `yaml:"signature,omitempty"`
|
Signature string `yaml:"signature,omitempty"`
|
||||||
Artifacts string `yaml:"artifacts,omitempty"`
|
Artifacts string `yaml:"artifacts,omitempty"`
|
||||||
IDs []string `yaml:"ids,omitempty"`
|
IDs []string `yaml:"ids,omitempty"`
|
||||||
Stdin *string `yaml:"stdin,omitempty"`
|
Stdin *string `yaml:"stdin,omitempty"`
|
||||||
StdinFile string `yaml:"stdin_file,omitempty"`
|
StdinFile string `yaml:"stdin_file,omitempty"`
|
||||||
|
Env []string `yaml:"env,omitempty"`
|
||||||
|
Certificate string `yaml:"certificate,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// SnapcraftAppMetadata for the binaries that will be in the snap package.
|
// SnapcraftAppMetadata for the binaries that will be in the snap package.
|
||||||
|
@ -120,18 +120,21 @@ func Wrap(ctx ctx.Context, config config.Project) *Context {
|
|||||||
return &Context{
|
return &Context{
|
||||||
Context: ctx,
|
Context: ctx,
|
||||||
Config: config,
|
Config: config,
|
||||||
Env: splitEnv(append(os.Environ(), config.Env...)),
|
Env: ToEnv(append(os.Environ(), config.Env...)),
|
||||||
Parallelism: 4,
|
Parallelism: 4,
|
||||||
Artifacts: artifact.New(),
|
Artifacts: artifact.New(),
|
||||||
Date: time.Now(),
|
Date: time.Now(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func splitEnv(env []string) map[string]string {
|
// ToEnv converts a list of strings to an Env (aka a map[string]string).
|
||||||
// TODO: this might panic if there is no `=` sign
|
func ToEnv(env []string) Env {
|
||||||
r := map[string]string{}
|
r := Env{}
|
||||||
for _, e := range env {
|
for _, e := range env {
|
||||||
p := strings.SplitN(e, "=", 2)
|
p := strings.SplitN(e, "=", 2)
|
||||||
|
if len(p) != 2 || p[0] == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
r[p[0]] = p[1]
|
r[p[0]] = p[1]
|
||||||
}
|
}
|
||||||
return r
|
return r
|
||||||
|
@ -30,3 +30,9 @@ func TestNewWithTimeout(t *testing.T) {
|
|||||||
<-ctx.Done()
|
<-ctx.Done()
|
||||||
require.EqualError(t, ctx.Err(), `context canceled`)
|
require.EqualError(t, ctx.Err(), `context canceled`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestToEnv(t *testing.T) {
|
||||||
|
require.Equal(t, Env{"FOO": "BAR"}, ToEnv([]string{"=nope", "FOO=BAR"}))
|
||||||
|
require.Equal(t, Env{"FOO": "BAR"}, ToEnv([]string{"nope", "FOO=BAR"}))
|
||||||
|
require.Equal(t, Env{"FOO": "BAR", "nope": ""}, ToEnv([]string{"nope=", "FOO=BAR"}))
|
||||||
|
}
|
||||||
|
@ -20,11 +20,6 @@ docker_signs:
|
|||||||
id: foo
|
id: foo
|
||||||
|
|
||||||
# Name/template of the signature file.
|
# Name/template of the signature file.
|
||||||
#
|
|
||||||
# Available environment variables:
|
|
||||||
# - '${artifact}': the path to the artifact that will be signed
|
|
||||||
# - '${artifactID}': the ID of the artifact that will be signed
|
|
||||||
#
|
|
||||||
# Note that with cosign you don't need to use this.
|
# Note that with cosign you don't need to use this.
|
||||||
#
|
#
|
||||||
# Defaults to empty.
|
# Defaults to empty.
|
||||||
@ -65,8 +60,33 @@ docker_signs:
|
|||||||
# StdinFile file to be given to the signature command as stdin.
|
# StdinFile file to be given to the signature command as stdin.
|
||||||
# Defaults to empty
|
# Defaults to empty
|
||||||
stdin_file: ./.password
|
stdin_file: ./.password
|
||||||
|
|
||||||
|
# Sets a certificate name that your signing command should write to.
|
||||||
|
# You can later use `${certificate}` or `.Env.certificate` in the `args` section.
|
||||||
|
# This is particularly useful for keyless signing (for instance, with cosign).
|
||||||
|
# Note that this should be a name, not a path.
|
||||||
|
#
|
||||||
|
# Defaults to empty.
|
||||||
|
certificate: '{{ trimsuffix .Env.artifactName ".tar.gz" }}.pem'
|
||||||
|
|
||||||
|
# List of environment variables that will be passed to the signing command as well as the templates.
|
||||||
|
#
|
||||||
|
# Defaults to empty
|
||||||
|
env:
|
||||||
|
- FOO=bar
|
||||||
|
- HONK=honkhonk
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Available variable names
|
||||||
|
|
||||||
|
These environment variables might be available in the fields that are templateable:
|
||||||
|
|
||||||
|
- `${artifactName}`: the name of the artifact
|
||||||
|
- `${artifact}`: the path to the artifact that will be signed
|
||||||
|
- `${artifactID}`: the ID of the artifact that will be signed
|
||||||
|
- `${certificate}`: the certificate filename, if provided
|
||||||
|
- `${signature}`: the signature filename, if provided
|
||||||
|
|
||||||
## Common usage example
|
## Common usage example
|
||||||
|
|
||||||
Assuming you have a `cosign.key` in the repository root and a `COSIGN_PWD`
|
Assuming you have a `cosign.key` in the repository root and a `COSIGN_PWD`
|
||||||
|
@ -34,10 +34,6 @@ signs:
|
|||||||
|
|
||||||
# Name/template of the signature file.
|
# Name/template of the signature file.
|
||||||
#
|
#
|
||||||
# Available environment variables:
|
|
||||||
# - '${artifact}': the path to the artifact that will be signed
|
|
||||||
# - '${artifactID}': the ID of the artifact that will be signed
|
|
||||||
#
|
|
||||||
# Defaults to `${artifact}.sig`.
|
# Defaults to `${artifact}.sig`.
|
||||||
signature: "${artifact}_sig"
|
signature: "${artifact}_sig"
|
||||||
|
|
||||||
@ -86,8 +82,33 @@ signs:
|
|||||||
#
|
#
|
||||||
# Defaults to empty
|
# Defaults to empty
|
||||||
stdin_file: ./.password
|
stdin_file: ./.password
|
||||||
|
|
||||||
|
# Sets a certificate that your signing command should write to.
|
||||||
|
# You can later use `${certificate}` or `.Env.certificate` in the `args` section.
|
||||||
|
# This is particularly useful for keyless signing (for instance, with cosign).
|
||||||
|
# Note that this should be a name, not a path.
|
||||||
|
#
|
||||||
|
# Defaults to empty.
|
||||||
|
certificate: '{{ trimsuffix .Env.artifactName ".tar.gz" }}.pem'
|
||||||
|
|
||||||
|
# List of environment variables that will be passed to the signing command as well as the templates.
|
||||||
|
#
|
||||||
|
# Defaults to empty
|
||||||
|
env:
|
||||||
|
- FOO=bar
|
||||||
|
- HONK=honkhonk
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Available variable names
|
||||||
|
|
||||||
|
These environment variables might be available in the fields that are templateable:
|
||||||
|
|
||||||
|
- `${artifactName}`: the name of the artifact
|
||||||
|
- `${artifact}`: the path to the artifact that will be signed
|
||||||
|
- `${artifactID}`: the ID of the artifact that will be signed
|
||||||
|
- `${certificate}`: the certificate filename, if provided
|
||||||
|
- `${signature}`: the signature filename
|
||||||
|
|
||||||
## Signing with cosign
|
## Signing with cosign
|
||||||
|
|
||||||
You can sign you artifacts with [cosign][] as well.
|
You can sign you artifacts with [cosign][] as well.
|
||||||
@ -109,6 +130,7 @@ Your users can then verify the signature with:
|
|||||||
cosign verify-blob -key cosign.pub -signature file.tar.gz.sig file.tar.gz
|
cosign verify-blob -key cosign.pub -signature file.tar.gz.sig file.tar.gz
|
||||||
```
|
```
|
||||||
|
|
||||||
|
<!-- TODO: keyless signing with cosign example -->
|
||||||
|
|
||||||
## Signing executables
|
## Signing executables
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user