@mhome/core-protocol 1.16.0 → 1.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +35 -0
- package/contract/host-permissions.md +40 -55
- package/manifest/core.v1.json +2 -2
- package/package.json +1 -1
- package/protocol.json +1 -1
- package/schema/host-permissions.schema.json +8 -147
package/README.md
CHANGED
|
@@ -27,6 +27,41 @@ Storage separates backing-filesystem capacity from Storage-owned logical
|
|
|
27
27
|
usage. Namespace is an internal protocol term; user-facing clients present it
|
|
28
28
|
as a Folder.
|
|
29
29
|
|
|
30
|
+
## Lossless external boundaries (core-api 1.19.0)
|
|
31
|
+
|
|
32
|
+
External protocol **17** returns `HttpPayloadResponse { statusCode, body }` from
|
|
33
|
+
all HTTP handler RPCs. A completed HTTP response (including 4xx/5xx) is an RPC
|
|
34
|
+
success; RPC errors describe failures to execute the call, not HTTP status.
|
|
35
|
+
Hosts preserve status and JSON body, never infer them from error messages.
|
|
36
|
+
`ExternalCoreError` preserves domain `code`, `message` and optional `details`,
|
|
37
|
+
with conversions to/from the shared client `ErrorResponse`.
|
|
38
|
+
|
|
39
|
+
The transport-neutral `webhook` module defines the common route, body limit and
|
|
40
|
+
JSON-versus-UTF-8-text decoding. Hosts own network listeners and method admission;
|
|
41
|
+
Core owns dispatch and execution. Upgrade service shell and Core together.
|
|
42
|
+
|
|
43
|
+
## Host LAN observations (introduced in core-api 1.18.0)
|
|
44
|
+
|
|
45
|
+
The Host owns `host::network::HostNetworkSnapshot`, exposed through local IPC
|
|
46
|
+
`GET /internal/network`. It samples eligible private IPv4 interfaces at startup
|
|
47
|
+
and every 15 seconds, preferring `192.168/16`, then `10/8`, then `172.16/12`.
|
|
48
|
+
Within the best priority it retains a still-valid address, otherwise picks the
|
|
49
|
+
numerically smallest address. This is a deterministic common LAN policy, not
|
|
50
|
+
Ethernet/Wi-Fi classification or proof of reachability to every destination.
|
|
51
|
+
|
|
52
|
+
The response is `{ "lanIpv4": "192.168.1.2", "observedAtMs": 123456789 }`;
|
|
53
|
+
`lanIpv4: null` means unavailable. Consumers reject observations older than
|
|
54
|
+
45 seconds, future observations, and non-private IPv4. No loopback fallback.
|
|
55
|
+
The query does not enumerate interfaces. Existing multicast discovery still
|
|
56
|
+
uses its own complete interface inventory, not this single preferred address.
|
|
57
|
+
|
|
58
|
+
External protocol 16 changes `UpdateCallbackBaseRequest` to `{ network, port }`.
|
|
59
|
+
The service supplies the actual bound HTTP port and the unchanged Host
|
|
60
|
+
observation. Core derives the origin instead of trusting an independent URL.
|
|
61
|
+
Before the service reports, the sidecar has no callback origin. Freshness-only
|
|
62
|
+
updates do not trigger subscription reconciliation. Shell and runtime must be
|
|
63
|
+
upgraded together; local IPC is distinct from advertised callback URLs.
|
|
64
|
+
|
|
30
65
|
## Playground Provider (core-api 1.10.0)
|
|
31
66
|
|
|
32
67
|
External protocol 15 removes the dedicated Playground webhook method and payload.
|
|
@@ -9,48 +9,37 @@ This is a direct development cutover. There is one report model and no legacy
|
|
|
9
9
|
serialization, implicit component selection or alternative compatibility route.
|
|
10
10
|
Update Foundation consumers together after publishing the matching packages.
|
|
11
11
|
|
|
12
|
-
## Declaration
|
|
13
|
-
|
|
14
|
-
Each service keeps its source-root `permission.yml
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
There is no generic public macOS query in this contract that discovers another
|
|
31
|
-
process's TCC grant owner. Verify responsible-application attribution using the
|
|
32
|
-
real signed launch chain before enabling a shared subject for a permission.
|
|
33
|
-
If attribution is unconfirmed, `subject` is null and that component stays separate.
|
|
34
|
-
Different Automation `targetBundleId` values always remain distinct grants.
|
|
35
|
-
|
|
36
|
-
A grouped row preserves every `PermissionUse`, its observation and any collection
|
|
37
|
-
error. There is deliberately no group-level grant/state that can erase a denial,
|
|
38
|
-
an unknown executor or conflicting observations. A stopped service has no current
|
|
39
|
-
observation. Do not copy another service's grant into that empty observation.
|
|
40
|
-
Host chooses `requestComponentId` from available executors; it is null when none
|
|
41
|
-
can handle the request. `supportedActions` describes available mechanisms only.
|
|
12
|
+
## Declaration and executor
|
|
13
|
+
|
|
14
|
+
Each service keeps its source-root `permission.yml` and packages it. The installed
|
|
15
|
+
package is the sole source of desired permissions. Host loads declarations into
|
|
16
|
+
its installed-service inventory on startup and when packages change. Status reads
|
|
17
|
+
use that memory snapshot; they do not scan packages or maintain a database copy.
|
|
18
|
+
Stopped services retain their requirements. Invalid declarations remain visible.
|
|
19
|
+
|
|
20
|
+
Each `HostPermission` is one component and one permission: `componentId`,
|
|
21
|
+
`componentName`, `permission`, `feature`, `reason`, `observation`, `error`, and
|
|
22
|
+
`supportedActions`. There are no grouped subjects or selected substitute executors.
|
|
23
|
+
`PermissionObservation.processId` identifies the actual executing process, not an
|
|
24
|
+
OS grant identity. A sidecar reports its own observation through its service.
|
|
25
|
+
Reading status must not start an absent sidecar or substitute its parent's grant.
|
|
26
|
+
|
|
27
|
+
A helper can share its responsible application's consent without any grouping
|
|
28
|
+
fields in this protocol. Equal PIDs, signing teams or states alone do not establish
|
|
29
|
+
shared grants. Automation keys remain distinct per target application.
|
|
42
30
|
|
|
43
31
|
## Transport and actions
|
|
44
32
|
|
|
45
33
|
- `GET /v1/permissions` returns `HostPermissions` for installed requirements,
|
|
46
34
|
including stopped services and declaration/collection failures.
|
|
47
35
|
- `POST /internal/permissions/request` performs one explicit request or probe in
|
|
48
|
-
the selected service's actual execution context
|
|
36
|
+
the selected service's actual execution context. It returns `{ "ok": true }`
|
|
37
|
+
once submitted, without collecting another snapshot or waiting for user consent.
|
|
49
38
|
- `POST /internal/permissions/open-settings` opens the platform settings pane.
|
|
50
|
-
|
|
39
|
+
It returns `{ "ok": true }` after opening. Status is queried separately.
|
|
51
40
|
- Both POSTs take `HostPermissionRequest`. `hostId`, `componentId` and `permission`
|
|
52
|
-
are mandatory. The component must declare that exact key.
|
|
53
|
-
|
|
41
|
+
are mandatory. The component must declare that exact key. The caller cannot assert locality
|
|
42
|
+
or an arbitrary Settings URL.
|
|
54
43
|
- Require valid local control credentials and matching Host identity. Native
|
|
55
44
|
Desktop and CLI use Client IPC. Remote Hosts accept status only. Do not send
|
|
56
45
|
local control credentials to discovered addresses or redirects. A future Hub
|
|
@@ -59,18 +48,19 @@ can handle the request. `supportedActions` describes available mechanisms only.
|
|
|
59
48
|
PID identifies the reporting service; individual observations can identify its
|
|
60
49
|
sidecar. The service rejects requests outside its declared requirements.
|
|
61
50
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
latency
|
|
51
|
+
Foundation owns native request deduplication in the actual executor. Transport
|
|
52
|
+
timeouts do not release that ownership. UI polls status every two seconds while
|
|
53
|
+
managing permissions and refreshes on focus; a pending read is shared. CLI batch
|
|
54
|
+
requests query once after submission. Bound collection concurrency and the whole
|
|
55
|
+
snapshot latency so a stalled executor cannot hold every other service indefinitely.
|
|
67
56
|
|
|
68
|
-
##
|
|
57
|
+
## Authorization observations
|
|
69
58
|
|
|
70
|
-
`PermissionObservation.state` describes application consent.
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
59
|
+
`PermissionObservation.state` describes application consent only. The report
|
|
60
|
+
contains declared requirements and authorization observations; it does not collect
|
|
61
|
+
or carry resource availability or business-operation results. `granted` and
|
|
62
|
+
`notRequired` satisfy a requirement when the observation has valid evidence and
|
|
63
|
+
no errors. Missing, denied or unreadable observations remain unresolved.
|
|
74
64
|
|
|
75
65
|
- `system`: passive native authorization query and its timestamp.
|
|
76
66
|
- `platform`: platform consent semantics, not measured resource availability.
|
|
@@ -78,17 +68,13 @@ scan does not prove that every connection or operation will succeed.
|
|
|
78
68
|
- `unavailable`: a reliable consent observation could not be obtained.
|
|
79
69
|
- `notRequired`: this native backend has no application-consent step. It does not
|
|
80
70
|
bypass users/groups, D-Bus policies, device rules, sessions, portals or sandboxes.
|
|
81
|
-
- `access`: the actual backend's checked condition, timestamp and result. Missing
|
|
82
|
-
access evidence is unknown, not proof of success. Its detail describes only the
|
|
83
|
-
operation/condition actually observed. Do not relabel a hardware failure as OS
|
|
84
|
-
user denial or a successful consent query as a successful resource probe.
|
|
85
71
|
|
|
86
72
|
Passive report reads never request authorization, probe Local Network, scan
|
|
87
73
|
Bluetooth, launch an Automation target, restart a service or open Settings.
|
|
88
74
|
Local Network's last explicit probe is historical; ordinary Refresh cannot make
|
|
89
75
|
it a fresh OS setting. Keep cached reports visibly stale when collection fails.
|
|
90
76
|
Missing/malformed declarations remain errors; an empty list is not proof of a
|
|
91
|
-
complete inventory
|
|
77
|
+
complete inventory. Do not grant by default on other OSes.
|
|
92
78
|
|
|
93
79
|
## macOS and Linux
|
|
94
80
|
|
|
@@ -107,8 +93,8 @@ Host BLE broker is implied by this contract.
|
|
|
107
93
|
|
|
108
94
|
Linux native services use the configured ordinary runtime account and existing
|
|
109
95
|
system interfaces, including BlueZ D-Bus. Foundation reports the absence of a
|
|
110
|
-
native application-consent step
|
|
111
|
-
|
|
96
|
+
native application-consent step as `notRequired`. Resource health belongs to the
|
|
97
|
+
service's own diagnostics and does not affect this permission report.
|
|
112
98
|
An installation preflight collects concrete missing conditions. An administrator
|
|
113
99
|
may authorize a bounded, idempotent setup step for those conditions; service
|
|
114
100
|
manifests must not supply privileged commands. Runtime processes remain ordinary
|
|
@@ -119,10 +105,9 @@ policies are separate deployment conditions, not automatically inherited grants.
|
|
|
119
105
|
## Acceptance
|
|
120
106
|
|
|
121
107
|
Test passive reads without prompts; real signed allow/deny/revoke/relaunch
|
|
122
|
-
behavior; shared grants across two executors;
|
|
123
|
-
sidecar and stopped-service observations; conflicting per-service states;
|
|
108
|
+
behavior; shared grants across two executors; sidecar and stopped-service observations; conflicting per-component states;
|
|
124
109
|
per-target Automation; cross-host mutation rejection; required component
|
|
125
|
-
selection; incomplete manifests; bounded collection;
|
|
126
|
-
Linux
|
|
110
|
+
selection; incomplete manifests; bounded collection; native request deduplication; and
|
|
111
|
+
Linux `notRequired` without any resource observation. Test Linux setup first as
|
|
127
112
|
a dry-run and verify effective access in the intended ordinary runtime session.
|
|
128
113
|
Signing fixtures and mocked status tests do not prove TCC attribution.
|
package/manifest/core.v1.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"manifest": "mhome.core.v1",
|
|
3
|
-
"contractVersion": "1.
|
|
3
|
+
"contractVersion": "1.19.0",
|
|
4
4
|
"protocols": {
|
|
5
5
|
"agentGateway": {
|
|
6
6
|
"submitTarget": "/agent/submit",
|
|
@@ -63,7 +63,7 @@
|
|
|
63
63
|
"version": "storage.v2"
|
|
64
64
|
},
|
|
65
65
|
"hostDelivery": {
|
|
66
|
-
"externalProtocolVersion":
|
|
66
|
+
"externalProtocolVersion": 17,
|
|
67
67
|
"requestKind": "deliveryRequested",
|
|
68
68
|
"connectionControlKind": "connectionControlRequested",
|
|
69
69
|
"acceptanceBoundaries": [
|
package/package.json
CHANGED
package/protocol.json
CHANGED
|
@@ -41,39 +41,6 @@
|
|
|
41
41
|
}
|
|
42
42
|
]
|
|
43
43
|
},
|
|
44
|
-
"PermissionAccess": {
|
|
45
|
-
"type": "object",
|
|
46
|
-
"additionalProperties": false,
|
|
47
|
-
"required": [
|
|
48
|
-
"state",
|
|
49
|
-
"observedAtMs",
|
|
50
|
-
"detail"
|
|
51
|
-
],
|
|
52
|
-
"properties": {
|
|
53
|
-
"state": {
|
|
54
|
-
"enum": [
|
|
55
|
-
"unknown",
|
|
56
|
-
"available",
|
|
57
|
-
"unavailable"
|
|
58
|
-
]
|
|
59
|
-
},
|
|
60
|
-
"observedAtMs": {
|
|
61
|
-
"anyOf": [
|
|
62
|
-
{
|
|
63
|
-
"type": "integer",
|
|
64
|
-
"minimum": 0
|
|
65
|
-
},
|
|
66
|
-
{
|
|
67
|
-
"type": "null"
|
|
68
|
-
}
|
|
69
|
-
]
|
|
70
|
-
},
|
|
71
|
-
"detail": {
|
|
72
|
-
"type": "string",
|
|
73
|
-
"minLength": 1
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
},
|
|
77
44
|
"PermissionObservation": {
|
|
78
45
|
"type": "object",
|
|
79
46
|
"additionalProperties": false,
|
|
@@ -83,7 +50,6 @@
|
|
|
83
50
|
"state",
|
|
84
51
|
"evidence",
|
|
85
52
|
"observedAtMs",
|
|
86
|
-
"access",
|
|
87
53
|
"error"
|
|
88
54
|
],
|
|
89
55
|
"properties": {
|
|
@@ -124,16 +90,6 @@
|
|
|
124
90
|
}
|
|
125
91
|
]
|
|
126
92
|
},
|
|
127
|
-
"access": {
|
|
128
|
-
"anyOf": [
|
|
129
|
-
{
|
|
130
|
-
"$ref": "#/$defs/PermissionAccess"
|
|
131
|
-
},
|
|
132
|
-
{
|
|
133
|
-
"type": "null"
|
|
134
|
-
}
|
|
135
|
-
]
|
|
136
|
-
},
|
|
137
93
|
"error": {
|
|
138
94
|
"anyOf": [
|
|
139
95
|
{
|
|
@@ -165,34 +121,18 @@
|
|
|
165
121
|
}
|
|
166
122
|
]
|
|
167
123
|
},
|
|
168
|
-
"
|
|
169
|
-
"type": "object",
|
|
170
|
-
"additionalProperties": false,
|
|
171
|
-
"required": [
|
|
172
|
-
"id",
|
|
173
|
-
"name"
|
|
174
|
-
],
|
|
175
|
-
"properties": {
|
|
176
|
-
"id": {
|
|
177
|
-
"type": "string",
|
|
178
|
-
"minLength": 1
|
|
179
|
-
},
|
|
180
|
-
"name": {
|
|
181
|
-
"type": "string",
|
|
182
|
-
"minLength": 1
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
},
|
|
186
|
-
"PermissionUse": {
|
|
124
|
+
"HostPermission": {
|
|
187
125
|
"type": "object",
|
|
188
126
|
"additionalProperties": false,
|
|
189
127
|
"required": [
|
|
190
128
|
"componentId",
|
|
191
129
|
"componentName",
|
|
130
|
+
"permission",
|
|
192
131
|
"feature",
|
|
193
132
|
"reason",
|
|
194
133
|
"observation",
|
|
195
|
-
"error"
|
|
134
|
+
"error",
|
|
135
|
+
"supportedActions"
|
|
196
136
|
],
|
|
197
137
|
"properties": {
|
|
198
138
|
"componentId": {
|
|
@@ -203,6 +143,9 @@
|
|
|
203
143
|
"type": "string",
|
|
204
144
|
"minLength": 1
|
|
205
145
|
},
|
|
146
|
+
"permission": {
|
|
147
|
+
"$ref": "#/$defs/PermissionKey"
|
|
148
|
+
},
|
|
206
149
|
"feature": {
|
|
207
150
|
"type": "string",
|
|
208
151
|
"minLength": 1
|
|
@@ -230,50 +173,6 @@
|
|
|
230
173
|
"type": "null"
|
|
231
174
|
}
|
|
232
175
|
]
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
},
|
|
236
|
-
"HostPermission": {
|
|
237
|
-
"type": "object",
|
|
238
|
-
"additionalProperties": false,
|
|
239
|
-
"required": [
|
|
240
|
-
"permission",
|
|
241
|
-
"subject",
|
|
242
|
-
"uses",
|
|
243
|
-
"requestComponentId",
|
|
244
|
-
"supportedActions"
|
|
245
|
-
],
|
|
246
|
-
"properties": {
|
|
247
|
-
"permission": {
|
|
248
|
-
"$ref": "#/$defs/PermissionKey"
|
|
249
|
-
},
|
|
250
|
-
"subject": {
|
|
251
|
-
"anyOf": [
|
|
252
|
-
{
|
|
253
|
-
"$ref": "#/$defs/PermissionSubject"
|
|
254
|
-
},
|
|
255
|
-
{
|
|
256
|
-
"type": "null"
|
|
257
|
-
}
|
|
258
|
-
]
|
|
259
|
-
},
|
|
260
|
-
"uses": {
|
|
261
|
-
"type": "array",
|
|
262
|
-
"minItems": 1,
|
|
263
|
-
"items": {
|
|
264
|
-
"$ref": "#/$defs/PermissionUse"
|
|
265
|
-
}
|
|
266
|
-
},
|
|
267
|
-
"requestComponentId": {
|
|
268
|
-
"anyOf": [
|
|
269
|
-
{
|
|
270
|
-
"type": "string",
|
|
271
|
-
"minLength": 1
|
|
272
|
-
},
|
|
273
|
-
{
|
|
274
|
-
"type": "null"
|
|
275
|
-
}
|
|
276
|
-
]
|
|
277
176
|
},
|
|
278
177
|
"supportedActions": {
|
|
279
178
|
"type": "array",
|
|
@@ -285,45 +184,7 @@
|
|
|
285
184
|
]
|
|
286
185
|
}
|
|
287
186
|
}
|
|
288
|
-
}
|
|
289
|
-
"allOf": [
|
|
290
|
-
{
|
|
291
|
-
"if": {
|
|
292
|
-
"properties": {
|
|
293
|
-
"subject": {
|
|
294
|
-
"type": "null"
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
},
|
|
298
|
-
"then": {
|
|
299
|
-
"properties": {
|
|
300
|
-
"uses": {
|
|
301
|
-
"maxItems": 1
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
|
-
},
|
|
306
|
-
{
|
|
307
|
-
"if": {
|
|
308
|
-
"properties": {
|
|
309
|
-
"requestComponentId": {
|
|
310
|
-
"type": "null"
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
|
-
},
|
|
314
|
-
"then": {
|
|
315
|
-
"properties": {
|
|
316
|
-
"supportedActions": {
|
|
317
|
-
"not": {
|
|
318
|
-
"contains": {
|
|
319
|
-
"const": "request"
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
}
|
|
323
|
-
}
|
|
324
|
-
}
|
|
325
|
-
}
|
|
326
|
-
]
|
|
187
|
+
}
|
|
327
188
|
},
|
|
328
189
|
"PermissionDeclarationError": {
|
|
329
190
|
"type": "object",
|