Skip to content

Configuration and environment

Everything these commands read comes from a flag or a positional argument. This page collects the few things that are not flags: the environment variables that change behaviour, the default output paths, the file modes written, and who owns the exit code.

There is no configuration file

signing-cli reads no config file, defines no environment-variable prefix, and binds no flag to an environment variable. That holds even inside a go-tool-base host: the commands never consult the host's config store, so a .mytool.yaml cannot set --backend or --key-id.

Every invocation is fully described by its command line. If you want defaults, wrap the command in your own — that is what having the builders as a library is for.

Environment variables that change behaviour

Two, and both belong to something other than this module.

Variable Read by Effect
SOURCE_DATE_EPOCH sign --format minisign Unix seconds. Sets the trusted comment's timestamp when --created is not passed. Ignored when --created is passed.
AWS_* (AWS_REGION, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN, AWS_PROFILE, …) the aws-kms backend, via the AWS SDK default credential chain Resolves credentials for --backend aws-kms. Nothing in signing-cli reads them.

SOURCE_DATE_EPOCH is honoured on the minisign path only

sign --format openpgp ignores SOURCE_DATE_EPOCH entirely. Without --created it stamps the signature with the current time, so an OpenPGP signature is not reproducible by setting the environment variable alone. Pass --created explicitly for that path.

A SOURCE_DATE_EPOCH that is not an integer fails the run rather than being ignored:

Error: parsing SOURCE_DATE_EPOCH "nope" as Unix seconds: strconv.ParseInt: parsing "nope": invalid syntax

How --created is interpreted

--created takes an RFC3339 timestamp and is accepted by sign, keys mint and keys generate. It is converted to UTC. On sign it is also truncated to whole seconds, because an OpenPGP v4 signature packet stores creation time as a 32-bit count of seconds.

Precedence on sign --format minisign is --created, then SOURCE_DATE_EPOCH, then the current time. On sign --format openpgp it is --created, then the current time.

--created must not be earlier than the signing key's own creation time. The value is used as go-crypto's notion of "now" while building the signature, so a timestamp from before the key existed makes the key look not-yet-valid and the run fails with an error that does not say so:

Error: computing signature: computing detached signature: openpgp: invalid argument: no valid signing keys

If you see that, compare --created against the key's creation date (gpg --list-packets release.asc shows it) before suspecting the key itself.

Default output paths

Command Flag Default
sign --format openpgp --output <input-file>.sig
sign --format minisign --output <input-file>.minisig
keys mint --output release.asc
keys generate --output <algorithm>.asc — i.e. rsa.asc or ed25519.asc
keys generate --private-output --output with its extension replaced: .priv.asc for Ed25519, .pem for RSA or for --private-format pem
keys minisign --output none — the bare key goes to stdout
keys wkd --output ./wkd-staging
keys publish --output ./keys-staging

keys publish places the key at <output>/minisign/<project>/v<generation>.pub and the manifest at <output>/keys.json.

keys wkd places its tree at <output>/.well-known/openpgpkey/<domain>/ for --method advanced and <output>/.well-known/openpgpkey/ for --method direct.

File modes written

Artefact Mode Why
Signature files (.sig, .minisig) 0644 Public, distributed alongside the signed file.
Armored public keys, minisign public keys 0644 Distributing them is the point.
Private halves (.pem, .priv.asc) 0600 Owner read/write only. Created with the mode, never chmod'd afterwards, so the file is never briefly world-readable.
keys.json, WKD tree files 0644 Published content.
Directories created under --output 0755 Published content.

The process umask still applies, so a restrictive umask yields tighter modes than the table; it will never yield looser ones.

Overwrite behaviour differs between sign and keys

Command Existing output
sign Overwritten silently. No --force flag exists.
keys mint Refused unless --force.
keys generate Refused unless --force (checked on both halves).
keys minisign --output Refused unless --force.
keys publish Identical content is a no-op; different content is refused. No --force.
keys wkd Overwritten silently. No --force flag exists.

The keys no-clobber guard uses O_EXCL, so the existence check and the create are one atomic syscall — there is no window between them for another process to slip in.

Exit codes belong to the host binary

Every command returns a Go error from its RunE. What that becomes is decided by the CLI you attached the builders to — typically Cobra's Execute() returning non-nil and the host's main calling os.Exit(1). signing-cli never calls os.Exit and defines no exit-code vocabulary, so there is no table of codes to match on. Match on the message or, for programmatic callers, on the exported sentinel errors listed in Errors and what they mean.

Backend-specific flags appear only when the backend is compiled in

A backend may add its own flags to sign, keys mint and keys minisign by implementing RegisterFlags(*pflag.FlagSet). The aws-kms backend adds one:

Flag Default Meaning
--kms-region eu-west-2 AWS region the KMS key lives in.

That flag is absent from --help in a binary that did not blank-import signing-aws-kms. Its default is set by the backend module, not by signing-cli, and a binary built against a different version of that backend may default differently — check --help rather than this table when it matters.

See also