Help us shape the future of Go! Take the 2026 Go Developer Survey

packagesign

package
v3.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 1, 2026 License: MIT Imports: 19 Imported by: 0

README

Native package signing

Sign adds signatures to existing DEB and RPM packages using the existing ProtonMail OpenPGP dependency. It does not execute a package manager, GnuPG or another signing program. It streams package contents and preserves the existing DEB members or RPM immutable header and compressed payload byte for byte.

The caller supplies separate input and output paths and owns transactional publication. An error can leave a partial output; the input is never overwritten. The key must be an exported armored or binary private key. Encrypted keys use the supplied password. A multi-identity export requires a full fingerprint or long key ID selector. Expired, revoked, public-only and unavailable signing keys are rejected through the crypto library's signing-key selection.

DEB signatures use the dpkg-sig v4 clear-signed manifest, including the format's MD5/SHA1 member digests. The OpenPGP signature uses SHA-256. Existing signatures are preserved and included in the new signature; repeated roles receive a numeric member suffix. This is package-level dpkg-sig compatibility, not apt repository metadata signing or an assertion that apt automatically verifies these signatures.

RPM signing supports the v4 immutable-header format and OpenPGP v4 RSA, DSA, ECDSA and legacy EdDSA keys. Both header and header-plus-payload signatures use SHA-256. Existing header/payload digests are checked before adding signatures. Package signatures are replaced while unrelated signature-header fields survive. Header allocations are bounded; malformed indexes, strings, lengths, and regions are rejected. No unpacking, recompression or package metadata regeneration occurs.

The archlinux format writes a binary detached OpenPGP signature to the supplied output path. It shares key parsing and selection with DEB and RPM.

A bare GnuPG key ID is not a key file and cannot be resolved without access to a GnuPG keyring. Callers retaining key-ID configurations must keep their legacy external-tool path or ask users to export the private key. Missing or unreadable key files must not silently fall back to a different identity.

Validation

Unit tests use only standard-library test helpers and Wails-owned fixtures. The encrypted fixture password is package-test-password; these committed keys are public test material and must never be used for releases. The RSA and Ed25519 keys were generated specifically for these tests with GnuPG. The unsigned packages were generated through the already-installed nfpm API from an original one-line shell payload, not copied from another project.

go test -race ./internal/packagesign
go test ./internal/packagesign -run '^$' -bench BenchmarkSignPackage -benchmem
WAILS_TEST_PACKAGE_SIGNING=1 go test ./internal/packagesign -run TestIndependentPackageReaders -v

The optional acceptance test requires GnuPG, dpkg-sig and RPM, with a writable temporary RPM database. These are independent test verifiers, not runtime dependencies. Acceptance on 2026-11-01 used dpkg-sig 0.13.1+nmu4, RPM 4.18.2 and GnuPG 2.4.4: encrypted/plain RSA and encrypted Ed25519 signatures, repeated native signing, and native signing after official dpkg-sig/rpmsign signing all verified. Both official readers rejected modified payloads.

Three 200 ms benchmark samples on Linux/amd64, Go 1.26.10, Ryzen 3950X and GOMAXPROCS=4 measured median signing times for the small fixtures:

Key DEB RPM
Encrypted RSA 48.216 ms 50.023 ms
Plain RSA 2.525 ms 3.895 ms

These measure complete key parsing/unlocking and file signing, not large-package throughput or a comparison against external tools. A separate CPU profile spent about 97% in the encrypted key's iterated S2K derivation; SHA-NI hashing was the largest leaf. Existing library/standard-library acceleration is used. No custom assembly or weakened key derivation was justified.

Format references and implementation provenance

The archive/signature-envelope code is original Wails code written against the published formats and checked with independent command-line readers. No external implementation was copied or adapted. Existing dependencies were inspected for public API availability: nfpm and rpmpack expose creation-time signing callbacks, but no existing-artifact rewrite API. No module was added.

Documentation

Overview

Package packagesign signs existing Linux package archives without invoking external tools. The archive payload is preserved byte for byte.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func KeyFile

func KeyFile(root, reference string) (string, bool)

KeyFile distinguishes exported files from legacy GnuPG key IDs. Explicit paths and conventional key extensions remain files even when unreadable or missing, so a broken key cannot silently select the external signer.

func Sign

func Sign(ctx context.Context, input, output string, options Options) error

Sign writes a signed archive to output, which must differ from input. The caller owns transactional publication and removal of a partial output. KeyFile must contain an exported OpenPGP secret key, not a GnuPG key ID.

Types

type Options

type Options struct {
	Format   string
	KeyFile  string
	Password string
	// KeyID optionally selects a primary key or signing subkey from the export.
	// It accepts a full fingerprint or a 16-digit key ID.
	KeyID string
	// Role is the dpkg-sig role; an empty value means builder.
	Role string
}

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL