Skip to content

Attach the commands to a CLI

This guide shows how a host binary wires the sign and keys command builders onto its root command — first for a plain Cobra CLI, then for a go-tool-base tool. Both paths are real and compilable.

Every constructor returns a plain *cobra.Command and takes one signingcli.Logger. You do not need an adapter: a *slog.Logger and go-tool-base's logger.Logger both satisfy the interface structurally.

Attaching the commands does not compile in any signing backend — that is a separate, deliberate step. See Compile in signing backends.

Plain Cobra root (e.g. sigillum)

Add the module and attach the two top-level builders directly. NewCmdKeys returns the keys parent with mint, generate, and wkd already attached, so one AddCommand brings the whole group.

package main

import (
    "log/slog"
    "os"

    "github.com/spf13/cobra"

    signingcli "gitlab.com/phpboyscout/go/signing-cli"

    // Compile in the backends this binary should offer (see the
    // companion how-to). Without at least one, `--backend` has no
    // valid value.
    _ "gitlab.com/phpboyscout/go/signing-aws-kms" // registers "aws-kms"
    _ "gitlab.com/phpboyscout/go/signing/local"   // registers "local"
)

func main() {
    log := slog.New(slog.NewTextHandler(os.Stderr, nil))

    root := &cobra.Command{Use: "sigillum"}
    root.AddCommand(
        signingcli.NewCmdSign(log), // sign <input-file>
        signingcli.NewCmdKeys(log), // keys (mint | generate | wkd)
    )

    if err := root.Execute(); err != nil {
        os.Exit(1)
    }
}

That is the entire integration. sigillum sign …, sigillum keys mint …, sigillum keys generate …, and sigillum keys wkd … all work.

Attaching a single subcommand

If you want only part of the group — say keys mint under your own parent — the subcommand builders are exported too:

myKeys := &cobra.Command{Use: "keys"}
myKeys.AddCommand(
    signingcli.NewCmdKeysMint(log),
    signingcli.NewCmdKeysGenerate(log),
    signingcli.NewCmdKeysWKD(log),
)
root.AddCommand(myKeys)

NewCmdKeys(log) is just the convenience that does exactly this.

go-tool-base root (gtb and scaffolded tools)

go-tool-base registers subcommands through setup.Wrap, which pairs a command with the GTB feature it belongs to (an empty feature string means "always on, not gated by a feature flag"). Pass the framework logger straight in via p.GetLogger():

import (
    "gitlab.com/phpboyscout/go-tool-base/pkg/cmd/root"
    "gitlab.com/phpboyscout/go-tool-base/pkg/setup"

    signingcli "gitlab.com/phpboyscout/go/signing-cli"
)

rootCmd := root.NewCmdRoot(p,
    // … other subcommands …
    setup.Wrap("", signingcli.NewCmdKeys(p.GetLogger())),
    setup.Wrap("", signingcli.NewCmdSign(p.GetLogger())),
)

p is the GTB *props.Props; p.GetLogger() returns a logger.Logger, which satisfies signingcli.Logger directly. This is exactly how the shipped gtb binary wires the commands (internal/cmd/root/root.go).

As with the plain-Cobra path, the backends must still be blank-imported in the binary's main package. In gtb those live in a single on/off file, cmd/gtb/signing.go — see Compile in signing backends.

Verify the wiring

your-tool sign --help          # shows --backend, --key-id, --public-key, …
your-tool keys --help          # lists mint, generate, wkd
your-tool keys mint --help     # --backend's help lists the compiled-in backends

If --backend lists no backends, you have attached the commands but not compiled any backend in.

See also