diff --git a/.github/workflows/sync-ceremony-to-main.yml b/.github/workflows/sync-ceremony-to-main.yml index b7dd0fd1..58ffed4a 100644 --- a/.github/workflows/sync-ceremony-to-main.yml +++ b/.github/workflows/sync-ceremony-to-main.yml @@ -13,9 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. -# This workflow is triggered when a ceremony branch is completed, and will: -# - Create a PR that merges the completed ceremony branch to main -# - Sync the ceremony branch to the GCS preprod bucket +# This workflow is triggered when a ceremony branch is completed, +# creating a PR that merges the completed ceremony branch to main name: Sync Published Ceremony Branch to Main and Preprod @@ -23,8 +22,6 @@ name: Sync Published Ceremony Branch to Main and Preprod permissions: {} on: - schedule: - - cron: '0 */12 * * *' # every 12 hours workflow_dispatch: inputs: branch: @@ -63,73 +60,9 @@ jobs: pr_body: "Merge ceremony branch to main" pr_reviewer: bobcallaway,haydentherapper,joshuagl,kommendorkapten - sync: - permissions: - id-token: 'write' - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 - with: - fetch-depth: 0 - - uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0 - with: - go-version-file: './go.mod' - check-latest: true - # Setup OIDC->SA auth - - uses: google-github-actions/auth@55bd3a7c6e2ae7cf1877fd1ccb9d54c0503c457c # v2.1.2 - id: auth - with: - token_format: 'access_token' - workload_identity_provider: 'projects/306323169285/locations/global/workloadIdentityPools/github-actions-pool/providers/github-actions-provider' - service_account: 'tuf-gha@project-rekor.iam.gserviceaccount.com' - create_credentials_file: true - - uses: google-github-actions/setup-gcloud@98ddc00a17442e89a24bbf282954a3b65ce6d200 # v2.1.0 - with: - project_id: project-rekor - - name: Login - run: | - gcloud auth login --brief --cred-file="${{ steps.auth.outputs.credentials_file_path }}" - gcloud auth list - # sync - - name: sync - run: | - check_expiration() { - expiry=$(jq -r '.signed.expires' $1) - expires=$(date -d $expiry +%s) - current=$(date +%s) - if (( expires < current )); then - echo "Detected expired metadata file $1 at $expiry!" - exit 1 - fi; - } - # Upload all but TUF timestamp. Once timestamp is uploaded, all other files must have been uploaded. - for f in $(ls repository/repository/ -I *timestamp.json) - do - # Check for expiration if this is a non-versioned metadata file. - # Versioned metadata like 1.root.json may be expired. - # TODO(asraa): When consistent snapshots are enabled, this logic must be changed so that - # only old versioned metadata can be expired. - if [[ $f == [^0-9]*.json ]]; then - check_expiration repository/repository/$f - fi; - gcloud --quiet storage cp --cache-control=no-store -r repository/repository/$f gs://sigstore-preprod-tuf-root/ - done - # Upload timestamp after checking latest timestamp expiration - check_expiration repository/repository/timestamp.json - gcloud --quiet storage cp --cache-control=no-store -r repository/repository/*timestamp.json gs://sigstore-preprod-tuf-root/ - # delete any files present in sigstore-preprod-tuf-root not in repository/repository - gcloud --quiet storage cp -r gs://sigstore-preprod-tuf-root/ . - diff -qr repository/repository sigstore-preprod-tuf-root | while read l; do - if [[ $l =~ "Only in sigstore-preprod-tuf-root" ]]; then - path=$(python3 -c "import re; s='$l'; pattern=r'^Only in sigstore-preprod-tuf-root(\/?)(.*): (.*)$'; match=re.search(pattern, s); print('/'.join([match.group(2), match.group(3)]).lstrip('/'))") - gcloud --quiet storage rm gs://sigstore-preprod-tuf-root/$path - fi; - done - gcloud compute url-maps invalidate-cdn-cache tuf-preprod-repo-cdn-lb --path "/*" --async - if-failed: runs-on: ubuntu-latest - needs: [sync] + needs: [push] permissions: issues: 'write' actions: 'read' diff --git a/.github/workflows/sync-main-to-preprod.yml b/.github/workflows/sync-main-to-preprod.yml new file mode 100644 index 00000000..a0d9eaac --- /dev/null +++ b/.github/workflows/sync-main-to-preprod.yml @@ -0,0 +1,109 @@ +# +# Copyright 2024 The Sigstore Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# This workflow is triggered a root signing completes and is merged +# into main, syncing the repository to the GCS preprod bucket + +name: Sync Published Root Signing to Preprod + +# Declare default permissions as none. +permissions: {} + +on: + workflow_dispatch: + push: + # When a root signing ceremony completes + branches: + - main + paths: + - 'repository/repository/root.json' + +jobs: + sync: + permissions: + id-token: 'write' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 + with: + fetch-depth: 0 + - uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0 + with: + go-version-file: './go.mod' + check-latest: true + # Setup OIDC->SA auth + - uses: google-github-actions/auth@55bd3a7c6e2ae7cf1877fd1ccb9d54c0503c457c # v2.1.2 + id: auth + with: + token_format: 'access_token' + workload_identity_provider: 'projects/306323169285/locations/global/workloadIdentityPools/github-actions-pool/providers/github-actions-provider' + service_account: 'tuf-gha@project-rekor.iam.gserviceaccount.com' + create_credentials_file: true + - uses: google-github-actions/setup-gcloud@98ddc00a17442e89a24bbf282954a3b65ce6d200 # v2.1.0 + with: + project_id: project-rekor + - name: Login + run: | + gcloud auth login --brief --cred-file="${{ steps.auth.outputs.credentials_file_path }}" + gcloud auth list + # sync + - name: sync + run: | + check_expiration() { + expiry=$(jq -r '.signed.expires' $1) + expires=$(date -d $expiry +%s) + current=$(date +%s) + if (( expires < current )); then + echo "Detected expired metadata file $1 at $expiry!" + exit 1 + fi; + } + # Upload all but TUF timestamp. Once timestamp is uploaded, all other files must have been uploaded. + for f in $(ls repository/repository/ -I *timestamp.json) + do + # Check for expiration if this is a non-versioned metadata file. + # Versioned metadata like 1.root.json may be expired. + # TODO(asraa): When consistent snapshots are enabled, this logic must be changed so that + # only old versioned metadata can be expired. + if [[ $f == [^0-9]*.json ]]; then + check_expiration repository/repository/$f + fi; + gcloud --quiet storage cp --cache-control=no-store -r repository/repository/$f gs://sigstore-preprod-tuf-root/ + done + # Upload timestamp after checking latest timestamp expiration + check_expiration repository/repository/timestamp.json + gcloud --quiet storage cp --cache-control=no-store -r repository/repository/*timestamp.json gs://sigstore-preprod-tuf-root/ + # delete any files present in sigstore-preprod-tuf-root not in repository/repository + gcloud --quiet storage cp -r gs://sigstore-preprod-tuf-root/ . + diff -qr repository/repository sigstore-preprod-tuf-root | while read l; do + if [[ $l =~ "Only in sigstore-preprod-tuf-root" ]]; then + path=$(python3 -c "import re; s='$l'; pattern=r'^Only in sigstore-preprod-tuf-root(\/?)(.*): (.*)$'; match=re.search(pattern, s); print('/'.join([match.group(2), match.group(3)]).lstrip('/'))") + gcloud --quiet storage rm gs://sigstore-preprod-tuf-root/$path + fi; + done + gcloud compute url-maps invalidate-cdn-cache tuf-preprod-repo-cdn-lb --path "/*" --async + + if-failed: + runs-on: ubuntu-latest + needs: [sync] + permissions: + issues: 'write' + actions: 'read' + if: always() && needs.sync.result == 'failure' + steps: + - name: Open issue or add comment on failure + uses: sigstore/sigstore-probers/.github/actions/open-workflow-issue@main + with: + comment_for_each_failure: true diff --git a/playbooks/ORCHESTRATION.md b/playbooks/ORCHESTRATION.md index c325a87e..9d3e1b68 100644 --- a/playbooks/ORCHESTRATION.md +++ b/playbooks/ORCHESTRATION.md @@ -389,21 +389,23 @@ required. ## Step 7: Publication -Once the PR from [Step 3](#step-3-snapshotting-and-timestamping) is merged, a [workflow](../.github/workflows/sync-ceremony-to-main.yml) will automatically create a PR merging the changes on the completed ceremony branch to main. +Once the PR from [Step 6](#step-6-snapshotting-and-timestamping) is merged, a [workflow](../.github/workflows/sync-ceremony-to-main.yml) will automatically create a PR merging the changes on the completed ceremony branch to main. -Submitting this PR will trigger a push to the preproduction GCS bucket, so ensure that this PR is verified and ready to be pushed! +Submitting this PR will trigger [a workflow](../.github/workflows/sync-main-to-preprod.yml) to push to the preproduction GCS bucket for further testing, so ensure that this PR is verified and ready to be pushed! ## Post-ceremony Steps -1. The preproduction GCS bucket will need to be manually synced to the GCS production bucket as of [916](https://github.com/sigstore/root-signing/pull/916). +1. Perform manual testing against the preproduction environment. Assuming no issues, continue with the following steps. -2. If any root keyholders have changed, update the [current root keyholders](https://github.com/sigstore/root-signing#current-sigstore-root-keyholders) with their name, key ID, and location of their key material. +1. To push to the production environment, run [this workflow](../.github/workflows/sync-preprod-to-prod.yml), which syncs the preproduction and production GCS buckets. -3. If any targets have changed, update them and their usage in the table containing the [repository structure](https://github.com/sigstore/root-signing#tuf-repository-structure). +1. If any root keyholders have changed, update the [current root keyholders](https://github.com/sigstore/root-signing#current-sigstore-root-keyholders) with their name, key ID, and location of their key material. -4. Announce the root rotation on twitter and the community meeting, and thank the keyholders! +1. If any targets have changed, update them and their usage in the table containing the [repository structure](https://github.com/sigstore/root-signing#tuf-repository-structure). -5. Schedule the next root signing event one month before expiration on the calendar. Check [here](https://github.com/sigstore/root-signing/blob/e3f1fe5e487984f525afc81ac77fa5ce39737d0f/cmd/tuf/app/init.go#L29) for root expiration. Schedule a testing event for the week before. +1. Announce the root rotation on twitter and the community meeting, and thank the keyholders! + +1. Schedule the next root signing event one month before expiration on the calendar. Check [here](https://github.com/sigstore/root-signing/blob/e3f1fe5e487984f525afc81ac77fa5ce39737d0f/cmd/tuf/app/init.go#L29) for root expiration. Schedule a testing event for the week before. ### Other