block / block/proto-fleet

Platform: standardize building targeting and add building-scoped RBAC

Open
#428 0 comments 0 reactions 1 assignee Claimed by @rl-block View on GitHub
Dominant language
Go
Stars
55
Forks
16
Avg merge
1d 22h
Merged PRs (30d)
87

Description

## Status

Open, but no longer a tracker for introducing building targeting from scratch.

Proto Fleet now targets buildings in several workflows. The remaining platform work is to standardize those patterns, close ownership-validation gaps, and add true building-scoped RBAC. This is still not a blocker for MQTT curtailment automation, which can use whole-org, site, device-set, or device-list response-profile scopes.

## Current state

### Building targeting and topology already exist

The codebase now has strong reusable building-aware primitives:

- `MinerListFilter` supports `building_ids`, `include_no_building`, building-scoped `zone_keys`, and `include_no_rack`.
- Rack/device-set filters support building IDs and building-scoped zone keys.
- `common.v1.ZoneKey` identifies a zone by building because zone labels are not globally unique.
- `ValidateFilterBuildings`, `BuildingBelongsToOrg`, and `BuildingsByIDs` provide reusable ownership and deleted-row checks.
- Miner membership can come from direct `device.building_id` assignment or rack membership through `device_set_rack.building_id`.
- Building CRUD, rack/device placement, stats, site reassignment, and site-map import/export enforce topology invariants at the building boundary.
- Schedules persist `SCHEDULE_TARGET_TYPE_BUILDING` and expand the building to its current paired devices at execution time.
- Bulk miner commands can target a building dynamically through `DeviceSelector.all_matching_filter` and `MinerListFilter.building_ids`.

Schedules therefore already satisfy the original outcome of targeting a building without enumerating miners. Miner commands provide the same capability for request-time filtered bulk actions, though not as a durable resource target.

### Building-scoped RBAC is still missing

Authorization remains org/site only:

- `authz.v1.ScopeType` has org and site values only.
- `authz.ResourceContext` carries only `SiteID`.
- `EffectivePermissions.Has`, `HasOrgWide`, and `SiteScopeFor` do not model building containment.
- `user_organization_role.scope_type` is constrained to `org` or `site`.
- Permission-denied payloads and list-scope projection expose site context only.

Site-scoped permission enforcement is now live across curtailment, infrastructure, miner commands, device-set reads, and selected building flows. Building role assignments and building-aware permission projection do not exist. The role-assignment API also remains incomplete, so product-managed narrowed assignments need to be considered alongside the new scope.

### Workflow gaps

- Curtailment scopes remain whole-org, site, device-set, device-list, or mixed. There is no `ScopeBuilding` and no building-scoped closed-loop admission.
- Activity supports site filters and unassigned-site filtering, but activity rows and filters have no first-class building dimension.
- Combined telemetry supports site filters, but telemetry requests have no first-class building dimension.
- Facility-fan curtailment uses explicit infrastructure device IDs plus persisted site authorization snapshots. It does not add building miner scope.
- Schedule create/update accepts syntactically valid building IDs but does not run the shared building ownership validator. A cross-org or deleted building ID can be persisted and later expand to zero devices instead of being rejected at the mutation boundary.

## Goal

Standardize building as a durable resource target where workflows need one, and add building-scoped authorization without retrofitting every API prematurely.

This work has three tracks.

## 1. Standard building target primitives

- Define when APIs should use a durable `ScopeBuilding { building_id }` shape versus the existing `MinerListFilter.building_ids` filter shape.
- Reuse `ValidateFilterBuildings` / `BuildingsByIDs` at mutation boundaries before persisting targets or applying side effects.
- Define target membership as the union of direct device building assignment and rack-derived building assignment, matching current miner filters and schedule overlap logic.
- Preserve org and deleted-row guards for all point and bulk building lookups.
- Harden schedule building targets first because schedules are the shipped durable reference implementation.

A shared proto scope should be introduced only for APIs that need a durable building resource reference. List and command filters should continue to reuse `MinerListFilter` rather than gaining parallel scope messages.

## 2. Building-scoped RBAC

- Add a building value to the authz scope enum and persistence constraint.
- Add building context to `authz.ResourceContext` and permission-denied details.
- Extend effective-permission containment so a request can be allowed by, in order:
- a matching building assignment;
- a site assignment covering the building's current parent site; or
- an unnarrowed org assignment.
- Add building-aware list projection so handlers can push readable building sets into stores instead of fetching unauthorized rows.
- Define the assignment foreign-key shape and building-move behavior.

The design must explicitly decide whether a building assignment follows the stable building ID when the building moves between sites, and how the former and new parent-site assignments affect access. Current site reassignment preserves `building.id` while cascading the new `site_id` to racks and devices.

## 3. RBAC-aware adopter

Schedules already prove operational building targeting. Select one workflow to prove building authorization end to end:

- building list/detail/stats is the narrowest platform-native adopter;
- curtailment is a strong later adopter because it already has persisted composable scopes and site-scoped authorization, but it carries higher safety and reconciler complexity; or
- schedules can adopt building permission checks after write-time ownership validation is fixed.

Do not require activity and telemetry building dimensions until their product UX needs are defined.

## Acceptance criteria

### Targeting and validation

- A canonical rule documents when to use `ScopeBuilding` versus `MinerListFilter.building_ids`.
- Schedule create/update rejects cross-org, deleted, zero, or nonexistent building IDs before persisting the target.
- Building expansion includes both directly assigned devices and devices assigned through racks, with org and pairing-status guards.
- Existing schedule and filtered-command building targeting remains compatible.

### Authorization

- Authz proto, database constraints, domain models, resolver, middleware, and error details support building scope.
- Permission tests cover matching building grants, another-building denial, parent-site fallback, org fallback, and narrowing by a site or building assignment that lacks the required permission.
- Building-aware list handlers exclude unreadable buildings at the query boundary.
- Building move semantics are documented and tested, including access through the old site, new site, and direct building assignment.
- Cross-org or deleted building assignments cannot be created.

### Adopter

- At least one workflow enforces a building-scoped permission from request through ownership validation, store query, and side effect.
- End-to-end tests cover authorization, cross-org isolation, deleted buildings, and building movement.
- Curtailment, activity, and telemetry remain unchanged unless selected as explicit adopters.

## Out of scope

- Replacing existing building-aware list filters with a universal scope abstraction.
- Retrofitting every activity, telemetry, history, or command API with building scope.
- Blocking MQTT sources, response profiles, or curtailment automation on building RBAC.
- Treating activity `scope_type` as an authz scope; it describes event target types, not permission containment.

## References

- Site-scoped curtailment foundation: #418.
- Site/building schedule targets: #552 and `docs/plans/2026-06-23-schedule-site-building-targets-tdd.md`.
- Building-aware miner/rack filters: `docs/plans/2026-05-14-229-miner-zone-building-filter-plan.md`.
- Filtered bulk miner commands: #733.
- Facility-fan curtailment stack through #770 is site-authorized and orthogonal to building miner scope.
- Authz anchors: `proto/authz/v1/authz.proto`, `server/internal/domain/authz/effective.go`, and migration `000052_create_permission_tables`.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.