diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json index 62c8c1e..9d8dac2 100644 --- a/.claude-plugin/plugin.json +++ b/.claude-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "vercel", - "version": "0.45.1", + "version": "0.46.0", "description": "Build and deploy web apps and agents", "author": { "name": "Vercel", diff --git a/.cursor-plugin/plugin.json b/.cursor-plugin/plugin.json index 1eba763..68b828b 100644 --- a/.cursor-plugin/plugin.json +++ b/.cursor-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "vercel", - "version": "0.45.1", + "version": "0.46.0", "description": "Build and deploy web apps and agents", "author": { "name": "Vercel", diff --git a/.kimi-plugin/plugin.json b/.kimi-plugin/plugin.json index d301957..56d4278 100644 --- a/.kimi-plugin/plugin.json +++ b/.kimi-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "vercel-plugin", - "version": "0.45.1", + "version": "0.46.0", "description": "Comprehensive Vercel ecosystem plugin — relational knowledge graph, skills for every major product, specialized agents, and Vercel conventions. Turns any AI agent into a Vercel expert.", "keywords": [ "vercel", diff --git a/.plugin/plugin.json b/.plugin/plugin.json index 5380024..510de2f 100644 --- a/.plugin/plugin.json +++ b/.plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "vercel-plugin", - "version": "0.45.1", + "version": "0.46.0", "description": "Comprehensive Vercel ecosystem plugin — relational knowledge graph, skills for every major product, specialized agents, and Vercel conventions. Turns any AI agent into a Vercel expert.", "author": { "name": "Vercel", diff --git a/README.md b/README.md index aefe567..a5f4cd4 100644 --- a/README.md +++ b/README.md @@ -46,10 +46,11 @@ A text-form relational graph covering: - Common cross-product workflows - Migration awareness for sunset products -### Skills (30 skills) +### Skills (31 skills) | Skill | Covers | | ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------ | +| `access-protected-vercel-deployment` | Authenticated CLI and browser access to protected preview and production deployments using `vc curl`, OIDC, and Trusted Sources | | `ai-gateway` | Unified model API, provider routing, failover, cost tracking, 100+ models | | `ai-sdk` | AI SDK v6 — text/object generation, streaming, tool calling, agents, MCP, providers, embeddings | | `auth` | Authentication integrations — Clerk, Descope, Auth0 setup for Next.js with Marketplace provisioning | @@ -226,7 +227,7 @@ Exits non-zero if any `SKILL.md` is stale. Add to CI to catch drift. vercel-plugin/ ├── .plugin/plugin.json # Plugin manifest ├── vercel.md # Ecosystem graph + conventions (injected via SessionStart hook) -├── skills/ # 29 skills +├── skills/ # 31 skills │ ├── ai-sdk/ # Upstream-synced skill example: │ │ ├── overlay.yaml # Plugin injection metadata │ │ ├── upstream/ # Pure upstream content @@ -280,6 +281,7 @@ bun run build:from-skills # Stage 4: Resolve template includes - Turbopack (default bundler in Next.js 16) - v0 (agentic intelligence, GitHub integration) - Vercel CLI (cache management, MCP integration, marketplace discovery) +- Protected deployment access (`vc curl`, local OIDC tokens, Trusted Sources) - Vercel Observability (Analytics, Speed Insights, Drains) - Vercel Marketplace (one-click integrations, unified billing) - Agent Browser (browser automation for dev server verification and testing) diff --git a/generated/skill-catalog.md b/generated/skill-catalog.md index 18f15fc..1074e60 100644 --- a/generated/skill-catalog.md +++ b/generated/skill-catalog.md @@ -1,8 +1,8 @@ # Skill Catalog > Auto-generated by `scripts/generate-catalog.ts` — do not edit manually. -> Generated: 2026-07-06T20:39:13.075Z -> Skills: 30 +> Generated: 2026-07-31T16:50:47.870Z +> Skills: 31 ## Table of Contents @@ -17,6 +17,7 @@ |-------|----------|---------------|---------------|-----------------| | `knowledge-update` | 10 | 1 | 0 | 0 | | `workflow` | 9 | 6 | 14 | 4 | +| `access-protected-vercel-deployment` | 8 | 0 | 4 | 0 | | `ai-sdk` | 8 | 27 | 11 | 2 | | `bootstrap` | 8 | 10 | 6 | 8 | | `chat-sdk` | 8 | 45 | 12 | 2 | @@ -88,6 +89,14 @@ **Matched examples:** - `lib/workflow/index.ts` (path) +#### `access-protected-vercel-deployment` (priority 8) + +**Bash patterns:** +- `\b(?:vercel|vc)\s+curl\b` +- `\b(?:curl|wget)\b[^\n]*\.vercel\.app\b` +- `\bagent-browser\b[^\n]*(?:open|navigate|goto)[^\n]*\.vercel\.app\b` +- `\bx-vercel-(?:trusted-oidc-idp-token|protection-bypass)\b` + #### `ai-sdk` (priority 8) **Path patterns:** @@ -959,7 +968,7 @@ Shows which skills compete on shared bash commands. **Priority 9:** `workflow` -**Priority 8:** `ai-sdk`, `bootstrap`, `chat-sdk`, `eve`, `vercel-functions` +**Priority 8:** `access-protected-vercel-deployment`, `ai-sdk`, `bootstrap`, `chat-sdk`, `eve`, `vercel-functions` **Priority 7:** `ai-gateway`, `env-vars`, `microfrontends`, `vercel-firewall`, `vercel-storage`, `verification` diff --git a/generated/skill-manifest.json b/generated/skill-manifest.json index bfab66c..170937b 100644 --- a/generated/skill-manifest.json +++ b/generated/skill-manifest.json @@ -1,7 +1,116 @@ { - "generatedAt": "2026-07-24T23:01:08.971Z", + "generatedAt": "2026-07-31T18:16:05.834Z", "version": 2, "skills": { + "access-protected-vercel-deployment": { + "priority": 8, + "summary": "Access protected Vercel URLs with vercel curl or a short-lived OIDC token", + "docs": [ + "https://vercel.com/docs/cli/curl", + "https://vercel.com/docs/deployment-protection/methods-to-bypass-deployment-protection/trusted-sources", + "https://vercel.com/docs/oidc#in-local-development" + ], + "sitemap": "https://vercel.com/sitemap/docs.xml", + "pathPatterns": [], + "bashPatterns": [ + "\\b(?:vercel|vc)\\s+curl\\b", + "\\b(?:curl|wget)\\b[^\\n]*\\.vercel\\.app\\b", + "\\bagent-browser\\b[^\\n]*(?:open|navigate|goto)[^\\n]*\\.vercel\\.app\\b", + "\\bx-vercel-(?:trusted-oidc-idp-token|protection-bypass)\\b" + ], + "importPatterns": [], + "bodyPath": "skills/access-protected-vercel-deployment/SKILL.md", + "pathRegexSources": [], + "bashRegexSources": [ + "\\b(?:vercel|vc)\\s+curl\\b", + "\\b(?:curl|wget)\\b[^\\n]*\\.vercel\\.app\\b", + "\\bagent-browser\\b[^\\n]*(?:open|navigate|goto)[^\\n]*\\.vercel\\.app\\b", + "\\bx-vercel-(?:trusted-oidc-idp-token|protection-bypass)\\b" + ], + "importRegexSources": [], + "promptSignals": { + "phrases": [ + "access protected vercel deployment", + "protected vercel deployment", + "deployment protection", + "vercel sso", + "vercel authentication page", + "behind vercel authentication", + "behind vercel sso", + "x-vercel-trusted-oidc-idp-token", + "trusted_sources_environment_mismatch", + "trusted sources environment mismatch", + "protection bypass" + ], + "allOf": [ + [ + "vercel", + "protected" + ], + [ + "vercel", + "sso" + ], + [ + "vercel", + "403" + ], + [ + "deployment", + "login" + ], + [ + "preview", + "protected" + ], + [ + "production", + "protected" + ] + ], + "anyOf": [ + "deployment", + "preview", + "production", + "curl", + "browser", + "authentication" + ], + "noneOf": [ + "aws deployment protection", + "github deployment protection", + "kubernetes deployment protection" + ], + "minScore": 6 + }, + "retrieval": { + "aliases": [ + "protected Vercel deployment", + "Vercel SSO bypass", + "Vercel deployment authentication", + "Vercel Trusted Sources" + ], + "intents": [ + "access a protected deployment", + "test a protected preview", + "verify a protected production deployment", + "authenticate browser automation to Vercel" + ], + "entities": [ + "vercel curl", + "VERCEL_OIDC_TOKEN", + "x-vercel-trusted-oidc-idp-token", + "Trusted Sources", + "Deployment Protection" + ], + "examples": [ + "preview is behind Vercel SSO", + "curl this protected Vercel deployment", + "access a protected Vercel deployment through a custom domain", + "open the protected production URL in agent-browser" + ] + } + }, "ai-gateway": { "priority": 7, "summary": "", diff --git a/hooks/telemetry.mjs b/hooks/telemetry.mjs index 20dfdd7..44736f1 100644 --- a/hooks/telemetry.mjs +++ b/hooks/telemetry.mjs @@ -5,7 +5,7 @@ import { join, dirname } from "path"; import { homedir } from "os"; var BRIDGE_ENDPOINT = "https://telemetry.vercel.com/api/vercel-plugin/v1/events"; var FLUSH_TIMEOUT_MS = 3e3; -var PLUGIN_VERSION = true ? "0.45.1" : "0.43.0"; +var PLUGIN_VERSION = true ? "0.46.0" : "0.43.0"; var ACTIVE_SESSION_TTL_MS = 60 * 60 * 1e3; var DAU_STAMP_PATH = join(homedir(), ".config", "vercel-plugin", "dau-stamp"); var FIRST_USE_STAMP_PATH = join(homedir(), ".config", "vercel-plugin", "first-use-stamp"); diff --git a/package.json b/package.json index f0bbe40..180dbfd 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "vercel-plugin", - "version": "0.45.1", + "version": "0.46.0", "private": true, "license": "Apache-2.0", "bin": { diff --git a/skills/access-protected-vercel-deployment/SKILL.md b/skills/access-protected-vercel-deployment/SKILL.md new file mode 100644 index 0000000..1f3605b --- /dev/null +++ b/skills/access-protected-vercel-deployment/SKILL.md @@ -0,0 +1,169 @@ +--- +name: access-protected-vercel-deployment +description: Access and test Vercel deployments protected by Vercel Authentication, SSO, or Deployment Protection. Use when curl, agent-browser, Playwright, or another automated request reaches a Vercel login or protection page; when a protected preview or production URL returns 401 or 403; when TRUSTED_SOURCES_ENVIRONMENT_MISMATCH appears; or when choosing between `vercel curl` and the `x-vercel-trusted-oidc-idp-token` header. +summary: Access protected Vercel URLs with vercel curl or a short-lived OIDC token +metadata: + priority: 8 + docs: + - "https://vercel.com/docs/cli/curl" + - "https://vercel.com/docs/deployment-protection/methods-to-bypass-deployment-protection/trusted-sources" + - "https://vercel.com/docs/oidc#in-local-development" + sitemap: "https://vercel.com/sitemap/docs.xml" + pathPatterns: [] + bashPatterns: + # Match vc curl for every hostname, including custom aliases. + - '\b(?:vercel|vc)\s+curl\b' + # Keep raw clients scoped to hostnames that identify themselves as Vercel. + - '\b(?:curl|wget)\b[^\n]*\.vercel\.app\b' + - '\bagent-browser\b[^\n]*(?:open|navigate|goto)[^\n]*\.vercel\.app\b' + # Match custom aliases when the request includes an explicit Vercel protection header. + - '\bx-vercel-(?:trusted-oidc-idp-token|protection-bypass)\b' + importPatterns: [] + promptSignals: + phrases: + - "access protected vercel deployment" + - "protected vercel deployment" + - "deployment protection" + - "vercel sso" + - "vercel authentication page" + - "behind vercel authentication" + - "behind vercel sso" + - "x-vercel-trusted-oidc-idp-token" + - "trusted_sources_environment_mismatch" + - "trusted sources environment mismatch" + - "protection bypass" + allOf: + - [vercel, protected] + - [vercel, sso] + - [vercel, "403"] + - [deployment, login] + - [preview, protected] + - [production, protected] + anyOf: + - "deployment" + - "preview" + - "production" + - "curl" + - "browser" + - "authentication" + noneOf: + - "aws deployment protection" + - "github deployment protection" + - "kubernetes deployment protection" + minScore: 6 +retrieval: + aliases: + - protected Vercel deployment + - Vercel SSO bypass + - Vercel deployment authentication + - Vercel Trusted Sources + intents: + - access a protected deployment + - test a protected preview + - verify a protected production deployment + - authenticate browser automation to Vercel + entities: + - vercel curl + - VERCEL_OIDC_TOKEN + - x-vercel-trusted-oidc-idp-token + - Trusted Sources + - Deployment Protection + examples: + - preview is behind Vercel SSO + - curl this protected Vercel deployment + - access a protected Vercel deployment through a custom domain + - open the protected production URL in agent-browser +--- + +# Access Protected Vercel Deployments + +Use the caller's existing Vercel authentication. Do not disable Deployment Protection or ask for a long-lived bypass secret as the first solution. + +## Choose the access path + +### HTTP requests: use `vercel curl` + +For response bodies, headers, health checks, and API calls, replace raw `curl` with `vercel curl` (`vc curl`). It accepts native curl options and uses Vercel authentication to access protected preview and production deployments. + +```bash +vc curl https://my-app.vercel.app/api/health +vc curl https://app.example.com/api/health +vc curl my-app.vercel.app/api/users -X POST \ + -H "Content-Type: application/json" \ + -d '{"name":"Ada"}' +vc curl /api/health +``` + +The path-only form targets the linked project's production deployment. Pass a full URL when the exact deployment matters. + +If authentication fails, check the local identity and project before changing protection settings: + +```bash +vc whoami +``` + +Inspect `.vercel/project.json` to confirm the linked project and team. Run `vc link` only when the directory is not linked or is linked to the wrong project. Run `vc login` only when the CLI reports that no authenticated user is available. + +### Browser automation: attach the development OIDC token as a header + +Browser requests must include the short-lived local token as a request header: + +```text +x-vercel-trusted-oidc-idp-token: +``` + +Use a browser tool that supports origin-scoped request headers. With `agent-browser`, inject development variables without printing or persisting the token: + +```bash +vc env run -- sh -c \ + 'test -n "$VERCEL_OIDC_TOKEN" && agent-browser open "$1" --headers "{\"x-vercel-trusted-oidc-idp-token\":\"$VERCEL_OIDC_TOKEN\"}"' \ + sh https://my-app.vercel.app +``` + +Then continue the normal browser workflow in the same session. For Playwright or another browser driver, set the same header in the browser context's extra HTTP headers before the first navigation. + +If the local CLI version does not provide the token through `vc env run`, refresh local development credentials with: + +```bash +vc env pull .env.local --yes +``` + +Load the file through the project's existing dotenv mechanism. Never print the token, paste its value into source code, or commit `.env.local`. + +Use `x-vercel-trusted-oidc-idp-token` for Trusted Sources. Do not substitute `x-vercel-oidc-token`; that header carries an OIDC token into a Vercel Function and serves a different purpose. + +## Trusted Sources rules + +A local development token for a linked Vercel project can access that same project's Preview deployments by default. It does not automatically access protected Production deployments. For protected Production, the project's own Trusted Sources entry must allow `development` → `production`. + +Do not ask the user to configure Trusted Sources for the normal same-project Preview case. + +Configuration is needed when: + +- the target is a protected Production deployment and the caller uses a local development token; +- the caller belongs to another Vercel project or team; +- the target project's self-access rules were customized; or +- the response is `TRUSTED_SOURCES_ENVIRONMENT_MISMATCH`. + +In the target project, open **Settings → Deployment Protection → Trusted Sources**. Add or edit the caller and allow the required `from` → `to` environment pair. A local token has the `development` environment, so access to protected Production requires `development` → `production`. + +Treat this as an access-control change: explain the exact rule required and obtain authorization before changing it. Do not broaden unrelated environment pairs. + +## Diagnose the response + +- A Vercel login, SSO, or Deployment Protection page means the request did not use an accepted authentication path. +- `TRUSTED_SOURCES_ENVIRONMENT_MISMATCH` means the token is valid but its caller environment is not allowed to reach the target environment. +- An application-generated `401` or `403` after Vercel protection is bypassed belongs to the application's own authentication and must be debugged separately. +- A deployment marked `"target": "production"` can still be protected. Do not assume production is public. + +## Avoid + +- Do not disable Deployment Protection to make automation pass. +- Do not send raw unauthenticated `curl` repeatedly after receiving the protection page. +- Do not start an interactive SSO browser login when `vc curl` or an origin-scoped OIDC header can authenticate the request. +- Do not expose `VERCEL_OIDC_TOKEN` in logs, screenshots, committed files, or user-facing output. + +## Related skills + +- General Vercel CLI usage: `⤳ skill: vercel-cli` +- End-to-end application verification: `⤳ skill: verification` diff --git a/tests/access-protected-vercel-deployment-skill.test.ts b/tests/access-protected-vercel-deployment-skill.test.ts new file mode 100644 index 0000000..b7c2ce4 --- /dev/null +++ b/tests/access-protected-vercel-deployment-skill.test.ts @@ -0,0 +1,127 @@ +import { beforeAll, describe, expect, test } from "bun:test"; +import { readFileSync } from "node:fs"; +import { resolve } from "node:path"; +import { + compileSkillPatterns, + matchBashWithReason, + type CompiledSkillEntry, +} from "../hooks/src/patterns.mts"; +import { + compilePromptSignals, + matchPromptWithReason, + normalizePromptText, + type CompiledPromptSignals, +} from "../hooks/src/prompt-patterns.mts"; +import { loadValidatedSkillMap } from "../src/shared/skill-map-loader.ts"; + +const ROOT = resolve(import.meta.dirname, ".."); +const SKILL_PATH = resolve( + ROOT, + "skills/access-protected-vercel-deployment/SKILL.md", +); + +let compiledPromptSignals: CompiledPromptSignals; +let compiledSkill: CompiledSkillEntry; + +beforeAll(() => { + const { skills } = loadValidatedSkillMap(resolve(ROOT, "skills")); + const protectedDeployment = skills["access-protected-vercel-deployment"]; + + expect(protectedDeployment).toBeDefined(); + expect(protectedDeployment.priority).toBe(8); + expect(protectedDeployment.promptSignals).toBeDefined(); + expect(protectedDeployment.promptSignals!.allOf).toContainEqual([ + "vercel", + "403", + ]); + + compiledPromptSignals = compilePromptSignals( + protectedDeployment.promptSignals!, + ); + compiledSkill = compileSkillPatterns({ + "access-protected-vercel-deployment": protectedDeployment, + })[0]; +}); + +function matchesPrompt(prompt: string): boolean { + return matchPromptWithReason( + normalizePromptText(prompt), + compiledPromptSignals, + ).matched; +} + +describe("protected deployment prompt activation", () => { + test.each([ + "Access this protected Vercel deployment.", + "Preview is behind Vercel SSO deployment protection.", + "The Vercel authentication page appears instead of the app.", + "curl gets a 403 from this Vercel deployment.", + "Open the protected production deployment in the browser.", + "My protected Vercel deployment uses a custom domain.", + "Fix TRUSTED_SOURCES_ENVIRONMENT_MISMATCH.", + "Use x-vercel-trusted-oidc-idp-token for this request.", + ])("matches protected Vercel access intent: %s", (prompt) => { + expect(matchesPrompt(prompt)).toBe(true); + }); + + test.each([ + "Add authentication to my application.", + "Protect this Next.js route with Clerk.", + "Explain AWS deployment protection.", + "Run curl against localhost.", + "My Kubernetes deployment is protected by a pod disruption budget.", + ])("does not match unrelated protection or authentication intent: %s", (prompt) => { + expect(matchesPrompt(prompt)).toBe(false); + }); +}); + +describe("protected deployment command activation", () => { + test.each([ + "vc curl https://my-app.vercel.app/api/health", + "vc curl https://app.example.com/api/health", + "vercel curl /api/health", + "vercel curl https://preview.example.com/api/health", + "curl -I https://my-app-git-main.vercel.app", + "agent-browser open https://my-app.vercel.app", + "curl -H 'x-vercel-trusted-oidc-idp-token: token' https://app.example.com", + "curl -H 'x-vercel-protection-bypass: token' https://app.example.com", + ])("matches protected deployment access commands: %s", (command) => { + expect( + matchBashWithReason(command, compiledSkill.compiledBash), + ).not.toBeNull(); + }); + + test.each([ + "curl http://localhost:3000", + "curl https://api.example.com", + "agent-browser open https://example.com", + "vercel logs", + "kubectl get deployments", + ])("does not match unrelated commands: %s", (command) => { + expect(matchBashWithReason(command, compiledSkill.compiledBash)).toBeNull(); + }); +}); + +describe("protected deployment guidance", () => { + test("documents both CLI and browser authentication paths", () => { + const skill = readFileSync(SKILL_PATH, "utf8"); + + expect(skill).toContain("vc curl"); + expect(skill).toContain("VERCEL_OIDC_TOKEN"); + expect(skill).toContain("x-vercel-trusted-oidc-idp-token"); + expect(skill).toContain("agent-browser"); + expect(skill).toContain( + "Browser automation: attach the development OIDC token as a header", + ); + expect(skill).toContain( + "short-lived local token as a request header", + ); + expect(skill).toContain("same project's Preview deployments by default"); + expect(skill).toContain( + "does not automatically access protected Production deployments", + ); + expect(skill).not.toContain("same project's deployments by default"); + expect(skill).toContain("development` → `production"); + expect(skill).toContain("Do not disable Deployment Protection"); + }); +}); diff --git a/tests/telemetry.test.ts b/tests/telemetry.test.ts index 63909dd..e435135 100644 --- a/tests/telemetry.test.ts +++ b/tests/telemetry.test.ts @@ -115,7 +115,7 @@ describe("telemetry controls", () => { expect(result.activeSessionMarker).toEqual({ schema: 1, active: true, - pluginVersion: "0.45.1", + pluginVersion: "0.46.0", updatedAt: Date.parse("2026-05-15T12:00:00.000Z"), expiresAt: Date.parse("2026-05-15T13:00:00.000Z"), }); @@ -131,7 +131,7 @@ describe("telemetry controls", () => { }), expect.objectContaining({ key: "plugin:version", - value: "0.45.1", + value: "0.46.0", }), ], ]); diff --git a/vercel.md b/vercel.md index e760184..59167c4 100644 --- a/vercel.md +++ b/vercel.md @@ -1,4 +1,4 @@ -# Vercel Ecosystem — Relational Knowledge Graph (as of Mar 4, 2026) +# Vercel Ecosystem — Relational Knowledge Graph (as of Jul 30, 2026) > This document is the master reference for understanding the entire Vercel ecosystem. > It maps every product, library, CLI, API, and service — how they relate, when to use each, @@ -29,6 +29,8 @@ VERCEL PLATFORM 📖 docs: https://vercel.com/docs │ → Build System (Turbopack or framework-native) │ ↔ Vercel CLI │ ↔ Vercel REST API / @vercel/sdk +│ ⊃ Deployment Protection (Vercel Authentication, SSO, Trusted Sources) +│ ⤳ skill: access-protected-vercel-deployment │ ⤳ skill: vercel-cli │ ⤳ skill: deployments-cicd │ @@ -522,6 +524,12 @@ VERCEL CLI (vercel / vc) ⤳ skill: vercel-cli 📖 docs: htt │ ⊃ vercel deploy --prebuilt (deploy build output only) │ ⊃ vercel promote / vercel rollback │ +├── Protected Deployment Access ⤳ skill: access-protected-vercel-deployment +│ ⊃ vercel curl (authenticated HTTP requests to preview or production) +│ ⊃ VERCEL_OIDC_TOKEN (short-lived local development identity) +│ ⊃ x-vercel-trusted-oidc-idp-token (browser and automation requests) +│ ↔ Trusted Sources (caller project and environment access rules) +│ ├── Development │ ⊃ vercel dev (local dev server) │ ⊃ vercel link (connect to Vercel project)