Menú de documentación

Documentación

Publishing packages

Build, sign, submit and manage an immutable TDE Package release.

En esta página

What publishing does

The TDE CLI can publish a signed .tpk directly to the TDE Store. The Website authenticates the request with a dedicated Publisher Token or GitHub OIDC, verifies the package and every declared artifact, reserves the package id for your account, and stores the release as an immutable version.

The Publisher area in Account shows apps and releases, creates the CLI token, registers signing keys, and connects GitHub Actions automation.

Choose what you are publishing

The .tpk package format and Publisher are language-agnostic. The language requirement depends on how deeply the product integrates with TDE:

ProductLanguageRuntime
TDE Native AppRust with tde-app-sdkNative TDE UI hosted by the app host
Shell WidgetRust with tde-widget-sdkIsolated widget process outside the desktop process
Terminal AppAny languageRuns inside a PTY

Start a native integration from the official TDE Native App template or Shell Widget template. Terminal applications can use their existing Rust, Go, Python, Node, Zig, or other build; Publisher only requires compatible immutable artifacts and a valid package manifest.

Prerequisites

You need:

  • a TDE account and a Publisher Token created in Account → Publisher → CLI Token;
  • a unique reverse-DNS package id, such as dev.example.my-app;
  • one or more immutable HTTPS artifacts;
  • the exact byte size and SHA-256 of each artifact;
  • a local 32-byte Ed25519 seed, or the same seed encoded as 64 hexadecimal characters.

Connect the CLI once with tde auth login and paste the token into the hidden prompt. The token is encrypted in the TDE vault, backed by the OS keyring on a desktop or an owner-only key file on a headless host, and can be rotated or revoked from the Account page. TDE_PUBLISHER_TOKEN overrides the saved token. Requests go to https://tde.sh by default; TDE_SITE_URL can select another Website deployment.

Create the package manifest

From the application's repository:

Terminal
tde package init --id dev.example.my-app --name "My App"

This creates .tde/package.toml. Replace the sample artifact URL, checksum and size before validating it:

.tde/package.toml
schema_version = 1

[app]
id = "dev.example.my-app"
name = "My App"
version = "1.0.0"
description = "A concise description"
publisher = "Example Developer"
license = "MIT"
homepage = "https://example.dev/my-app"
repository = "https://github.com/example/my-app"
exec = "my-app"
args = []
category = "Utilities"

[[artifacts]]
os = "linux"
arch = "x86_64"
url = "https://github.com/example/my-app/releases/download/v1.0.0/my-app-linux-x86_64.tar.gz"
sha256 = "<64 lowercase hexadecimal characters>"
size = 1234567

[requirements]
system_packages = []

[permissions]
capabilities = []

[config]
paths = []

[uninstall]
owned_paths = ["bin/my-app"]

[update]
channel = "stable"

Add another [[artifacts]] block for each supported combination of linux or macos with x86_64 or aarch64. Artifact URLs must stay on HTTPS, including redirects. The Website downloads each artifact and requires its actual size and SHA-256 to match the declaration.

The manifest is declarative and fail-closed. Shell commands, scripts, preinstall, postinstall, hooks and unknown capabilities are rejected; there is no force flag.

Validate, pack and sign

Terminal
tde package validate .tde/package.toml
tde package pack --manifest .tde/package.toml --out dist/my-app-1.0.0.tpk
tde package sign dist/my-app-1.0.0.tpk --key ~/.config/tde/publisher.ed25519
tde package verify dist/my-app-1.0.0.tpk

The key file contains exactly the 32 raw seed bytes. In CI-like local automation, a 64-character hexadecimal seed can be supplied without writing a key file:

Terminal
export TDE_SIGNING_KEY='<64 hex characters>'
tde package sign dist/my-app-1.0.0.tpk --key-env TDE_SIGNING_KEY

The recommended flow generates the key locally, registers only its public half, and stores the private seed in the encrypted TDE vault. The latest generated key becomes the default for tde package sign:

Terminal
tde package keys generate --name "Release laptop"
tde package keys list
tde package sign dist/my-app-1.0.0.tpk
tde package sign dist/my-app-1.0.0.tpk --key-id <fingerprint>
tde package keys revoke <fingerprint> --reason "Device retired"

