Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 68 additions & 6 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,21 @@ BUILD_DATE := $(shell date -u +%Y-%m-%dT%H:%M:%SZ)
BUILD_HASH := $(shell git rev-parse --short HEAD 2>/dev/null || echo unknown)
PKG := github.com/sdoque/mbaigo/components

SYSTEMS := beehive beekeeper busdriver clerk collector democrat \
SYSTEMS := beehive beekeeper busdriver ca clerk collector democrat \
drafter ds18b20 emulator esr ethermostat filmer flattener kgrapher \
leveler messenger meteorologue modeler modboss nurse orchestrator \
parallax photographer recognizer revolutionary sapper sailor \
telegrapher thermostat tracker uaclient weatherman
leveler maitreD messenger meteorologue modeler modboss nurse \
orchestrator parallax photographer recognizer revolutionary sapper \
sailor telegrapher thermostat tracker uaclient weatherman

.PHONY: all ci release rpi test lint clean $(SYSTEMS)
.PHONY: all ci release rpi test lint clean whitelist $(SYSTEMS)

# Default target: build everything
all: rpi

# Clean rebuild with version stamp: make release VERSION=1.2.3
release: clean rpi
# Produces both the cross-compiled binaries and the matching whitelist.json
# that authorises exactly those binaries for certificate issuance.
release: clean rpi whitelist

# Full pipeline: tests and lint must pass before building
ci: lint test rpi
Expand Down Expand Up @@ -77,6 +79,66 @@ endef

$(foreach sys,$(SYSTEMS),$(eval $(call build_system,$(sys))))

# --- Whitelist generation -----------------------------------------------------
#
# A release of mbaigo systems must be paired with a whitelist that authorises
# exactly the binaries in that release. The security/ca Certificate Authority
# reads `whitelist.json` (a flat JSON array of SHA-256 hex strings) at runtime
# and serves it to maitreDs on every host; the maitreDs deny attestation for
# any process whose hash is not on that list.
#
# This section walks the just-built binaries in $(STAGING) and writes both
# files into $(STAGING)/ca/, alongside the CA binary they belong to:
#
# $(STAGING)/ca/whitelist.json — flat array of hashes; the wire
# format the CA reads at runtime.
# $(STAGING)/ca/whitelist-manifest.txt — annotated `system → hash` map
# with VERSION and BUILD_DATE,
# for human review and audit.
#
# Co-locating with the CA binary lets a single `rsync $(STAGING)/ca/` deploy
# both the executable and the authorisation file as one atomic operation.
#
# Deployment: rsync the CA's directory to its host, e.g.
# rsync -av $(STAGING)/ca/ ca-host:/path/to/ca/
# Every maitreD picks up the new list on its next sync (≤5 min by default).
#
# `release` depends on `whitelist`, so a single `make release VERSION=1.2.3`
# produces binaries and the matching authorisation file in one shot.
#
# Note: uses `shasum -a 256`, which is present on macOS and on most Linux
# distros. If your build host has only `sha256sum`, swap it in below.

whitelist: $(STAGING)/ca/whitelist.json $(STAGING)/ca/whitelist-manifest.txt

# Flat JSON array — the wire format expected by the CA's loadWhitelist().
# Depends on every staged binary, so editing any system's source and
# re-running `make rpi` causes the whitelist to regenerate automatically.
$(STAGING)/ca/whitelist.json: $(foreach sys,$(SYSTEMS),$(STAGING)/$(sys)/$(sys)_rpi64)
@mkdir -p $(STAGING)/ca
@printf '[\n' > $@
@first=1; for sys in $(SYSTEMS); do \
bin=$(STAGING)/$$sys/$${sys}_rpi64; \
hash=$$(shasum -a 256 $$bin | cut -d' ' -f1); \
if [ $$first -eq 1 ]; then first=0; else printf ',\n' >> $@; fi; \
printf ' "%s"' "$$hash" >> $@; \
done
@printf '\n]\n' >> $@
@echo "Wrote $@"

# Human-readable manifest — never read by code, always read by people.
# Use this to answer "what binary is hash e3b0c44…?" during ops review.
$(STAGING)/ca/whitelist-manifest.txt: $(foreach sys,$(SYSTEMS),$(STAGING)/$(sys)/$(sys)_rpi64)
@mkdir -p $(STAGING)/ca
@printf 'Whitelist manifest — VERSION=%s built %s\n\n' \
"$(VERSION)" "$(BUILD_DATE)" > $@
@for sys in $(SYSTEMS); do \
bin=$(STAGING)/$$sys/$${sys}_rpi64; \
hash=$$(shasum -a 256 $$bin | cut -d' ' -f1); \
printf '%-20s %s\n' "$$sys" "$$hash" >> $@; \
done
@echo "Wrote $@"

