stitch-sdk-bug-bash

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Stitch SDK Bug Bash

Stitch SDK Bug 攻坚活动

This skill provides a framework and instructions for finding bugs in the Stitch SDK using a real API key. It guides you through exploring standard functional edge cases and tricky situations beyond the golden path.

本技能提供了一套框架和操作指引,用于使用真实API密钥查找Stitch SDK中的漏洞,引导你探索标准功能边界用例,以及常规路径之外的复杂异常场景。

The Mindset: Adversarial Exploration

核心思路:对抗性探索

When using this skill, do not just verify that the SDK works. Try to break it!
  • Pass invalid or boundary parameters.
  • Attempt operations on deleted or stale handles.
  • Simulate unexpected API responses if possible or find edge cases where projection might fail.

使用本技能时,不要只验证SDK是否能正常运行,要尝试把它搞坏!
  • 传入无效或边界参数
  • 尝试对已删除或过期的句柄执行操作
  • 尽可能模拟异常API响应,或者寻找投影功能可能失效的边界场景

Surface Areas to Cover

需要覆盖的测试范围

1. Root & Initialization (
Stitch
)

1. 根模块与初始化(
Stitch

  • Zero Config: Verify the singleton works without explicit config if
    STITCH_API_KEY
    is present.
  • Invalid Config: Pass an empty API key or invalid base URL to
    StitchToolClient
    and verify that the first call fails with a clear authentication or connection error, not a generic noise error.
  • 零配置:验证当存在
    STITCH_API_KEY
    环境变量时,单例无需显式配置即可正常运行。
  • 无效配置:向
    StitchToolClient
    传入空API密钥或无效的基础URL,验证首次调用会返回清晰的认证或连接错误,而不是泛化的无意义错误。

2. Project Lifecycle (
Project
)

2. 项目生命周期(
Project

  • Handle Creation: Verify that
    stitch.project('invalid-id')
    does not throw (lazy instantiation) but the first call on it fails safely.
  • Factory vs API: Verify that creating a project handle via the factory doesn't trigger API calls, but methods like
    project.listScreens()
    do.
  • 句柄创建:验证
    stitch.project('invalid-id')
    不会抛出异常(懒加载实例化),但对其执行的首次调用会安全失败。
  • 工厂方法与API调用差异:验证通过工厂方法创建项目句柄不会触发API调用,但
    project.listScreens()
    等方法会触发API调用。

3. Screen Lifecycle (
Screen
)

3. 页面生命周期(
Screen

  • The Handover: Verify that properties from
    Project.generate()
    are correctly populated on the returned
    Screen
    instances without a second fetch.
  • Null Safety in Projections: Test tools or scenarios that return empty arrays or missing optional fields. Verify that the SDK handle handles them as
    undefined
    or empty arrays rather than crashing on null property access!
  • 数据交接:验证
    Project.generate()
    返回的属性会正确填充到返回的
    Screen
    实例中,无需二次拉取。
  • 投影空安全:测试返回空数组或缺失可选字段的工具/场景,验证SDK句柄会将其处理为
    undefined
    或空数组,而不会因为访问空属性崩溃!

4. Design System (
DesignSystem
)

4. 设计系统(
DesignSystem

  • Application: Create a design system, and apply it to a list of screens. Verify that if the list is empty or invalid, the SDK fails cleanly!
  • Handles: Verify that
    project.designSystem('ds-id')
    correctly receives the
    projectId
    and injects it into calls like
    ds.apply(...)
    .

  • 应用能力:创建一个设计系统,并将其应用到一系列页面上,验证当列表为空或无效时,SDK会干净地失败,不会崩溃!
  • 句柄属性传递:验证
    project.designSystem('ds-id')
    会正确获取
    projectId
    ,并将其注入到
    ds.apply(...)
    等调用中。

Tricky Situations Matrix (Standard Functional Edges)

复杂场景矩阵(标准功能边界)

ScenarioWhat to tryExpected Behavior
Stale HandlesCreate a screen, delete the project, then try to edit the screen handle.Clean API error indicating resource not found, wrapped in
StitchError
.
Empty PromptsCall
project.generate('')
or with only whitespace.
Safe rejection or clear API error, no crash in codegen.
Projections on nullForce an API call that returns a response without the expected projection field (if you can simulate or find such a tool fallback case).The SDK should use optional chaining (e.g.,
raw?.prop
) and return
undefined
rather than throwing
TypeError: cannot read property of undefined
.
Massive arraysPass hundreds of screen IDs to
ds.apply()
.
Check if it hits payload limits gracefully or fails with a clear message.

场景测试操作预期行为
过期句柄创建一个页面,删除所属项目,然后尝试编辑该页面句柄。清晰的API错误,提示资源未找到,封装在
StitchError
中。
空提示词调用
project.generate('')
或仅传入空白字符。
安全的拒绝响应或清晰的API错误,代码生成环节不会崩溃。
空值投影强制发起一个API调用,返回的响应中不存在预期的投影字段(如果你能模拟或者找到这类工具降级场景)。SDK应使用可选链(例如
raw?.prop
)返回
undefined
,而不是抛出
TypeError: cannot read property of undefined
超大规模数组
ds.apply()
传入数百个页面ID。
检查是否能优雅处理载荷上限,或返回清晰的错误提示。

Diagnostic Hygiene

诊断规范

  • Always wrap your test calls in
    try/catch
    .
  • Log the error and inspect
    error.code
    or
    error.name
    to see if it's a
    StitchError
    or a generic raw error.
  • If an execution throws a raw
    TypeError
    or "cannot read property of undefined", that is a HIGH PRIORITY BUG in the SDK's projection logic!

  • 始终将测试调用包裹在
    try/catch
    中。
  • 打印错误并检查
    error.code
    error.name
    ,确认是
    StitchError
    还是泛化的原生错误。
  • 如果执行过程抛出原生
    TypeError
    或"cannot read property of undefined",这是SDK投影逻辑中的最高优先级漏洞

Test Template: The Full Workflow Bash

测试模板:完整工作流测试

Use this template to run a quick end-to-end bash session.
typescript
import { stitch } from "@google/stitch-sdk";

async function bash() {
  const apiKey = process.env.STITCH_API_KEY;
  if (!apiKey) throw new Error("STITCH_API_KEY is required");

  console.log("🚀 Starting Bug Bash...");

  let project;
  try {
    // 1. Create a fresh project
    project = await stitch.createProject({
      displayName: `Bug Bash ${new Date().toISOString()}`
    });
    console.log(`✓ Created Project: ${project.id}`);

    // 2. Try to break generate with empty prompt
    try {
      await project.generate({ prompt: "" });
      console.log("✗ BUG: Generate with empty prompt should have failed!");
    } catch (e) {
      console.log("✓ Generate with empty prompt failed safely as expected.");
    }

    // 3. Create a design system
    const ds = await project.createDesignSystem({
      name: "Bash Style",
      variables: { primaryColor: "#ff0000" }
    });
    console.log(`✓ Created Design System: ${ds.id}`);

    // 4. List screens (should be empty)
    const screens = await project.listScreens();
    console.log(`✓ Listed screens: found ${screens.length}`);

    // 5. Apply design system to empty list
    try {
      await ds.apply({ selectedScreenIds: [] });
      console.log("✓ Applied design system to empty list (handled).");
    } catch (e) {
      console.log("✗ Did applying to empty list fail? Inspect error.");
    }

  } catch (error) {
    console.error("💥 Bash failed with error:", error);
  } finally {
    // 6. Cleanup
    if (project) {
      console.log(`🧹 Cleaning up project ${project.id}...`);
      // Assuming we have a deleteProject binding or we just leave it if not available
      // await project.delete(); 
    }
  }
}

bash();
使用以下模板运行快速端到端测试会话。
typescript
import { stitch } from "@google/stitch-sdk";

async function bash() {
  const apiKey = process.env.STITCH_API_KEY;
  if (!apiKey) throw new Error("STITCH_API_KEY is required");

  console.log("🚀 Starting Bug Bash...");

  let project;
  try {
    // 1. Create a fresh project
    project = await stitch.createProject({
      displayName: `Bug Bash ${new Date().toISOString()}`
    });
    console.log(`✓ Created Project: ${project.id}`);

    // 2. Try to break generate with empty prompt
    try {
      await project.generate({ prompt: "" });
      console.log("✗ BUG: Generate with empty prompt should have failed!");
    } catch (e) {
      console.log("✓ Generate with empty prompt failed safely as expected.");
    }

    // 3. Create a design system
    const ds = await project.createDesignSystem({
      name: "Bash Style",
      variables: { primaryColor: "#ff0000" }
    });
    console.log(`✓ Created Design System: ${ds.id}`);

    // 4. List screens (should be empty)
    const screens = await project.listScreens();
    console.log(`✓ Listed screens: found ${screens.length}`);

    // 5. Apply design system to empty list
    try {
      await ds.apply({ selectedScreenIds: [] });
      console.log("✓ Applied design system to empty list (handled).");
    } catch (e) {
      console.log("✗ Did applying to empty list fail? Inspect error.");
    }

  } catch (error) {
    console.error("💥 Bash failed with error:", error);
  } finally {
    // 6. Cleanup
    if (project) {
      console.log(`🧹 Cleaning up project ${project.id}...`);
      // Assuming we have a deleteProject binding or we just leave it if not available
      // await project.delete(); 
    }
  }
}

bash();