Skip to content

feat: team deployment — bcli doctor, signed bundles, query discovery, records view#10

Merged
igor-ctrl merged 4 commits into
mainfrom
feat/team-deployment
May 8, 2026
Merged

feat: team deployment — bcli doctor, signed bundles, query discovery, records view#10
igor-ctrl merged 4 commits into
mainfrom
feat/team-deployment

Conversation

@igor-ctrl

@igor-ctrl igor-ctrl commented May 8, 2026

Copy link
Copy Markdown
Owner

Summary

First slice of bcli features for team / multi-role deployments.

  • Phase 1bcli doctor: 11 independent checks (profile / tenant / env / company / auth / profile-scoped token cache / registry / field coverage / queries / team bundle / BC connectivity), --json mode, non-zero exit on FAIL. Connectivity uses httpx with trust_env=True so corporate proxies are honored.
  • Phase 2 — team bundle infra: bcli config refresh / rollback / bundle-status / make-bundle. Allowlisted file set, no symlinks/devices, gzip-bomb-bounded fetch (25 MB compressed, 100 MB extracted, 64 members), content-hash + canonical roll-up verifier with traversal rejection, per-profile flock for concurrent refresh, atomic write with .previous backups + manifest backup, field-lists merged into registry on apply, file:// gated behind BCLI_DEV=1.
  • Phase 3 — saved-query discovery: additive YAML metadata (aliases / tags / owner / freshness / examples / related), bcli q list / search / info / run sub-verbs, reserved-name collisions hard-error at bundle load. Substring + alias + tag scoring, no embeddings.
  • Phase 6 — Windows PowerShell wide-table fix: records formatter (vertical, psql \x style). Auto-promote on 1-2 wide rows only when format wasn't user-explicit (-f markdown is honored as a contract).

Phases 4 (response caching) and 5 (Redis-for-AI) stay deferred behind explicit telemetry / scale triggers — see docs/plans/team-deployment.md.

Sha256Verifier is an integrity check, not an authenticity check. Operators distributing bundles via a trusted private channel (org-authenticated HTTPS, internal artifact registry) get authenticity from the channel itself; the integrity check then catches in-flight corruption. Operators who want defense-in-depth plug in a stronger Verifier at that seam — design intent, not a gap.

Test plan

  • uv run pytest tests/ -v593 passed, 1 skipped
  • uv run ruff check src/ — clean
  • bcli doctor smoke-tested against active install
  • bcli q list / search / info smoke-tested against a 60-query saved-query library
  • bcli config make-bundle + bcli config refresh --dry-run round-trip via file:// works under BCLI_DEV=1
  • Bundle fetch rejects: wrong scheme, oversized, path traversal in tar, unexpected filenames, traversal in manifest contents map, tampered file contents, tampered manifest hashes
  • Concurrent apply_bundle from two threads serializes via flock; both finish, manifest is consistent
  • Profile-scoped token cache regression: a valid token for a different tenant no longer reports "OK" for the active profile
  • Explicit -f markdown disables auto-promotion to records view (contract honored)

Files of interest

  • src/bcli/diagnostics/_checks.py — diagnostic primitives
  • src/bcli/bundle/{_manifest,_verify,_fetch,_apply,_publish}.py — bundle pipeline
  • src/bcli_cli/commands/{doctor_cmd,refresh_cmd}.py — CLI surfaces
  • src/bcli/workflow/_query_search.py — query discovery scoring
  • src/bcli_cli/output/_formatters.py — records formatter + auto-promote logic

igor-ctrl added 4 commits May 8, 2026 12:13
…ecords view

Phase 1 — `bcli doctor` (diagnostics):
  Self-rescue command for team installs. 11 independent checks (active
  profile, tenant, env, company, auth mode, profile-scoped token cache,
  registry, field coverage, saved queries, team bundle, BC connectivity).
  --json for monitoring scripts; non-zero exit on any FAIL. Connectivity
  uses httpx with trust_env=True so corporate proxies are honored.