# --- Housekeeping -------------------------------------------------------------

clean:
Expand Down
141 changes: 141 additions & 0 deletions authorizer/MISSIONS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
# Standard Mission Taxonomy

**Status:** Working specification. Pre-implementation. Subject to refinement once a
testbed deployment exercises it.

## Purpose

A *mission* is a coarse-grained classification of what a unit asset *is for*. It is
the primary axis along which the authorizer evaluates policies. Missions are
declared by each asset (in the system's `systemconfig.json`) and travel with the
asset's service-registration record, so the authorizer can read missions from the
service registrar rather than from every system's local file.

The mission taxonomy is intentionally small. Too many missions becomes
indistinguishable from per-asset enumeration; too few cannot express real
distinctions. The eight missions below are the working set. Additions require a
deliberate revision of this document.

## The taxonomy

### `measurement`

Assets that observe physical or digital state without changing it.

- **Examples:** temperature sensor, position encoder, voltage probe, packet counter.
- **Typical actions:** `read` for any consumer with a legitimate use; `write` only
rarely (calibration parameters, set-points for the sensor's own operation).
- **Pairing:** typically location-bound. A bathroom temperature sensor is paired
to bathroom-class consumers via `functional_location`.

### `actuation`

Assets that change physical or digital state.

- **Examples:** servo position setter, valve open/close, heater plug, pump speed
command.
- **Typical actions:** `write` only by authorised controllers; `read` permitted
for status display and audit.
- **Pairing:** location-bound. A kitchen heater plug is paired to kitchen-class
controllers.

### `state`

Internal mode, schedule, or configuration of a system or asset.

- **Examples:** thermostat target temperature, scheduler entries, operating mode
(auto/manual/off).
- **Typical actions:** `read` widely; `write` by commissioning or maintenance role.
- **Pairing:** typically per-system, not location-bound.

### `event`

Ephemeral notifications, alarms, transitions.

- **Examples:** door-opened event, threshold-crossed alarm, mode-change announcement.
- **Typical actions:** `read` (subscribe) widely; `write` (publish) only by the
asset that owns the event source.
- **Pairing:** event-stream-bound, occasionally location-bound.

### `aggregation`

Derived or computed values built from other assets' outputs.

- **Examples:** rolling-window mean, hourly average, count over a tag set.
- **Typical actions:** `read` widely; `write` only by the aggregator producing the value.
- **Pairing:** typically not location-bound (aggregations span locations by design).

### `logging`

Write-only sinks for audit trails or data.

- **Examples:** audit log, time-series database ingestion endpoint, alarm history.
- **Typical actions:** `write` widely; `read` only by audit and analytics roles.
- **Pairing:** typically not location-bound (logs are cloud-wide by design).

### `control`

Bidirectional control loops that both observe and act on physical state.

- **Examples:** PID controller, feedback loop, servo position-and-feedback combined.
- **Typical actions:** `read` and `write` together; the consumer expects both as a
paired use.
- **Pairing:** location-bound, like `actuation`.

### `core`

Framework infrastructure: service registrar, orchestrator, certificate authority,
authorizer itself, maitreD.

- **Examples:** the four core systems of an Arrowhead local cloud.
- **Typical actions:** restricted; framework-only roles.
- **Pairing:** never location-bound — core systems serve the whole cloud.

## When the taxonomy doesn't fit cleanly

Most assets land in exactly one mission. Two situations require care:

### A service that is genuinely both measurement and actuation

The parallax `position` service is the canonical example: GET reads the current
position; PUT sets a new one. Two design choices, in increasing complexity:

1. **Split into two services** within the same asset: `position-read` (mission
`measurement`) and `position-write` (mission `actuation`). Cleanest but
requires the implementation to expose two endpoints.
2. **Mark the asset as `actuation`** and let read access be granted to broader
subjects via policy (the collector's policy in the example below). Pragmatic
for the common case where read is permissive but write is tight.

For mbaigo today, option 2 is operationally simpler. Option 1 is the right move
if the read and write semantics ever need to be authorised differently for
different consumers.

### Multi-mission assets

If an asset honestly serves two missions (e.g. a controller that is both
`actuation` and `state`), declare both in the systemconfig:

```json
"unit_assets": [
{
"name": "servo1",
"missions": ["actuation", "state"],
...
}
]
```

Policy matching uses *any* match (the asset's mission set ∩ the policy's mission
set must be non-empty).

## Versioning

This taxonomy is part of the authorization contract. Changes — adding a mission,
splitting one, deprecating one — must be propagated to every system's
configuration. We treat changes here as a versioned event, with a corresponding
note in the paper (or the journal-paper revision history once that is published).

| Date | Change |
|------|--------|
| 2026-04-30 | Initial taxonomy: measurement, actuation, state, event, aggregation, logging, control, core |
Loading
Loading