MOAT: Model for Origin Attestation and Trust
MOAT — the Model for Origin Attestation and Trust — is an open protocol for publishing, verifying, and revoking content through a signed manifest. Publishers attest to what they released, registries aggregate and re-attest, and clients verify the chain of custody against a Sigstore transparency log before trusting any content.
Syllago adopts MOAT as its provenance layer. This page describes the pieces of syllago that implement the protocol and the operator-facing surfaces that expose the results.
Why Syllago uses MOAT
Section titled “Why Syllago uses MOAT”MOAT solves a problem that comes up the moment you have more than one registry and more than one publisher: how does an operator know the content they just installed is what the publisher actually released? The usual answers are central PKI, hosted package stores, or “trust the URL.” All three have known failure modes.
MOAT takes a different approach:
- Keyless Sigstore signing. Publishers sign with short-lived Fulcio certificates tied to an OIDC identity (a GitHub Actions workflow, an OIDC-federated CI job, etc.) and record the signature in the Rekor transparency log. No long-lived keys to rotate, lose, or steal.
- Three tiers of attestation. Unsigned, Signed, and Dual-Attested — with an explicit spec rule that absence of a stronger signal is not a negative signal. See Trust Tiers.
- First-class revocation. A manifest can carry revocations from either the registry or the publisher, and each source has different semantics (hard-block vs. warn).
- No central registry of registries. Each operator adds the registries they trust and pins the signing identity at add-time, so a repository rename or transfer cannot silently swap the source of content. See Registry Signing Identity.
For the full protocol, see the MOAT specification. The rest of this page documents what syllago implements.
What syllago implements
Section titled “What syllago implements”Trust tiers and the install gate
Section titled “Trust tiers and the install gate”Every item syllago installs from a MOAT registry is classified as Unsigned, Signed, or Dual-Attested, based on the fields the manifest carries. The install gate evaluates the tier, revocation state, privacy flag, and policy floor and produces one of five outcomes:
| Gate decision | Behavior |
|---|---|
Proceed | Tier meets policy, no revocation, not private — install continues. |
HardBlock | Registry-source revocation. Install refuses; structured error surfaces the reason. |
PublisherWarn | Publisher-source revocation. Interactive Y/n prompt; non-interactive callers exit 12. |
PrivatePrompt | private_repo=true. Interactive Y/n; non-interactive callers exit 10. |
TierBelowPolicy | Item tier is below the configured minimum. Install refuses. |
Each install emits telemetry tagging both the observed tier (moat_tier) and the gate decision (moat_gated), so operators can measure the trust distribution of their actual installs over time.
For the tier classification rules, badge presentation, and the revocation two-tier contract, see Trust Tiers.
Registry signing identity
Section titled “Registry signing identity”Syllago pins a cryptographic signing identity to every MOAT registry at registry add time. Well-known registries are covered by a bundled allowlist; others require --signing-* flags or a non-GitHub OIDC issuer. The pinning resists rename and transfer attacks by binding to the numeric repository and owner IDs, not just the URL.
See Registry Signing Identity for the operator workflow, the three paths to pin an identity, and the escape hatch for air-gapped deployments.
Trusted-root lifecycle
Section titled “Trusted-root lifecycle”Syllago ships a bundled Sigstore trusted root and exposes its freshness through a dedicated command:
syllago moat trust statusThe output is key=value lines (with a --json option for scripts). Exit codes are stable and CI-grep-friendly:
| Exit | State | Verification behavior |
|---|---|---|
0 | Fresh (age < 90 days) | Runs |
1 | Warn (90–179) / Escalated (180–364) | Runs, with stderr warning |
2 | Expired (365+), missing, or corrupt | Refuses |
Expired roots are resolved by running syllago update. Operators who pin their own trusted root via --trusted-root or reg.trusted_root take responsibility for refreshing it — the 365-day cliff applies only to the bundled root.
Registry sync and non-interactive exit codes
Section titled “Registry sync and non-interactive exit codes”Every syllago registry sync verifies the manifest against the pinned signing profile, merges revocations into the lockfile, and advances the last-fetched-at timestamp. When the sync cannot silently proceed in a pipeline, syllago exits with a distinct code so CI can branch on the exact condition:
| Exit | Condition | Recovery |
|---|---|---|
10 | TOFU: first registry add requires human approval. | Run syllago registry add interactively. |
11 | registry_signing_profile has moved — possible key rotation or compromise. | Run syllago registry approve <name> interactively. |
12 | Publisher-source revocation hit during a non-interactive install. | Acknowledge interactively, or choose an alternative. |
13 | Manifest is stale (over 72 hours since last successful fetch). | Run syllago registry sync before the next install. |
Each exit is accompanied by a kebab-case label on stderr (tofu-acceptance, signing-profile-change, publisher-revocation, manifest-stale) so pipelines can grep the failure class without parsing the exit code.
The 72-hour staleness threshold is the MOAT default; a registry’s manifest can override it with an explicit expires field.
TUI trust inspector
Section titled “TUI trust inspector”The syllago TUI interface surfaces trust state directly on each library row and registry card. A trust badge (✓ Verified / R Recalled / none) sits next to every item, and the metadata panel shows the drill-down tier and recall reason.
For a full view, the Trust Inspector modal (reachable from both the library and registries tabs) shows:
- Item scope: tier, detail text, visibility, and any recall fields (source, reason, issuer, details URL).
- Registry scope: the aggregate — tier, issuer, subject, operator, manifest URI, last fetched-at, staleness, and item counts (total / verified / recalled / private).
The inspector is the same modal for both scopes, so the shape of the information is consistent regardless of where an operator opened it from. See Trust Tiers for the full field list.
Structured errors
Section titled “Structured errors”Every MOAT failure mode maps to a stable error code with documented remediation. The seven codes in the MOAT_* band cover unpinned identity, malformed flags, mismatched certificates, malformed bundles, stale trusted roots, pinned-without-manifest mismatches, and unusable override roots. See the MOAT error codes for the full list.
Spec alignment
Section titled “Spec alignment”Syllago tracks MOAT v0.6.x Draft. The spec is pre-1.0; syllago follows it as it evolves, and signing-profile changes on existing registries may trigger a re-approval prompt (exit 11) when a registry operator rotates their identity — which is the protocol working as designed.