Skip to content

Introduce support for TUF in Update Server#191

Open
doanac wants to merge 13 commits into
mainfrom
tuf-v2
Open

Introduce support for TUF in Update Server#191
doanac wants to merge 13 commits into
mainfrom
tuf-v2

Conversation

@doanac

@doanac doanac commented Jun 26, 2026

Copy link
Copy Markdown
Member

This is a fairly substantial change that introduces the ability to transparently manage TUF metadata for Updates. The branch produces a fully functioning server with TUF metadata that aklite will consume. There are some features that will be added once this has been merged:

The current logic for handling timestamp and targets metadata may not jive well with users wanting to move devices between tags. Given the size and scope of this current change, I'd like to delay work on that until I can get this work merged.

I also haven't tested rollback support. The current approach creates a single Target in the targets.json and doesn't not include any other older Targets. I believe aklite will work correctly but this will need to be tested.

This has been reviewed by Claude Sonnet and Claude Opus.

Introduce a self-contained storage model for The Update Framework (TUF)
using the Foundries.io/ota-tuf metadata format.

- Define TUF metadata structs internally (no external TUF type imports):
  root, targets, snapshot and timestamp metadata plus AtsKey/Signature.
- Add TufFsHandle under <datadir>/tuf with:
  - InitTuf(): generate ed25519 keys for the root, targets, snapshot and
    timestamp roles, store them AES-256-GCM encrypted under a key derived
    from the HMAC secret, and create a signed initial root.json (20y).
  - LoadTuf(): decrypt and load role keys; errors if not initialized.
  - GetRoots(): return all root.json files ordered by version.
- Default expirations: root 20y, timestamp 7d, targets/snapshot 90d.
- Use go-securesystemslib/cjson for canonical JSON signing.

Co-authored-by: GitHub Copilot:claude-4-opus <noreply@github.com>
Signed-off-by: Andy Doan <doanac@qti.qualcomm.com>
@doanac

doanac commented Jun 26, 2026

Copy link
Copy Markdown
Member Author

Screenshot of improved Update page:
image

The Update creation section defaults to:
image

and expands to:
image

Andy Doan and others added 12 commits June 26, 2026 16:35
Add a tuf-init server subcommand to initialize TUF keys and root
metadata, and require TUF to be initialized before the server starts.

Co-authored-by: GitHub Copilot:claude-4-opus <noreply@github.com>
Signed-off-by: Andy Doan <doanac@qti.qualcomm.com>
Add /v1/tuf/root.json (latest) and /v1/tuf/<n>.root.json (specific
version) endpoints backed by a new ReadRoot storage method.

Co-authored-by: GitHub Copilot:claude-4-opus <noreply@github.com>
Signed-off-by: Andy Doan <doanac@qti.qualcomm.com>
This introduces a new API to properly add target to a given tag/update
and sign its TUF metadata. Target metadata logic works by:

 * Finding the latest targets TUF version and application version for a
   tag. We must know these values to ensure we are creating metadata a
   device will pull down (if the version isn't higher - it won't pull
   it).
 * Increment the TUF version by 10. This gives us some flexibility to
   resign a Targets meta in the event we need to use it longer than the
   default 90 day expiration.
 * Create Snapshot metadata that's basically the same as the Targets.
   Our configuration/usage allows for these files to follow each other's
   versions.
 * Create Timestamp metadata. This follows some clever logic in our
   current ota-lite backend for setting a version that will work across
   mulitple updates for a given update tag.

Targets/Snapshot get a 90 day expiry.
Timestamp get a 7 day expiry.

Co-authored-by: GitHub Copilot:claude-4-opus <noreply@github.com>
Signed-off-by: Andy Doan <doanac@qti.qualcomm.com>
This introduces an new API that allows us to refresh timestamp metadata
for any updates that may need it. When the update expiry is within one
day of expiration, it will bump the expiration by a week and resign the
metatdata.

Signed-off-by: Andy Doan <doanac@qti.qualcomm.com>
We will use this to help populate default data into a TUF target during
an Update upload

Signed-off-by: Andy Doan <doanac@qti.qualcomm.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
This feature probes the update content itself to help automatically
generate the TUF Target for the user removing the need for them to have
TUF set up outside of this project.

Signed-off-by: Andy Doan <doanac@qti.qualcomm.com>
Co-authored-by: GitHub Copilot:claude-4-opus <noreply@github.com>
Add --version, --name, --ostree-hash, and --apps flags to the update
upload command so users can override the auto-generated TUF target
metadata via the new query parameters on the updates create API.

Signed-off-by: Andy Doan <doanac@qti.qualcomm.com>
Co-authored-by: GitHub Copilot:claude-opus-4.8 <noreply@github.com>
Add a collapsible "Advanced options" section to the update upload form
with version, target name, ostree hash, and apps fields. These map to
the new query parameters on the updates create API to override the
auto-generated TUF target metadata.

Signed-off-by: Andy Doan <doanac@qti.qualcomm.com>
Co-authored-by: GitHub Copilot:claude-opus-4.8 <noreply@github.com>
It makes more sense to show in the order timestamp,snapshot,target

Signed-off-by: Andy Doan <doanac@qti.qualcomm.com>
Collect the de-duplicated set of hardwareIds and tags from across all
targets in targets.json and display them in their own fieldsets on the
update details page.

Signed-off-by: Andy Doan <doanac@qti.qualcomm.com>
Co-authored-by: GitHub Copilot:claude-opus-4.8 <noreply@github.com>
Add an isExpired template helper and wrap expired root, timestamp,
snapshot, and targets expiration values in a <del> element on the update
details page.

Signed-off-by: Andy Doan <doanac@qti.qualcomm.com>
Co-authored-by: GitHub Copilot:claude-opus-4.8 <noreply@github.com>
Signed-off-by: Andy Doan <doanac@qti.qualcomm.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant