fix(agents): Cloud Agent Figma REST file read - #1034
Conversation
|
Bugbot is not enabled for your account, so this pull request was not reviewed. Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs. |
There was a problem hiding this comment.
Stale comment
Review — #1034 @
b332f91dVerdict: COMMENT. Do not merge yet. Do not self-approve. This head closes the #1028 overclaim (whoami is not file read) with a pinned
GET /v1/files/{key}helper. It is the landing vehicle. Keep #1028 and #1032 from merging in parallel.What this head actually does
scripts/ci/figma_rest_auth.py— pinnedHTTPSConnection("api.figma.com")GET /v1/me,X-Figma-Tokenonly, 64 KiB body cap, token never printed.scripts/ci/figma_rest_file.py— allowlisted file key (10–128[A-Za-z0-9]) andpage:nodeids, thenGET /v1/files/{key}?depth=N,/nodes, or/images.file://,http://, andapi.figma.comlocators never reach TLS. 8 MiB body cap.- ADR/changelog/APA 7 doctoring now name the file helper. That was the #1028 merge blocker.
Local evidence on this SHA (not a substitute for required GitHub checks):
pytest tests/test_figma_rest_auth.py tests/test_figma_rest_file.py— 57 passed, including the live unauthenticated/v1/me401/403 accuracy check.- Coverage 100% statements/branches on both helpers;
interrogate100%.- Governance/changelog contract tests still pass.
FIGMA_ACCESS_TOKENis unset in this environment, so a live file GET was not run. That is the remaining accuracy gap, not a source defect.CodeRabbit CLI is not authenticated in this Cloud/Automation environment (
coderabbitmissing; priorauth login --agentbrowser callback times out). This is not CodeRabbit output.No merge-blocking source defect
Allowlist, Host-header refusal, body caps, and token-free stdout match the stated contract. Official Figma file-endpoint examples use
ids=1:2,1:3anddepth=2for pages plus top-level frames (Figma, 2026c). The helper matches that shape.Stale
failrows ongh pr checks(OpenCode, Bandit, pip-audit, CodeQL, coverage) are cancelled jobs from8fe679d8after this synchronize. Fresh required runs are queued/pending onb332f91d. Treat those as in-flight, not as a source regression.Residuals (do not block this increment; do not open a fourth Figma REST PR)
- Store
FIGMA_ACCESS_TOKEN(plan token preferred for org fleets; PAT max 90 days). Then runpython3 scripts/ci/figma_rest_auth.pyandpython3 scripts/ci/figma_rest_file.py '<file-key-or-url>'on a Cloud Agent. Until that secret exists, design-to-code still stops at whoami-missing.- Non-author approval + green required checks on this SHA.
mergeStateStatus=BLOCKED,reviewDecision=REVIEW_REQUIRED. Reviewerseonghobaeis already requested.- Next buyer gap after this lands: the GET file JSON includes
styles,components, andcomponentSets(Figma, 2026c).summarize_file_payloaddrops them, so a Cloud Agent still cannot recover design tokens from the same call. Add a token/style outline on this helper after merge — do not start a competing PR.- Doc nit: doctoring cites CWE-22 for Host-header refusal. The file-key allowlist is the CWE-22 control; Host refusal is host-injection defense. Fix the citation on a later docs touch, not a reset of this SHA.
Operator next actions
- Leave #1028 draft / unmerged at
8dd905ea. Leave #1032 unmerged at5239fa65.- Wait for OpenCode / Strix / Noema / security / coverage on
b332f91d. Re-run only a cancelled job on this SHA if it stays cancelled; do not push a no-op commit.- After a non-author approval and green required checks, merge this head.
- After merge, store the Figma secret and use the two-step REST path. Desktop/CLI stay on Figma MCP Connect.
Figma. (2026c). Endpoints. Figma Developer Docs. Retrieved August 16, 2026, from https://developers.figma.com/docs/rest-api/file-endpoints/
Sent by Cursor Automation: Fix Issues
There was a problem hiding this comment.
Do not merge #1034. GitHub rejects a changes-requested review from this author on its own PR, so this is a findings review, not an approval.
Whoami-versus-file-read is fixed; the buyer job is not. The default CLI still prints a name/type tree after Figma already returned bbox, fills, characters, auto-layout, thumbnailUrl, components, and styles. A Cloud Agent that follows the documented design URL therefore cannot implement the selected frame. Desktop/CLI get_design_context remains required on this head.
Landing vehicle is #1043 (78fec778) on cursor/bc-88fdcdc4-d1c5-4cb7-806a-4f33bddc8336-b493. That successor keeps the allowlisted REST path and adds geometry, SOLID fills, TEXT, auto-layout, branch-key parsing, instance ids, honest changelog/ADR, CWE-22/918/113 citations, and a live unauthenticated /v1/files check.
Keep #1028 and #1032 draft. Do not open a fifth Figma REST PR; extend #1043 if a residual remains. Store FIGMA_ACCESS_TOKEN, then run python3 scripts/ci/figma_rest_auth.py and python3 scripts/ci/figma_rest_file.py '<figma-url>' on #1043 after it is green. This automation will not merge or self-approve.
Sent by Cursor Automation: Fix Issues
| return payload | ||
|
|
||
|
|
||
| def outline_node(node: object, remaining_depth: int) -> dict[str, Any] | None: |
There was a problem hiding this comment.
outline_node drops bbox, fills, characters, auto-layout, and constraints that GET /v1/files and /v1/files/.../nodes already returned (Figma, 2026c). Default CLI output is a name/type tree. Keep a bounded subset of those fields. Repair is #1043.
| return cleaned | ||
|
|
||
|
|
||
| def summarize_file_payload(payload: Mapping[str, Any], outline_depth: int) -> dict[str, Any]: |
There was a problem hiding this comment.
summarize_file_payload ignores thumbnailUrl, components, and styles. https_image_url already exists — pass thumbnailUrl through so a Cloud Agent gets one preview without a second unpinned fetch. Repair is #1043.
| """Return the Cloud Agent CLI for Figma file reads.""" | ||
| parser = argparse.ArgumentParser( | ||
| prog="figma_rest_file.py", | ||
| description=( |
There was a problem hiding this comment.
"continue design-to-code without Figma MCP" overclaims. Match the doctoring table: REST outline + optional expiring PNG URLs. Desktop/CLI get_design_context stays the richer path. Repair is #1043.
| "locator", | ||
| help="Figma file key or https://www.figma.com/design/<key>/... URL", | ||
| ) | ||
| parser.add_argument( |
There was a problem hiding this comment.
"default 2: pages and top-level frames" is only true for GET /v1/files/:key. The documented URL-with-node-id path uses /nodes, where depth is levels under the selected node (Figma file-endpoints). Repair is #1043.
| return key | ||
|
|
||
|
|
||
| def validate_node_id(raw: str) -> str: |
There was a problem hiding this comment.
^\d+:\d+$ rejects instance ids (I12:34;56:78) that outline_node will print via identity_field. Accept the instance form for --node-id or strip those ids from the outline. Repair is #1043.
| EXIT_INVALID_TARGET, | ||
| ) | ||
| node_ids = [validate_node_id(value) for value in parse_qs(parsed.query).get("node-id", [])] | ||
| return validate_file_key(parts[1]), node_ids |
There was a problem hiding this comment.
/design/<file_key>/branch/<branch_key>/... uses parts[1] (main file). Figma's :key may be a branch key. Detect a branch segment and use that key, or fail closed. Repair is #1043.
| token only when the operator is acting on their own account (maximum 90 days). | ||
| Both kinds are stored in the same secret name. Whoami and file bodies are | ||
| capped (64 KiB / 8 MiB). The opener refuses every header except | ||
| `X-Figma-Token` so a `Host` override cannot retarget TLS (CWE-22; MITRE, 2026). |
There was a problem hiding this comment.
Host-header filtering is not CWE-22, and it does not retarget TLS after HTTPSConnection("api.figma.com"). Cite CWE-22 on the file-key allowlist; cite CWE-918 for parse-don't-fetch. Update the contract pin that currently requires the string CWE-22. Repair is #1043.
| `api.figma.com` origin, and prints a token-free JSON outline (pages and | ||
| top-level frames at depth 2 by default). `--images` returns HTTPS PNG | ||
| URLs for those nodes. `file://`, `http://`, and `api.figma.com` locators | ||
| are refused. Use the outline or image URLs as the next design-to-code |
There was a problem hiding this comment.
"Use the outline or image URLs as the next design-to-code input" sends reconstructing agents into a dead end on this head. Say: outline is navigation until design fields are kept; --images URLs expire in 30 days; get_design_context stays on Desktop/CLI. Repair is #1043.
|
|
||
| ### Added | ||
|
|
||
| - Added Cloud Agent Figma REST helpers `scripts/ci/figma_rest_auth.py` and `scripts/ci/figma_rest_file.py` that verify `FIGMA_ACCESS_TOKEN` against pinned `GET /v1/me` and then read an allowlisted `GET /v1/files/{file_key}` (optional `/nodes` or `/images`) without printing the secret, so design-to-code continues when Figma MCP OAuth is unavailable. |
There was a problem hiding this comment.
"so design-to-code continues" is not true of the default outline on this head. Changelog should say whoami + allowlisted file/nodes/images GET, then name the fields actually printed. Repair is #1043.
| ) | ||
| assert files.main(opener=opener) == auth.EXIT_OK | ||
| captured = capsys.readouterr() | ||
| assert "Home" in captured.out or "image" in captured.out or captured.out |
There was a problem hiding this comment.
or captured.out makes this assertion succeed for any nonempty stdout. Assert file_name / image_urls explicitly. Add a live unauthenticated GET /v1/files 401/403/404 case parallel to whoami. Repair is #1043.
| connection = http.client.HTTPSConnection( | ||
| "api.figma.com", | ||
| timeout=REQUEST_TIMEOUT_SECONDS, | ||
| ) |
| connection = http.client.HTTPSConnection( | ||
| FIGMA_API_HOST, | ||
| timeout=REQUEST_TIMEOUT_SECONDS, | ||
| ) |
b332f91 to
f902645
Compare
|
Rebased onto current main |
Cursor Cloud Agents cannot complete Figma MCP OAuth. Record the 401 challenge, the official Cloud-unsupported decision, and a REST FIGMA_ACCESS_TOKEN whoami helper that never prints the secret. Co-authored-by: Seongho Bae <seonghobae@users.noreply.github.com>
Semgrep p/default flagged urllib.request.urlopen in figma_rest_auth.py as dynamic-urllib-use-detected. Open api.figma.com over TLS with a literal host and path, and refuse any other URL. Co-authored-by: Seongho Bae <seonghobae@users.noreply.github.com>
Whoami alone does not read a Figma file. Add a pinned api.figma.com GET /v1/files helper with allowlisted keys and node ids, and record the operator path in ADR, changelog, and APA 7 doctoring so Cloud Agents can continue design-to-code. Co-authored-by: Seongho Bae <seonghobae@users.noreply.github.com>
f902645 to
0135ce0
Compare
|
Current-head evidence: rebased the Figma Cloud Agent REST auth/file-read repair onto main bbedc1a. Exact head 0135ce0. Focused Figma tests: 57 passed; git diff --check passed. The repository's pre-existing agent-mention workflow contains an actionlint-invalid queue key outside this PR's diff; it was not widened into this change. Protected hosted checks remain; no bypass used. |


Summary
#1028 records that Cloud Agents cannot complete Figma MCP OAuth and ships a whoami helper. Whoami is not file read. This successor adds the allowlisted REST file GET the
file_content:readtoken is for, and closes the ADR/changelog/APA 7 gaps that would have let #1028 merge while still overclaiming.scripts/ci/figma_rest_file.pyGETs pinnedhttps://api.figma.com/v1/files/{key}(optional/nodesor/images) after allowlisting the file key and node ids.file://,http://, andapi.figma.comlocators never reach TLS. The token is never printed.FIGMA_ACCESS_TOKEN→python3 scripts/ci/figma_rest_auth.py→python3 scripts/ci/figma_rest_file.py <file-key-or-url>.AGENTS.md,CLAUDE.md,ARCHITECTURE.md,CHANGELOG.md,docs/CWL-MASTER-CONTEXT.md, anddocs/doctoring/figma-cloud-agent-mcp-auth.md(## APA 7th references, retrieved 2026-08-16, Figma file-endpoints).Supersedes #1028 at
8dd905ea. Keep #1028 draft; merge this head instead.Developer experience
dynamic-urllib-use-detectedstays inapplicable (urllib.request.urlopenis not used).User experience
Test plan
tests/test_figma_rest_auth.pyandtests/test_figma_rest_file.py— missing/empty token, unsafe locators, 200/400/401/403/404/503, refusedfile://, token never echoed, URL node-id parse, image-without-node-id fail-closedcoverage run -m pytest tests/test_figma_rest_auth.py tests/test_figma_rest_file.py(100% on both helpers)interrogate(100% on both helpers)pytest tests(1168 passed) before pushFIGMA_ACCESS_TOKENis added, runpython3 scripts/ci/figma_rest_auth.pythenpython3 scripts/ci/figma_rest_file.py <real-file-url>on a Cloud Agent