-
Notifications
You must be signed in to change notification settings - Fork 29
chore: implement signing of extensions #79
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 18 commits
644c355
fe51069
3b91874
75208fe
f4091e7
2e4c55e
a72ead1
21661f0
62d0a17
404d3a7
0cdd5a3
cc33da1
43d8b50
77a862c
f8b3714
35c997b
4f7cd91
1ab2dcc
e51ea05
dd76177
adb3c66
0fa5b4e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -29,8 +29,8 @@ jobs: | |
- uses: actions/checkout@v4 | ||
- uses: actions/setup-go@v5 | ||
with: | ||
go-version: "~1.19" | ||
go-version: "~1.22" | ||
- name: golangci-lint | ||
uses: golangci/[email protected] | ||
with: | ||
version: v1.48.0 | ||
version: v1.58.0 |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,4 +2,4 @@ | |
bin | ||
coverage | ||
extensions | ||
.idea | ||
.idea |
Original file line number | Diff line number | Diff line change | ||||||
---|---|---|---|---|---|---|---|---|
|
@@ -15,21 +15,64 @@ import ( | |||||||
|
||||||||
"cdr.dev/slog" | ||||||||
"cdr.dev/slog/sloggers/sloghuman" | ||||||||
"github.com/coder/code-marketplace/extensionsign" | ||||||||
|
||||||||
"github.com/coder/code-marketplace/api" | ||||||||
"github.com/coder/code-marketplace/database" | ||||||||
"github.com/coder/code-marketplace/storage" | ||||||||
) | ||||||||
|
||||||||
func serverFlags() (addFlags func(cmd *cobra.Command), opts *storage.Options) { | ||||||||
opts = &storage.Options{} | ||||||||
var sign bool | ||||||||
return func(cmd *cobra.Command) { | ||||||||
cmd.Flags().StringVar(&opts.ExtDir, "extensions-dir", "", "The path to extensions.") | ||||||||
cmd.Flags().StringVar(&opts.Artifactory, "artifactory", "", "Artifactory server URL.") | ||||||||
cmd.Flags().StringVar(&opts.Repo, "repo", "", "Artifactory repository.") | ||||||||
cmd.Flags().DurationVar(&opts.ListCacheDuration, "list-cache-duration", time.Minute, "The duration of the extension cache.") | ||||||||
Emyrk marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||
cmd.Flags().BoolVar(&sign, "sign", false, "Sign extensions.") | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sort of a similar thought process here, I know it is hidden at the moment, but Mostly thinking of it in terms of what a user might see and think when they run There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You are right it does not make the most sense, but it is hidden. The See the flags in my other PR: code-marketplace/cli/server.go Lines 35 to 37 in 449f77c
I do have a flag to save the signature to disk. Makes it easier to debug There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm going to leave When I fix it, I'll make the flags make sense. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fabulous! |
||||||||
_ = cmd.Flags().MarkHidden("sign") // This flag needs to import a key, not just be a bool | ||||||||
|
||||||||
var before func(cmd *cobra.Command, args []string) error | ||||||||
if cmd.PreRunE != nil { | ||||||||
before = cmd.PreRunE | ||||||||
} | ||||||||
if cmd.PreRun != nil { | ||||||||
beforeNoE := cmd.PreRun | ||||||||
before = func(cmd *cobra.Command, args []string) error { | ||||||||
beforeNoE(cmd, args) | ||||||||
return nil | ||||||||
} | ||||||||
} | ||||||||
|
||||||||
cmd.PreRunE = func(cmd *cobra.Command, args []string) error { | ||||||||
opts.Logger = cmdLogger(cmd) | ||||||||
if before != nil { | ||||||||
return before(cmd, args) | ||||||||
} | ||||||||
if sign { // TODO: Remove this for an actual key import | ||||||||
opts.Signer, _ = extensionsign.GenerateKey() | ||||||||
} | ||||||||
return nil | ||||||||
} | ||||||||
}, opts | ||||||||
} | ||||||||
|
||||||||
func cmdLogger(cmd *cobra.Command) slog.Logger { | ||||||||
verbose, _ := cmd.Flags().GetBool("verbose") | ||||||||
logger := slog.Make(sloghuman.Sink(cmd.ErrOrStderr())) | ||||||||
if verbose { | ||||||||
logger = logger.Leveled(slog.LevelDebug) | ||||||||
} | ||||||||
return logger | ||||||||
} | ||||||||
|
||||||||
func server() *cobra.Command { | ||||||||
var ( | ||||||||
address string | ||||||||
artifactory string | ||||||||
extdir string | ||||||||
repo string | ||||||||
listcacheduration time.Duration | ||||||||
maxpagesize int | ||||||||
address string | ||||||||
maxpagesize int | ||||||||
) | ||||||||
addFlags, opts := serverFlags() | ||||||||
|
||||||||
cmd := &cobra.Command{ | ||||||||
Use: "server", | ||||||||
|
@@ -41,26 +84,12 @@ func server() *cobra.Command { | |||||||
RunE: func(cmd *cobra.Command, args []string) error { | ||||||||
ctx, cancel := context.WithCancel(cmd.Context()) | ||||||||
defer cancel() | ||||||||
logger := opts.Logger | ||||||||
|
||||||||
notifyCtx, notifyStop := signal.NotifyContext(ctx, interruptSignals...) | ||||||||
defer notifyStop() | ||||||||
|
||||||||
verbose, err := cmd.Flags().GetBool("verbose") | ||||||||
if err != nil { | ||||||||
return err | ||||||||
} | ||||||||
logger := slog.Make(sloghuman.Sink(cmd.ErrOrStderr())) | ||||||||
if verbose { | ||||||||
logger = logger.Leveled(slog.LevelDebug) | ||||||||
} | ||||||||
|
||||||||
store, err := storage.NewStorage(ctx, &storage.Options{ | ||||||||
Artifactory: artifactory, | ||||||||
ExtDir: extdir, | ||||||||
Logger: logger, | ||||||||
Repo: repo, | ||||||||
ListCacheDuration: listcacheduration, | ||||||||
}) | ||||||||
store, err := storage.NewStorage(ctx, opts) | ||||||||
if err != nil { | ||||||||
return err | ||||||||
} | ||||||||
|
@@ -137,12 +166,9 @@ func server() *cobra.Command { | |||||||
}, | ||||||||
} | ||||||||
|
||||||||
cmd.Flags().StringVar(&extdir, "extensions-dir", "", "The path to extensions.") | ||||||||
cmd.Flags().IntVar(&maxpagesize, "max-page-size", api.MaxPageSizeDefault, "The maximum number of pages to request") | ||||||||
cmd.Flags().StringVar(&artifactory, "artifactory", "", "Artifactory server URL.") | ||||||||
cmd.Flags().StringVar(&repo, "repo", "", "Artifactory repository.") | ||||||||
cmd.Flags().StringVar(&address, "address", "127.0.0.1:3001", "The address on which to serve the marketplace API.") | ||||||||
cmd.Flags().DurationVar(&listcacheduration, "list-cache-duration", time.Minute, "The duration of the extension cache.") | ||||||||
addFlags(cmd) | ||||||||
|
||||||||
return cmd | ||||||||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
package cli | ||
|
||
import ( | ||
"fmt" | ||
"os" | ||
|
||
"github.com/spf13/cobra" | ||
"golang.org/x/xerrors" | ||
|
||
"github.com/coder/code-marketplace/extensionsign" | ||
) | ||
|
||
func signature() *cobra.Command { | ||
cmd := &cobra.Command{ | ||
Use: "signature", | ||
Short: "Commands for debugging and working with signatures.", | ||
Hidden: true, // Debugging tools | ||
Aliases: []string{"sig", "sigs", "signatures"}, | ||
} | ||
cmd.AddCommand(compareSignatureSigZips()) | ||
return cmd | ||
} | ||
|
||
func compareSignatureSigZips() *cobra.Command { | ||
cmd := &cobra.Command{ | ||
Use: "compare", | ||
Args: cobra.ExactArgs(2), | ||
RunE: func(cmd *cobra.Command, args []string) error { | ||
decode := func(path string) (extensionsign.SignatureManifest, error) { | ||
data, err := os.ReadFile(path) | ||
if err != nil { | ||
return extensionsign.SignatureManifest{}, xerrors.Errorf("read %q: %w", args[0], err) | ||
} | ||
|
||
sig, err := extensionsign.ExtractSignatureManifest(data) | ||
if err != nil { | ||
return extensionsign.SignatureManifest{}, xerrors.Errorf("unmarshal %q: %w", path, err) | ||
} | ||
return sig, nil | ||
} | ||
|
||
a, err := decode(args[0]) | ||
if err != nil { | ||
return err | ||
} | ||
b, err := decode(args[1]) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
_, _ = fmt.Fprintf(os.Stdout, "Signature A:%s\n", a) | ||
_, _ = fmt.Fprintf(os.Stdout, "Signature B:%s\n", b) | ||
err = a.Equal(b) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
_, _ = fmt.Fprintf(os.Stdout, "Signatures are equal\n") | ||
return nil | ||
}, | ||
} | ||
return cmd | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
// Package extensionsign is a Go implementation of https://github.com/filiptronicek/node-ovsx-sign | ||
package extensionsign |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
package extensionsign | ||
|
||
import ( | ||
"crypto/ed25519" | ||
"crypto/rand" | ||
) | ||
|
||
func GenerateKey() (ed25519.PrivateKey, error) { | ||
_, private, err := ed25519.GenerateKey(rand.Reader) | ||
if err != nil { | ||
return nil, err | ||
} | ||
return private, nil | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oo yeah very nice