Concepts¶
Why a separate, standalone CLI¶
The signing logic has been a reusable module family for a while
(go/signing and its backends). The signing commands, however, lived inside
gtb, a framework that is deliberately both a library and a CLI. That was fine
while gtb was the only consumer, but it meant you could only get a sign /
keys command surface by building a whole gtb application.
sigillum exists to remove that constraint. It exposes sign and keys as
top-level commands rather than sub-commands of a larger app. It has since
gained decrypt and certificate, its own commands for the other job a
project's keys do: receiving encrypted vulnerability reports.
Signing, note, and not verifying: there is no sigillum verify. The
verification half of go/signing is linked in (sigillum's own update command
uses it to check the release it downloads), but it is not exposed as a command.
What sigillum does not do covers why, and
what to use instead.
The practical payoff is for non-Go and non-gtb release pipelines. A Rust
project, a shell-driven release, or any CI job that just needs to produce and
publish OpenPGP or minisign signatures can go install (or download) one
binary and sign. There is no framework build, no gtb dependency, and no bespoke
signing script to maintain.
sigillum holds no signing logic of its own. All of it stays in go/signing,
shared with gtb, so the two tools cannot drift in how they sign. See
Components & architecture for the module stack.
The build-time backend model¶
A signing backend (AWS KMS, local PEM, or a third party) implements
go/signing's crypto.Signer-based contract and registers itself in that
module's registry. The command layer never hard-codes a backend; --backend
selects a registered one, and sigillum sign --help lists whichever
backends are present.
Which backends a given binary carries is decided at build time by blank
imports in sigillum's main package:
// cmd/sigillum/signing.go
import (
_ "gitlab.com/phpboyscout/go/signing-aws-kms"
_ "gitlab.com/phpboyscout/go/signing/local"
)
Each blank import runs the backend package's init, which registers it. sigillum
ships the full set: AWS KMS + local PEM.
The encryption side has its own registry¶
decrypt and certificate resolve --backend against a separate registry
in go/encryption, populated by a separate file:
// cmd/sigillum/encryption.go
import (
_ "gitlab.com/phpboyscout/go/encryption-aws-kms"
_ "gitlab.com/phpboyscout/go/encryption/local"
)
There are two registries rather than one because the two sides want different
things from a backend. A signing backend supplies a crypto.Signer. An
encryption backend must derive a shared secret from a sender's ephemeral point
and hand back its own public half so a certificate can be published. A signing
backend has no reason to implement either. Merging them would let --backend offer a
name that cannot serve the command it was passed to.
The same build-time property holds on both sides, and independently: a build can carry AWS KMS for signing and local PEM only for encryption, or drop either side entirely.
This model also limits what a build can reach. A regulated or hardened
build can drop a blank import (remove the AWS KMS line, say) and rebuild. The
Go linker's dead-code elimination then keeps that backend's SDK, and its
transitive dependencies, out of the linked binary. The backend set is a
compile-time decision, not a runtime flag that configuration could toggle. (sigillum uses the same pattern for OS-keychain support via
cmd/sigillum/keychain.go.)