@passioncode-ai/fabric-agent-adapter 0.49.0 → 0.49.2
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/CHANGELOG.md +29 -0
- package/package.json +1 -1
- package/plugins/fabric-agent-adapter/.claude-plugin/plugin.json +1 -1
- package/plugins/fabric-agent-adapter/skills/adapting-projects-to-fabric/SKILL.md +1 -1
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/SKILL.md +1 -1
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/references/remote-placement.md +13 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/check_service.py +3 -2
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/check_service_rules.py +31 -1
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_estate.py +17 -18
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_jsvalue.py +1 -1
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/kit.json +155 -3
- package/plugins/fabric-agent-adapter/skills/creating-fabric-agents/SKILL.md +1 -1
- package/plugins/fabric-agent-adapter/skills/working-with-fabric/SKILL.md +1 -1
- package/plugins/fabric-agent-adapter/skills/working-with-fabric/scripts/fabric_session_env.py +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,34 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.49.2 (2026-10-24)
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
|
|
7
|
+
- **The probe judges a remote service's session cookie by its name** (FAA-115, a finding from a service on
|
|
8
|
+
DigitalOcean App Platform). `check_service.py` kept one `Set-Cookie` per answer, so when a CDN edge added its own
|
|
9
|
+
cookie to the login redirect (`__cf_bm` from Cloudflare) `login.cookie-host-bound` and `login.single-use` judged the
|
|
10
|
+
edge's cookie and failed a service that does everything right. The probe now keeps every `Set-Cookie`
|
|
11
|
+
(`merge_headers`) and picks the session cookie by name, `__Host-fabric_session` or `fabric_session`; with neither,
|
|
12
|
+
the first cookie a known edge does not set (`session_cookie` in `check_service_rules.py`). A session cookie that is
|
|
13
|
+
not host-bound still fails.
|
|
14
|
+
|
|
15
|
+
## 0.49.1 (2026-10-24)
|
|
16
|
+
|
|
17
|
+
### Fixed
|
|
18
|
+
|
|
19
|
+
- **The Python estate kit matches every membership as the contract does** (FAA-113, from the 0.49.0 seam reading).
|
|
20
|
+
The contract keeps machine ids, passkeys, publisher keys, grants and revocations in a `Set`, or tests them with
|
|
21
|
+
`includes`; both match NaN with NaN. Fifteen lookups in `fabric_estate.py` used `===`-style matching, so a record a
|
|
22
|
+
Python caller builds with a NaN id was read differently from the Node twin: a NaN id listed twice passed, and a
|
|
23
|
+
secret from a NaN machine was flagged as coming from outside the estate. They now use `set_has`. No JSON the kit
|
|
24
|
+
loads carries NaN (`parse_constant` refuses it), so a service reading records from JSON saw no difference.
|
|
25
|
+
|
|
26
|
+
### Tests
|
|
27
|
+
|
|
28
|
+
- FAC-SEM-137 on the verify path (FAA-112): six `verify` vectors vary the delta anchor on the contract's EdDSA
|
|
29
|
+
revision 2, re-signed with the vectors' test seed and answered by the contract's `verifyEstateRecord`.
|
|
30
|
+
- The board restart cases wait on their condition, not a fixed 20 ms (FAA-114).
|
|
31
|
+
|
|
3
32
|
## 0.49.0 (2026-10-24)
|
|
4
33
|
|
|
5
34
|
The operator's sweep (FAA-111): blind seam and product readings of 0.47.0 to 0.48.3, their findings fixed, documented
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@passioncode-ai/fabric-agent-adapter",
|
|
3
|
-
"version": "0.49.
|
|
3
|
+
"version": "0.49.2",
|
|
4
4
|
"description": "Create Fabric-compatible agents, run them as always-alive local services with dashboards (fabric-service/0.1), and adapt existing projects to the Fabric Agent Contract. This package is the installer CLI.",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"test": "python3 test/validate.py && python3 -m unittest discover -s test -q && node --test 'test/*.test.mjs'"
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"name": "fabric-agent-adapter",
|
|
4
4
|
"displayName": "Fabric Agent Adapter",
|
|
5
5
|
"description": "Create new Fabric-compatible agents, build them as always-alive local services with dashboards (fabric-service/0.1), and adapt existing projects to the Fabric Agent Contract through evidence-backed MCP, A2A, or local-runner provider bundles; and teach a coding agent to work in a project through Fabric (fabric-mcp, fabric_whoami, claim and release), with Claude Code session hooks.",
|
|
6
|
-
"version": "0.49.
|
|
6
|
+
"version": "0.49.2",
|
|
7
7
|
"author": {
|
|
8
8
|
"name": "PassionCode.ai",
|
|
9
9
|
"url": "https://passioncode.ai/"
|
|
@@ -5,7 +5,7 @@ license: AGPL-3.0-only OR LicenseRef-PassionCode-Commercial
|
|
|
5
5
|
compatibility: Requires filesystem access and Python 3.9+. Exact schema checks additionally need git, Node.js, pnpm, and the pinned fabric-agent-contract checkout (a public repository). Works without those tools in an explicitly degraded structural-check mode.
|
|
6
6
|
metadata:
|
|
7
7
|
author: PassionCode.ai
|
|
8
|
-
version: "0.49.
|
|
8
|
+
version: "0.49.2"
|
|
9
9
|
contract-version: "0.1.0"
|
|
10
10
|
contract-commit: "2f020a696453ae299b123517f14957f6a1354379"
|
|
11
11
|
---
|
|
@@ -14,7 +14,7 @@ license: AGPL-3.0-only OR LicenseRef-PassionCode-Commercial
|
|
|
14
14
|
compatibility: Python 3.9+ or Node.js 20+ for the kits (Node.js 22+ for a Linux service's instance lock); the probe needs Python 3.9+. launchd steps are macOS-only; Linux services install a systemd user unit and Windows ones a per-user Scheduled Task with the kits' writers. Dashboard handoff optionally uses Fabric Dashboards MCP link/host_status/open; without it, report unresolved host capability. The contract checkout is optional.
|
|
15
15
|
metadata:
|
|
16
16
|
author: PassionCode.ai
|
|
17
|
-
version: "0.49.
|
|
17
|
+
version: "0.49.2"
|
|
18
18
|
contract-version: "0.1.0"
|
|
19
19
|
extension: "fabric-service/0.1"
|
|
20
20
|
extension-commit: "2f020a696453ae299b123517f14957f6a1354379"
|
package/plugins/fabric-agent-adapter/skills/building-fabric-services/references/remote-placement.md
CHANGED
|
@@ -3,6 +3,15 @@
|
|
|
3
3
|
Normative source: `fabric-agent-contract` `docs/specification/service.md` → *Remote placement*,
|
|
4
4
|
DEC-0019, at the commit this skill pins. This page is the how-to.
|
|
5
5
|
|
|
6
|
+
## Contents
|
|
7
|
+
|
|
8
|
+
- [Is it a remote service?](#is-it-a-remote-service)
|
|
9
|
+
- [The descriptor](#the-descriptor)
|
|
10
|
+
- [On the platform](#on-the-platform)
|
|
11
|
+
- [Checking it](#checking-it)
|
|
12
|
+
- [What a host does and will not do](#what-a-host-does-and-will-not-do)
|
|
13
|
+
- [Rotation](#rotation)
|
|
14
|
+
|
|
6
15
|
## Is it a remote service?
|
|
7
16
|
|
|
8
17
|
It is, when it runs outside the operator's computer and the operator wants it in Fabric beside
|
|
@@ -77,6 +86,10 @@ FAILs remain possible, and the evidence names the value it found: a proxy page t
|
|
|
77
86
|
`id.instance` (an application the proxy titles after the service), and, when the document was read, a page that happens
|
|
78
87
|
to contain the service's pid as a whole number (an inline script's constant, say).
|
|
79
88
|
|
|
89
|
+
A CDN edge may add its own cookie to the login redirect (DigitalOcean App Platform's Cloudflare edge sets `__cf_bm`).
|
|
90
|
+
The login rules keep every `Set-Cookie` of the answer and judge the session cookie by its name, `__Host-fabric_session`
|
|
91
|
+
(or `fabric_session`); with neither, the first cookie that is not a known edge cookie (FAA-115).
|
|
92
|
+
|
|
80
93
|
## What a host does and will not do
|
|
81
94
|
|
|
82
95
|
| Situation | Host |
|
package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/check_service.py
CHANGED
|
@@ -68,6 +68,7 @@ from check_service_rules import session_lifetime_problem # noqa: E402,F401 - mo
|
|
|
68
68
|
from check_service_rules import _semver # noqa: E402,F401 - moved (FAA-65)
|
|
69
69
|
from check_service_rules import usage_problems # noqa: E402,F401 - moved (FAA-65)
|
|
70
70
|
from check_service_rules import same_repository # noqa: E402,F401 - moved (FAA-65)
|
|
71
|
+
from check_service_rules import merge_headers, session_cookie # noqa: E402,F401 - FAA-115
|
|
71
72
|
|
|
72
73
|
|
|
73
74
|
class _PinnedHTTPS(http.client.HTTPSConnection):
|
|
@@ -131,7 +132,7 @@ class Probe:
|
|
|
131
132
|
try:
|
|
132
133
|
conn.request(method, path, body=body, headers=base)
|
|
133
134
|
resp = conn.getresponse()
|
|
134
|
-
return resp.status,
|
|
135
|
+
return resp.status, merge_headers(resp.getheaders()), resp.read()
|
|
135
136
|
finally:
|
|
136
137
|
conn.close()
|
|
137
138
|
|
|
@@ -444,7 +445,7 @@ class Probe:
|
|
|
444
445
|
except (OSError, ValueError, KeyError) as exc:
|
|
445
446
|
self.add("login.single-use", "FAIL", "login-code flow broke: %s" % exc)
|
|
446
447
|
return
|
|
447
|
-
cookie = headers1.get("set-cookie", "")
|
|
448
|
+
cookie = session_cookie(headers1.get("set-cookie", ""), self.remote)
|
|
448
449
|
ok = status1 in (302, 303) and "HttpOnly" in cookie and "SameSite=Strict" in cookie and status2 not in (302, 303)
|
|
449
450
|
if self.remote:
|
|
450
451
|
host_bound = cookie.startswith("__Host-") and "Secure" in cookie and "Path=/" in cookie and "domain=" not in cookie.lower()
|
package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/check_service_rules.py
CHANGED
|
@@ -13,7 +13,7 @@ import subprocess
|
|
|
13
13
|
import sys
|
|
14
14
|
import time
|
|
15
15
|
from pathlib import Path
|
|
16
|
-
from typing import Any, Dict, List, Optional, Tuple
|
|
16
|
+
from typing import Any, Dict, Iterable, List, Optional, Tuple
|
|
17
17
|
|
|
18
18
|
sys.path.insert(0, str(Path(__file__).resolve().parent))
|
|
19
19
|
import fabric_service as fs # noqa: E402 - beside this file
|
|
@@ -185,6 +185,36 @@ def board_responder_verdict(wk: Any, kit: Optional[str] = None) -> Tuple[str, st
|
|
|
185
185
|
", ".join(declared), " at %s" % kit if kit else " beside this probe")
|
|
186
186
|
|
|
187
187
|
|
|
188
|
+
def merge_headers(pairs: Iterable[Tuple[str, str]]) -> Dict[str, str]:
|
|
189
|
+
"""Response headers by lower-case name. Every Set-Cookie is kept, one per line (a header value never holds a
|
|
190
|
+
newline): an edge in front of a service adds its own (FAA-115), so the last or the first is not the service's."""
|
|
191
|
+
merged: Dict[str, str] = {}
|
|
192
|
+
for name, value in pairs:
|
|
193
|
+
key = name.lower()
|
|
194
|
+
merged[key] = merged[key] + "\n" + value if key == "set-cookie" and key in merged else value
|
|
195
|
+
return merged
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
def session_cookie(set_cookie: str, remote: bool) -> str:
|
|
199
|
+
"""The service's session cookie among the Set-Cookie lines merge_headers kept: the one named as the kit names it
|
|
200
|
+
(`__Host-fabric_session` remote, `fabric_session` local, either accepted), else the first a CDN edge does not
|
|
201
|
+
set, so a service that names its cookie otherwise is still judged on its own cookie. "" when none was set."""
|
|
202
|
+
lines = [line.strip() for line in set_cookie.split("\n") if line.strip()]
|
|
203
|
+
names = (fs.REMOTE_SESSION_COOKIE, fs.SESSION_COOKIE) if remote else (fs.SESSION_COOKIE, fs.REMOTE_SESSION_COOKIE)
|
|
204
|
+
for wanted in names:
|
|
205
|
+
for line in lines:
|
|
206
|
+
if line.split("=", 1)[0].strip() == wanted:
|
|
207
|
+
return line
|
|
208
|
+
for line in lines:
|
|
209
|
+
if line.split("=", 1)[0].strip() not in EDGE_COOKIES:
|
|
210
|
+
return line
|
|
211
|
+
return lines[0] if lines else ""
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
# Cookies CDN edges add on their own (Cloudflare, AWS load balancers, Akamai); never a service's session.
|
|
215
|
+
EDGE_COOKIES = frozenset({"__cf_bm", "_cfuvid", "cf_clearance", "__cflb", "AWSALB", "AWSALBCORS", "ak_bmsc", "bm_sv"})
|
|
216
|
+
|
|
217
|
+
|
|
188
218
|
def session_lifetime_problem(set_cookie: str, now: Optional[float] = None) -> Optional[str]:
|
|
189
219
|
"""DEC-0039: a session cookie set at sign-in lives at most 7 days. Max-Age wins over Expires (RFC 6265
|
|
190
220
|
§5.3); a cookie with neither ends with the browser session. None when it is within the bound."""
|
package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_estate.py
CHANGED
|
@@ -49,7 +49,6 @@ from fabric_crypto import ( # noqa: E402 - the core (FAA-65)
|
|
|
49
49
|
)
|
|
50
50
|
from fabric_jsvalue import ( # noqa: E402 - the core (FAA-65)
|
|
51
51
|
MISSING as _MISSING,
|
|
52
|
-
contains as _contains,
|
|
53
52
|
get as _get,
|
|
54
53
|
get_string as _s,
|
|
55
54
|
indexed_objects as _indexed,
|
|
@@ -59,7 +58,7 @@ from fabric_jsvalue import ( # noqa: E402 - the core (FAA-65)
|
|
|
59
58
|
objects as _list,
|
|
60
59
|
safe_integer as _safe_integer,
|
|
61
60
|
same as _same,
|
|
62
|
-
set_has as _set_has,
|
|
61
|
+
set_has as _set_has, # every membership the contract keeps in a Set or tests with includes (FAA-113)
|
|
63
62
|
show as _show,
|
|
64
63
|
)
|
|
65
64
|
from fabric_time import ( # noqa: E402 - the core (FAA-65)
|
|
@@ -331,7 +330,7 @@ def verify_estate_record(record: Any, *, at: Any, parent: Any = _MISSING, author
|
|
|
331
330
|
if not matches:
|
|
332
331
|
return {"ok": False, "problem": "unknown-authority"}
|
|
333
332
|
authority = matches[0]
|
|
334
|
-
if
|
|
333
|
+
if _set_has(revoked, _get(authority, "credentialId")):
|
|
335
334
|
return {"ok": False, "problem": "revoked-authority"}
|
|
336
335
|
origins = _get(authority, "origins")
|
|
337
336
|
credential = {"credentialId": _s(authority, "credentialId"), "alg": _s(authority, "alg"),
|
|
@@ -385,7 +384,7 @@ def _scope_admits(record: Any, kid: Any, context: Any) -> bool:
|
|
|
385
384
|
"""DEC-0090: a key no `publisherScopes[]` entry names is trusted in any context; a partner's key, only in a context
|
|
386
385
|
one of its scopes lists."""
|
|
387
386
|
scopes = [s for s in _list(_get(record, "publisherScopes")) if _same(_get(s, "kid"), kid)]
|
|
388
|
-
return not scopes or any(isinstance(_get(s, "contexts"), list) and
|
|
387
|
+
return not scopes or any(isinstance(_get(s, "contexts"), list) and _set_has(s["contexts"], context) for s in scopes)
|
|
389
388
|
|
|
390
389
|
|
|
391
390
|
#: v4 §7, Freshness: an estate revision's window is at most 30 days (DEC-0055 item 2).
|
|
@@ -545,7 +544,7 @@ def _keys(value: Dict[str, Any], flag) -> None:
|
|
|
545
544
|
hub_keys: List[Any] = []
|
|
546
545
|
for machine, m in _indexed(_get(value, "machines")):
|
|
547
546
|
at = "/machines/%d" % m
|
|
548
|
-
if
|
|
547
|
+
if _set_has(ids, _get(machine, "id")):
|
|
549
548
|
flag("%s/id" % at, "machine %s is listed twice" % _show(_get(machine, "id")))
|
|
550
549
|
ids.append(_get(machine, "id"))
|
|
551
550
|
device_keys = _list(_get(machine, "deviceKeys"))
|
|
@@ -562,15 +561,15 @@ def _keys(value: Dict[str, Any], flag) -> None:
|
|
|
562
561
|
flag("%s/deviceKeys/%d/publicKey" % (at, k), "a device key's octets are written in canonical padded base64, the one form a key reference can name (DEC-0084)")
|
|
563
562
|
elif not _valid_device_key(key):
|
|
564
563
|
flag("%s/deviceKeys/%d/publicKey" % (at, k), "an Ed25519 key is never of small order (DEC-0045) and a P-256 key is a valid point (SEC 1 §3.2.2)")
|
|
565
|
-
if
|
|
564
|
+
if _set_has(seen, _get(key, "publicKey")):
|
|
566
565
|
flag("%s/deviceKeys/%d/publicKey" % (at, k), "one key is never used for the other role")
|
|
567
566
|
seen.append(_get(key, "publicKey"))
|
|
568
567
|
hub = _get(machine, "hubKey")
|
|
569
568
|
if isinstance(hub, dict):
|
|
570
|
-
if
|
|
569
|
+
if _set_has(hub_kids, _get(hub, "kid")):
|
|
571
570
|
flag("%s/hubKey/kid" % at, "hub key %s is certified for two machines: one kid per machine" % _show(_get(hub, "kid")))
|
|
572
571
|
hub_kids.append(_get(hub, "kid"))
|
|
573
|
-
if
|
|
572
|
+
if _set_has(hub_keys, _get(hub, "x")):
|
|
574
573
|
flag("%s/hubKey/x" % at, "one hub public key is certified for two machines under two kids: one key per machine")
|
|
575
574
|
hub_keys.append(_get(hub, "x"))
|
|
576
575
|
x = _get(hub, "x")
|
|
@@ -579,7 +578,7 @@ def _keys(value: Dict[str, Any], flag) -> None:
|
|
|
579
578
|
flag("%s/hubKey/x" % at, "a hub key of small order verifies forged tokens and is never certified (DEC-0045)")
|
|
580
579
|
credentials: List[Any] = []
|
|
581
580
|
for authority, index in _indexed(_get(value, "authorities")):
|
|
582
|
-
if
|
|
581
|
+
if _set_has(credentials, _get(authority, "credentialId")):
|
|
583
582
|
flag("/authorities/%d/credentialId" % index, "a passkey is listed once")
|
|
584
583
|
credentials.append(_get(authority, "credentialId"))
|
|
585
584
|
if "problem" in credential_key(_get(authority, "publicKey"), _show(_get(authority, "alg"))):
|
|
@@ -589,7 +588,7 @@ def _keys(value: Dict[str, Any], flag) -> None:
|
|
|
589
588
|
def _placements(value: Dict[str, Any], flag) -> None:
|
|
590
589
|
kids: List[Any] = []
|
|
591
590
|
for key, index in _indexed(_get(value, "publisherKeys")):
|
|
592
|
-
if
|
|
591
|
+
if _set_has(kids, _get(key, "kid")):
|
|
593
592
|
flag("/publisherKeys/%d/kid" % index, "publisher key %s is pinned twice" % _show(_get(key, "kid")))
|
|
594
593
|
kids.append(_get(key, "kid"))
|
|
595
594
|
for machine, m in _indexed(_get(value, "machines")):
|
|
@@ -601,7 +600,7 @@ def _placements(value: Dict[str, Any], flag) -> None:
|
|
|
601
600
|
flag("%s/agentRef" % at, "%s is placed twice on one machine in the context %s"
|
|
602
601
|
% (_show(_get(placement, "agentRef")), _show(_context_of(placement))))
|
|
603
602
|
agents.append(key)
|
|
604
|
-
if not
|
|
603
|
+
if not _set_has(kids, _get(placement, "publisherKid")):
|
|
605
604
|
flag("%s/publisherKid" % at, "publisher key %s is not in publisherKeys, so the machine pins no key to verify the package under" % _show(_get(placement, "publisherKid")))
|
|
606
605
|
|
|
607
606
|
|
|
@@ -611,10 +610,10 @@ def _partner_scopes(value: Dict[str, Any], flag) -> None:
|
|
|
611
610
|
pinned = [_get(k, "kid") for k in _list(_get(value, "publisherKeys"))]
|
|
612
611
|
scoped: List[Any] = []
|
|
613
612
|
for scope, index in _indexed(_get(value, "publisherScopes")):
|
|
614
|
-
if
|
|
613
|
+
if _set_has(scoped, _get(scope, "kid")):
|
|
615
614
|
flag("/publisherScopes/%d/kid" % index, "publisher key %s is scoped twice" % _show(_get(scope, "kid")))
|
|
616
615
|
scoped.append(_get(scope, "kid"))
|
|
617
|
-
if not
|
|
616
|
+
if not _set_has(pinned, _get(scope, "kid")):
|
|
618
617
|
flag("/publisherScopes/%d/kid" % index, "publisher key %s is not in publisherKeys, so the scope limits no key" % _show(_get(scope, "kid")))
|
|
619
618
|
for machine, m in _indexed(_get(value, "machines")):
|
|
620
619
|
for placement, p in _indexed(_get(machine, "packages")):
|
|
@@ -638,7 +637,7 @@ def _secret_references(value: Dict[str, Any], flag) -> None:
|
|
|
638
637
|
flag("%s/%s" % (at, field), "a secret placement names a slot, never a value: this looks like a credential")
|
|
639
638
|
if _key_of(_get(secret, "agentRef"), _context_of(secret)) not in placed:
|
|
640
639
|
flag("%s/agentRef" % at, "a secret goes only where a placed package declares it (v4 Path 2): this agent is not placed on this machine in the secret's context")
|
|
641
|
-
if not
|
|
640
|
+
if not _set_has(machine_ids, _get(secret, "from")):
|
|
642
641
|
flag("%s/from" % at, "the slot is filled from a machine of this estate")
|
|
643
642
|
elif not _same(_context_of(secret), PERSONAL_CONTEXT) and not _same(_get(secret, "from"), _get(machine, "id")):
|
|
644
643
|
# An envelope names no context (DEC-0082): an organization's instance fills its slot on its own machine.
|
|
@@ -693,7 +692,7 @@ def _machine_profiles(value: Dict[str, Any], flag) -> None:
|
|
|
693
692
|
flag("/machines/%d/secrets" % m, "a view machine holds none of the estate's secrets")
|
|
694
693
|
for machine, m in _indexed(_get(value, "machines")):
|
|
695
694
|
for secret, s in _indexed(_get(machine, "secrets")):
|
|
696
|
-
if _set_has(views, _get(secret, "from")):
|
|
695
|
+
if _set_has(views, _get(secret, "from")):
|
|
697
696
|
flag("/machines/%d/secrets/%d/from" % (m, s), "machine %s is a view machine: it is the source of no secret" % _show(_get(secret, "from")))
|
|
698
697
|
|
|
699
698
|
|
|
@@ -709,7 +708,7 @@ def _grants_and_revocations(value: Dict[str, Any], flag) -> None:
|
|
|
709
708
|
if _get(grant, "principalKind") != "external":
|
|
710
709
|
flag("/shareGrants/%d/principalKind" % index, "a share grant is to a principal outside the estate: principalKind external")
|
|
711
710
|
ident = _get(_get(grant, "meta"), "id") if isinstance(_get(grant, "meta"), dict) else _MISSING
|
|
712
|
-
if
|
|
711
|
+
if _set_has(grant_ids, _grant_key(ident)):
|
|
713
712
|
flag("/shareGrants/%d/meta/id" % index, "grant %s is listed twice" % _show(ident))
|
|
714
713
|
grant_ids.append(_grant_key(ident))
|
|
715
714
|
machines = _list(_get(value, "machines"))
|
|
@@ -735,7 +734,7 @@ def _grants_and_revocations(value: Dict[str, Any], flag) -> None:
|
|
|
735
734
|
if _get(revocation, "kind") == "device-key" and isinstance(raw_ref, str) and "@" in raw_ref and not KEY_REFERENCE.match(raw_ref):
|
|
736
735
|
flag("/revocations/%d/ref" % index, "a device-key revocation names a kid or a key reference <kid>@sha256:<64 lower-case hex digits> (DEC-0084)")
|
|
737
736
|
seen.append(key)
|
|
738
|
-
if
|
|
737
|
+
if _set_has(listed.get(kind, []), ref):
|
|
739
738
|
flag("/revocations/%d/ref" % index, "the record still lists the %s it revokes: revocation outranks addition" % kind)
|
|
740
739
|
|
|
741
740
|
|
|
@@ -906,7 +905,7 @@ def _installation(value: Dict[str, Any]) -> List[Dict[str, str]]:
|
|
|
906
905
|
declared = [_get(slot, "name") for slot in _list(_get(pkg, "secrets"))]
|
|
907
906
|
flag075 = _finding(findings, "FAC-SEM-075")
|
|
908
907
|
for secret, index in _indexed(_get(machine, "secrets")):
|
|
909
|
-
if _same(_get(secret, "agentRef"), _get(pkg, "agentRef")) and _same(_context_of(secret), context) and not
|
|
908
|
+
if _same(_get(secret, "agentRef"), _get(pkg, "agentRef")) and _same(_context_of(secret), context) and not _set_has(declared, _get(secret, "slot")):
|
|
910
909
|
flag075("/record/machines/%d/secrets/%d/slot" % (machine_index, index),
|
|
911
910
|
"the package declares no slot %s: a secret goes only where a placed package declares it" % _show(_get(secret, "slot")))
|
|
912
911
|
if placement is not None and not _scope_admits(record, _get(placement, "publisherKid"), context):
|
package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_jsvalue.py
CHANGED
|
@@ -158,7 +158,7 @@ def double(value: Any) -> float:
|
|
|
158
158
|
|
|
159
159
|
def same(a: Any, b: Any) -> bool:
|
|
160
160
|
"""JavaScript's === on parsed JSON: an object equals only itself. A Set's SameValueZero differs only for NaN, which
|
|
161
|
-
no JSON value is: use ``set_has`` where the contract keeps a Set (FAA-107)."""
|
|
161
|
+
no JSON value is: use ``set_has`` where the contract keeps a Set or tests with ``includes`` (FAA-107, FAA-113)."""
|
|
162
162
|
if a is MISSING or b is MISSING:
|
|
163
163
|
return a is b
|
|
164
164
|
if isinstance(a, (dict, list)) or isinstance(b, (dict, list)):
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fabric-service-kit",
|
|
3
|
-
"version": "0.49.
|
|
3
|
+
"version": "0.49.2",
|
|
4
4
|
"about": "The service kit's modules in dependency order: a module imports only modules listed before it. Written by fabric_kit.py build; edit the order and layers by hand, never the digests.",
|
|
5
5
|
"python": [
|
|
6
6
|
{
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
"file": "fabric_jsvalue.py",
|
|
9
9
|
"layer": "L0",
|
|
10
10
|
"imports": [],
|
|
11
|
-
"sha256": "
|
|
11
|
+
"sha256": "12888a2c934a885d35999ac9782eaedc8d04946d9775213344a235a8814d3d28"
|
|
12
12
|
},
|
|
13
13
|
{
|
|
14
14
|
"module": "fabric_time",
|
|
@@ -77,7 +77,7 @@
|
|
|
77
77
|
"fabric_secrets",
|
|
78
78
|
"fabric_time"
|
|
79
79
|
],
|
|
80
|
-
"sha256": "
|
|
80
|
+
"sha256": "a0ddc49d748c1efb1830de176998d6c8eac30f77d387c71eae12549c52aaab27"
|
|
81
81
|
},
|
|
82
82
|
{
|
|
83
83
|
"module": "fabric_delegation",
|
|
@@ -2951,6 +2951,158 @@
|
|
|
2951
2951
|
"fabric-openrouter.mjs": "ab6c4c7251d563980d895061ee19976bde2f364c21b6354efdd9a9027b1ea139",
|
|
2952
2952
|
"fabric-package.schema.json": "2ba799f576fad0f608029223c4ccccd122152f1c5dbfa8ce8b31cd63ac92ad44",
|
|
2953
2953
|
"share-registration.schema.json": "34b3997eeaf936ebc861342a23045634a7c18c19f01d7ed4198310d81989f5b0"
|
|
2954
|
+
},
|
|
2955
|
+
"0.49.1": {
|
|
2956
|
+
"fabric_jsvalue.py": "12888a2c934a885d35999ac9782eaedc8d04946d9775213344a235a8814d3d28",
|
|
2957
|
+
"fabric_time.py": "588f383da4ac6a243ea95b6ffc3a0aa99ca94245732dc4937734f190b7af4ae9",
|
|
2958
|
+
"fabric_identifiers.py": "0fd814d521ac3aa39907458265870753046a73f48af3d8581ab864b93b211607",
|
|
2959
|
+
"fabric_secrets.py": "68a0b5e9e90c468ec9ac67b2f0fd1848e08813d6ec1ec14a2a47337eb1a98911",
|
|
2960
|
+
"fabric_crypto.py": "9c34aee20dbe4d6742e4fdbaab68ceb934bbe7dbd3a904c0010824ace16cdeaa",
|
|
2961
|
+
"fabric_base.py": "f62bcc2ed9912660fa875d27a09f60867260cc4925f79873501fd9620be59611",
|
|
2962
|
+
"fabric_platform.py": "a9350dff55ef0fb3a23cdb4d0320a15868b15a8deb10d2eb74d72c58740c284b",
|
|
2963
|
+
"fabric_paths.py": "6c92af34292baddf7e10d3134d0a5b0bb23387741812a9f79c409cf1628bad23",
|
|
2964
|
+
"fabric_estate.py": "a0ddc49d748c1efb1830de176998d6c8eac30f77d387c71eae12549c52aaab27",
|
|
2965
|
+
"fabric_delegation.py": "6638a6039befe3b43f59018bab292e050931af21b544df1044cd5059572ded36",
|
|
2966
|
+
"fabric_share.py": "78506fe1a60829c525dbf6266a0aa0749a2164290ed94da8249a20b4e9be5605",
|
|
2967
|
+
"fabric_ceremonies.py": "a59e83cf4adb2669a9b98008e3d3a0cba991a35cbff97bc604fc82fe81cfd49f",
|
|
2968
|
+
"fabric_package_schema.py": "e623f0408d38e3343ed66222fb812907c6c52e1a286eb1c1176ab2e64640c9ad",
|
|
2969
|
+
"fabric_package.py": "ff533f1b3f92b4ea0f532fcec50b68c610d47549930eef8ad5247692a64dfb3c",
|
|
2970
|
+
"fabric_protocols.py": "28e693282cddff8e4396ae39ce6fa935e875e8ddac7375bea2c189dd6fb04970",
|
|
2971
|
+
"fabric_connections.py": "77d3ccf863c70e9209d21ef45c46a6db9c06237019bc20d54f8d3946873f3f11",
|
|
2972
|
+
"fabric_lock.py": "ba2399d2137c7a7791b7133b9db9cca36693f4eb7e30955b25a75ade814e95ba",
|
|
2973
|
+
"fabric_usage.py": "b1f335cab4625171a616cf68cf3fd892b18bdadcf4baec3a3a0fdcf12785c170",
|
|
2974
|
+
"fabric_backups.py": "02dc5eb66ec956723d3ddba07b6dd15f6a9726d901f4d60edfd02eee57880ceb",
|
|
2975
|
+
"fabric_descriptor.py": "daf16f95b1810283b1386488e006e940a0cdfa5c3c8d09386ac33d29d58df78d",
|
|
2976
|
+
"fabric_auth.py": "55794587750f6c9f40935b74295d83d7096cb4b26a0b36ac292334cd87d8f853",
|
|
2977
|
+
"fabric_events.py": "0086886c2c29dbd5c9d152be9d375c5bdf4a29f89b8095baff8490c2bcd64e47",
|
|
2978
|
+
"fabric_logs.py": "86dc55bfafa2a57264722e2403510a249b95de0e4a722b2e4bc3948e3bd93da9",
|
|
2979
|
+
"fabric_supervisors.py": "a2dbf15aa1c4eb9de42996b413103fa4814afd2e4e66d1ab7315f30e06ab6841",
|
|
2980
|
+
"fabric_service.py": "103ab4026f96e127c01cd91e4ad44f6b0ce2424ff33f078ed106b39e773a10e3",
|
|
2981
|
+
"fabric_profiles.py": "26e21ec29c016000f8ca8053b7b489184854a73be1b7fdc0a18d12990203db9b",
|
|
2982
|
+
"fabric_interop_rules.py": "b5f0ecb1791b4c50c5ac151f987f692ed7001bc74841a8a161125ec775145e09",
|
|
2983
|
+
"fabric_interop.py": "f92fa111328fe3811438f733d8f0eb5295e6941c774123a78e26318bdcb35fc3",
|
|
2984
|
+
"fabric_hub.py": "b9ac852e601b1d54cf61351677a628afc69faeed7d1fc74ebe541c1cf38e0c2a",
|
|
2985
|
+
"fabric_board_shapes.py": "0a0e8d3d40e33dfd8c457aedb85330b2ff25f8c49a33eb6cbd5a5cc8a5007f7e",
|
|
2986
|
+
"fabric_board_link.py": "b5bff994cb615c6a4bb0d88d020e3a59504166180e1fa1aea3be93224f2aeccb",
|
|
2987
|
+
"fabric_board_session.py": "2845d7d758b06ac4588bdf825a471c201a46ce535a631805697b1e35495fead6",
|
|
2988
|
+
"fabric_board_fixture.py": "69761ce205ec640762ec9b591c6903e5a87f844e8d423b041681924027e39d1e",
|
|
2989
|
+
"fabric_board.py": "0f075894b3e352194fcaf3fc7d08dee4e9f1c215e859769ed85fa5010e4a1599",
|
|
2990
|
+
"fabric_http.py": "5d7f72af3a73fdbe8c1f487ecf60cef23a7c46289eba542b03aff4706b8218d4",
|
|
2991
|
+
"fabric_openrouter.py": "309f588f9c976b1061323f3161e35d86248afd5b59b16391afbfc4e1099ecd65",
|
|
2992
|
+
"fabric-jsvalue.mjs": "dfbdb8c41584972c9389750a41719374a1cfc5652ed438dd1623025190b0106e",
|
|
2993
|
+
"fabric-time.mjs": "3ff932069038a720df1c68c6492976906737b2e67e5c12d9c81c418597f661de",
|
|
2994
|
+
"fabric-identifiers.mjs": "a18c2a501a4aa170bfd3d99e571ad6b7662649b4d3b9d2a540c002ea42811bbf",
|
|
2995
|
+
"fabric-secrets.mjs": "6ad8ab18ac899ecc2384e8ec6a3fb689b92be3b9a5ce3a59b92a37d52da5d766",
|
|
2996
|
+
"fabric-crypto.mjs": "038e03689701e3c9721a1e7f8e0a4d02a52d6a5d1661b0dc84035edc3ebbfcf6",
|
|
2997
|
+
"fabric-base.mjs": "7804b2df7715dbbf9702a9b61b6b8cef2110f9a52b04cabd8fb0a66458d87512",
|
|
2998
|
+
"fabric-platform.mjs": "a8119d95ebba4d589a9e401f5d6fc8dda62d59d44e4c1ff811d97fac3771ac0c",
|
|
2999
|
+
"fabric-paths.mjs": "2201b4ed7126f260931b63e8386377b4317d8dcad419d109bf22c683e44b7f29",
|
|
3000
|
+
"fabric-estate.mjs": "b6610aaad9d00d8a7f42955627fb81725950841455bcedfc050abb0e079f0f93",
|
|
3001
|
+
"fabric-delegation.mjs": "dafde9ea327c88d92dc73d1400282b43dc6f84dd345a2d2b9b154304f65fc9d7",
|
|
3002
|
+
"fabric-share.mjs": "d40a7405d7bd4c3213ed691330b7549afe8e023db0753b582e249714e672010d",
|
|
3003
|
+
"fabric-ceremonies.mjs": "117d4374c9e95c930a38de7adbd4323774798f4fe6ec6f24afcd6f2c7298ca44",
|
|
3004
|
+
"fabric-package-schema.mjs": "cd28092375db0fc21ffab1f0bb7794f7f8979ee08c64d3b9faf4b3845357caa6",
|
|
3005
|
+
"fabric-package.mjs": "13913ea6d12056c3a31b8222b6c4aab8395941fe519913692e1a06d8672e1c88",
|
|
3006
|
+
"fabric-protocols.mjs": "dc039ec3612d0090c9ba6a3a949b0b7df54712bead300dcb6cc8b9bc305cd183",
|
|
3007
|
+
"fabric-connections.mjs": "303432e547ce563e90ca9ffcd827f5612f51d3582929834e1add0fdaf6485dcc",
|
|
3008
|
+
"fabric-lock.mjs": "ac219ab0a326d5c43c7c4c255e0c3843d4794de795a60e3af661e7d5350ea052",
|
|
3009
|
+
"fabric-usage.mjs": "1c4d18004639409624ac3516a02f2b60bbf55abdb612e9a96c37e83666eb87a7",
|
|
3010
|
+
"fabric-backups.mjs": "849acdc6eba0fff648c8158e61f6b68cccd7bedf0880f7d5ec03a6a20f1e7005",
|
|
3011
|
+
"fabric-descriptor.mjs": "95c0b7ff36c29d7c748f1fa6fb1767d6fe8c97fca7f1ee404559930abbd3cc84",
|
|
3012
|
+
"fabric-auth.mjs": "3ea6796470fcd829bc72a772fb7e4c37532a09d1e37ff41592dcf1a1a3074ca2",
|
|
3013
|
+
"fabric-events.mjs": "c463d6ffcae24229a5c608d8fcea4268d2ccc5024b19fa10e5a452284068fa71",
|
|
3014
|
+
"fabric-logs.mjs": "58467e5719c16e099d05bbedec47a95712506ab03c33f3cd4be1252e8498a946",
|
|
3015
|
+
"fabric-supervisors.mjs": "9d61c1a17538a5e2453e33e5ae347337336748041bc054478a96dd51f3d4fc51",
|
|
3016
|
+
"fabric-service.mjs": "1b4639a10c530c1241d317c5e9cf3a10cd96e5d9af8b29fc1b1844de5c63bfec",
|
|
3017
|
+
"fabric-profiles.mjs": "314376cf2deb87f235fb18b11d3b532e211f585b9af0a9302b5f4cc39971b532",
|
|
3018
|
+
"fabric-interop-rules.mjs": "57a8081307956e8c381119b361fa5232a7bf791815be8e3541eb5492820e2ea5",
|
|
3019
|
+
"fabric-interop.mjs": "581983ec3e197e5c2340ad25e8468320c69a2459c90097c7fcf2699766b4fb26",
|
|
3020
|
+
"fabric-hub.mjs": "c005115a864cfd67daa4862097bb14acfe5a60bf653897e5bf8a570dd80f1070",
|
|
3021
|
+
"fabric-board-shapes.mjs": "c1db7b7bd0d58d82bb6d8dfbc3cd1547a256a333052d367e82ff1b3edf2804d7",
|
|
3022
|
+
"fabric-board-link.mjs": "4cd6d4e21713a38c8e56f7d59db3148638b8c27c08e774d96a0f6283c6049e0a",
|
|
3023
|
+
"fabric-board-session.mjs": "26c9b0b2818a4cedc5248b08ea6732e2ee4ee81e31f6fee2b572a019db813c93",
|
|
3024
|
+
"fabric-board-fixture.mjs": "83c4b7e33ee47b68385faf2569d38d5c8a0c5cb0f8656090f41e1b0eed2f436e",
|
|
3025
|
+
"fabric-board.mjs": "9e7bfe4d412521982224ef12bebfc2ff255eeeaf8d96cf40234ac18de68e7a59",
|
|
3026
|
+
"fabric-http.mjs": "f886bcb49c4353d039387ac9568738dda26697a94dd07fc6a6204500f0bc27bf",
|
|
3027
|
+
"fabric-openrouter.mjs": "ab6c4c7251d563980d895061ee19976bde2f364c21b6354efdd9a9027b1ea139",
|
|
3028
|
+
"fabric-package.schema.json": "2ba799f576fad0f608029223c4ccccd122152f1c5dbfa8ce8b31cd63ac92ad44",
|
|
3029
|
+
"share-registration.schema.json": "34b3997eeaf936ebc861342a23045634a7c18c19f01d7ed4198310d81989f5b0"
|
|
3030
|
+
},
|
|
3031
|
+
"0.49.2": {
|
|
3032
|
+
"fabric_jsvalue.py": "12888a2c934a885d35999ac9782eaedc8d04946d9775213344a235a8814d3d28",
|
|
3033
|
+
"fabric_time.py": "588f383da4ac6a243ea95b6ffc3a0aa99ca94245732dc4937734f190b7af4ae9",
|
|
3034
|
+
"fabric_identifiers.py": "0fd814d521ac3aa39907458265870753046a73f48af3d8581ab864b93b211607",
|
|
3035
|
+
"fabric_secrets.py": "68a0b5e9e90c468ec9ac67b2f0fd1848e08813d6ec1ec14a2a47337eb1a98911",
|
|
3036
|
+
"fabric_crypto.py": "9c34aee20dbe4d6742e4fdbaab68ceb934bbe7dbd3a904c0010824ace16cdeaa",
|
|
3037
|
+
"fabric_base.py": "f62bcc2ed9912660fa875d27a09f60867260cc4925f79873501fd9620be59611",
|
|
3038
|
+
"fabric_platform.py": "a9350dff55ef0fb3a23cdb4d0320a15868b15a8deb10d2eb74d72c58740c284b",
|
|
3039
|
+
"fabric_paths.py": "6c92af34292baddf7e10d3134d0a5b0bb23387741812a9f79c409cf1628bad23",
|
|
3040
|
+
"fabric_estate.py": "a0ddc49d748c1efb1830de176998d6c8eac30f77d387c71eae12549c52aaab27",
|
|
3041
|
+
"fabric_delegation.py": "6638a6039befe3b43f59018bab292e050931af21b544df1044cd5059572ded36",
|
|
3042
|
+
"fabric_share.py": "78506fe1a60829c525dbf6266a0aa0749a2164290ed94da8249a20b4e9be5605",
|
|
3043
|
+
"fabric_ceremonies.py": "a59e83cf4adb2669a9b98008e3d3a0cba991a35cbff97bc604fc82fe81cfd49f",
|
|
3044
|
+
"fabric_package_schema.py": "e623f0408d38e3343ed66222fb812907c6c52e1a286eb1c1176ab2e64640c9ad",
|
|
3045
|
+
"fabric_package.py": "ff533f1b3f92b4ea0f532fcec50b68c610d47549930eef8ad5247692a64dfb3c",
|
|
3046
|
+
"fabric_protocols.py": "28e693282cddff8e4396ae39ce6fa935e875e8ddac7375bea2c189dd6fb04970",
|
|
3047
|
+
"fabric_connections.py": "77d3ccf863c70e9209d21ef45c46a6db9c06237019bc20d54f8d3946873f3f11",
|
|
3048
|
+
"fabric_lock.py": "ba2399d2137c7a7791b7133b9db9cca36693f4eb7e30955b25a75ade814e95ba",
|
|
3049
|
+
"fabric_usage.py": "b1f335cab4625171a616cf68cf3fd892b18bdadcf4baec3a3a0fdcf12785c170",
|
|
3050
|
+
"fabric_backups.py": "02dc5eb66ec956723d3ddba07b6dd15f6a9726d901f4d60edfd02eee57880ceb",
|
|
3051
|
+
"fabric_descriptor.py": "daf16f95b1810283b1386488e006e940a0cdfa5c3c8d09386ac33d29d58df78d",
|
|
3052
|
+
"fabric_auth.py": "55794587750f6c9f40935b74295d83d7096cb4b26a0b36ac292334cd87d8f853",
|
|
3053
|
+
"fabric_events.py": "0086886c2c29dbd5c9d152be9d375c5bdf4a29f89b8095baff8490c2bcd64e47",
|
|
3054
|
+
"fabric_logs.py": "86dc55bfafa2a57264722e2403510a249b95de0e4a722b2e4bc3948e3bd93da9",
|
|
3055
|
+
"fabric_supervisors.py": "a2dbf15aa1c4eb9de42996b413103fa4814afd2e4e66d1ab7315f30e06ab6841",
|
|
3056
|
+
"fabric_service.py": "103ab4026f96e127c01cd91e4ad44f6b0ce2424ff33f078ed106b39e773a10e3",
|
|
3057
|
+
"fabric_profiles.py": "26e21ec29c016000f8ca8053b7b489184854a73be1b7fdc0a18d12990203db9b",
|
|
3058
|
+
"fabric_interop_rules.py": "b5f0ecb1791b4c50c5ac151f987f692ed7001bc74841a8a161125ec775145e09",
|
|
3059
|
+
"fabric_interop.py": "f92fa111328fe3811438f733d8f0eb5295e6941c774123a78e26318bdcb35fc3",
|
|
3060
|
+
"fabric_hub.py": "b9ac852e601b1d54cf61351677a628afc69faeed7d1fc74ebe541c1cf38e0c2a",
|
|
3061
|
+
"fabric_board_shapes.py": "0a0e8d3d40e33dfd8c457aedb85330b2ff25f8c49a33eb6cbd5a5cc8a5007f7e",
|
|
3062
|
+
"fabric_board_link.py": "b5bff994cb615c6a4bb0d88d020e3a59504166180e1fa1aea3be93224f2aeccb",
|
|
3063
|
+
"fabric_board_session.py": "2845d7d758b06ac4588bdf825a471c201a46ce535a631805697b1e35495fead6",
|
|
3064
|
+
"fabric_board_fixture.py": "69761ce205ec640762ec9b591c6903e5a87f844e8d423b041681924027e39d1e",
|
|
3065
|
+
"fabric_board.py": "0f075894b3e352194fcaf3fc7d08dee4e9f1c215e859769ed85fa5010e4a1599",
|
|
3066
|
+
"fabric_http.py": "5d7f72af3a73fdbe8c1f487ecf60cef23a7c46289eba542b03aff4706b8218d4",
|
|
3067
|
+
"fabric_openrouter.py": "309f588f9c976b1061323f3161e35d86248afd5b59b16391afbfc4e1099ecd65",
|
|
3068
|
+
"fabric-jsvalue.mjs": "dfbdb8c41584972c9389750a41719374a1cfc5652ed438dd1623025190b0106e",
|
|
3069
|
+
"fabric-time.mjs": "3ff932069038a720df1c68c6492976906737b2e67e5c12d9c81c418597f661de",
|
|
3070
|
+
"fabric-identifiers.mjs": "a18c2a501a4aa170bfd3d99e571ad6b7662649b4d3b9d2a540c002ea42811bbf",
|
|
3071
|
+
"fabric-secrets.mjs": "6ad8ab18ac899ecc2384e8ec6a3fb689b92be3b9a5ce3a59b92a37d52da5d766",
|
|
3072
|
+
"fabric-crypto.mjs": "038e03689701e3c9721a1e7f8e0a4d02a52d6a5d1661b0dc84035edc3ebbfcf6",
|
|
3073
|
+
"fabric-base.mjs": "7804b2df7715dbbf9702a9b61b6b8cef2110f9a52b04cabd8fb0a66458d87512",
|
|
3074
|
+
"fabric-platform.mjs": "a8119d95ebba4d589a9e401f5d6fc8dda62d59d44e4c1ff811d97fac3771ac0c",
|
|
3075
|
+
"fabric-paths.mjs": "2201b4ed7126f260931b63e8386377b4317d8dcad419d109bf22c683e44b7f29",
|
|
3076
|
+
"fabric-estate.mjs": "b6610aaad9d00d8a7f42955627fb81725950841455bcedfc050abb0e079f0f93",
|
|
3077
|
+
"fabric-delegation.mjs": "dafde9ea327c88d92dc73d1400282b43dc6f84dd345a2d2b9b154304f65fc9d7",
|
|
3078
|
+
"fabric-share.mjs": "d40a7405d7bd4c3213ed691330b7549afe8e023db0753b582e249714e672010d",
|
|
3079
|
+
"fabric-ceremonies.mjs": "117d4374c9e95c930a38de7adbd4323774798f4fe6ec6f24afcd6f2c7298ca44",
|
|
3080
|
+
"fabric-package-schema.mjs": "cd28092375db0fc21ffab1f0bb7794f7f8979ee08c64d3b9faf4b3845357caa6",
|
|
3081
|
+
"fabric-package.mjs": "13913ea6d12056c3a31b8222b6c4aab8395941fe519913692e1a06d8672e1c88",
|
|
3082
|
+
"fabric-protocols.mjs": "dc039ec3612d0090c9ba6a3a949b0b7df54712bead300dcb6cc8b9bc305cd183",
|
|
3083
|
+
"fabric-connections.mjs": "303432e547ce563e90ca9ffcd827f5612f51d3582929834e1add0fdaf6485dcc",
|
|
3084
|
+
"fabric-lock.mjs": "ac219ab0a326d5c43c7c4c255e0c3843d4794de795a60e3af661e7d5350ea052",
|
|
3085
|
+
"fabric-usage.mjs": "1c4d18004639409624ac3516a02f2b60bbf55abdb612e9a96c37e83666eb87a7",
|
|
3086
|
+
"fabric-backups.mjs": "849acdc6eba0fff648c8158e61f6b68cccd7bedf0880f7d5ec03a6a20f1e7005",
|
|
3087
|
+
"fabric-descriptor.mjs": "95c0b7ff36c29d7c748f1fa6fb1767d6fe8c97fca7f1ee404559930abbd3cc84",
|
|
3088
|
+
"fabric-auth.mjs": "3ea6796470fcd829bc72a772fb7e4c37532a09d1e37ff41592dcf1a1a3074ca2",
|
|
3089
|
+
"fabric-events.mjs": "c463d6ffcae24229a5c608d8fcea4268d2ccc5024b19fa10e5a452284068fa71",
|
|
3090
|
+
"fabric-logs.mjs": "58467e5719c16e099d05bbedec47a95712506ab03c33f3cd4be1252e8498a946",
|
|
3091
|
+
"fabric-supervisors.mjs": "9d61c1a17538a5e2453e33e5ae347337336748041bc054478a96dd51f3d4fc51",
|
|
3092
|
+
"fabric-service.mjs": "1b4639a10c530c1241d317c5e9cf3a10cd96e5d9af8b29fc1b1844de5c63bfec",
|
|
3093
|
+
"fabric-profiles.mjs": "314376cf2deb87f235fb18b11d3b532e211f585b9af0a9302b5f4cc39971b532",
|
|
3094
|
+
"fabric-interop-rules.mjs": "57a8081307956e8c381119b361fa5232a7bf791815be8e3541eb5492820e2ea5",
|
|
3095
|
+
"fabric-interop.mjs": "581983ec3e197e5c2340ad25e8468320c69a2459c90097c7fcf2699766b4fb26",
|
|
3096
|
+
"fabric-hub.mjs": "c005115a864cfd67daa4862097bb14acfe5a60bf653897e5bf8a570dd80f1070",
|
|
3097
|
+
"fabric-board-shapes.mjs": "c1db7b7bd0d58d82bb6d8dfbc3cd1547a256a333052d367e82ff1b3edf2804d7",
|
|
3098
|
+
"fabric-board-link.mjs": "4cd6d4e21713a38c8e56f7d59db3148638b8c27c08e774d96a0f6283c6049e0a",
|
|
3099
|
+
"fabric-board-session.mjs": "26c9b0b2818a4cedc5248b08ea6732e2ee4ee81e31f6fee2b572a019db813c93",
|
|
3100
|
+
"fabric-board-fixture.mjs": "83c4b7e33ee47b68385faf2569d38d5c8a0c5cb0f8656090f41e1b0eed2f436e",
|
|
3101
|
+
"fabric-board.mjs": "9e7bfe4d412521982224ef12bebfc2ff255eeeaf8d96cf40234ac18de68e7a59",
|
|
3102
|
+
"fabric-http.mjs": "f886bcb49c4353d039387ac9568738dda26697a94dd07fc6a6204500f0bc27bf",
|
|
3103
|
+
"fabric-openrouter.mjs": "ab6c4c7251d563980d895061ee19976bde2f364c21b6354efdd9a9027b1ea139",
|
|
3104
|
+
"fabric-package.schema.json": "2ba799f576fad0f608029223c4ccccd122152f1c5dbfa8ce8b31cd63ac92ad44",
|
|
3105
|
+
"share-registration.schema.json": "34b3997eeaf936ebc861342a23045634a7c18c19f01d7ed4198310d81989f5b0"
|
|
2954
3106
|
}
|
|
2955
3107
|
},
|
|
2956
3108
|
"data": {
|
|
@@ -5,7 +5,7 @@ license: AGPL-3.0-only OR LicenseRef-PassionCode-Commercial
|
|
|
5
5
|
compatibility: Requires filesystem access and Python 3.9+. Exact schema checks additionally need git, Node.js, pnpm, and the pinned fabric-agent-contract checkout (a public repository). Works without those tools in an explicitly degraded structural-check mode. Ships in one plugin with adapting-projects-to-fabric, whose scripts it reuses.
|
|
6
6
|
metadata:
|
|
7
7
|
author: PassionCode.ai
|
|
8
|
-
version: "0.49.
|
|
8
|
+
version: "0.49.2"
|
|
9
9
|
contract-version: "0.1.0"
|
|
10
10
|
contract-commit: "2f020a696453ae299b123517f14957f6a1354379"
|
|
11
11
|
---
|