AI Agents SDE Task Viewer
      • Context
      • Plan
      • Prd
  1. Home
  2. AgentSDE
  3. agent-core
  4. gh-546
  5. plan
  6. context.json
context.json(6.9 KB)· Apr 23, 2026
{
  "meta": {
    "agent": "planner",
    "task_id": "546",
    "title": "BJ-6: BitbucketAdapter + webhook route",
    "created_at": "2026-04-23T17:15:00Z"
  },
  "inputs": [
    {
      "name": "issue",
      "type": "link",
      "ref": "AgentSDE/agent-core#546",
      "notes": "Wave 2, depends on #540 (BJ-0)"
    },
    {
      "name": "epic",
      "type": "link",
      "ref": "AgentSDE/agent-core#539",
      "notes": "Atlassian integration EPIC"
    },
    {
      "name": "interface",
      "type": "file",
      "ref": "src/webhook/adapters/platform-adapter.interface.ts"
    },
    {
      "name": "reference-adapter",
      "type": "file",
      "ref": "src/webhook/adapters/github.adapter.ts"
    },
    {
      "name": "controller",
      "type": "file",
      "ref": "src/webhook/webhook.controller.ts"
    },
    {
      "name": "module",
      "type": "file",
      "ref": "src/webhook/webhook.module.ts"
    },
    {
      "name": "dispatch-event",
      "type": "file",
      "ref": "src/webhook/dto/dispatch-event.dto.ts"
    }
  ],
  "outputs": [
    {
      "name": "plan",
      "type": "spec",
      "format": "md",
      "content": "See plan.md"
    }
  ],
  "files": [
    {
      "path": "src/webhook/adapters/bitbucket.adapter.ts",
      "action": "create",
      "reason": "New PlatformAdapter for Bitbucket webhook normalization"
    },
    {
      "path": "src/webhook/adapters/bitbucket.adapter.spec.ts",
      "action": "create",
      "reason": "Unit tests for all event types, auth paths, bot filter"
    },
    {
      "path": "src/webhook/adapters/platform-adapter.interface.ts",
      "action": "modify",
      "reason": "Add optional context arg to verifySignature for non-header auth (query, ip)"
    },
    {
      "path": "src/webhook/adapters/github.adapter.ts",
      "action": "modify",
      "reason": "Accept optional context arg to match updated interface (no behavior change)"
    },
    {
      "path": "src/webhook/webhook.controller.ts",
      "action": "modify",
      "reason": "Add POST /webhooks/bitbucket handler with query + ip context"
    },
    {
      "path": "src/webhook/webhook.module.ts",
      "action": "modify",
      "reason": "Register BitbucketAdapter in onModuleInit()"
    },
    {
      "path": "src/webhook/dto/dispatch-event.dto.ts",
      "action": "modify",
      "reason": "Add pr_updated, approved, changes_requested, push to DispatchEventType"
    },
    {
      "path": "src/config/config.schema.ts",
      "action": "modify",
      "reason": "Declare BITBUCKET_WEBHOOK_SECRET + BITBUCKET_WEBHOOK_IP_ALLOWLIST env vars"
    },
    {
      "path": ".env.example",
      "action": "modify",
      "reason": "Document new Bitbucket env vars"
    },
    {
      "path": "CLAUDE.md",
      "action": "modify",
      "reason": "Add the new env vars to the environment table per repo convention"
    }
  ],
  "steps": [
    {
      "id": "S1",
      "summary": "Extend PlatformAdapter.verifySignature with optional context arg; update GitHubAdapter to match signature (no behavior change).",
      "acceptance": [
        "platform-adapter.interface.ts declares optional context?: { clientIp?: string; query?: Record<string,string> }",
        "GitHubAdapter compiles with new signature and all existing unit tests still pass"
      ],
      "depends_on": []
    },
    {
      "id": "S2",
      "summary": "Extend DispatchEventType union with 'pr_updated' | 'approved' | 'changes_requested' | 'push'.",
      "acceptance": [
        "DispatchEventType union includes the four new values",
        "tsc --noEmit passes across the repo"
      ],
      "depends_on": []
    },
    {
      "id": "S3",
      "summary": "Implement BitbucketAdapter with platform='bitbucket', verifySignature (query secret + IP allowlist), normalize for 7 event types, bot self-filter + /agentsde directive on pullrequest:comment_created.",
      "acceptance": [
        "Class implements PlatformAdapter with platform='bitbucket'",
        "verifySignature throws UnauthorizedException on bad secret or IP outside allowlist; no-op on success",
        "normalize maps all 7 X-Event-Key values to correct DispatchEvent types",
        "Unknown X-Event-Key returns { event: null, reason }",
        "Comment events from bot user are filtered out; /agentsde (and legacy /agent) emit directive events"
      ],
      "depends_on": [
        "S1",
        "S2"
      ]
    },
    {
      "id": "S4",
      "summary": "Register BitbucketAdapter in WebhookModule (providers + onModuleInit) and add POST /webhooks/bitbucket handler in WebhookController that passes req.ip + req.query to verifySignature.",
      "acceptance": [
        "WebhookModule.onModuleInit registers both GitHubAdapter and BitbucketAdapter",
        "POST /webhooks/bitbucket returns 401 when ?secret is missing/wrong",
        "Valid payload returns 200 and enqueues via DispatchService",
        "WebhookDeliveryEntity is persisted with source='bitbucket'"
      ],
      "depends_on": [
        "S3"
      ]
    },
    {
      "id": "S5",
      "summary": "Add BITBUCKET_WEBHOOK_SECRET + BITBUCKET_WEBHOOK_IP_ALLOWLIST to config.schema.ts (optional), .env.example, and CLAUDE.md env table.",
      "acceptance": [
        "Joi schema declares both vars as optional strings",
        ".env.example contains both entries with inline comments",
        "CLAUDE.md environment variables table lists both new vars"
      ],
      "depends_on": [
        "S4"
      ]
    },
    {
      "id": "S6",
      "summary": "Write unit tests in bitbucket.adapter.spec.ts covering all auth + event paths.",
      "acceptance": [
        "verifySignature: valid secret, bad secret, missing secret, allowlist hit, allowlist miss, no allowlist configured",
        "normalize: one test per X-Event-Key (7 total) + unknown key + bot self-filter + /agentsde directive on PR comment",
        "npm run test passes with the new spec file"
      ],
      "depends_on": [
        "S3"
      ]
    }
  ],
  "risks": [
    {
      "risk": "Extending DispatchEventType may break downstream exhaustive switches in dispatch/phase services.",
      "mitigation": "Run npm run build; add default/no-op branches where new event types are not yet handled — they will be wired in later BJ-* tickets."
    },
    {
      "risk": "IP allowlist implementation complexity (CIDR parsing).",
      "mitigation": "Accept only comma-separated plain IPv4/IPv6 strings for v1; CIDR support deferred unless the issue explicitly requires it."
    },
    {
      "risk": "Interface change could conflict with in-flight BJ-0 (#540).",
      "mitigation": "Keep context arg strictly optional; coordinate rebase of #540 if needed — both target rc/atlassian-integration."
    }
  ],
  "assumptions": [
    "Unknown X-Event-Key values return 200 with { event: null } — same pattern as GitHubAdapter.",
    "IP allowlist matches raw strings (no CIDR) for v1 unless subsequent review requires otherwise.",
    "BITBUCKET_WEBHOOK_SECRET remains optional in Joi schema — route returns 401 via verifySignature when the env var is unset.",
    "Tenant resolution for Bitbucket reuses the existing TenantResolverService with platform='bitbucket'; extraction of repoFullName from the Bitbucket payload uses repository.full_name (same key as GitHub).",
    "PR base branch is rc/atlassian-integration (per issue) — branch already exists on the worktree."
  ],
  "open_questions": [
    "Should CIDR parsing be supported in BITBUCKET_WEBHOOK_IP_ALLOWLIST, or is a plain IP list sufficient for v1?"
  ]
}
Plan