Skip to content

Run Library migrations on the deployment candidate - #193

Open
takanorifukuyama wants to merge 1 commit into
mainfrom
feature/library-candidate-migration-hook
Open

Run Library migrations on the deployment candidate#193
takanorifukuyama wants to merge 1 commit into
mainfrom
feature/library-candidate-migration-hook

Conversation

@takanorifukuyama

Copy link
Copy Markdown
Contributor

Summary

  • replace the dedicated lambda-library-api-migrate pre-deploy invocation with a candidate API migration gate
  • add a bearer-authenticated POST /internal/deploy/migrate endpoint and call it from the production candidate lifecycle hook before Alias promotion
  • remove the dedicated migration Lambda build target/script and document the deployment contract in ADR-0007
  • bump library-api from 1.11.2 on origin/main to 1.11.3 (patch)

Root cause

The dedicated migration Lambda reused a warm execution environment and attempted to initialize the global tracing subscriber again. Its second invocation panicked, which prevented the otherwise successful Library API build from being promoted to production.

The generic command pre-deploy JobRun has neither repository checkout nor the API build artifact, so it cannot run the Rust/SQLx migration directly. The candidate API carries the exact migration set for its build and is available before production Alias promotion, making the lifecycle hook a pre-release gate.

Validation

  • cargo +nightly-2026-06-04 fmt --all -- --check
  • cargo +nightly-2026-06-04 test -p library-api --lib --no-default-features — 105 passed, 3 ignored
  • focused deploy bearer-auth tests — 2 passed
  • cargo +nightly-2026-06-04 clippy -p library-api --no-default-features --all-targets -- -D warnings
  • cargo +nightly-2026-06-04 build -p library-api --bin lambda-library-api --no-default-features
  • production manifest dry-run — valid, dedicated hook secret reference resolved
  • secret-value scan — clean; only secret references are committed

Production follow-up after merge

  • verify the candidate migration hook succeeds
  • verify the production Alias is promoted to the new Version
  • verify /version reports 1.11.3
  • use Playwright to sign in as the test user and create an organization

Production verification is intentionally pending because this commit has not yet been merged into the production branch.

Docs

  • docs/specs/decisions/ADR-0007-library-candidate-migration-gate.md
  • docs/src/tasks/completed/v1.11.3/library-candidate-migration-hook/verification-report.md

@tachyon-cloud

tachyon-cloud Bot commented Aug 5, 2026

Copy link
Copy Markdown

Tachyon Preview

App Preview URL Status Last updated SHA Build D1
library-client https://pr193--library-client.txcloud.app Skipped(reused) 2026-08-08T06:41:41.529514363+00:00 c04e2a9 - -

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c04e2a992d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

else {
return false;
};
constant_time_compare(provided.as_bytes(), expected.as_bytes())

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Reject blank deploy hook tokens

When LIBRARY_DEPLOY_HOOK_TOKEN is present but empty, a request with Authorization: Bearer reaches this comparison with both byte slices empty, so the public deploy-migration endpoint authorizes and runs production migrations with a trivially guessable token. Treat an empty expected token the same as missing configuration before comparing.

Useful? React with 👍 / 👎.

Comment thread apps/api/src/router.rs
Comment on lines +544 to +547
.route(
"/internal/deploy/migrate",
post(handler::deploy::run_migrations),
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Keep schema creation off the booted API path

In a fresh or recovered production database where library or tachyon_apps_database_manager does not exist yet, this hook can never reach run_migrations: the normal Lambda entrypoint constructs database-manager state and router() opens pools against those schemas before this route is available, while the migration runner is the code that would create them. The previous dedicated migration Lambda could connect to the admin DSN first, but invoking the fully booted candidate API deadlocks first-time/schema-recovery deploys on the missing database.

Useful? React with 👍 / 👎.

Comment thread tachyon.yaml
run: >-
set -eu;
wget --quiet --output-document=/dev/null
--header="Authorization: Bearer $LIBRARY_DEPLOY_HOOK_TOKEN"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Avoid putting the hook bearer token in argv

In the production hook, the shell expands $LIBRARY_DEPLOY_HOOK_TOKEN into wget's --header argument, so every hook run places the token that authorizes the public migration endpoint in the process command line, where hook-runner diagnostics or process-list capture can expose it. Pass the header through a protected temporary config/file descriptor instead of argv so the secret stays out of command metadata.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant