feat(code-repo): add Bitbucket Cloud provisioning provider#6
Open
pablovilas wants to merge 13 commits into
Open
feat(code-repo): add Bitbucket Cloud provisioning provider#6pablovilas wants to merge 13 commits into
pablovilas wants to merge 13 commits into
Conversation
…t auth Replace the workspace-access-token / OAuth-2LO dual auth model (which never matched the seeded NRN keys and could not enable Pipelines) with a single dedicated bot-user Atlassian API token: - build_context resolves bitbucket.email + bitbucket.apiToken and exports BITBUCKET_EMAIL + BITBUCKET_API_TOKEN; no auth_method branch, no OAuth mint. - _api sends HTTP Basic (email:api_token) on every REST call. - create_repository seeds git over HTTPS with the username x-bitbucket-api-token-auth and the token as password. - run_first_build surfaces a 403 on pipelines enable as the bot-user 2SV requirement, not a phantom scopes bug. - Tests, smoke runner, README and CHANGELOG updated to the API-token model.
…ken from env Two production-path bugs in build_context: - The provider record from `np provider list` uses the schema (snake_case) attribute shape, like the GitLab provider reads .attributes.setup.access_token. The camelCase paths (projectKey/installationUrl/apiToken) resolved to null; read project_key/installation_url/api_token instead. The camelCase forms are the NRN key names only, kept in the error-message hints. - The api token is marked secret, and providers-api nullifies secret attribute values on authenticated reads, so `np provider list` returns api_token: null -- the platform read cannot supply the credential (GitLab only works because its access_token was never marked secret). Make the BITBUCKET_API_TOKEN env var the primary, documented source; fail loudly explaining the secret-nullification and how to configure it when neither env nor record yields a token. Offline fixtures now mirror real `np provider list` output (snake_case, api_token null) plus an env-provided-token happy path. README documents the credential-sourcing difference vs GitLab and its rationale.
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.
Summary
Adds Bitbucket Cloud as a code-repository provider to
application-lifecycle-manager, the YAML + bash +npCLI provisioning path, at parity with the existing GitLab provider. Implements Plan 08 of the Bitbucket support program.The service dispatches repo provisioning to
scripts/code-repo/$PROVIDER/(create_code_repositoryderives the dir fromaccount.repository_provider). Onlygitlab/existed, so a Bitbucket-backed account failed at a missing path. This addsscripts/code-repo/bitbucket/with the same six contract scripts GitLab has, plus one shared non-step helper.The dispatcher (
scripts/code-repo/create_code_repository) and the workflow (workflows/create_code_repository.yaml) are unchanged — they already select the provider directory by name.Authentication — dedicated bot-user Atlassian API token
nullplatform authenticates to Bitbucket Cloud with a single dedicated bot user's Atlassian API token, over HTTP Basic (
email:api_token). This is the only credential that can enable Bitbucket Pipelines: enabling Pipelines requires a 2SV-enabled user principal, and (validated live) an OAuth 2LO token is refused there with a permanent403while a workspace access token fails the same check.curl -u "$email:$token"on every call.x-bitbucket-api-token-auth, password is the token.build_contextis the only auth-aware step; every other script goes throughbb_api/bb_git. Noauth_methodbranch, no OAuth mint — that dual model in Plan 08's auth section was stale and has been superseded (the plan doc is annotated).Credential sourcing — differs from GitLab (and why)
$CODE_REPOSITORYisnp provider listoutput whoseattributesuse the schema shape, exactly like the GitLab provider reads.attributes.setup.access_token.build_contextreads.attributes.setup.{workspace,email,project_key,installation_url,api_token}. The camelCasebitbucket.projectKeyetc. are NRN key names only.bitbucket-configurationspec marksapi_tokensecret: true, and nullplatform nullifies secret attribute values on authenticated provider reads (nullifySecrets), sonp provider listreturnsapi_token: null. (GitLab's flow only works because itsaccess_tokenwas never marked secret — a laxity not repeated here.) The token's primary, documented source is theBITBUCKET_API_TOKENenvironment variable on the ALM deployment; the non-secret fields still come from the provider record. If the token is absent from both env and record,build_contextfails immediately with a message explaining the secret-nullification and how to configure it.np nrn readinvestigation: it exists and can address raw NRN keys (--nrn/--ids ${ns}.${key}), but it is explicitly deprecated ("might be removed; use Providers instead") and its secret-returning behaviour could not be verified in this environment (no live account with a configured Bitbucket secret). It is therefore not relied upon; ENV is the supported path.What's included
scripts/code-repo/bitbucket/(all mode644— the scripts aresourced, never executed):_apibb_api(HTTP Basic →BB_HTTP_CODE/BB_BODY),bb_encode_uuid,bb_scrub(redacts the API token),bb_git,bb_fail. Noset -euo pipefail(would leak into the sourcing workflow shell).build_contextprojectKey, normalises the repo slug (strip.git, lower-case), and fails loudly if any credential is missing.validate_repository_does_not_existGET /repositories/{ws}/{slug}; 404 = free, 401/403 explicitly ≠ free.create_repositoryPOST(expects 200, not 201) with mandatoryproject.key; seeds the template via git clone + squash + push (ADR-1 — Bitbucket has no import API); reconcilesrepository_urlfromlinks.html.href(Contract A).add_collaboratorsPUT permissions-config/users|groups/...; per-principal failures don't abort the rest; non-members reported loudly with an actionable message (ADR-3 — no workspace-invite API).create_secretsPUTby percent-encoded uuid); alwayssecured: true; endpoint ispipelines_config(underscore).run_first_buildGET404 = never enabled, thenPUT), thenPOST /pipelines/; a403on enable is surfaced as the bot-user 2SV requirement (not a phantom scopes bug); a missingbitbucket-pipelines.yml(400) warns rather than fails.Cross-cutting:
scripts/code-repo/generate_secretsnow emits bothNP_API_KEY(unchanged) andNULLPLATFORM_API_KEYat the provider-agnostic seam, so the shared templates work under either provisioning path. (The GitLab scripts'NP_API_KEY-only bug is left untouched — separate ticket.)links.html.href(neverlinks.clone[], which carries.git+ embedded credentials).README.mddocuments Bitbucket Cloud (config table + auth/collaborator/import limitations);CHANGELOG.mdgets a0.3.0entry.Testing
New offline harness (no bats — pure bash +
jq+ fixture stubs) and a.github/workflows/ci.yamlrunning shellcheck + the suite.project.key, slug normalisation, 404-vs-401 on validate,links.html.hrefvslinks.clone[], Contract A write-back, the 409-no-upsert recovery,pipelines_config404, enable-before-trigger ordering, and ADR-3's non-member error.shellcheck 0.11.0, exact CI invocation) andbash -nclean on every script.tests/smoke_bitbucket_live(operator-run, not CI) added for live scratch-workspace verification — not executed in this PR (needs a real bot-user API token; the bot must have Bitbucket 2SV enabled or the Pipelines-enable step 403s).Notes for reviewers / program
assert_called_gitcould never match a git subcommand that immediately followed the recorded leading tab (clone,init,add) — see commitfix(tests): match git subcommands after the leading tab.account.repo_providermust acceptbitbucket(Plan 02 enum +ALTER TYPE) before the dispatcher can select this directory; thebitbucket-configurationprovider spec must exposesetup.{email,apiToken,workspace,projectKey,installationUrl}(Plan 01).run_first_buildfails on the Pipelines enable with a clear message. Atlassian API tokens expire ≤365 days → rotation required.🤖 Generated with Claude Code