feat(bin): add Bitbucket Cloud as a first-class PR provider - #1
Merged
Merged
Conversation
…compatibility Accept any truthy value of HERDR_ENV (true, yes, on, etc.) instead of requiring exact '1' match. This fixes Herdr backend detection in devcontainer and other environments that may stringify booleans. Explicitly reject falsy variants (0, false, no, etc.) and unset. Backward compatible: HERDR_ENV=1 still works as before.
Thread bitbucket through the same provider seams github and gitlab already use in bin/fm-pr-lib.sh and bin/fm-pr-merge.sh: URL parsing, the meta/data/registration/poll/snapshot/retirement records, the per-provider record read, and the guarded merge. Bitbucket Cloud is addressed with curl against the REST API v2.0 and no CLI, since it has no gh/glab-style tool, authenticated with a Workspace or Repository Access Token read from FM_BITBUCKET_TOKEN or the calling home's gitignored .env. Green is a policy definition, since Bitbucket Cloud exposes no required-checks flag: every present commit status on the live head must be SUCCESSFUL with none INPROGRESS/FAILED/STOPPED, and at least one status must have reported at all. The merge endpoint has no head-SHA precondition of its own, so the head is re-read and compared immediately before the merge call; the call may return synchronously (200) or asynchronously (202, a pollable task this path does not chase), and either way one live re-read confirms state=MERGED before anything is reported landed, mirroring the GitLab confirm-merged path exactly. bin/fm-pr-poll.sh's Bitbucket branch (curl+jq, same token resolution) is what eventually confirms an unconfirmed landing. Bitbucket Server/Data Center and any CLI or MCP-server binding remain out of scope. Adds docs/bitbucket-backend.md as the design record, extends docs/architecture.md's PR-merge section, and adds tests/fm-pr-bitbucket.test.sh covering URL parsing, a mocked REST record read, and the merge preconditions.
…-file token delivery
cloud-practitioner
force-pushed
the
main
branch
from
September 21, 2026 23:06
30a79c7 to
aec043c
Compare
Refactor HERDR_ENV check to only accept '1' as truthy.
Remove comments about HERDR_ENV handling.
This was referenced Sep 22, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Intent
Give firstmate full automated pull-request handling on Bitbucket Cloud repositories. The main repository this is needed for is hosted on Bitbucket Cloud, but firstmate's PR pipeline - polling a PR, gating on a green-at-head CI signal, and the guarded merge - currently supports only GitHub and GitLab, so Bitbucket-hosted work cannot use automated PR delivery at all.
Add Bitbucket Cloud as a first-class third PR provider alongside github and gitlab, so a Bitbucket Cloud pull request is polled, CI-gated, and merged through the same guarded pipeline and with the same safety guarantees as the existing two providers. The chosen implementation approach is curl against the Bitbucket Cloud REST API v2.0 - no CLI dependency (not acli), and not via any MCP server. Scope is Bitbucket Cloud only; Bitbucket Server / Data Center is a different API and is explicitly out of scope.
What Changed
bin/fm-pr-lib.sh,bin/fm-pr-check.sh,bin/fm-pr-poll.sh, andbin/fm-pr-merge.shto detect and support Bitbucket Cloud repositories alongside GitHub and GitLab, implementing polling, CI-gating, and guarded merge via curl against the Bitbucket Cloud REST API v2.0 (no CLI/acli or MCP dependency).bin/fm-crew-state.sh,bin/fm-test-run.sh, andbin/fm-watch.shto integrate Bitbucket-related state and workflow handling.docs/bitbucket-backend.mddocumenting the new provider, and updatedREADME.md,docs/architecture.md,docs/scripts.md, anddocs/documentation-audiences.jsonto reference Bitbucket support.tests/fm-pr-bitbucket.test.shcovering the new Bitbucket Cloud PR pipeline and extendedtests/fm-pr-check-security.test.shwith additional security checks.Risk Assessment
✅ Low: The fix-round change is a narrow, correctly and consistently applied mechanical fix to all three previously flagged call sites, removes the token-in-argv exposure, handles temp-file cleanup on both success and error paths, and introduces no new functional risk.
Testing
Ran the dedicated tests/fm-pr-bitbucket.test.sh suite (all 16 assertions pass, covering URL parsing, token resolution, record reads, green-gating, and both synchronous and asynchronous merge paths including the head-moved race refusal) and the shared tests/fm-pr-check-security.test.sh regression suite (all pass, confirming GitHub/GitLab behavior is untouched). Additionally drove a live behavioral check with a PATH-shadowing mock curl to confirm the review-round token-argv-exposure fix: the Bitbucket bearer token appears only inside the curl -K config file's contents, never as a literal argv token, across all three call sites (fm_pr_bitbucket_api_get, fm_pr_bitbucket_api_post, and fm-pr-poll.sh's inlined Bitbucket branch). This is a pure shell-library/CLI change with no Herdr TUI/session lifecycle surface, so the herdr-lab runbook does not apply; the test suite plus direct curl-argv probing is the appropriate live-exercisable surface for this change.
Pipeline
Updates from git push no-mistakes
✅ **intent** - passed
✅ No issues found.
✅ **Rebase** - passed
✅ No issues found.
🔧 **Review** - 1 issue found → auto-fixed ✅
bin/fm-pr-lib.sh:1072- The Bitbucket bearer token is passed to curl as a literal-H "Authorization: Bearer $token"command-line argument in fm_pr_bitbucket_api_get and fm_pr_bitbucket_api_post (bin/fm-pr-lib.sh:1072, 1096) and in bin/fm-pr-poll.sh's inlined bitbucket branch (bin/fm-pr-poll.sh:172). Unlike gh/glab, which manage credentials internally rather than passing them as literal argv, this makes the token visible for the process's lifetime to anything that can read its argv (e.g.ps//proc/<pid>/cmdlinefor same-uid processes). The mechanical fix is to feed the header through curl's-K -/config-file mechanism (or a token file) instead of argv, applied at all three call sites since they share the exact same pattern.🔧 Fix applied.
✅ Re-checked - no issues remain.
✅ **Test** - passed
✅ No issues found.
bash tests/fm-pr-bitbucket.test.sh (16 assertions: URL parsing, token resolution precedence, record reads, green/red gating, synchronous and asynchronous merge, head-moved race refusal)bash tests/fm-pr-check-security.test.sh (shared cross-provider poll/merge/teardown security matrix, unaffected by the Bitbucket addition)Live manual probe: sourced bin/fm-pr-lib.sh with a mock curl on PATH that records its own argv and dumps the contents of any -K config file, then called fm_pr_bitbucket_api_get with a real-shaped FM_BITBUCKET_TOKEN to prove the bearer token is never a literal curl argv token and instead flows only through the -K config file's contents✅ **Document** - passed
✅ No issues found.
🔧 **Lint** - 1 issue found → no changes applied ✅
🔧 No changes applied.
✅ Re-checked - no issues remain.
✅ **Push** - passed
✅ No issues found.