diff --git a/README.md b/README.md index f600174e..80dc44cb 100644 --- a/README.md +++ b/README.md @@ -84,7 +84,7 @@ bb auth status ``` ```text -Target Bitbucket: https://bitbucket.acme.corp (expected version 9.4.16, auth=token, source=stored/default) +Target Bitbucket: https://bitbucket.acme.corp (auth=token, source=stored/default) ``` **Clone and browse** — no need to look up URLs: @@ -123,7 +123,7 @@ bb --json auth status "version": "v2", "data": { "bitbucket_url": "https://bitbucket.acme.corp", - "bitbucket_version_target": "9.4.16", + "bitbucket_version_target": "", "auth_mode": "token", "auth_source": "stored/default" }, @@ -146,8 +146,16 @@ bb --json auth status ## Compatibility and contracts -- Primary target: Atlassian Bitbucket Data Center `9.4.x` -- API contract source: Atlassian Bitbucket `9.4` OpenAPI (`docs/reference/atlassian/bitbucket-9.4-openapi.json`) +- Supported version: the newest Bitbucket Data Center release that runs in the project's + container stack and passes the live integration suite. There is no pinned target advertised + here — the version under test is the image tag in `docker/compose.yml`, which is the one place + it is recorded. Newer releases are adopted by bumping that image when they work; some do not + run in the stack, so the newest published release is not automatically the supported one. + Set `BITBUCKET_VERSION_TARGET` if you want to record a version for your own environment. +- API contract source: a version-pinned Atlassian OpenAPI artifact + (`docs/reference/atlassian/bitbucket-9.4-openapi.json`). This fixes the endpoint and payload + shapes the generated client is built from — it is the provenance of the spec, not a statement + about which server versions work. Behavior is established by live tests, not the spec. - CLI identity and machine contract: `bb` / `bb.machine` `v2` - JSON schemas for bulk policy/plan/status published in docs and versioned with releases diff --git a/docs/decisions/018-supported-bitbucket-version-policy.yaml b/docs/decisions/018-supported-bitbucket-version-policy.yaml index 380df90a..75f82c0e 100644 --- a/docs/decisions/018-supported-bitbucket-version-policy.yaml +++ b/docs/decisions/018-supported-bitbucket-version-policy.yaml @@ -1,7 +1,8 @@ number: 18 title: Supported Bitbucket version policy category: architecture -status: accepted +status: superseded +superseded_by: 42 decision: > Support Atlassian Bitbucket 9.4.16 as the primary compatibility target initially. Additional versions may be introduced through explicit decision updates and expanded live test coverage. diff --git a/docs/decisions/042-track-newest-containerisable-bitbucket-version.yaml b/docs/decisions/042-track-newest-containerisable-bitbucket-version.yaml new file mode 100644 index 00000000..0ba07a21 --- /dev/null +++ b/docs/decisions/042-track-newest-containerisable-bitbucket-version.yaml @@ -0,0 +1,48 @@ +number: 42 +title: Track the newest containerisable Bitbucket version +category: architecture +status: accepted +supersedes: 18 +decision: > + Target the newest Bitbucket Data Center version that runs in this project's container stack and + passes the live integration suite, rather than a version pinned in advance. + A release that cannot run in the stack, or that runs but fails the suite, is not a target however + recent it is. + The version under test is recorded only in the stack definition, in docker/compose.yml and + docker/custom-bitbucket/Dockerfile. No other surface states a supported version. +agent_instructions: > + Do not state or assume a specific supported Bitbucket version in code, CLI output, or + documentation, and do not reintroduce a default version target in configuration. + To find the version under test, read the image tag in docker/compose.yml. + To move to a newer release, bump the image there and in docker/custom-bitbucket/Dockerfile and let + the live suite decide whether it holds; do not assume the newest published release is usable. + Where behavior differs between versions, record the version it was observed on next to the + workaround and cover it with a live test. +rationale: > + The previous 9.4.16 pin drifted. The stack moved on while the configuration default, the auth + status output, and the README still advertised 9.4.16, so the documented target described a + version nothing was testing against. + The intent was never to freeze on one release but to run the newest version that works, and that + has a real upper bound: newer releases have failed to run in this containerised stack, so the + newest published release and the newest supportable one are not the same thing. + Support is therefore a property of the stack and the suite rather than a number to restate, and + keeping it in the stack definition leaves one place to change on upgrade with no copies to drift. +rejected_alternatives: + - alternative: Bump the pinned target to the current stack version + reason: > + Drifts again at the next upgrade and recreates the duplicated copies this removes, without + making the claim any better verified. + - alternative: Always track the newest published Bitbucket release + reason: > + Newer releases have broken this containerised stack, so tracking the newest release would + claim support for versions the suite cannot exercise. + - alternative: Declare a supported version range + reason: > + Implies every version in the range is verified, which nothing in this project establishes, and + the upper bound is whatever still runs in the container rather than a version chosen up front. + - alternative: Remove the bitbucket_version_target field from machine output + reason: > + It is a required field of the bb.machine envelope, so removing it breaks consumers. Leaving it + settable lets operators record a version for their own environment without the project + asserting one. +provenance: human diff --git a/docs/site/adr/018-supported-bitbucket-version-policy.md b/docs/site/adr/018-supported-bitbucket-version-policy.md index cdc59521..2c69bbfb 100644 --- a/docs/site/adr/018-supported-bitbucket-version-policy.md +++ b/docs/site/adr/018-supported-bitbucket-version-policy.md @@ -5,7 +5,8 @@ This page is generated from `docs/decisions/*.yaml` by `task docs:export-adr-mar - Number: `018` - Title: `Supported Bitbucket version policy` - Category: `architecture` -- Status: `accepted` +- Status: `superseded` +- Superseded By: `042` - Provenance: `guided-ai` - Source: `docs/decisions/018-supported-bitbucket-version-policy.yaml` diff --git a/docs/site/adr/042-track-newest-containerisable-bitbucket-version.md b/docs/site/adr/042-track-newest-containerisable-bitbucket-version.md new file mode 100644 index 00000000..e8e4ac77 --- /dev/null +++ b/docs/site/adr/042-track-newest-containerisable-bitbucket-version.md @@ -0,0 +1,30 @@ +# ADR 042: Track the newest containerisable Bitbucket version + +This page is generated from `docs/decisions/*.yaml` by `task docs:export-adr-markdown`. Do not edit manually. + +- Number: `042` +- Title: `Track the newest containerisable Bitbucket version` +- Category: `architecture` +- Status: `accepted` +- Supersedes: `018` +- Provenance: `human` +- Source: `docs/decisions/042-track-newest-containerisable-bitbucket-version.yaml` + +## Decision + +Target the newest Bitbucket Data Center version that runs in this project's container stack and passes the live integration suite, rather than a version pinned in advance. A release that cannot run in the stack, or that runs but fails the suite, is not a target however recent it is. The version under test is recorded only in the stack definition, in docker/compose.yml and docker/custom-bitbucket/Dockerfile. No other surface states a supported version. + +## Agent Instructions + +Do not state or assume a specific supported Bitbucket version in code, CLI output, or documentation, and do not reintroduce a default version target in configuration. To find the version under test, read the image tag in docker/compose.yml. To move to a newer release, bump the image there and in docker/custom-bitbucket/Dockerfile and let the live suite decide whether it holds; do not assume the newest published release is usable. Where behavior differs between versions, record the version it was observed on next to the workaround and cover it with a live test. + +## Rationale + +The previous 9.4.16 pin drifted. The stack moved on while the configuration default, the auth status output, and the README still advertised 9.4.16, so the documented target described a version nothing was testing against. The intent was never to freeze on one release but to run the newest version that works, and that has a real upper bound: newer releases have failed to run in this containerised stack, so the newest published release and the newest supportable one are not the same thing. Support is therefore a property of the stack and the suite rather than a number to restate, and keeping it in the stack definition leaves one place to change on upgrade with no copies to drift. + +## Rejected Alternatives + +- `Bump the pinned target to the current stack version`: Drifts again at the next upgrade and recreates the duplicated copies this removes, without making the claim any better verified. +- `Always track the newest published Bitbucket release`: Newer releases have broken this containerised stack, so tracking the newest release would claim support for versions the suite cannot exercise. +- `Declare a supported version range`: Implies every version in the range is verified, which nothing in this project establishes, and the upper bound is whatever still runs in the container rather than a version chosen up front. +- `Remove the bitbucket_version_target field from machine output`: It is a required field of the bb.machine envelope, so removing it breaks consumers. Leaving it settable lets operators record a version for their own environment without the project asserting one. diff --git a/docs/site/adr/index.md b/docs/site/adr/index.md index 221f304e..4c9927f7 100644 --- a/docs/site/adr/index.md +++ b/docs/site/adr/index.md @@ -4,7 +4,7 @@ Published Architecture and Development Decision Records for this project. This page and linked ADR pages are generated from `docs/decisions/*.yaml` by `task docs:export-adr-markdown`. -- Total ADRs: `41` +- Total ADRs: `42` - Accepted ADRs: `40` ## ADR List @@ -26,7 +26,7 @@ This page and linked ADR pages are generated from `docs/decisions/*.yaml` by `ta - [ADR 015: Live test harness and deterministic seeding](015-live-test-harness-and-deterministic-seeding.md) (`development`, `accepted`) - [ADR 016: Test classification and execution policy](016-test-classification-and-execution-policy.md) (`development`, `accepted`) - [ADR 017: Undocumented behavior registry via live tests](017-undocumented-behavior-registry-via-live-tests.md) (`development`, `accepted`) -- [ADR 018: Supported Bitbucket version policy](018-supported-bitbucket-version-policy.md) (`architecture`, `accepted`) +- [ADR 018: Supported Bitbucket version policy](018-supported-bitbucket-version-policy.md) (`architecture`, `superseded`) - [ADR 019: Configuration and secret handling policy](019-configuration-and-secret-handling-policy.md) (`development`, `accepted`) - [ADR 020: Execgit as default Git backend](020-execgit-as-default-git-backend.md) (`architecture`, `accepted`) - [ADR 021: Persistent auth configuration and keyring storage](021-persistent-auth-configuration-and-keyring-storage.md) (`architecture`, `accepted`) @@ -50,4 +50,5 @@ This page and linked ADR pages are generated from `docs/decisions/*.yaml` by `ta - [ADR 039: Built-in MCP server with explicit host scoping and token capability restriction](039-built-in-mcp-server-with-host-scoping-and-token-restriction.md) (`architecture`, `accepted`) - [ADR 040: Agent skill distribution via static npx packaging and dynamic CLI generation](040-agent-skill-distribution-static-npx-and-dynamic-cli.md) (`development`, `accepted`) - [ADR 041: Host aliases and clone URL discovery for server contexts](041-host-aliases-and-clone-url-discovery-for-server-contexts.md) (`architecture`, `accepted`) +- [ADR 042: Track the newest containerisable Bitbucket version](042-track-newest-containerisable-bitbucket-version.md) (`architecture`, `accepted`) diff --git a/internal/cli/cmd/auth/auth.go b/internal/cli/cmd/auth/auth.go index a0b3887e..f1921a56 100644 --- a/internal/cli/cmd/auth/auth.go +++ b/internal/cli/cmd/auth/auth.go @@ -97,14 +97,14 @@ func New(deps Dependencies) *cobra.Command { return deps.WriteJSON(cmd.OutOrStdout(), payload) } - fmt.Fprintf( - cmd.OutOrStdout(), - "Target Bitbucket: %s (expected version %s, auth=%s, source=%s)\n", - cfg.BitbucketURL, - cfg.BitbucketVersionTarget, - cfg.AuthMode(), - cfg.AuthSource, - ) + // The expected version is only reported when the operator pinned + // one; the project itself does not claim a supported version. + details := fmt.Sprintf("auth=%s, source=%s", cfg.AuthMode(), cfg.AuthSource) + if version := strings.TrimSpace(cfg.BitbucketVersionTarget); version != "" { + details = fmt.Sprintf("expected version %s, %s", version, details) + } + + fmt.Fprintf(cmd.OutOrStdout(), "Target Bitbucket: %s (%s)\n", cfg.BitbucketURL, details) return nil }, } diff --git a/internal/cli/cmd/auth/auth_test.go b/internal/cli/cmd/auth/auth_test.go index c3ada0e0..d759737c 100644 --- a/internal/cli/cmd/auth/auth_test.go +++ b/internal/cli/cmd/auth/auth_test.go @@ -1609,3 +1609,63 @@ func recentResponseToAll(response *openapigenerated.GetRepositoriesRecentlyAcces ApplicationjsonCharsetUTF8200: response.ApplicationjsonCharsetUTF8200, } } + +// TestStatusHumanOmitsVersionWhenUnpinned covers the default: the project does +// not claim a supported Bitbucket version, so status must not report one +// unless the operator pinned it (ADR 042). +func TestStatusHumanOmitsVersionWhenUnpinned(t *testing.T) { + cmd := New(Dependencies{ + JSONEnabled: func() bool { return false }, + LoadConfig: func() (config.AppConfig, error) { + return config.AppConfig{ + BitbucketURL: "http://bitbucket.example", + AuthSource: "env/default", + }, nil + }, + }) + + buffer := &bytes.Buffer{} + cmd.SetOut(buffer) + cmd.SetErr(buffer) + cmd.SetArgs([]string{"status"}) + + if err := cmd.Execute(); err != nil { + t.Fatalf("expected no error, got: %v", err) + } + + output := buffer.String() + if strings.Contains(output, "expected version") { + t.Errorf("status must not report a version when none is pinned, got %q", output) + } + if !strings.Contains(output, "http://bitbucket.example") { + t.Errorf("expected the target host in the output, got %q", output) + } +} + +// TestStatusHumanReportsPinnedVersion covers the opposite: an operator who set +// BITBUCKET_VERSION_TARGET still sees it. +func TestStatusHumanReportsPinnedVersion(t *testing.T) { + cmd := New(Dependencies{ + JSONEnabled: func() bool { return false }, + LoadConfig: func() (config.AppConfig, error) { + return config.AppConfig{ + BitbucketURL: "http://bitbucket.example", + BitbucketVersionTarget: "10.2.1", + AuthSource: "env/default", + }, nil + }, + }) + + buffer := &bytes.Buffer{} + cmd.SetOut(buffer) + cmd.SetErr(buffer) + cmd.SetArgs([]string{"status"}) + + if err := cmd.Execute(); err != nil { + t.Fatalf("expected no error, got: %v", err) + } + + if output := buffer.String(); !strings.Contains(output, "expected version 10.2.1") { + t.Errorf("expected the pinned version to be reported, got %q", output) + } +} diff --git a/internal/config/config.go b/internal/config/config.go index b4de013c..c11bdac9 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -18,7 +18,10 @@ import ( ) const ( - defaultBitbucketVersionTarget = "9.4.16" + // No default Bitbucket version target: the supported version is whatever the + // container stack runs and the live suite passes against (ADR 042). Operators + // may still pin one for their own environment via BITBUCKET_VERSION_TARGET. + defaultBitbucketVersionTarget = "" defaultProjectKey = "TEST" defaultRequestTimeout = 20 * time.Second defaultRetryCount = 2