A hub on Bitbucket Cloud¶
A hub hosted on Bitbucket Cloud, whose CI is Bitbucket Pipelines: the template's
bitbucket-pipelines.yml checks every pull request to the hub and delivers from the
default branch. Bitbucket Data Center is not supported.
Not verified on a live Bitbucket yet
The Bitbucket support is built from Atlassian's documentation and tested against a stand-in of its API, not on a live workspace. The points a first live run must confirm are listed under Assumed, not yet seen live.
touchmark setup has nothing for Bitbucket yet: the steps below are by hand.
Where the write key can live¶
Bitbucket Pipelines gives a step the variables of a deployment environment only when the
step names it (deployment: touchmark-distribute). But any branch's copy of
bitbucket-pipelines.yml can name it too, so the write key stays on the default branch
only when the environment's deployment permissions stop the steps of other branches
(they pause).
Those permissions are a Premium feature, and Bitbucket's API does not show them, so
touchmark cannot check them. Choose by plan:
| Plan | hub.yml |
What keeps the write key |
|---|---|---|
| Premium | write_isolation: platform and a reason that states the restriction |
the deployment touchmark-distribute admits the default branch only, and only admins or selected users deploy to it; you state it, touchmark cannot read it |
| Free, Standard | write_isolation: none and a reason |
nothing but who may push: every branch of the hub can read the write key; protect the branches and keep write access to the hub tight |
| any | write_isolation: external |
an external secret store that releases the key to the default branch only |
# hub.yml of a hub on Bitbucket Premium
version: 1
id: acme-eng
writer: "{3f2a8d4e-1b6c-4f0a-9e7d-5c2b1a0f9e8d}" # the writer account's UUID
security:
write_isolation: platform
reason: "Bitbucket Premium: only admins may deploy to touchmark-distribute, from main only"
Under platform without a reason, which is how the template ships, distribute and
doctor refuse to run on Bitbucket Pipelines (exit 2): a hub on Free or Standard is
never taken for isolated. On every plan the probe step fails a pipeline that sees a
write key in a repository or workspace variable.
Steps¶
- Create the hub. In your workspace choose Create → Repository → Import
repository, and give the URL of
the template,
https://github.com/bedrock-python/engineering-assets-template.git. Keep it private unless the hub may be public. Turn Pipelines on under Repository settings → Pipelines → Settings. - Create two bot accounts, Atlassian accounts that only touchmark uses, each with an
API token (Atlassian account settings → Security → API tokens, with scopes):
- the reader, with read access to your target repositories and the scopes
read:user,read:workspace,read:repository,read:pullrequest(all…:bitbucket); - the writer, with write access to the targets only (not admin, and no access to
the hub), and the reader's scopes plus
write:repositoryandwrite:pullrequest. A token's scopes do not narrow the repositories it reaches, the account's permissions do. See Bitbucket Cloud for the details.
- the reader, with read access to your target repositories and the scopes
- Create the hub's access token. Under Repository settings → Security → Access
tokens of the hub, create one with Repositories: Read and Pull requests: Write.
Pipelines gives a step no API token of its own: touchmark reads the hub's default
branch, its tip and visibility with this token, and keeps
plan's comment in the hub pull request with it. It reaches the hub alone, and every pipeline of the hub sees it, so give it nothing more;Pull requests: Writealso lets it merge, so restrict who may merge into the default branch (step 5). - Store the keys under Repository settings → Pipelines → Repository variables
and → Deployments, all Secured:
- repository variables:
TOUCHMARK_READ_TOKEN(the reader's API token) andTOUCHMARK_PIPELINES_TOKEN(the hub's access token); - create the deployment environment
touchmark-distributeand store the writer's API token as its variableTOUCHMARK_WRITE_TOKEN, and nowhere else: not as a repository or workspace variable; - on Premium, open the environment's settings: allow deployments from the default
branch only, and let only admins deploy (Only allow admins to deploy to this
environment) or only named users or groups (Allow selected users or groups to
deploy to this environment). The branch alone is not enough: anyone with write
access to the hub can run the custom pipelines on the default branch and pass
them variables (below).
The hub delivers to Bitbucket Cloud with these one-provider names; with
providersinhub.ymlthey carry the provider's id (TOUCHMARK_BB_WRITE_TOKEN).
- repository variables:
- Protect the hub. Under Repository settings → Branch restrictions, let no one
push to the default branch directly and only your maintainers merge into it; keep the
bot accounts and the hub's access token out of those lists. Bitbucket reads none of
the template's CODEOWNERS files: replace
@acme/hub-maintainersin them with your team, or delete them with the other platforms' CI files (touchmark checkwarns about the placeholder). - Schedule the runs. Under Pipelines → Schedules, create two schedules on the
default branch: a daily one for the custom pipeline
distribute, and a weekly one fordoctor. - Describe your hub. In
hub.ymlsetid,writerto the writer account's UUID in quotes (GET https://api.bitbucket.org/2.0/userwith its token shows it), andsecurityas above. List your repositories intargets.yml(org: <workspace>withmatch, orrepo: <workspace>/<repository>; Bitbucket has no topics). - Open a pull request and check the
probe,checkandplansteps.plankeeps its report in one comment of the pull request, and the report files are the step's artifacts. - Merge it. The push pipeline of the default branch runs
probe, thendistribute, which opens a pull request in every repository that has opted in. Run pipeline runs the custom pipelinesdistributeanddoctorby hand.
What the pipelines do¶
| Pipeline | Steps |
|---|---|
| pull request to the hub | probe, check, plan --strict --comment |
push to main or master, the custom pipeline distribute |
probe, then distribute with deployment: touchmark-distribute |
the custom pipeline doctor |
probe, then doctor with deployment: touchmark-distribute |
- The default branch. Pipelines names no default branch, so touchmark reads it with
TOUCHMARK_PIPELINES_TOKEN(a public hub answers without it) and refusesdistributeanddoctoron any other branch, or when it cannot read it. The push pipeline starts onmainandmaster: add your default branch to its pattern if it has another name. - The deployment.
distributeanddoctorrun only in a step withdeployment: touchmark-distribute(BITBUCKET_DEPLOYMENT_ENVIRONMENT). Bitbucket runs one deployment to an environment at a time, so two runs never overlap. - Time. The
distributestep may run 6 hours (max-time: 360); touchmark starts no target after 5 hours 30 minutes (--deadline 5h30m), and the next run picks up what is left. - Reports. Bitbucket has no step summary or annotations: the report is in the step's
log, and
touchmark-report.{md,json,jsonl}andtouchmark-doctor.{md,json}are the steps' artifacts (kept 14 days). - The plan comment is written with the hub's access token. Bitbucket shows HTML as
text, so the comment has no folded sections, and its marker is a Markdown link
reference definition,
[touchmark-plan]: # "touchmark plan: <hub id>", which renders as nothing. An access token cannot tell its own account, so touchmark edits the newest comment with the marker that Bitbucket lets it edit, and writes a new one otherwise. - The fingerprint of the hub is
bitbucket.org/<repository UUID>, lowercase and without braces:bitbucket.org/3f2a8d4e-1b6c-4f0a-9e7d-5c2b1a0f9e8d.--hub-fpandprevious_fingerprintsalso take the UUID asBITBUCKET_REPO_UUIDgives it, in braces. - Custom pipelines accept variables when they run: anyone with write access to the
hub can run them, through the website or the API, and a pipeline variable overrides a
deployment variable. The template's scripts reference no variable, so the website asks
for none, but the API takes any. touchmark's git ignores the variables that would
change its config or the programs it runs (
GIT_CONFIG_*,GIT_SSH_COMMAND,LD_PRELOAD, …; see the threat model), but whoever runs the step chooses its whole environment. So restrict the deploymenttouchmark-distributeto admins or named users, not only to the default branch: on Premium, deployment permissions pause a run by anyone else.
Check it¶
touchmark doctor --hub-token, run from a clone of the hub, reads where the keys live
with the token in TOUCHMARK_HUB_TOKEN: a one-off access token of the hub with
Repositories: Read and Pipelines: Read, or a maintainer's API token with
read:repository:bitbucket and read:pipeline:bitbucket (not the pipelines' own
token, which needs no Pipelines scope). It finds that a write key in a repository or workspace variable fails, one in the
deployment touchmark-distribute is unknown (the API does not show who may deploy; it
is ok when the environment admits only admins), and a variable that is not secured
warns. Workspace variables need a workspace administrator's token; without one they are
reported as not read.
Assumed, not yet seen live¶
- Pipelines runs the step scripts with the image's shell, not its
touchmarkentrypoint, and the image's user (uid 65532) may write the report files into the clone. If not, setrun-as-useron the steps. - The
planstep'sgit fetchwrites into the clone's.git, and Bitbucket clones as root (BCLOUD-23217): if Pipelines runs the step as the image's user (uid 65532), the fetch may fail with a permission error. Then setrun-as-user: 0on theplanstep. git fetch originworks in a pull request's step with Pipelines' own credentials.BITBUCKET_DEPLOYMENT_ENVIRONMENTholds the environment's name (touchmark-distribute).- An access token with Pull requests: Write may comment on the hub's pull requests,
and a
PUTof another account's comment answers 403. - Bitbucket renders a link reference definition in a comment as nothing.
restrictions.admin_onlyof a deployment environment, which the API returns but does not document.- Custom pipeline variables via the API: a run started through the API with variables the YAML does not declare gets them in its environment, overriding deployment variables, and a deployment restricted to admins or selected users pauses it when someone else starts it.
- A scheduled run, and the push pipeline after a merge, pass a deployment restricted to admins or selected users; Atlassian says deployment permissions hold scheduled and automated deployments too, until an allowed user resumes them.
Next: opt a repository in.