Do not commit the seed or place it inside the .tpk. The public key is embedded in signatures/publisher.ed25519; the private seed never leaves your machine.

Publish and follow review

Terminal
tde auth login
tde auth status
tde package publish dist/my-app-1.0.0.tpk
tde package status <submission-id>
tde package releases --package dev.example.my-app

The first release of a package enters pending_review. The package id is then owned by your TDE account, so another account cannot publish under the same id. After approval, updates signed by a key owned by the same account are approved automatically when they request the same capabilities or fewer. Adding a capability returns the release to review.

StatusMeaning
pending_reviewWaiting for TDE review; not yet accepted by the Store
approvedAccepted and carrying a TDE Store Ed25519 attestation
rejectedReview refused; inspect review_note in the status response
yankedKept in release history but unavailable for new installs
revokedPermanently blocked because of a security incident

Published versions are immutable. Repeating the exact same submission is safe and returns the existing release, but changing the bytes of an existing package id + version is rejected. Increment the semantic version and publish a new .tpk instead.

All package commands support the global --json option for stable structured output:

Terminal
tde --json package publish dist/my-app-1.0.0.tpk
tde --json package status <submission-id>
tde --json package releases --package dev.example.my-app

Yank a release

Yanking stops new installs without deleting history or allowing the version to be replaced:

Terminal
tde package yank dev.example.my-app 1.0.0
tde package unyank dev.example.my-app 1.0.0

Yank is idempotent. Publish a higher fixed version rather than trying to reuse the yanked version number.

For a compromised release, revoke it permanently and provide an advisory:

Terminal
tde package revoke dev.example.my-app 1.0.0 --reason "Compromised upstream artifact" --confirm-package-id dev.example.my-app

GitHub Actions without a permanent secret

In Account → Publisher → Automation, connect the numeric GitHub repository id, package id, trusted workflow reference, and allowed ref pattern. Then grant the workflow id-token: write and publish with --oidc github:

.github/workflows/release.yml
name: Release
on:
push:
  tags: ["v*"]
permissions:
contents: read
id-token: write
jobs:
publish:
  runs-on: ubuntu-latest
  steps:
    - uses: actions/checkout@v4
    - name: Build and pack
      run: |
        tde package pack --out dist/app.tpk
    - name: Publish with GitHub identity
      run: tde package publish dist/app.tpk --oidc github

The CLI requests a GitHub OIDC identity, exchanges it for a ten-minute, package-bound TDE credential, creates an ephemeral Ed25519 signing key in memory, publishes, and discards the private key. No Publisher Token or signing seed is stored in GitHub secrets. Tokens are replay-protected and the Website checks repository id, exact workflow identity, and Git ref.

Validation limits and common failures

FailureWhat to check
Publisher Token is requiredRun tde auth login or set TDE_PUBLISHER_TOKEN
Publisher signature is requiredRun tde package sign, then tde package verify
Artifact size/checksum mismatchRecalculate both from the exact bytes served by the HTTPS URL
Namespace belongs to another publisherChoose an id you own; package ids cannot be transferred through the CLI today
Published versions are immutableIncrement app.version, repack and sign again
Pending review after an updateThe release is new or requests a capability the last approved version did not have
Too many submissionsWait for the Retry-After interval before retrying

A .tpk upload is limited to 8 MiB and 64 archive members. Downloaded artifacts are limited to 1 GiB each. Archive paths, duplicate entries, checksum coverage and compression ratios are validated before the release is stored.

Trust chain

An approved Store release has three independent checks:

  1. the .tpk checksums cover every non-signature member;
  2. the publisher's Ed25519 signature covers the canonical manifest and checksums;
  3. the TDE Store attestation binds the package id, version and exact package hash to the review decision.

The Store public key is available from GET /api/v1/store/attestation-key. An attestation proves which bytes the Store approved; capabilities still follow the Package Engine and broker policy.

Ownership and collaborators

Publishing without an owner option creates a personal namespace. Use --org ORG_ID for an organization namespace. In Account → Publisher → Apps, Owner and Admin roles can add Admin, Publisher, or Viewer collaborators; only the Owner can transfer the namespace. Transfer requires typing the exact package id and never changes the immutable package id or release history.