@passioncode-ai/fabric-agent-adapter 0.80.2 → 0.82.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.
Files changed (92) hide show
  1. package/CHANGELOG.md +157 -0
  2. package/README.md +18 -5
  3. package/SECURITY.md +25 -8
  4. package/bin/fabric-agent-adapter.js +24 -1
  5. package/package.json +1 -1
  6. package/plugins/fabric-agent-adapter/.claude-plugin/plugin.json +1 -1
  7. package/plugins/fabric-agent-adapter/skills/adapting-projects-to-fabric/SKILL.md +6 -4
  8. package/plugins/fabric-agent-adapter/skills/adapting-projects-to-fabric/references/dashboard-links.md +16 -3
  9. package/plugins/fabric-agent-adapter/skills/adapting-projects-to-fabric/references/source-and-instance.md +44 -7
  10. package/plugins/fabric-agent-adapter/skills/adapting-projects-to-fabric/scripts/adapt_project.py +116 -4
  11. package/plugins/fabric-agent-adapter/skills/adapting-projects-to-fabric/scripts/check_dashboard_link.py +33 -3
  12. package/plugins/fabric-agent-adapter/skills/adapting-projects-to-fabric/scripts/fabric_secrets.py +257 -10
  13. package/plugins/fabric-agent-adapter/skills/adapting-projects-to-fabric/scripts/fabric_source_check.py +57 -77
  14. package/plugins/fabric-agent-adapter/skills/adapting-projects-to-fabric/scripts/fabric_source_restart.py +56 -0
  15. package/plugins/fabric-agent-adapter/skills/adapting-projects-to-fabric/scripts/fabric_source_tree.py +899 -0
  16. package/plugins/fabric-agent-adapter/skills/adapting-projects-to-fabric/scripts/new_agent.py +308 -0
  17. package/plugins/fabric-agent-adapter/skills/building-fabric-services/SKILL.md +7 -4
  18. package/plugins/fabric-agent-adapter/skills/building-fabric-services/assets/dashboard-kit/fabric-button.js +23 -5
  19. package/plugins/fabric-agent-adapter/skills/building-fabric-services/assets/dashboard-kit/fabric-dashboard.css +1 -1
  20. package/plugins/fabric-agent-adapter/skills/building-fabric-services/assets/dashboard-kit/fabric-dashboard.js +2 -2
  21. package/plugins/fabric-agent-adapter/skills/building-fabric-services/assets/dashboard-kit/kit.json +9 -4
  22. package/plugins/fabric-agent-adapter/skills/building-fabric-services/recipes/support-agent/README.md +1 -1
  23. package/plugins/fabric-agent-adapter/skills/building-fabric-services/references/board.md +4 -2
  24. package/plugins/fabric-agent-adapter/skills/building-fabric-services/references/dashboard-kit.md +15 -2
  25. package/plugins/fabric-agent-adapter/skills/building-fabric-services/references/dashboard-links.md +16 -3
  26. package/plugins/fabric-agent-adapter/skills/building-fabric-services/references/delegation.md +5 -2
  27. package/plugins/fabric-agent-adapter/skills/building-fabric-services/references/interop.md +28 -0
  28. package/plugins/fabric-agent-adapter/skills/building-fabric-services/references/kit-modules.md +4 -3
  29. package/plugins/fabric-agent-adapter/skills/building-fabric-services/references/lifecycle.md +47 -10
  30. package/plugins/fabric-agent-adapter/skills/building-fabric-services/references/migrating-a-service.md +1 -0
  31. package/plugins/fabric-agent-adapter/skills/building-fabric-services/references/package.md +10 -0
  32. package/plugins/fabric-agent-adapter/skills/building-fabric-services/references/protocol.md +31 -8
  33. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/check_dashboard_layout.mjs +21 -0
  34. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/check_dashboard_link.py +33 -3
  35. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/check_service.py +19 -28
  36. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/check_service_channel_agent.py +9 -6
  37. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/check_service_rules.py +146 -3
  38. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-connections.mjs +3 -2
  39. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-delegation.mjs +2 -0
  40. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-descriptor.mjs +79 -2
  41. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-holds.mjs +269 -0
  42. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-http.mjs +64 -5
  43. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-hub.mjs +16 -7
  44. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-lock.mjs +73 -3
  45. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-package.mjs +98 -1
  46. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-peer-owner.mjs +89 -22
  47. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-protocols.mjs +1 -1
  48. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-secrets.mjs +39 -6
  49. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-service.mjs +8 -0
  50. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-supervisors.mjs +76 -11
  51. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_connections.py +8 -153
  52. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_descriptor.py +86 -2
  53. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_holds.py +324 -0
  54. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_http.py +34 -3
  55. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_hub.py +35 -17
  56. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_lock.py +77 -4
  57. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_package.py +103 -1
  58. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_peer_owner.py +156 -133
  59. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_protocols.py +1 -1
  60. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_secrets.py +257 -10
  61. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_service.py +6 -0
  62. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_supervisors.py +64 -3
  63. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/kit.json +246 -24
  64. package/plugins/fabric-agent-adapter/skills/creating-fabric-agents/SKILL.md +16 -6
  65. package/plugins/fabric-agent-adapter/skills/creating-fabric-agents/references/agent-templates.md +44 -0
  66. package/plugins/fabric-agent-adapter/skills/creating-fabric-agents/references/communication-agent-template.md +19 -328
  67. package/plugins/fabric-agent-adapter/skills/creating-fabric-agents/references/dashboard-links.md +16 -3
  68. package/plugins/fabric-agent-adapter/skills/creating-fabric-agents/references/models-and-providers.md +1 -1
  69. package/plugins/fabric-agent-adapter/skills/creating-fabric-agents/references/new-agent.md +42 -0
  70. package/plugins/fabric-agent-adapter/skills/creating-fabric-agents/references/source-and-instance.md +44 -7
  71. package/plugins/fabric-agent-adapter/skills/creating-fabric-agents/schemas/template/access.schema.json +50 -0
  72. package/plugins/fabric-agent-adapter/skills/creating-fabric-agents/schemas/template/connections.schema.json +23 -0
  73. package/plugins/fabric-agent-adapter/skills/creating-fabric-agents/schemas/template/data-rooms.schema.json +74 -0
  74. package/plugins/fabric-agent-adapter/skills/creating-fabric-agents/schemas/template/manifest.schema.json +170 -0
  75. package/plugins/fabric-agent-adapter/skills/creating-fabric-agents/schemas/template/template-header.schema.json +25 -0
  76. package/plugins/fabric-agent-adapter/skills/creating-fabric-agents/scripts/check_dashboard_link.py +33 -3
  77. package/plugins/fabric-agent-adapter/skills/creating-fabric-agents/scripts/template_check.py +491 -0
  78. package/plugins/fabric-agent-adapter/skills/creating-fabric-agents/templates/communication-agent/CHANGELOG.md +7 -0
  79. package/plugins/fabric-agent-adapter/skills/creating-fabric-agents/templates/communication-agent/TEMPLATE.md +347 -0
  80. package/plugins/fabric-agent-adapter/skills/creating-fabric-agents/templates/communication-agent/access.json +24 -0
  81. package/plugins/fabric-agent-adapter/skills/creating-fabric-agents/templates/communication-agent/assembly.md +15 -0
  82. package/plugins/fabric-agent-adapter/skills/creating-fabric-agents/templates/communication-agent/checks/acceptance.md +17 -0
  83. package/plugins/fabric-agent-adapter/skills/creating-fabric-agents/templates/communication-agent/connections.json +29 -0
  84. package/plugins/fabric-agent-adapter/skills/creating-fabric-agents/templates/communication-agent/data-rooms.json +9 -0
  85. package/plugins/fabric-agent-adapter/skills/creating-fabric-agents/templates/communication-agent/manifest.json +32 -0
  86. package/plugins/fabric-agent-adapter/skills/observing-products/SKILL.md +1 -1
  87. package/plugins/fabric-agent-adapter/skills/working-with-fabric/SKILL.md +2 -2
  88. package/plugins/fabric-agent-adapter/skills/working-with-fabric/references/on-demand-session.md +16 -8
  89. package/plugins/fabric-agent-adapter/skills/working-with-fabric/references/project-board.md +46 -31
  90. package/plugins/fabric-agent-adapter/skills/working-with-fabric/references/session-hooks.md +1 -1
  91. package/plugins/fabric-agent-adapter/skills/working-with-fabric/scripts/fabric_session_cli.py +18 -16
  92. package/plugins/fabric-agent-adapter/skills/working-with-fabric/scripts/fabric_session_env.py +23 -13
