Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Trigger preproduction sync only after merge to main #1170

Merged
merged 1 commit into from Mar 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
73 changes: 3 additions & 70 deletions .github/workflows/sync-ceremony-to-main.yml
Expand Up @@ -13,18 +13,15 @@
# 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

# Declare default permissions as none.
permissions: {}

on:
schedule:
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kommendorkapten any reason you think this is needed? i don't see why we need to continually try to sync

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the idea is to open a PR automatically when the ceremony branch is ready, but I think that's quite unnecessary, it's trivial to open that PR manually so I'm in favour of dropping this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is already covered under the push condition, once the ceremony branch is created and pushed to.

- cron: '0 */12 * * *' # every 12 hours
workflow_dispatch:
inputs:
branch:
Expand Down Expand Up @@ -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'
Expand Down
109 changes: 109 additions & 0 deletions .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
16 changes: 9 additions & 7 deletions playbooks/ORCHESTRATION.md
Expand Up @@ -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

Expand Down