trident
Publishing, yanking, and auditing packages
Releasing a version of a package, withdrawing it without breaking existing users, and requiring human review and signed provenance for the dependencies a project uses.
since 0.1.0-alpha.1linux
Description
This page covers the two ends of the package life cycle: the author, who publishes and withdraws
versions, and the consumer, who decides which packages to trust. The commands are publish,
yank, attest, audit and audit-record; their full argument lists are in trident.commands.
Publishing a version
A package is a git repository with a trident.toml that has a name, a version and the
sources that make up the package. trident publish turns the current commit into a release:
$ trident publish . --path github.com/acme/json
published github.com/acme/json@1.2.0
tag: v1.2.0 (3d897718e9af7d68553d49745db79182deefc4cb)
hash: sha256:ab66a23e591b15c87616eb388c9f7351a4b4291b35da98d119acf2502f9e4696
It refuses unless the package's working tree is clean, so everything that is published is committed.
It then creates the git tag v<version>, taking the version from the manifest, or from --tag vX.Y.Z when you give one, and records the package's hash in the checksum record. A published tag
is immutable: publishing again from the same commit changes nothing and succeeds, and publishing a
tag that already names a different commit is an error. --path is the repository path that consumers
will write in their [[dep]] tables. trident publish creates the tag in your local repository; pushing
it to the remote is a separate git push.
If TRIDENT_INDEX is set, publish also registers the package's name as a short name for that
path (see trident.versions-and-integrity). A name that is already registered to another repository
cannot be re-registered.
Yanking a version
trident yank <path>@<version> withdraws a version without deleting it. A fresh resolution can no
longer choose a yanked version, and says so, while a project that already has the version in its
trident.lock keeps building and auditing with it:
$ trident yank github.com/acme/json@1.2.0
yanked github.com/acme/json@1.2.0 (existing locks remain valid)
$ trident fetch
error: github.com/acme/json@1.2.0 is yanked and cannot be selected by a new resolution; an existing consistent trident.lock may continue to use it (run `trident why github.com/acme/json` to inspect the chain)
The yank is recorded in the checksum record on the machine where you ran the command.
Attesting where a package came from
An attestation is a signed statement that says "this identity produced this source". It names the
module, the version, the source hash and the commit, and may also name a built file and its hash. It is
signed with a private key by the external openssl program, which must be installed. You can create one
while publishing with --sign-key private.pem --identity <name> (and optionally --artifact <file> and --attestation-out <file>), or on its own with trident attest --key private.pem --identity <name>. Without --attestation-out or --out the file is placed under
$TRIDENT_HOME/attestations/.
Reviewing and enforcing a policy
trident audit-record <path>@<version> --auditor <name> writes a review record: "this auditor
reviewed this module at this version and this source hash". It appends to trident.audits.toml
beside the manifest, or to the file named by --file, and the module must be in the project's lock:
$ trident audit-record github.com/acme/json@1.2.0 --auditor security-team
recorded audit by security-team for github.com/acme/json@1.2.0 in trident.audits.toml
trident audit always verifies that every locked module's source matches the checksum record and the
lock (see trident.versions-and-integrity). If a file named trident.audit.toml sits beside the
manifest, or you pass --policy <file>, it also enforces that policy for every locked module:
version = 1
trusted_auditors = ["security-team"]
audit_files = ["trident.audits.toml"]
require_attestations = true
attestation_dirs = ["attestations"]
[[key]]
identity = "release-ci"
public_key = "keys/release-ci.pem"
| Key | Meaning |
|---|---|
trusted_auditors |
Every locked module needs a review record from one of these auditors. |
audit_files |
The files that hold the review records written by audit-record. |
require_attestations |
When true, every locked module needs a valid signed attestation. |
attestation_dirs |
Folders searched for attestation files. |
[[key]] |
One per signer: the identity an attestation claims and the public_key that must verify it. Put these last. |
Relative paths are resolved beside the policy file. An audit record or attestation pins the module, the version and the source hash, so it stops applying if the source changes. A review record from an auditor who is not trusted, or an attestation whose signature does not verify, makes the audit fail. When the policy passes, the report lists the evidence that was accepted:
$ trident audit
OK github.com/acme/json@1.2.0 sha256:ab66a23e591b15c87616eb388c9f7351a4b4291b35da98d119acf2502f9e4696
AUDIT github.com/acme/json@1.2.0 by security-team
ATTEST github.com/acme/json@1.2.0 by acme-ci (./attestations/json.attestation)
policy passed: ./trident.audit.toml
audit passed: 1 module(s) verified
The package that these commands act on is ordinary Leviathan source. The one published above holds a namespace of public functions:
A package's source, with a caller
namespace Json {
public string encode(int n) => "{\"value\":" + n + "}";
public string tag(string s) => "<" + s + ">";
}
uses Json;
console.writeln(encode(42));
console.writeln(tag("hi"));
{"value":42}
<hi>
Rules
publishneeds a clean git working tree and a version of the formvMAJOR.MINOR.PATCH.- A tag is immutable: the same commit may be published again, a different commit may not.
- A yanked version is never chosen by a new resolution and never removed from a lock that already uses it.
- Without a policy file
trident auditonly verifies hashes. With one, it also enforces trusted auditors and signed provenance. - Signing and verifying use the
opensslprogram and are only needed when provenance is requested. [[key]]tables come last in a policy file.
Examples
A release with a signed attestation:
trident publish . --path github.com/acme/json \
--sign-key private.pem --identity acme-ci --attestation-out attestations/json.attestation
git push origin v1.2.0
A consumer recording a review and then requiring it:
trident audit-record github.com/acme/json@1.2.0 --auditor security-team
trident audit
Notes
trident auditneeds an existing lock; runtrident lockfirst if there is none.- There is no command to delete a published version; yanking is the supported way to stop new projects from selecting it.
See also
- Versions, the lock file, and integrity — How trident picks versions of repository dependencies, what
trident.lockand the checksum record guarantee, and how to build without the network. - The trident commands — Every
tridentsubcommand with its arguments, grouped into building, managing dependencies, and publishing and auditing. - The manifest: trident.toml — Every key of
trident.toml, how sources and assets are listed, and the three ways a project can choose its entry point.