@@ -0,0 +1,23 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://github.com/passioncode-ai/fabric-agent-adapter/schemas/template/connections.schema.json",
4
+ "title": "connections.json of an agent template: the source classes it reads and writes, each with its connector and grant",
5
+ "type": "array",
6
+ "items": {
7
+ "type": "object",
8
+ "required": ["source_class", "connector", "grant", "required", "direction"],
9
+ "additionalProperties": false,
10
+ "properties": {
11
+ "source_class": {"type": "string", "minLength": 1, "description": "a class of source (a tracker, a chat, a store), never one installation"},
12
+ "connector": {"type": "string", "minLength": 1},
13
+ "grant": {"type": "string", "minLength": 1, "description": "the grant or scope it needs, by name; never a value"},
14
+ "required": {"type": "boolean"},
15
+ "when": {"type": "string", "minLength": 1, "description": "the condition under which an optional connection is needed, or under which a required one applies"},
16
+ "direction": {"enum": ["read", "write", "read-write", "call"]},
17
+ "scope": {"type": "string", "minLength": 1, "description": "what the direction covers, in words (\"draft pull requests only\")"},
18
+ "spends": {"type": "boolean", "description": "true when a call through it costs money (rule A6)"},
19
+ "variants": {"type": "array", "items": {"type": "string"}, "minItems": 1, "uniqueItems": true},
20
+ "notes": {"type": "string"}
21
+ }
22
+ }
23
+ }
@@ -0,0 +1,74 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://github.com/passioncode-ai/fabric-agent-adapter/schemas/template/data-rooms.schema.json",
4
+ "title": "data-rooms.json of an agent template: the rooms and blocks it reads or writes ([] when none)",
5
+ "type": "array",
6
+ "items": {
7
+ "type": "object",
8
+ "required": [
9
+ "room",
10
+ "blocks",
11
+ "access"
12
+ ],
13
+ "additionalProperties": false,
14
+ "properties": {
15
+ "room": {
16
+ "type": "string",
17
+ "minLength": 1
18
+ },
19
+ "blocks": {
20
+ "type": "array",
21
+ "items": {
22
+ "type": "string",
23
+ "minLength": 1
24
+ },
25
+ "minItems": 1,
26
+ "uniqueItems": true
27
+ },
28
+ "access": {
29
+ "enum": [
30
+ "read",
31
+ "write",
32
+ "read-write"
33
+ ]
34
+ },
35
+ "scope": {
36
+ "type": "string",
37
+ "minLength": 1,
38
+ "description": "what the access covers, in words (\"its own block\", \"aggregate cells only\")"
39
+ },
40
+ "classes": {
41
+ "type": "array",
42
+ "items": {
43
+ "type": "string",
44
+ "minLength": 1
45
+ },
46
+ "minItems": 1,
47
+ "uniqueItems": true,
48
+ "description": "the data classes it may touch in the block"
49
+ },
50
+ "level": {
51
+ "type": "string",
52
+ "minLength": 1,
53
+ "description": "whose level bounds the read (\"the asker's level\")"
54
+ },
55
+ "required": {
56
+ "type": "boolean"
57
+ },
58
+ "variants": {
59
+ "type": "array",
60
+ "items": {
61
+ "type": "string"
62
+ },
63
+ "minItems": 1,
64
+ "uniqueItems": true
65
+ },
66
+ "use": {
67
+ "type": "string"
68
+ },
69
+ "notes": {
70
+ "type": "string"
71
+ }
72
+ }
73
+ }
74
+ }
@@ -0,0 +1,170 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://github.com/passioncode-ai/fabric-agent-adapter/schemas/template/manifest.schema.json",
4
+ "title": "manifest.json of an agent template: placement, contract, doors, dashboard, base model per task, budget",
5
+ "description": "placement, doors, models, dashboard and budget sit at the top level, or in every entry of `variants` when the variants differ. Their inner shape is the template's own in schema 1.",
6
+ "type": "object",
7
+ "required": [
8
+ "template",
9
+ "version",
10
+ "contract"
11
+ ],
12
+ "additionalProperties": false,
13
+ "patternProperties": {
14
+ "^x-[a-z0-9-]+$": {}
15
+ },
16
+ "properties": {
17
+ "template": {
18
+ "type": "string",
19
+ "pattern": "^[a-z][a-z0-9-]{1,63}$",
20
+ "description": "equals TEMPLATE.md's template.id"
21
+ },
22
+ "version": {
23
+ "type": "string",
24
+ "pattern": "^(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)$",
25
+ "description": "equals TEMPLATE.md's template.version"
26
+ },
27
+ "contract": {
28
+ "description": "one protocol the template was checked against, or a map of them by role",
29
+ "oneOf": [
30
+ {
31
+ "$ref": "#/$defs/protocol"
32
+ },
33
+ {
34
+ "type": "object",
35
+ "minProperties": 1,
36
+ "additionalProperties": {
37
+ "$ref": "#/$defs/protocol"
38
+ }
39
+ }
40
+ ]
41
+ },
42
+ "placement": {
43
+ "type": [
44
+ "object",
45
+ "string"
46
+ ]
47
+ },
48
+ "doors": {
49
+ "type": [
50
+ "object",
51
+ "array"
52
+ ]
53
+ },
54
+ "models": {
55
+ "type": [
56
+ "object",
57
+ "array"
58
+ ]
59
+ },
60
+ "dashboard": {
61
+ "type": [
62
+ "object",
63
+ "string"
64
+ ]
65
+ },
66
+ "budget": {
67
+ "type": [
68
+ "object",
69
+ "string"
70
+ ]
71
+ },
72
+ "schedules": {
73
+ "type": [
74
+ "array",
75
+ "object",
76
+ "string"
77
+ ]
78
+ },
79
+ "limits": {
80
+ "type": "object"
81
+ },
82
+ "events": {
83
+ "type": "array"
84
+ },
85
+ "variants": {
86
+ "type": "object",
87
+ "minProperties": 1,
88
+ "additionalProperties": {
89
+ "type": "object",
90
+ "properties": {
91
+ "placement": {
92
+ "type": [
93
+ "object",
94
+ "string"
95
+ ]
96
+ },
97
+ "doors": {
98
+ "type": [
99
+ "object",
100
+ "array"
101
+ ]
102
+ },
103
+ "models": {
104
+ "type": [
105
+ "object",
106
+ "array"
107
+ ]
108
+ },
109
+ "dashboard": {
110
+ "type": [
111
+ "object",
112
+ "string"
113
+ ]
114
+ },
115
+ "budget": {
116
+ "type": [
117
+ "object",
118
+ "string"
119
+ ]
120
+ }
121
+ }
122
+ }
123
+ },
124
+ "notes": {
125
+ "type": "string"
126
+ }
127
+ },
128
+ "$defs": {
129
+ "protocol": {
130
+ "type": "object",
131
+ "required": [
132
+ "name",
133
+ "home",
134
+ "checked_against"
135
+ ],
136
+ "additionalProperties": false,
137
+ "properties": {
138
+ "name": {
139
+ "type": "string",
140
+ "minLength": 1
141
+ },
142
+ "home": {
143
+ "type": "string",
144
+ "minLength": 1
145
+ },
146
+ "checked_against": {
147
+ "type": "string",
148
+ "minLength": 1,
149
+ "description": "the version or date checked against: \"checked against\", never \"requires\""
150
+ },
151
+ "extensions": {
152
+ "type": "array",
153
+ "items": {
154
+ "type": "string",
155
+ "minLength": 1
156
+ },
157
+ "uniqueItems": true,
158
+ "description": "the protocol's extensions the template uses, by name"
159
+ },
160
+ "applies_to": {
161
+ "type": "string",
162
+ "minLength": 1
163
+ },
164
+ "notes": {
165
+ "type": "string"
166
+ }
167
+ }
168
+ }
169
+ }
170
+ }
@@ -0,0 +1,25 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://github.com/passioncode-ai/fabric-agent-adapter/schemas/template/template-header.schema.json",
4
+ "title": "The `template:` header of an agent template's TEMPLATE.md (fabric-workspace S2, decision W0-Q8)",
5
+ "type": "object",
6
+ "required": ["template"],
7
+ "additionalProperties": false,
8
+ "properties": {
9
+ "template": {
10
+ "type": "object",
11
+ "required": ["id", "name", "version", "family", "checked", "readiness", "variants"],
12
+ "additionalProperties": false,
13
+ "properties": {
14
+ "id": {"type": "string", "pattern": "^[a-z][a-z0-9-]{1,63}$", "description": "equals the folder's name"},
15
+ "name": {"type": "string", "minLength": 1, "maxLength": 120},
16
+ "version": {"type": "string", "pattern": "^(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)$"},
17
+ "family": {"type": "string", "pattern": "^[a-z]+(-[a-z]+)*$"},
18
+ "checked": {"type": "string", "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}$"},
19
+ "readiness": {"enum": ["draft", "validated", "proven"]},
20
+ "sources": {"type": "integer", "minimum": 0},
21
+ "variants": {"type": "array", "items": {"type": "string", "pattern": "^[a-z][a-z0-9-]{0,63}$"}, "uniqueItems": true}
22
+ }
23
+ }
24
+ }
25
+ }
@@ -28,8 +28,32 @@ CREDENTIAL_PAIRS = {
28
28
  'session': {'token', 'id'},
29
29
  'code': {'login', 'auth', 'access', 'session'}}
30
30
  JWT_SHAPE = re.compile(r'eyJ[A-Za-z0-9_-]{2,}\.[A-Za-z0-9_-]{2,}\.[A-Za-z0-9_-]*')
31
- SECRET_VALUE = re.compile(r'(^bearer\s.+|sk-[A-Za-z0-9_-]{16,}|gh[pousr]_[A-Za-z0-9]{20,}|xox[abposr]-[A-Za-z0-9-]{10,}'
32
- r'|AKIA[0-9A-Z]{16}|glpat-[A-Za-z0-9_-]{20,})', re.I | re.S)
31
+ URL_BASE64_RUN = re.compile(r'[A-Za-z0-9_-]*')
32
+
33
+
34
+ def has_jwt(text):
35
+ # Whether JWT_SHAPE matches anywhere, read in one pass (the contract's hasJwt, FAA-313): the expression backtracks
36
+ # from every `eyJ` of a long run, quadratic in it, while every `eyJ` of one run shares that run's end, so only its
37
+ # first is tried. The kit's fabric_secrets.has_jwt reads the same way; this file stands alone, so it has its own.
38
+ at = text.find('eyJ')
39
+ while at >= 0:
40
+ one = URL_BASE64_RUN.match(text, at + 3).end()
41
+ if one - at - 3 >= 2 and text[one:one + 1] == '.':
42
+ two = URL_BASE64_RUN.match(text, one + 1).end()
43
+ if two - one - 1 >= 2 and text[two:two + 1] == '.':
44
+ return True
45
+ at = text.find('eyJ', one)
46
+ return False
47
+
48
+
49
+ # The contract's SECRET_VALUE at the pin (DEC-0151): `Bearer ` at a value's start in any case, or a provider key with its
50
+ # prefix in its canonical case after a boundary (the start, a character that is no ASCII letter or digit, or an escape);
51
+ # an `sk-` key holds a digit and an upper-case letter with 16 or more characters, or a digit with 32 or more.
52
+ SECRET_VALUE = re.compile(r'(^[Bb][Ee][Aa][Rr][Ee][Rr]\s.+|(?:^|[^A-Za-z0-9]|%[0-9A-Fa-f]{2}|\\[nrt"\']|\\u[0-9A-Fa-f]{4}'
53
+ r'|\\x[0-9A-Fa-f]{2}|\\[bfv0ae]|\\[0-7]{1,3}|%25[0-9A-Fa-f]{2}|\x1b\[[0-9;:]*m'
54
+ r'|(?:\\u001[bB]|\\x1[bB]|\\e|\\033|\\33)\[[0-9;:]*m)'
55
+ r'(?:sk-(?=[A-Za-z0-9_-]{0,255}?[0-9])(?:(?=[A-Za-z0-9_-]{0,255}?[A-Z])[A-Za-z0-9_-]{16,}|[A-Za-z0-9_-]{32,})'
56
+ r'|gh[pousr]_[A-Za-z0-9]{20,}|xox[abposr]-[A-Za-z0-9-]{10,}|AKIA[0-9A-Z]{16}|glpat-[A-Za-z0-9_-]{20,}))', re.S)
33
57
  LONG_RUN = re.compile(r'[A-Za-z0-9+/=_-]{40,}')
