From 5c3cb24c38bf28dfb54a14430917d0eb9e510230 Mon Sep 17 00:00:00 2001 From: Jussi Kukkonen Date: Tue, 18 Jul 2023 09:43:47 +0300 Subject: [PATCH 1/7] Big rename playground -> tuf-on-ci * variable and class names * directories * packages/modules * the signer configuration file * custom metadata field names This is very incompatible with any existing repositories. It may be possible to create a playground2tuf-on-ci import script but this is not included here. Also remove the downloader client code for now -- We should have an example but A) it should be clearly an example, not part of the code release B) the old code had a lot of unrelated things --- README.md | 78 +++++++++---------- actions/offline-version-bump/action.yml | 2 +- actions/online-version-bump/action.yml | 2 +- actions/signing-event/action.yml | 4 +- actions/snapshot/action.yml | 2 +- repo/README.md | 14 ++-- repo/playground/__init__.py | 5 -- repo/pyproject.toml | 12 +-- ...und_reposiory.py => test_ci_repository.py} | 16 ++-- repo/test/test_repo1/root.json | 12 +-- repo/test/test_repo1/targets.json | 4 +- repo/test/test_repo2/root.json | 14 ++-- repo/tuf_on_ci/__init__.py | 5 ++ .../_repository.py} | 16 ++-- .../bump_expiring.py | 8 +- repo/{playground => tuf_on_ci}/snapshot.py | 8 +- repo/{playground => tuf_on_ci}/status.py | 18 ++--- signer/README.md | 44 +---------- signer/create-config-file.sh | 6 +- signer/playground_sign/__init__.py | 4 - signer/pyproject.toml | 8 +- signer/tuf_on_ci_sign/__init__.py | 4 + .../_common.py | 2 +- .../_signer_repository.py | 74 +++++++++--------- .../delegate.py | 22 +++--- .../sign.py | 10 +-- tests/README.md | 18 ++--- tests/e2e.sh | 62 +++++++-------- tests/expected/basic/metadata/1.root.json | 16 ++-- tests/expected/basic/metadata/1.targets.json | 4 +- .../multi-user-signing/metadata/1.root.json | 18 ++--- .../metadata/1.targets.json | 4 +- .../multi-user-signing/metadata/2.root.json | 18 ++--- .../online-version-bump/metadata/1.root.json | 16 ++-- .../metadata/1.targets.json | 4 +- .../root-key-rotation/metadata/1.root.json | 16 ++-- .../root-key-rotation/metadata/1.targets.json | 4 +- .../root-key-rotation/metadata/2.root.json | 18 ++--- .../target-file-changes/metadata/1.root.json | 18 ++--- .../metadata/1.targets.json | 4 +- .../metadata/3.targets.json | 4 +- 41 files changed, 287 insertions(+), 331 deletions(-) delete mode 100644 repo/playground/__init__.py rename repo/test/{test_playground_reposiory.py => test_ci_repository.py} (71%) create mode 100644 repo/tuf_on_ci/__init__.py rename repo/{playground/_playground_repository.py => tuf_on_ci/_repository.py} (96%) rename repo/{playground => tuf_on_ci}/bump_expiring.py (95%) rename repo/{playground => tuf_on_ci}/snapshot.py (87%) rename repo/{playground => tuf_on_ci}/status.py (92%) delete mode 100644 signer/playground_sign/__init__.py create mode 100644 signer/tuf_on_ci_sign/__init__.py rename signer/{playground_sign => tuf_on_ci_sign}/_common.py (98%) rename signer/{playground_sign => tuf_on_ci_sign}/_signer_repository.py (91%) rename signer/{playground_sign => tuf_on_ci_sign}/delegate.py (94%) rename signer/{playground_sign => tuf_on_ci_sign}/sign.py (90%) diff --git a/README.md b/README.md index 9b3f298e..94257cd3 100644 --- a/README.md +++ b/README.md @@ -1,21 +1,20 @@ -# CI-based TUF implementation +# TUF-on-CI: A TUF repository and signing tool implementation This is a TUF implementation that operates on Continuous Integration platform. Supported features include: * Threshold signing with offline keys, guided by CI * Automated online signing -* Streamlined, opinionated user experience +* Polished signer and maintainer experience * No custom code required -The optimal use case (at least to begin with) is TUF repositories with a low -to moderate frequency of change, both for target files and keys. +The optimal use case is TUF repositories with a low to moderate frequency of change, both for target files and keys. -This is a Work-In-Progress: any code should be seen as experimental for now. See [example](https://github.com/jku/test-repo-for-playground/) for an instance running repository-playground. +This is a Work-In-Progress and no stable releases have been made yet. See +[example](https://github.com/jku/test-repo-for-playground/) for an instance running TUF-on-CI. ## Documentation * [Design document](https://docs.google.com/document/d/140jiFHGc3wwEmNaJmUdgkNeNK4i4CC-lm5-eVQYXiL0/edit?resourcekey=0-CLZhA-H2jtd3WQD-lBLsqQ) -* [Implementation notes](IMPLEMENTATION-NOTES.md) ## Setup @@ -31,7 +30,7 @@ Current signing requirements are: ```shell yubico-piv-tool -a generate -a verify-pin -a selfsign -a import-certificate -s 9c -k -A ECCP256 -S '/CN=piv_auth/OU=example/O=example.com/' ``` -1. Install a PKCS#11 module. Playground has been tested with the Yubico implementation, +1. Install a PKCS#11 module. TUF-on-CI has been tested with the Yubico implementation, Debian users can install it with ```shell $ apt install ykcs11 @@ -40,14 +39,14 @@ Current signing requirements are: ```shell $ brew install yubico-piv-tool ``` -1. install playground-sign +1. install tuf-on-ci-sign ```shell - $ pip install git+https://git@github.com/jku/repository-playground#subdirectory=playground/signer + $ pip install git+https://git@github.com/theupdateframework/tuf-on-ci#subdirectory=signer ``` ### Configure signer -Whenever you run signing tools, you need a configuration file `.playground-sign.ini` in the root dir of the git repository that contains the metadata: +Whenever you run signing tools, you need a configuration file `.tuf-on-ci-sign.ini` in the root dir of the git repository that contains the metadata: ``` [settings] # Path to PKCS#11 module @@ -61,12 +60,12 @@ Whenever you run signing tools, you need a configuration file `.playground-sign. ``` A [provided -script](https://github.com/jku/repository-playground/blob/main/playground/signer/create-config-file.sh) +script](https://github.com/theupdateframework/tuf-on-ci/blob/main/signer/create-config-file.sh) exists that can generate one. -### Setup a new Playground repository +### Setup a new TUF-on-CI repository -1. Fork the [template](https://github.com/jku/playground-template). +1. Fork the [template](https://github.com/theupdateframework/tuf-on-ci-template). 1. To enable repository publishing, set _Settings->Pages->Source_ to `Github Actions` #### Using a KMS @@ -102,7 +101,7 @@ If you intend to use a Cloud KMS for online signing (instead of the default tenant-id: ${{ secrets.AZURE_TENANT_ID }} subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} - id: snapshot - uses: jku/repository-playground/playground/actions/snapshot@main + uses: theupdateframework/tuf-on-ci/actions/snapshot@main ... deploy: @@ -111,7 +110,7 @@ If you intend to use a Cloud KMS for online signing (instead of the default environment for accessing the cloud KMS. 1. For GCP use [gcloud](https://cloud.google.com/sdk/docs/install) and authenticate in the environment where you plan to run - playground-delegate tool (you will need + tuf-on-ci-delegate tool (you will need _roles/cloudkms.publicKeyViewer_ permission) 1. For Azure use [az @@ -121,7 +120,7 @@ If you intend to use a Cloud KMS for online signing (instead of the default ## Operation -Both tools (`playground-delegate` and `playground-sign`) take one required argument, the +Both tools (`tuf-on-ci-delegate` and `tuf-on-ci-sign`) take one required argument, the signing event name (it is used as a git branch name). Typically the signing event exists and you know its name but in some cases (delegation, target modification) you can choose a name for a new signing event: anything starting with "sign/" is fine. @@ -130,7 +129,7 @@ The tools will fetch the current signing event content from a matching branch in _pull-remote_. After signing or delegation changes, the tools will push the changes to matching branch on _push-remote_. -Notes on remotes configured in `.playground-sign.ini`: +Notes on remotes configured in `.tuf-on-ci-sign.ini`: * _pull-remote_ should always be the actual TUF repository * If you have permissions to push to the TUF repository, you can set _push-remote_ to same value * Otherwise you can set _push-remote_ to your fork: in this case after running the tools, you @@ -140,7 +139,7 @@ Notes on remotes configured in `.playground-sign.ini`: 1. Run delegate tool to create initial metadata ```shell - $ playground-delegate + $ tuf-on-ci-delegate ``` 1. Respond to the prompts @@ -148,7 +147,7 @@ Notes on remotes configured in `.playground-sign.ini`: 1. Run delegate tool when you want to modify a roles delegation ```shell - $ playground-delegate + $ tuf-on-ci-delegate ``` 1. Respond to the prompts @@ -173,7 +172,7 @@ Signing should be done when the signing event (GitHub issue) asks for it: 1. Run signer tool in the signing event branch ```shell - $ playground-sign + $ tuf-on-ci-sign ``` 1. Respond to the prompts @@ -181,12 +180,12 @@ Signing should be done when the signing event (GitHub issue) asks for it: ### Repository template -Status: Implemented in the playground-template project. Workflows include +Status: Implemented in the tuf-on-ci-template project. Workflows include * signing-event * snapshot * version-bumps -See [here](https://github.com/jku/playground-template). +See [here](https://github.com/theupdateframework/tuf-on-ci-template). ### Repository actions @@ -208,8 +207,8 @@ See [repo/](repo/), See [actions/](actions/) ### signing tool Status: -* playground-delegate mostly implemented -* playground-sign mostly implemented, although output is a work in progress +* tuf-on-ci-delegate mostly implemented +* tuf-on-ci-sign mostly implemented, although output is a work in progress See [signer/](signer/) @@ -224,15 +223,15 @@ TODO: Client is currently not up-to-date WRT repository implementation. ### Initialize a new repository -1. Instantiate [template](https://github.com/jku/playground-template) +1. Instantiate [template](https://github.com/theupdateframework/tuf-on-ci-template) 1. Enable publishing to GitHub Pages: `Settings > Pages > Source: GitHub Actions` 1. Install the signer tools as described - [here](https://github.com/jku/repository-playground/blob/main/playground/signer/README.md) + [here](https://github.com/theupdateframework/tuf-on-ci/blob/main/signer/README.md) on your local computer 1. Clone the instantiated repository -1. Prepate the configuration file (`.playground-sign.ini`) -1. Run `playground-delegate ` +1. Prepate the configuration file (`.tuf-on-ci-sign.ini`) +1. Run `tuf-on-ci-delegate ` 1. Follow the instructions to configure the root, after this is done a new branch with `` is pushed to `origin` 1. Once the new metadata is pushed, reivew the change and merge into @@ -242,10 +241,10 @@ TODO: Client is currently not up-to-date WRT repository implementation. ### Adding a new signer -Adding a new root signer is done via the `playground-sign` command. +Adding a new root signer is done via the `tuf-on-ci-sign` command. ```shell -$ playground-delegate sign/add-fakeuser-2 +$ tuf-on-ci-delegate sign/add-fakeuser-2 Remote branch not found: branching off from main Enter name of role to modify: root @@ -268,18 +267,15 @@ which in the above example is `sign/add-fakueuser-2`. By naming the event with `sign/` automation will pick up this branch and run the [signing -automation](https://github.com/jku/playground-template/blob/main/.github/workflows/signing-event.yml) +automation](https://github.com/theupdateframework/tuf-on-ci-template/blob/main/.github/workflows/signing-event.yml) that creates issues with the current signing state and tags each signer on what's expected to do. This always provides a clear state of the situation. To accept the invitation and become a signer, the invitee runs -`playground-sign ` and provides information on what key to +`tuf-on-ci-sign ` and provides information on what key to use. After completion the updated metadata will be pushed to -`origin`. Currently the invitee must execute `playground-sign -` twice, the first run will only add the key to the -metadata, the second invocation will actually sign the metadata. This -will be changed in a future release. +`origin`. When adding or changing root signer, remember that a quorum of _current_ key-holders **must** sign the updated root metadata for it @@ -308,19 +304,19 @@ The branch can now be pushed to `origin` and an issue will be created that tracks the changes and the required signaturesby the correct key holders. -Run the `playground-sign ` command to sign the metadata +Run the `tuf-on-ci-sign ` command to sign the metadata and push the branch to `origin`, once pushed, and signed by all key holders create a PR and merge. The snapshot workflow will then run an publish the repository for consumption. ## Debug tools -The same tool (`playground-status`) that runs during the automation +The same tool (`tuf-on-ci-status`) that runs during the automation can be run locally too to inspect the current status of a branch (signing event). To install the repository tools, run pip install from the -`playground/repo` directory where the +`repo/` directory where the [pyproject.toml](repo/pyproject.toml) file exists: ```shell @@ -331,11 +327,11 @@ As an example, this would be the output when an open invitation exists for a new user to become a root key holder: ```shell -$ playground-status +$ tuf-on-ci-status ### Current signing event state Event [sign/add-fakeuser-1](../compare/sign/add-fakeuser-1) #### :x: root root delegations have open invites (@-fakeuser-2). -Invitees can accept the invitations by running `playground-sign add-fakeuser-2` +Invitees can accept the invitations by running `tuf-on-ci-sign add-fakeuser-2` $ ``` diff --git a/actions/offline-version-bump/action.yml b/actions/offline-version-bump/action.yml index 2a014f71..c8db6429 100644 --- a/actions/offline-version-bump/action.yml +++ b/actions/offline-version-bump/action.yml @@ -18,7 +18,7 @@ runs: - name: Bump offline role versions id: offline-bump run: | - events=$(playground-bump-offline --push) + events=$(tuf-on-ci-bump-offline --push) echo events="$events" echo events="$events" >> $GITHUB_OUTPUT shell: bash diff --git a/actions/online-version-bump/action.yml b/actions/online-version-bump/action.yml index 46f08654..a8438535 100644 --- a/actions/online-version-bump/action.yml +++ b/actions/online-version-bump/action.yml @@ -49,7 +49,7 @@ runs: run: | mkdir publish cd repository - if playground-bump-online --push --metadata ${{ inputs.metadata_path}} --targets ${{ inputs.targets_path}} ../publish; then + if tuf-on-ci-bump-online --push --metadata ${{ inputs.metadata_path}} --targets ${{ inputs.targets_path}} ../publish; then find "../publish" -type f | xargs ls -lh echo "generated=true" >> $GITHUB_OUTPUT else diff --git a/actions/signing-event/action.yml b/actions/signing-event/action.yml index ef6c05c6..419d31d7 100644 --- a/actions/signing-event/action.yml +++ b/actions/signing-event/action.yml @@ -1,5 +1,5 @@ name: 'Signing event' -description: 'TUF signing event management for Repository Playground' +description: 'TUF-on-CI Signing event management' runs: using: "composite" steps: @@ -16,7 +16,7 @@ runs: - id: status run: | - if playground-status >> status-output; then + if tuf-on-ci-status >> status-output; then echo "status=success" >> $GITHUB_OUTPUT else echo "status=failure" >> $GITHUB_OUTPUT diff --git a/actions/snapshot/action.yml b/actions/snapshot/action.yml index cb66360d..17ce929c 100644 --- a/actions/snapshot/action.yml +++ b/actions/snapshot/action.yml @@ -49,7 +49,7 @@ runs: run: | mkdir publish cd repository - playground-snapshot --push --metadata ${{ inputs.metadata_path}} --targets ${{ inputs.targets_path}} ../publish + tuf-on-ci-snapshot --push --metadata ${{ inputs.metadata_path}} --targets ${{ inputs.targets_path}} ../publish find "../publish" -type f | xargs ls -lh shell: bash diff --git a/repo/README.md b/repo/README.md index 7ca02b76..f40042c8 100644 --- a/repo/README.md +++ b/repo/README.md @@ -1,4 +1,6 @@ -## CI tools for Repository Playground +## CI tools for TUF-on-CI + +These commands are used by the GitHub actions in the [actions directory](../actions/). There should be no reason to install or use them elsewhere (except for debugging and testing). ### Installation @@ -6,12 +8,10 @@ Development install: `pip install -e .` ### Usage -These commands are used by the GitHub actions in the [actions directory](../actions/) . - -`playground-status`: Prints status of the signing event (aka current branch) based on the changes done in the signing event (compared to the starting point of the event) and invites in .signing-event-state file +`tuf-on-ci-status`: Prints status of the signing event (aka current branch) based on the changes done in the signing event (compared to the starting point of the event) and invites in .signing-event-state file -`playground-snapshot [--push] []`: Updates snapshot & timestamp based on current repository content. If `--push` is used, the changes are pushed to main branch. If PUBLISH_DIR is given, will create a publishable repository version in PUBLISH_DIR. +`tuf-on-ci-snapshot [--push] []`: Updates snapshot & timestamp based on current repository content. If `--push` is used, the changes are pushed to main branch. If PUBLISH_DIR is given, will create a publishable repository version in PUBLISH_DIR. -`playground-online [--push] []`: Bumps the online roles version if they are about to expire, and signs the changes. If `--push` is used, the changes are pushed to main branch. If PUBLISH_DIR is given, will create a publishable repository version in PUBLISH_DIR. +`tuf-on-ci-bump-online [--push] []`: Bumps the online roles version if they are about to expire, and signs the changes. If `--push` is used, the changes are pushed to main branch. If PUBLISH_DIR is given, will create a publishable repository version in PUBLISH_DIR. -`playground-offline [--push]`: Bumps the roles versions if they are about to expire. If `--push` is used, the changes are pushed to signing event branches (branch per role): the signing event names are printed on stdout. +`tuf-on-ci-bump-offline [--push]`: Bumps the roles versions if they are about to expire. If `--push` is used, the changes are pushed to signing event branches (branch per role): the signing event names are printed on stdout. diff --git a/repo/playground/__init__.py b/repo/playground/__init__.py deleted file mode 100644 index 96ff3d03..00000000 --- a/repo/playground/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -from playground.bump_expiring import bump_offline, bump_online -from playground.snapshot import snapshot -from playground.status import status - -__all__ = ["status", "snapshot", "bump_online", "bump_offline"] diff --git a/repo/pyproject.toml b/repo/pyproject.toml index 35bd948f..363f8fc1 100644 --- a/repo/pyproject.toml +++ b/repo/pyproject.toml @@ -7,9 +7,9 @@ build-backend = "hatchling.build" allow-direct-references = true [project] -name = "playground" +name = "tuf-on-ci" version = "0.0.1" -description = "CI tools for Repository Plaground" +description = "TUF-on-CI repository tools, intended to be executed on a CI system" readme = "README.md" dependencies = [ "sigstore @ git+https://github.com/sigstore/sigstore-python@7d4af6c5f6732ef12e5bb455962321ebe5cce137", @@ -20,10 +20,10 @@ dependencies = [ requires-python = ">=3.10" [project.scripts] -playground-status = "playground:status" -playground-snapshot = "playground:snapshot" -playground-bump-online = "playground:bump_online" -playground-bump-offline = "playground:bump_offline" +tuf-on-ci-status = "tuf_on_ci:status" +tuf-on-ci-snapshot = "tuf_on_ci:snapshot" +tuf-on-ci-bump-online = "tuf_on_ci:bump_online" +tuf-on-ci-bump-offline = "tuf_on_ci:bump_offline" [[tool.mypy.overrides]] module = [ diff --git a/repo/test/test_playground_reposiory.py b/repo/test/test_ci_repository.py similarity index 71% rename from repo/test/test_playground_reposiory.py rename to repo/test/test_ci_repository.py index 73b897fc..b02ec60b 100644 --- a/repo/test/test_playground_reposiory.py +++ b/repo/test/test_ci_repository.py @@ -1,43 +1,43 @@ import unittest -from playground._playground_repository import PlaygroundRepository +from tuf_on_ci._repository import CIRepository -class TestPlaygroundRepository(unittest.TestCase): +class TestCIRepository(unittest.TestCase): def test_non_existing_repo(self): - repo = PlaygroundRepository("/tmp/no_such_file") + repo = CIRepository("/tmp/no_such_file") self.assertRaises(ValueError, repo.open, "root") def test_signing_expiry_days_root(self): - repo = PlaygroundRepository("test/test_repo1") + repo = CIRepository("test/test_repo1") signing_days, expiry_days = repo.signing_expiry_period("root") self.assertEqual(signing_days, 60) self.assertEqual(expiry_days, 365) def test_signing_expiry_days_targets(self): - repo = PlaygroundRepository("test/test_repo1") + repo = CIRepository("test/test_repo1") signing_days, expiry_days = repo.signing_expiry_period("targets") self.assertEqual(signing_days, 40) self.assertEqual(expiry_days, 123) def test_signing_expiry_days_role(self): - repo = PlaygroundRepository("test/test_repo2") + repo = CIRepository("test/test_repo2") signing_days, expiry_days = repo.signing_expiry_period("timestamp") self.assertEqual(signing_days, 6) self.assertEqual(expiry_days, 40) def test_default_signing_days(self): - repo = PlaygroundRepository("test/test_repo1") + repo = CIRepository("test/test_repo1") signing_days, expiry_days = repo.signing_expiry_period("timestamp") self.assertEqual(signing_days, 2) self.assertEqual(expiry_days, 4) # def test_bump_expires_expired(self): - # repo = PlaygroundRepository("test/test_repo1") + # repo = CIRepository("test/test_repo1") # ver = repo.bump_expiring("timestamp") # self.assertEqual(ver, 2) diff --git a/repo/test/test_repo1/root.json b/repo/test/test_repo1/root.json index 75e48e7b..f8f1324a 100644 --- a/repo/test/test_repo1/root.json +++ b/repo/test/test_repo1/root.json @@ -16,7 +16,7 @@ "public": "-----BEGIN PUBLIC KEY-----\nMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEJ3pswWmx9Bx2VBcpqaooQFA7dQnhRafh\ntj942eg086x6EMHdfgdox9TbwGm7sU2sn/gyjyDr1ez8Ld2ORnyYJ8cAlegfTqNq\nE0eSrLrb+YpzQJxLwh6qWcSngF99Unft\n-----END PUBLIC KEY-----\n" }, "scheme": "ecdsa-sha2-nistp384", - "x-playground-keyowner": "@playgrounduser1" + "x-tuf-on-ci-keyowner": "@playgrounduser1" }, "fa47289": { "keytype": "ed25519", @@ -24,7 +24,7 @@ "public": "fa472895c9756c2b9bcd1440bf867d0fa5c4edee79e9792fa9822be3dd6fcbb3" }, "scheme": "ed25519", - "x-playground-online-uri": "envvar:LOCAL_TESTING_KEY" + "x-tuf-on-ci-online-uri": "envvar:LOCAL_TESTING_KEY" } }, "roles": { @@ -39,7 +39,7 @@ "fa47289" ], "threshold": 1, - "x-playground-expiry-period": 365 + "x-tuf-on-ci-expiry-period": 365 }, "targets": { "keyids": [ @@ -52,12 +52,12 @@ "fa47289" ], "threshold": 1, - "x-playground-expiry-period": 4 + "x-tuf-on-ci-expiry-period": 4 } }, "spec_version": "1.0.31", "version": 1, - "x-playground-expiry-period": 365, - "x-playground-signing-period": 60 + "x-tuf-on-ci-expiry-period": 365, + "x-tuf-on-ci-signing-period": 60 } } diff --git a/repo/test/test_repo1/targets.json b/repo/test/test_repo1/targets.json index b9e16d8c..aa6e4973 100644 --- a/repo/test/test_repo1/targets.json +++ b/repo/test/test_repo1/targets.json @@ -11,7 +11,7 @@ "spec_version": "1.0.31", "targets": {}, "version": 1, - "x-playground-expiry-period": 123, - "x-playground-signing-period": 40 + "x-tuf-on-ci-expiry-period": 123, + "x-tuf-on-ci-signing-period": 40 } } diff --git a/repo/test/test_repo2/root.json b/repo/test/test_repo2/root.json index 810af754..2eac18b4 100644 --- a/repo/test/test_repo2/root.json +++ b/repo/test/test_repo2/root.json @@ -16,7 +16,7 @@ "public": "-----BEGIN PUBLIC KEY-----\nMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEJ3pswWmx9Bx2VBcpqaooQFA7dQnhRafh\ntj942eg086x6EMHdfgdox9TbwGm7sU2sn/gyjyDr1ez8Ld2ORnyYJ8cAlegfTqNq\nE0eSrLrb+YpzQJxLwh6qWcSngF99Unft\n-----END PUBLIC KEY-----\n" }, "scheme": "ecdsa-sha2-nistp384", - "x-playground-keyowner": "@playgrounduser1" + "x-tuf-on-ci-keyowner": "@tuf-on-ci-user1" }, "fa47289": { "keytype": "ed25519", @@ -24,7 +24,7 @@ "public": "fa472895c9756c2b9bcd1440bf867d0fa5c4edee79e9792fa9822be3dd6fcbb3" }, "scheme": "ed25519", - "x-playground-online-uri": "envvar:LOCAL_TESTING_KEY" + "x-tuf-on-ci-online-uri": "envvar:LOCAL_TESTING_KEY" } }, "roles": { @@ -39,7 +39,7 @@ "fa47289" ], "threshold": 1, - "x-playground-expiry-period": 365 + "x-tuf-on-ci-expiry-period": 365 }, "targets": { "keyids": [ @@ -52,13 +52,13 @@ "fa47289" ], "threshold": 1, - "x-playground-expiry-period": 40, - "x-playground-signing-period": 6 + "x-tuf-on-ci-expiry-period": 40, + "x-tuf-on-ci-signing-period": 6 } }, "spec_version": "1.0.31", "version": 1, - "x-playground-expiry-period": 365, - "x-playground-signing-period": 60 + "x-tuf-on-ci-expiry-period": 365, + "x-tuf-on-ci-signing-period": 60 } } diff --git a/repo/tuf_on_ci/__init__.py b/repo/tuf_on_ci/__init__.py new file mode 100644 index 00000000..bec5414a --- /dev/null +++ b/repo/tuf_on_ci/__init__.py @@ -0,0 +1,5 @@ +from tuf_on_ci.bump_expiring import bump_offline, bump_online +from tuf_on_ci.snapshot import snapshot +from tuf_on_ci.status import status + +__all__ = ["status", "snapshot", "bump_online", "bump_offline"] diff --git a/repo/playground/_playground_repository.py b/repo/tuf_on_ci/_repository.py similarity index 96% rename from repo/playground/_playground_repository.py rename to repo/tuf_on_ci/_repository.py index e80f1f06..0d1e6a91 100644 --- a/repo/playground/_playground_repository.py +++ b/repo/tuf_on_ci/_repository.py @@ -95,7 +95,7 @@ def roles_with_delegation_invites(self) -> set[str]: return roles -class PlaygroundRepository(Repository): +class CIRepository(Repository): """A online repository implementation for use in GitHub Actions Arguments: @@ -172,12 +172,12 @@ def signing_expiry_period(self, rolename: str) -> tuple[int, int]: """ if rolename in ["timestamp", "snapshot"]: role = self.root().get_delegated_role(rolename) - expiry_days = role.unrecognized_fields["x-playground-expiry-period"] - signing_days = role.unrecognized_fields.get("x-playground-signing-period") + expiry_days = role.unrecognized_fields["x-tuf-on-ci-expiry-period"] + signing_days = role.unrecognized_fields.get("x-tuf-on-ci-signing-period") else: signed = self.root() if rolename == "root" else self.targets(rolename) - expiry_days = signed.unrecognized_fields["x-playground-expiry-period"] - signing_days = signed.unrecognized_fields.get("x-playground-signing-period") + expiry_days = signed.unrecognized_fields["x-tuf-on-ci-expiry-period"] + signing_days = signed.unrecognized_fields.get("x-tuf-on-ci-signing-period") if signing_days is None: signing_days = expiry_days // 2 @@ -198,7 +198,7 @@ def close(self, rolename: str, md: Metadata) -> None: md.signatures.clear() for key in self._get_keys(rolename): if rolename in ["timestamp", "snapshot"]: - uri = key.unrecognized_fields["x-playground-online-uri"] + uri = key.unrecognized_fields["x-tuf-on-ci-online-uri"] # WORKAROUND while sigstoresigner is not finished if uri == "sigstore:": signer = SigstoreSigner(detect_credential(), key) @@ -274,7 +274,7 @@ def _validate_role( if md.signed.version <= prev_md.signed.version: return False, f"Version {md.signed.version} is not valid for {rolename}" - days = md.signed.unrecognized_fields["x-playground-expiry-period"] + days = md.signed.unrecognized_fields["x-tuf-on-ci-expiry-period"] if md.signed.expires > datetime.utcnow() + timedelta(days=days): return False, f"Expiry date is further than expected {days} days ahead" @@ -421,7 +421,7 @@ def _get_signing_status( # Build lists of signed signers and not signed signers for key in self._get_keys(rolename, known_good): - keyowner = key.unrecognized_fields["x-playground-keyowner"] + keyowner = key.unrecognized_fields["x-tuf-on-ci-keyowner"] try: payload = CanonicalJSONSerializer().serialize(md.signed) key.verify_signature(md.signatures[key.keyid], payload) diff --git a/repo/playground/bump_expiring.py b/repo/tuf_on_ci/bump_expiring.py similarity index 95% rename from repo/playground/bump_expiring.py rename to repo/tuf_on_ci/bump_expiring.py index 4b70d8f4..f92a0a9f 100644 --- a/repo/playground/bump_expiring.py +++ b/repo/tuf_on_ci/bump_expiring.py @@ -9,7 +9,7 @@ import click -from playground._playground_repository import PlaygroundRepository +from tuf_on_ci._repository import CIRepository logger = logging.getLogger(__name__) @@ -18,7 +18,7 @@ def _git(cmd: list[str]) -> subprocess.CompletedProcess: cmd = [ "git", "-c", - "user.name=repository-playground", + "user.name=TUF-on-CI", "-c", "user.email=41898282+github-actions[bot]@users.noreply.github.com", ] + cmd @@ -47,7 +47,7 @@ def bump_online( logging.basicConfig(level=logging.WARNING - verbose * 10) msg = "Periodic online role version bump and resign\n\n" - repo = PlaygroundRepository("metadata") + repo = CIRepository("metadata") snapshot_version = repo.bump_expiring("snapshot") if snapshot_version is None: timestamp_version = repo.bump_expiring("timestamp") @@ -90,7 +90,7 @@ def bump_offline(verbose: int, push: bool) -> None: """ logging.basicConfig(level=logging.WARNING - verbose * 10) - repo = PlaygroundRepository("metadata") + repo = CIRepository("metadata") events = [] for filename in glob("*.json", root_dir="metadata"): if filename in ["timestamp.json", "snapshot.json"]: diff --git a/repo/playground/snapshot.py b/repo/tuf_on_ci/snapshot.py similarity index 87% rename from repo/playground/snapshot.py rename to repo/tuf_on_ci/snapshot.py index 9b7665d4..b2cb2bf8 100644 --- a/repo/playground/snapshot.py +++ b/repo/tuf_on_ci/snapshot.py @@ -1,13 +1,13 @@ # Copyright 2023 Google LLC -"""Command line tool to update snapshot (and timestamp) for Repository Playground CI""" +"""Command line tool to update snapshot (and timestamp) for TUF-on-CI""" import logging import subprocess import click -from playground._playground_repository import PlaygroundRepository +from tuf_on_ci._repository import CIRepository logger = logging.getLogger(__name__) @@ -16,7 +16,7 @@ def _git(cmd: list[str]) -> subprocess.CompletedProcess: cmd = [ "git", "-c", - "user.name=repository-playground", + "user.name=tuf-on-ci", "-c", "user.email=41898282+github-actions[bot]@users.noreply.github.com", ] + cmd @@ -42,7 +42,7 @@ def snapshot( """ logging.basicConfig(level=logging.WARNING - verbose * 10) - repo = PlaygroundRepository("metadata") + repo = CIRepository("metadata") snapshot_updated, _ = repo.do_snapshot() if not snapshot_updated: click.echo("No snapshot needed") diff --git a/repo/playground/status.py b/repo/tuf_on_ci/status.py similarity index 92% rename from repo/playground/status.py rename to repo/tuf_on_ci/status.py index 4e1e11b3..b177ec31 100644 --- a/repo/playground/status.py +++ b/repo/tuf_on_ci/status.py @@ -1,6 +1,6 @@ # Copyright 2023 Google LLC -"""Command line signing event status output tool for Repository Playground CI""" +"""Command line signing event status output tool for TUF-on-CI""" import filecmp import logging @@ -12,7 +12,7 @@ import click -from playground._playground_repository import PlaygroundRepository +from tuf_on_ci._repository import CIRepository logger = logging.getLogger(__name__) @@ -21,7 +21,7 @@ def _git(cmd: list[str]) -> subprocess.CompletedProcess: cmd = [ "git", "-c", - "user.name=repository-playground", + "user.name=TUF-on-CI", "-c", "user.email=41898282+github-actions[bot]@users.noreply.github.com", ] + cmd @@ -83,7 +83,7 @@ def _find_changed_target_roles( return changed_roles -def _role_status(repo: PlaygroundRepository, role: str, event_name) -> bool: +def _role_status(repo: CIRepository, role: str, event_name) -> bool: status, prev_status = repo.status(role) role_is_valid = status.valid sig_counts = f"{len(status.signed)}/{status.threshold}" @@ -109,7 +109,7 @@ def _role_status(repo: PlaygroundRepository, role: str, event_name) -> bool: ) click.echo( "Invitees can accept the invitations by running " - f"`playground-sign {event_name}`" + f"`tuf-on-ci-sign {event_name}`" ) if not status.invites: @@ -136,7 +136,7 @@ def _role_status(repo: PlaygroundRepository, role: str, event_name) -> bool: click.echo(f"Still missing signatures from {', '.join(missing)}") click.echo( "Signers can sign these changes by running " - f"`playground-sign {event_name}`" + f"`tuf-on-ci-sign {event_name}`" ) if status.message: @@ -149,7 +149,7 @@ def _role_status(repo: PlaygroundRepository, role: str, event_name) -> bool: @click.option("-v", "--verbose", count=True, default=0) @click.option("--push/--no-push", default=True) def status(verbose: int, push: bool) -> None: - """Status markdown output tool for Repository Playground CI""" + """Status markdown output tool""" logging.basicConfig(level=logging.WARNING - verbose * 10) event_name = _git(["branch", "--show-current"]).stdout.strip() @@ -160,7 +160,7 @@ def status(verbose: int, push: bool) -> None: if not os.path.exists("metadata/root.json"): click.echo( "Repository does not exist yet. Create one with " - f"`playground-delegate {event_name}`." + f"`tuf-on-ci-delegate {event_name}`." ) sys.exit(1) @@ -181,7 +181,7 @@ def status(verbose: int, push: bool) -> None: # Compare current repository and the known good version. # Print status for each role, count invalid roles - repo = PlaygroundRepository("metadata", good_metadata) + repo = CIRepository("metadata", good_metadata) # first create a list of roles with metadata or artifact changes or invites roles = list( diff --git a/signer/README.md b/signer/README.md index 32e75c58..bd0a6f8a 100644 --- a/signer/README.md +++ b/signer/README.md @@ -1,41 +1,5 @@ -### Requirements +### TUF-on-CI Signing tools -In addition to the Python requirements managed by pip, a PKCS#11 module is -required (and it's location needs to be configured, see below). - -This tool has been tested with the Yubico implementation of PKCS#11, -[YKCS11](https://developers.yubico.com/yubico-piv-tool/YKCS11/). Debian users -can install it with `apt install ykcs11`. - -### Installation - -Development install: `pip install -e .` - -### Configuration - -Tool does not currently write the config file itself so this needs to be done manually. - -`.playground-sign.ini` (in the git toplevel directory): -``` -[settings] -pykcs11lib = /usr/lib/x86_64-linux-gnu/libykcs11.so -user-name = @jku -``` - -### Usage - -When a signing event (GitHub issue) requests your signature, run `playground-sign`. - -### TODO - -* implement role-metadata cache -- currently we load the same file quite a lot -* avoid asking for pin too many times - 1. same role is sometimes signed multiple times -- could avoid all but last one - 2. multiple roles may be signed -- this is likely not worth optimizing -* refactor event state handling (invites): it's currently clumsy in _signer_repository.py -* git integration. Would be nice to be able to avoid - * git fetch - * git checkout - * git push - * _figure out how to create a PR to the signing-event - We can do all this if we store pull-remote and push-remote information in the configuration \ No newline at end of file +This package contains the signing tools for +(TUF-on-CI)[https://github.com/theupdateframework/tuf-on-ci]. Please see +TUF-on-CI README for usage. diff --git a/signer/create-config-file.sh b/signer/create-config-file.sh index acaec348..6a68ddb4 100755 --- a/signer/create-config-file.sh +++ b/signer/create-config-file.sh @@ -1,6 +1,6 @@ #!/bin/sh -# Run this script in the folder where the TUF repository resides to +# Run this script in the folder where the TUF-on-CI repository resides to # initialize the config. set -u @@ -35,10 +35,10 @@ if [ ! -f ${YKSLIB} ]; then echo "Could not find a PKCS library at path ${YKSLIB}" echo "Please install a PKCS library, or enter a path where one is installed:" read YKSLIB - echo "Using ${YKSLIB}. This can changed later via 'pykcs11lib' in file .playground-sign.ini" + echo "Using ${YKSLIB}. This can changed later via 'pykcs11lib' in file .tuf-on-ci-sign.ini" fi -cat > .playground-sign.ini < .tuf-on-ci-sign.ini < bool: """Return true if current role metadata is unsigned by user""" md = self.open(rolename) for key in self._get_keys(rolename): - keyowner = key.unrecognized_fields["x-playground-keyowner"] + keyowner = key.unrecognized_fields["x-tuf-on-ci-keyowner"] if keyowner == self.user_name: try: payload = CanonicalJSONSerializer().serialize(md.signed) @@ -160,7 +160,7 @@ def _user_signature_needed(self, rolename: str) -> bool: # the current version if rolename == "root": for key in self._get_keys(rolename, True): - keyowner = key.unrecognized_fields["x-playground-keyowner"] + keyowner = key.unrecognized_fields["x-tuf-on-ci-keyowner"] if keyowner == self.user_name: try: payload = CanonicalJSONSerializer().serialize(md.signed) @@ -241,7 +241,7 @@ def secret_handler(secret: str) -> str: return self._get_secret(secret, role) if key.keyid not in self._signers: - # TODO Get key uri from .playground-sign.ini, avoid if-else here + # TODO Get key uri from config file, avoid if-else here if key.keytype == "sigstore-oidc": self._signers[key.keyid] = Signer.from_priv_key_uri( "sigstore:?ambient=false", key, secret_handler @@ -285,8 +285,8 @@ def open(self, role: str) -> Metadata: md: Metadata = Metadata(Root()) else: md = Metadata(Targets()) - md.signed.unrecognized_fields["x-playground-expiry-period"] = 0 - md.signed.unrecognized_fields["x-playground-signing-period"] = 0 + md.signed.unrecognized_fields["x-tuf-on-ci-expiry-period"] = 0 + md.signed.unrecognized_fields["x-tuf-on-ci-signing-period"] = 0 else: with open(fname, "rb") as f: md = Metadata.from_bytes(f.read()) @@ -303,7 +303,7 @@ def close(self, role: str, md: Metadata) -> None: md.signed.version = self._known_good_version(role) + 1 # Set expiry based on custom metadata - days = md.signed.unrecognized_fields["x-playground-expiry-period"] + days = md.signed.unrecognized_fields["x-tuf-on-ci-expiry-period"] md.signed.expires = datetime.utcnow() + timedelta(days=days) # figure out if there are open invites to delegations of this role @@ -343,7 +343,7 @@ def close(self, role: str, md: Metadata) -> None: md.signatures[key.keyid] = Signature(key.keyid, "") # Mark role as unsigned if user is a signer (and there are no open invites) - keyowner = key.unrecognized_fields["x-playground-keyowner"] + keyowner = key.unrecognized_fields["x-tuf-on-ci-keyowner"] if keyowner == self.user_name and not open_invites: if role not in self.unsigned: self.unsigned.append(role) @@ -366,16 +366,14 @@ def get_online_config(self) -> OnlineConfig: timestamp_role = root.get_delegated_role("timestamp") snapshot_role = root.get_delegated_role("snapshot") timestamp_expiry = timestamp_role.unrecognized_fields[ - "x-playground-expiry-period" + "x-tuf-on-ci-expiry-period" ] timestamp_signing = timestamp_role.unrecognized_fields.get( - "x-playground-signing-period" + "x-tuf-on-ci-signing-period" ) - snapshot_expiry = snapshot_role.unrecognized_fields[ - "x-playground-expiry-period" - ] + snapshot_expiry = snapshot_role.unrecognized_fields["x-tuf-on-ci-expiry-period"] snapshot_signing = snapshot_role.unrecognized_fields.get( - "x-playground-signing-period" + "x-tuf-on-ci-signing-period" ) if timestamp_signing is None: @@ -410,16 +408,16 @@ def set_online_config(self, online_config: OnlineConfig): # set online role periods timestamp.unrecognized_fields[ - "x-playground-expiry-period" + "x-tuf-on-ci-expiry-period" ] = online_config.timestamp_expiry timestamp.unrecognized_fields[ - "x-playground-signing-period" + "x-tuf-on-ci-signing-period" ] = online_config.timestamp_signing snapshot.unrecognized_fields[ - "x-playground-expiry-period" + "x-tuf-on-ci-expiry-period" ] = online_config.snapshot_expiry snapshot.unrecognized_fields[ - "x-playground-signing-period" + "x-tuf-on-ci-signing-period" ] = online_config.snapshot_signing def get_role_config(self, rolename: str) -> OfflineConfig | None: @@ -442,8 +440,8 @@ def get_role_config(self, rolename: str) -> OfflineConfig | None: except ValueError: return None - expiry = delegated.unrecognized_fields["x-playground-expiry-period"] - signing = delegated.unrecognized_fields["x-playground-signing-period"] + expiry = delegated.unrecognized_fields["x-tuf-on-ci-expiry-period"] + signing = delegated.unrecognized_fields["x-tuf-on-ci-signing-period"] threshold = role.threshold signers = [] # Include current invitees on config @@ -454,7 +452,7 @@ def get_role_config(self, rolename: str) -> OfflineConfig | None: for keyid in role.keyids: try: key = delegator.get_key(keyid) - signers.append(key.unrecognized_fields["x-playground-keyowner"]) + signers.append(key.unrecognized_fields["x-tuf-on-ci-keyowner"]) except ValueError: pass @@ -483,7 +481,7 @@ def set_role_config( # Find signers key is_signer = False for key in self._get_keys(rolename): - if signer == key.unrecognized_fields["x-playground-keyowner"]: + if signer == key.unrecognized_fields["x-tuf-on-ci-keyowner"]: is_signer = True # If signer does not have key, add invitation @@ -514,10 +512,10 @@ def set_role_config( for keyid in role.keyids: key = delegator.get_key(keyid) - if key.unrecognized_fields["x-playground-keyowner"] in config.signers: + if key.unrecognized_fields["x-tuf-on-ci-keyowner"] in config.signers: # signer is still a signer config.signers.remove( - key.unrecognized_fields["x-playground-keyowner"] + key.unrecognized_fields["x-tuf-on-ci-keyowner"] ) else: # signer was removed @@ -530,9 +528,7 @@ def set_role_config( and rolename in self._invites[self.user_name] ) if invited and signing_key: - signing_key.unrecognized_fields[ - "x-playground-keyowner" - ] = self.user_name + signing_key.unrecognized_fields["x-tuf-on-ci-keyowner"] = self.user_name delegator.add_key(signing_key, rolename) self._invites[self.user_name].remove(rolename) @@ -554,16 +550,16 @@ def set_role_config( # Modify the role itself with self.edit(rolename) as signed: - expiry = signed.unrecognized_fields.get("x-playground-expiry-period") - signing = signed.unrecognized_fields.get("x-playground-signing-period") + expiry = signed.unrecognized_fields.get("x-tuf-on-ci-expiry-period") + signing = signed.unrecognized_fields.get("x-tuf-on-ci-signing-period") if expiry == config.expiry_period and signing == config.signing_period: raise AbortEdit(f"No changes to {rolename}") signed.unrecognized_fields[ - "x-playground-expiry-period" + "x-tuf-on-ci-expiry-period" ] = config.expiry_period signed.unrecognized_fields[ - "x-playground-signing-period" + "x-tuf-on-ci-signing-period" ] = config.signing_period state_file_path = os.path.join(self._dir, ".signing-event-state") @@ -585,10 +581,10 @@ def _role_status_lines(self, rolename: str) -> list[str]: signed = self.targets(rolename) old_signed = self._known_good_targets(rolename) - expiry = signed.unrecognized_fields["x-playground-expiry-period"] - signing = signed.unrecognized_fields["x-playground-signing-period"] - old_expiry = old_signed.unrecognized_fields.get("x-playground-expiry-period") - old_signing = old_signed.unrecognized_fields.get("x-playground-signing-period") + expiry = signed.unrecognized_fields["x-tuf-on-ci-expiry-period"] + signing = signed.unrecognized_fields["x-tuf-on-ci-signing-period"] + old_expiry = old_signed.unrecognized_fields.get("x-tuf-on-ci-expiry-period") + old_signing = old_signed.unrecognized_fields.get("x-tuf-on-ci-signing-period") output.append(blue(f"{rolename} v{signed.version}")) @@ -612,9 +608,9 @@ def _delegation_status_lines(self, rolename: str) -> list[str]: def _get_signer_name(key: Key) -> str: if name in ["timestamp", "snapshot"]: # there's no "signer" in the online case: use signing system as signer - uri = key.unrecognized_fields["x-playground-online-uri"] + uri = key.unrecognized_fields["x-tuf-on-ci-online-uri"] return uri.split(":")[0] - return key.unrecognized_fields["x-playground-keyowner"] + return key.unrecognized_fields["x-tuf-on-ci-keyowner"] output = [] delegations: dict[str, Role] = {} @@ -718,7 +714,7 @@ def sign(self, rolename: str): """Sign without payload changes""" md = self.open(rolename) for key in self._get_keys(rolename): - keyowner = key.unrecognized_fields["x-playground-keyowner"] + keyowner = key.unrecognized_fields["x-tuf-on-ci-keyowner"] if keyowner == self.user_name: self._sign(rolename, md, key) self._write(rolename, md) @@ -728,7 +724,7 @@ def sign(self, rolename: str): # in previous version if rolename == "root": for key in self._get_keys(rolename, True): - keyowner = key.unrecognized_fields["x-playground-keyowner"] + keyowner = key.unrecognized_fields["x-tuf-on-ci-keyowner"] if keyowner == self.user_name: self._sign(rolename, md, key) self._write(rolename, md) diff --git a/signer/playground_sign/delegate.py b/signer/tuf_on_ci_sign/delegate.py similarity index 94% rename from signer/playground_sign/delegate.py rename to signer/tuf_on_ci_sign/delegate.py index dd068d18..aa66c768 100755 --- a/signer/playground_sign/delegate.py +++ b/signer/tuf_on_ci_sign/delegate.py @@ -1,6 +1,6 @@ # Copyright 2023 Google LLC -"""playground-modify: A command line tool to modify Repository Playground delegations""" +"""tuf-on-ci-delegate: A command line tool to modify TUF-on-CI delegations""" import copy import logging @@ -18,7 +18,7 @@ SSlibKey, ) -from playground_sign._common import ( +from tuf_on_ci_sign._common import ( SignerConfig, bold, get_signing_key_input, @@ -26,7 +26,7 @@ git_expect, signing_event, ) -from playground_sign._signer_repository import ( +from tuf_on_ci_sign._signer_repository import ( OfflineConfig, OnlineConfig, SignerRepository, @@ -137,7 +137,7 @@ def _sigstore_import(pull_remote: str) -> list[SigstoreKey]: key = SigstoreKey( keyid, "sigstore-oidc", "Fulcio", {"issuer": issuer, "identity": id} ) - key.unrecognized_fields["x-playground-online-uri"] = "sigstore:" + key.unrecognized_fields["x-tuf-on-ci-online-uri"] = "sigstore:" keys.append(key) return keys @@ -146,7 +146,7 @@ def _get_online_input(config: OnlineConfig, user_config: SignerConfig) -> Online config = copy.deepcopy(config) click.echo("\nConfiguring online roles") while True: - keyuri = config.keys[0].unrecognized_fields["x-playground-online-uri"] + keyuri = config.keys[0].unrecognized_fields["x-tuf-on-ci-online-uri"] click.echo(f" 1. Configure online key: {keyuri}") click.echo( f" 2. Configure timestamp: Expires in {config.timestamp_expiry} days," @@ -211,7 +211,7 @@ def _collect_online_keys(user_config: SignerConfig) -> list[SSlibKey]: key_id = _collect_string("Enter a Google Cloud KMS key id") try: uri, key = GCPSigner.import_(key_id) - key.unrecognized_fields["x-playground-online-uri"] = uri + key.unrecognized_fields["x-tuf-on-ci-online-uri"] = uri return [key] except Exception as e: raise click.ClickException(f"Failed to read Google Cloud KMS key: {e}") @@ -220,7 +220,7 @@ def _collect_online_keys(user_config: SignerConfig) -> list[SSlibKey]: key_name = _collect_string("Enter key name") try: uri, key = AzureSigner.import_(vault_name, key_name) - key.unrecognized_fields["x-playground-online-uri"] = uri + key.unrecognized_fields["x-tuf-on-ci-online-uri"] = uri return [key] except Exception as e: raise click.ClickException(f"Failed to read Azure Keyvault key: {e}") @@ -234,7 +234,7 @@ def _collect_online_keys(user_config: SignerConfig) -> list[SSlibKey]: "ed25519", "ed25519", {"public": pub_key}, - {"x-playground-online-uri": uri}, + {"x-tuf-on-ci-online-uri": uri}, ) return [key] @@ -249,7 +249,7 @@ def _collect_string(prompt: str) -> str: def _init_repository(repo: SignerRepository, user_config: SignerConfig) -> bool: - click.echo("Creating a new Playground TUF repository") + click.echo("Creating a new TUF-on-CI repository") root_config = _get_offline_input( "root", OfflineConfig([repo.user_name], 1, 365, 60) @@ -316,11 +316,11 @@ def _update_offline_role(repo: SignerRepository, role: str) -> bool: @click.argument("event-name", metavar="SIGNING-EVENT") @click.argument("role", required=False) def delegate(verbose: int, push: bool, event_name: str, role: str | None): - """Tool for modifying Repository Playground delegations.""" + """Tool for modifying TUF-on-CI delegations.""" logging.basicConfig(level=logging.WARNING - verbose * 10) toplevel = git_expect(["rev-parse", "--show-toplevel"]) - settings_path = os.path.join(toplevel, ".playground-sign.ini") + settings_path = os.path.join(toplevel, ".tuf-on-ci-sign.ini") user_config = SignerConfig(settings_path) with signing_event(event_name, user_config) as repo: diff --git a/signer/playground_sign/sign.py b/signer/tuf_on_ci_sign/sign.py similarity index 90% rename from signer/playground_sign/sign.py rename to signer/tuf_on_ci_sign/sign.py index 7975afdf..ee335a19 100755 --- a/signer/playground_sign/sign.py +++ b/signer/tuf_on_ci_sign/sign.py @@ -1,13 +1,13 @@ # Copyright 2023 Google LLC -"""playground-sign: A command line tool to sign Repository Playground changes""" +"""tuf-on-ci-sign: A command line signing tool for TUF-on-CI signing events""" import logging import os import click -from playground_sign._common import ( +from tuf_on_ci_sign._common import ( SignerConfig, bold, get_signing_key_input, @@ -15,7 +15,7 @@ git_expect, signing_event, ) -from playground_sign._signer_repository import SignerState +from tuf_on_ci_sign._signer_repository import SignerState logger = logging.getLogger(__name__) @@ -25,11 +25,11 @@ @click.option("--push/--no-push", default=True) @click.argument("event-name", metavar="signing-event") def sign(verbose: int, push: bool, event_name: str): - """Signing tool for Repository Playground signing events.""" + """Signing tool for TUF-on-CI signing events.""" logging.basicConfig(level=logging.WARNING - verbose * 10) toplevel = git_expect(["rev-parse", "--show-toplevel"]) - settings_path = os.path.join(toplevel, ".playground-sign.ini") + settings_path = os.path.join(toplevel, ".tuf-on-ci-sign.ini") user_config = SignerConfig(settings_path) with signing_event(event_name, user_config) as repo: diff --git a/tests/README.md b/tests/README.md index c852a257..7fceaee4 100644 --- a/tests/README.md +++ b/tests/README.md @@ -1,6 +1,6 @@ -# End-to-end tests for repository-playground +# End-to-end tests for TUF-on-CI -Repository-playground is implemented on top of a CI system, git and quite a bit of +TUF-on-CI is implemented on top of a CI system, git and includes quite a bit of user interaction (through both the CI system and the signing tools). This makes testing tricky. These tests are an attempt at defining a set of functionality that can be tested without @@ -9,18 +9,18 @@ can be tested without * sigstore or Google Cloud signing for online keys * a user signing with a Yubikey -The rough layout of repository-playground is: -1. Users run a set of python programs (see playground/signer/) +The rough layout of TUF-on-CI is: +1. Users run a set of python programs (see signer/) 2. **These programs modify metadata stored in git, commit the changes into git and push various branches to upstream** -3. Github workflows react to triggers (cron, push) and call GitHub actions defined in repository-playground -4. The GitHub actions run a separate set of python programs (see playground/repo/) +3. Github workflows react to triggers (cron, push) and call GitHub actions defined in TUF-on-CI +4. The GitHub actions run a separate set of python programs (see repo/) 5. **These programs also modify metadata stored in git, commit changes and push various branches** The tests are designed to test steps 2 and 5 and emulate steps 1, 3 and 4. The purpose is to make refactoring and development of the python programs easier (because they have test coverage). In practice: -* functions named `signer_*()` emulate user interactions with tools in playground/signer/ (`playground-sign`, `playground-delegate`). -* functions name `repo_*()` emulate GitHub workflows and actions using the tools in playground/repo/ +* functions named `signer_*()` emulate user interactions with tools in signer/ (`tuf-on-ci-sign`, `tuf-on-ci-delegate`). +* functions name `repo_*()` emulate GitHub workflows and actions using the tools in repo/ * The signer functions operate within one git repository, the repo functions in another: both of them push to and pull from the "upstream" git repository. In this test setup all of these git repositories are local * Yubikeys are simulated with SoftHSM2 @@ -35,7 +35,7 @@ structure would be nice to verify as well but unfortunately the nondeterministic * libsofthsm2 (currently hardcoded "/usr/lib/softhsm/libsofthsm2.so") * libfaketime (currently hardcoded "/usr/lib/x86_64-linux-gnu/faketime/libfaketime.so.1") -* Both playground/signer and playground/repo must be installed +* Both signer and repo must be installed (`pip install -e ../signer/ && pip install -e ../repo/`) ## Issues diff --git a/tests/e2e.sh b/tests/e2e.sh index 0bb66703..39bfa917 100755 --- a/tests/e2e.sh +++ b/tests/e2e.sh @@ -1,6 +1,6 @@ #!/bin/bash -# Run a end-to-end test of repository-playground locally +# Run a end-to-end test of TUF-on-CI locally # This emulates: # * GitHub Actions # * Hardware signing @@ -14,8 +14,8 @@ # $ brew install softhsm swig libfaketime # # Python dependencies -# * signer: pip install ./playground/signer/ -# * repo: pip install ./playground/repo/ +# * signer: pip install ./signer/ +# * repo: pip install ./repo/ # * pynacl: pip install pynacl # for the testing ed25519 key # # @@ -28,7 +28,7 @@ # + repo/ # + git/ -- the repository used for emulate GitHub Actions, like snapshot # + signer/ -# + git/ -- the repository used to emulate human user running playground-delegate and sign +# + git/ -- the repository used to emulate human user running tuf-on-ci-delegate and sign set -euo pipefail @@ -68,7 +68,7 @@ git_repo() { git \ -C $REPO_GIT \ - -c user.name=repository-playground \ + -c user.name=tuf-on-ci \ -c user.email=41898282+github-actions[bot]@users.noreply.github.com \ -c commit.gpgsign=false \ $@ @@ -107,14 +107,14 @@ signer_setup() # Set user configuration echo -e "[settings]\n" \ "pykcs11lib = $SOFTHSMLIB\n" \ - "user-name = @playground$USER\n" \ + "user-name = @tuf-on-ci-$USER\n" \ "push-remote = origin\n" \ - "pull-remote = origin\n" > $SIGNER_GIT/.playground-sign.ini + "pull-remote = origin\n" > $SIGNER_GIT/.tuf-on-ci-sign.ini } signer_init() { - # run playground-delegate: creates a commit, pushes it to remote branch + # run tuf-on-ci-delegate: creates a commit, pushes it to remote branch USER=$1 EVENT=$2 @@ -139,12 +139,12 @@ signer_init() for line in "${INPUT[@]}"; do echo $line - done | playground-delegate $EVENT >> $SIGNER_DIR/out 2>&1 + done | tuf-on-ci-delegate $EVENT >> $SIGNER_DIR/out 2>&1 } signer_change_root_signer() { - # run playground-delegate to change root signer from user1 to user2: + # run tuf-on-ci-delegate to change root signer from user1 to user2: USER1=$1 USER2=$2 EVENT=$3 @@ -158,7 +158,7 @@ signer_change_root_signer() INPUT=( "root" # select role to modify "1" # Configure root? [1: configure signers] - "@playground$USER2" # Enter list of signers + "@tuf-on-ci-$USER2" # Enter list of signers "" # Configure root? [enter to continue] "" # press enter to push ) @@ -167,12 +167,12 @@ signer_change_root_signer() for line in "${INPUT[@]}"; do echo $line - done | playground-delegate $EVENT >> $SIGNER_DIR/out 2>&1 + done | tuf-on-ci-delegate $EVENT >> $SIGNER_DIR/out 2>&1 } signer_init_shorter_snapshot_expiry() { - # run playground-delegate: creates a commit, pushes it to remote branch + # run tuf-on-ci-delegate: creates a commit, pushes it to remote branch USER=$1 EVENT=$2 @@ -200,12 +200,12 @@ signer_init_shorter_snapshot_expiry() for line in "${INPUT[@]}"; do echo $line - done | playground-delegate $EVENT >> $SIGNER_DIR/out 2>&1 + done | tuf-on-ci-delegate $EVENT >> $SIGNER_DIR/out 2>&1 } signer_init_multiuser() { - # run playground-delegate: creates a commit, pushes it to remote branch + # run tuf-on-ci-delegate: creates a commit, pushes it to remote branch USER=$1 EVENT=$2 @@ -216,7 +216,7 @@ signer_init_multiuser() INPUT=( "" # Configure root? [enter to continue] "1" # Configure targets? [1: configure signers] - "@playgrounduser1, @playgrounduser2" # Enter signers + "@tuf-on-ci-user1, @tuf-on-ci-user2" # Enter signers "2" # Enter threshold "" # Configure targets? [enter to continue] "1" # Configure online roles? [1: configure key] @@ -232,12 +232,12 @@ signer_init_multiuser() for line in "${INPUT[@]}"; do echo $line - done | playground-delegate $EVENT >> $SIGNER_DIR/out 2>&1 + done | tuf-on-ci-delegate $EVENT >> $SIGNER_DIR/out 2>&1 } signer_accept_invite() { - # run playground-sign: creates a commit, pushes it to remote branch + # run tuf-on-ci-sign: creates a commit, pushes it to remote branch USER=$1 EVENT=$2 @@ -256,13 +256,13 @@ signer_accept_invite() for line in "${INPUT[@]}"; do echo $line - done | playground-sign $EVENT >> $SIGNER_DIR/out 2>&1 + done | tuf-on-ci-sign $EVENT >> $SIGNER_DIR/out 2>&1 } signer_sign() { - # run playground-sign: creates a commit, pushes it to remote branch + # run tuf-on-ci-sign: creates a commit, pushes it to remote branch USER=$1 EVENT=$2 @@ -280,7 +280,7 @@ signer_sign() for line in "${INPUT[@]}"; do echo $line - done | playground-sign $EVENT >> $SIGNER_DIR/out 2>&1 + done | tuf-on-ci-sign $EVENT >> $SIGNER_DIR/out 2>&1 } signer_add_targets() @@ -328,7 +328,7 @@ signer_modify_targets() non_signer_change_online_delegation() { - # run playground-delegate: creates a commit, pushes it to remote branch + # run tuf-on-ci-delegate: creates a commit, pushes it to remote branch # this is called by someone who is not a root signer USER=$1 EVENT=$2 @@ -349,7 +349,7 @@ non_signer_change_online_delegation() for line in "${INPUT[@]}"; do echo $line - done | playground-delegate $EVENT timestamp >> $SIGNER_DIR/out 2>&1 + done | tuf-on-ci-delegate $EVENT timestamp >> $SIGNER_DIR/out 2>&1 } repo_merge() @@ -361,9 +361,9 @@ repo_merge() git_repo fetch --quiet origin git_repo merge --quiet origin/$EVENT - # run playground-status to check that all is ok + # run tuf-on-ci-status to check that all is ok cd $REPO_GIT - playground-status >> $REPO_DIR/out + tuf-on-ci-status >> $REPO_DIR/out git_repo push --quiet } @@ -377,12 +377,12 @@ repo_status_fail() git_repo checkout --quiet $EVENT git_repo pull --quiet - # run playground-status, expect failure - # Note that playground-status may make a commit (to modify targets metadata) even if end result is failure + # run tuf-on-ci-status, expect failure + # Note that tuf-on-ci-status may make a commit (to modify targets metadata) even if end result is failure # TODO: check output for specifics cd $REPO_GIT - if playground-status >> $REPO_DIR/out; then + if tuf-on-ci-status >> $REPO_DIR/out; then return 1 fi git_repo checkout --quiet main @@ -396,7 +396,7 @@ repo_snapshot() cd $REPO_GIT - if LOCAL_TESTING_KEY=$ONLINE_KEY playground-snapshot --push --metadata metadata --targets targets $PUBLISH_DIR >> $REPO_DIR/out 2>&1; then + if LOCAL_TESTING_KEY=$ONLINE_KEY tuf-on-ci-snapshot --push --metadata metadata --targets targets $PUBLISH_DIR >> $REPO_DIR/out 2>&1; then echo "generated=true" >> $REPO_DIR/out else echo "generated=false" >> $REPO_DIR/out @@ -410,13 +410,13 @@ repo_bump_versions() cd $REPO_GIT - if LOCAL_TESTING_KEY=$ONLINE_KEY playground-bump-online --push --metadata metadata --targets targets $PUBLISH_DIR >> $REPO_DIR/out 2>&1; then + if LOCAL_TESTING_KEY=$ONLINE_KEY tuf-on-ci-bump-online --push --metadata metadata --targets targets $PUBLISH_DIR >> $REPO_DIR/out 2>&1; then echo "generated=true" >> $REPO_DIR/out else echo "generated=false" >> $REPO_DIR/out fi - events=$(playground-bump-offline --push) + events=$(tuf-on-ci-bump-offline --push) echo "events=$events" >> $REPO_DIR/out # TODO: run signing events diff --git a/tests/expected/basic/metadata/1.root.json b/tests/expected/basic/metadata/1.root.json index 72b82697..436d49f7 100644 --- a/tests/expected/basic/metadata/1.root.json +++ b/tests/expected/basic/metadata/1.root.json @@ -16,7 +16,7 @@ "public": "-----BEGIN PUBLIC KEY-----\nMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEJ3pswWmx9Bx2VBcpqaooQFA7dQnhRafh\ntj942eg086x6EMHdfgdox9TbwGm7sU2sn/gyjyDr1ez8Ld2ORnyYJ8cAlegfTqNq\nE0eSrLrb+YpzQJxLwh6qWcSngF99Unft\n-----END PUBLIC KEY-----\n" }, "scheme": "ecdsa-sha2-nistp384", - "x-playground-keyowner": "@playgrounduser1" + "x-tuf-on-ci-keyowner": "@tuf-on-ci-user1" }, "fa47289": { "keytype": "ed25519", @@ -24,7 +24,7 @@ "public": "fa472895c9756c2b9bcd1440bf867d0fa5c4edee79e9792fa9822be3dd6fcbb3" }, "scheme": "ed25519", - "x-playground-online-uri": "envvar:LOCAL_TESTING_KEY" + "x-tuf-on-ci-online-uri": "envvar:LOCAL_TESTING_KEY" } }, "roles": { @@ -39,8 +39,8 @@ "fa47289" ], "threshold": 1, - "x-playground-expiry-period": 365, - "x-playground-signing-period": 60 + "x-tuf-on-ci-expiry-period": 365, + "x-tuf-on-ci-signing-period": 60 }, "targets": { "keyids": [ @@ -53,13 +53,13 @@ "fa47289" ], "threshold": 1, - "x-playground-expiry-period": 2, - "x-playground-signing-period": 1 + "x-tuf-on-ci-expiry-period": 2, + "x-tuf-on-ci-signing-period": 1 } }, "spec_version": "1.0.31", "version": 1, - "x-playground-expiry-period": 365, - "x-playground-signing-period": 60 + "x-tuf-on-ci-expiry-period": 365, + "x-tuf-on-ci-signing-period": 60 } } \ No newline at end of file diff --git a/tests/expected/basic/metadata/1.targets.json b/tests/expected/basic/metadata/1.targets.json index 3dc90909..30598879 100644 --- a/tests/expected/basic/metadata/1.targets.json +++ b/tests/expected/basic/metadata/1.targets.json @@ -11,7 +11,7 @@ "spec_version": "1.0.31", "targets": {}, "version": 1, - "x-playground-expiry-period": 365, - "x-playground-signing-period": 60 + "x-tuf-on-ci-expiry-period": 365, + "x-tuf-on-ci-signing-period": 60 } } \ No newline at end of file diff --git a/tests/expected/multi-user-signing/metadata/1.root.json b/tests/expected/multi-user-signing/metadata/1.root.json index 32a1b0c6..1361aee3 100644 --- a/tests/expected/multi-user-signing/metadata/1.root.json +++ b/tests/expected/multi-user-signing/metadata/1.root.json @@ -16,7 +16,7 @@ "public": "-----BEGIN PUBLIC KEY-----\nMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE+jBdFHGUlKUilRL3/ReI6whKNbCZk8CL\nJFGVf5JypwD/2lr7d/6owMGuqd9ocCVVHw2GsuGRS7aCQfEvEsTgal6y2NC2gGpi\n1rsv2TGRzxKeZ7m0yX4h/vXlfJe7xys9\n-----END PUBLIC KEY-----\n" }, "scheme": "ecdsa-sha2-nistp384", - "x-playground-keyowner": "@playgrounduser2" + "x-tuf-on-ci-keyowner": "@tuf-on-ci-user2" }, "95da323daa78f7b2557ae91e23be619ff932f9aec035abd4e40301405b363999": { "keytype": "ecdsa", @@ -24,7 +24,7 @@ "public": "-----BEGIN PUBLIC KEY-----\nMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEJ3pswWmx9Bx2VBcpqaooQFA7dQnhRafh\ntj942eg086x6EMHdfgdox9TbwGm7sU2sn/gyjyDr1ez8Ld2ORnyYJ8cAlegfTqNq\nE0eSrLrb+YpzQJxLwh6qWcSngF99Unft\n-----END PUBLIC KEY-----\n" }, "scheme": "ecdsa-sha2-nistp384", - "x-playground-keyowner": "@playgrounduser1" + "x-tuf-on-ci-keyowner": "@tuf-on-ci-user1" }, "fa47289": { "keytype": "ed25519", @@ -32,7 +32,7 @@ "public": "fa472895c9756c2b9bcd1440bf867d0fa5c4edee79e9792fa9822be3dd6fcbb3" }, "scheme": "ed25519", - "x-playground-online-uri": "envvar:LOCAL_TESTING_KEY" + "x-tuf-on-ci-online-uri": "envvar:LOCAL_TESTING_KEY" } }, "roles": { @@ -47,8 +47,8 @@ "fa47289" ], "threshold": 1, - "x-playground-expiry-period": 365, - "x-playground-signing-period": 60 + "x-tuf-on-ci-expiry-period": 365, + "x-tuf-on-ci-signing-period": 60 }, "targets": { "keyids": [ @@ -62,13 +62,13 @@ "fa47289" ], "threshold": 1, - "x-playground-expiry-period": 2, - "x-playground-signing-period": 1 + "x-tuf-on-ci-expiry-period": 2, + "x-tuf-on-ci-signing-period": 1 } }, "spec_version": "1.0.31", "version": 1, - "x-playground-expiry-period": 365, - "x-playground-signing-period": 60 + "x-tuf-on-ci-expiry-period": 365, + "x-tuf-on-ci-signing-period": 60 } } \ No newline at end of file diff --git a/tests/expected/multi-user-signing/metadata/1.targets.json b/tests/expected/multi-user-signing/metadata/1.targets.json index 2e6b048d..45fb219c 100644 --- a/tests/expected/multi-user-signing/metadata/1.targets.json +++ b/tests/expected/multi-user-signing/metadata/1.targets.json @@ -15,7 +15,7 @@ "spec_version": "1.0.31", "targets": {}, "version": 1, - "x-playground-expiry-period": 365, - "x-playground-signing-period": 60 + "x-tuf-on-ci-expiry-period": 365, + "x-tuf-on-ci-signing-period": 60 } } \ No newline at end of file diff --git a/tests/expected/multi-user-signing/metadata/2.root.json b/tests/expected/multi-user-signing/metadata/2.root.json index 558bb1c9..e42199ff 100644 --- a/tests/expected/multi-user-signing/metadata/2.root.json +++ b/tests/expected/multi-user-signing/metadata/2.root.json @@ -16,7 +16,7 @@ "public": "-----BEGIN PUBLIC KEY-----\nMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE+jBdFHGUlKUilRL3/ReI6whKNbCZk8CL\nJFGVf5JypwD/2lr7d/6owMGuqd9ocCVVHw2GsuGRS7aCQfEvEsTgal6y2NC2gGpi\n1rsv2TGRzxKeZ7m0yX4h/vXlfJe7xys9\n-----END PUBLIC KEY-----\n" }, "scheme": "ecdsa-sha2-nistp384", - "x-playground-keyowner": "@playgrounduser2" + "x-tuf-on-ci-keyowner": "@tuf-on-ci-user2" }, "95da323daa78f7b2557ae91e23be619ff932f9aec035abd4e40301405b363999": { "keytype": "ecdsa", @@ -24,7 +24,7 @@ "public": "-----BEGIN PUBLIC KEY-----\nMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEJ3pswWmx9Bx2VBcpqaooQFA7dQnhRafh\ntj942eg086x6EMHdfgdox9TbwGm7sU2sn/gyjyDr1ez8Ld2ORnyYJ8cAlegfTqNq\nE0eSrLrb+YpzQJxLwh6qWcSngF99Unft\n-----END PUBLIC KEY-----\n" }, "scheme": "ecdsa-sha2-nistp384", - "x-playground-keyowner": "@playgrounduser1" + "x-tuf-on-ci-keyowner": "@tuf-on-ci-user1" }, "fa47289": { "keytype": "ed25519", @@ -32,7 +32,7 @@ "public": "fa472895c9756c2b9bcd1440bf867d0fa5c4edee79e9792fa9822be3dd6fcbb3" }, "scheme": "ed25519", - "x-playground-online-uri": "envvar:LOCAL_TESTING_KEY" + "x-tuf-on-ci-online-uri": "envvar:LOCAL_TESTING_KEY" } }, "roles": { @@ -47,8 +47,8 @@ "fa47289" ], "threshold": 1, - "x-playground-expiry-period": 365, - "x-playground-signing-period": 60 + "x-tuf-on-ci-expiry-period": 365, + "x-tuf-on-ci-signing-period": 60 }, "targets": { "keyids": [ @@ -62,13 +62,13 @@ "fa47289" ], "threshold": 1, - "x-playground-expiry-period": 5, - "x-playground-signing-period": 1 + "x-tuf-on-ci-expiry-period": 5, + "x-tuf-on-ci-signing-period": 1 } }, "spec_version": "1.0.31", "version": 2, - "x-playground-expiry-period": 365, - "x-playground-signing-period": 60 + "x-tuf-on-ci-expiry-period": 365, + "x-tuf-on-ci-signing-period": 60 } } \ No newline at end of file diff --git a/tests/expected/online-version-bump/metadata/1.root.json b/tests/expected/online-version-bump/metadata/1.root.json index 482f07be..47725b06 100644 --- a/tests/expected/online-version-bump/metadata/1.root.json +++ b/tests/expected/online-version-bump/metadata/1.root.json @@ -16,7 +16,7 @@ "public": "-----BEGIN PUBLIC KEY-----\nMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEJ3pswWmx9Bx2VBcpqaooQFA7dQnhRafh\ntj942eg086x6EMHdfgdox9TbwGm7sU2sn/gyjyDr1ez8Ld2ORnyYJ8cAlegfTqNq\nE0eSrLrb+YpzQJxLwh6qWcSngF99Unft\n-----END PUBLIC KEY-----\n" }, "scheme": "ecdsa-sha2-nistp384", - "x-playground-keyowner": "@playgrounduser1" + "x-tuf-on-ci-keyowner": "@tuf-on-ci-user1" }, "fa47289": { "keytype": "ed25519", @@ -24,7 +24,7 @@ "public": "fa472895c9756c2b9bcd1440bf867d0fa5c4edee79e9792fa9822be3dd6fcbb3" }, "scheme": "ed25519", - "x-playground-online-uri": "envvar:LOCAL_TESTING_KEY" + "x-tuf-on-ci-online-uri": "envvar:LOCAL_TESTING_KEY" } }, "roles": { @@ -39,8 +39,8 @@ "fa47289" ], "threshold": 1, - "x-playground-expiry-period": 10, - "x-playground-signing-period": 4 + "x-tuf-on-ci-expiry-period": 10, + "x-tuf-on-ci-signing-period": 4 }, "targets": { "keyids": [ @@ -53,13 +53,13 @@ "fa47289" ], "threshold": 1, - "x-playground-expiry-period": 2, - "x-playground-signing-period": 1 + "x-tuf-on-ci-expiry-period": 2, + "x-tuf-on-ci-signing-period": 1 } }, "spec_version": "1.0.31", "version": 1, - "x-playground-expiry-period": 365, - "x-playground-signing-period": 60 + "x-tuf-on-ci-expiry-period": 365, + "x-tuf-on-ci-signing-period": 60 } } \ No newline at end of file diff --git a/tests/expected/online-version-bump/metadata/1.targets.json b/tests/expected/online-version-bump/metadata/1.targets.json index 3dc90909..30598879 100644 --- a/tests/expected/online-version-bump/metadata/1.targets.json +++ b/tests/expected/online-version-bump/metadata/1.targets.json @@ -11,7 +11,7 @@ "spec_version": "1.0.31", "targets": {}, "version": 1, - "x-playground-expiry-period": 365, - "x-playground-signing-period": 60 + "x-tuf-on-ci-expiry-period": 365, + "x-tuf-on-ci-signing-period": 60 } } \ No newline at end of file diff --git a/tests/expected/root-key-rotation/metadata/1.root.json b/tests/expected/root-key-rotation/metadata/1.root.json index 72b82697..436d49f7 100644 --- a/tests/expected/root-key-rotation/metadata/1.root.json +++ b/tests/expected/root-key-rotation/metadata/1.root.json @@ -16,7 +16,7 @@ "public": "-----BEGIN PUBLIC KEY-----\nMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEJ3pswWmx9Bx2VBcpqaooQFA7dQnhRafh\ntj942eg086x6EMHdfgdox9TbwGm7sU2sn/gyjyDr1ez8Ld2ORnyYJ8cAlegfTqNq\nE0eSrLrb+YpzQJxLwh6qWcSngF99Unft\n-----END PUBLIC KEY-----\n" }, "scheme": "ecdsa-sha2-nistp384", - "x-playground-keyowner": "@playgrounduser1" + "x-tuf-on-ci-keyowner": "@tuf-on-ci-user1" }, "fa47289": { "keytype": "ed25519", @@ -24,7 +24,7 @@ "public": "fa472895c9756c2b9bcd1440bf867d0fa5c4edee79e9792fa9822be3dd6fcbb3" }, "scheme": "ed25519", - "x-playground-online-uri": "envvar:LOCAL_TESTING_KEY" + "x-tuf-on-ci-online-uri": "envvar:LOCAL_TESTING_KEY" } }, "roles": { @@ -39,8 +39,8 @@ "fa47289" ], "threshold": 1, - "x-playground-expiry-period": 365, - "x-playground-signing-period": 60 + "x-tuf-on-ci-expiry-period": 365, + "x-tuf-on-ci-signing-period": 60 }, "targets": { "keyids": [ @@ -53,13 +53,13 @@ "fa47289" ], "threshold": 1, - "x-playground-expiry-period": 2, - "x-playground-signing-period": 1 + "x-tuf-on-ci-expiry-period": 2, + "x-tuf-on-ci-signing-period": 1 } }, "spec_version": "1.0.31", "version": 1, - "x-playground-expiry-period": 365, - "x-playground-signing-period": 60 + "x-tuf-on-ci-expiry-period": 365, + "x-tuf-on-ci-signing-period": 60 } } \ No newline at end of file diff --git a/tests/expected/root-key-rotation/metadata/1.targets.json b/tests/expected/root-key-rotation/metadata/1.targets.json index 3dc90909..30598879 100644 --- a/tests/expected/root-key-rotation/metadata/1.targets.json +++ b/tests/expected/root-key-rotation/metadata/1.targets.json @@ -11,7 +11,7 @@ "spec_version": "1.0.31", "targets": {}, "version": 1, - "x-playground-expiry-period": 365, - "x-playground-signing-period": 60 + "x-tuf-on-ci-expiry-period": 365, + "x-tuf-on-ci-signing-period": 60 } } \ No newline at end of file diff --git a/tests/expected/root-key-rotation/metadata/2.root.json b/tests/expected/root-key-rotation/metadata/2.root.json index 7f7c6f00..717372eb 100644 --- a/tests/expected/root-key-rotation/metadata/2.root.json +++ b/tests/expected/root-key-rotation/metadata/2.root.json @@ -20,7 +20,7 @@ "public": "-----BEGIN PUBLIC KEY-----\nMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE+jBdFHGUlKUilRL3/ReI6whKNbCZk8CL\nJFGVf5JypwD/2lr7d/6owMGuqd9ocCVVHw2GsuGRS7aCQfEvEsTgal6y2NC2gGpi\n1rsv2TGRzxKeZ7m0yX4h/vXlfJe7xys9\n-----END PUBLIC KEY-----\n" }, "scheme": "ecdsa-sha2-nistp384", - "x-playground-keyowner": "@playgrounduser2" + "x-tuf-on-ci-keyowner": "@tuf-on-ci-user2" }, "95da323daa78f7b2557ae91e23be619ff932f9aec035abd4e40301405b363999": { "keytype": "ecdsa", @@ -28,7 +28,7 @@ "public": "-----BEGIN PUBLIC KEY-----\nMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEJ3pswWmx9Bx2VBcpqaooQFA7dQnhRafh\ntj942eg086x6EMHdfgdox9TbwGm7sU2sn/gyjyDr1ez8Ld2ORnyYJ8cAlegfTqNq\nE0eSrLrb+YpzQJxLwh6qWcSngF99Unft\n-----END PUBLIC KEY-----\n" }, "scheme": "ecdsa-sha2-nistp384", - "x-playground-keyowner": "@playgrounduser1" + "x-tuf-on-ci-keyowner": "@tuf-on-ci-user1" }, "fa47289": { "keytype": "ed25519", @@ -36,7 +36,7 @@ "public": "fa472895c9756c2b9bcd1440bf867d0fa5c4edee79e9792fa9822be3dd6fcbb3" }, "scheme": "ed25519", - "x-playground-online-uri": "envvar:LOCAL_TESTING_KEY" + "x-tuf-on-ci-online-uri": "envvar:LOCAL_TESTING_KEY" } }, "roles": { @@ -51,8 +51,8 @@ "fa47289" ], "threshold": 1, - "x-playground-expiry-period": 365, - "x-playground-signing-period": 60 + "x-tuf-on-ci-expiry-period": 365, + "x-tuf-on-ci-signing-period": 60 }, "targets": { "keyids": [ @@ -65,13 +65,13 @@ "fa47289" ], "threshold": 1, - "x-playground-expiry-period": 2, - "x-playground-signing-period": 1 + "x-tuf-on-ci-expiry-period": 2, + "x-tuf-on-ci-signing-period": 1 } }, "spec_version": "1.0.31", "version": 2, - "x-playground-expiry-period": 365, - "x-playground-signing-period": 60 + "x-tuf-on-ci-expiry-period": 365, + "x-tuf-on-ci-signing-period": 60 } } \ No newline at end of file diff --git a/tests/expected/target-file-changes/metadata/1.root.json b/tests/expected/target-file-changes/metadata/1.root.json index 32a1b0c6..1361aee3 100644 --- a/tests/expected/target-file-changes/metadata/1.root.json +++ b/tests/expected/target-file-changes/metadata/1.root.json @@ -16,7 +16,7 @@ "public": "-----BEGIN PUBLIC KEY-----\nMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE+jBdFHGUlKUilRL3/ReI6whKNbCZk8CL\nJFGVf5JypwD/2lr7d/6owMGuqd9ocCVVHw2GsuGRS7aCQfEvEsTgal6y2NC2gGpi\n1rsv2TGRzxKeZ7m0yX4h/vXlfJe7xys9\n-----END PUBLIC KEY-----\n" }, "scheme": "ecdsa-sha2-nistp384", - "x-playground-keyowner": "@playgrounduser2" + "x-tuf-on-ci-keyowner": "@tuf-on-ci-user2" }, "95da323daa78f7b2557ae91e23be619ff932f9aec035abd4e40301405b363999": { "keytype": "ecdsa", @@ -24,7 +24,7 @@ "public": "-----BEGIN PUBLIC KEY-----\nMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEJ3pswWmx9Bx2VBcpqaooQFA7dQnhRafh\ntj942eg086x6EMHdfgdox9TbwGm7sU2sn/gyjyDr1ez8Ld2ORnyYJ8cAlegfTqNq\nE0eSrLrb+YpzQJxLwh6qWcSngF99Unft\n-----END PUBLIC KEY-----\n" }, "scheme": "ecdsa-sha2-nistp384", - "x-playground-keyowner": "@playgrounduser1" + "x-tuf-on-ci-keyowner": "@tuf-on-ci-user1" }, "fa47289": { "keytype": "ed25519", @@ -32,7 +32,7 @@ "public": "fa472895c9756c2b9bcd1440bf867d0fa5c4edee79e9792fa9822be3dd6fcbb3" }, "scheme": "ed25519", - "x-playground-online-uri": "envvar:LOCAL_TESTING_KEY" + "x-tuf-on-ci-online-uri": "envvar:LOCAL_TESTING_KEY" } }, "roles": { @@ -47,8 +47,8 @@ "fa47289" ], "threshold": 1, - "x-playground-expiry-period": 365, - "x-playground-signing-period": 60 + "x-tuf-on-ci-expiry-period": 365, + "x-tuf-on-ci-signing-period": 60 }, "targets": { "keyids": [ @@ -62,13 +62,13 @@ "fa47289" ], "threshold": 1, - "x-playground-expiry-period": 2, - "x-playground-signing-period": 1 + "x-tuf-on-ci-expiry-period": 2, + "x-tuf-on-ci-signing-period": 1 } }, "spec_version": "1.0.31", "version": 1, - "x-playground-expiry-period": 365, - "x-playground-signing-period": 60 + "x-tuf-on-ci-expiry-period": 365, + "x-tuf-on-ci-signing-period": 60 } } \ No newline at end of file diff --git a/tests/expected/target-file-changes/metadata/1.targets.json b/tests/expected/target-file-changes/metadata/1.targets.json index 2e6b048d..45fb219c 100644 --- a/tests/expected/target-file-changes/metadata/1.targets.json +++ b/tests/expected/target-file-changes/metadata/1.targets.json @@ -15,7 +15,7 @@ "spec_version": "1.0.31", "targets": {}, "version": 1, - "x-playground-expiry-period": 365, - "x-playground-signing-period": 60 + "x-tuf-on-ci-expiry-period": 365, + "x-tuf-on-ci-signing-period": 60 } } \ No newline at end of file diff --git a/tests/expected/target-file-changes/metadata/3.targets.json b/tests/expected/target-file-changes/metadata/3.targets.json index 60cfa30c..1c6f67bd 100644 --- a/tests/expected/target-file-changes/metadata/3.targets.json +++ b/tests/expected/target-file-changes/metadata/3.targets.json @@ -22,7 +22,7 @@ } }, "version": 3, - "x-playground-expiry-period": 365, - "x-playground-signing-period": 60 + "x-tuf-on-ci-expiry-period": 365, + "x-tuf-on-ci-signing-period": 60 } } \ No newline at end of file From a0a18f908be31fabccae60765e8a46adb3e70605 Mon Sep 17 00:00:00 2001 From: Jussi Kukkonen Date: Tue, 18 Jul 2023 10:48:32 +0300 Subject: [PATCH 2/7] Add some notes on development setup / tools --- README.md | 1 + docs/DEVELOPMENT.md | 28 ++++++++++++++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 docs/DEVELOPMENT.md diff --git a/README.md b/README.md index 94257cd3..7534ff00 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,7 @@ This is a Work-In-Progress and no stable releases have been made yet. See ## Documentation * [Design document](https://docs.google.com/document/d/140jiFHGc3wwEmNaJmUdgkNeNK4i4CC-lm5-eVQYXiL0/edit?resourcekey=0-CLZhA-H2jtd3WQD-lBLsqQ) +* [Developer notes](docs/DEVELOPMENT.md) ## Setup diff --git a/docs/DEVELOPMENT.md b/docs/DEVELOPMENT.md new file mode 100644 index 00000000..4053b600 --- /dev/null +++ b/docs/DEVELOPMENT.md @@ -0,0 +1,28 @@ +## Developer notes + +A development install can be made in any environment but venv is recommended: + +```shell +# Create environment +python3 -m venv .venv +# Enter environment +source .venv/bin/activate +# install the signing and repository tools as editable +pip install -e signer/ repo/ +# install tox for a reproducible testing environment +pip install tox +``` + +At this point `tuf-on-ci-sign` and other commands are available from the editable install (source code). + +### Running tests and linters + +Tests and lints can be run with tox: + +```shell +# Run all lints +tox -m lint + +# run all tests +tox -m test +``` From f19f395bb0a18e80d88d1f081347681c3c028e5a Mon Sep 17 00:00:00 2001 From: Jussi Kukkonen Date: Tue, 18 Jul 2023 11:07:19 +0300 Subject: [PATCH 3/7] Fix the CI workflow File locations have changed compared to repository-playground --- .github/workflows/ci.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f3a07b98..288f0c88 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -26,13 +26,10 @@ jobs: run: python -m pip install tox - name: Lint - working-directory: playground run: tox -m lint - name: Repository unit tests - working-directory: playground run: tox -e test-repo - name: End-to-end tests - working-directory: playground run: tox -e test-e2e From 4bf66d7dc09d36a758fc43d9684d125fa6d75e02 Mon Sep 17 00:00:00 2001 From: Jussi Kukkonen Date: Tue, 18 Jul 2023 13:28:58 +0300 Subject: [PATCH 4/7] workflows: Set permissions explicitly This is by default on for public repos but not for private ones --- .github/workflows/ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 288f0c88..ee4c5899 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -9,6 +9,8 @@ permissions: {} jobs: build-and-test: runs-on: ubuntu-latest + permissions: + contents: read steps: - uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c From d8520de7dd8c7839cac0cb8143efeedf73a995ee Mon Sep 17 00:00:00 2001 From: Jussi Kukkonen Date: Tue, 18 Jul 2023 13:34:42 +0300 Subject: [PATCH 5/7] Specify a dependency file for actions/setup-python --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ee4c5899..aafaf812 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,6 +18,7 @@ jobs: with: python-version: "3.11" cache: 'pip' + cache-dependency-path: "**/pyproject.toml" - name: Install system dependencies for e2e test run: | From f75fe27688dc6aaacfed99a02ef7445609b619d2 Mon Sep 17 00:00:00 2001 From: Jussi Kukkonen Date: Tue, 18 Jul 2023 14:55:50 +0300 Subject: [PATCH 6/7] docs: Install both signer and repo as editable --- docs/DEVELOPMENT.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/DEVELOPMENT.md b/docs/DEVELOPMENT.md index 4053b600..9051a9fa 100644 --- a/docs/DEVELOPMENT.md +++ b/docs/DEVELOPMENT.md @@ -8,7 +8,7 @@ python3 -m venv .venv # Enter environment source .venv/bin/activate # install the signing and repository tools as editable -pip install -e signer/ repo/ +pip install -e ./signer -e ./repo # install tox for a reproducible testing environment pip install tox ``` From f5d897ec10ece94bf1312525e1eafdaf8678d271 Mon Sep 17 00:00:00 2001 From: Jussi Kukkonen Date: Tue, 18 Jul 2023 14:57:15 +0300 Subject: [PATCH 7/7] repo/tests: One more missing rename This does not affect the test in any way --- repo/test/test_repo1/root.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/repo/test/test_repo1/root.json b/repo/test/test_repo1/root.json index f8f1324a..0f8a7ef3 100644 --- a/repo/test/test_repo1/root.json +++ b/repo/test/test_repo1/root.json @@ -16,7 +16,7 @@ "public": "-----BEGIN PUBLIC KEY-----\nMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEJ3pswWmx9Bx2VBcpqaooQFA7dQnhRafh\ntj942eg086x6EMHdfgdox9TbwGm7sU2sn/gyjyDr1ez8Ld2ORnyYJ8cAlegfTqNq\nE0eSrLrb+YpzQJxLwh6qWcSngF99Unft\n-----END PUBLIC KEY-----\n" }, "scheme": "ecdsa-sha2-nistp384", - "x-tuf-on-ci-keyowner": "@playgrounduser1" + "x-tuf-on-ci-keyowner": "@tuf-on-ci-user1" }, "fa47289": { "keytype": "ed25519",