Skip to content

feat(control-api): publish recommended client version - #130

Merged
tomi-stipancik merged 3 commits into
mainfrom
feat/tenant-client-version
Sep 17, 2026
Merged

tomi-stipancik merged 3 commits into
mainfrom
feat/tenant-client-version

Conversation

@cubeorgdev

@cubeorgdev cubeorgdev Bot commented Sep 16, 2026

Copy link
Copy Markdown
Contributor

Export an exact recommended Blue release in governance documents and the X-Blue-Required-Client-Version response header. The control API defaults the value to its own release, validates explicit canonical SemVer overrides, and advertises the tenant_client_version_pin capability before personalization.

This is the control-plane half of a two-PR stack. It is not independently deployable: merge #162 before deploying this capability gate, because older clients receive HTTP 426.

Validation: formatting, strict Clippy, workspace tests/build, focused control API and service tests, and byte-identical OpenAPI copies passed. Docs validation was skipped because dependencies are not installed in the workspace.

Fixes #101

@cubeorgdev

cubeorgdev Bot commented Sep 16, 2026

Copy link
Copy Markdown
Contributor Author

This pull request was created from a Blocks session.

View in dashboard | View on desktop

Comment thread crates/gh-service/src/cache.rs Outdated
Comment thread crates/gh-cli/src/client_version.rs Outdated
Comment thread crates/gh-cli/src/commands.rs Outdated
Comment thread crates/gh-cli/src/commands.rs Outdated
Comment thread crates/gh-cli/src/client_version.rs Outdated
Comment thread services/control-api/src/lib.rs Outdated
let mut config = serde_json::from_value(row.document)
.map_err(|error| ApiError::internal(format!("decoding stored config: {error}")))?;
enforce_client_capabilities(&headers, &config)?;
let pin_headers = prepare_client_version_pin(&mut config, env!("CARGO_PKG_VERSION"))?;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The deployment version default uses the compile-time crate version (env!("CARGO_PKG_VERSION")) instead of the runtime BLUE_DEPLOYMENT_VERSION that the Dockerfile, compose file, and release scripts all set. The release check script keeps the two equal at tag time, but any runtime override of BLUE_DEPLOYMENT_VERSION will be ignored, so the X-Blue-Required-Client-Version header and required_client_version document can point clients at the wrong Blue CLI release.

Read BLUE_DEPLOYMENT_VERSION at runtime with a fallback to the crate version, e.g. std::env::var("BLUE_DEPLOYMENT_VERSION").unwrap_or_else(|_| env!("CARGO_PKG_VERSION").into()), and pass that into prepare_client_version_pin. This keeps the documented "defaults to the control API deployment version" behavior correct when the deployment is configured with a non-default version.

Severity 8/10 · View on dashboard

@cubeorgdev
cubeorgdev Bot force-pushed the feat/tenant-client-version branch from 4c6aa82 to ea9cfeb Compare September 17, 2026 02:07
@cubeorgdev cubeorgdev Bot changed the title feat(cli): enforce and repair tenant-required Blue versions feat(control-api): publish recommended client version Sep 17, 2026
Comment on lines 5073 to 5089
async fn governance_config(
State(state): State<Arc<AppState>>,
Extension(who): Extension<Principal>,
headers: HeaderMap,
) -> Result<Json<gh_service::GovernanceConfig>, ApiError> {
) -> Result<Response, ApiError> {
let row = current_config(&state.pool, who.organization_id).await?;
let revision = row.revision;
let mut config = serde_json::from_value(row.document)
.map_err(|error| ApiError::internal(format!("decoding stored config: {error}")))?;
enforce_client_capabilities(&headers, &config)?;
let pin_headers = prepare_client_version_pin(&mut config, env!("CARGO_PKG_VERSION"))?;
if let Err(error) = enforce_client_capabilities(&headers, &config) {
return Ok((pin_headers, error).into_response());
}
personalize_package_config(&state.pool, &revision, who.user_id, &mut config).await?;
personalize_gateway_config(&state, &who, &mut config).await?;
Ok(Json(config))
Ok((pin_headers, Json(config)).into_response())
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This control-plane code publishes the recommended client version and requires the tenant_client_version_pin capability, but the PR title and description claim the full CLI-side feature: blocking governed commands when Blue differs from the tenant pin, including newer clients and cached policy, plus the default-no interactive install/rollback repair flow and platform-specific remedies. None of that CLI logic is present in this diff — the current branch only contains the contract/control-api surface (feat(contract): … and feat(control-api): …). The CLI enforcement implementation appears to be on a separate branch (origin/feat/client-version-enforcement, commit 32832b0).

Either merge that branch into this PR so the title/body match the code, or update the PR title and description to reflect that this is only the server-side prerequisite (feat(control-api) / feat(contract)). Leaving it as-is will confuse reviewers looking for the enforcement/repair behavior described.

Severity 7/10 · View on dashboard

Comment thread deploy/blue.yaml
Comment on lines +70 to +72
# Exact recommended release and major compatibility boundary. Same-major
# differences warn and continue; different majors block.
# required_client_version: "0.1.0"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment describes major-version warning/blocking behavior that isn't implemented in this control-plane PR (or visible in the client half). The field is an exact canonical SemVer pin; enforcement today is only the tenant_client_version_pin capability gate and the X-Blue-Required-Client-Version header. Please align the comment with the actual behavior or remove the unimplemented claims.

Severity 7/10 · View on dashboard

Comment on lines +71 to +73
# Exact recommended release and major compatibility boundary. Same-major
# differences warn and continue; different majors block.
# required_client_version: "0.1.0"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment describes major-version warning/blocking behavior that isn't implemented in this control-plane PR (or visible in the client half). The field is an exact canonical SemVer pin; enforcement today is only the tenant_client_version_pin capability gate and the X-Blue-Required-Client-Version header. Please align the comment with the actual behavior or remove the unimplemented claims.

Severity 7/10 · View on dashboard

@tomi-stipancik
tomi-stipancik merged commit aa86d33 into main Sep 17, 2026
34 checks passed
@tomi-stipancik
tomi-stipancik deleted the feat/tenant-client-version branch September 17, 2026 03:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Blocking incompatibility when the CLI version doesn't match the tenant's

2 participants