From d1ed765d522b913dc784c18b1232f5f18aed3ebc Mon Sep 17 00:00:00 2001 From: VikramChennai Date: Fri, 1 May 2026 13:21:52 -0700 Subject: [PATCH] docs: security, architecture, and CI/CD updates - Security: minimal production footprint (not read-only), encryption and secrets section, BYOC framing, control plane language - Architecture: shared storage via copy-on-write for efficient scale - CI/CD: full validated workflow, Claude snippet, deterministic project/connector, compared-to section with production data and efficiency - Sidebar: Examples renamed to Workflows - Added .gitignore for node_modules Co-authored-by: Cursor --- .gitignore | 1 + architecture.mdx | 11 ++-- index.mdx | 76 ++++++++++++----------- security.mdx | 16 ++--- workflows/ci-cd.mdx | 146 +++++++++++++++++++++++++++++++++++++------- 5 files changed, 177 insertions(+), 73 deletions(-) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c2658d7 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +node_modules/ diff --git a/architecture.mdx b/architecture.mdx index 389aa07..2c0da0d 100644 --- a/architecture.mdx +++ b/architecture.mdx @@ -3,10 +3,10 @@ title: "Architecture" description: "How Ardent's split-plane architecture keeps your data safe and your branches fast" --- -Ardent follows a split-plane architecture where the **control plane** and **data plane** are separated: +Ardent follows a split-plane architecture like databricks where the **control plane** and **data plane** are separated: - **Control plane:** Operated by Ardent. Handles branch orchestration, replication health monitoring, connection routing, auto-scaling, and policy enforcement. Spans across all deployments. -- **Data plane:** Where your data lives. The Ardent Replicator syncs from your production database via a Kafka pipeline into a read replica. **Branches** are isolated Postgres databases created from that replica, each with **auto-scaling compute** and its own storage. +- **Data plane:** Where your data lives. Includes the ardent replicator, kafka, your read replica, cloned databases and more. Can be deployed on your cloud or ours. Only metadata (schema structure, replication status, branch state) flows from the data plane to the control plane. Your actual data never leaves the data plane. @@ -18,6 +18,7 @@ flowchart TB subgraph CP["Control plane"] direction TB ORCH["Branch orchestration"] + PRXY["Branch proxy"] ROUTE["Connection routing"] HEALTH["Health and WAL monitoring"] POL["Policies and auth"] @@ -37,7 +38,7 @@ flowchart TB Always operated by Ardent. Orchestration, policies, routing, and visibility across every branch and connection. -- **Branch lifecycle:** Create, suspend, delete, and route traffic to the right branch. Connection URLs go through Ardent so every session is tied to an account and can enforce rules, hooks, and policies. +- **Branch lifecycle:** Create, suspend, delete, and route traffic to the right branch. Connection URLs go through Ardent's proxy so every session is tied to an account and can enforce rules, hooks, and policies as well as prevent leakage of raw URLs for safety. - **Replication coordination:** Monitors health, lag, and pipeline status from metadata; scales and manages the Kafka layer that backs replication so you are not sizing or operating brokers yourself. - **Connector setup:** Discovery and validation when you connect a database, plus connector-scoped settings such as default database and branch SQL hooks. - **Auth, usage, and billing:** Org access, API keys, and metering. Per-user and per-branch visibility Postgres does not give you out of the box. @@ -53,8 +54,8 @@ Where your data physically lives and where branches are served from. Runs on Ard - Manages WAL and slot pressure so replication does not destabilize the primary. - Quarantines, resumes, and recovers broken streams without manual replay scripts. - **Read replica:** Stays in sync with production; branches are always created from the replica, never from production directly, so branch load never hits your primary. -- **Branches (compute and storage):** Each branch is a full Postgres instance with **compute that auto-scales with load**. Storage is built on the same replica snapshot so new branches stay fast to create at any data size and stay inexpensive when idle, while queries and connections run on elastic branch compute. -- **Isolation:** Your table data stays inside this boundary. Only metadata crosses to the control plane. +- **Branches (compute and storage):** Each branch is a full Postgres instance with **compute that auto-scales with load**. Branches share storage from the same replica through copy-on-write, so scaling to many branches is efficient for both compute and storage. Queries and connections run independently on autoscaling branch compute. +- **Isolation:** Your data stays inside this boundary. Only metadata crosses to the control plane. This means in a BYOC model you can maintain residency of all your data without losing Ardent's ability to manage the service You connect your database and open branches. The control plane orchestrates; the data plane runs replication, the replica, and branches. diff --git a/index.mdx b/index.mdx index 8ca7521..5d758ca 100644 --- a/index.mdx +++ b/index.mdx @@ -24,41 +24,46 @@ An instant database for every task. -## Start making Database copies in just 4 commands - - - - ```bash - npm install -g ardent-cli - ``` - - - ```bash - ardent login - ``` - - - ```bash - ardent connector create postgresql '' - ``` - Use single quotes around the URL so characters like `?`, `&`, or `$` in the string are not mangled by the shell. - - - ```bash - ardent branch create my-feature - ``` - - - -That's it. You can make full, isolated copies of your database — ready in under 6 seconds regardless of data size. - -**Rather have Claude set this up?** Copy this into Claude Code or Cursor: +## Get started + + + Up and running in 4 commands. Takes about 2 minutes. + + +**Or have Claude walk you through it.** Paste this into Claude Code or Cursor: ``` -I want to set up Ardent for database branching. -Install ardent-cli, log in, connect my Postgres database -[paste connection string here], and create my first branch. -Docs: https://docs.tryardent.com +Set up Ardent for database branching. Act like a teammate at my keyboard: +run the commands yourself, stop only when you need me to do something +only I can do (browser sign-up, paste a credential). Before each step, +give me one short line on what's happening and why — process guidance, +not a recap afterward. + +Run these in order: + +1. Install the CLI: npm install -g ardent-cli + +2. ardent login → opens a browser to authenticate. Tell me to finish + sign-up or login and ping you when done. + +3. Tell me to export my Postgres connection string in this shell so + Ardent can connect to my database and start replicating it for + branching: + export ARDENT_DB_URL='postgres://...' + Then run: + ardent connector create postgresql "$ARDENT_DB_URL" + (a project gets auto-created here) + +4. ardent branch create my-feature → spins up an isolated copy of my + database I can use however I want without touching prod. + +5. ardent branch info → give me the connection URL. That URL is my + isolated branch — I connect to it like any Postgres database. + +Skip the after-the-fact recap. Hand me the URL at the end. If a command +errors, fix it. + +Docs: https://docs.tryardent.com/quickstart ``` ## How it works @@ -84,10 +89,7 @@ Create as many as you need, throw them away when you're done without worrying. ## Next steps - - - Up and running in 3 commands. - + Supabase, RDS, PlanetScale, and self-hosted Postgres. diff --git a/security.mdx b/security.mdx index 4c3a36b..55ba9f4 100644 --- a/security.mdx +++ b/security.mdx @@ -5,21 +5,21 @@ description: "How Ardent keeps your data safe" Ardent is designed to never put your production data at risk. Here's how. -## Production is read-only +## Minimal production footprint -Ardent uses logical replication to sync your data — it only reads from your production database. It never writes to it or modifies it. +Ardent uses logical replication to sync your table data and does not write to your application tables. During connector setup, Ardent creates one dedicated schema for its own metadata and installs DDL event triggers there so schema changes can be detected and replayed in order on the replica. -## Credentials are never exposed +This has little to no performance impact on production. Normal application reads and writes continue against your database as usual. -Every branch gets its own generated connection string. Your real database credentials are never shared — not with agents, not with team members, not with Ardent itself. +## Encryption and secrets -If a branch URL is ever compromised, it has zero access to your original database. This makes it safe to hand branch URLs to AI agents like Claude Code or Cursor without worrying about your production credentials leaking. +Ardent encrypts source database credentials, API keys, and connection secrets at rest. Replication components read credentials only at runtime when they need to connect. -Branches are controlled through Ardent's connection layer, so you can delete or de-provision them at any time. +With **BYOC (bring your own cloud)**, secrets live in your own infrastructure (for example AWS SSM Parameter Store). Ardent reads them directly from your secret store at runtime, and your credentials never leave your network. -## All secrets are encrypted +Every branch gets its own generated connection string. If a branch URL is ever compromised, it has zero access to your original database. This makes it safe to hand branch URLs to AI agents like Claude Code or Cursor without leaking your source database credentials. -All secrets (connection strings, credentials, API keys) are encrypted at rest. Nothing is stored unencrypted. In **managed, your cloud** deployments, secrets live in your own infrastructure (for example AWS SSM Parameter Store). Ardent reads them at runtime but never persists your credentials on Ardent infrastructure. +Branches are controlled through Ardent's control plane, so you can delete or de-provision them at any time. ## Branch anonymization diff --git a/workflows/ci-cd.mdx b/workflows/ci-cd.mdx index 9b7a00a..2df92a2 100644 --- a/workflows/ci-cd.mdx +++ b/workflows/ci-cd.mdx @@ -5,38 +5,138 @@ description: "A fresh database for every PR. Isolated, production-like, torn dow Every PR gets its own fresh database cloned from production, torn down after merge. No shared staging that drifts out of sync. No test runs that corrupt each other. -## GitHub Actions example +## Have Claude set this up -The CLI needs to authenticate before running any commands. In CI, use `ardent login --token` with a token stored in your repo secrets. This creates a local session the same way `ardent login` does interactively. +Paste this into Claude Code or Cursor and it will walk you through the whole thing: -After login, create the branch. The CLI doesn't expose the URL as a structured output yet, so grab it from `ardent branch info` and append it to `GITHUB_ENV` so later steps (npm, pytest, your migration runner) see `DATABASE_URL`. +``` +Set up Ardent branching in our GitHub Actions CI. Act like a teammate +at my keyboard: write the workflow yourself, only stop when you need +me to do browser-only steps. + +Steps: + +1. Tell me to create an API token at + https://app.tryardent.com/app/settings/api-keys and add it as a + repo secret called ARDENT_TOKEN (Settings > Secrets and variables > + Actions). Wait until I confirm both are done. + +2. Run `ardent project list` and `ardent connector list` to get my + project and connector names. If I have multiple, ask me which to use. + +3. Create .github/workflows/ardent-branch.yml using the template at + https://docs.tryardent.com/workflows/ci-cd, with my project and + connector substituted in. Use `npm test` unless this repo uses + something else (check package.json). + +4. Commit on a new branch and open a PR so the workflow runs. + +Don't narrate every step. Hand me a working PR at the end. If a step +errors, fix it. +``` + +Or follow the manual walkthrough below. + +## Prerequisites + +You need an Ardent account with at least one connector set up. If you haven't done that yet, follow the [Quickstart](/quickstart) first. + +## Setup + + + + +Run these locally to find the values you'll need for the workflow: + +```bash +ardent project list +ardent connector list +``` + +Note the project name and connector name. You will use these in the workflow to explicitly select which database to branch from. + + + + + +Go to [Ardent dashboard > API keys](https://app.tryardent.com/app/settings/api-keys) and create a token. + + + + + +In your repo, go to **Settings > Secrets and variables > Actions** and click **New repository secret**. Name it **`ARDENT_TOKEN`** and paste your token. + + + + + +Copy the YAML below to `.github/workflows/ardent-branch.yml` in your repo, replacing `my-project` and `my-connector` with your values from step 1. + + + + +## GitHub Actions workflow ```yaml -- name: Install Ardent CLI - run: npm install -g ardent-cli +name: Test with Ardent branch + +on: + pull_request: + types: [opened, synchronize, reopened] + +jobs: + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-node@v4 + with: + node-version: "22" -- name: Log in to Ardent - run: ardent login --token ${{ secrets.ARDENT_TOKEN }} + - name: Install dependencies + run: npm ci -- name: Create database branch - run: | - NAME="pr-${{ github.event.pull_request.number }}" - ardent branch create "$NAME" - echo "DATABASE_URL=$(ardent branch info | awk '/URL:/{print $2}')" >> "$GITHUB_ENV" + - name: Install Ardent CLI + run: npm install -g ardent-cli -- name: Run migrations + tests - run: npm test + - name: Log in to Ardent + run: ardent login --token ${{ secrets.ARDENT_TOKEN }} -- name: Delete branch - if: always() - run: ardent branch delete pr-${{ github.event.pull_request.number }} + - name: Select project and connector + run: | + ardent project switch my-project + ardent connector switch my-connector + + - name: Create database branch + run: | + BRANCH_NAME="pr-${{ github.event.pull_request.number }}-${{ github.run_id }}" + ardent branch create "$BRANCH_NAME" + echo "DATABASE_URL=$(ardent branch info | awk '/URL:/{print $2}')" >> "$GITHUB_ENV" + echo "ARDENT_BRANCH=$BRANCH_NAME" >> "$GITHUB_ENV" + + - name: Run tests + run: npm test + + - name: Delete database branch + if: always() + run: ardent branch delete "$ARDENT_BRANCH" ``` -Use the same `DATABASE_URL` for `pytest`, `pnpm test`, or any tool your repo already uses in CI. If your framework reads a different variable, write that name to `GITHUB_ENV` instead. +**What each step does:** + +- **`ardent login --token`** authenticates the CLI using your repo secret. +- **`ardent project switch` / `ardent connector switch`** explicitly selects which project and connector to branch from. A connector represents one Postgres server. Replace `my-project` and `my-connector` with your names. Always set these in CI so the workflow is deterministic. +- **`ardent branch create`** creates an isolated database branch. The name includes the PR number and run ID so concurrent runs and re-runs don't collide. +- **`ardent branch info | awk '/URL:/{print $2}'`** extracts the branch connection URL and writes it to `DATABASE_URL` in `GITHUB_ENV`. Your test step reads `DATABASE_URL` like any other environment variable. If your app uses a different env var name, change it in the `echo` line. +- **`npm test`** runs your test suite against the branch. Replace with `pytest`, `pnpm test`, `make test`, or whatever your project uses. +- **`ardent branch delete`** cleans up the branch. `if: always()` ensures this runs even when tests fail. -## Why this beats a shared staging database +## Compared to a shared staging database -- **Isolation:** each PR can't interfere with other test runs -- **Always in sync:** branched from production, no drift -- **No idle cost:** branches auto-suspend between CI runs -- **Auto cleanup:** `if: always()` means no orphaned environments +- **Full production data:** branches are not schema-only copies. You test against the same data at the same scale, so if something would blow up in production, it blows up here first. +- **Isolation:** each PR gets its own branch. No test run can interfere with another. +- **Efficient at scale:** compute auto-scales per branch and storage is shared across branches, so spinning up many ephemeral environments stays cheap. +- **Always in sync:** branches are created from a continuously synced replica. No drift. +- **Auto cleanup:** `if: always()` deletes the branch after the run. No orphaned environments.