34
58
 
35
59
 
@@ -52,7 +76,7 @@ def credential_name(name):
52
76
  def secret_value(value):
53
77
  long_secret = any(re.search(r'[a-z]', run) and re.search(r'[A-Z]', run) and re.search(r'[0-9]', run)
54
78
  for run in LONG_RUN.findall(value))
55
- return bool(JWT_SHAPE.search(value) or SECRET_VALUE.search(value) or long_secret)
79
+ return bool(has_jwt(value) or SECRET_VALUE.search(value) or long_secret)
56
80
 
57
81
 
58
82
  def carries_credential(text):
@@ -115,6 +139,11 @@ def check(data):
115
139
  require(all(isinstance(v, str) and 0 < len(v) <= 200 for v in (target, viewer)), 'missing_device')
116
140
  fallback = data.get('fallback', 'if_absent')
117
141
  require(fallback in ('if_absent', 'never'), 'invalid_fallback')
142
+ # DEC-0154 PL-3 and HA-2 (FAA-251): who listens on http_url's port, as the host read it from the socket table
143
+ # (fabric_peer_owner's kinds, or check_service.py's foreign-user). A browser opens a raw loopback address only
144
+ # after that listener is this OS account's; absent, it is unknown.
145
+ owner = data.get('listener_owner', 'unknown')
146
+ require(owner in ('this-account', 'another-account', 'system', 'unknown', 'none', 'foreign-user'), 'invalid_listener_owner')
118
147
  kind = action.get('kind')
119
148
  if kind == 'remote_open':
120
149
  require(set(action) <= {'kind', 'device_id', 'service', 'path'}, 'unexpected_action_field')
@@ -128,6 +157,7 @@ def check(data):
128
157
  require(set(action) == {'kind', 'url'} and action.get('url') == http, 'not_resolved_http_url')
129
158
  require(viewer == target, 'wrong_viewer_device')
130
159
  require(state == 'not_installed' and fallback == 'if_absent', 'browser_fallback_forbidden')
160
+ require(owner == 'this-account', 'listener_not_this_account')
131
161
  else:
132
162
  raise ValueError('unsupported_dashboard_action')
133
163
  return {'ok': True, 'kind': kind}