mirror of
https://github.com/n8n-io/n8n.git
synced 2026-10-17 13:39:44 +02:00
feat: Add Flaky MCP, Docker-in-Docker, and rotation-proof git auth to Codespaces (no-changelog) (#35950)
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
ec92ffcd56
commit
d4bb2c63ee
|
|
@ -16,8 +16,14 @@ RUN npx -y playwright@${PLAYWRIGHT_VERSION} install-deps chromium
|
|||
ENV DISABLE_AUTOUPDATER=1
|
||||
RUN npm install -g @anthropic-ai/claude-code opencode-ai
|
||||
|
||||
COPY codespaces-env.sh /usr/local/lib/codespaces-env.sh
|
||||
COPY codespaces-secrets.sh /etc/profile.d/codespaces-secrets.sh
|
||||
|
||||
# git and gh must survive token rotation: these read the token on each call
|
||||
COPY gitcredential-refresh.sh /usr/local/bin/gitcredential-refresh.sh
|
||||
COPY gh-shim.sh /usr/local/bin/gh
|
||||
RUN chmod +x /usr/local/bin/gitcredential-refresh.sh /usr/local/bin/gh
|
||||
|
||||
RUN echo node ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/node && chmod 0440 /etc/sudoers.d/node
|
||||
RUN mkdir -p /workspaces && chown node:node /workspaces
|
||||
RUN corepack enable
|
||||
|
|
|
|||
|
|
@ -6,7 +6,8 @@ from anywhere with a terminal, resume tomorrow.
|
|||
|
||||
This is a separate devcontainer config from the laptop one in
|
||||
`.devcontainer/` — it ships both agent CLIs, `tmux` for session persistence,
|
||||
and Playwright system deps, on the same Postgres sidecar setup.
|
||||
Playwright system deps, and Docker-in-Docker (for testcontainers and
|
||||
`pnpm --filter n8n-containers services`), on the same Postgres sidecar setup.
|
||||
|
||||
## One-time setup (~5 min)
|
||||
|
||||
|
|
@ -38,6 +39,15 @@ pnpm session rm # delete the codespace
|
|||
- First codespace creation takes ~20 min uncached (image + full build). After
|
||||
that, sessions attach instantly; new worktrees cost a `pnpm install` (~1–2 min).
|
||||
|
||||
## Flaky tools (MCP)
|
||||
|
||||
Claude sessions get the `flaky` MCP server automatically: Currents
|
||||
flaky/quarantine data, the `qa_*` BigQuery dataset, Sentry RCA, live Linear,
|
||||
and repo investigation. Login registers it from the repo-level
|
||||
`FLAKY_MCP_TOKEN` / `FLAKY_MCP_URL` secrets. Forks have no secrets and skip
|
||||
it. Tell the agent to call `get_flaky_context` first — it returns the rules
|
||||
the tools assume.
|
||||
|
||||
## Viewing the dev UI locally
|
||||
|
||||
Two terminal windows:
|
||||
|
|
@ -84,6 +94,14 @@ After a stop, `pnpm session <name>` restarts the codespace (~30–60 s); run
|
|||
agent injects them into VS Code sessions only; they're delivered
|
||||
base64-encoded to `/workspaces/.codespaces/shared/.env-secrets`. The image's
|
||||
profile shim exports them for ssh/tmux sessions.
|
||||
- **`git push` / `gh` return 401 in tmux and long sessions** — same root
|
||||
cause as the secrets gotcha, plus rotation: Codespaces refreshes the
|
||||
on-disk `GITHUB_TOKEN` every few minutes, so a login-time snapshot goes
|
||||
stale. The image fixes both: a credential helper reads the current token
|
||||
on each `git push` (`gitcredential-refresh.sh`), and a shim at
|
||||
`/usr/local/bin/gh` does the same for `gh`. The token is scoped to
|
||||
`n8n-io/n8n`: fork-based flows do not work, push branches directly. Do
|
||||
not add SSH keys as a workaround — they have no per-repo granularity.
|
||||
- Codespaces created by org members on this repo are **org-owned and
|
||||
org-billed** (organization ownership + a monthly Codespaces budget are
|
||||
enabled for n8n-io). Codespaces created before that change, or by
|
||||
|
|
|
|||
9
.devcontainer/codespaces/codespaces-env.sh
Normal file
9
.devcontainer/codespaces/codespaces-env.sh
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
# Codespaces delivers secrets base64-encoded in a shared env file. It injects
|
||||
# them into VS Code sessions only. Other shells must source this file to get
|
||||
# them. Tokens rotate every few minutes: read at time of use, not at login.
|
||||
if [ -f /workspaces/.codespaces/shared/.env-secrets ]; then
|
||||
while IFS='=' read -r key val; do
|
||||
case "$key" in '' | *[!A-Za-z0-9_]*) continue ;; esac
|
||||
dec=$(printf %s "$val" | base64 -d 2>/dev/null) && export "$key=$dec"
|
||||
done </workspaces/.codespaces/shared/.env-secrets
|
||||
fi
|
||||
|
|
@ -1,8 +1,19 @@
|
|||
# Codespaces delivers user secrets base64-encoded to a shared env file and only
|
||||
# injects them into VS Code sessions; ssh/tmux login shells must source them here.
|
||||
if [ -f /workspaces/.codespaces/shared/.env-secrets ]; then
|
||||
while IFS='=' read -r key val; do
|
||||
case "$key" in '' | *[!A-Za-z0-9_]*) continue ;; esac
|
||||
dec=$(printf %s "$val" | base64 -d 2>/dev/null) && export "$key=$dec"
|
||||
done </workspaces/.codespaces/shared/.env-secrets
|
||||
# Login-shell setup for ssh/tmux sessions: export secrets, then do the
|
||||
# one-time registrations.
|
||||
. /usr/local/lib/codespaces-env.sh
|
||||
|
||||
# Register the Flaky MCP server for Claude Code. The config keeps a literal
|
||||
# ${FLAKY_MCP_TOKEN}; Claude Code expands it at connect time, so the token is
|
||||
# not written to disk. Forks have no repo secrets and skip this.
|
||||
if [ -n "$FLAKY_MCP_URL" ] && ! grep -qs '"flaky"' "$HOME/.claude.json" && command -v claude >/dev/null 2>&1; then
|
||||
claude mcp add --scope user --transport http flaky "$FLAKY_MCP_URL" \
|
||||
--header 'Authorization: Bearer ${FLAKY_MCP_TOKEN}' >/dev/null 2>&1 || true
|
||||
fi
|
||||
|
||||
# Register the credential helper in the user config, because Codespaces
|
||||
# regenerates the managed /etc/gitconfig. When the env token is missing, the
|
||||
# system helper exits 0 without output, and git falls through to ours.
|
||||
if command -v git >/dev/null 2>&1 &&
|
||||
! git config --global --get-all credential.helper 2>/dev/null | grep -qs gitcredential-refresh; then
|
||||
git config --global --add credential.helper /usr/local/bin/gitcredential-refresh.sh
|
||||
fi
|
||||
|
|
|
|||
|
|
@ -12,7 +12,10 @@
|
|||
"features": {
|
||||
"ghcr.io/devcontainers/features/github-cli:1": {},
|
||||
// gh codespace ssh needs an SSH server inside the container
|
||||
"ghcr.io/devcontainers/features/sshd:1": {}
|
||||
"ghcr.io/devcontainers/features/sshd:1": {},
|
||||
// Docker for testcontainers and `pnpm --filter n8n-containers services`;
|
||||
// needs `privileged: true` on the n8n service (compose-based config)
|
||||
"ghcr.io/devcontainers/features/docker-in-docker:2": {}
|
||||
},
|
||||
"forwardPorts": [8080, 5678],
|
||||
// Runs in prebuilds, so a fresh codespace starts with deps installed and the build warm
|
||||
|
|
@ -23,6 +26,13 @@
|
|||
},
|
||||
"CLAUDE_CODE_OAUTH_TOKEN": {
|
||||
"description": "Alternative to an API key: token from `claude setup-token` (Max subscription)"
|
||||
},
|
||||
// Both set at the repository level — team members get them automatically
|
||||
"FLAKY_MCP_TOKEN": {
|
||||
"description": "Bearer token for the Flaky (QA assistant) MCP endpoint"
|
||||
},
|
||||
"FLAKY_MCP_URL": {
|
||||
"description": "URL of the Flaky MCP endpoint on the internal n8n instance"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,8 @@ services:
|
|||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
# Required by the docker-in-docker devcontainer feature
|
||||
privileged: true
|
||||
volumes:
|
||||
- ../..:/workspaces:cached
|
||||
command: sleep infinity
|
||||
|
|
|
|||
7
.devcontainer/codespaces/gh-shim.sh
Normal file
7
.devcontainer/codespaces/gh-shim.sh
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
#!/bin/sh
|
||||
# gh reads its token from the env only. Long sessions hold a stale snapshot of
|
||||
# the rotated token. Read the current token on each call, then run the real gh
|
||||
# (the github-cli feature installs it at /usr/bin/gh).
|
||||
. /usr/local/lib/codespaces-env.sh
|
||||
[ -n "$GITHUB_TOKEN" ] && export GH_TOKEN="$GITHUB_TOKEN"
|
||||
exec /usr/bin/gh "$@"
|
||||
6
.devcontainer/codespaces/gitcredential-refresh.sh
Normal file
6
.devcontainer/codespaces/gitcredential-refresh.sh
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
#!/bin/sh
|
||||
# The stock helper reads $GITHUB_TOKEN from the env. Non-login shells do not
|
||||
# have it, and the token rotates. Read the current token, then delegate.
|
||||
[ "$1" = get ] || exit 0
|
||||
. /usr/local/lib/codespaces-env.sh
|
||||
exec /.codespaces/bin/gitcredential_github.sh "$@"
|
||||
Loading…
Reference in New Issue
Block a user