Phase 2 — team bundle infra (`bcli config refresh`/`make-bundle`/etc.):
  Manifest schema, fetch over HTTPS (file:// gated behind BCLI_DEV=1),
  per-file content-hash + canonical roll-up verifier, atomic apply with
  per-profile flock + .previous backup retention, rollback. Hardening:
  allowlisted file set, no symlinks/devices, bounded compressed/decom-
  pressed sizes (gzip-bomb defense), traversal-rejecting verifier.
  field_lists.json is merged into the registry on apply so the prewarm
  isn't a dead artifact. NOTE: Sha256Verifier is internal-consistency
  only, not publisher authentication — phase 2 cannot ship to finance
  without a real cryptographic signer at the Verifier seam OR strict
  HTTPS+org-auth distribution. Gap is loud in plan + verifier docstring.

Phase 3 — saved-query metadata + `bcli q` discovery:
  Additive YAML keys (aliases, tags, owner, freshness, examples,
  related). New sub-verbs `bcli q list [tag=...] [owner=...]`,
  `bcli q search <phrase>`, `bcli q info <name>`, `bcli q run <name>`
  (escape hatch). Reserved sub-verb names hard-error at bundle load.
  Substring + alias + tag scoring, no embeddings — codex consult was
  right that boring metadata wins for a 50-100 query library.

Phase 6 — Windows PowerShell wide-table fix:
  New `records` formatter (vertical, psql-\\x style). Auto-promotion when
  result is 1-2 rows with >8 columns or wider than the terminal — only
  when format was auto-detected, never when user passed -f explicitly
  (auto_format flag threaded through CLIState).

Plan: docs/plans/team-deployment.md (drafted earlier; updated to fix
schema mismatch and call out the signing ship-blocker explicitly).

Tests: 593 passing (+45 new across 4 phases). Includes concurrency test
for the apply lock, gzip-bomb rejection, traversal rejection in fetch
and verify paths, file://-blocked-without-dev, profile-scoped token
cache regression, and explicit-format-disables-auto-records.

Codex review (high reasoning) found 2 P1 + 8 P2 issues; all fixed in
this commit except the publisher-signing P1 which is correctly deferred
to a phase-2-extension and now flagged as a finance-rollout ship-blocker
in the plan.
CI runs `ruff check src/ tests/`; my local pre-commit only checked `src/`.
Removed `pytest` and `_formatters` imports that became unused after
refactoring. No behavioral change.
The team-bundle infra ships in the OSS bcli; how Beautech rolls it out
to finance/engine-tech is internal business. Drop "ship-blocker for
finance rollout" framing in the plan + verifier docstring — the OSS
project doesn't owe Beautech's deployment a publisher-signing
implementation, that's tracked separately as a Beautech rollout gate
(#11). Sha256Verifier is correctly an integrity check; operators who
need authenticity plug Ed25519Verifier into the same Verifier seam
when they're ready.
Cross-repo terminology cleanup matching the Beautech bootstrap rename
(bcli-beautech-installer#14): role label changes from "engine-tech" to
"technical" everywhere it referred to the role/team. The OSS bcli tool
itself is unchanged behaviorally — these are pure string renames in
internal-Beautech planning notes, a test fixture, and a diagnostic hint.

- docs/plans/team-deployment.md: 12 occurrences. Plan doc is already
  flagged as Beautech-internal (not OSS roadmap) per earlier framing fix.
- tests/test_workflow/test_query_search.py: 2 occurrences in fixtures
  ("owner": "engine-tech" → "technical"). Tests still pass — the metadata
  is opaque strings.
- src/bcli/diagnostics/_checks.py: 1 hint string in check_auth_mode.

593 tests pass.
@igor-ctrl igor-ctrl merged commit 99fcce9 into main May 8, 2026
3 checks passed
igor-ctrl added a commit that referenced this pull request May 12, 2026
The Typer root-callback (introduced in #10) shared the name `main` with
the console-script entry point (added in #13), tripping ruff F811
(redefinition) when CI lint runs against the rebased history. The
callback's name is arbitrary — Typer wires it via the `@app.callback()`
decorator, not by symbol lookup — so renaming to `_root_callback`
resolves the redefinition without behavior change.
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.

1 participant