Files
ops-bridge/workplans/BRIDGE-WP-0002-opscatalog-extension.md
tegwick af2d419bf6 chore: mark BRIDGE-WP-0001 and BRIDGE-WP-0002 workplans as completed
All 39 tasks marked done; both workstreams updated to completed status
in the State Hub and workplan files.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-12 03:37:32 +01:00

405 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
id: BRIDGE-WP-0002
type: workplan
title: "OpsCatalog Extension"
domain: custodian
repo: ops-bridge
status: completed
owner: Bernd
topic_slug: custodian
state_hub_workstream_id: f38bfcdb-f115-4431-88b5-ce906a24199c
created: "2026-03-11"
updated: "2026-03-12"
---
# 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-2729, 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: done
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: done
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: done
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: done
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: done
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: done
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: done
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: done
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: done
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: done
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: done
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: done
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: done
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: done
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: done
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: done
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-2729 (identity integration) remain deferred — require external identity
provider infrastructure.*
---
## Deferred
- **FR-2729** — 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.