v0.17.0 ab8e178

cli_signing.go RawHistoryFolder

1// SPDX-License-Identifier: AGPL-3.0-or-later
2
3package app
4
5import (
6	"fmt"
7
8	"connectrpc.com/connect"
9	"github.com/spf13/cobra"
10
11	"bnema.dev/ermite-api/gen/ermite"
12)
13
14// jsonSigningKey is the stable JSON shape of `signing-key show --json`.
15type jsonSigningKey struct {
16	PublicKey      string `json:"public_key"`
17	Fingerprint    string `json:"fingerprint"`
18	CommitterName  string `json:"committer_name"`
19	CommitterEmail string `json:"committer_email"`
20	AllowedSigners string `json:"allowed_signers"`
21}
22
23func newSigningKeyCmd(env *cliEnv) *cobra.Command {
24	key := &cobra.Command{
25		Use:   "signing-key",
26		Short: "Show the key that signs the commits the server creates",
27		Long: "The server signs the commits it creates (squash merges) with its own SSH key, so that they show as\n" +
28			"verified. Needs a server with the signing_key feature (see `ermite version`).",
29	}
30	key.AddCommand(newSigningKeyShowCmd(env))
31	return key
32}
33
34func newSigningKeyShowCmd(env *cliEnv) *cobra.Command {
35	var allowedSigners, publicKey bool
36	cmd := &cobra.Command{
37		Use:   "show",
38		Short: "Print the public signing key of the server",
39		Long: "Print the public key of the server, its fingerprint and the committer it records. The key is public:\n" +
40			"no token is needed. Register it for the committer's email on Forgejo or GitHub, or save the\n" +
41			"allowed-signers line to a file to verify commits locally:\n\n" +
42			"  ermite signing-key show --allowed-signers >> ~/.config/git/allowed_signers\n" +
43			"  git config gpg.ssh.allowedSignersFile ~/.config/git/allowed_signers\n" +
44			"  git log --show-signature\n\n" +
45			"--public-key prints only the authorized_keys line, --allowed-signers only the allowed-signers line\n" +
46			"(\"<committer email> <key>\"), each ready to be redirected into a file.\n\n" +
47			"JSON fields (--json): public_key, fingerprint (SHA256:...), committer_name, committer_email,\n" +
48			"allowed_signers.",
49		Args: cobra.NoArgs,
50	}
51	cmd.Flags().BoolVar(&publicKey, "public-key", false, "print only the key as an authorized_keys line")
52	cmd.Flags().BoolVar(&allowedSigners, "allowed-signers", false, "print only the line for an allowed signers file")
53	cmd.MarkFlagsMutuallyExclusive("public-key", "allowed-signers")
54	asJSON := addJSONFlag(cmd)
55	cmd.MarkFlagsMutuallyExclusive("json", "public-key")
56	cmd.MarkFlagsMutuallyExclusive("json", "allowed-signers")
57	cmd.RunE = func(cmd *cobra.Command, _ []string) error {
58		c, err := env.client(cmd)
59		if err != nil {
60			return err
61		}
62		res, err := c.Server().GetSigningKey(env.ctx(cmd), connect.NewRequest(&ermite.GetSigningKeyRequest{}))
63		if err != nil {
64			return c.Describe(err)
65		}
66		k := res.Msg
67		out := cmd.OutOrStdout()
68		switch {
69		case *asJSON:
70			return writeJSON(out, jsonSigningKey{
71				PublicKey: k.GetPublicKey(), Fingerprint: k.GetFingerprint(), CommitterName: k.GetCommitterName(),
72				CommitterEmail: k.GetCommitterEmail(), AllowedSigners: k.GetAllowedSigners(),
73			})
74		case publicKey:
75			_, err = fmt.Fprintln(out, clean(k.GetPublicKey()))
76		case allowedSigners:
77			_, err = fmt.Fprintln(out, clean(k.GetAllowedSigners()))
78		default:
79			err = fields(out, [][2]string{
80				{"fingerprint", k.GetFingerprint()},
81				{"committer", k.GetCommitterName() + " <" + k.GetCommitterEmail() + ">"},
82				{"public key", k.GetPublicKey()},
83				{"allowed signers", k.GetAllowedSigners()},
84			})
85		}
86		return err
87	}
88	return cmd
89}

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 2

Tags 43

↑↓ moveenter openesc close