2 changed files with 305 additions and 0 deletions
@ -0,0 +1,300 @@ |
|||
# Serverless release runbook |
|||
|
|||
Use this runbook to upgrade this fork to a tagged Vaultwarden release and |
|||
deploy it to the existing AWS serverless stack. It is written for an agent or |
|||
operator starting from any branch in a possibly dirty worktree. |
|||
|
|||
Loading this runbook does not authorize a deployment, history rewrite, or |
|||
other external mutation. Confirm that the user's request includes each action |
|||
before doing it. |
|||
|
|||
## Deployment shape |
|||
|
|||
The branch and runtime layers are ordered as follows: |
|||
|
|||
```text |
|||
upstream release tag |
|||
-> aws-ses (AWS HTTP integration and SES) |
|||
-> main (Aurora DSQL and Lambda deployment) |
|||
``` |
|||
|
|||
Production uses: |
|||
|
|||
- AWS profile `vaultwarden`. |
|||
- The stack name and region in `aws/samconfig.toml`. |
|||
- An ARM64 Lambda package built by `aws/build-lambda.sh`. |
|||
- A static web vault in the `WebVaultAssetsBucket` stack output. |
|||
- The web-vault version pinned by `docker/DockerSettings.yaml` at the release |
|||
tag. Do not substitute the newest web-vault release. |
|||
|
|||
Never infer account IDs, bucket names, function names, or CloudFront IDs from |
|||
old output. Resolve them from CloudFormation on every run. |
|||
|
|||
## 1. Inventory and protect local state |
|||
|
|||
From the repository root, record: |
|||
|
|||
```sh |
|||
git status --short --branch |
|||
git remote -v |
|||
git branch -vv |
|||
git log --graph --decorate --oneline --all -30 |
|||
``` |
|||
|
|||
The expected remotes are `upstream` for `dani-garcia/vaultwarden` and `origin` |
|||
for this fork. Stop if either URL is unexpected. |
|||
|
|||
Preserve all existing changes before switching branches. Prefer a named stash |
|||
that includes untracked files, then record its object ID. Do not discard, |
|||
overwrite, or accidentally commit operator files such as |
|||
`aws/samconfig.toml` or database dumps. |
|||
|
|||
```sh |
|||
git stash push --include-untracked --message "operator state before release" |
|||
git stash list --format='%gd %H %s' -1 |
|||
``` |
|||
|
|||
If the tree was already clean, no stash is created. Do not assume an older |
|||
`stash@{0}` belongs to this run. |
|||
|
|||
## 2. Authenticate the release |
|||
|
|||
Set the requested release, fetch only from the upstream repository, and read |
|||
the immutable GitHub release notes: |
|||
|
|||
```sh |
|||
release_version=1.37.2 |
|||
git fetch upstream "refs/tags/${release_version}:refs/tags/${release_version}" \ |
|||
refs/heads/main:refs/remotes/upstream/main |
|||
gh release view "${release_version}" --repo dani-garcia/vaultwarden |
|||
git show --no-patch --format=fuller "${release_version}" |
|||
``` |
|||
|
|||
Confirm that the tag is annotated, identifies the expected release commit, |
|||
and is the immutable non-prerelease requested by the user. Run |
|||
`git tag -v "$release_version"` when GPG and the maintainer key are available. |
|||
If local signature verification is unavailable, explicitly record that fact; |
|||
do not describe the signature as locally verified. |
|||
|
|||
Read the pinned web-vault version before changing branches: |
|||
|
|||
```sh |
|||
git show "${release_version}:docker/DockerSettings.yaml" |
|||
``` |
|||
|
|||
## 3. Rebase the branch stack |
|||
|
|||
Fetch `origin` immediately before rewriting and record its branch tips. These |
|||
object IDs become the force-with-lease expectations. |
|||
|
|||
```sh |
|||
git fetch origin aws-ses main |
|||
old_aws_ses=$(git rev-parse aws-ses) |
|||
old_main=$(git rev-parse main) |
|||
origin_aws_ses=$(git rev-parse origin/aws-ses) |
|||
origin_main=$(git rev-parse origin/main) |
|||
``` |
|||
|
|||
Create uniquely named local recovery branches. Never overwrite an existing |
|||
backup branch. |
|||
|
|||
```sh |
|||
git branch "backup-aws-ses-pre-${release_version}" "${old_aws_ses}" |
|||
git branch "backup-main-pre-${release_version}" "${old_main}" |
|||
``` |
|||
|
|||
Rebase the AWS integration layer first: |
|||
|
|||
```sh |
|||
git switch aws-ses |
|||
git rebase "${release_version}" |
|||
``` |
|||
|
|||
Resolve conflicts by preserving the upstream behavior and reapplying only the |
|||
OpenDAL transport, shared AWS HTTP client integration, and SES transport. |
|||
Review each complete resulting commit, not just conflict markers. |
|||
|
|||
Replay only the commits that were above the old `aws-ses` tip onto its new tip: |
|||
|
|||
```sh |
|||
git switch main |
|||
git rebase --onto aws-ses "${old_aws_ses}" |
|||
``` |
|||
|
|||
This form avoids replaying the old AWS integration commits as part of `main`. |
|||
Restore the operator stash only after both rebases finish and the worktree is |
|||
back on `main`. Resolve a stash conflict without losing either version. |
|||
|
|||
Review these invariants before building: |
|||
|
|||
```sh |
|||
git merge-base --is-ancestor "${release_version}" aws-ses |
|||
git merge-base --is-ancestor aws-ses main |
|||
git log --oneline "${release_version}..aws-ses" |
|||
git log --oneline "aws-ses..main" |
|||
git diff --check "${release_version}..main" |
|||
git status --short --branch |
|||
``` |
|||
|
|||
The release-to-`aws-ses` range should contain the upstreamable OpenDAL HTTP |
|||
transport, the separate AWS connector fix, and the SES layer unless the |
|||
release already includes any of them. The `aws-ses`-to-`main` range should |
|||
contain the DSQL, Lambda deployment, and release documentation commits. |
|||
|
|||
## 4. Validate and publish source |
|||
|
|||
Run formatting and an AWS-feature compile check before the packaging build: |
|||
|
|||
```sh |
|||
cargo fmt --all -- --check |
|||
cargo check --locked --features aws |
|||
``` |
|||
|
|||
The S3 feature deliberately injects Vaultwarden's HTTP client into OpenDAL's |
|||
reqwest transport. If the rebase changes OpenDAL, confirm that each S3 |
|||
operator still receives that transport in an `OperationContext`. A compile |
|||
check covers the trait API, but an S3 smoke test is still needed to detect |
|||
runtime routing failures. Both the OpenDAL and AWS SDK transports should |
|||
continue to use `get_reqwest_client_builder(false)` so they inherit the shared |
|||
HTTP policy and standard ten-second deadline. |
|||
|
|||
Build from `main`, test the archive, and record its checksum: |
|||
|
|||
```sh |
|||
./aws/build-lambda.sh |
|||
unzip -t aws/vaultwarden-lambda.zip |
|||
shasum -a 256 aws/vaultwarden-lambda.zip |
|||
``` |
|||
|
|||
The build script and its GitHub workflow must invoke `cargo lambda build` with |
|||
the `aws` feature. Stop and fix the build configuration if they do not. |
|||
|
|||
Fetch `origin` again immediately before pushing. Publish rebased history only |
|||
with explicit leases recorded above; a lease failure means someone else |
|||
updated the branch, so stop and reconcile rather than retrying blindly. |
|||
|
|||
```sh |
|||
git fetch origin aws-ses main |
|||
git push --force-with-lease="aws-ses:${origin_aws_ses}" \ |
|||
origin aws-ses:aws-ses |
|||
git push --force-with-lease="main:${origin_main}" origin main:main |
|||
``` |
|||
|
|||
## 5. Create and review the deployment changeset |
|||
|
|||
Confirm AWS identity, stack health, and live versions before mutation: |
|||
|
|||
```sh |
|||
aws sts get-caller-identity --profile vaultwarden |
|||
aws cloudformation describe-stacks --profile vaultwarden \ |
|||
--stack-name vaultwarden |
|||
curl -fsS https://vault.chasedouglas.net/api/config |
|||
curl -fsS https://vault.chasedouglas.net/vw-version.json |
|||
``` |
|||
|
|||
Resolve the actual stack name and region from `aws/samconfig.toml` if they are |
|||
not `vaultwarden` and `us-east-2`. Do not commit that file merely to perform a |
|||
release. |
|||
|
|||
Build the SAM staging directory and create, but do not yet execute, a |
|||
changeset. Explicitly override the local `disable_rollback` setting: |
|||
|
|||
```sh |
|||
cd aws |
|||
sam build |
|||
sam deploy --profile vaultwarden --no-execute-changeset \ |
|||
--no-confirm-changeset --no-disable-rollback |
|||
``` |
|||
|
|||
Capture the exact changeset ARN printed by SAM. Inspect it with |
|||
`aws cloudformation describe-change-set` and confirm: |
|||
|
|||
- The stack name, account, and region are correct. |
|||
- There are no replacements or deletions. |
|||
- The expected Lambda code/configuration is the only material runtime change, |
|||
unless the upstream rebase intentionally changed the template. |
|||
- Parameter values match the existing stack. No blank local value silently |
|||
replaces a production setting. |
|||
|
|||
Stop if the changeset differs from those expectations. |
|||
|
|||
## 6. Execute and verify the backend |
|||
|
|||
Execute the exact reviewed changeset, wait for completion, and inspect stack |
|||
events if it fails: |
|||
|
|||
```sh |
|||
aws cloudformation execute-change-set --profile vaultwarden \ |
|||
--change-set-name CHANGESET_ARN |
|||
aws cloudformation wait stack-update-complete --profile vaultwarden \ |
|||
--stack-name vaultwarden |
|||
``` |
|||
|
|||
Verify that `/api/config` reports the new `main` commit hash and expected |
|||
compatibility version. Query recent Lambda logs for startup panics or request |
|||
errors. Do not rely on a successful CloudFormation status alone. |
|||
|
|||
## 7. Update the compatible web vault |
|||
|
|||
Extract `vault_version` from `docker/DockerSettings.yaml` on the deployed |
|||
`main` branch. Remove its leading `v` only for the JSON version comparison. |
|||
|
|||
Inspect the immutable release and download its tarball, checksum manifest, and |
|||
detached signature from `dani-garcia/bw_web_builds`. Verify the entire checksum |
|||
manifest before extraction. Reject archives containing absolute paths, |
|||
parent-directory traversal, or symlinks. |
|||
|
|||
Resolve current resource IDs: |
|||
|
|||
```sh |
|||
aws cloudformation describe-stacks --profile vaultwarden \ |
|||
--stack-name vaultwarden |
|||
aws cloudformation describe-stack-resource --profile vaultwarden \ |
|||
--stack-name vaultwarden --logical-resource-id CDN |
|||
``` |
|||
|
|||
If the live `vw-version.json` already matches the pinned version, do not |
|||
rewrite the bucket. Otherwise: |
|||
|
|||
1. Download the current bucket into a newly created temporary rollback |
|||
directory. |
|||
2. Compare the rollback copy with the extracted release by content. Do not |
|||
trust `aws s3 sync` as a byte comparison: a changed file with the same size |
|||
is skipped when the release archive's timestamp is older than S3. Normalize |
|||
timestamps in the temporary extracted copy, or otherwise force every |
|||
content difference to appear in the dry run. |
|||
3. Run `aws s3 sync ... --delete --dryrun` and inspect uploads and deletions. |
|||
4. Sync the extracted `web-vault/` directory with `--delete`. |
|||
5. Repeat the dry run with `--size-only`; it must report no changes. Download |
|||
the resulting bucket into a separate temporary directory and compare the |
|||
complete directory with the extracted release byte for byte. |
|||
6. Invalidate `/*` on the resolved CloudFront distribution and wait for it. |
|||
7. Verify the public version marker, `index.html`, primary JavaScript bundle, |
|||
and WASM module against the release artifact byte for byte. |
|||
|
|||
Keep the rollback directory until all live checks succeed. Never use a bucket |
|||
name or distribution ID copied from an earlier release. |
|||
|
|||
## 8. Finish and clean up |
|||
|
|||
Record: |
|||
|
|||
- Release tag and commit. |
|||
- New `aws-ses` and `main` tips. |
|||
- Lambda package SHA-256. |
|||
- CloudFormation changeset ARN and final stack status. |
|||
- Backend compatibility version and live `gitHash`. |
|||
- Pinned and live web-vault versions. |
|||
- CloudFront invalidation ID, if one was needed. |
|||
- Any verification that could not be performed. |
|||
|
|||
After successful verification, remove only generated artifacts and temporary |
|||
directories created by this run, including `target/`, `aws/.aws-sam/`, the |
|||
Lambda ZIP, downloaded web-vault files, and rollback copies. Do not delete |
|||
operator files or prune shared Docker caches unless the user separately asks |
|||
for that cleanup. |
|||
|
|||
If production verification fails, retain rollback material, stop cleanup, and |
|||
report the exact failure. Use the backup branches for source recovery. Restore |
|||
the previous Lambda package or web-vault bucket contents only with explicit |
|||
authorization for that rollback. |
|||
Loading…
Reference in new issue