diff --git a/.fossa.yml b/.fossa.yml
deleted file mode 100755
index f7edc69558..0000000000
--- a/.fossa.yml
+++ /dev/null
@@ -1,17 +0,0 @@
-# Generated by FOSSA CLI (https://github.com/fossas/fossa-cli)
-# Visit https://fossa.com to learn more
-
-version: 2
-cli:
- server: https://app.fossa.com
- fetcher: custom
- project: github.com/theupdateframework/python-tuf
-analyze:
- modules:
- - name: tuf
- type: pip
- target: .
- path: .
- options:
- strategy: requirements
- requirements: requirements.txt
diff --git a/.gitattributes b/.gitattributes
index 66709ac428..c35f57e223 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -1,3 +1,3 @@
-# Files that will always have LF line endings on checkout.
-tests/repository_data/** text eol=lf
-
+# All JSON files will always have LF line endings on checkout.
+# This prevents git replacing line endings with CRLF on Windows.
+*.json text eol=lf
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
index f4952bab42..ec5a47efab 100644
--- a/.github/dependabot.yml
+++ b/.github/dependabot.yml
@@ -1,8 +1,16 @@
version: 2
updates:
-- package-ecosystem: pip
+
+- package-ecosystem: "pip"
directory: "/"
schedule:
- interval: daily
+ interval: "daily"
+ time: "10:00"
+ open-pull-requests-limit: 10
+
+- package-ecosystem: "github-actions"
+ directory: "/"
+ schedule:
+ interval: "daily"
time: "10:00"
open-pull-requests-limit: 10
diff --git a/.github/workflows/_test.yml b/.github/workflows/_test.yml
new file mode 100644
index 0000000000..328037863a
--- /dev/null
+++ b/.github/workflows/_test.yml
@@ -0,0 +1,90 @@
+on:
+ workflow_call:
+ # Permissions inherited from caller workflow
+
+
+jobs:
+ tests:
+ name: Tests
+ strategy:
+ fail-fast: false
+ # Run regular TUF tests on each OS/Python combination, plus special tests
+ # (sslib master) and linters on Linux/Python3.x only.
+ matrix:
+ python-version: ["3.7", "3.8", "3.9", "3.10"]
+ os: [ubuntu-latest, macos-latest, windows-latest]
+ toxenv: [py]
+ include:
+ - python-version: 3.x
+ os: ubuntu-latest
+ toxenv: with-sslib-master
+ experimental: true
+ - python-version: 3.x
+ os: ubuntu-latest
+ toxenv: lint
+
+ env:
+ # Set TOXENV env var to tell tox which testenv (see tox.ini) to use
+ # NOTE: The Python 2.7 runner has two Python versions on the path (see
+ # setup-python below), so we tell tox explicitly to use the 'py27'
+ # testenv. For all other runners the toxenv configured above suffices.
+ TOXENV: ${{ matrix.toxenv }}
+
+ runs-on: ${{ matrix.os }}
+
+ steps:
+ - name: Checkout TUF
+ uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b
+
+ - name: Set up Python ${{ matrix.python-version }}
+ uses: actions/setup-python@98f2ad02fd48d057ee3b4d4f66525b231c3e52b6
+ with:
+ python-version: ${{ matrix.python-version }}
+ cache: 'pip'
+ cache-dependency-path: 'requirements*.txt'
+
+ - name: Install dependencies
+ run: |
+ python3 -m pip install --upgrade pip
+ python3 -m pip install --upgrade tox coveralls
+
+ - name: Run tox (${{ env.TOXENV }})
+ # See TOXENV environment variable for the testenv to be executed here
+ run: tox
+
+ - name: Publish on coveralls.io
+ # A failure to publish coverage results on coveralls should not
+ # be a reason for a job failure.
+ continue-on-error: true
+ # TODO: Maybe make 'lint' a separate job instead of case handling here
+ if: ${{ env.TOXENV != 'lint' }}
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ COVERALLS_FLAG_NAME: ${{ runner.os }} / Python ${{ matrix.python-version }} / ${{ env.TOXENV }}
+ COVERALLS_PARALLEL: true
+ # Use cp workaround to publish coverage reports with relative paths
+ # FIXME: Consider refactoring the tests to not require the test
+ # aggregation script being invoked from the `tests` directory, so
+ # that `.coverage` is written to and .coveragrc can also reside in
+ # the project root directory as is the convention.
+ run: |
+ cp tests/.coverage .
+ coveralls --service=github --rcfile=tests/.coveragerc
+
+ coveralls-fin:
+ # Always run when all 'tests' jobs have finished even if they failed
+ # TODO: Replace always() with a 'at least one job succeeded' expression
+ if: always()
+ needs: tests
+ runs-on: ubuntu-latest
+ container: python:3-slim
+ steps:
+ - name: Install dependencies
+ run: |
+ python3 -m pip install --upgrade pip
+ python3 -m pip install --upgrade coveralls
+ - name: Finalize publishing on coveralls.io
+ continue-on-error: true
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ run: coveralls --finish
diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml
new file mode 100644
index 0000000000..ccc67798ad
--- /dev/null
+++ b/.github/workflows/cd.yml
@@ -0,0 +1,87 @@
+name: CD
+concurrency: cd
+
+on:
+ push:
+ tags:
+ - v*
+
+permissions:
+ contents: write
+
+jobs:
+ test:
+ uses: ./.github/workflows/_test.yml
+
+ build:
+ name: Build
+ runs-on: ubuntu-latest
+ needs: test
+ outputs:
+ release_id: ${{ steps.gh-release.outputs.id }}
+ steps:
+ - name: Checkout release tag
+ uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b
+ with:
+ ref: ${{ github.event.workflow_run.head_branch }}
+
+ - name: Set up Python
+ uses: actions/setup-python@0ebf233433c08fb9061af664d501c3f3ff0e9e20
+ with:
+ python-version: '3.x'
+
+ - name: Install build dependency
+ run: python3 -m pip install --upgrade pip build
+
+ - name: Build binary wheel and source tarball
+ run: python3 -m build --sdist --wheel --outdir dist/ .
+
+ - id: gh-release
+ name: Publish GitHub release candiate
+ uses: softprops/action-gh-release@1e07f4398721186383de40550babbdf2b84acfc5
+ with:
+ name: ${{ github.ref_name }}-rc
+ tag_name: ${{ github.ref }}
+ body: "Release waiting for review..."
+ files: dist/*
+
+ - name: Store build artifacts
+ uses: actions/upload-artifact@6673cd052c4cd6fcf4b4e6e60ea986c889389535
+ # NOTE: The GitHub release page contains the release artifacts too, but using
+ # GitHub upload/download actions seems robuster: there is no need to compute
+ # download URLs and tampering with artifacts between jobs is more limited.
+ with:
+ name: build-artifacts
+ path: dist
+
+ release:
+ name: Release
+ runs-on: ubuntu-latest
+ needs: build
+ environment: release
+ steps:
+ - name: Fetch build artifacts
+ uses: actions/download-artifact@fb598a63ae348fa914e94cd0ff38f362e927b741
+ with:
+ name: build-artifacts
+ path: dist
+
+ - name: Publish binary wheel and source tarball on PyPI
+ uses: pypa/gh-action-pypi-publish@717ba43cfbb0387f6ce311b169a825772f54d295
+ with:
+ user: __token__
+ password: ${{ secrets.PYPI_API_TOKEN }}
+
+ - name: Finalize GitHub release
+ uses: actions/github-script@9ac08808f993958e9de277fe43a64532a609130e
+ with:
+ script: |
+ await github.rest.repos.updateRelease({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ release_id: '${{ needs.build.outputs.release_id }}',
+ name: '${{ github.ref_name }}',
+ body: 'See [CHANGELOG.md](https://github.com/' +
+ context.repo.owner + '/' + context.repo.repo +
+ '/blob/${{ github.ref_name }}/docs/CHANGELOG.md) for details.'
+ })
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 1355ab29de..87c8ccdbe6 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -1,104 +1,16 @@
-name: Run TUF tests and linter
+name: CI
on:
push:
branches:
- develop
+
pull_request:
workflow_dispatch:
-jobs:
- build:
- strategy:
- fail-fast: false
- # Run regular TUF tests on each OS/Python combination, plus special tests
- # (sslib master) and linters on Linux/Python3.x only.
- matrix:
- python-version: [3.6, 3.7, 3.8, 3.9]
- os: [ubuntu-latest, macos-latest, windows-latest]
- toxenv: [py]
- include:
- - python-version: 3.x
- os: ubuntu-latest
- toxenv: with-sslib-master
- experimental: true
- # TODO: Change to 3.x once pylint fully supports Python 3.9
- - python-version: 3.8
- os: ubuntu-latest
- toxenv: lint
-
- env:
- # Set TOXENV env var to tell tox which testenv (see tox.ini) to use
- # NOTE: The Python 2.7 runner has two Python versions on the path (see
- # setup-python below), so we tell tox explicitly to use the 'py27'
- # testenv. For all other runners the toxenv configured above suffices.
- TOXENV: ${{ matrix.toxenv }}
-
- runs-on: ${{ matrix.os }}
-
- steps:
- - name: Checkout TUF
- uses: actions/checkout@v2
-
- - name: Set up Python ${{ matrix.python-version }}
- uses: actions/setup-python@v2
- with:
- python-version: ${{ matrix.python-version }}
+permissions:
+ contents: read
- - name: Find pip cache dir
- id: pip-cache
- run: echo "::set-output name=dir::$(pip cache dir)"
-
- - name: pip cache
- uses: actions/cache@v2
- with:
- # Use the os dependent pip cache directory found above
- path: ${{ steps.pip-cache.outputs.dir }}
- # A match with 'key' counts as cache hit
- key: ${{ runner.os }}-pip-${{ hashFiles('requirements*.txt') }}
- # A match with 'restore-keys' is used as fallback
- restore-keys: ${{ runner.os }}-pip-
-
- - name: Install dependencies
- run: |
- python3 -m pip install --upgrade pip
- python3 -m pip install --upgrade tox coveralls
-
- - name: Run tox (${{ env.TOXENV }})
- # See TOXENV environment variable for the testenv to be executed here
- run: tox
-
- - name: Publish on coveralls.io
- # A failure to publish coverage results on coveralls should not
- # be a reason for a job failure.
- continue-on-error: true
- # TODO: Maybe make 'lint' a separate job instead of case handling here
- if: ${{ env.TOXENV != 'lint' }}
- env:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- COVERALLS_FLAG_NAME: ${{ runner.os }} / Python ${{ matrix.python-version }} / ${{ env.TOXENV }}
- COVERALLS_PARALLEL: true
- # Use cp workaround to publish coverage reports with relative paths
- # FIXME: Consider refactoring the tests to not require the test
- # aggregation script being invoked from the `tests` directory, so
- # that `.coverage` is written to and .coveragrc can also reside in
- # the project root directory as is the convention.
- run: |
- cp tests/.coverage .
- coveralls --service=github --rcfile=tests/.coveragerc
-
- coveralls-fin:
- # Always run when all 'build' jobs have finished even if they failed
- # TODO: Replace always() with a 'at least one job succeeded' expression
- if: always()
- needs: build
- runs-on: ubuntu-latest
- container: python:3-slim
- steps:
- - name: Finalize publishing on coveralls.io
- env:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- run: |
- python3 -m pip install --upgrade pip
- python3 -m pip install --upgrade coveralls
- coveralls --finish
+jobs:
+ test:
+ uses: ./.github/workflows/_test.yml
diff --git a/.github/workflows/maintainer-permissions-reminder.yml b/.github/workflows/maintainer-permissions-reminder.yml
new file mode 100644
index 0000000000..c6b02aa166
--- /dev/null
+++ b/.github/workflows/maintainer-permissions-reminder.yml
@@ -0,0 +1,55 @@
+name: Maintainer review reminder
+
+on:
+ schedule:
+ - cron: '10 10 10 2 *'
+ workflow_dispatch:
+
+permissions:
+ issues: write
+
+jobs:
+ file-reminder-issue:
+ name: File issue to review maintainer permissions
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/github-script@9ac08808f993958e9de277fe43a64532a609130e
+ with:
+ script: |
+ await github.rest.issues.create({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ title: "Yearly maintainer permissions review",
+ body: `
+ This is a checklist for evaluating python-tuf maintainer accounts and permissions. This issue is automatically opened once a year.
+
+ ### Tasks
+
+ 1. Update this list to include any new services
+ 2. Evaluate the accounts and permissions for each service on the list. Some rules of thumb:
+ * Critical services should have a minimum of 3 _active_ maintainers/admins to prevent project lockout
+ * Each additional maintainer/admin increases the risk of project compromise: for this reason permissions should be removed if they are no longer used
+ * For services that are not frequently used, each maintainer/admin should check that they really are still able to authenticate to the service and confirm this in the comments
+ 3. Update MAINTAINERS.txt to reflect current permissions
+ 4. (Bonus) Update significant contributors in README.md#acknowledgements
+
+ ### Critical services
+
+ * [ ] **PyPI**: maintainer list is visible to everyone at https://pypi.org/project/tuf/
+ * Only enough maintainers and org admins to prevent locking the project out
+ * [ ] **GitHub**: release environment reviewers listed in https://github.com/theupdateframework/python-tuf/settings/environments
+ * Maintainers who can approve releases to PyPI
+ * [ ] **GitHub**: permissions visible to admins at https://github.com/theupdateframework/python-tuf/settings/access
+ * "admin" permission: Only for maintainers and org admins who do project administration
+ * "push/maintain" permission: Maintainers who actively approve and merge PRs (+admins)
+ * "triage" permission: All contributors trusted to manage issues
+
+ ### Other
+
+ * [ ] **ReadTheDocs**: admin list is visible to everyone at https://readthedocs.org/projects/theupdateframework/
+ * [ ] **Coveralls**: everyone with github "admin" permissions is a Coveralls admin: https://coveralls.io/github/theupdateframework/python-tuf
+ `
+ })
+ console.log("New issue created.")
+
+
diff --git a/.github/workflows/specification-version-check.yml b/.github/workflows/specification-version-check.yml
new file mode 100644
index 0000000000..717a6a47c6
--- /dev/null
+++ b/.github/workflows/specification-version-check.yml
@@ -0,0 +1,31 @@
+on:
+ schedule:
+ - cron: "0 13 * * *"
+ workflow_dispatch:
+ push:
+name: Specification version check
+jobs:
+ # Get the version of the TUF specification the project states it supports
+ get-supported-tuf-version:
+ runs-on: ubuntu-latest
+ outputs:
+ version: ${{ steps.get-version.outputs.version }}
+ steps:
+ - uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b
+ - uses: actions/setup-python@98f2ad02fd48d057ee3b4d4f66525b231c3e52b6
+ - id: get-version
+ run: |
+ python3 -m pip install -e .
+ script="from tuf.api.metadata import SPECIFICATION_VERSION; \
+ print(f\"v{'.'.join(SPECIFICATION_VERSION)}\")"
+ ver=$(python3 -c "$script")
+ echo "::set-output name=version::$ver"
+ # Get the latest TUF specification release and open an issue (if needed)
+ specification-bump-check:
+ permissions:
+ contents: read
+ issues: read
+ needs: get-supported-tuf-version
+ uses: rdimitrov/specification/.github/workflows/check-latest-spec-version.yml@dimitrovr/spec-bump-workflow
+ with:
+ tuf-version: ${{needs.get-supported-tuf-version.outputs.version}}
diff --git a/.gitignore b/.gitignore
index e988195f05..ff032a6f68 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,10 +1,10 @@
# root level directories
-dist/*
-build/*
-env/*
+dist/
+build/
+env/
# docs build directory
-docs/build/*
+docs/build/
# global file patterns
*.log
@@ -14,19 +14,20 @@ docs/build/*
*.swp
*.egg-info
.coverage
-.tox/*
-tests/htmlcov/*
+.tox/
+tests/htmlcov/
.DS_Store
-.pybuild/*
+.pybuild/
.python-version
*~
*.tmp
.pre-commit-config.yaml
+.vscode
# Debian generated files
-debian/.debhelper/*
+debian/.debhelper/
debian/*-stamp
debian/files
debian/*.debhelper
debian/*.substvars
-debian/python*-tuf/*
+debian/python*-tuf/
diff --git a/.readthedocs.yaml b/.readthedocs.yaml
index 58dec99503..11d82d2ab5 100644
--- a/.readthedocs.yaml
+++ b/.readthedocs.yaml
@@ -7,13 +7,16 @@ version: 2
# Build documentation with Sphinx
sphinx:
- builder: html
- configuration: docs/conf.py
+ builder: html
+ configuration: docs/conf.py
+ fail_on_warning: true
# Optionally build your docs in additional formats such as PDF
formats: []
# Optionally set the version of Python and requirements required to build your docs
python:
- install:
- - requirements: requirements-docs.txt
+ install:
+ - requirements: requirements-docs.txt
+ - method: pip
+ path: .
diff --git a/MANIFEST.in b/MANIFEST.in
deleted file mode 100644
index 6e2a7cbb01..0000000000
--- a/MANIFEST.in
+++ /dev/null
@@ -1,29 +0,0 @@
-include LICENSE*
-include README.md
-include tox.ini
-include tests/repository_data/keystore/delegation_key
-include tests/repository_data/keystore/root_key*
-include tests/repository_data/keystore/snapshot_key
-include tests/repository_data/keystore/targets_key
-include tests/repository_data/keystore/timestamp_key
-include tests/ssl_certs/*.crt
-include tests/ssl_certs/*.key
-
-recursive-include docs *.txt
-recursive-include docs *.md
-recursive-include docs *.rst
-recursive-include docs/images *.png
-recursive-include tuf/scripts *.py
-recursive-include examples *
-recursive-include tests *.py
-recursive-include tests *.pem
-recursive-include tests *.json
-recursive-include tests *.txt
-recursive-include tests *.cfg
-recursive-include tests *.coveragerc
-recursive-include tests *.gz
-recursive-include tests *.pub
-recursive-include tuf *.gitignore
-recursive-include tuf *.md
-recursive-include tuf *.rst
-recursive-include tuf *.yml
diff --git a/README.md b/README.md
index 4429de9be9..03caec8e7c 100644
--- a/README.md
+++ b/README.md
@@ -1,41 +1,29 @@
# A Framework for Securing Software Update Systems
-![Build](https://github.com/theupdateframework/python-tuf/workflows/Run%20TUF%20tests%20and%20linter/badge.svg)
-[![Coveralls](https://coveralls.io/repos/theupdateframework/tuf/badge.svg?branch=develop)](https://coveralls.io/r/theupdateframework/tuf?branch=develop)
+![Build](https://github.com/theupdateframework/python-tuf/actions/workflows/ci.yml/badge.svg)
+[![Coveralls](https://coveralls.io/repos/theupdateframework/python-tuf/badge.svg?branch=develop)](https://coveralls.io/r/theupdateframework/python-tuf?branch=develop)
+[![Docs](https://readthedocs.org/projects/theupdateframework/badge/)](https://theupdateframework.readthedocs.io/)
[![CII](https://bestpractices.coreinfrastructure.org/projects/1351/badge)](https://bestpractices.coreinfrastructure.org/projects/1351)
[![PyPI](https://img.shields.io/pypi/v/tuf)](https://pypi.org/project/tuf/)
----------------------------
-This repository is the **reference implementation** of
-[The Update Framework (TUF)](https://theupdateframework.github.io/).
-It is written in Python and intended to conform to version 1.0 of the
-[TUF specification](https://theupdateframework.github.io/specification/latest/).
-
-The repository currently includes two implementations:
-1) A *legacy implementation*, with
- [`tuf/client/updater.py`](tuf/client/updater.py) implementing the detailed
- client workflow and [`tuf/repository_tool.py`](tuf/repository_tool.py)
- providing a high-level interface for repository operations.
- The legacy implementation is in use in production systems, but is [no longer
- being actively worked on](docs/adr/0002-pre-1-0-deprecation-strategy.md).
-2) A *modern implementation*. We are in the process of rewriting the reference
- implementation in [modern Python](docs/adr/0001-python-version-3-6-plus.md)
- to both: a) address scalability and integration issues identified in
- supporting integration into the Python Package Index (PyPI), and other
- large-scale repositories, and b) to ensure maintainability of the project.
- This implementation consists of:
- * a "low-level" metadata API, designed to provide easy and safe access to
- TUF metadata and handle (de)serialization from/to files, provided in the
- [`tuf/api/metadata.py`](tuf/api/metadata.py) module.
- * an implementation of the detailed client workflow built on top of the
- metadata API, provided in the
- [`tuf/ngclient/updater.py`](tuf/ngclient/updater.py) module.
- The modern implementation is not considered production ready and does not yet
- provide any high-level support for implementing
- [repository operations](https://theupdateframework.github.io/specification/latest/#repository-operations),
- though the addition of API to support them is planned.
-
-
+[The Update Framework (TUF)](https://theupdateframework.io/) is a framework for
+secure content delivery and updates. It protects against various types of
+supply chain attacks and provides resilience to compromise. This repository is a
+**reference implementation** written in Python. It is intended to conform to
+version 1.0 of the [TUF
+specification](https://theupdateframework.github.io/specification/latest/).
+
+Python-TUF provides two APIs:
+ * [`tuf.api.metadata`](https://theupdateframework.readthedocs.io/en/latest/api/tuf.api.html),
+ a "low-level" API, designed to provide easy and safe access to TUF
+ metadata and to handle (de)serialization from/to files.
+ * [`tuf.ngclient`](https://theupdateframework.readthedocs.io/en/latest/api/tuf.ngclient.html),
+ a client implementation built on top of the metadata API.
+
+High-level support for implementing
+[repository operations](https://theupdateframework.github.io/specification/latest/#repository-operations)
+is planned but not yet provided: see [ADR 10](https://github.com/theupdateframework/python-tuf/blob/develop/docs/adr/0010-repository-library-design.md).
The reference implementation strives to be a readable guide and demonstration
for those working on implementing TUF in their own languages, environments, or
@@ -59,26 +47,27 @@ by various tech companies and open source organizations. A variant of TUF
called [Uptane](https://uptane.github.io/) is used to secure over-the-air
updates in automobiles.
-Please see the [TUF Introduction](docs/OVERVIEW.rst) and
-[TUF's website](https://theupdateframework.com/) for more information about TUF!
+Please see [TUF's website](https://theupdateframework.com/) for more information about TUF!
Documentation
-------------
-* [Introduction to TUF's Design](docs/OVERVIEW.rst)
+* [Introduction to TUF's Design](https://theupdateframework.io/overview/)
* [The TUF Specification](https://theupdateframework.github.io/specification/latest/)
-* [Getting Started with the TUF Reference Implementation](docs/GETTING_STARTED.rst)
-* [Governance](docs/GOVERNANCE.md) and [Maintainers](docs/MAINTAINERS.txt)
+* [API Reference](https://theupdateframework.readthedocs.io/)
+* [Usage examples](https://github.com/theupdateframework/python-tuf/tree/develop/examples/)
+* [Governance](https://github.com/theupdateframework/python-tuf/blob/develop/docs/GOVERNANCE.md)
+and [Maintainers](https://github.com/theupdateframework/python-tuf/blob/develop/docs/MAINTAINERS.txt)
for the reference implementation
-* [Miscellaneous Docs](docs/)
+* [Miscellaneous Docs](https://github.com/theupdateframework/python-tuf/tree/develop/docs)
Contact
-------
-Please contact us via our [mailing
-list](https://groups.google.com/forum/?fromgroups#!forum/theupdateframework).
-Questions, feedback, and suggestions are welcomed on this low volume mailing
-list.
+Questions, feedback, and suggestions are welcomed on our low volume [mailing
+list](https://groups.google.com/forum/?fromgroups#!forum/theupdateframework) or
+the [#tuf](https://cloud-native.slack.com/archives/C8NMD3QJ3) channel on [CNCF
+Slack](https://slack.cncf.io/).
We strive to make the specification easy to implement, so if you come across
any inconsistencies or experience any difficulty, do let us know by sending an
@@ -101,7 +90,9 @@ PGP key fingerprint **E9C0 59EC 0D32 64FA B35F 94AD 465B F9F6 F8EB 475A**.
Please do not use the GitHub issue tracker to submit vulnerability reports.
The issue tracker is intended for bug reports and to make feature requests.
Major feature requests, such as design changes to the specification, should
-be proposed via a [TUF Augmentation Proposal](docs/TAP.rst) (TAP).
+be proposed via a
+[TUF Augmentation Proposal](https://theupdateframework.github.io/specification/latest/#tuf-augmentation-proposal-tap-support)
+(TAP).
Limitations
-----------
@@ -114,22 +105,23 @@ License
This work is [dual-licensed](https://en.wikipedia.org/wiki/Multi-licensing) and
distributed under the (1) MIT License and (2) Apache License, Version 2.0.
-Please see [LICENSE-MIT](LICENSE-MIT) and [LICENSE](LICENSE).
+Please see [LICENSE-MIT](https://github.com/theupdateframework/python-tuf/blob/develop/LICENSE-MIT)
+and [LICENSE](https://github.com/theupdateframework/python-tuf/blob/develop/LICENSE).
Acknowledgements
----------------
This project is hosted by the Linux Foundation under the Cloud Native Computing
-Foundation. TUF's early development was managed by
-members of the [Secure Systems Lab](https://ssl.engineering.nyu.edu/) at [New
-York University](https://engineering.nyu.edu/). We appreciate the efforts of
-Konstantin Andrianov, Geremy Condra, Vladimir Diaz, Yuyu Zheng, Sebastien Awwad,
-Santiago Torres-Arias, Trishank Kuppusamy, Zane Fisher, Pankhuri Goyal, Tian Tian,
-Konstantin Andrianov, and Justin Samuel who are among those who helped significantly
-with TUF's reference implementation. [Contributors](https://github.com/theupdateframework/python-tuf/blob/develop/docs/AUTHORS.txt)
-and
-[maintainers](https://github.com/theupdateframework/python-tuf/blob/develop/docs/MAINTAINERS.txt)
+Foundation. TUF's early development was managed by members of the [Secure
+Systems Lab](https://ssl.engineering.nyu.edu/) at [New York
+University](https://engineering.nyu.edu/). We appreciate the efforts of all
+[maintainers and emeritus
+maintainers](https://github.com/theupdateframework/python-tuf/blob/develop/docs/MAINTAINERS.txt),
+as well as the contributors Konstantin Andrianov, Kairo de Araujo, Ivana
+Atanasova, Geremy Condra, Zane Fisher, Pankhuri Goyal, Justin Samuel, Tian
+Tian, Martin Vrachev and Yuyu Zheng who are among those who helped
+significantly with TUF's reference implementation. Maintainers and Contributors
are governed by the [CNCF Community Code of
Conduct](https://github.com/cncf/foundation/blob/master/code-of-conduct.md).
diff --git a/docs/1.0.0-ANNOUNCEMENT.md b/docs/1.0.0-ANNOUNCEMENT.md
new file mode 100644
index 0000000000..0020632b22
--- /dev/null
+++ b/docs/1.0.0-ANNOUNCEMENT.md
@@ -0,0 +1,41 @@
+# Announcing TUF 1.0.0
+
+Python-TUF v1.0.0 is a rewritten stable reference implementation of the TUF
+specification, which *currently* includes:
+- a modern low-level [*metadata
+ API*](https://theupdateframework.readthedocs.io/en/latest/api/tuf.api.html)
+- a fully specification-compliant [*updater
+ client*](https://theupdateframework.readthedocs.io/en/latest/api/tuf.ngclient.html),
+ serving as a more robust and yet more flexible stand-in replacement
+ for the legacy client updater
+
+For the reasons outlined in [ADR 10](https://github.com/theupdateframework/python-tuf/blob/develop/docs/adr/0010-repository-library-design.md
+), this release *does not yet* include *repository tool*-like functionality.
+However, the new *metadata API* makes it easy to replicate the desired
+functionality tailored to the specific needs of any given repository (see
+*Migration* for details).
+
+As discussed in [ADR 2](https://github.com/theupdateframework/python-tuf/blob/develop/docs/adr/0002-pre-1-0-deprecation-strategy.md), this
+release *does not* include any legacy code, as its maintenance has become
+infeasible for the python-tuf team. The pre-1.0.0 deprecation strategy from ADR
+2 applies as follows:
+
+> *Bugs reported with tuf versions prior to 1.0.0 will likely not be addressed
+directly by tuf’s maintainers. Pull Requests to fix bugs in the last release
+prior to 1.0.0 will be considered, and merged (subject to normal review
+processes). Note that there may be delays due to the lack of developer resources
+for reviewing such pull requests.*
+
+
+## Migration
+
+Given the clean cut with the legacy reference implementation, we provide the
+following migration support:
+
+- detailed code documentation on
+ [https://theupdateframework.readthedocs.io](https://theupdateframework.readthedocs.io/)
+- verbose [code examples](https://github.com/theupdateframework/python-tuf/tree/develop/examples) for *client updater* usage, and
+ repository-side operations based on the low-level *metadata API*
+- individual migration support upon
+ [request](https://github.com/theupdateframework/python-tuf#contact)
+- targeted migration support initiative for known users
diff --git a/docs/AUTHORS.txt b/docs/AUTHORS.txt
deleted file mode 100644
index 376f201ee0..0000000000
--- a/docs/AUTHORS.txt
+++ /dev/null
@@ -1,62 +0,0 @@
-The TUF project is managed by Justin Cappos at NYU (jcappos@nyu.edu). See GOVERNANCE.md for more information.
-
-Contributors:
-
-Organizations
--------------
-
-Advanced Telematic Systems
-Datadog
-Docker
-Flynn
-LEAP
-OCaml
-Quay by CoreOS
-
-Individuals
------------
-
-Alan Castonguay
-Andrew Meyer
-Arturo Filastò
-Benno Fünfstück
-David Halls
-David Lawrence
-Diogo Monica
-Eric Hartsuyker
-Evan Cordell
-Felix Wang
-Geremy Condra
-goldenMetteyya
-Hannes Mehnert
-Jerry Trieu
-Johannes Dorfner
-John Ward
-Jonathan Rudenberg
-Julian Hille
-Justin Cappos
-Justin Samuel
-Konstantin Andrianov
-Linda Vigdor
-Lois DeLong
-Lukas Puehringer
-María José Barrera
-Martin Peck
-Max Goodman
-Monzur Muhammad
-Nektarios Tsoutsos
-Nick Mathewson
-Pankhuri Goyal
-Riyaz Faizullabhoy
-Roger Dingledine
-Ruben Pollan
-Santiago Torres
-Sebastian Hahn
-Sebastien Awwad
-Tian Tian
-Trishank Karthik Kuppusamy
-Vladimir Diaz
-Wilson Ding
-Ying Li
-Yuyu Zheng
-Zane Fisher
diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md
index 0ceb224767..3c712ba93e 100644
--- a/docs/CHANGELOG.md
+++ b/docs/CHANGELOG.md
@@ -1,5 +1,212 @@
# Changelog
+
+## v1.1.0
+
+This release contains major build improvements as well as fixes and
+backwards-compatible API improvements.
+
+### Added
+* build: Release process was moved to CD platform (#1946, #1971, #1976)
+* build: Build is now reproducible thanks to Hatchling (#1896, #1900)
+* build: Build results are now verifiable (#1913, #1926, #1947, #1979)
+* build: test dependencies are now pinned for reproducibility (#1867, #1918)
+* Metadata API: Validation is now possible during serialization (#1775)
+* Infrastructure: Setup development blog (#1886, #1887)
+
+### Changed
+* Metadata API: Supported specification version updated (#1908, #1960)
+* Metadata API: unrecognized_fields annotation fix (#1950)
+* Metadata API: Constructors are now easier to use (#1922)
+* Metadata API: Logging and error message improvements (#1876)
+* build: Include examples in source distribution (#1970)
+* build: Updated pinned dependency versions
+* tests: Various improvements (#1707, #1758, #1808, #1860, #1915, #1936,
+ #1953, #1954, #1955)
+
+
+## v1.0.0
+
+This release makes ngclient and the Metadata API the supported python-tuf APIs.
+It also removes the legacy implementation as documented in the
+[1.0.0 announcement](1.0.0-ANNOUNCEMENT.md): all library code is now contained
+in `tuf.api` or `tuf.ngclient`.
+
+### Added
+* tests: Extend testing (#1689, #1703, #1711, #1728, #1735, #1738,
+ #1742, #1766, #1777, #1809, #1831)
+
+### Changed
+* Metadata API: Disallow microseconds in expiry (#1712)
+* Metadata API: Preserve role keyid order (#1754)
+* Metadata API: Make exceptions more consistent (#1725, #1734, #1787, #1840,
+ #1836)
+* Metadata API: Update supported spec version to "1.0.28" (#1825)
+* Metadata API: Accept legacy spec version "1.0" (#1796)
+* Metadata API: Accept custom fields in Metadata (#1861)
+* ngclient: Remove temporary file in failure cases (#1757)
+* ngclient: Explicitly encode rolename in URL (#1759)
+* ngclient: Allow HTTP payload compression (#1774)
+* ngclient: Make exceptions more consistent (#1799, #1810)
+* docs: Improve documentation (#1744, #1749, #1750, #1755, #1771, #1776, #1772,
+ #1780, #1781, #1800, #1815, #1820, #1829, #1838, #1850, #1853, #1855, #1856
+ #1868, #1871)
+* build: Various build infrastructure improvements (#1718, #1724, #1760, #1762,
+ #1767, #1803, #1830, #1832, #1837, #1839)
+* build: Stop supporting EOL Python 3.6 (#1783)
+* build: Update dependencies (#1809, #1827, #1834, #1863, #1865, #1870)
+
+### Removed
+* Remove all legacy code including old client, repository_tool, repository_lib
+ and the scripts (#1790)
+* Metadata API: Remove modification helper methods that are no longer necessary
+ (#1736, #1740, #1743)
+* tests: Remove client tests that were replaced with better ones (#1741)
+* tests: Stop using unittest_toolbox (#1792)
+* docs: Remove deprecated documentation (#1768, #1769, #1773, #1848)
+
+
+## v0.20.0
+
+*__NOTE:__ This will be the final release of python-tuf that includes the
+legacy implementation code. Please see the [*1.0.0
+announcement*](1.0.0-ANNOUNCEMENT.md) page for more details about the next
+release and the deprecation of the legacy implementation, including migration
+instructions.*
+
+### Added
+* metadata API: misc input validation (#1630, #1688, #1668, #1672, #1690)
+* doc: repository library design document and ADR (#1693)
+* doc: 1.0.0 announcement (#1706)
+* doc: misc docstrings in metadata API (#1620)
+* doc: repository and client examples (#1675, #1685, #1700)
+* test: ngclient key rotation (#1635, #1649, #1691)
+* test: ngclient top-level role update (#1636)
+* test: ngclient non-consistent snapshot (#1666, #1705)
+* test: more lint/type checks and auto-formatting (#1658, #1664, #1659, #1674,
+ #1677, #1687, #1699, #1701, #1708, #1710, #1720, #1726)
+* build: Python 3.10 support (#1628)
+
+### Changed
+* ngclient: misc API changes (#1604, #1731)
+* ngclient: avoid re-loading verified targets metadata (#1593)
+* ngclient: implicitly call refresh() (#1654)
+* ngclient: return loaded metadata (#1680)
+* ngclient: skip visited nodes on delegation tree traversal (#1683)
+* ngclient: remove URL normalisation (#1686)
+* build: modernise packaging configuration (#1626)
+* build: bump dependencies (#1609, #1611, #1616, #1621)
+* build: limit GitHub Action token visibility and permissions (#1652, #1663)
+* test: misc test changes (#1715, #1670, #1671, #1631, #1695, #1702)
+
+### Removed
+* doc: obsolete roadmap (#1698)
+
+## v0.19.0
+
+For users of legacy client (tuf.client module) this is purely a security fix
+release with no API or functionality changes. For ngclient (tuf.ngclient) and
+Metadata API (tuf.api.metadata), some API changes are included.
+
+**All users are advised to upgrade**.
+
+Note that python-tuf has required python>=3.5 since release 0.18.0.
+
+### Fixed
+* GHSA-wjw6-2cqr-j4qr: Fix client side issue in both legacy client (tuf.client)
+ and ngclient (tuf.ngclient) where a malicious repository could trick client
+ to overwrite files outside the client metadata store during a metadata
+ update. The fix includes percent-encoding the metadata rolename before using
+ it as part of a filename
+ https://github.com/theupdateframework/python-tuf/security/advisories/GHSA-wjw6-2cqr-j4qr
+* ngclient: Do not use urljoin to form metadata URL (included in
+ GHSA-wjw6-2cqr-j4qr)
+* ngclient: Persist metadata safely (#1574)
+* ngclient: Handle timeout on session.get() (#1588)
+
+### Added
+* build: Dependabot now monitors GitHub Actions (#1572)
+* tests: ngclient test improvements (#1564, #1569, #1587)
+* Metadata API: Add TargetFile.from_file() (#1521)
+
+### Changed
+* build: Bump dependency charset-normalizer (#1581, #1586)
+* build: Bump dependency urllib3 (#1589)
+* build: Bump dependency cryptography (#1596)
+* Metadata API: Documentation improvements (#1533, #1590)
+* Metadata API: change Timestamp meta API (#1446)
+* Metadata API: change Delegations roles API (#1537)
+* ngclient: Remove unnecessary sleep() (#1608)
+* ngclient: Fix consistent targets URL resolution (#1591)
+* ngclient: Don't use target path as local path (#1592)
+
+## v0.18.1
+
+### Changed
+* Update setup.cfg to not build universal wheels (#1566)
+
+## v0.18.0
+
+0.18 is a big release with 3 main themes:
+* Support only Python 3 and modernize the infrastructure accordingly
+* Metadata API (a low-level API for metadata de/serialization and
+ modification) is now feature-complete for the client use cases
+* ngclient (a new high-level client API) was added. ngclient should be
+ considered an unstable API and is not yet recommended for production
+ use.
+
+Additionally the Github project name changed: project is now "python-tuf"
+instead of "tuf". Redirects are in place for the old name but updating links is
+advised.
+
+### Added
+* Add ADR6: Where to implement serialization (#1270)
+* Add ADR8: Unrecognized fields (#1343)
+* Add ADR9: Refine reference implementation purpose (#1554)
+* Add client Network IO abstraction (#1250, #1302)
+* Add many features to Metadata API to support de/serializing
+ specification-compliant metadata, and safer access through API:
+ * Metadata.from_bytes()/to_bytes() (#1354, #1490)
+ * Key, Role (#1360, #1386, #1423, #1480, #1481, #1520)
+ * DelegationRole, Delegations (#1370, #1512)
+ * MetaFile, TargetFile (#1329, #1437, #1454, #1514)
+ * verification of threshold of signatures (#1435, #1436)
+ * expiration check method (#1347)
+ * support unrecognized fields in metadata (#1345)
+ * use Generics to improve static typing (#1457)
+* Extensive Metadata API testing and validation
+ (#1359, #1416, #1416, #1430, #1449, #1450, #1451, #1460, #1466, #1511)
+* Add ngclient: a new client library implementation
+ (#1408, #1448, #1463 #1467, #1470, #1474, #1501, #1509, #1519, #1524)
+* Infrastructure improvements:
+ * mypy, black and isort integration (#1314, #1363, #1395, #1455, #1489)
+ * API reference documentation build (#1517)
+
+### Removed
+* Remove Python 2 support (#1293)
+* Remove direct dependency on six
+* Remove obsolete reference to Thandy in a LICENSE file (#1472)
+
+### Changed
+* Bump dependencies:
+ * Certifi
+ * Cryptography
+ * Idna
+ * Requests
+ * Securesystemslib
+ * Six
+ * Urllib3
+* Replace indirect dependency chardet with charset-normalizer
+* Move Metadata API serialization to sub-package (#1279)
+* Use SecureSystemslib Signer interface in Metadata API (#1272)
+* Make imports compatible with vendoring (#1261)
+
+### Fixed
+* 'ecdsa' is a supported key type (#1453)
+* Fix various build infrastructure issues (#1289, #1295, #1321, #1327, #1364,
+ #1369, #1542)
+* Test fixes (#1337, #1346)
+
## v0.17.0
**NOTE**: this will be the final release of tuf that supports Python 2.7.
This is because Python 2.7 was marked [end-of-life](
diff --git a/docs/CLI.md b/docs/CLI.md
deleted file mode 100644
index c07b73be7c..0000000000
--- a/docs/CLI.md
+++ /dev/null
@@ -1,447 +0,0 @@
-# Command-Line Interface #
-
-The TUF command-line interface (CLI) requires a full
-[TUF installation](INSTALLATION.rst). Be sure to include the installation of
-extra dependencies and C extensions (
-```python3 -m pip install securesystemslib[crypto,pynacl]```).
-
-The use of the CLI is documented with examples below.
-
-----
-# Basic Examples #
-
-## Create a repository ##
-
-Create a TUF repository in the current working directory. A cryptographic key
-is created and set for each top-level role. The written Targets metadata does
-not sign for any targets, nor does it delegate trust to any roles. The
-`--init` call will also set up a client directory. By default, these
-directories will be `./tufrepo` and `./tufclient`.
-
-```Bash
-$ repo.py --init
-```
-
-Optionally, the repository can be written to a specified location.
-```Bash
-$ repo.py --init --path
-```
-
-The default top-level key files created with `--init` are saved to disk
-encrypted, with a default password of 'pw'. Instead of using the default
-password, the user can enter one on the command line for each top-level role.
-These optional command-line options also work with other CLI actions (e.g.,
-repo.py --add).
-```Bash
-$ repo.py --init [--targets_pw, --root_pw, --snapshot_pw, --timestamp_pw]
-```
-
-
-
-Create a bare TUF repository in the current working directory. A cryptographic
-key is *not* created nor set for each top-level role.
-```Bash
-$ repo.py --init --bare
-```
-
-
-
-Create a TUF repository with [consistent
-snapshots](https://github.com/theupdateframework/specification/blob/master/tuf-spec.md#7-consistent-snapshots)
-enabled, where target filenames have their hash prepended (e.g.,
-`.README.txt`), and metadata filenames have their version numbers
-prepended (e.g., `.snapshot.json`).
-```Bash
-$ repo.py --init --consistent
-```
-
-
-
-## Add a target file ##
-
-Copy a target file to the repo and add it to the Targets metadata (or the
-Targets role specified in --role). More than one target file, or directory,
-may be specified in --add. The --recursive option may be toggled to also
-include files in subdirectories of a specified directory. The Snapshot
-and Timestamp metadata are also updated and signed automatically, but this
-behavior can be toggled off with --no_release.
-```Bash
-$ repo.py --add
-$ repo.py --add [--recursive]
-```
-
-Similar to the --init case, the repository location can be chosen.
-```Bash
-$ repo.py --add --path
-```
-
-
-
-## Remove a target file ##
-
-Remove a target file from the Targets metadata (or the Targets role specified
-in --role). More than one target file or glob pattern may be specified in
---remove. The Snapshot and Timestamp metadata are also updated and signed
-automatically, but this behavior can be toggled off with --no_release.
-
-```Bash
-$ repo.py --remove ...
-```
-
-Examples:
-
-Remove all target files, that match `foo*.tgz,` from the Targets metadata.
-```Bash
-$ repo.py --remove "foo*.tgz"
-```
-
-Remove all target files from the `my_role` metadata.
-```Bash
-$ repo.py --remove "*" --role my_role --sign tufkeystore/my_role_key
-```
-
-
-## Generate key ##
-Generate a cryptographic key. The generated key can later be used to sign
-specific metadata with `--sign`. The supported key types are: `ecdsa`,
-`ed25519`, and `rsa`. If a keytype is not given, an Ed25519 key is generated.
-
-If adding a top-level key to a bare repo (i.e., repo.py --init --bare),
-the filenames of the top-level keys must be "root_key," "targets_key,"
-"snapshot_key," "timestamp_key." The filename can vary for any additional
-top-level key.
-```Bash
-$ repo.py --key
-$ repo.py --key
-$ repo.py --key [--path --pw [my_password],
- --filename ]
-```
-
-Instead of using a default password, the user can enter one on the command
-line or be prompted for it via password masking.
-```Bash
-$ repo.py --key ecdsa --pw my_password
-```
-
-```Bash
-$ repo.py --key rsa --pw
-Enter a password for the RSA key (...):
-Confirm:
-```
-
-
-
-## Sign metadata ##
-Sign, with the specified key(s), the metadata of the role indicated in --role.
-The Snapshot and Timestamp role are also automatically signed, if possible, but
-this behavior can be disabled with --no_release.
-```Bash
-$ repo.py --sign ... [--role , --path ]
-```
-
-For example, to sign the delegated `foo` metadata:
-```Bash
-$ repo.py --sign --role foo
-```
-
-
-
-## Trust keys ##
-
-The Root role specifies the trusted keys of the top-level roles, including
-itself. The --trust command-line option, in conjunction with --pubkeys and
---role, can be used to indicate the trusted keys of a role.
-
-```Bash
-$ repo.py --trust --pubkeys --role
-```
-
-For example:
-```Bash
-$ repo.py --init --bare
-$ repo.py --trust --pubkeys tufkeystore/my_key.pub tufkeystore/my_key_too.pub
- --role root
-```
-
-
-
-### Distrust keys ###
-
-Conversely, the Root role can discontinue trust of specified key(s).
-
-Example of how to discontinue trust of a key:
-```Bash
-$ repo.py --distrust --pubkeys tufkeystore/my_key_too.pub --role root
-```
-
-
-
-## Delegations ##
-
-Delegate trust of target files from the Targets role (or the one specified in
---role) to some other role (--delegatee). --delegatee is trusted to sign for
-target files that match the delegated glob pattern(s). The --delegate option
-does not create metadata for the delegated role, rather it updates the
-delegator's metadata to list the delegation to --delegatee. The Snapshot and
-Timestamp metadata are also updated and signed automatically, but this behavior
-can be toggled off with --no_release.
-
-```Bash
-$ repo.py --delegate ... --delegatee --pubkeys
- ... [--role --terminating --threshold
---sign ]
-```
-
-For example, to delegate trust of `foo*.gz` packages to the `foo` role:
-
-```
-$ repo.py --delegate "foo*.tgz" --delegatee foo --pubkeys tufkeystore/foo.pub
-```
-
-
-
-## Revocations ##
-
-Revoke trust of target files from a delegated role (--delegatee). The
-"targets" role performs the revocation if --role is not specified. The
---revoke option does not delete the metadata belonging to --delegatee, instead
-it removes the delegation to it from the delegator's (or --role) metadata. The
-Snapshot and Timestamp metadata are also updated and signed automatically, but
-this behavior can be toggled off with --no_release.
-
-
-```Bash
-$ repo.py --revoke --delegatee [--role
---sign ]
-```
-
-
-
-## Verbosity ##
-
-Set the verbosity of the logger (2, by default). The lower the number, the
-greater the verbosity. Logger messages are saved to `tuf.log` in the current
-working directory.
-```Bash
-$ repo.py --verbose <0-5>
-```
-
-
-
-## Clean ##
-
-Delete the repo in the current working directory, or the one specified with
-`--path`. Specifically, the `tufrepo`, `tufclient`, and `tufkeystore`
-directories are deleted.
-
-```Bash
-$ repo.py --clean
-$ repo.py --clean --path
-```
-----
-
-
-
-
-
-
-
-
-# Further Examples #
-
-## Basic Update Delivery ##
-
-Steps:
-
-(1) initialize a repo.
-
-(2) delegate trust of target files to another role.
-
-(3) add a trusted file to the delegated role.
-
-(4) fetch the trusted file from the delegated role.
-
-```Bash
-Step (1)
-$ repo.py --init
-
-Step (2)
-$ repo.py --key ed25519 --filename mykey
-$ repo.py --delegate "README.*" --delegatee myrole --pubkeys tufkeystore/mykey.pub
-$ repo.py --sign tufkeystore/mykey --role myrole
-Enter a password for the encrypted key (tufkeystore/mykey):
-$ echo "my readme text" > README.txt
-
-Step (3)
-$ repo.py --add README.txt --role myrole --sign tufkeystore/mykey
-Enter a password for the encrypted key (tufkeystore/mykey):
-```
-
-Serve the repo
-```Bash
-$ python3 -m http.server 8001
-```
-
-```Bash
-Step (4)
-$ client.py --repo http://localhost:8001 README.txt
-$ tree .
-.
-├── tuf.log
-├── tufrepo
-│ └── metadata
-│ ├── current
-│ │ ├── 1.root.json
-│ │ ├── myrole.json
-│ │ ├── root.json
-│ │ ├── snapshot.json
-│ │ ├── targets.json
-│ │ └── timestamp.json
-│ └── previous
-│ ├── 1.root.json
-│ ├── root.json
-│ ├── snapshot.json
-│ ├── targets.json
-│ └── timestamp.json
-└── tuftargets
- └── README.txt
-
- 5 directories, 13 files
-```
-
-
-## Correcting a Key ##
-The filename of the top-level keys must be "root_key," "targets_key,"
-"snapshot_key," and "root_key." The filename can vary for any additional
-top-level key.
-
-Steps:
-
-(1) initialize a repo containing default keys for the top-level roles.
-(2) distrust the default key for the root role.
-(3) create a new key and trust its use with the root role.
-(4) sign the root metadata file.
-
-```Bash
-Step (1)
-$ repo.py --init
-
-Step (2)
-$ repo.py --distrust --pubkeys tufkeystore/root_key.pub --role root
-
-Step (3)
-$ repo.py --key ed25519 --filename root_key
-$ repo.py --trust --pubkeys tufkeystore/root_key.pub --role root
-
-Step (4)
-$ repo.py --sign tufkeystore/root_key --role root
-Enter a password for the encrypted key (tufkeystore/root_key):
-```
-
-
-## More Update Delivery ##
-
-Steps:
-
-(1) create a bare repo.
-
-(2) add keys to the top-level roles.
-
-(3) delegate trust of particular target files to another role X, where role X
-has a signature threshold 2 and is marked as a terminating delegation. The
-keys for role X and Y should be created prior to performing the delegation.
-
-(4) Delegate from role X to role Y.
-
-(5) have role X sign for a file also signed by the Targets role, to demonstrate
-the expected file that should be downloaded by the client.
-
-(6) perform an update.
-
-(7) halt the server, add README.txt to the Targets role, restart the server,
-and fetch the Target's role README.txt.
-
-(8) Add LICENSE to 'role_y' and demonstrate that the client must not fetch it
-because 'role_x' is a terminating delegation (and hasn't signed for it).
-
-```Bash
-Steps (1) and (2)
-$ repo.py --init --consistent --bare
-$ repo.py --key ed25519 --filename root_key
-$ repo.py --trust --pubkeys tufkeystore/root_key.pub --role root
-$ repo.py --key ecdsa --filename targets_key
-$ repo.py --trust --pubkeys tufkeystore/targets_key.pub --role targets
-$ repo.py --key rsa --filename snapshot_key
-$ repo.py --trust --pubkeys tufkeystore/snapshot_key.pub --role snapshot
-$ repo.py --key ecdsa --filename timestamp_key
-$ repo.py --trust --pubkeys tufkeystore/timestamp_key.pub --role timestamp
-$ repo.py --sign tufkeystore/root_key --role root
-Enter a password for the encrypted key (tufkeystore/root_key):
-$ repo.py --sign tufkeystore/targets_key --role targets
-Enter a password for the encrypted key (tufkeystore/targets_key):
-```
-
-```Bash
-Steps (3) and (4)
-$ repo.py --key ed25519 --filename key_x
-$ repo.py --key ed25519 --filename key_x2
-
-$ repo.py --delegate "README.*" "LICENSE" --delegatee role_x --pubkeys
- tufkeystore/key_x.pub tufkeystore/key_x2.pub --threshold 2 --terminating
-$ repo.py --sign tufkeystore/key_x tufkeystore/key_x2 --role role_x
-
-$ repo.py --key ed25519 --filename key_y
-
-$ repo.py --delegate "README.*" "LICENSE" --delegatee role_y --role role_x
- --pubkeys tufkeystore/key_y.pub --sign tufkeystore/key_x tufkeystore/key_x2
-
-$ repo.py --sign tufkeystore/key_y --role role_y
-```
-
-```Bash
-Steps (5) and (6)
-$ echo "role_x's readme" > README.txt
-$ repo.py --add README.txt --role role_x --sign tufkeystore/key_x tufkeystore/key_x2
-```
-
-Serve the repo
-```Bash
-$ python3 -m http.server 8001
-```
-
-Fetch the role x's README.txt
-```Bash
-$ client.py --repo http://localhost:8001 README.txt
-$ cat tuftargets/README.txt
-role_x's readme
-```
-
-
-```Bash
-Step (7)
-halt the server...
-
-$ echo "Target role's readme" > README.txt
-$ repo.py --add README.txt
-
-restart the server...
-```
-
-```Bash
-$ rm -rf tuftargets/ tuf.log
-$ client.py --repo http://localhost:8001 README.txt
-$ cat tuftargets/README.txt
-Target role's readme
-```
-
-```Bash
-Step (8)
-$ echo "role_y's license" > LICENSE
-$ repo.py --add LICENSE --role role_y --sign tufkeystore/key_y
-```
-
-```Bash
-$ rm -rf tuftargets/ tuf.log
-$ client.py --repo http://localhost:8001 LICENSE
-Error: 'LICENSE' not found.
-```
diff --git a/docs/CONTRIBUTING.rst b/docs/CONTRIBUTING.rst
new file mode 100644
index 0000000000..94e10f6fb0
--- /dev/null
+++ b/docs/CONTRIBUTING.rst
@@ -0,0 +1,88 @@
+Instructions for contributors
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Contribute to python-tuf by submitting pull requests against the "develop"
+branch of this repository. Detailed instructions are available in our
+`development guidelines
+`_.
+All submitted code should follow our `style guidelines
+`_
+and must be `unit tested <#unit-tests>`_.
+
+.. note::
+
+ Also see `development installation instructions `_.
+
+Testing
+=======
+
+With `tox `_ the whole test suite can be executed in
+a separate *virtual environment* for each supported Python version available on
+the system. ``tuf`` and its dependencies are installed automatically for each
+tox run.
+
+::
+
+ $ tox
+
+Below, you will see more details about each step managed by ``tox``, in case
+you need debug/run outside ``tox``.
+
+Unit tests
+----------
+
+More specifically, the Update Framework's test suite can be executed by invoking
+the test aggregation script inside the *tests* subdirectory. ``tuf`` and its
+dependencies must already be installed.
+::
+
+ $ cd tests/
+ $ python3 aggregate_tests.py
+
+
+Individual tests can also be executed. Optional ``-v`` flags can be added to
+increase log level up to DEBUG (``-vvvv``).
+::
+
+ $ cd tests/
+ $ python3 test_updater_ng.py -v
+
+
+Coverage
+--------
+
+To run the tests and measure their code coverage, the aggregation script can be
+invoked with the ``coverage`` tool (requires installation of ``coverage``, e.g.
+via PyPI).
+::
+
+ $ cd tests/
+ $ coverage run aggregate_tests.py && coverage report
+
+
+Auto-formatting
+---------------
+
+CI/CD will check that new TUF code is formatted with `black
+`__ and `isort `__.
+Auto-formatting can be done on the command line:
+::
+
+ $ black
+ $ isort
+
+or via source code editor plugin
+[`black `__,
+`isort `__] or
+`pre-commit `__-powered git hooks
+[`black `__,
+`isort `__].
+
+
+DCO
+===
+
+Contributors must also indicate acceptance of the `Developer Certificate of
+Origin `_ by appending a ``Signed-off-by:
+Your Name `` to each git commit message (see `git commit
+--signoff `_).
diff --git a/docs/CONTRIBUTORS.rst b/docs/CONTRIBUTORS.rst
deleted file mode 100644
index 302c8c205b..0000000000
--- a/docs/CONTRIBUTORS.rst
+++ /dev/null
@@ -1,202 +0,0 @@
-Instructions for Contributors
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Note: Development of TUF occurs on the "develop" branch of this repository.
-
-Contributions can be made by submitting GitHub pull requests. Submitted code
-should follow our `code style guidelines
-`_, which are
-enforced with linters and auto-formatters (details below).
-
-Contributors must also indicate acceptance of the `Developer Certificate of
-Origin `_ (DCO) when making a contribution
-to the project. Acceptance of the DCO can be established by appending a
-``Signed-off-by: Your Name `` to the Git commit message.
-For example:
-
-::
-
- Commit message
-
- Signed-off-by: Vladimir Diaz
-
-The required ``Signed-off-by`` text can be automatically appended to the commit
-message via the ``-s`` command-line option to ``git commit``:
-
-::
-
- $ git commit -s -m "Commit message"
-
-The full text of the DCO:
-
-::
-
- Developer Certificate of Origin
- Version 1.1
-
- Copyright (C) 2004, 2006 The Linux Foundation and its contributors.
- 1 Letterman Drive
- Suite D4700
- San Francisco, CA, 94129
-
- Everyone is permitted to copy and distribute verbatim copies of this
- license document, but changing it is not allowed.
-
- Developer's Certificate of Origin 1.1
-
- By making a contribution to this project, I certify that:
-
- (a) The contribution was created in whole or in part by me and I have the
- right to submit it under the open source license indicated in the file; or
-
- (b) The contribution is based upon previous work that, to the best of my
- knowledge, is covered under an appropriate open source license and I have
- the right under that license to submit that work with modifications,
- whether created in whole or in part by me, under the same open source
- license (unless I am permitted to submit under a different license), as
- indicated in the file; or
-
- (c) The contribution was provided directly to me by some other person who
- certified (a), (b) or (c) and I have not modified it.
-
- (d) I understand and agree that this project and the contribution are
- public and that a record of the contribution (including all personal
- information I submit with it, including my sign-off) is maintained
- indefinitely and may be redistributed consistent with this project or the
- open source license(s) involved.
-
-
-To facilitate development and installation of edited version of the code base,
-developers are encouraged to install `Virtualenv `_,
-which is a tool to create isolated Python environments. It includes
-``pip`` and ``setuptools``, Python packages that can be used to
-install TUF and its dependencies. All installation methods of
-virtualenv are outlined in the `installation
-section `_,
-and instructions for installing locally from source are provided here:
-::
-
- $ curl -O https://pypi.python.org/packages/source/v/virtualenv/virtualenv-15.0.3.tar.gz
- $ tar xvfz virtualenv-15.0.3.tar.gz
- $ cd virtualenv-15.0.3
- $ python3 virtualenv.py myVE
-
-
-Development Installation
-========================
-
-To work on the TUF project, it's best to perform a development install.
-
-1. First, `install non-Python dependencies `_.
-
-2. Then clone this repository:
-
-::
-
- $ git clone https://github.com/theupdateframework/python-tuf
-
-3. Then perform a full, editable/development install. This will include all
- optional cryptographic support, the testing/linting dependencies, etc.
- With a development installation, modifications to the code in the current
- directory will affect the installed version of TUF.
-
-::
-
- $ python3 -m pip install -r requirements-dev.txt
-
-
-Auto-formatting
-===============
-
-CI/CD will check that new TUF code is formatted with `black
-`__ and `isort `__.
-Auto-formatting can be done on the command line:
-::
-
- $ # TODO: configure black and isort args in pyproject.toml (see #1161)
- $ black --line-length 80 tuf/api
- $ isort --line-length 80 --profile black -p tuf tuf/api
-
-or via source code editor plugin
-[`black `__,
-`isort `__] or
-`pre-commit `__-powered git hooks
-[`black `__,
-`isort `__].
-
-
-Testing
-=======
-
-The Update Framework's unit test suite can be executed by invoking the test
-aggregation script inside the *tests* subdirectory. ``tuf`` and its
-dependencies must already be installed (see above).
-::
-
- $ cd tests
- $ python3 aggregate_tests.py
-
-Individual tests can also be executed. Optional '-v' flags can be added to
-increase log level up to DEBUG ('-vvvv').
-::
-
- $ python3 test_updater.py # run a specific test file
- $ python3 test_updater.py TestUpdater.test_4_refresh # run a specific test
- $ python3 test_updater.py -vvvv TestUpdater.test_4_refresh # run test with DEBUG log level
-
-
-All of the log levels and the corresponding options that could be used for testing are:
-
-.. list-table::
- :widths: 20 25
- :header-rows: 1
-
- * - Option
- - Log Level
- * - default (no argument passed)
- - ERROR (test names are not printed)
- * - `-v`
- - ERROR (test names are printed at this level and above)
- * - `-vv`
- - WARNING
- * - `-vvv`
- - INFO
- * - `-vvvv`
- - DEBUG
-
-
-To run the tests and measure their code coverage, the aggregation script can be
-invoked with the ``coverage`` tool (requires installation of ``coverage``, e.g.
-via PyPI).
-::
-
- $ coverage run aggregate_tests.py && coverage report
-
-
-To develop and test ``tuf`` with above commands alongside its in-house dependency
-`securesystemslib `_,
-it is recommended to first make an editable install of ``tuf`` (in
-a *venv*), and then install ``securesystemslib`` in editable mode too (in the same *venv*).
-::
-
- $ cd path/to/tuf
- $ python3 -m pip install -r requirements-dev.txt
- $ cd path/to/securesystemslib
- $ python3 -m pip install -r requirements-dev.txt
-
-
-With `tox `_ the test suite can be executed in a
-separate *venv* for each supported Python version. While the supported
-Python versions must already be available, ``tox`` will install ``tuf`` and its
-dependencies anew in each environment.
-::
-
- $ tox
-
-
-An additional non-default ``tox`` environment is available and can be used to
-test ``tuf`` against the tip of development of ``securesystemslib`` on GitHub,
-to e.g. prepare the former for a new release of the latter.
-::
-
- $ tox -e with-sslib-master
diff --git a/docs/GETTING_STARTED.rst b/docs/GETTING_STARTED.rst
deleted file mode 100644
index fad0d847fb..0000000000
--- a/docs/GETTING_STARTED.rst
+++ /dev/null
@@ -1,10 +0,0 @@
-Getting Started
----------------
-
-- `Overview of TUF `_
-- `Installation `_
-- Beginner Tutorials (using the basic command-line interface):
- - `Quickstart `_
- - `CLI Documentation and Examples `_
-- `Advanced Tutorial `_
-- `Guidelines for Contributors `_
diff --git a/docs/GOVERNANCE.md b/docs/GOVERNANCE.md
index 627c7c83f2..75d9a16e21 100644
--- a/docs/GOVERNANCE.md
+++ b/docs/GOVERNANCE.md
@@ -10,16 +10,16 @@ The project is maintained by the people indicated in
review GitHub pull requests and (2) open issues or [submit vulnerability
reports](https://github.com/theupdateframework/python-tuf#security-issues-and-bugs).
A maintainer has the authority to approve or reject pull requests submitted by
-contributors.
+contributors.
More significant changes in the project, such as those that require a TAP or
-changes in governance, are guided by a maintainer called the Consensus
-Builder (CB). The project's Consensus Builder (CB) is Justin Cappos
+changes in governance, are guided by a maintainer called the Consensus
+Builder (CB). The project's Consensus Builder (CB) is Justin Cappos
, who has a lifetime appointment.
## Contributions
[A contributor can submit GitHub pull
-requests](CONTRIBUTORS.rst)
+requests](CONTRIBUTING.rst)
to the project's repositories. They must follow the project's [code of
conduct](CODE-OF-CONDUCT.md), the [developer certificate of
origin](https://developercertificate.org/), the [code style
@@ -54,7 +54,7 @@ The CB has the authority to add or remove maintainers.
## Changes in governance
-The CB supervises changes in governance, but a majority of maintainers must vote +1 on the PR.
+The CB supervises changes in governance, but a majority of maintainers must vote +1 on the PR.
## Changes in the consensus builder
diff --git a/docs/INSTALLATION.rst b/docs/INSTALLATION.rst
index 6a85122e70..ae6d1d6f1f 100644
--- a/docs/INSTALLATION.rst
+++ b/docs/INSTALLATION.rst
@@ -1,93 +1,86 @@
Installation
============
-*pip* is the recommended installer for installing and managing Python packages.
-The project can be installed either locally or from the Python Package Index.
-All `TUF releases
-`_ are cryptographically
-signed, with GPG signatures available on both GitHub and `PyPI
-`_. PGP key information for our maintainers
-is available on our `website
-`_, on major keyservers,
-and on the `maintainers page
-`_.
+All versions of ``python-tuf`` can be installed from
+`PyPI `_ with
+`pip `_.
+::
-Release Verification
---------------------
+ python3 -m pip install tuf
-Assuming you trust `the maintainer's PGP key
-`_,
-the detached ASC signature can be downloaded and verified. For example::
+By default tuf is installed as pure python package with limited cryptographic
+abilities. See `Install with full cryptographic abilities`_ for more options.
- $ gpg --verify securesystemslib-0.10.8.tar.gz.asc
- gpg: assuming signed data in 'securesystemslib-0.10.8.tar.gz'
- gpg: Signature made Wed Nov 8 15:21:47 2017 EST
- gpg: using RSA key 3E87BB339378BC7B3DD0E5B25DEE9B97B0E2289A
- gpg: Good signature from "Vladimir Diaz (Vlad) " [ultimate]
+Install with full cryptographic abilities
+-----------------------------------------
+Default installation supports signature verification only, using a pure Python
+*ed25519* implementation. While this allows to operate a *basic client* on
+almost any computing device, you will need additional cryptographic abilities
+for *repository* code, i.e. key and signature generation, additional
+algorithms, and more performant backends. Opt-in is available via
+``securesystemslib``.
-Simple Installation
--------------------
+.. note::
-If you are only using ed25519-based cryptography, you can employ a pure-Python
-installation, done simply with one of the following commands:
+ Please consult with underlying crypto backend installation docs --
+ `cryptography `_ and
+ `pynacl `_ --
+ for possible system dependencies.
-Installing from Python Package Index (https://pypi.python.org/pypi).
-(Note: Please use "python3 -m pip install --no-use-wheel tuf" if your version
-of pip <= 1.5.6)::
+::
- $ python3 -m pip install tuf
+ python3 -m pip securesystemslib[crypto,pynacl] tuf
-**Alternatively**, if you wish to install from a GitHub release you've already
-downloaded, or a package you obtained in another way, you can instead:
-
-Install from a local source archive::
-
- $ python3 -m pip install
-
-Or install from the root directory of the unpacked archive::
-
- $ python3 -m pip install .
-
-
-
-Install with More Cryptographic Flexibility
--------------------------------------------
+Install for development
+-----------------------
-By default, C extensions are not installed and only Ed25519 signatures can
-be verified, in pure Python. To fully support RSA, Ed25519, ECDSA, and
-other crypto, you must install the extra dependencies declared by
-securesystemslib. **Note**: that may require non-Python dependencies, so if
-you encounter an error attempting this pip command, see
-`more instructions below <#non-python-dependencies>`_). ::
+To install tuf in editable mode together with development dependencies,
+`clone `_ the
+`python-tuf repository `_
+from GitHub, change into the project root directory, and install with pip
+(using `venv `_ is recommended).
- $ python3 -m pip install securesystemslib[crypto,pynacl] tuf
+.. note::
+ Development installation will `Install with full cryptographic abilities`_.
+ Please check above for possible system dependencies.
+::
-Non-Python Dependencies
------------------------
+ python3 -m pip install -r requirements-dev.txt
-If you encounter errors during installation, you may be missing
-certain system libraries.
-For example, PyNaCl and Cryptography -- two libraries used in the full
-installation to support certain cryptographic functions -- may require FFI
-(Foreign Function Interface) development header files.
+Verify release signatures
+-------------------------
-Debian-based distributions can install the necessary header libraries with apt::
+Releases on PyPI are signed with a maintainer key using
+`gpg `_ (see
+`MAINTAINERS.txt `_
+for key fingerprints). Signatures can be downloaded from the
+`GitHub release `_
+page (look for *\*.asc* files in the *Assets* section).
- $ apt-get install build-essential libssl-dev libffi-dev python-dev
+Below code shows how to verify the signature of a
+`built `_ distribution,
+signed by the maintainer *Lukas Pühringer*. It works
+alike for `source `_ distributions.
-Fedora-based distributions can instead install these libraries with dnf::
+::
- $ dnf install libffi-devel redhat-rpm-config openssl-devel
+ # Get wheel from PyPI and signature from GitHub
+ python3 -m pip download --no-deps tuf==0.20.0
+ wget https://github.com/theupdateframework/python-tuf/releases/download/v0.20.0/tuf-0.20.0-py3-none-any.whl.asc
-OS X users can install these header libraries with the `Homebrew `_
-package manager, among other options::
+ # Get public key, compare fingerprint in MAINTAINERS.txt, and verify with gpg
+ gpg --recv-keys 89A2AD3C07D962E8
+ gpg --verify tuf-0.20.0-py3-none-any.whl.asc
- $ brew install python3
- $ brew install libffi
+ # Output:
+ # gpg: assuming signed data in 'tuf-0.20.0-py3-none-any.whl'
+ # gpg: Signature made Thu Dec 16 09:21:38 2021 CET
+ # gpg: using RSA key 8BA69B87D43BE294F23E812089A2AD3C07D962E8
+ # gpg: Good signature from "Lukas Pühringer " [ultimate]
diff --git a/docs/MAINTAINERS.txt b/docs/MAINTAINERS.txt
index ba87ff01b3..b6515b9ea9 100644
--- a/docs/MAINTAINERS.txt
+++ b/docs/MAINTAINERS.txt
@@ -10,11 +10,6 @@ Consensus Builder:
Maintainers:
- Sebastien Awwad
- Email: sebastien.awwad@nyu.edu
- GitHub username: @awwad
- PGP fingerprint: C2FB 9C91 0758 B682 7BC4 3233 BC0C 6DED D5E5 CC03
-
Marina Moore
Email: mm9693@nyu.edu
GitHub username: @mnm678
@@ -24,17 +19,12 @@ Maintainers:
GitHub username: @trishankatdatadog
PGP fingerprint: 8C48 08B5 B684 53DE 06A3 08FD 5C09 0ED7 318B 6C1E
Keybase username: trishankdatadog
-
+
Lukas Puehringer
Email: lukas.puehringer@nyu.edu
GitHub username: @lukpueh
PGP fingerprint: 8BA6 9B87 D43B E294 F23E 8120 89A2 AD3C 07D9 62E8
- Santiago Torres-Arias
- Email: santiago@nyu.edu
- GitHub username: @SantiagoTorres
- PGP fingerprint: 903B AB73 640E B6D6 5533 EFF3 468F 122C E816 2295
-
Joshua Lock
Email: jlock@vmware.com
GitHub username: @joshuagl
@@ -46,6 +36,9 @@ Maintainers:
GitHub username: @jku
PGP fingerprint: 1343 C98F AB84 859F E5EC 9E37 0527 D8A3 7F52 1A2F
+Emeritus Maintainers:
+
+ Sebastien Awwad
+ Vladimir Diaz
Teodora Sechkova
- Email: tsechkova@vmware.com
- GitHub username: @sechkova
+ Santiago Torres-Arias
diff --git a/docs/METADATA.md b/docs/METADATA.md
deleted file mode 100644
index 9f140fe8fe..0000000000
--- a/docs/METADATA.md
+++ /dev/null
@@ -1,91 +0,0 @@
-# Metadata
-
-Metadata files provide information that clients can use to make update decisions. Different metadata files provide different information. The various metadata files are signed by different keys as are indicated by the root role. The concept of roles allows TUF to only trust information that a role is trusted to provide.
-
-The signed metadata files always include the time they were created and their expiration dates. This ensures that outdated metadata will be detected and that clients can refuse to accept metadata older than that which they've already seen.
-
-All TUF metadata uses a subset of the JSON object format. When calculating the digest of an object, we use the [Canonical JSON](http://wiki.laptop.org/go/Canonical_JSON) format. Implementation-level detail about the metadata can be found in the [spec](docs/tuf-spec.txt).
-
-There are four required top-level roles and one optional top-level role, each with their own metadata file.
-
-Required:
-
-* Root
-* Targets
-* Snapshot
-* Timestamp
-
-Optional:
-
-* Mirrors (unimplemented)
-
-There may also be any number of delegated target roles.
-
-## Root Metadata (root.json)
-
-Signed by: Root role.
-
-Specifies the other top-level roles. When specifying these roles, the trusted keys for each role are listed along with the minimum number of those keys which are required to sign the role's metadata. We call this number the signature threshold.
-
-See [example](https://raw.githubusercontent.com/theupdateframework/tuf/develop/tests/repository_data/repository/metadata/root.json) of Root metadata.
-
-## Targets Metadata (targets.json)
-
-Signed by: Targets role.
-
-The targets.json metadata file lists hashes and sizes of target files. Target files are the actual files that clients are intending to download (for example, the software updates they are trying to obtain).
-
-This file can optionally define other roles to which it delegates trust. Delegating trust means that the delegated role is trusted for some or all of the target files available from the repository. When delegated roles are specified, they are specified in a similar way to how the Root role specifies the top-level roles: the trusted keys and signature threshold for each role is given. Additionally, one or more patterns are specified which indicate the target file paths for which clients should trust each delegated role.
-
-See [example](https://raw.githubusercontent.com/theupdateframework/tuf/develop/tests/repository_data/repository/metadata/targets.json) of Targets metadata.
-
-## Delegated Targets Metadata (role1.json)
-
-Signed by: A delegated targets role.
-
-The metadata files provided by delegated targets roles follow exactly the same format as the metadata file provided by the top-level Targets role.
-
-When the targets role delegates trust to other roles, each delegated role provides one signed metadata file. As is the
-case with the directory structure of top-level metadata, the delegated files are relative to the base URL of metadata available from a given repository mirror.
-
-A delegated role file is located at:
-
-/DELEGATED_ROLE.json
-
-where DELEGATED_ROLE is the name of the delegated role that has been specified in targets.json. If this role further delegates trust to a role named ANOTHER_ROLE, that role's signed metadata file is made available at:
-
-/ANOTHER_ROLE.json
-
-See
-[example](https://raw.githubusercontent.com/theupdateframework/tuf/develop/tests/repository_data/repository/metadata/role1.json)
-of delegated Targets metadata and [example](https://raw.githubusercontent.com/theupdateframework/tuf/develop/tests/repository_data/repository/metadata/role2.json) of a nested delegation.
-
-## snapshot Metadata (snapshot.json)
-
-Signed by: Snapshot role.
-
-The snapshot.json metadata file lists the version, and optionally the file hashes and sizes, of the top-level targets metadata and all delegated targets metadata. This file ensures that clients will see a consistent view of the files on the repository. That is, metadata files (and thus target file) that existed on the repository at different times cannot be combined and presented to clients by an attacker.
-
-See [example](https://raw.githubusercontent.com/theupdateframework/tuf/develop/tests/repository_data/repository/metadata/snapshot.json) of Snapshot metadata.
-
-## Timestamp Metadata (timestamp.json)
-
-Signed by: Timestamp role.
-
-The timestamp.json metadata file lists the hashes and size of the snapshot.json file. This is the first and potentially only file that needs to be downloaded when clients poll for the existence of updates. This file is frequently resigned and has a short expiration date, thus allowing clients to quickly detect if they are being prevented from obtaining the most recent metadata. An online key is generally used to automatically resign this file at regular intervals.
-
-There are two primary reasons why the timestamp.json file doesn't contain all of the information that the snapshot.json file does.
-
-* The timestamp.json file is downloaded very frequently and so should be kept as small as possible, especially considering that the snapshot.json file grows in size in proportion to the number of delegated target roles.
-* As the Timestamp role's key is an online key and thus at high risk, separate keys should be used for signing the snapshot.json metadata file so that the Snapshot role's keys can be kept offline and thus more secure.
-
-See [example](https://raw.githubusercontent.com/theupdateframework/tuf/develop/tests/repository_data/repository/metadata/timestamp.json) of Timestamp metadata.
-
-## Mirrors Metadata (mirrors.json)
-
-Optionally signed by: Mirrors role.
-
-The mirrors.json file provides an optional way to provide mirror list updates to TUF clients. Mirror lists can alternatively be provided directly by the software update system and obtained in any way the system sees fit, including being hard coded if that is what an applications wants to do.
-
-No example available. At the time of writing, this hasn't been implemented in
-TUF. Currently mirrors are specified by the client code.
diff --git a/docs/OVERVIEW.rst b/docs/OVERVIEW.rst
deleted file mode 100644
index 44f942c652..0000000000
--- a/docs/OVERVIEW.rst
+++ /dev/null
@@ -1,120 +0,0 @@
-What Is a Software Update System?
----------------------------------
-
-Generally, a software update system is an application (or part of an
-application) running on a client system that obtains and installs
-software. These systems typically update the applications installed
-on client systems to introduce new features, enhancements, and security
-fixes.
-
-Three major classes of software update systems are:
-
-- **Application updaters** which are used by applications to update
- themselves. For example, Firefox updates itself through its own
- application updater.
-
-- **Library package managers** such as those offered by many
- programming languages for installing additional libraries. These are
- systems such as Python's pip/easy_install + PyPI, Perl's CPAN,
- Ruby's RubyGems, and PHP's Composer.
-
-- **System package managers** used by operating systems to update and
- install all of the software on a client system. Debian's APT, Red
- Hat's YUM, and openSUSE's YaST are examples of these.
-
-Our Approach
-------------
-
-There are literally thousands of different software update systems in
-common use today. (In fact the average Windows user has about `two
-dozen `_
-different software updaters on their machine!)
-
-We are building a library that can be universally (and in most cases
-transparently) used to secure software update systems.
-
-Overview
---------
-
-On the surface, the update procedure followed by a software update system can be regarded
-as straightforward. Obtaining and installing an update just means:
-
-- Knowing when an update exists.
-- Downloading the update.
-- Applying the changes introduced by the update.
-
-The problem with this view is that it is only straightforward when there
-are no malicious parties involved throughout the update procedure. If an attacker
-is trying to interfere with these seemingly simple steps, there is plenty
-that they can do.
-
-TUF is designed to perform the first two steps of the above update procedure,
-while guarding against the majority of attacks that malicious actors have at
-their disposal; especially those attacks that are overlooked by security-conscious
-developers.
-
-
-Background
-----------
-
-Let's assume you take the approach that most systems do (at least, the
-ones that even try to be secure). You download both the file you want
-and a cryptographic signature of the file. You already know which key
-you trust to make the signature. You check that the signature is correct
-and was made by this trusted key. All seems well, right? Wrong. You are
-still at risk in many ways, including:
-
-- An attacker keeps giving you the same file, so you never realize
- there is an update.
-- An attacker gives you an older, insecure version of a file that you
- already have, so you download that one and blindly use it thinking
- it's newer.
-- An attacker gives you a newer version of a file you have but it's not
- the newest one. It's newer to you, but it may be insecure and
- exploitable by the attacker.
-- An attacker compromises the key used to sign these files and now you
- download a malicious file that is properly signed.
-
-These are just some of the attacks software update systems are
-vulnerable to when only using signed files. See
-`Security `_ for a full list of attacks and updater
-weaknesses TUF is designed to prevent.
-
-The following papers provide detailed information on securing software
-updater systems, TUF's design and implementation details, attacks on
-package managers, and package management security:
-
-- `Mercury: Bandwidth-Effective Prevention of Rollback Attacks Against Community Repositories
- `
-
-- `Diplomat: Using Delegations to Protect Community Repositories
- `
-
-- `Survivable Key Compromise in Software Update
- Systems `
-
-- `A Look In the Mirror: Attacks on Package
- Managers `
-
-- `Package Management
- Security `
-
-What TUF Does
--------------
-
-In order to securely download and verify target files, TUF requires a
-few extra files to exist on a repository. These are called metadata
-files. TUF metadata files contain additional information, including
-information about which keys are trusted, the cryptographic hashes of
-files, signatures on the metadata, metadata version numbers, and the
-date after which the metadata should be considered expired.
-
-When a software update system using TUF wants to check for updates, it
-asks TUF to do the work. That is, your software update system never has
-to deal with this additional metadata or understand what's going on
-underneath. If TUF reports back that there are updates available, your
-software update system can then ask TUF to download these files. TUF
-downloads them and checks them against the TUF metadata that it also
-downloads from the repository. If the downloaded target files are
-trustworthy, TUF hands them over to your software update system. See
-`Metadata `_ for more information and examples.
diff --git a/docs/QUICKSTART.md b/docs/QUICKSTART.md
deleted file mode 100644
index 6d35fb1d7d..0000000000
--- a/docs/QUICKSTART.md
+++ /dev/null
@@ -1,149 +0,0 @@
-# Quickstart #
-
-In this quickstart tutorial, we'll use the basic TUF command-line interface
-(CLI), which includes the `repo.py` script and the `client.py` script, to set
-up a repository with an update and metadata about that update, then download
-and verify that update as a client.
-
-Unlike the underlying TUF modules that the CLI uses, the CLI itself is a bit
-bare-bones. Using the CLI is the easiest way to familiarize yourself with
-how TUF works, however. It will serve as a very basic update system.
-
-----
-
-**Step (0)** - Make sure TUF is installed.
-
-Make sure that TUF is installed, along with some of the optional cryptographic
-libraries and C extensions. Try this command to do that:
-`python3 -m pip install securesystemslib[colors,crypto,pynacl] tuf`
-
-If you run into errors during that pip command, please consult the more
-detailed [TUF Installation Instructions](INSTALLATION.rst). (There are some
-system libraries that you may need to install first.)
-
-
-**Step (1)** - Create a basic repository and client.
-
-The following command will set up a basic update repository and basic client
-that knows about the repository. `tufrepo`, `tufkeystore`, and
-`tufclient` directories will be created in the current directory.
-
-```Bash
-$ repo.py --init
-```
-
-Four sets of keys are created in the `tufkeystore` directory. Initial metadata
-about the repository is created in the `tufrepo` directory, and also provided
-to the client in the `tufclient` directory.
-
-
-**Step (2)** - Add an update to the repository.
-
-We'll create a target file that will later be delivered as an update to clients.
-Metadata about that file will be created and signed, and added to the
-repository's metadata.
-
-```Bash
-$ echo 'Test file' > testfile
-$ repo.py --add testfile
-$ tree tufrepo/
-tufrepo/
-├── metadata
-│ ├── 1.root.json
-│ ├── root.json
-│ ├── snapshot.json
-│ ├── targets.json
-│ └── timestamp.json
-├── metadata.staged
-│ ├── 1.root.json
-│ ├── root.json
-│ ├── snapshot.json
-│ ├── targets.json
-│ └── timestamp.json
-└── targets
- └── testfile
-
- 3 directories, 11 files
-```
-
-The new file `testfile` is added to the repository, and metadata is updated in
-the `tufrepo` directory. The Targets metadata (`targets.json`) now includes
-the file size and hashes of the `testfile` target file, and this metadata is
-signed by the Targets role's key, so that clients can verify that metadata
-about `testfile` and then verify `testfile` itself.
-
-
-**Step (3)** - Serve the repo.
-
-We'll host a toy http server containing the `testfile` update and the
-repository's metadata.
-
-```Bash
-$ cd "tufrepo/"
-$ python3 -m http.server 8001
-```
-
-**Step (4)** - Obtain and verify the `testfile` update on a client.
-
-The client can request the package `testfile` from the repository. TUF will
-download and verify metadata from the repository as necessary to determine
-what the trustworthy hashes and length of `testfile` are, then download
-the target `testfile` from the repository and keep it only if it matches that
-trustworthy metadata.
-
-```Bash
-$ cd "../tufclient/"
-$ client.py --repo http://localhost:8001 testfile
-$ tree
-.
-├── tufrepo
-│ └── metadata
-│ ├── current
-│ │ ├── 1.root.json
-│ │ ├── root.json
-│ │ ├── snapshot.json
-│ │ ├── targets.json
-│ │ └── timestamp.json
-│ └── previous
-│ ├── 1.root.json
-│ ├── root.json
-│ ├── snapshot.json
-│ ├── targets.json
-│ └── timestamp.json
-└── tuftargets
- └── testfile
-
- 5 directories, 11 files
-```
-
-Now that a trustworthy update target has been obtained, an updater can proceed
-however it normally would to install or use the update.
-
-----
-
-### Next Steps
-
-TUF provides functionality for both ends of a software update system, the
-**update provider** and the **update client**.
-
-`repo.py` made use of `tuf.repository_tool`'s functionality for an update
-provider, helping you produce and sign metadata about your updates.
-
-`client.py` made use of `tuf.client.updater`'s client-side functionality,
-performing download and the critical verification steps for metadata and the
-update itself.
-
-You can look at [CLI.md](CLI.md) to toy with the TUF CLI a bit more.
-After that, try out using the underlying modules for a great deal more control.
-The more detailed [Advanced Tutorial](TUTORIAL.md) shows you how to use the
-underlying modules, `repository_tool` and `updater`.
-
-Ultimately, a sophisticated update client will use or re-implement those
-underlying modules. The TUF design is intended to play well with any update
-workflow.
-
-Please provide feedback or questions for this or other tutorials, or
-TUF in general, by checking out
-[our contact info](https://github.com/theupdateframework/python-tuf#contact), or
-creating [issues](https://github.com/theupdateframework/python-tuf/issues) in this
-repository!
diff --git a/docs/RELEASE.md b/docs/RELEASE.md
index ec1ad2a1e0..a0a8862027 100644
--- a/docs/RELEASE.md
+++ b/docs/RELEASE.md
@@ -1,36 +1,54 @@
# Release process
-* Ensure you have a backup of all working files and then remove files not tracked by git
- `git clean -xdf`. **NOTE**: this will delete all files in the tuf tree that aren't
- tracked by git
-* Ensure `docs/CHANGELOG.md` contains a one-line summary of each [notable
+
+**Prerequisites (one-time setup)**
+
+
+1. Go to [PyPI management page](https://pypi.org/manage/account/#api-tokens) and create
+ an [API token](https://pypi.org/help/#apitoken) with its scope limited to the tuf project.
+1. Go to [GitHub
+ settings](https://github.com/theupdateframework/python-tuf/settings/environments),
+ create an
+ [environment](https://docs.github.com/en/actions/deployment/targeting-different-environments/using-environments-for-deployment#creating-an-environment)
+ called `release` and configure [review
+ protection](https://docs.github.com/en/actions/deployment/targeting-different-environments/using-environments-for-deployment#required-reviewers).
+1. In the environment create a
+ [secret](https://docs.github.com/en/actions/deployment/targeting-different-environments/using-environments-for-deployment#environment-secrets)
+ called `PYPI_API_TOKEN` and paste the token created above.
+
+## Release
+
+1. Ensure `docs/CHANGELOG.md` contains a one-line summary of each [notable
change](https://keepachangelog.com/) since the prior release
-* Update `setup.py` and `tuf/__init__.py` to the new version number vA.B.C
-* Test packaging, uploading to Test PyPI and installing from a virtual environment
- (ensure commands invoking `python` below are using Python 3)
- * Remove existing dist build dirs
- * Create source dist `python3 setup.py sdist`
- * Create wheel (with 2 and 3 support) `python3 setup.py bdist_wheel --universal`
- * Sign the dists `gpg --detach-sign -a dist/tuf-vA.B.C.tar.gz`
- * Upload to test PyPI `twine upload --repository testpypi dist/*`
- * Verify the uploaded package https://testpypi.python.org/pypi/tuf/
-* Create a PR with updated `CHANGELOG.md` and version bumps
-* Once the PR is merged, pull the updated `develop` branch locally
-* Create a signed tag matching the updated version number on the merge commit
+2. Update `tuf/__init__.py` to the new version number `A.B.C`
+3. Create a PR with updated `CHANGELOG.md` and version bumps
+
+➔ Review PR on GitHub
+
+4. Once the PR is merged, pull the updated `develop` branch locally
+5. Create a signed tag for the version number on the merge commit
`git tag --sign vA.B.C -m "vA.B.C"`
- * Push the tag to GitHub `git push origin vA.B.C`
-* Create a new release on GitHub, copying the `CHANGELOG.md` entries for the
- release
-* Create a package for the formal release
- (ensure commands invoking `python` below are using Python 3)
- * Remove existing dist build dirs
- * Create source dist `python3 setup.py sdist`
- * Create wheel (with 2 and 3 support) `python3 setup.py bdist_wheel --universal`
- * Sign source dist `gpg --detach-sign -a dist/tuf-vA.B.C.tar.gz`
- * Sign wheel `gpg --detach-sign -a dist/tuf-vA.B.C-py2.py3-none-any.whl`
- * Upload to test PyPI `twine upload --repository testpypi dist/*`
- * Verify the uploaded package https://testpypi.python.org/pypi/tuf/
- * Upload to PyPI `twine upload dist/*`
-* Attach the signed dists to the release on GitHub
-* Announce the release on [#tuf on CNCF Slack](https://cloud-native.slack.com/archives/C8NMD3QJ3)
-* Ensure [POUF 1](https://github.com/theupdateframework/taps/blob/master/POUFs/reference-POUF/pouf1.md), for the reference implementation, is up-to-date
+6. Push the tag to GitHub `git push origin vA.B.C`
+
+ *A tag push triggers the [CD
+ workflow](https://github.com/theupdateframework/python-tuf/blob/develop/.github/workflows/cd.yml),
+ which runs the tests, builds source dist and wheel, creates a preliminary GitHub
+ release under `vA.B.C-rc`, and pauses for review.*
+
+7. Run `verify_release --skip-pypi` locally to make sure a build on your machine matches
+ the preliminary release artifacts published on GitHub.
+
+➔ [Review *deployment*](https://docs.github.com/en/actions/managing-workflow-runs/reviewing-deployments)
+on GitHub
+
+ *An approval resumes the CD workflow to publish the release on PyPI, and to finalize the
+ GitHub release (removes `-rc` suffix and updates release notes).*
+
+8. Run `verify_release` to make sure the PyPI release artifacts match the local build as
+ well. When called as `verify_release --sign []` the script additionally
+ creates gpg release signatures. When signed by maintainers with a corresponding GPG
+ fingerprint in the MAINTAINERS.md file, these signature files should be made available on
+ the GitHub release page under Assets.
+9. Announce the release on [#tuf on CNCF Slack](https://cloud-native.slack.com/archives/C8NMD3QJ3)
+10. Ensure [POUF 1](https://github.com/theupdateframework/taps/blob/master/POUFs/reference-POUF/pouf1.md),
+ for the reference implementation, is up-to-date
diff --git a/docs/ROADMAP.md b/docs/ROADMAP.md
deleted file mode 100644
index cf6baf2f3d..0000000000
--- a/docs/ROADMAP.md
+++ /dev/null
@@ -1,80 +0,0 @@
-# ROADMAP
-
-This is the roadmap for the project.
-
-## Release schedule
-A new release of the project is expected every 3 months. The release cycle,
-upcoming tasks, and any stated goals are subject to change.
-
-Releases are available both on [GitHub](https://github.com/theupdateframework/python-tuf/releases)
-and on [PyPI](https://pypi.org/project/tuf/#history). The GitHub listing
-includes release notes.
-
-
-## Latest release
-Please consult the repository's
-[releases page on GitHub](https://github.com/theupdateframework/python-tuf/releases)
-for information about the latest releases.
-
-As of the last editing of this document, the latest release was:
-Pre-release v0.11.2.dev3, January 10, 2019.
-* [Release notes and Download](https://github.com/theupdateframework/python-tuf/releases/tag/v0.11.1)
-* [PyPI release](https://pypi.org/project/tuf/)
-* Packaged by Sebastien Awwad
-* PGP fingerprint: C2FB 9C91 0758 B682 7BC4 3233 BC0C 6DED D5E5 CC03
-
-A number of older releases were packaged by Vladimir V Diaz:
-* Vladimir Diaz
-* PGP fingerprint: 3E87 BB33 9378 BC7B 3DD0 E5B2 5DEE 9B97 B0E2 289A
-
-
-## Tasks for upcoming releases
-
-In no particular order...
-
-- [ ] Provide protection against a class of slow retrieval attacks using long
-inter-byte delays, without sacrificing the use of clean, modern,
-production-quality HTTP libraries (requests currently).
-
-- [ ] Support ASN.1 metadata: loading, writing, signing, and verification.
-
-- [x] [CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/1351) badge.
- - [x] silver badge
- - [ ] gold badge (currently at 74%)
-
-- [ ] [Support graph of delegations](https://github.com/theupdateframework/python-tuf/issues/660)
-(requires refactor of API and client code).
-
-- [ ] [TAP 3: Multi-role delegations](https://github.com/theupdateframework/taps/blob/master/tap3.md).
-
-- [x] [TAP 4: Multiple repository consensus on entrusted targets](https://github.com/theupdateframework/taps/blob/master/tap4.md).
-
-- [ ] [TAP 5: Setting URLs for roles in the Root metadata file](https://github.com/theupdateframework/taps/blob/master/tap5.md).
-
-- [ ] [TAP 8: Key rotation and explicit self-revocation](https://github.com/theupdateframework/taps/blob/master/tap8.md).
-
-- [x] CLI tool and quickstart guide.
-
-- [x] Improve update speed.
-
-- [x] Fully support Windows.
-
-- [ ] Generalize metadata format in specification.
-
-- [ ] Support post quantum resilient crypto.
-
-- [ ] Resolve TODOs in the code.
-
-- [ ] Support Python's multilingual internationalization and localization
-services.
-
-- [ ] Improved regression and attack testing.
-
-- [ ] Automated tutorial and instructions testing to enforce doc maintenance.
-
-- [ ] Continue resolution of outstanding tickets on the issue tracker.
-
-- [ ] Generalize encrypted key files. Allow different forms of encryption, key derivation functions, etc.
-
-- [ ] Speed up loading and saving of metadata. Support option to save metadata to memory.
-
diff --git a/docs/SECURITY.md b/docs/SECURITY.md
deleted file mode 100644
index 8535acd3ef..0000000000
--- a/docs/SECURITY.md
+++ /dev/null
@@ -1,76 +0,0 @@
-# Security
-
-Generally, a software update system is secure if it can be sure that it knows about the latest available updates in a timely manner, any files it downloads are the correct files, and no harm results from checking or downloading files. The details of making this happen are complicated by various attacks that can be carried out against software update systems.
-
-## Attacks and Weaknesses
-
-The following are some of the known attacks on software update systems, including weaknesses that make attacks possible. In order to design a secure software update framework, these need to be understood and protected against. Some of these issues are or can be related depending on the design and implementation of a software update system.
-
-* **Arbitrary software installation**. An attacker installs anything they want on the client system. That is, an attacker can provide arbitrary files in response to download requests and the files will not be detected as illegitimate.
-
-* **Rollback attacks**. An attacker presents a software update system with older files than those the client has already seen, causing the client to use files older than those the client knows about.
-
-* **Fast-forward attacks**. An attacker arbitrarily increases the version numbers of project metadata files in the snapshot
-metadata well beyond the current value, thus tricking a software update system into thinking any subsequent updates are trying
-to rollback the package to a previous, out-of-date version. In some situations, such as those where there is a maximum possible
-version number, the perpetrator could use a number so high that the system would never be able to match it with the one in the
-snapshot metadata, and thus new updates could never be downloaded.
-
-* **Indefinite freeze attacks**. An attacker continues to present a software update system with the same files the client has already seen. The result is that the client does not know that new files are available.
-
-* **Endless data attacks**. An attacker responds to a file download request with an endless stream of data, causing harm to clients (e.g. a disk partition filling up or memory exhaustion).
-
-* **~~Slow retrieval attacks~~**. An attacker responds to clients with a very slow stream of data that essentially results in the client never continuing the update process.\
-**_NOTE: Due to limitations in a 3rd-party HTTP library, the TUF reference implementation currently provides only limited protection against slow retrieval attacks (see [tuf#932](https://github.com/theupdateframework/python-tuf/issues/932)). We plan to fix this in a future release._**
-
-* **Extraneous dependencies attacks**. An attacker indicates to clients that in order to install the software they wanted, they also need to install unrelated software. This unrelated software can be from a trusted source but may have known vulnerabilities that are exploitable by the attacker.
-
-* **Mix-and-match attacks**. An attacker presents clients with a view of a repository that includes files that did not exist together on the repository at the same time. This can result in, for example, outdated versions of dependencies being installed.
-
-* **Wrong software installation**. An attacker provides a client with a trusted file that is not the one the client wanted.
-
-* **Malicious mirrors preventing updates**. An attacker in control of one repository mirror is able to prevent users from obtaining updates from other, good mirrors.
-
-* **Vulnerability to key compromises**. An attacker who is able to compromise a single key or less than a given threshold of keys can compromise clients. This includes relying on a single online key (such as only being protected by SSL) or a single offline key (such as most software update systems use to sign files).
-
-## Design Concepts
-
-The design and implementation of TUF aims to be secure against all of the above attacks. A few general ideas drive much of the security of TUF.
-
-For the details of how TUF conveys the information discussed below, see the [Metadata documentation](METADATA.md).
-
-## Trust
-
-Trusting downloaded files really means trusting that the files were provided by some trusted party. Two frequently overlooked aspects of trust in a secure software update system are:
-
-* Trust should not be granted forever. Trust should expire if it is not renewed.
-* Compartmentalized trust. A trusted party should only be trusted for files that it is supposed to provide.
-
-## Mitigated Key Risk
-
-Cryptographic signatures are a necessary component in securing a software update system. The safety of the keys that are used to create these signatures affects the security of clients. Rather than incorrectly assume that private keys are always safe from compromise, a secure software update system must strive to keep clients as safe as possible even when compromises happen.
-
-Keeping clients safe despite dangers to keys involves:
-
-* Fast and secure key replacement and revocation.
-* Minimally trusting keys that are at high risk. Keys that are kept online or used in an automated fashion shouldn't pose immediate risk to clients if compromised.
-* Supporting the use of multiple keys with threshold/quorum signatures trust.
-
-## Integrity
-
-File integrity is important both with respect to single files as well as collections of files. It's fairly obvious that clients must verify that individual downloaded files are correct. Not as obvious but still very important is the need for clients to be certain that their entire view of a repository is correct. For example, if a trusted party is providing two files, a software update system should see the latest versions of both of those files, not just one of the files and not versions of the two files that were never provided together.
-
-## Freshness
-
-As software updates often fix security bugs, it is important for software update systems to be able to obtain the latest versions of files that are available. An attacker may want to trick a client into installing outdated versions of software or even just convince a client that no updates are available.
-
-Ensuring freshness means to:
-
-* Never accept files older than those that have been seen previously.
-* Recognize when there may be a problem obtaining updates.
-
-Note that it won't always be possible for a client to successfully update if an attacker is responding to their requests. However, a client should be able to recognize that updates may exist that they haven't been able to obtain.
-
-## Implementation Safety
-
-In addition to a secure design, TUF also works to be secure against implementation vulnerabilities including those common to software update systems. In some cases this is assisted by the inclusion of additional information in metadata. For example, knowing the expected size of a target file that is to be downloaded allows TUF to limit the amount of data it will download when retrieving the file. As a result, TUF is secure against endless data attacks (discussed above).
diff --git a/docs/TAP.rst b/docs/TAP.rst
deleted file mode 100644
index 3c20fde4f0..0000000000
--- a/docs/TAP.rst
+++ /dev/null
@@ -1,12 +0,0 @@
-What is a TAP?
---------------
-
-A TAP (TUF Augmentation Proposal) is a design document providing information to
-the TUF community, or describing a new feature for TUF or its processes or
-environment. We intend TAPs to be the primary mechanisms for proposing major
-new features, for collecting community input on an issue, and for documenting
-the design decisions that have gone into TUF.
-
-Please visit the `TAPs GitHub repo `_
-to review design changes that have been proposed to date, or to submit
-your own new feature.
diff --git a/docs/TUTORIAL.md b/docs/TUTORIAL.md
deleted file mode 100644
index d8659e7213..0000000000
--- a/docs/TUTORIAL.md
+++ /dev/null
@@ -1,696 +0,0 @@
-# Advanced Tutorial #
-
-## Table of Contents ##
-- [How to Create and Modify a TUF Repository](#how-to-create-and-modify-a-tuf-repository)
- - [Overview](#overview)
- - [Keys](#keys)
- - [Create RSA Keys](#create-rsa-keys)
- - [Import RSA Keys](#import-rsa-keys)
- - [Create and Import Ed25519 Keys](#create-and-import-ed25519-keys)
- - [Create Top-level Metadata](#create-top-level-metadata)
- - [Create Root](#create-root)
- - [Create Timestamp, Snapshot, Targets](#create-timestamp-snapshot-targets)
- - [Targets](#targets)
- - [Add Target Files](#add-target-files)
- - [Remove Target Files](#remove-target-files)
- - [Delegations](#delegations)
- - [Revoke Delegated Role](#revoke-delegated-role)
- - [Wrap-up](#wrap-up)
-- [Delegate to Hashed Bins](#delegate-to-hashed-bins)
-- [Consistent Snapshots](#consistent-snapshots)
-- [How to Perform an Update](#how-to-perform-an-update)
-
-## How to Create and Modify a TUF Repository ##
-
-### Overview ###
-A software update system must follow two steps to integrate The Update
-Framework (TUF). First, it must add the framework to the client side of the
-update system. The [tuf.client.updater](../tuf/client/README.md) module assists in
-integrating TUF on the client side. Second, the software repository on the
-server side must be modified to include a minimum of four top-level metadata
-(root.json, targets.json, snapshot.json, and timestamp.json). No additional
-software is required to convert a software repository to a TUF one. The
-low-level repository tool that generates the required TUF metadata for a
-software repository is the focus of this tutorial. There is also separate
-document that [demonstrates how TUF protects against malicious
-updates](../tuf/ATTACKS.md).
-
-The [repository tool](../tuf/repository_tool.py) contains functions to generate
-all of the files needed to populate and manage a TUF repository. The tool may
-either be imported into a Python module, or used with the Python interpreter in
-interactive mode.
-
-A repository object that encapsulates the metadata files of the repository can
-be created or loaded by the repository tool. Repository maintainers can modify
-the repository object to manipulate the metadata files stored on the
-repository. TUF clients use the metadata files to validate files requested and
-downloaded. In addition to the repository object, where the majority of
-changes are made, the repository tool provides functions to generate and
-persist cryptographic keys. The framework utilizes cryptographic keys to sign
-and verify metadata files.
-
-To begin, cryptographic keys are generated with the repository tool. However,
-before metadata files can be validated by clients and target files fetched in a
-secure manner, public keys must be pinned to particular metadata roles and
-metadata signed by role's private keys. After covering keys, the four required
-top-level metadata are created next. Examples are given demonstrating the
-expected work flow, where the metadata roles are created in a specific order,
-keys imported and loaded, and metadata signed and written to disk. Lastly,
-target files are added to the repository, and a custom delegation performed to
-extend the default roles of the repository. By the end, a fully populated TUF
-repository is generated that can be used by clients to securely download
-updates.
-
-### Keys ###
-The repository tool supports multiple public-key algorithms, such as
-[RSA](https://en.wikipedia.org/wiki/RSA_%28cryptosystem%29) and
-[Ed25519](https://ed25519.cr.yp.to/), and multiple cryptography libraries.
-
-Using [RSA-PSS](https://tools.ietf.org/html/rfc8017#section-8.1) or
-[ECDSA](https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm)
-signatures requires the [cryptography](https://cryptography.io/) library. If
-generation of Ed25519 signatures is needed
-[PyNaCl](https://github.com/pyca/pynacl) library should be installed. This
-tutorial assumes both dependencies are installed: refer to
-[Installation Instructions](INSTALLATION.rst#install-with-more-cryptographic-flexibility)
-for details.
-
-The Ed25519 and ECDSA keys are stored in JSON format and RSA keys are stored in PEM
-format. Private keys are encrypted and passphrase-protected (strengthened with
-PBKDF2-HMAC-SHA256.) Generating, importing, and loading cryptographic key
-files can be done with functions available in the repository tool.
-
-To start, a public and private RSA key pair is generated with the
-`generate_and_write_rsa_keypair()` function. The keys generated next are
-needed to sign the repository metadata files created in upcoming sub-sections.
-
-Note: In the instructions below, lines that start with `>>>` denote commands
-that should be entered by the reader, `#` begins the start of a comment, and
-text without prepended symbols is the output of a command.
-
-#### Create RSA Keys ####
-```python
->>> from tuf.repository_tool import *
-
-# Generate and write the first of two root keys for the TUF repository. The
-# following function creates an RSA key pair, where the private key is saved to
-# "root_key" and the public key to "root_key.pub" (both saved to the current
-# working directory).
->>> generate_and_write_rsa_keypair(password="password", filepath="root_key", bits=2048)
-
-# If the key length is unspecified, it defaults to 3072 bits. A length of less
-# than 2048 bits raises an exception. A similar function is available to supply
-# a password on the prompt. If an empty password is entered, the private key
-# is saved unencrypted.
->>> generate_and_write_rsa_keypair_with_prompt(filepath="root_key2")
-enter password to encrypt private key file '/path/to/root_key2'
-(leave empty if key should not be encrypted):
-Confirm:
-```
-The following four key files should now exist:
-
-1. **root_key**
-2. **root_key.pub**
-3. **root_key2**
-4. **root_key2.pub**
-
-If a filepath is not given, the KEYID of the generated key is used as the
-filename. The key files are written to the current working directory.
-```python
-# Continuing from the previous section . . .
->>> generate_and_write_rsa_keypair_with_prompt()
-enter password to encrypt private key file '/path/to/KEYID'
-(leave empty if key should not be encrypted):
-Confirm:
-```
-
-### Import RSA Keys ###
-```python
-# Continuing from the previous section . . .
-
-# Import an existing public key.
->>> public_root_key = import_rsa_publickey_from_file("root_key.pub")
-
-# Import an existing private key. Importing a private key requires a password,
-# whereas importing a public key does not.
->>> private_root_key = import_rsa_privatekey_from_file("root_key")
-enter password to decrypt private key file '/path/to/root_key'
-(leave empty if key not encrypted):
-```
-
-### Create and Import Ed25519 Keys ###
-```Python
-# Continuing from the previous section . . .
-
-# The same generation and import functions as for rsa keys exist for ed25519
->>> generate_and_write_ed25519_keypair_with_prompt(filepath='ed25519_key')
-enter password to encrypt private key file '/path/to/ed25519_key'
-(leave empty if key should not be encrypted):
-Confirm:
-
-# Import the ed25519 public key just created . . .
->>> public_ed25519_key = import_ed25519_publickey_from_file('ed25519_key.pub')
-
-# and its corresponding private key.
->>> private_ed25519_key = import_ed25519_privatekey_from_file('ed25519_key')
-enter password to decrypt private key file '/path/to/ed25519_key'
-(leave empty if key should not be encrypted):
-```
-
-Note: Methods are also available to generate and write keys from memory.
-* generate_ed25519_key()
-* generate_ecdsa_key()
-* generate_rsa_key()
-
-* import_ecdsakey_from_pem(pem)
-* import_rsakey_from_pem(pem)
-
-### Create Top-level Metadata ###
-The [metadata document](METADATA.md) outlines the JSON files that must exist
-on a TUF repository. The following sub-sections demonstrate the
-`repository_tool.py` calls repository maintainers may issue to generate the
-required roles. The top-level roles to be created are `root`, `timestamp`,
-`snapshot`, and `target`.
-
-We begin with `root`, the locus of trust that specifies the public keys of the
-top-level roles, including itself.
-
-
-#### Create Root ####
-```python
-# Continuing from the previous section . . .
-
-# Create a new Repository object that holds the file path to the TUF repository
-# and the four top-level role objects (Root, Targets, Snapshot, Timestamp).
-# Metadata files are created when repository.writeall() or repository.write()
-# are called. The repository directory is created if it does not exist. You
-# may see log messages indicating any directories created.
->>> repository = create_new_repository("repository")
-
-# The Repository instance, 'repository', initially contains top-level Metadata
-# objects. Add one of the public keys, created in the previous section, to the
-# root role. Metadata is considered valid if it is signed by the public key's
-# corresponding private key.
->>> repository.root.add_verification_key(public_root_key)
-
-# A role's verification key(s) (to be more precise, the verification key's
-# keyid) may be queried. Other attributes include: signing_keys, version,
-# signatures, expiration, threshold, and delegations (attribute available only
-# to a Targets role).
->>> repository.root.keys
-['b23514431a53676595922e955c2d547293da4a7917e3ca243a175e72bbf718df']
-
-# Add a second public key to the root role. Although previously generated and
-# saved to a file, the second public key must be imported before it can added
-# to a role.
->>> public_root_key2 = import_rsa_publickey_from_file("root_key2.pub")
->>> repository.root.add_verification_key(public_root_key2)
-
-# The threshold of each role defaults to 1. Maintainers may change the
-# threshold value, but repository_tool.py validates thresholds and warns users.
-# Set the threshold of the root role to 2, which means the root metadata file
-# is considered valid if it's signed by at least two valid keys. We also load
-# the second private key, which hasn't been imported yet.
->>> repository.root.threshold = 2
->>> private_root_key2 = import_rsa_privatekey_from_file("root_key2", password="password")
-
-# Load the root signing keys to the repository, which writeall() or write()
-# (write multiple roles, or a single role, to disk) use to sign the root
-# metadata.
->>> repository.root.load_signing_key(private_root_key)
->>> repository.root.load_signing_key(private_root_key2)
-
-# repository.status() shows missing verification and signing keys for the
-# top-level roles, and whether signatures can be created (also see #955).
-# This output shows that so far only the "root" role meets the key threshold and
-# can successfully sign its metadata.
->>> repository.status()
-'targets' role contains 0 / 1 public keys.
-'snapshot' role contains 0 / 1 public keys.
-'timestamp' role contains 0 / 1 public keys.
-'root' role contains 2 / 2 signatures.
-'targets' role contains 0 / 1 signatures.
-
-# In the next section we update the other top-level roles and create a repository
-# with valid metadata.
-```
-
-#### Create Timestamp, Snapshot, Targets
-Now that `root.json` has been set, the other top-level roles may be created.
-The signing keys added to these roles must correspond to the public keys
-specified by the Root role.
-
-On the client side, `root.json` must always exist. The other top-level roles,
-created next, are requested by repository clients in (Root -> Timestamp ->
-Snapshot -> Targets) order to ensure required metadata is downloaded in a
-secure manner.
-
-```python
-# Continuing from the previous section . . .
-
-# 'datetime' module needed to optionally set a role's expiration.
->>> import datetime
-
-# Generate keys for the remaining top-level roles. The root keys have been set above.
->>> generate_and_write_rsa_keypair(password='password', filepath='targets_key')
->>> generate_and_write_rsa_keypair(password='password', filepath='snapshot_key')
->>> generate_and_write_rsa_keypair(password='password', filepath='timestamp_key')
-
-# Add the verification keys of the remaining top-level roles.
-
->>> repository.targets.add_verification_key(import_rsa_publickey_from_file('targets_key.pub'))
->>> repository.snapshot.add_verification_key(import_rsa_publickey_from_file('snapshot_key.pub'))
->>> repository.timestamp.add_verification_key(import_rsa_publickey_from_file('timestamp_key.pub'))
-
-# Import the signing keys of the remaining top-level roles.
->>> private_targets_key = import_rsa_privatekey_from_file('targets_key', password='password')
->>> private_snapshot_key = import_rsa_privatekey_from_file('snapshot_key', password='password')
->>> private_timestamp_key = import_rsa_privatekey_from_file('timestamp_key', password='password')
-
-# Load the signing keys of the remaining roles so that valid signatures are
-# generated when repository.writeall() is called.
->>> repository.targets.load_signing_key(private_targets_key)
->>> repository.snapshot.load_signing_key(private_snapshot_key)
->>> repository.timestamp.load_signing_key(private_timestamp_key)
-
-# Optionally set the expiration date of the timestamp role. By default, roles
-# are set to expire as follows: root(1 year), targets(3 months), snapshot(1
-# week), timestamp(1 day).
->>> repository.timestamp.expiration = datetime.datetime(2080, 10, 28, 12, 8)
-
-# Mark roles for metadata update (see #964, #958)
->>> repository.mark_dirty(['root', 'snapshot', 'targets', 'timestamp'])
-
-# Write all metadata to "repository/metadata.staged/"
->>> repository.writeall()
-```
-
-### Targets ###
-TUF makes it possible for clients to validate downloaded target files by
-including a target file's length, hash(es), and filepath in metadata. The
-filepaths are relative to a `targets/` directory on the software repository. A
-TUF client can download a target file by first updating the latest copy of
-metadata (and thus available targets), verifying that their length and hashes
-are valid, and saving the target file(s) locally to complete the update
-process.
-
-In this section, the target files intended for clients are added to a
-repository and listed in `targets.json` metadata.
-
-#### Add Target Files ####
-
-The repository maintainer adds target files to roles (e.g., `targets` and
-`unclaimed`) by specifying their filepaths. The target files must exist at the
-specified filepaths before the repository tool can generate and add their
-(hash(es), length, and filepath) to metadata.
-
-First, the actual target files are manually created and saved to the `targets/`
-directory of the repository:
-
-```Bash
-# Create and save target files to the targets directory of the software
-# repository.
-$ cd repository/targets/
-$ echo 'file1' > file1.txt
-$ echo 'file2' > file2.txt
-$ echo 'file3' > file3.txt
-$ mkdir myproject; echo 'file4' > myproject/file4.txt
-$ cd ../../
-```
-
-With the target files available on the `targets/` directory of the software
-repository, the `add_targets()` method of a Targets role can be called to add
-the target filepaths to metadata.
-
-```python
-# Continuing from the previous section . . .
-
-# NOTE: If you exited the Python interactive interpreter above you need to
-# re-import the repository_tool-functions and re-load the repository and
-# signing keys.
->>> from tuf.repository_tool import *
-
-# The 'os' module is needed to gather file attributes, which will be included
-# in a custom field for some of the target files added to metadata.
->>> import os
-
-# Load the repository created in the previous section. This repository so far
-# contains metadata for the top-level roles, but no target paths are yet listed
-# in targets metadata.
->>> repository = load_repository('repository')
-
-# Create a list of all targets in the directory.
->>> list_of_targets = ['file1.txt', 'file2.txt', 'file3.txt']
-
-# Add the list of target paths to the metadata of the top-level Targets role.
-# Any target file paths that might already exist are NOT replaced, and
-# add_targets() does not create or move target files on the file system. Any
-# target paths added to a role must fall under the expected targets directory,
-# otherwise an exception is raised. The targets added to a role should actually
-# exist once writeall() or write() is called, so that the hash and size of
-# these targets can be included in Targets metadata.
->>> repository.targets.add_targets(list_of_targets)
-
-# Individual target files may also be added to roles, including custom data
-# about the target. In the example below, file permissions of the target
-# (octal number specifying file access for owner, group, others e.g., 0755) is
-# added alongside the default fileinfo. All target objects in metadata include
-# the target's filepath, hash, and length.
-# Note: target path passed to add_target() method has to be relative
-# to the targets directory or an exception is raised.
->>> target4_filepath = 'myproject/file4.txt'
->>> target4_abspath = os.path.abspath(os.path.join('repository', 'targets', target4_filepath))
->>> octal_file_permissions = oct(os.stat(target4_abspath).st_mode)[4:]
->>> custom_file_permissions = {'file_permissions': octal_file_permissions}
->>> repository.targets.add_target(target4_filepath, custom_file_permissions)
-```
-
-The private keys of roles affected by the changes above must now be imported and
-loaded. `targets.json` must be signed because a target file was added to its
-metadata. `snapshot.json` keys must be loaded and its metadata signed because
-`targets.json` has changed. Similarly, since `snapshot.json` has changed, the
-`timestamp.json` role must also be signed.
-
-```Python
-# Continuing from the previous section . . .
-
-# The private key of the updated targets metadata must be re-loaded before it
-# can be signed and written (Note the load_repository() call above).
->>> private_targets_key = import_rsa_privatekey_from_file('targets_key')
-enter password to decrypt private key file '/path/to/targets_key'
-(leave empty if key not encrypted):
-
->>> repository.targets.load_signing_key(private_targets_key)
-
-# Due to the load_repository() and new versions of metadata, we must also load
-# the private keys of Snapshot and Timestamp to generate a valid set of metadata.
->>> private_snapshot_key = import_rsa_privatekey_from_file('snapshot_key')
-enter password to decrypt private key file '/path/to/snapshot_key'
-(leave empty if key not encrypted):
->>> repository.snapshot.load_signing_key(private_snapshot_key)
-
->>> private_timestamp_key = import_rsa_privatekey_from_file('timestamp_key')
-enter password to decrypt private key file '/path/to/timestamp_key'
-(leave empty if key not encrypted):
->>> repository.timestamp.load_signing_key(private_timestamp_key)
-
-# Mark roles for metadata update (see #964, #958)
->>> repository.mark_dirty(['snapshot', 'targets', 'timestamp'])
-
-# Generate new versions of the modified top-level metadata (targets, snapshot,
-# and timestamp).
->>> repository.writeall()
-```
-
-#### Remove Target Files ####
-
-Target files previously added to roles may also be removed. Removing a target
-file requires first removing the target from a role and then writing the
-new metadata to disk.
-```python
-# Continuing from the previous section . . .
-
-# Remove a target file listed in the "targets" metadata. The target file is
-# not actually deleted from the file system.
->>> repository.targets.remove_target('myproject/file4.txt')
-
-# Mark roles for metadata update (see #964, #958)
->>> repository.mark_dirty(['snapshot', 'targets', 'timestamp'])
-
->>> repository.writeall()
-```
-
-#### Excursion: Dump Metadata and Append Signature ####
-
-The following two functions are intended for those that wish to independently
-sign metadata. Repository maintainers can dump the portion of metadata that is
-normally signed, sign it with an external signing tool, and append the
-signature to already existing metadata.
-
-First, the signable portion of metadata can be generated as follows:
-
-```Python
->>> signable_content = dump_signable_metadata('repository/metadata.staged/timestamp.json')
-```
-
-Then, use a tool like securesystemslib to create a signature over the signable
-portion. *Note, to make the signing key count towards the role's signature
-threshold, it needs to be added to `root.json`, e.g. via
-`repository.timestamp.add_verification_key(key)` (not shown in below snippet).*
-```python
->>> from securesystemslib.formats import encode_canonical
->>> from securesystemslib.keys import create_signature
->>> private_ed25519_key = import_ed25519_privatekey_from_file('ed25519_key')
-enter password to decrypt private key file '/path/to/ed25519_key'
->>> signature = create_signature(
-... private_ed25519_key, encode_canonical(signable_content).encode())
-```
-
-Finally, append the signature to the metadata
-```Python
->>> append_signature(signature, 'repository/metadata.staged/timestamp.json')
-```
-
-Note that the format of the signature is the format expected in metadata, which
-is a dictionary that contains a KEYID, the signature itself, etc. See the
-specification and [METADATA.md](METADATA.md) for a detailed example.
-
-### Delegations ###
-All of the target files available on the software repository created so far
-have been added to one role (the top-level Targets role). However, what if
-multiple developers are responsible for the files of a project? What if
-responsibility separation is desired? Performing a delegation, where one role
-delegates trust of some paths to another role, is an option for integrators
-that require additional roles on top of the top-level roles available by
-default.
-
-In the next sub-section, the `unclaimed` role is delegated from the top-level
-`targets` role. The `targets` role specifies the delegated role's public keys,
-the paths it is trusted to provide, and its role name.
-
-```python
-# Continuing from the previous section . . .
-
-# Generate a key for a new delegated role named "unclaimed".
->>> generate_and_write_rsa_keypair(password='password', filepath='unclaimed_key', bits=2048)
->>> public_unclaimed_key = import_rsa_publickey_from_file('unclaimed_key.pub')
-
-# Make a delegation (delegate trust of 'myproject/*.txt' files) from "targets"
-# to "unclaimed", where "unclaimed" initially contains zero targets.
->>> repository.targets.delegate('unclaimed', [public_unclaimed_key], ['myproject/*.txt'])
-
-# Thereafter, we can access the delegated role by its name to e.g. add target
-# files, just like we did with the top-level targets role.
->>> repository.targets("unclaimed").add_target("myproject/file4.txt")
-
-# Load the private key of "unclaimed" so that unclaimed's metadata can be
-# signed, and valid metadata created.
->>> private_unclaimed_key = import_rsa_privatekey_from_file('unclaimed_key', password='password')
-
->>> repository.targets("unclaimed").load_signing_key(private_unclaimed_key)
-
-# Mark roles for metadata update (see #964, #958)
->>> repository.mark_dirty(['snapshot', 'targets','timestamp', 'unclaimed'])
-
->>> repository.writeall()
-```
-
-
-
-
-#### Wrap-up ####
-
-In summary, the five steps a repository maintainer follows to create a TUF
-repository are:
-
-1. Create a directory for the software repository that holds the TUF metadata and the target files.
-2. Create top-level roles (`root.json`, `snapshot.json`, `targets.json`, and `timestamp.json`.)
-3. Add target files to the `targets` role.
-4. Optionally, create delegated roles to distribute target files.
-5. Write the changes.
-
-The repository tool saves repository changes to a `metadata.staged` directory.
-Repository maintainers may push finalized changes to the "live" repository by
-copying the staged directory to its destination.
-```Bash
-# Copy the staged metadata directory changes to the live repository.
-$ cp -r "repository/metadata.staged/" "repository/metadata/"
-```
-
-## Consistent Snapshots ##
-The basic TUF repository we have generated above is adequate for repositories
-that have some way of guaranteeing consistency of repository data. A community
-software repository is one example where consistency of files and metadata can
-become an issue. Repositories of this kind are continually updated by multiple
-maintainers and software authors uploading their packages, increasing the
-likelihood that a client downloading version X of a release unexpectedly
-requests the target files of a version Y just released.
-
-To guarantee consistency of metadata and target files, a repository may
-optionally support multiple versions of `snapshot.json` simultaneously, where a
-client with version 1 of `snapshot.json` can download `target_file.zip` and
-another client with version 2 of `snapshot.json` can also download a different
-`target_file.zip` (same file name, but different file digest.) If the
-`consistent_snapshot` parameter of writeall() or write() are `True`, metadata
-and target file names on the file system have their digests prepended (note:
-target file names specified in metadata do not contain digests in their names.)
-
-The repository maintainer is responsible for the duration of multiple versions
-of metadata and target files available on a repository. Generating consistent
-metadata and target files on the repository is enabled by setting the
-`consistent_snapshot` argument of `writeall()` or `write()` . Note that
-changing the consistent_snapshot setting involves writing a new version of
-root.
-
-
-
-## Delegate to Hashed Bins ##
-Why use hashed bin delegations?
-
-For software update systems with a large number of target files, delegating to
-hashed bins (a special type of delegated role) might be an easier alternative
-to manually performing the delegations. How many target files should each
-delegated role contain? How will these delegations affect the number of
-metadata that clients must additionally download in a typical update? Hashed
-bin delegations are available to integrators that rather not deal with the
-management of delegated roles and a great number of target files.
-
-A large number of target files may be distributed to multiple hashed bins with
-`delegate_hashed_bins()`. The metadata files of delegated roles will be nearly
-equal in size (i.e., target file paths are uniformly distributed by calculating
-the target filepath's digest and determining which bin it should reside in.)
-The updater client will use "lazy bin walk" (visit and download the minimum
-metadata required to find a target) to find a target file's hashed bin
-destination. This method is intended for repositories with a large number of
-target files, a way of easily distributing and managing the metadata that lists
-the targets, and minimizing the number of metadata files (and size) downloaded
-by the client.
-
-The `delegate_hashed_bins()` method has the following form:
-```Python
-delegate_hashed_bins(list_of_targets, keys_of_hashed_bins, number_of_bins)
-```
-
-We next provide a complete example of retrieving target paths to add to hashed
-bins, performing the hashed bin delegations, signing them, and delegating paths
-to some role.
-
-```Python
-# Continuing from the previous section . . .
-
-# Remove 'myproject/file4.txt' from unclaimed role and instead further delegate
-# all targets in myproject/ to hashed bins.
->>> repository.targets('unclaimed').remove_target("myproject/file4.txt")
-
-# Get a list of target paths for the hashed bins.
->>> targets = ['myproject/file4.txt']
-
-# Delegate trust to 32 hashed bin roles. Each role is responsible for the set
-# of target files, determined by the path hash prefix. TUF evenly distributes
-# hexadecimal ranges over the chosen number of bins (see output).
-# To initialize the bins we use one key, which TUF warns us about (see output).
-# However, we can assign separate keys to each bin, with the method used in
-# previous sections, accessing a bin by its hash prefix range name, e.g.:
-# "repository.targets('00-07').add_verification_key('public_00-07_key')".
->>> repository.targets('unclaimed').delegate_hashed_bins(
-... targets, [public_unclaimed_key], 32)
-Creating hashed bin delegations.
-1 total targets.
-32 hashed bins.
-256 total hash prefixes.
-Each bin ranges over 8 hash prefixes.
-Adding a verification key that has already been used. [repeated 32x]
-
-# The hashed bin roles can also be accessed by iterating the "delegations"
-# property of the delegating role, which we do here to load the signing key.
->>> for delegation in repository.targets('unclaimed').delegations:
-... delegation.load_signing_key(private_unclaimed_key)
-
-# Mark roles for metadata update (see #964, #958)
->>> repository.mark_dirty(['00-07', '08-0f', '10-17', '18-1f', '20-27', '28-2f',
-... '30-37', '38-3f', '40-47', '48-4f', '50-57', '58-5f', '60-67', '68-6f',
-... '70-77', '78-7f', '80-87', '88-8f', '90-97', '98-9f', 'a0-a7', 'a8-af',
-... 'b0-b7', 'b8-bf', 'c0-c7', 'c8-cf', 'd0-d7', 'd8-df', 'e0-e7', 'e8-ef',
-... 'f0-f7', 'f8-ff', 'snapshot', 'timestamp', 'unclaimed'])
-
->>> repository.writeall()
-
-```
-
-## How to Perform an Update ##
-
-The following [repository tool](../tuf/repository_tool.py) function creates a directory
-structure that a client downloading new software using TUF (via
-[tuf/client/updater.py](../tuf/client/updater.py)) expects. The `root.json` metadata file must exist, and
-also the directories that hold the metadata files downloaded from a repository.
-Software updaters integrating TUF may use this directory to store TUF updates
-saved on the client side.
-
-```python
->>> from tuf.repository_tool import *
->>> create_tuf_client_directory("repository/", "client/tufrepo/")
-```
-
-`create_tuf_client_directory()` moves metadata from `repository/metadata` to
-`client/` in this example. The repository in `repository/` may be the
-repository example created earlier in this document.
-
-## Test TUF Locally ##
-Run the local TUF repository server.
-```Bash
-$ cd "repository/"; python3 -m http.server 8001
-```
-
-We next retrieve targets from the TUF repository and save them to `client/`.
-The `client.py` script is available to download metadata and files from a
-specified repository. In a different command-line prompt, where `tuf` is
-installed . . .
-```Bash
-$ cd "client/"
-$ ls
-tufrepo/
-
-$ client.py --repo http://localhost:8001 file1.txt
-$ ls . tuftargets/
-.:
-tufrepo tuftargets
-
-tuftargets/:
-file1.txt
-```
diff --git a/docs/_config.yml b/docs/_config.yml
new file mode 100644
index 0000000000..586bd60b9a
--- /dev/null
+++ b/docs/_config.yml
@@ -0,0 +1,16 @@
+title: Python-TUF
+author: Python-TUF community
+#email: your-email@domain.com
+description: > # for footer and for search engines
+ Development blog for Python-TUF, a supply chain security framework
+ for secure content delivery and updates.
+
+github_username: theupdateframework
+
+show_excerpts: true # set to false to remove excerpts on the homepage
+
+header_pages: # make sure ordinary docs are not linked from blog header
+ - index.md
+
+theme: minima
+
diff --git a/docs/_posts/2022-02-21-release-1-0-0.md b/docs/_posts/2022-02-21-release-1-0-0.md
new file mode 100644
index 0000000000..9370597cc9
--- /dev/null
+++ b/docs/_posts/2022-02-21-release-1-0-0.md
@@ -0,0 +1,47 @@
+---
+title: "Python-TUF reaches version 1.0.0"
+author: Jussi Kukkonen and Lukas Pühringer
+---
+
+The Python-TUF community is proud to announce the release of Python-TUF 1.0.0.
+The release, which is available on [PyPI](https://pypi.org/project/tuf/) and
+[GitHub](https://github.com/theupdateframework/python-tuf/), introduces new
+stable and more ergonomic APIs.
+
+
+
+Python-TUF is the reference implementation of [The Update
+Framework](https://theupdateframework.io/) specification, an open source
+framework for securing content delivery and updates. It protects against
+various types of supply chain attacks and provides resilience to compromise.
+
+For the past 7 releases the project has introduced new designs and
+implementations, which have gradually formed two new stable APIs:
+- [`ngclient`](https://theupdateframework.readthedocs.io/en/latest/api/tuf.ngclient.html):
+ A client API that offers a robust internal design providing implementation
+ safety and flexibility to application developers.
+- [`Metadata API`](https://theupdateframework.readthedocs.io/en/latest/api/tuf.api.html):
+ A low-level interface for both consuming and creating TUF metadata. Metadata
+ API is a flexible and easy-to-use building block for any higher level tool or
+ library.
+
+Python-TUF 1.0.0 is the result of a comprehensive rewrite of the project,
+removing several hard to maintain modules and replacing them with safer and
+easier to use APIs:
+- The project was reduced from 4700 lines of hard to maintain code to 1400
+ lines of modern, maintainable code
+- The implementation details are now easier to reason about, which should
+ accelerate future improvements on the project
+- Metadata API provides a solid base to build other tools on top of – as proven
+ by the ngclient implementation and the [repository code
+ examples](https://github.com/theupdateframework/python-tuf/tree/develop/examples/repo_example)
+- Both new APIs are highly extensible and allow application developers to
+ include custom network stacks, file storage systems or public-key
+ cryptography algorithms, while providing easy-to-use default implementations
+
+With this foundation laid, Python-TUF developers are currently planning next
+steps. At the very least, you can expect improved repository side tooling, but
+we're also open to new ideas. Pop in to
+[#tuf](https://cloud-native.slack.com/archives/C8NMD3QJ3) on CNCF Slack or
+[Github issues](https://github.com/theupdateframework/python-tuf/issues/new)
+and let’s talk.
diff --git a/docs/_posts/2022-05-04-ngclient-design.md b/docs/_posts/2022-05-04-ngclient-design.md
new file mode 100644
index 0000000000..3c5623f662
--- /dev/null
+++ b/docs/_posts/2022-05-04-ngclient-design.md
@@ -0,0 +1,46 @@
+---
+title: "What's new in Python-TUF ngclient?"
+author: Jussi Kukkonen
+---
+
+We recently released a new TUF client implementation, `ngclient`, in Python-TUF. This post explains why we ended up doing that when a client already existed.
+
+# Simpler implementation, "correct" abstractions
+
+The legacy code had a few problems that could be summarized as non-optimal abstractions: Significant effort had been put to code re-use, but not enough attention had been paid to ensure the expectations and promises of that shared code were the same in all cases of re-use. This combined with Pythons type ambiguity, use of dictionaries as "blob"-like data structures and extensive use of global state meant touching the shared functions was a gamble: there was no way to be sure something wouldn't break.
+
+During the redesign, we really concentrated on finding abstractions that fit the processes we wanted to implement. It may be worth mentioning that in some cases this meant abstractions that have no equivalent in the TUF specification: some of the issues in the legacy implementation look like the result of mapping the TUF specifications [_Detailed client workflow_](https://theupdateframework.github.io/specification/latest/#detailed-client-workflow) directly into code.
+
+Here are the core abstractions we ended up with (number of lines of code in parenthesis to provide a bit of context, alongside links to sources and docs):
+* `Metadata` (900 SLOC, [docs](https://theupdateframework.readthedocs.io/en/latest/api/tuf.api.html)) handles everything related to individual pieces of TUF metadata: deserialization, signing, and verifying
+* `TrustedMetadataSet` (170 SLOC) is a collection of local, trusted metadata. It defines rules for how new metadata can be added into the set and ensures that metadata in it is always consistent and valid: As an example, if `TrustedMetadataSet` contains a targets metadata, the set guarantees that the targets metadata is signed by trusted keys and is part of a currently valid TUF snapshot
+* `Updater` (250 SLOC, [docs](https://theupdateframework.readthedocs.io/en/latest/api/tuf.ngclient.updater.html)) makes decisions on what metadata should be loaded into `TrustedMetadataSet`, both from the local cache and from a remote repository. While `TrustedMetadataSet` always raises an exception if a metadata is not valid, `Updater` considers the context and handles some failures as a part of the process and some as actual errors. `Updater` also handles persisting validated metadata and targets onto local storage and provides the user-facing API
+* `FetcherInterface` (100 SLOC, [docs](https://theupdateframework.readthedocs.io/en/latest/api/tuf.ngclient.fetcher.html)) is the abstract file downloader. By default, a Requests-based implementation is used but clients can use custom fetchers to tweak how downloads are done
+
+No design is perfect but so far we're quite happy with the above split. It has dramatically simplified the implementation: The code is subjectively easier to understand but also has significantly lower code branching counts for the same operations.
+
+# PyPI client requirements
+
+A year ago we added TUF support into pip as a prototype: this revealed some design issues that made the integration more difficult than it needed to be. As the potential pip integration is a goal for Python-TUF we wanted to smooth those rough edges.
+
+The main addition here was the `FetcherInterface`: it allows pip to keep doing all of the HTTP tweaks they have collected over the years.
+
+There were a bunch of smaller API tweaks as well: as an example, legacy Python-TUF had not anticipated downloading target files from a different host than it downloads metadata from. This is the design that PyPI uses with pypi.org and files.pythonhosted.org.
+
+# better API
+
+Since we knew we had to break API with the legacy implementation anyway, we also fixed multiple paper cuts in the API:
+ * Actual data structures are now exposed instead of dictionary "blobs"
+ * Configuration was removed or made non-global
+ * Exceptions are defined in a way that is useful to client applications
+
+# Plain old software engineering
+
+In addition to the big-ticket items, the rewrite allowed loads of improvements in project engineering practices. Some highlights:
+* Type annotations are now used extensively
+* Coding style is now consistent (and is now a common Python style)
+* There is a healthy culture of review in the project: bar for accepting changes is where it should be for a security project
+* Testing has so many improvements they probably need a blog post of their own
+
+These are not `ngclient` features as such but we expect they will show in the quality of products built with it.
+
diff --git a/docs/adr/0008-accept-unrecognised-fields.md b/docs/adr/0008-accept-unrecognised-fields.md
index 424ca0ff1f..7d4b4a8a0e 100644
--- a/docs/adr/0008-accept-unrecognised-fields.md
+++ b/docs/adr/0008-accept-unrecognised-fields.md
@@ -33,15 +33,18 @@ intermediate operations:
then, the checksum (the content) of the file must not be changed.
- Flexibility to add new fields in the spec without adding breaking changes.
+- Don't store unrecognized fields when it is not allowed by the specification.
## Considered Options
- Ignore and drop unrecognized fields.
- Ignore, but store unrecognized fields as an additional attribute.
+- Ignore, but store unrecognized fields as an additional attribute
+except for a couple of places where it's not allowed by the specification.
## Decision Outcome
-Chosen option: "Ignore, but store unrecognized fields as an additional
-attribute."
+Chosen option: "Ignore, but store unrecognized fields as an additional attribute
+except for a couple of places where it's not allowed by the specification."
The motivation for this decision is that the TUF specification already implies
that we should accept unrecognized fields for backward compatibility and easier
future extensibility.
@@ -49,3 +52,7 @@ future extensibility.
Additionally, it seems unacceptable to change a metadata file content just by
reading and writing it back.
+There are exceptions however for places in the metadata format when it is not
+allowed by specification: keys, roles, meta, hashes, and targets are
+actual dictionaries (vs JSON objects that most structures in the format are)
+where `unrecognized field` is not a meaningful concept.
diff --git a/docs/adr/0010-repository-library-design.md b/docs/adr/0010-repository-library-design.md
new file mode 100644
index 0000000000..0673063e89
--- /dev/null
+++ b/docs/adr/0010-repository-library-design.md
@@ -0,0 +1,136 @@
+# Repository library design built on top of Metadata API
+
+
+## Context and Problem Statement
+
+The Metadata API provides a modern Python API for accessing individual pieces
+of metadata. It does not provide any wider context help to someone looking to
+implement a TUF repository.
+
+The legacy python-tuf implementation offers tools for this but suffers from
+some issues (as do many other implementations):
+* There is a _very_ large amount of code to maintain: repo.py,
+ repository_tool.py and repository_lib.py alone are almost 7000 lines of code.
+* The "library like" parts of the implementation do not form a good coherent
+ API: methods routinely have a large number of arguments, code still depends
+ on globals in a major way and application (repo.py) still implements a lot of
+ "repository code" itself
+* The "library like" parts of the implementation make decisions that look like
+ application decisions. As an example, repository_tool loads _every_ metadata
+ file in the repository: this is fine for CLI that operates on a small
+ repository but is unlikely to be a good choice for a large scale server.
+
+
+## Decision Drivers
+
+* There is a consensus on removing the legacy code from python-tuf due to
+ maintainability issues
+* Metadata API makes modifying metadata far easier than legacy code base: this
+ makes significantly different designs possible
+* Not providing a "repository library" (and leaving implementers on their own)
+ may be a short term solution because of the previous point, but to make
+ adoption easier and to help adopters create safe implementations the project
+ would benefit from some shared repository code and a shared repository design
+* Maintainability of new library code must be a top concern
+* Allowing a wide range of repository implementations (from CLI tools to
+ minimal in-memory implementations to large scale application servers)
+ would be good: unfortunately these can have wildly differing requirements
+
+
+## Considered Options
+
+1. No repository packages
+2. repository_tool -like API
+3. Minimal repository abstraction
+
+
+## Decision Outcome
+
+Option 3: Minimal repository abstraction
+
+While option 1 might be used temporarily, the goal should be to implement a
+minimal repository abstraction as soon as possible: this should give the
+project a path forward where the maintenance burden is reasonable and results
+should be usable very soon. The python-tuf repository functionality can be
+later extended as ideas are experimented with in upstream projects and in
+python-tuf example code.
+
+The concept is still unproven but validating the design should be straight
+forward: decision could be re-evaluated in a few months if not in weeks.
+
+
+## Pros and Cons of the Options
+
+### No repository packages
+
+Metadata API makes editing the repository content vastly simpler. There are
+already repository implementations built with it[^1] so clearly a repository
+library is not an absolute requirement.
+
+Not providing repository packages in python-tuf does mean that external
+projects could experiment and create implementations without adding to the
+maintenance burden of python-tuf. This would be the easiest way to iterate many
+different designs and hopefully find good ones in the end.
+
+That said, there are some tricky parts of repository maintenance (e.g.
+initialization, snapshot update, hashed bin management) that would benefit from
+having a canonical implementation, both for easier adoption of python-tuf and
+as a reference for other implementations. Likewise, a well designed library
+could make some repeated actions (e.g. version bumps, expiry updates, signing)
+much easier to manage.
+
+### repository_tool -like API
+
+It won't be possible to support the repository_tool API as it is but a similar
+one would certainly be an option.
+
+This would likely be the easiest upgrade path for any repository_tool users out
+there. The implementation would not be a huge amount of work as Metadata API
+makes many things easier.
+
+However, repository_tool (and parts of repo.py) are not a great API. It is
+likely that a similar API suffers from some of the same issues: it might end up
+being a substantial amount of code that is only a good fit for one application.
+
+### Minimal repository abstraction
+
+python-tuf could define a tiny repository API that
+* provides carefully selected core functionality (like core snapshot update)
+* does not implement all repository actions itself, instead it makes it easy
+ for the application code to do them
+* leaves application details to specific implementations (examples of decisions
+ a library should not always decide: "are targets stored with the repo?",
+ "which versions of metadata are stored?", "when to load metadata?", "when to
+ unload metadata?", "when to bump metadata version?", "what is the new expiry
+ date?", "which targets versions should be part of new snapshot?")
+
+python-tuf could also provide one or more implementations of this abstraction
+as examples -- this could include a _repo.py_- or _repository_tool_-like
+implementation.
+
+This could be a compromise that allows:
+* low maintenance burden on python-tuf: initial library could be tiny
+* sharing the important, canonical parts of a TUF repository implementation
+* ergonomic repository modification, meaning most actions do not have to be in
+ the core code
+* very different repository implementations using the same core code and the
+ same abstract API
+
+The approach does have some downsides:
+* it's not a drop in replacement for repository_tool or repo.py
+* A prototype has been implemented (see Links below) but the concept is still
+ unproven
+
+More details in [Design document](../repository-library-design.md).
+
+## Links
+* [Design document for minimal repository abstraction](../repository-library-design.md)
+* [Prototype implementation of minimal repository abstraction](https://github.com/vmware-labs/repository-editor-for-tuf/)
+
+
+[^1]:
+ [RepositorySimulator](https://github.com/theupdateframework/python-tuf/blob/develop/tests/repository_simulator.py)
+ in python-tuf tests is an in-memory implementation, while
+ [repository-editor-for-tuf](https://github.com/vmware-labs/repository-editor-for-tuf)
+ is an external Command line repository maintenance tool.
+
diff --git a/docs/adr/index.md b/docs/adr/index.md
index 54a9be0861..46d9d84b5d 100644
--- a/docs/adr/index.md
+++ b/docs/adr/index.md
@@ -14,6 +14,7 @@ This log lists the architectural decisions for tuf.
- [ADR-0008](0008-accept-unrecognised-fields.md) - Accept metadata that includes unrecognized fields
- [ADR-0009](0009-what-is-a-reference-implementation.md) - Primary purpose of the reference implementation
+- [ADR-0010](0010-repository-library-design.md) - Repository library design built on top of Metadata API
diff --git a/docs/api/api-reference.rst b/docs/api/api-reference.rst
index 0c4b17bc05..d0805d8512 100644
--- a/docs/api/api-reference.rst
+++ b/docs/api/api-reference.rst
@@ -18,12 +18,10 @@ TUF provides multiple APIs:
is implemented on top of the Metadata API and can be used to implement
various TUF clients with relatively little effort.
-.. note:: Major API changes are unlikely but these APIs are not yet
- considered stable, and a higher-level repository operations API is not yet
- included.
+Code `examples `_
+are available for client implementation using ngclient and a
+basic repository using Metadata API.
- There is a legacy implementation in the source code (not covered by this
- documentation): it is in maintenance mode and receives no feature work.
.. toctree::
:maxdepth: 2
diff --git a/docs/api/tuf.api.metadata.metadata.rst b/docs/api/tuf.api.metadata.metadata.rst
new file mode 100644
index 0000000000..bac11a3133
--- /dev/null
+++ b/docs/api/tuf.api.metadata.metadata.rst
@@ -0,0 +1,4 @@
+Metadata class
+---------------------------------
+
+.. autoclass:: tuf.api.metadata.Metadata
diff --git a/docs/api/tuf.api.metadata.root.rst b/docs/api/tuf.api.metadata.root.rst
new file mode 100644
index 0000000000..ab6194bcc0
--- /dev/null
+++ b/docs/api/tuf.api.metadata.root.rst
@@ -0,0 +1,4 @@
+Root class
+---------------------------------
+
+.. autoclass:: tuf.api.metadata.Root
diff --git a/docs/api/tuf.api.metadata.rst b/docs/api/tuf.api.metadata.rst
deleted file mode 100644
index c4a58bb4e2..0000000000
--- a/docs/api/tuf.api.metadata.rst
+++ /dev/null
@@ -1,7 +0,0 @@
-Metadata
----------------------------------
-
-.. automodule:: tuf.api.metadata
- :members:
- :undoc-members:
- :show-inheritance:
diff --git a/docs/api/tuf.api.metadata.snapshot.rst b/docs/api/tuf.api.metadata.snapshot.rst
new file mode 100644
index 0000000000..1d1c202565
--- /dev/null
+++ b/docs/api/tuf.api.metadata.snapshot.rst
@@ -0,0 +1,4 @@
+Snapshot class
+---------------------------------
+
+.. autoclass:: tuf.api.metadata.Snapshot
diff --git a/docs/api/tuf.api.metadata.supporting.rst b/docs/api/tuf.api.metadata.supporting.rst
new file mode 100644
index 0000000000..906e70e95c
--- /dev/null
+++ b/docs/api/tuf.api.metadata.supporting.rst
@@ -0,0 +1,27 @@
+Supporting classes
+---------------------------------
+
+The Metadata API includes multiple classes that are used by the top-level
+ones (Root, Timestamp, Snapshot, Targets):
+
+.. autosummary::
+ :nosignatures:
+
+ tuf.api.metadata.DelegatedRole
+ tuf.api.metadata.Delegations
+ tuf.api.metadata.Key
+ tuf.api.metadata.MetaFile
+ tuf.api.metadata.Role
+ tuf.api.metadata.TargetFile
+
+.. autoclass:: tuf.api.metadata.DelegatedRole
+
+.. autoclass:: tuf.api.metadata.Delegations
+
+.. autoclass:: tuf.api.metadata.Key
+
+.. autoclass:: tuf.api.metadata.MetaFile
+
+.. autoclass:: tuf.api.metadata.Role
+
+.. autoclass:: tuf.api.metadata.TargetFile
diff --git a/docs/api/tuf.api.metadata.targets.rst b/docs/api/tuf.api.metadata.targets.rst
new file mode 100644
index 0000000000..a8af3ab326
--- /dev/null
+++ b/docs/api/tuf.api.metadata.targets.rst
@@ -0,0 +1,4 @@
+Targets class
+---------------------------------
+
+.. autoclass:: tuf.api.metadata.Targets
diff --git a/docs/api/tuf.api.metadata.timestamp.rst b/docs/api/tuf.api.metadata.timestamp.rst
new file mode 100644
index 0000000000..2d29d37dc4
--- /dev/null
+++ b/docs/api/tuf.api.metadata.timestamp.rst
@@ -0,0 +1,4 @@
+Timestamp class
+---------------------------------
+
+.. autoclass:: tuf.api.metadata.Timestamp
diff --git a/docs/api/tuf.api.rst b/docs/api/tuf.api.rst
index b93902c6bb..7d3126d23d 100644
--- a/docs/api/tuf.api.rst
+++ b/docs/api/tuf.api.rst
@@ -1,18 +1,20 @@
Metadata API
===============
-The low-level Metadata API contains two modules:
+.. toctree::
-* :doc:`tuf.api.metadata` contains the actual Metadata abstraction
- that higher level libraries and application code should use to interact
- with TUF metadata. This abstraction provides safe reading and writing to
- supported file formats and helper functions for accessing and modifying
- the metadata contents.
-* :doc:`tuf.api.serialization` covers serializing the metadata into
- specific wire formats (like json).
+ tuf.api.metadata.metadata
+ tuf.api.metadata.root
+ tuf.api.metadata.timestamp
+ tuf.api.metadata.snapshot
+ tuf.api.metadata.targets
.. toctree::
:hidden:
- tuf.api.metadata
+ tuf.api.metadata.supporting
tuf.api.serialization
+
+.. automodule:: tuf.api.metadata
+ :no-members:
+ :no-inherited-members:
diff --git a/docs/api/tuf.api.serialization.rst b/docs/api/tuf.api.serialization.rst
index 1603148dc6..610ab910d1 100644
--- a/docs/api/tuf.api.serialization.rst
+++ b/docs/api/tuf.api.serialization.rst
@@ -1,10 +1,10 @@
Serialization
=============================
+.. automodule:: tuf.api.serialization
+
JSON serialization
-----------------------------
.. automodule:: tuf.api.serialization.json
- :members:
- :undoc-members:
:show-inheritance:
diff --git a/docs/api/tuf.ngclient.config.rst b/docs/api/tuf.ngclient.config.rst
index 150df08273..b69d7cf484 100644
--- a/docs/api/tuf.ngclient.config.rst
+++ b/docs/api/tuf.ngclient.config.rst
@@ -2,6 +2,4 @@ Configuration
=============
.. automodule:: tuf.ngclient.config
- :members:
:undoc-members:
- :show-inheritance:
diff --git a/docs/api/tuf.ngclient.fetcher.rst b/docs/api/tuf.ngclient.fetcher.rst
index 1f689d4fd9..f37ea14f6f 100644
--- a/docs/api/tuf.ngclient.fetcher.rst
+++ b/docs/api/tuf.ngclient.fetcher.rst
@@ -2,6 +2,4 @@ Fetcher
============
.. automodule:: tuf.ngclient.fetcher
- :members:
:undoc-members:
- :show-inheritance:
diff --git a/docs/api/tuf.ngclient.updater.rst b/docs/api/tuf.ngclient.updater.rst
index 0fc46757c9..3f032c6b3b 100644
--- a/docs/api/tuf.ngclient.updater.rst
+++ b/docs/api/tuf.ngclient.updater.rst
@@ -2,5 +2,3 @@ Updater
=========
.. automodule:: tuf.ngclient.updater
- :members:
- :special-members: __init__
diff --git a/docs/conf.py b/docs/conf.py
index 2b0876200b..a80b6af618 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -30,27 +30,48 @@
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
-extensions = ['sphinx.ext.napoleon']
+extensions = [
+ 'sphinx.ext.napoleon', 'sphinx.ext.autosummary',
+ 'sphinx.ext.autosectionlabel'
+]
+
+autosectionlabel_prefix_document = True
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
-# List of patterns, relative to source directory, that match files and
-# directories to ignore when looking for source files.
-# This pattern also affects html_static_path and html_extra_path.
-exclude_patterns = ['GETTING_STARTED.rst', 'OVERVIEW.rst', 'TAP.rst']
-
# -- Options for HTML output -------------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
#
html_theme = 'sphinx_rtd_theme'
+html_theme_options = {
+ 'logo_only': True
+}
+html_logo = 'tuf-horizontal-white.png'
+html_favicon = 'tuf-icon-32.png'
+
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
#html_static_path = ['_static']
+# -- Autodoc configuration ---------------------------------------------------
+# https://www.sphinx-doc.org/en/master/usage/extensions/autodoc.html
+
autodoc_mock_imports = ['securesystemslib']
+# Tone down the "tuf.api.metadata." repetition
+add_module_names = False
+python_use_unqualified_type_names = True
+
+# Show typehints in argument doc lines, but not in signatures
+autodoc_typehints = "description"
+
+autodoc_default_options = {
+ 'members': True,
+ 'inherited-members': 'Exception', # excl. members inherited from 'Exception'
+ 'exclude-members': 'to_dict, from_dict'
+}
diff --git a/docs/images/all_logos.ai b/docs/images/all_logos.ai
deleted file mode 100644
index b2b7173be6..0000000000
--- a/docs/images/all_logos.ai
+++ /dev/null
@@ -1,5476 +0,0 @@
-%PDF-1.5
%
-1 0 obj
<>/OCGs[5 0 R 46 0 R 47 0 R 85 0 R 86 0 R]>>/Pages 3 0 R/Type/Catalog>>
endobj
2 0 obj
<>stream
-
-
-
-
- application/pdf
-
-
- Imprimir
-
-
-
-
- 2016-02-17T13:22:37-06:00
- 2016-02-17T13:22:37-06:00
- 2016-02-17T13:15:10-06:00
- Adobe Illustrator CS6 (Macintosh)
-
-
-
- 256
- 172
- JPEG
- /9j/4AAQSkZJRgABAgEASABIAAD/7QAsUGhvdG9zaG9wIDMuMAA4QklNA+0AAAAAABAASAAAAAEA
AQBIAAAAAQAB/+4ADkFkb2JlAGTAAAAAAf/bAIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoK
DBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxscHx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8f
Hx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgArAEAAwER
AAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAAAAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAA
AQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIGAnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPB
UtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6OzNhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE
1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZ
qbnJ2en5KjpKWmp6ipqqusra6voRAAICAQIDBQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEy
obHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LCB3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp
0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaWprbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo
+DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq+v/aAAwDAQACEQMRAD8A9U4q7FXYq7FUJqWs6Rpc
Qm1O+t7GI1pJcypCpp13cqNsVShPzH/L12CJ5o0hnY0VRf2xJPsBJjSp9b3FvcwpPbypNDIKpLGw
ZWHiGFQcVVMVdirsVUb5mSyuHU8WWNypHUEKcVa+ow/zS/8AI6X/AJqxV31GH+aX/kdL/wA1Yq76
jD/NL/yOl/5qxV31GH+aX/kdL/zViqUan5h8m6VN6Oqa5a2E3++rrUBC2/8AkvKpxVSsfNfkTULh
baw8xWV3cPssMGpLI5PsqSk4qnn1GH+aX/kdL/zVirvqMP8ANL/yOl/5qxV31GH+aX/kdL/zVirv
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
xV2KuxV2KuxV2KuxV2KuxV2KuxV2Kv8A/9k=
-
-
-
-
-
- uuid:d582b029-3a1b-f149-bd97-74bb63cc2b56
- xmp.did:06801174072068118083D5E0C0CE63C1
- uuid:5D20892493BFDB11914A8590D31508C8
- proof:pdf
-
- uuid:3e286528-41ee-0646-82dc-fdd40c176a77
- xmp.did:0980117407206811822A897E387FE54C
- uuid:5D20892493BFDB11914A8590D31508C8
- proof:pdf
-
-
-
-
- saved
- xmp.iid:06801174072068118083D5E0C0CE63C1
- 2016-02-17T13:15:10-06:00
- Adobe Illustrator CS6 (Macintosh)
- /
-
-
-
-
-
- Document
- Print
-
-
- False
- False
- 1
-
- 15.000118
- 15.000118
- Centimeters
-
-
-
-
- HelveticaNeue-Medium
- Helvetica Neue
- Medium
- TrueType
- 10.0d40e1
- False
- HelveticaNeue.dfont
-
-
-
-
-
- Cyan
- Magenta
- Yellow
- Black
- PANTONE Process Blue C
-
-
-
-
-
- Grupo de muestras por defecto
- 0
-
-
-
- Blanco
- CMYK
- PROCESS
- 0.000000
- 0.000000
- 0.000000
- 0.000000
-
-
- Negro
- CMYK
- PROCESS
- 0.000000
- 0.000000
- 0.000000
- 100.000000
-
-
- Rojo CMYK
- CMYK
- PROCESS
- 0.000000
- 100.000000
- 100.000000
- 0.000000
-
-
- Amarillo CMYK
- CMYK
- PROCESS
- 0.000000
- 0.000000
- 100.000000
- 0.000000
-
-
- Verde CMYK
- CMYK
- PROCESS
- 100.000000
- 0.000000
- 100.000000
- 0.000000
-
-
- Cian CMYK
- CMYK
- PROCESS
- 100.000000
- 0.000000
- 0.000000
- 0.000000
-
-
- Azul CMYK
- CMYK
- PROCESS
- 100.000000
- 100.000000
- 0.000000
- 0.000000
-
-
- Magenta CMYK
- CMYK
- PROCESS
- 0.000000
- 100.000000
- 0.000000
- 0.000000
-
-
- C=15 M=100 Y=90 K=10
- CMYK
- PROCESS
- 14.999998
- 100.000000
- 90.000000
- 10.000002
-
-
- C=0 M=90 Y=85 K=0
- CMYK
- PROCESS
- 0.000000
- 90.000000
- 85.000000
- 0.000000
-
-
- C=0 M=80 Y=95 K=0
- CMYK
- PROCESS
- 0.000000
- 80.000000
- 95.000000
- 0.000000
-
-
- C=0 M=50 Y=100 K=0
- CMYK
- PROCESS
- 0.000000
- 50.000000
- 100.000000
- 0.000000
-
-
- C=0 M=35 Y=85 K=0
- CMYK
- PROCESS
- 0.000000
- 35.000004
- 85.000000
- 0.000000
-
-
- C=5 M=0 Y=90 K=0
- CMYK
- PROCESS
- 5.000001
- 0.000000
- 90.000000
- 0.000000
-
-
- C=20 M=0 Y=100 K=0
- CMYK
- PROCESS
- 19.999998
- 0.000000
- 100.000000
- 0.000000
-
-
- C=50 M=0 Y=100 K=0
- CMYK
- PROCESS
- 50.000000
- 0.000000
- 100.000000
- 0.000000
-
-
- C=75 M=0 Y=100 K=0
- CMYK
- PROCESS
- 75.000000
- 0.000000
- 100.000000
- 0.000000
-
-
- C=85 M=10 Y=100 K=10
- CMYK
- PROCESS
- 85.000000
- 10.000002
- 100.000000
- 10.000002
-
-
- C=90 M=30 Y=95 K=30
- CMYK
- PROCESS
- 90.000000
- 30.000002
- 95.000000
- 30.000002
-
-
- C=75 M=0 Y=75 K=0
- CMYK
- PROCESS
- 75.000000
- 0.000000
- 75.000000
- 0.000000
-
-
- C=80 M=10 Y=45 K=0
- CMYK
- PROCESS
- 80.000000
- 10.000002
- 45.000000
- 0.000000
-
-
- C=70 M=15 Y=0 K=0
- CMYK
- PROCESS
- 70.000000
- 14.999998
- 0.000000
- 0.000000
-
-
- C=85 M=50 Y=0 K=0
- CMYK
- PROCESS
- 85.000000
- 50.000000
- 0.000000
- 0.000000
-
-
- C=100 M=95 Y=5 K=0
- CMYK
- PROCESS
- 100.000000
- 95.000000
- 5.000001
- 0.000000
-
-
- C=100 M=100 Y=25 K=25
- CMYK
- PROCESS
- 100.000000
- 100.000000
- 25.000000
- 25.000000
-
-
- C=75 M=100 Y=0 K=0
- CMYK
- PROCESS
- 75.000000
- 100.000000
- 0.000000
- 0.000000
-
-
- C=50 M=100 Y=0 K=0
- CMYK
- PROCESS
- 50.000000
- 100.000000
- 0.000000
- 0.000000
-
-
- C=35 M=100 Y=35 K=10
- CMYK
- PROCESS
- 35.000004
- 100.000000
- 35.000004
- 10.000002
-
-
- C=10 M=100 Y=50 K=0
- CMYK
- PROCESS
- 10.000002
- 100.000000
- 50.000000
- 0.000000
-
-
- C=0 M=95 Y=20 K=0
- CMYK
- PROCESS
- 0.000000
- 95.000000
- 19.999998
- 0.000000
-
-
- C=25 M=25 Y=40 K=0
- CMYK
- PROCESS
- 25.000000
- 25.000000
- 39.999996
- 0.000000
-
-
- C=40 M=45 Y=50 K=5
- CMYK
- PROCESS
- 39.999996
- 45.000000
- 50.000000
- 5.000001
-
-
- C=50 M=50 Y=60 K=25
- CMYK
- PROCESS
- 50.000000
- 50.000000
- 60.000004
- 25.000000
-
-
- C=55 M=60 Y=65 K=40
- CMYK
- PROCESS
- 55.000000
- 60.000004
- 65.000000
- 39.999996
-
-
- C=25 M=40 Y=65 K=0
- CMYK
- PROCESS
- 25.000000
- 39.999996
- 65.000000
- 0.000000
-
-
- C=30 M=50 Y=75 K=10
- CMYK
- PROCESS
- 30.000002
- 50.000000
- 75.000000
- 10.000002
-
-
- C=35 M=60 Y=80 K=25
- CMYK
- PROCESS
- 35.000004
- 60.000004
- 80.000000
- 25.000000
-
-
- C=40 M=65 Y=90 K=35
- CMYK
- PROCESS
- 39.999996
- 65.000000
- 90.000000
- 35.000004
-
-
- C=40 M=70 Y=100 K=50
- CMYK
- PROCESS
- 39.999996
- 70.000000
- 100.000000
- 50.000000
-
-
- C=50 M=70 Y=80 K=70
- CMYK
- PROCESS
- 50.000000
- 70.000000
- 80.000000
- 70.000000
-
-
- PANTONE Process Blue C
- SPOT
- 100.000000
- LAB
- 47.451004
- -33
- -53
-
-
-
-
-
- Grises
- 1
-
-
-
- C=0 M=0 Y=0 K=100
- CMYK
- PROCESS
- 0.000000
- 0.000000
- 0.000000
- 100.000000
-
-
- C=0 M=0 Y=0 K=90
- CMYK
- PROCESS
- 0.000000
- 0.000000
- 0.000000
- 89.999405
-
-
- C=0 M=0 Y=0 K=80
- CMYK
- PROCESS
- 0.000000
- 0.000000
- 0.000000
- 79.998795
-
-
- C=0 M=0 Y=0 K=70
- CMYK
- PROCESS
- 0.000000
- 0.000000
- 0.000000
- 69.999702
-
-
- C=0 M=0 Y=0 K=60
- CMYK
- PROCESS
- 0.000000
- 0.000000
- 0.000000
- 59.999104
-
-
- C=0 M=0 Y=0 K=50
- CMYK
- PROCESS
- 0.000000
- 0.000000
- 0.000000
- 50.000000
-
-
- C=0 M=0 Y=0 K=40
- CMYK
- PROCESS
- 0.000000
- 0.000000
- 0.000000
- 39.999401
-
-
- C=0 M=0 Y=0 K=30
- CMYK
- PROCESS
- 0.000000
- 0.000000
- 0.000000
- 29.998802
-
-
- C=0 M=0 Y=0 K=20
- CMYK
- PROCESS
- 0.000000
- 0.000000
- 0.000000
- 19.999701
-
-
- C=0 M=0 Y=0 K=10
- CMYK
- PROCESS
- 0.000000
- 0.000000
- 0.000000
- 9.999103
-
-
- C=0 M=0 Y=0 K=5
- CMYK
- PROCESS
- 0.000000
- 0.000000
- 0.000000
- 4.998803
-
-
-
-
-
- Brillantes
- 1
-
-
-
- C=0 M=100 Y=100 K=0
- CMYK
- PROCESS
- 0.000000
- 100.000000
- 100.000000
- 0.000000
-
-
- C=0 M=75 Y=100 K=0
- CMYK
- PROCESS
- 0.000000
- 75.000000
- 100.000000
- 0.000000
-
-
- C=0 M=10 Y=95 K=0
- CMYK
- PROCESS
- 0.000000
- 10.000002
- 95.000000
- 0.000000
-
-
- C=85 M=10 Y=100 K=0
- CMYK
- PROCESS
- 85.000000
- 10.000002
- 100.000000
- 0.000000
-
-
- C=100 M=90 Y=0 K=0
- CMYK
- PROCESS
- 100.000000
- 90.000000
- 0.000000
- 0.000000
-
-
- C=60 M=90 Y=0 K=0
- CMYK
- PROCESS
- 60.000004
- 90.000000
- 0.003099
- 0.003099
-
-
-
-
-
-
-
-
- Adobe PDF library 10.01
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
endstream
endobj
3 0 obj
<>
endobj
7 0 obj
<>/Resources<>/ExtGState<>/Font<>/ProcSet[/PDF/Text]/Properties<>>>/TrimBox[0.0 0.0 425.2 425.2]/Type/Page>>
endobj
8 0 obj
<>/Resources<>/ExtGState<>/Font<>/ProcSet[/PDF/Text]/Properties<>>>/TrimBox[0.0 0.0 425.2 425.2]/Type/Page>>
endobj
9 0 obj
<>/Resources<>/ExtGState<>/Properties<>>>/TrimBox[0.0 0.0 425.2 425.2]/Type/Page>>
endobj
10 0 obj
<>/Resources<>/ExtGState<>/Properties<>>>/TrimBox[0.0 0.0 425.2 425.2]/Type/Page>>
endobj
11 0 obj
<>/Resources<>/ExtGState<>/Font<>/ProcSet[/PDF/Text]/Properties<>>>/TrimBox[0.0 0.0 674.865 425.2]/Type/Page>>
endobj
97 0 obj
<>stream
-HW]5߯/'Nl;*Tk4E0A9Ǿқ:7Ncع6ݼ-7i{?7$q+Ik5FO?~Lo7ߗtJ^iC&fK{^ac$rmm%iGMw6~$ZSͥ(ޒ:v\zY:l3\j]m
-[MR,ϲ=V,aEj+"+1wdM\ԥ~Vxo*
-],sX{WJS--
-
-o(ی~m`-nX+u5,aaklpIgRO
g?4kʕ[9)d+\UOI(bUa;wT6v2Ԯ%
$L8 qwe_
-SHnEZEEBIź.L:-VSY:4*sSrC:HAZ5F~B*1%HJpe +l3:sx9$@=>[$֘[cM@1E `Om pn1Vcbw"#[GFO!t3,+G\--Cj#'bZB
5VJ؊U;kT*jhK;:FtxapUÑX43X~\y0i"Cn,5R=QAI++[X&)H\?)-DcvՋ
-:"n/ȗ d+( 3ˬ'u/6cA-P3^$B@ԚU\邓߹3
-YdO- *ANBkQ k2ETi C*"u|er1gkHpMa;
-$9}"Y|qIȓ=@p crG2bUj(
?p$9L?a zY6o~qbdJ|yEGmo4\cF&CG0R,V1d/oH0YbԙVbHJ4${;6"GuW^:nt{M!`t0B>M<LL'SHB5b$)UaEPYb&{ >G1J27wJC!)r)Zl&E16Opx9 Wz#4 xeP*!gD&_ȨP: diyvï$m\x4 :.Ɏ9Ez|lDK4B3%@g }~eqj;VP oHfs0FOcv+fC<aEh&!x8s5~.qvS**c?h Cۨü)ژ[bZH량z$qg
-a.^=vov8M"jr.7%[8>j$/[!yh88@y#~.898+sv?+QGCe!cs|n<1[Se7t5Ӑ`e=
+iU3r'<RqwK udh[Tqe_ AZUb(-xgXòxyᝅI|5O[WOѬ]d[4oP|>;_(Ws|n%sh*_2ڞ4C}a_As!\-RK
-dl,#^w<1q߆O~:0%.;RDm鐊70LIDO ^WݼLahw S#pn`)s