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
61 changes: 61 additions & 0 deletions .devcontainer/onCreateCommand.sh
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,67 @@ cargo install cargo-pgrx --version 0.16.1 --locked
echo "Initializing pgrx with PostgreSQL 17..."
cargo pgrx init --pg17 download

# ── Initialize private submodule (duroxide-pg-opt) ──────────────────
# duroxide-pg-opt is a private repo. Two auth mechanisms:
#
# 1. Prebuild phase: GH_PAT Codespace secret provides access.
# The PAT is injected as a temporary git insteadOf rewrite, used
# for clone, then scrubbed so it never persists in the image.
#
# 2. Interactive Codespace: devcontainer.json grants the built-in
# GITHUB_TOKEN read access via customizations.codespaces.repositories.
# The Codespace credential helper handles auth automatically.
#
# 3. Local Dev Container: user must have their own credentials.

SUBMODULE_INITIALIZED=0

if [ -n "$GH_PAT" ]; then
echo "GH_PAT detected — initializing submodule with PAT..."

# Temporarily rewrite GitHub HTTPS URLs to include the token.
git config --global url."https://x-access-token:${GH_PAT}@github.com/".insteadOf "https://github.com/"

if git submodule update --init --recursive; then
echo "✅ Submodule initialized successfully (via PAT)"
SUBMODULE_INITIALIZED=1
else
echo "⚠️ Submodule initialization failed with PAT"
fi

# ── Credential cleanup ──────────────────────────────────────────
# Remove the insteadOf rewrite so the PAT is NOT baked into the
# prebuild filesystem snapshot.
git config --global --remove-section "url.https://x-access-token:${GH_PAT}@github.com/" 2>/dev/null || true
echo -e "protocol=https\nhost=github.com" | git credential reject 2>/dev/null || true

# Belt-and-suspenders: verify no PAT traces remain
if grep -q "x-access-token" "$HOME/.gitconfig" 2>/dev/null; then
echo "⚠️ WARNING: PAT trace found in ~/.gitconfig — scrubbing"
sed -i '/x-access-token/d' "$HOME/.gitconfig"
fi
echo "✅ Credentials cleaned up"
else
echo "GH_PAT not set — trying submodule init with default credentials..."
if git submodule update --init --recursive; then
echo "✅ Submodule initialized successfully"
SUBMODULE_INITIALIZED=1
else
echo "⚠️ Submodule initialization failed — skipping"
echo " Set GH_PAT secret or ensure credentials for microsoft/duroxide-pg-opt"
fi
fi

# ── Build pg_durable ────────────────────────────────────────────────
# Only build if the submodule is present (needed for compilation)
if [ "$SUBMODULE_INITIALIZED" = "1" ] && [ -f "duroxide-pg-opt/Cargo.toml" ]; then
echo "Building pg_durable..."
cargo build --features pg17
echo "✅ pg_durable built successfully"
else
echo "⚠️ Submodule not available — skipping pg_durable build"
fi

echo ""
echo "========================================="
echo "✅ Prebuild setup complete!"
Expand Down
18 changes: 18 additions & 0 deletions .devcontainer/postCreateCommand.sh
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,25 @@ else
echo "⚠️ pgrx not initialized - running initialization..."
cargo pgrx init --pg17 download
fi
# Check if submodule is initialized
echo "Checking submodule status..."
if [ -f "duroxide-pg-opt/Cargo.toml" ]; then
echo "✓ duroxide-pg-opt submodule is initialized"
else
echo "⚠️ duroxide-pg-opt submodule not initialized"
echo " Run: git submodule update --init --recursive"
fi

# Check if pg_durable is already built
echo "Checking build status..."
if [ -n "$(find target/debug -name 'libpg_durable*' -print -quit 2>/dev/null)" ]; then
echo "✓ pg_durable is already built"
elif [ -f "duroxide-pg-opt/Cargo.toml" ]; then
echo "Building pg_durable (submodule present but build artifacts missing)..."
cargo build --features pg17
else
echo "⚠️ pg_durable not built (submodule needed first)"
fi
echo ""
echo "========================================="
echo "✅ Development environment ready!"
Expand Down
41 changes: 35 additions & 6 deletions docs/CODESPACES_PREBUILDS.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,37 @@ Pre-builds must be enabled by a repository administrator:
- **Reduce prebuild available to specific regions**: Optional
4. Click **Create**

Once enabled, GitHub will automatically create prebuilt images when:
- Changes are pushed to the main branch
- The devcontainer configuration changes
- Dependencies (Cargo.toml/Cargo.lock) are updated
### Private Submodule Access

The `duroxide-pg-opt` submodule is a **private repository**. Two mechanisms provide access:

**1. Interactive Codespaces** — `devcontainer.json` grants the built-in Codespace token read access:

```json
"codespaces": {
"repositories": {
"microsoft/duroxide-pg-opt": {
"permissions": { "contents": "read" }
}
}
}
```

This works when users open a Codespace directly.

**2. Prebuild phase** — The Codespace token permissions are **not effective during prebuilds**. A GitHub PAT stored as a Codespace secret is required:

1. Create a **fine-grained PAT** with **read-only** access to `microsoft/duroxide-pg-opt` (Contents: Read)
2. Go to repository **Settings** → **Secrets and variables** → **Codespaces**
3. Click **New repository secret**
4. Name: `GH_PAT`, Value: the PAT from step 1
5. Click **Add secret**

**Security notes:**
- `onCreateCommand.sh` uses a temporary `git config insteadOf` rewrite with the PAT, then **immediately scrubs** all traces (git config, credential cache) before the prebuild image is snapshotted.
- The prebuild image is a **filesystem snapshot** — environment variables from secrets are NOT persisted.
- Users who open a Codespace from the prebuild get the submodule files already present, without needing any PAT themselves.
- Use a fine-grained PAT scoped to only `duroxide-pg-opt` with read-only access to minimize exposure.

## How It Works

Expand All @@ -33,12 +60,14 @@ Codespaces has two distinct phases:
1. **Pre-build Phase** (runs in GitHub Actions, cached for all users)
- Triggered by: `.github/workflows/prebuild.yml`
- Executes: `onCreateCommand` in `devcontainer.json`
- Duration: ~10 minutes (but only runs once per configuration change)
- Duration: ~15 minutes (but only runs once per configuration change)
- Installs:
- System dependencies (libssl, clang, bison, etc.)
- cargo-pgrx 0.16.1
- PostgreSQL 17 (downloaded and compiled via pgrx)
- Result: Docker image with all dependencies baked in
- `duroxide-pg-opt` submodule (via `GH_PAT` Codespace secret)
- Pre-builds pg_durable (`cargo build --features pg17`)
- Result: Docker image with all dependencies and build artifacts baked in

2. **Post-Create Phase** (runs when user opens a Codespace)
- Executes: `postCreateCommand` in `devcontainer.json`
Expand Down
Loading