Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 5 additions & 15 deletions .github/scripts/resolve-staging-deploy.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
set -euo pipefail

: "${GITHUB_OUTPUT:?GITHUB_OUTPUT is required}"
: "${RELEASE_NAME:?RELEASE_NAME is required}"
: "${SYNAPSE_IMAGE_TAG:?SYNAPSE_IMAGE_TAG is required}"
: "${DNS_CNAME_READY:?DNS_CNAME_READY is required}"
: "${CONFIRM_STAGING:?CONFIRM_STAGING is required}"
Expand All @@ -21,6 +20,9 @@ set -euo pipefail
: "${STAGING_GRPC_LISTENER_PORT:?STAGING_KEYSTONE_GRPC_LISTENER_PORT repository or staging environment variable is required}"
: "${STAGING_HILBERT_BASE_URL:?STAGING_KEYSTONE_HILBERT_BASE_URL repository or staging environment variable is required}"

release_name="keystone-staging"
host="${release_name}.archebase.cn"

keystone_image_tag="${KEYSTONE_IMAGE_TAG_INPUT:-}"
if [[ -z "$keystone_image_tag" ]]; then
keystone_image_tag="$(git rev-parse HEAD)"
Expand All @@ -33,18 +35,7 @@ fi

if [[ "$DNS_CNAME_READY" != "true" ]]; then
echo "dnsCnameReady must be true before staging deployment" >&2
echo "Expected CNAME: keystone-staging-${RELEASE_NAME}.archebase.cn -> ${STAGING_ALB_DNS_NAME}" >&2
exit 1
fi

if ! [[ "$RELEASE_NAME" =~ ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ ]]; then
echo "releaseName must match ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$" >&2
exit 1
fi

# The derived keystone-staging-<releaseName> DNS label must stay within 63 bytes.
if [[ "${#RELEASE_NAME}" -gt 46 ]]; then
echo "releaseName must have length of 1-46 characters for the staging hostname" >&2
echo "Expected CNAME: ${host} -> ${STAGING_ALB_DNS_NAME}" >&2
exit 1
fi

