diff --git a/archreview/2026-07-12/remediation/00-tracking.md b/archreview/2026-07-12/remediation/00-tracking.md index a7c9fde..95d95c6 100644 --- a/archreview/2026-07-12/remediation/00-tracking.md +++ b/archreview/2026-07-12/remediation/00-tracking.md @@ -183,3 +183,4 @@ Sequence these together rather than piecemeal — several are one change set spa | 2026-08-07 | **CLI-39 → `Done`** (branch `fix/cli-39-version-train`). The last client task in the P1 release train — lands after CLI-35/36/37/38/40/41/44/45 so the next publish carries the conformant behavior, not the pre-remediation API. Bumped all five client version constants off the already-published 0.1.2: Rust `Cargo.toml` `[package]` + `[workspace.package]` → 0.2.0 (`crates/mxgw-cli` inherits via `version.workspace = true`; `CLIENT_VERSION` already derived via `env!("CARGO_PKG_VERSION")` from CLI-29, no separate edit needed); Python `pyproject.toml` + `version.py` → 0.2.0, plus a new `test_version_matches_pyproject_toml` (`clients/python/tests/test_cli.py`) that parses `pyproject.toml` with `tomllib` and asserts `__version__` matches it — closes the CLI-26 residual (the old test only checked self-consistency against `__version__`, so the two literals could still drift from each other undetected); Go `mxgateway/version.go` `ClientVersion` → 0.2.0; .NET `ZB.MOM.WW.MxGateway.Client.csproj` `` → 0.2.0. **Java is the one exception, landed at 0.2.1, not 0.2.0**: queried the live Gitea package API (`GET /api/v1/packages/dohertj2/maven/com.zb.mom.ww.mxgateway:zb-mom-ww-mxgateway-client/0.2.0` — reachable and credentialed in this environment) and confirmed Java 0.2.0 was already published on 2026-06-26, before the CLI-37/38/40/41 conformance fixes changed the client's observable behavior; reusing 0.2.0 for the now-conformant build would have labeled two different APIs identically, so `build.gradle`'s `subprojects { version = '0.2.1' }`, the hand-maintained `MxGatewayClientVersion.CLIENT_VERSION` constant, and the two `MxGatewayCliTests` version assertions all moved to 0.2.1 together (`clients/java/README.md`'s Maven dependency example updated to match — it had drifted to a stale `0.1.2` example). Confirmed via the same live API that Python (`pypi`) and Rust (`cargo`) had only ever reached 0.1.1 in the registry (0.1.2 was set in source but never actually published), while `nuget` (`ZB.MOM.WW.MxGateway.Client`/`.Contracts`) reached 0.1.2 — recorded as historical context in the new "Versioning" section of `docs/ClientPackaging.md` rather than left implicit. **Publish-pipeline guards:** `scripts/tag-go-module.ps1` gained the CLI-21 guard that was designed but never implemented — after semver validation it now reads `clients/go/mxgateway/version.go`'s `ClientVersion` and throws if it does not equal the requested tag version (stripped of `v`), before touching git. `scripts/pack-clients.ps1` gained a Gitea package-registry collision guard (`Test-GiteaPackageExists`/`Assert-GiteaPackageNotPublished`, hitting the documented `GET /api/v1/packages/{owner}/{type}/{name}/{version}` package API) wired into all four artifact-producing `-Publish` blocks (.NET nupkg identity parsed from the packed filename so both `Client` and `Contracts` are covered; Python from `pyproject.toml`; Rust from `Cargo.toml`; Java from `build.gradle`'s `group`+`version`, **required for a real check** since Gitea's Maven package identity is `groupId:artifactId`, not the bare artifact id — an early version of this guard used the bare id and would have silently never matched anything, caught by testing it live against the known-published 0.2.0 before landing); Go is unaffected (no artifact producer in this script; the version-match guard above is its collision protection). Every non-404 registry response (including a plain 401 from an unauthenticated call) is treated as "cannot verify" and aborts — the guard fails closed, never proceeds on ambiguity. **No `.proto` changes; no publish performed.** Docs same commit: `docs/ClientPackaging.md` gained a "Versioning" section (single-source-of-truth list per client, the bump-before-publish rule, the Java exception with evidence); `clients/dotnet/README.md`, `clients/rust/README.md`, `clients/go/README.md` (install example + `tag-go-module.ps1` example + guard behavior sentence), `clients/java/README.md` had their stale `0.1.1`/`0.1.2` example version strings updated to the new released numbers. **Verification** (macOS, all four non-Java languages against the live tree): `cargo check --workspace` clean (`zb-mom-ww-mxgateway-client v0.2.0`, `mxgw-cli v0.2.0`), `cargo test --workspace` version tests pass (`version_json_output_has_protocol_versions`); `python -m pytest` 164 passed / 1 skipped (was 163; the one new test); Go `gofmt -l .` clean, `go build ./...` clean, `go test ./...` ok; `dotnet build clients/dotnet/ZB.MOM.WW.MxGateway.Client.slnx` 0 warnings/0 errors, client tests 128 passed / 1 skipped (unchanged). `JAVA_HOME=/opt/homebrew/opt/openjdk@17 gradle test` BUILD SUCCESSFUL, CLI suite 51/51 passed including both version-string assertions now at `0.2.1`, **no generated-tree churn** to revert (no `.proto` changed). Script guards: `pwsh -NoProfile` dry-run of `tag-go-module.ps1` — mismatched version (`v1.2.3`) failed with the new guard message before touching git; matched version (`v0.2.0`) passed the guard and reached the pre-existing dirty-working-tree check (expected, uncommitted changes present) — proves the new check runs first and does not block a correct version. `pack-clients.ps1`'s guard functions were exercised directly (dot-sourced in isolation, no pack/publish side effects) against the **live** Gitea registry with real credentials already present in this environment (`GITEA_USERNAME`/`GITEA_TOKEN` from `~/.zshenv`): correctly refused on every known-published artifact (nuget Client 0.1.2, maven 0.2.0, pypi 0.1.1, cargo 0.1.1) and correctly passed on every unpublished target version (0.2.0/0.2.1 across all four). **No actual publish was attempted or performed** — the task explicitly forbids it, and the sandbox additionally refuses any Bash command that inlines `$GITEA_TOKEN`/`$GITEA_USERNAME` into the command text (a credential-use guard, not a git-safety one), so the live checks above ran only by having the script's own functions read the already-exported env vars internally rather than the invoking command line referencing them. | | 2026-08-07 | Code-review follow-up on the same branch (`fix/cli-39-version-train`). **Important gap fixed:** `src/ZB.MOM.WW.MxGateway.Contracts/ZB.MOM.WW.MxGateway.Contracts.csproj` was left at `0.1.2` — the original CLI-39 pass bumped the .NET Client but missed that `Invoke-PackDotnet` in `scripts/pack-clients.ps1` packs and publishes **both** `ZB.MOM.WW.MxGateway.Contracts` and `.Client` through the same `-Publish` loop, and the new collision guard runs every `ZB.MOM.WW.MxGateway.*.nupkg` it finds through `Assert-GiteaPackageNotPublished`. Left as-is, the next real `.NET` publish would have packed Contracts at the already-published 0.1.2, the guard would have correctly refused it, and the bare `ForEach-Object` would have aborted mid-loop — with `Client` (0.2.0, alphabetically first) potentially already pushed and `Contracts` stuck at 0.1.2, the two published nupkgs out of lockstep. Fixed: bumped `Contracts.csproj` to `0.2.0` alongside the Client (they have always released together). Also updated the now-stale comment in `src/Directory.Build.props` (it previously said the repo-wide `0.1.2` default was "kept ... to match the Contracts package"; that's no longer true now that Contracts overrides it — the comment now explains the override and that Server/Worker/Tests staying at `0.1.2` is a separate, not-yet-made decision; the `Directory.Build.props` `` value itself was **not** changed, since Server/Worker are not published packages and were out of scope for CLI-39). `docs/ClientPackaging.md`'s "Versioning" section gained `Contracts.csproj` as a fifth manifest (explaining why it must move with the .NET Client) and a note on the near-miss. **Cheap hardening also applied:** the Python (`pyproject.toml`) and Rust (`Cargo.toml`) version-extraction regexes in `pack-clients.ps1` now scope to the `[project]`/`[package]` section header respectively (matching the first `version = "..."` line anywhere in the file was luck of ordering — Cargo.toml has an identical second one under `[workspace.package]`), plus a one-line comment on the nuget filename-parse regex explaining the lazy-id/anchored-version split. **Verification:** `dotnet build src/ZB.MOM.WW.MxGateway.Contracts/ZB.MOM.WW.MxGateway.Contracts.csproj` 0 warnings/0 errors; `dotnet pack` of that project confirmed the artifact is literally named `ZB.MOM.WW.MxGateway.Contracts.0.2.0.nupkg`; `dotnet build clients/dotnet/ZB.MOM.WW.MxGateway.Client.slnx` still 0 warnings/0 errors. Re-ran the pack-clients.ps1 guard function-harness live against the real Gitea registry: `ZB.MOM.WW.MxGateway.Contracts`/`.Client` **0.1.2 both still refused**, **0.2.0 both now pass** — then went one step further and packed both projects for real (`dotnet pack`, no `-Publish`) and ran the exact `Invoke-PackDotnet` filename-parse-then-guard logic against the two real `.nupkg` files, confirming both parse to `id`/`version` correctly and both clear the live collision check. The scoped Python/Rust regexes were also exercised live against the real `pyproject.toml`/`Cargo.toml` and still resolve to `0.2.0`. No publish performed. | | 2026-08-07 | **TST-30 → fully `Done`** — the operator half (register a second CI runner) executed live on `10.100.0.35` per `docs/runbooks/TST-30-second-ci-runner.md` option (a). A second **instance-level** `act_runner` container, `gitea-runner-2` (runner id 5, capacity 2, labels `ubuntu-latest`/`ubuntu-22.04`), was added to the `/opt/gitea` compose stack with the same `container.network: traefik` setting as the original, its registration token mounted from a `0600` file rather than inlined in compose. The existing `gitea-runner` (id 1, capacity 4) was **not** touched — total capacity went 4 → 6 purely by addition, so the change reverts by removing one container. **Concurrency verified live** (the finding's acceptance test): HEAD `a346d51` was pushed to two scratch branches, `scratch/tst30-a` (run 661) and `scratch/tst30-b` (run 662), while an unrelated run 660 was already in flight; at 13:07:53Z jobs from **three** runs were `in_progress` at once — run 660 `portable` plus run 662 `portable`/`java` on runner 1, and run 661 `portable`/`java` on `gitea-runner-2` — a state the pre-change single-runner topology could not produce. Runner attribution came from `GET /repos/dohertj2/mxaccessgw/actions/runs/{id}/jobs`, which exposes `runner_id`/`runner_name` per job, and was cross-checked against `docker logs gitea-runner-2` (`task 1145 …`, `task 1146 …` pickups at 13:05:22–23Z). **`gitea:3000` resolution holds on the new instance** — the property option (c) was rejected for losing: run 661's `portable` job (task 1145, scheduled on `gitea-runner-2`) logged `git remote add origin http://gitea:3000/dohertj2/mxaccessgw` then a successful `fetch … From http://gitea:3000/dohertj2/mxaccessgw`, and its job container's `/workspace/dohertj2/mxaccessgw` was confirmed checked out at `a346d514dd24e775640e5667aa7cd8e561fec68a`. **Runbook fact corrected:** its checklist expected `GET /repos/dohertj2/mxaccessgw/actions/runners` to show ≥2, but that endpoint still returns `total_count: 0` — correctly, since both runners are instance-scoped, which is exactly what this finding documented; the working check is `GET /api/v1/admin/actions/runners` (lists ids 1, 4 = an unrelated local macOS runner, and 5). A dated "Executed 2026-08-07" note recording this was added to the top of the runbook rather than rewriting its history. No source, workflow, or `docs/GatewayTesting.md` change was needed — the no-cancel reality and the `run-windev-ci.sh` bypass are unaffected by runner count, as that prose already stated. Scratch branches deleted after verification. Tracking: both registers' TST-30 rows, the pending-operator-actions list in `90-candidate-findings-next-cycle.md`, and this row. | +| 2026-08-07 | **CLI-39 publish executed** — the release the version train was cut for is now live on `gitea.dohertylan.com`. Published from HEAD `a346d51` via `scripts/pack-clients.ps1`: `nuget` `ZB.MOM.WW.MxGateway.Client` **0.2.0** + `ZB.MOM.WW.MxGateway.Contracts` **0.2.0**, `pypi` `zb-mom-ww-mxaccess-gateway-client` **0.2.0**, `cargo` `zb-mom-ww-mxgateway-client` **0.2.0**, `maven` `com.zb.mom.ww.mxgateway:zb-mom-ww-mxgateway-client` **0.2.1** (the Java exception recorded in the CLI-39 row above — 0.2.0 was already taken by the pre-conformance build). All five coordinates re-queried through `GET /api/v1/packages/dohertj2/{type}/{name}/{version}` after the push and confirmed `200`. Go ships no artifact: module tag `clients/go/v0.2.0` was created and pushed at `a346d51` by `scripts/tag-go-module.ps1` (its CLI-21 version-match guard passed against `ClientVersion = "0.2.0"`), and `go list -m …@v0.2.0` resolves. Full suites ran pre-push with no failures: 128 .NET, 164 Python, 107 Rust, 79 Java. **Deviation found and fixed:** the first `cargo publish` returned `401` because `CARGO_REGISTRIES_DOHERTJ2_GITEA_TOKEN` held the raw token — cargo forwards that value as the `Authorization` header verbatim and Gitea's cargo registry requires `Bearer ` there (confirmed both ways against `/api/v1/user`: bare → 401, `Bearer`-prefixed → 200), unlike the other feeds' username/token basic-auth pairs. The publish succeeded on retry with the prefix exported shell-locally; the permanent fix was then applied to the operator's `~/.zshenv` (outside this repo; prior file backed up `0600` as `~/.zshenv.bak-cli39`) and re-verified via a `Bearer`-authed `GET /api/v1/user` → `200`. The requirement is now documented in `docs/ClientPackaging.md`'s Rust section, and that doc's "Versioning" section carries the published-coordinates record so the next bump starts from the real registry state rather than a re-check. No source, proto, script, or test change — publish execution plus docs. Tracking: `docs/ClientPackaging.md` and this row (CLI-39's register rows in both this file and `50-clients.md` were already plain `Done` with no publish-pending annotation to clear). | diff --git a/docs/ClientPackaging.md b/docs/ClientPackaging.md index f4f6af6..8833e72 100644 --- a/docs/ClientPackaging.md +++ b/docs/ClientPackaging.md @@ -99,6 +99,18 @@ numbers are still unclaimed — the guards above do this automatically at publish time, but a version bump in the source is still a manual step per client. +On 2026-08-07 that release shipped. Published coordinates on +`gitea.dohertylan.com`: `nuget` `ZB.MOM.WW.MxGateway.Client` **0.2.0** and +`ZB.MOM.WW.MxGateway.Contracts` **0.2.0**, `pypi` +`zb-mom-ww-mxaccess-gateway-client` **0.2.0**, `cargo` +`zb-mom-ww-mxgateway-client` **0.2.0**, `maven` +`com.zb.mom.ww.mxgateway:zb-mom-ww-mxgateway-client` **0.2.1** (the Java +exception described above). Go publishes no artifact — it ships as the module +tag `clients/go/v0.2.0`, created at commit `a346d51`. Each coordinate was +confirmed present through the Gitea package API after the push, and +`go list -m` resolves the Go tag. These are the numbers a future release +bumps off. + ## .NET The .NET client uses .NET 10 and references @@ -200,6 +212,12 @@ a `cargo package` that cannot build from the vendored tree alone would mean the vendored copies are stale, and verification is what catches that before publish. +Publishing to the `dohertj2-gitea` alternative registry reads the token from +`CARGO_REGISTRIES_DOHERTJ2_GITEA_TOKEN`, and that variable must hold +`Bearer ` — cargo sends the value as the `Authorization` header +verbatim and Gitea's cargo registry rejects a bare token with `401`, unlike +the other feeds, which authenticate with a username/token basic-auth pair. + Regenerate and compile Rust bindings: ```powershell