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}