Expand Down Expand Up @@ -102,12 +93,11 @@ if ! [[ "$STAGING_HILBERT_BASE_URL" =~ ^https://[^/]*staging[^/]*/.+ ]]; then
exit 1
fi

host="keystone-staging-${RELEASE_NAME}.archebase.cn"
keystone_image="${VOLCENGINE_CR_ENDPOINT}/${KEYSTONE_IMAGE_REPOSITORY}:${keystone_image_tag}"
synapse_image="${VOLCENGINE_CR_ENDPOINT}/${SYNAPSE_IMAGE_REPOSITORY}:${SYNAPSE_IMAGE_TAG}"

{
echo "release_name=${RELEASE_NAME}"
echo "release_name=${release_name}"
echo "host=${host}"
echo "keystone_image_tag=${keystone_image_tag}"
echo "synapse_image_tag=${SYNAPSE_IMAGE_TAG}"
Expand Down
15 changes: 10 additions & 5 deletions .github/scripts/resolve-staging-deploy_test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,22 @@ set -euo pipefail

script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
resolver="$script_dir/resolve-staging-deploy.sh"
workflow="$script_dir/../workflows/deploy-keystone-stack-staging.yml"
test_sha="0123456789abcdef0123456789abcdef01234567"
synapse_sha="89abcdef0123456789abcdef0123456789abcdef"

if grep -Fq "releaseName:" "$workflow" || grep -Fq "inputs.releaseName" "$workflow"; then
echo "staging workflow must not accept a releaseName input" >&2
exit 1
fi
grep -Fxq " group: keystone-staging" "$workflow"

run_resolver() {
local output_file="$1"
shift

env \
GITHUB_OUTPUT="$output_file" \
RELEASE_NAME=mercury \
KEYSTONE_IMAGE_TAG_INPUT="$test_sha" \
SYNAPSE_IMAGE_TAG="$synapse_sha" \
DNS_CNAME_READY=true \
Expand All @@ -37,10 +43,10 @@ run_resolver() {

valid_output="$(mktemp)"
trap 'rm -f "$valid_output" "${case_output:-}"' EXIT
run_resolver "$valid_output"
run_resolver "$valid_output" RELEASE_NAME=legacy-release

grep -Fxq "release_name=mercury" "$valid_output"
grep -Fxq "host=keystone-staging-mercury.archebase.cn" "$valid_output"
grep -Fxq "release_name=keystone-staging" "$valid_output"
grep -Fxq "host=keystone-staging.archebase.cn" "$valid_output"
grep -Fxq "keystone_image=registry.example.com/prod/keystone:$test_sha" "$valid_output"
grep -Fxq "synapse_image=registry.example.com/prod/synapse:$synapse_sha" "$valid_output"

Expand All @@ -60,7 +66,6 @@ expect_failure() {
expect_failure "missing confirmation" CONFIRM_STAGING=wrong
expect_failure "missing DNS confirmation" DNS_CNAME_READY=false
expect_failure "mutable image tag" KEYSTONE_IMAGE_TAG_INPUT=latest
expect_failure "oversized staging hostname" RELEASE_NAME=abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstu
expect_failure "shared HTTPS and gRPC listener" STAGING_GRPC_LISTENER_PORT=443
expect_failure "non-staging ingress class" STAGING_INGRESS_CLASS=keystone-prod
expect_failure "non-staging bucket" STAGING_TOS_BUCKET=archebase-prod-keystone
Expand Down
9 changes: 2 additions & 7 deletions .github/workflows/deploy-keystone-stack-staging.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,11 @@

name: Deploy Keystone Staging

run-name: Deploy Keystone staging ${{ inputs.releaseName }}
run-name: Deploy Keystone staging

on:
workflow_dispatch:
inputs:
releaseName:
description: "Helm release name. Derives keystone-staging-<releaseName>.archebase.cn."
required: true
type: string
keystoneImageTag:
description: "Full Keystone commit SHA image tag. Empty uses the checked-out main-v2 HEAD."
required: false
Expand Down Expand Up @@ -40,7 +36,7 @@ defaults:
shell: bash

concurrency:
group: keystone-staging-${{ inputs.releaseName }}
group: keystone-staging
cancel-in-progress: false

env:
Expand Down Expand Up @@ -94,7 +90,6 @@ jobs:
- name: Resolve and validate staging deployment inputs
id: inputs
env:
RELEASE_NAME: ${{ inputs.releaseName }}
KEYSTONE_IMAGE_TAG_INPUT: ${{ inputs.keystoneImageTag }}
SYNAPSE_IMAGE_TAG: ${{ inputs.synapseImageTag }}
DNS_CNAME_READY: ${{ inputs.dnsCnameReady }}
Expand Down
20 changes: 12 additions & 8 deletions deploy/helm/keystone-stack/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -180,17 +180,21 @@ the IngressClass, TOS bucket, IAM roles, and Hilbert endpoint to identify
staging, then verifies the ALB and workload identity against the staging
cluster before it mutates any Kubernetes resource.

Each release uses a staging-specific hostname that cannot collide with the
production hostname:
Staging uses one fixed Helm release, factory identifier, and hostname:

```text
keystone-staging-<releaseName>.archebase.cn
keystone-staging.archebase.cn
```

`releaseName` must contain 1–46 lowercase alphanumeric or hyphen characters.
The workflow does not accept a staging release name. Helm release name and
`KEYSTONE_FACTORY_ID` are both fixed to `keystone-staging`.
The release name `staging` is reserved from production deployments and must
not be passed to the production workflow, because production would derive the
same hostname. The `keystone-staging.archebase.cn` CNAME must always point to
the staging ALB identified by `STAGING_KEYSTONE_ALB_DNS_NAME`.
`keystoneImageTag` may be empty to select the checked-out `main-v2` HEAD;
`synapseImageTag` must be supplied explicitly. Both resolved image tags must be
full 40-character lowercase commit SHAs.
`synapseImageTag` must be supplied explicitly. Both resolved image tags must
be full 40-character lowercase commit SHAs.

Before dispatching the workflow, create the GitHub `staging` environment and
restrict it to the intended reviewers and `main-v2`, then configure these
Expand Down Expand Up @@ -231,7 +235,7 @@ The staging cluster must already contain:
gRPC port configured in `STAGING_KEYSTONE_GRPC_LISTENER_PORT`;
- a staging TOS bucket plus upload and read roles that the Keystone workload
identity can assume;
- a CNAME from the derived staging hostname to
- a CNAME from `keystone-staging.archebase.cn` to
`STAGING_KEYSTONE_ALB_DNS_NAME`.

The workflow creates or updates only the application-owned
Expand Down Expand Up @@ -265,7 +269,7 @@ connect to the corresponding environment endpoint:

```text
production: keystone-<releaseName>.archebase.cn:50053
staging: keystone-staging-<releaseName>.archebase.cn:<STAGING_KEYSTONE_GRPC_LISTENER_PORT>
staging: keystone-staging.archebase.cn:<STAGING_KEYSTONE_GRPC_LISTENER_PORT>
```

## S3 Override
Expand Down
Loading