generated from coulomb/repo-seed
docs: add BRIDGE-WP-0002 OpsCatalog extension workplan
7-phase plan covering catalog data models, loader, validator, bridge resolver (inline-first with catalog fallback), bridge targets and bridge catalog CLI commands, and integration tests. 16 tasks registered in Custodian State Hub (workstream bridge-wp-0002). Covers OpsCatalog FRS FR-1–15 and OpsBridge FRS FR-21–23. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
404
workplans/BRIDGE-WP-0002-opscatalog-extension.md
Normal file
404
workplans/BRIDGE-WP-0002-opscatalog-extension.md
Normal file
@@ -0,0 +1,404 @@
|
||||
---
|
||||
id: BRIDGE-WP-0002
|
||||
type: workplan
|
||||
title: "OpsCatalog Extension"
|
||||
domain: custodian
|
||||
repo: ops-bridge
|
||||
status: active
|
||||
owner: Bernd
|
||||
topic_slug: custodian
|
||||
state_hub_workstream_id: f38bfcdb-f115-4431-88b5-ce906a24199c
|
||||
created: "2026-03-11"
|
||||
updated: "2026-03-11"
|
||||
---
|
||||
|
||||
# BRIDGE-WP-0002 — OpsCatalog Extension
|
||||
|
||||
**Scope:** Implement OpsCatalog as a Git-backed YAML knowledge repository and
|
||||
integrate it with the `bridge` CLI.
|
||||
**Depends on:** BRIDGE-WP-0001 complete (bridge CLI operational).
|
||||
**Out of scope:** Identity provider integration (FR-27–29, deferred indefinitely).
|
||||
|
||||
---
|
||||
|
||||
## Goal
|
||||
|
||||
Deliver the OpsCatalog subsystem: a structured YAML catalog of operations
|
||||
domains, targets, bridges, and actor classes stored in a Git repository.
|
||||
OpsBridge loads the catalog at runtime to resolve bridge identifiers, orient
|
||||
operators, and expose the `bridge targets` and `bridge catalog` commands.
|
||||
|
||||
---
|
||||
|
||||
## Reference Documents
|
||||
|
||||
| Document | Location |
|
||||
|---|---|
|
||||
| OpsCatalog Spec (PRD + FRS + Schemas) | `wiki/OpsCatalogSpecification.md` |
|
||||
| OpsBridge FRS (deferred FRs) | `wiki/OpsBridgeFrs.md` §5.8, §5.10 |
|
||||
| CLAUDE.md | `CLAUDE.md` |
|
||||
|
||||
---
|
||||
|
||||
## Architecture Summary
|
||||
|
||||
```
|
||||
~/.config/bridge/tunnels.yaml
|
||||
catalog_path: ~/ops-catalog # path to the OpsCatalog Git repo
|
||||
|
||||
ops-catalog/ # separate Git repo, consumed by bridge
|
||||
domains/
|
||||
<domain>/
|
||||
domain.yaml # type: domain
|
||||
targets/
|
||||
<target>.yaml # type: target
|
||||
bridges/
|
||||
<bridge>.yaml # type: bridge
|
||||
docs/
|
||||
*.md # operations notes
|
||||
actors/
|
||||
<actor>.yaml # type: actor
|
||||
schemas/
|
||||
domain.schema.yaml
|
||||
target.schema.yaml
|
||||
bridge.schema.yaml
|
||||
actor.schema.yaml
|
||||
|
||||
src/bridge/
|
||||
catalog/
|
||||
__init__.py
|
||||
loader.py # walk catalog_path, parse YAML files into typed objects
|
||||
models.py # CatalogDomain, CatalogTarget, CatalogBridge, ActorClass
|
||||
validator.py # validate catalog entries against schemas
|
||||
resolver.py # resolve tunnel name → CatalogBridge → TunnelConfig
|
||||
```
|
||||
|
||||
**Integration points with existing bridge code:**
|
||||
- `config.py`: read `catalog_path` from `tunnels.yaml`; pass to catalog loader
|
||||
- `manager.py`: use `resolver.py` to look up bridge config from catalog when
|
||||
tunnel is not defined inline in `tunnels.yaml`
|
||||
- `cli.py`: add `bridge targets` and `bridge catalog` commands
|
||||
|
||||
---
|
||||
|
||||
## YAML Schemas
|
||||
|
||||
### domain.yaml
|
||||
```yaml
|
||||
type: domain
|
||||
id: coulombcore
|
||||
name: CoulombCore Infrastructure
|
||||
description: Core infrastructure domain for operational services
|
||||
environment: production
|
||||
```
|
||||
|
||||
### target.yaml
|
||||
```yaml
|
||||
type: target
|
||||
id: state-hub
|
||||
domain: coulombcore
|
||||
kind: service
|
||||
description: Infrastructure state coordination service
|
||||
reachable_via:
|
||||
- state-hub-coulombcore
|
||||
```
|
||||
|
||||
### bridge.yaml
|
||||
```yaml
|
||||
type: bridge
|
||||
id: state-hub-coulombcore
|
||||
domain: coulombcore
|
||||
target: state-hub
|
||||
description: Operations bridge for state hub diagnostics
|
||||
access_method: ssh-reverse
|
||||
host: coulombcore.local
|
||||
remote_port: 18000
|
||||
local_port: 8000
|
||||
ssh_user: ubuntu
|
||||
ssh_key: ~/.ssh/id_ops
|
||||
actor: agent.claude-coulombcore
|
||||
health_check:
|
||||
url: http://127.0.0.1:18000/health
|
||||
interval_seconds: 30
|
||||
timeout_seconds: 5
|
||||
reconnect:
|
||||
max_attempts: 0
|
||||
backoff_initial: 5
|
||||
backoff_max: 60
|
||||
```
|
||||
|
||||
### actor.yaml
|
||||
```yaml
|
||||
type: actor
|
||||
id: agent.claude-remediator
|
||||
class: automation
|
||||
description: Automated remediation agent
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Phase 1 — Catalog Data Models
|
||||
|
||||
**Acceptance:** All catalog YAML types parse into typed Python objects.
|
||||
|
||||
### T01 — Define catalog dataclasses in catalog/models.py
|
||||
|
||||
```task
|
||||
id: BRIDGE-WP-0002-T01
|
||||
state_hub_task_id: 21b90574-a27c-467c-8e9d-d4029a659171
|
||||
status: todo
|
||||
priority: high
|
||||
```
|
||||
|
||||
Define `CatalogDomain`, `CatalogTarget`, `CatalogBridge`, `ActorClass` dataclasses.
|
||||
`CatalogBridge` must be mergeable with `TunnelConfig` (catalog supplies defaults;
|
||||
inline `tunnels.yaml` entries can override).
|
||||
|
||||
---
|
||||
|
||||
## Phase 2 — Catalog Loader (FR-14)
|
||||
|
||||
**Acceptance:** `catalog.load(path)` returns a populated `Catalog` object from a
|
||||
directory tree; unknown `type:` values are skipped with a warning.
|
||||
|
||||
### T02 — Implement catalog/loader.py
|
||||
|
||||
```task
|
||||
id: BRIDGE-WP-0002-T02
|
||||
state_hub_task_id: 782b5b4d-1f3f-4e5d-ad46-dc57b345bda3
|
||||
status: todo
|
||||
priority: high
|
||||
```
|
||||
|
||||
Walk `catalog_path` recursively, parse every `*.yaml` file, dispatch on `type:`
|
||||
field. Build in-memory index: domains, targets, bridges, actors.
|
||||
|
||||
### T03 — Unit tests for catalog loader
|
||||
|
||||
```task
|
||||
id: BRIDGE-WP-0002-T03
|
||||
state_hub_task_id: 41fed4f8-7818-4ca1-bb48-6ac1089220e8
|
||||
status: todo
|
||||
priority: medium
|
||||
```
|
||||
|
||||
Test: full catalog directory fixture loads correctly; missing required field raises
|
||||
clear error; unknown type is skipped; empty catalog returns empty index.
|
||||
|
||||
---
|
||||
|
||||
## Phase 3 — Catalog Validation (FR-15)
|
||||
|
||||
**Acceptance:** `bridge catalog validate` exits non-zero and prints all violations
|
||||
when the catalog contains invalid entries.
|
||||
|
||||
### T04 — Implement catalog/validator.py
|
||||
|
||||
```task
|
||||
id: BRIDGE-WP-0002-T04
|
||||
state_hub_task_id: 32946d15-5516-4599-8f27-8c653dec6786
|
||||
status: todo
|
||||
priority: medium
|
||||
```
|
||||
|
||||
Validate required fields per type. Cross-reference checks: target's `domain` must
|
||||
exist; target's `reachable_via` bridge IDs must exist; bridge's `target` and
|
||||
`domain` must exist; actor referenced by bridge must exist.
|
||||
|
||||
### T05 — Unit tests for catalog validation
|
||||
|
||||
```task
|
||||
id: BRIDGE-WP-0002-T05
|
||||
state_hub_task_id: 6061a6eb-9966-4be9-aa5e-ea7edf7fd085
|
||||
status: todo
|
||||
priority: medium
|
||||
```
|
||||
|
||||
Test: valid catalog passes; dangling `reachable_via` reference fails; missing
|
||||
required field fails.
|
||||
|
||||
---
|
||||
|
||||
## Phase 4 — Bridge Resolver (FR-2 integration)
|
||||
|
||||
**Acceptance:** `bridge up state-hub-coulombcore` resolves the bridge config from
|
||||
the catalog when no inline entry exists in `tunnels.yaml`.
|
||||
|
||||
### T06 — Implement catalog/resolver.py
|
||||
|
||||
```task
|
||||
id: BRIDGE-WP-0002-T06
|
||||
state_hub_task_id: a92d97c8-4eec-4dd5-9b90-d9c1cba813ac
|
||||
status: todo
|
||||
priority: high
|
||||
```
|
||||
|
||||
`resolve(name, catalog, inline_config) → TunnelConfig`. Lookup order: inline
|
||||
`tunnels.yaml` entry wins; fall back to catalog bridge by ID. Merge catalog
|
||||
bridge fields into `TunnelConfig`. Raise `BridgeNotFound` if neither source
|
||||
has the name.
|
||||
|
||||
### T07 — Integrate resolver into config.py and manager.py
|
||||
|
||||
```task
|
||||
id: BRIDGE-WP-0002-T07
|
||||
state_hub_task_id: 23799377-64f2-4c13-aa72-364770d80f91
|
||||
status: todo
|
||||
priority: high
|
||||
```
|
||||
|
||||
Read `catalog_path` from `tunnels.yaml` (optional; catalog disabled if absent).
|
||||
Pass resolved `TunnelConfig` to `TunnelManager` unchanged — manager stays
|
||||
catalog-unaware.
|
||||
|
||||
### T08 — Unit tests for resolver
|
||||
|
||||
```task
|
||||
id: BRIDGE-WP-0002-T08
|
||||
state_hub_task_id: d2313182-975f-409f-9d4f-ebabf66b44df
|
||||
status: todo
|
||||
priority: medium
|
||||
```
|
||||
|
||||
Test: inline entry takes precedence; catalog fallback works; inline overrides
|
||||
catalog fields; missing name raises `BridgeNotFound`.
|
||||
|
||||
---
|
||||
|
||||
## Phase 5 — CLI: bridge targets (FR-21, FR-22, FR-23)
|
||||
|
||||
**Acceptance:** `bridge targets` prints a table of domains, targets, and which
|
||||
bridges provide access to each target.
|
||||
|
||||
### T09 — CLI: bridge targets command
|
||||
|
||||
```task
|
||||
id: BRIDGE-WP-0002-T09
|
||||
state_hub_task_id: f9e508db-a19f-42be-9437-b4bdeb00a534
|
||||
status: todo
|
||||
priority: medium
|
||||
```
|
||||
|
||||
Table columns: `DOMAIN`, `TARGET`, `KIND`, `BRIDGES`. `--domain <name>` filter.
|
||||
`--json` flag for automation. Requires catalog to be configured; clear error if
|
||||
`catalog_path` not set.
|
||||
|
||||
### T10 — CLI: bridge targets show <target>
|
||||
|
||||
```task
|
||||
id: BRIDGE-WP-0002-T10
|
||||
state_hub_task_id: e288a1d3-d676-404a-a3eb-25dbb241502d
|
||||
status: todo
|
||||
priority: low
|
||||
```
|
||||
|
||||
Show full metadata for a single target: domain, kind, description, reachable_via
|
||||
bridges, and any operations notes from `docs/*.md` files in the domain directory.
|
||||
|
||||
---
|
||||
|
||||
## Phase 6 — CLI: bridge catalog commands
|
||||
|
||||
**Acceptance:** Operators can inspect and validate the catalog from the CLI.
|
||||
|
||||
### T11 — CLI: bridge catalog list
|
||||
|
||||
```task
|
||||
id: BRIDGE-WP-0002-T11
|
||||
state_hub_task_id: 73899b70-b0ac-4f48-b362-cc2455a66f41
|
||||
status: todo
|
||||
priority: medium
|
||||
```
|
||||
|
||||
List all domains and a count of targets and bridges per domain.
|
||||
|
||||
### T12 — CLI: bridge catalog validate
|
||||
|
||||
```task
|
||||
id: BRIDGE-WP-0002-T12
|
||||
state_hub_task_id: e091daa2-7c20-4169-b634-1fcc469513ea
|
||||
status: todo
|
||||
priority: medium
|
||||
```
|
||||
|
||||
Run `validator.py` and print all violations. Exit 0 if clean, 1 if violations
|
||||
found. Useful in CI pipelines for the catalog repo.
|
||||
|
||||
### T13 — CLI: bridge catalog show <bridge-id>
|
||||
|
||||
```task
|
||||
id: BRIDGE-WP-0002-T13
|
||||
state_hub_task_id: 9f5f4f30-bfe6-40fd-b178-2fbb396816ee
|
||||
status: todo
|
||||
priority: low
|
||||
```
|
||||
|
||||
Print full resolved bridge metadata including target and domain context.
|
||||
|
||||
---
|
||||
|
||||
## Phase 7 — Integration Tests
|
||||
|
||||
**Acceptance:** `uv run pytest` passes cleanly with catalog fixtures.
|
||||
|
||||
### T14 — Integration test: catalog load and resolve
|
||||
|
||||
```task
|
||||
id: BRIDGE-WP-0002-T14
|
||||
state_hub_task_id: 5ccb2b4b-7ea5-4c38-8246-d59b8f7d4419
|
||||
status: todo
|
||||
priority: medium
|
||||
```
|
||||
|
||||
Fixture: minimal catalog directory with one domain, one target, one bridge.
|
||||
Test `bridge up <catalog-bridge-name>` resolves and starts tunnel.
|
||||
|
||||
### T15 — Integration test: bridge targets output
|
||||
|
||||
```task
|
||||
id: BRIDGE-WP-0002-T15
|
||||
state_hub_task_id: 72c9f686-c474-46c4-a759-bfd47e2d4211
|
||||
status: todo
|
||||
priority: medium
|
||||
```
|
||||
|
||||
Test `bridge targets` output matches catalog fixture. Test `--json` flag.
|
||||
|
||||
### T16 — Integration test: bridge catalog validate
|
||||
|
||||
```task
|
||||
id: BRIDGE-WP-0002-T16
|
||||
state_hub_task_id: 83c0734e-0dc2-49ce-8b6a-a4d5e26ff33a
|
||||
status: todo
|
||||
priority: medium
|
||||
```
|
||||
|
||||
Test clean catalog exits 0; catalog with a dangling reference exits 1 with a
|
||||
clear message.
|
||||
|
||||
---
|
||||
|
||||
## FRS Traceability
|
||||
|
||||
| FRS Requirement Group | Phase |
|
||||
|---|---|
|
||||
| FR-14 — Catalog retrieval | 2 |
|
||||
| FR-15 — Catalog validation | 3 |
|
||||
| FR-1 to FR-3 — Domain management | 2, 5 |
|
||||
| FR-4 to FR-6 — Target management | 2, 5 |
|
||||
| FR-7 to FR-9 — Bridge definition | 2, 4 |
|
||||
| FR-10 to FR-11 — Actor classification | 2 |
|
||||
| FR-12 to FR-13 — Operational annotations | 5 (docs/*.md) |
|
||||
| FR-21 to FR-23 — Infrastructure target discovery (OpsBridge FRS) | 5 |
|
||||
|
||||
*FR-27–29 (identity integration) remain deferred — require external identity
|
||||
provider infrastructure.*
|
||||
|
||||
---
|
||||
|
||||
## Deferred
|
||||
|
||||
- **FR-27–29** — Identity provider integration (privacyIDEA / SSH CA) — separate
|
||||
workplan when identity infrastructure is available.
|
||||
- **Operations notes search** — full-text search across `docs/*.md` files — nice
|
||||
to have, not required for MVP.
|
||||
Reference in New Issue
Block a user