Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .claude/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
"allowedDomains": [
"github.com",
"api.github.com",
"api.bitbucket.org",
"raw.githubusercontent.com",
"objects.githubusercontent.com",
"codeload.github.com",
Expand Down
2 changes: 1 addition & 1 deletion docs/adapters/registry.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ extension point = a documented, labelled slot with a tracking issue.
| [`tools/forwarder-relay`](../../tools/forwarder-relay/) | ASF-security ([`tools/gmail/asf-relay.md`](../../tools/gmail/asf-relay.md)) | huntr.com, HackerOne, GHSA relay |
| [`tools/scan-format`](../../tools/scan-format/) | ASVS | other scanner formats |
| [`tools/vcs`](../../tools/vcs/) | Git, Mercurial | Subversion [\#602](https://github.com/apache/magpie/issues/602), Jujutsu [\#603](https://github.com/apache/magpie/issues/603), Fossil [\#604](https://github.com/apache/magpie/issues/604), Perforce [\#605](https://github.com/apache/magpie/issues/605) |
| Forge / tracker | [`github`](../../tools/github/), [`jira`](../../tools/jira/), [`sourcehut`](../../tools/sourcehut/) | GitLab [\#305](https://github.com/apache/magpie/issues/305), Forgejo/Gitea [\#310](https://github.com/apache/magpie/issues/310), Pagure [\#312](https://github.com/apache/magpie/issues/312), Bitbucket [\#606](https://github.com/apache/magpie/issues/606), Bugzilla [\#302](https://github.com/apache/magpie/issues/302) |
| Forge / tracker | [`github`](../../tools/github/), [`jira`](../../tools/jira/), [`bitbucket`](../../tools/bitbucket/) read-only foundation, [`sourcehut`](../../tools/sourcehut/) | GitLab [\#305](https://github.com/apache/magpie/issues/305), Forgejo/Gitea [\#310](https://github.com/apache/magpie/issues/310), Pagure [\#312](https://github.com/apache/magpie/issues/312), deeper Bitbucket/Jira coverage [\#606](https://github.com/apache/magpie/issues/606), Bugzilla [\#302](https://github.com/apache/magpie/issues/302) |
| Agentic runtime | Claude Code | Codex [#313](https://github.com/apache/magpie/issues/313)–OpenHands [#322](https://github.com/apache/magpie/issues/322) |
| Security cross-ref | — | OSV.dev [#311](https://github.com/apache/magpie/issues/311) |

Expand Down
1 change: 1 addition & 0 deletions docs/labels-and-capabilities.md
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,7 @@ it implements multiple contracts (e.g. `tools/gmail` provides both
| [`tools/dev`](../tools/dev/) | `substrate:framework-dev` | Framework dev-loop helpers |
| [`tools/egress-gateway`](../tools/egress-gateway/) | `substrate:sandbox` | Egress-allowlist forward proxy (proxy.py plugin); host-level egress chokepoint — defence-in-depth for RFC-AI-0003 §4.4 |
| [`tools/forwarder-relay`](../tools/forwarder-relay/) | `contract:report-relay` | Adapter contract for inbound-relay backends (ASF Security relay, huntr.com, HackerOne triagers). Pure interface spec; adapters declare detection + credit-extraction + reporter-addressing rules. |
| [`tools/bitbucket`](../tools/bitbucket/) | `contract:change-request` | Bitbucket Cloud and Bitbucket Data Center read-only bridge foundation for repository metadata and pull-request discovery/fetching. Future PRs will add Bitbucket Issues / Jira handoff coverage before claiming tracker completeness. |
| [`tools/github`](../tools/github/) | `contract:tracker` + `contract:source-control` + `contract:change-request` | GitHub REST / GraphQL tracker substrate (called by every lifecycle phase) plus the Git source-control binding documented in [`source-control.md`](../tools/github/source-control.md) (runnable backend in [`tools/vcs`](../tools/vcs/)) and the pull-request review/merge gate (`change-request`; the ASF default backend, alongside `tools/jira-patch/` and `tools/mail-patch/` for SVN-first projects) |
| [`tools/github-body-field`](../tools/github-body-field/) | `contract:tracker` | Read or rewrite one `### Field` section of a GitHub issue body without bringing the body into agent context — substrate helper for the security-sync skills |
| [`tools/github-rollup`](../tools/github-rollup/) | `contract:tracker` | Append to (or create) the status-rollup comment on a GitHub issue without bringing the rollup body into agent context — substrate helper for every status-update-emitting skill |
Expand Down
7 changes: 4 additions & 3 deletions docs/vendor-neutrality.md
Original file line number Diff line number Diff line change
Expand Up @@ -345,8 +345,9 @@ issue`, not hypothetical:
[Codeberg / Gitea / Forgejo](https://github.com/apache/magpie/issues/310),
[Pagure](https://github.com/apache/magpie/issues/312) (Fedora /
`pagure.io`),
[Bitbucket](https://github.com/apache/magpie/issues/606) (deep Jira
pairing), and
[Bitbucket](https://github.com/apache/magpie/issues/606) (initial
[`tools/bitbucket`](../tools/bitbucket/) bridge; deeper Jira pairing and
write coverage tracked there), and
[SourceHut](https://github.com/apache/magpie/issues/607) (email-patch
review). Tracker-only surfaces are tracked the same way — e.g.
[Bugzilla](https://github.com/apache/magpie/issues/302) — alongside the
Expand Down Expand Up @@ -484,7 +485,7 @@ coverage without pretending one team can implement an open-ended set.
|---|---|---|---|
| LLM backend | ✅ by construction | Claude Code, Ollama, vLLM, Apache-hosted, Bedrock, direct Anthropic | Any endpoint meeting the capability floor + privacy gate |
| Agentic runtime | ✅ by construction (`AGENTS.md` standard) | Claude Code; community use under Codex, Cursor, Gemini CLI, Copilot, OpenCode, Kiro | Runtime adapters [#313–#322](https://github.com/apache/magpie/issues?q=is%3Aissue+state%3Aopen+adapter+in%3Atitle) |
| Forge / tracker | ✅ by construction | GitHub, Jira, SourceHut; CVE/scan/relay via adapter contracts | GitLab [#305](https://github.com/apache/magpie/issues/305), Forgejo/Gitea [#310](https://github.com/apache/magpie/issues/310), Pagure [#312](https://github.com/apache/magpie/issues/312), Bitbucket [#606](https://github.com/apache/magpie/issues/606), Bugzilla [#302](https://github.com/apache/magpie/issues/302) |
| Forge / tracker | ✅ by construction | GitHub, Jira, SourceHut; Bitbucket read-only foundation; CVE/scan/relay via adapter contracts | GitLab [#305](https://github.com/apache/magpie/issues/305), Forgejo/Gitea [#310](https://github.com/apache/magpie/issues/310), Pagure [#312](https://github.com/apache/magpie/issues/312), full Bitbucket tracker/change-request/Jira coverage [#606](https://github.com/apache/magpie/issues/606), Bugzilla [#302](https://github.com/apache/magpie/issues/302) |
| Communication channels | ✅ by construction | PonyMail / mail-archive reads | mbox [#304](https://github.com/apache/magpie/issues/304), IMAP [#303](https://github.com/apache/magpie/issues/303), Mailman 3 [#306](https://github.com/apache/magpie/issues/306); Discourse [#307](https://github.com/apache/magpie/issues/307), Zulip [#308](https://github.com/apache/magpie/issues/308), Matrix [#309](https://github.com/apache/magpie/issues/309) |
| Source control (VCS) | ✅ by construction | **Git (complete)**, **Mercurial (complete)**; ASF SVN surface ([`tools/asf-svn`](../tools/asf-svn/): source control + dist.apache.org + authorization) | Subversion generic VCS binding [\#602](https://github.com/apache/magpie/issues/602) (detected); Jujutsu [\#603](https://github.com/apache/magpie/issues/603), Fossil [\#604](https://github.com/apache/magpie/issues/604), Perforce [\#605](https://github.com/apache/magpie/issues/605) (tracked) |
| Project governance | ✅ by construction | ASF + non-ASF adopter profiles | Adopter config (modes, thresholds) |
Expand Down
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ package = false
members = [
"tools/agent-guard",
"tools/agent-isolation",
"tools/bitbucket",
"tools/egress-gateway",
"tools/cve-tool-vulnogram/generate-cve-json",
"tools/cve-tool-vulnogram/oauth-api",
Expand Down
120 changes: 120 additions & 0 deletions tools/bitbucket/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
**Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)*

- [Bitbucket forge bridge](#bitbucket-forge-bridge)
- [Prerequisites](#prerequisites)
- [Features](#features)
- [Invocation](#invocation)
- [Configuration](#configuration)
- [Output contract](#output-contract)
- [Write-path discipline](#write-path-discipline)
- [Planned follow-up coverage](#planned-follow-up-coverage)

<!-- END doctoc generated TOC please keep comment here to allow auto update -->

<!-- SPDX-License-Identifier: Apache-2.0
https://www.apache.org/licenses/LICENSE-2.0 -->

# Bitbucket forge bridge

**Capability:** contract:change-request

**Kind:** implementation

**Vendor:** Atlassian

Bitbucket Cloud and Bitbucket Data Center bridge for Magpie adopters
that use Bitbucket as a forge, pull-request review surface, or Jira-paired Atlassian backend.

This initial bridge provides a read-only foundation for repository
metadata and pull-request discovery/fetching. It is not a complete
`contract:change-request` backend yet; #606 remains open for the
remaining Bitbucket/Jira workflow coverage. Later PRs can extend the
same adapter with write operations, Bitbucket Issues, linked Jira
handoff, branch permissions, and Pipelines status reads.

## Prerequisites

- **Runtime:** Python 3.11+ run via `uv`; the bridge uses the Python standard library at runtime.
- **CLIs:** `uv` to run the bridge and its tests; no Bitbucket-specific CLI is required.
- **Credentials / auth:** `BITBUCKET_TOKEN` is required for authenticated Bitbucket API calls. Bitbucket Cloud also needs `BITBUCKET_CLOUD_USER`; Data Center uses `BITBUCKET_AUTH_SCHEME=Bearer` by default.
- **Network:** Bitbucket Cloud reaches `api.bitbucket.org`; Bitbucket Data Center reaches the configured `BITBUCKET_BASE_URL`. Adopters using Data Center must explicitly allow their own Bitbucket host in the secure egress configuration.
- **Optional:** `pytest`, `ruff`, and `mypy` run through `uv` for the test/type/lint harness.

## Features

This first implementation covers read-only operations:

1. **Authentication preflight:** verify the configured Bitbucket backend and credentials can reach the selected repository.
2. **Repository metadata:** fetch normalized repository details from Bitbucket Cloud or Data Center.
3. **Pull-request listing:** list open pull requests as `contract:change-request` proposal summaries.
4. **Pull-request fetch:** fetch one pull request as a normalized proposal object.

The bridge supports two Bitbucket API flavours behind one command
surface:

- `BITBUCKET_KIND=cloud`
- `BITBUCKET_KIND=datacenter`

## Invocation

```bash
# Verify Bitbucket configuration and credentials
uv run --project tools/bitbucket magpie-bitbucket auth-check

# Fetch repository metadata
uv run --project tools/bitbucket magpie-bitbucket repo get

# List open pull requests
uv run --project tools/bitbucket magpie-bitbucket pr list-open

# Fetch one pull request
uv run --project tools/bitbucket magpie-bitbucket pr get 123
```

## Configuration

The bridge is configured through environment variables. The calling
skill resolves adopter project configuration and exports these values;
the bridge does not read `<project-config>/` files directly.

| Variable | Required for | Description |
|---|---|---|
| `BITBUCKET_KIND` | all commands | `cloud` or `datacenter`. Defaults to `cloud`. |
| `BITBUCKET_TOKEN` | authenticated API calls | API token or personal access token accepted by the selected backend. For Bitbucket Cloud, use minimum read scopes for repositories and pull requests. |
| `BITBUCKET_AUTH_SCHEME` | all commands | Authentication scheme. Defaults to `Basic` for Cloud and `Bearer` for Data Center. |
| `BITBUCKET_CLOUD_USER` | Cloud Basic auth | Atlassian account email/user used with `BITBUCKET_TOKEN`. |
| `BITBUCKET_WORKSPACE` | Cloud | Bitbucket Cloud workspace slug. |
| `BITBUCKET_REPO_SLUG` | Cloud and Data Center | Repository slug. |
| `BITBUCKET_BASE_URL` | Data Center | Base URL of the Bitbucket Data Center instance. |
| `BITBUCKET_PROJECT_KEY` | Data Center | Data Center project key. |

## Output contract

Every successful command emits JSON to stdout. Failures return a
non-zero exit code with a human-readable error on stderr.

The bridge normalizes Bitbucket Cloud and Data Center responses into
stable fields before emitting output, so consuming skills do not need
to know which backend answered.

## Write-path discipline

This initial bridge is read-only.

Future write commands will follow the same discipline as the GitHub and
Jira tools: the bridge may execute a mutation, but it must not decide
whether to mutate. Calling skills must draft the proposed action,
surface it to the maintainer, wait for explicit confirmation, and only
then invoke the write command.

## Planned follow-up coverage

Follow-up PRs can extend this bridge with:

- Bitbucket issue read/write operations, which will add tracker coverage.
- Linked Jira issue handoff through `tools/jira/`.
- Pull-request comment, review, approve, decline, and merge operations.
- Branch restriction and permission reads.
- Bitbucket Pipelines status reads for change-request `status`.
87 changes: 87 additions & 0 deletions tools/bitbucket/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.

[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

[project]
name = "magpie-bitbucket"
version = "0.1.0"
description = "Bitbucket Cloud and Data Center bridge for Apache Magpie."
readme = "README.md"
requires-python = ">=3.11"
license = { text = "Apache-2.0" }
dependencies = []

[project.scripts]
magpie-bitbucket = "magpie_bitbucket:main"

[tool.hatch.build.targets.wheel]
packages = ["src/magpie_bitbucket"]

[tool.ruff]
line-length = 110
target-version = "py311"
src = ["src", "tests"]

[tool.ruff.lint]
select = [
"E",
"W",
"F",
"I",
"B",
"UP",
"SIM",
"C4",
"RUF",
]
ignore = [
"E501",
]

[tool.ruff.lint.per-file-ignores]
"tests/**" = ["B", "SIM"]

[tool.mypy]
python_version = "3.11"
files = ["src", "tests"]
warn_unused_ignores = true
warn_redundant_casts = true
warn_unreachable = true
check_untyped_defs = true
no_implicit_optional = true
disallow_untyped_defs = true
disallow_incomplete_defs = true

[[tool.mypy.overrides]]
module = "tests.*"
disallow_untyped_defs = false
disallow_incomplete_defs = false

[tool.pytest.ini_options]
minversion = "8.0"
addopts = "-ra -q"
testpaths = ["tests"]

[dependency-groups]
dev = [
"mypy>=1.10",
"pytest>=8.0",
"ruff>=0.6",
]
36 changes: 36 additions & 0 deletions tools/bitbucket/src/magpie_bitbucket/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.

"""Bitbucket forge bridge implementation for Apache Magpie."""

from __future__ import annotations

import sys
from collections.abc import Sequence

__all__ = ["main"]


def main(argv: Sequence[str] | None = None) -> int:
"""CLI entry point."""
from magpie_bitbucket.cli import main as cli_main

try:
return cli_main(argv)
except Exception as exc:
print(f"magpie-bitbucket error: {exc}", file=sys.stderr)
return 1
Loading
Loading