@passioncode-ai/fabric-agent-adapter 0.83.1 → 0.85.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/CHANGELOG.md +78 -0
- package/README.md +2 -1
- 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/adapting-projects-to-fabric/scripts/check_dashboard_link.py +3 -0
- package/plugins/fabric-agent-adapter/skills/adapting-projects-to-fabric/scripts/fabric_identifiers.py +1 -0
- package/plugins/fabric-agent-adapter/skills/adapting-projects-to-fabric/scripts/fabric_secrets.py +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/SKILL.md +2 -2
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/assets/dashboard-kit/fabric-button.js +3 -2
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/assets/dashboard-kit/fabric-dashboard.css +2 -1
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/assets/dashboard-kit/fabric-dashboard.js +3 -2
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/assets/dashboard-kit/kit.json +9 -4
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/references/board.md +8 -3
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/references/dashboard-kit.md +1 -1
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/references/kit-modules.md +9 -1
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/references/lifecycle.md +3 -2
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/check_dashboard_link.py +3 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-a2a-server.mjs +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-a2a.mjs +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-actions.mjs +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-auth.mjs +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-backups.mjs +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-base.mjs +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-board-fixture.mjs +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-board-link.mjs +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-board-session.mjs +2 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-board-shapes.mjs +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-board-slots.mjs +9 -1
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-board.mjs +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-ceremonies.mjs +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-connections.mjs +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-context.mjs +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-crypto.mjs +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-delegation.mjs +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-descriptor.mjs +2 -1
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-estate-rules.mjs +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-estate.mjs +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-events.mjs +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-holds.mjs +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-http.mjs +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-hub.mjs +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-identifiers.mjs +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-interop-rules.mjs +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-interop.mjs +6 -2
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-jsvalue.mjs +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-load.mjs +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-lock.mjs +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-logs.mjs +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-mandate.mjs +4 -2
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-openrouter.mjs +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-ops-digest.mjs +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-package-schema.mjs +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-package.mjs +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-page-links.mjs +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-paths.mjs +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-peer-owner.mjs +2 -1
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-platform.mjs +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-profiles.mjs +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-protocols.mjs +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-secrets.mjs +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-service.mjs +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-share.mjs +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-socket-proof.mjs +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-supervisors.mjs +15 -3
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-tailnet-identity.mjs +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-tailnet.mjs +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-time.mjs +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-usage.mjs +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_a2a.py +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_a2a_server.py +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_actions.py +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_auth.py +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_backups.py +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_base.py +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_board.py +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_board_fixture.py +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_board_link.py +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_board_session.py +2 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_board_shapes.py +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_board_slots.py +10 -1
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_ceremonies.py +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_connections.py +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_context.py +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_crypto.py +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_delegation.py +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_descriptor.py +2 -1
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_estate.py +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_estate_rules.py +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_events.py +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_holds.py +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_http.py +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_hub.py +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_identifiers.py +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_interop.py +2 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_interop_rules.py +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_jsvalue.py +3 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_load.py +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_lock.py +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_logs.py +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_mandate.py +20 -3
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_openrouter.py +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_ops_digest.py +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_package.py +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_package_schema.py +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_page_links.py +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_paths.py +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_peer_owner.py +47 -47
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_platform.py +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_profiles.py +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_protocols.py +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_secrets.py +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_service.py +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_share.py +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_socket_proof.py +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_supervisors.py +16 -8
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_tailnet.py +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_tailnet_identity.py +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_time.py +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_usage.py +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/kit.json +428 -105
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/sample_service.py +2 -1
- package/plugins/fabric-agent-adapter/skills/creating-fabric-agents/SKILL.md +3 -3
- package/plugins/fabric-agent-adapter/skills/creating-fabric-agents/references/where-agents-run.md +2 -2
- package/plugins/fabric-agent-adapter/skills/creating-fabric-agents/scripts/admit.py +33 -13
- package/plugins/fabric-agent-adapter/skills/creating-fabric-agents/scripts/check_dashboard_link.py +3 -0
- package/plugins/fabric-agent-adapter/skills/observing-products/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/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_peer_owner.py
CHANGED
|
@@ -1,26 +1,25 @@
|
|
|
1
|
+
# SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-PassionCode-Commercial
|
|
1
2
|
"""peer_owner: which OS account owns each end of a loopback TCP connection.
|
|
2
3
|
|
|
3
|
-
peer_owner 1.3.1+kit.
|
|
4
|
+
peer_owner 1.3.1+kit.8: Observatory's peer_owner (passioncode-ai/project-observatory-dashboard,
|
|
4
5
|
`observatory/engine/peer_owner.py`, vendored at f86f0622, read against 2180235c for 1.2.0 and a69c6fee for 1.3.1),
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
reach every service any account listens with on 127.0.0.1, and a loopback socket proves nothing about who is on the
|
|
23
|
-
other end. This module answers that question from the host's socket table, read without privileges:
|
|
6
|
+
kit layer L0 (DEC-0154 HA-2, FAA-226, FAA-258). 1.3.1's proof from this account's own sockets (DEC-0155 RT-2) is the
|
|
7
|
+
kit's `fabric_socket_proof`, asked when it sits beside this file (FAA-292, FAA-327); else this file
|
|
8
|
+
stands alone. Kit differences: NamedTuples (a service may load a kit file by path); the Python 3.9 floor; `classify`
|
|
9
|
+
/ `classify_sid` ask for this process's uid or SID first (a client running as root owns root's listener); on Linux
|
|
10
|
+
`server_end` reads an accepted connection's own row and, for one not accept()ed yet (uid 0, inode 0), the listener
|
|
11
|
+
on its local address (CT-254), several rows of one owner are that owner, a row printed twice counts once, and a
|
|
12
|
+
`/proc` question that finds no row or several reads once more. On macOS (FAA-267, FAA-273): the sysctl calibration
|
|
13
|
+
also requires a child's listener, read under one deadline with `selectors`; a number is ASCII digits only; a caller
|
|
14
|
+
may vouch for a listener with a pid it started (`pid_listens`, `CheckedHTTPConnection(vouch_pid=...)`, RT-3, after
|
|
15
|
+
RT-2). DEC-0155 (FAA-312): a netstat that fails or is empty, a table with no row of another uid (sysctl) or process
|
|
16
|
+
(netstat) and a missing connection row read as `table-restricted` (RT-1); a restricted table's listener is this
|
|
17
|
+
account's only on exactly 127.0.0.1 (RT-4); no proof is taken from a set-uid reader. `main` is the CLI, `listener
|
|
18
|
+
<port>` (FAA-315). /proc carries a socket's creator, so a listener root created and handed to another account
|
|
19
|
+
(socket activation) reads as root's. Tests: `test/test_fabric_peer_owner.py`; Node twin: `fabric-peer-owner.mjs`.
|
|
20
|
+
|
|
21
|
+
WHY. Loopback is one per machine, not per OS account: every account's processes reach every 127.0.0.1 service, and a
|
|
22
|
+
loopback socket proves nothing about the other end. This module reads the host's socket table, without privileges:
|
|
24
23
|
|
|
25
24
|
listener(port) -> Owner who listens on 127.0.0.1:<port> (also 0.0.0.0, ::1, ::)
|
|
26
25
|
server_end(sock) -> Owner for a client's connected socket: who accepted it
|
|
@@ -65,13 +64,13 @@ answer; two live rows with the same addresses are `unknown` (`several-rows`), ne
|
|
|
65
64
|
cannot be opened (another account's, usually) is `unknown`, never `another-account`. `Owner.uid` is None there.
|
|
66
65
|
- Anything else: `unknown`, reason `unsupported-platform`.
|
|
67
66
|
|
|
68
|
-
`LOCAL_PEERCRED`, `getpeereid` and `SO_PEERCRED`
|
|
69
|
-
|
|
70
|
-
privilege, and reports the process names `netstat` prints only as far as the pid behind them.
|
|
67
|
+
`LOCAL_PEERCRED`, `getpeereid` and `SO_PEERCRED` cover Unix-domain sockets only, hence a socket table. It never reads
|
|
68
|
+
from the asked socket, resolves a name, sends anything or needs a privilege; of `netstat`'s names, only the pid.
|
|
71
69
|
"""
|
|
72
70
|
from __future__ import annotations
|
|
73
71
|
|
|
74
72
|
import http.client
|
|
73
|
+
import importlib.util
|
|
75
74
|
import ipaddress
|
|
76
75
|
import json
|
|
77
76
|
import os
|
|
@@ -83,8 +82,7 @@ import threading
|
|
|
83
82
|
import time
|
|
84
83
|
from typing import NamedTuple, Optional, Tuple
|
|
85
84
|
|
|
86
|
-
#
|
|
87
|
-
PEER_OWNER_VERSION = "1.3.1+kit.7" # Observatory's 1.3.1 line with the kit's differences above
|
|
85
|
+
PEER_OWNER_VERSION = "1.3.1+kit.8" # this file's own, for projects that copy it: 1.3.1 with the kit's differences above
|
|
88
86
|
|
|
89
87
|
THIS_ACCOUNT = "this-account"
|
|
90
88
|
ANOTHER_ACCOUNT = "another-account"
|
|
@@ -93,8 +91,7 @@ UNKNOWN = "unknown"
|
|
|
93
91
|
NONE = "none"
|
|
94
92
|
KINDS = (THIS_ACCOUNT, ANOTHER_ACCOUNT, SYSTEM, UNKNOWN, NONE)
|
|
95
93
|
|
|
96
|
-
#: The most table bytes one read accepts:
|
|
97
|
-
#: developer machine passes; 4 MiB holds about 6,800 at 616 bytes measured on macOS 26 (FAA-260).
|
|
94
|
+
#: The most table bytes one read accepts: about 6,800 sockets at 616 bytes each, measured on macOS 26 (FAA-260).
|
|
98
95
|
MAX_TABLE_BYTES = 4 * 1024 * 1024
|
|
99
96
|
#: Every subprocess this module starts is stopped after this many seconds.
|
|
100
97
|
TIMEOUT_SECONDS = 2.0
|
|
@@ -105,8 +102,7 @@ NETSTAT = "/usr/sbin/netstat"
|
|
|
105
102
|
PS = "/bin/ps"
|
|
106
103
|
LSOF = "/usr/sbin/lsof"
|
|
107
104
|
|
|
108
|
-
#:
|
|
109
|
-
#: interpreter, such as a Homebrew Python, only its own sockets through sysctl and nothing through netstat).
|
|
105
|
+
#: Why a table hides other processes' sockets (FAA-267: macOS 27.2 shows an ad-hoc-signed Python only its own).
|
|
110
106
|
TABLE_RESTRICTED = "table-restricted"
|
|
111
107
|
#: A macOS table that lists sockets but not the reader's own connection (DEC-0155 RT-1, FAA-312).
|
|
112
108
|
NO_ROW_RESTRICTED = TABLE_RESTRICTED + ": no row for this connection"
|
|
@@ -117,8 +113,7 @@ SERVER_UNVERIFIED = "server-unverified"
|
|
|
117
113
|
SERVER_NOT_THIS_WORKSPACE = "server-not-this-workspace"
|
|
118
114
|
|
|
119
115
|
|
|
120
|
-
#
|
|
121
|
-
# namespace without builtins, where `int | None` as a string is unresolvable (and a TypeError on Python 3.9).
|
|
116
|
+
# Real types, not postponed strings: a NamedTuple's __new__ cannot resolve `int | None` as a string (3.9: TypeError).
|
|
122
117
|
_OwnerFields = NamedTuple("_OwnerFields", [("kind", str), ("uid", Optional[int]), ("pid", Optional[int]),
|
|
123
118
|
("method", str), ("reason", Optional[str])])
|
|
124
119
|
_OwnerFields.__new__.__defaults__ = (None, None, "none", None)
|
|
@@ -229,8 +224,7 @@ def parse_netstat(text: str) -> list[Row]:
|
|
|
229
224
|
leading = at - sum(1 for w in names[:at] if w == "Address")
|
|
230
225
|
trailing = len(names) - at - 1
|
|
231
226
|
if not any(line.split()[:1] and line.split()[0].startswith("tcp") for line in lines[header + 1:]):
|
|
232
|
-
#
|
|
233
|
-
# (FAA-273 item 3), not `no-row`.
|
|
227
|
+
# A header and no tcp row is the restricted table, not `no-row`: the caller's own row is in any table (FAA-273)
|
|
234
228
|
raise TableUnreadable(f"{TABLE_RESTRICTED}: netstat printed only its header to this process")
|
|
235
229
|
rows: list[Row] = []
|
|
236
230
|
for line in lines[header + 1:]:
|
|
@@ -532,8 +526,7 @@ def _child_listener_seen(rows_of) -> Optional[bool]:
|
|
|
532
526
|
except (TableUnreadable, OSError, struct.error, ValueError):
|
|
533
527
|
return False
|
|
534
528
|
finally:
|
|
535
|
-
# One deadline
|
|
536
|
-
# left of the deadline to exit on its closed stdin before it is killed.
|
|
529
|
+
# One deadline: a child that gave no port is killed at once; one that did has the rest to exit on a closed stdin
|
|
537
530
|
try:
|
|
538
531
|
child.stdin.close()
|
|
539
532
|
if port is None:
|
|
@@ -790,9 +783,8 @@ def _owner_of(local: tuple[str, int], remote: tuple[str, int], server: bool = Fa
|
|
|
790
783
|
if len(found) > 1:
|
|
791
784
|
return Owner(UNKNOWN, None, None, how, "several-rows")
|
|
792
785
|
if how == "proc" and server and found[0].uid is None:
|
|
793
|
-
# Linux:
|
|
794
|
-
#
|
|
795
|
-
# listener swapped after another account accepted cannot pass (CT-254). An orphaned server row reads so too.
|
|
786
|
+
# Linux: an unaccepted connection (uid 0, inode 0) or an orphaned server row is the listener's on its local address
|
|
787
|
+
# (exact, else wildcard); an accepted row holds the acceptor's uid (sock_graft): no listener swap passes (CT-254).
|
|
796
788
|
return _one_owner(_listeners_of(rows, found[0].local), how, "not-accepted")
|
|
797
789
|
if how == "proc" and found[0].uid is None:
|
|
798
790
|
# A client's socket with inode 0 has already closed (0.74.0 unit reading 4): never another socket's owner.
|
|
@@ -830,10 +822,18 @@ def _proved(ask: str, *args, fallback: Owner, **kwargs) -> Owner:
|
|
|
830
822
|
if fallback.kind != UNKNOWN or not (fallback.reason or "").startswith(TABLE_RESTRICTED) or sys.platform != "darwin":
|
|
831
823
|
return fallback
|
|
832
824
|
try:
|
|
833
|
-
if _PROOF[0] is None:
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
825
|
+
if _PROOF[0] is None: # the file beside this one; sys.path stays the host's (FAA-327); alone, the table stands
|
|
826
|
+
here = os.path.realpath(os.path.join(os.path.dirname(os.path.abspath(__file__)), "fabric_socket_proof.py"))
|
|
827
|
+
if not os.path.isfile(here):
|
|
828
|
+
raise ImportError(here)
|
|
829
|
+
try: # the host's imported copy if it is that file (one calibration); the statement keeps it in the closure
|
|
830
|
+
import fabric_socket_proof as module
|
|
831
|
+
except ImportError:
|
|
832
|
+
module = None
|
|
833
|
+
if os.path.realpath(getattr(module, "__file__", None) or "-") != here: # else that file, by its path
|
|
834
|
+
spec = importlib.util.spec_from_file_location("fabric_socket_proof", here)
|
|
835
|
+
spec.loader.exec_module(module := importlib.util.module_from_spec(spec))
|
|
836
|
+
_PROOF[0] = module
|
|
837
837
|
proof = getattr(_PROOF[0], ask)(*args, **kwargs) if _PROOF[0] else None
|
|
838
838
|
except ImportError:
|
|
839
839
|
_PROOF[0], proof = False, None
|
|
@@ -973,11 +973,11 @@ class CheckedHTTPConnection(http.client.HTTPConnection):
|
|
|
973
973
|
|
|
974
974
|
def own_connection(port: int, *, expect_pid: Optional[int] = None, timeout: float = 10.0,
|
|
975
975
|
host: str = "127.0.0.1", vouch_pid: Optional[int] = None) -> CheckedHTTPConnection:
|
|
976
|
-
"""A `CheckedHTTPConnection` to `host:port`, connected, whose server end is this account's (
|
|
977
|
-
|
|
978
|
-
ListenerRefused,
|
|
979
|
-
|
|
980
|
-
|
|
976
|
+
"""A `CheckedHTTPConnection` to `host:port`, connected, whose server end is this account's (with `expect_pid`, that
|
|
977
|
+
process's), checked on the connection the caller sends on and on every reconnect; no proxy is consulted.
|
|
978
|
+
ListenerRefused, closed: `server-not-own` (another account's or the system's process), `server-unverified` (owner
|
|
979
|
+
not told: fail closed), `server-not-this-workspace` (not the pid expected). `vouch_pid`: a pid the caller started
|
|
980
|
+
(FAA-267), as on `CheckedHTTPConnection` and the Node twin's `checkedSocket`."""
|
|
981
981
|
conn = CheckedHTTPConnection(host, port, expect_pid=expect_pid, timeout=timeout, vouch_pid=vouch_pid)
|
|
982
982
|
conn.connect()
|
|
983
983
|
return conn
|
package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_platform.py
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-PassionCode-Commercial
|
|
1
2
|
"""Windows, where the kit needs it (DEC-0032): named pipes that hold one copy, protecting a file to its owner, and
|
|
2
3
|
reading a file's ACL to refuse a token file others can read. On other systems the same names exist and do nothing
|
|
3
4
|
or answer "absent". Part of the service kit (FAA-65, layer L1)."""
|
package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_profiles.py
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
|
+
# SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-PassionCode-Commercial
|
|
2
3
|
"""Runner and model profiles in the kit (Fabric Agent Contract DEC-0046, Fabric ADR-0147). A port of the contract's
|
|
3
4
|
`src/profile-rules.ts` at the pin — `resolve_model_profile` and the FAC-SEM-058…060 checks — held to the contract's own
|
|
4
5
|
answers by test/fixtures/contract/profile-vectors.json; plus what a service does with them: the doctor's runner and
|
package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_protocols.py
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-PassionCode-Commercial
|
|
1
2
|
"""Protocol revisions (DEC-0067) and an event's machine-readable data (DEC-0070, the feed-data protocols): parse,
|
|
2
3
|
accept, negotiate and check them. Part of the service kit (FAA-65, layer L3)."""
|
|
3
4
|
from __future__ import annotations
|
package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_secrets.py
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
|
+
# SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-PassionCode-Commercial
|
|
2
3
|
"""The contract's one credential detector (Fabric Agent Contract DEC-0044, `src/secret-shape.ts` at the pin): a name
|
|
3
4
|
that can only carry a credential, a value shaped like one, a launch argument that carries one, and a URL that does
|
|
4
5
|
(LC-21). A port held to the contract's own answers by test/fixtures/contract/profile-vectors.json. Standard library
|
package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_service.py
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-PassionCode-Commercial
|
|
1
2
|
"""Reference kit for the fabric-service/0.1 local service extension: the facade.
|
|
2
3
|
|
|
3
4
|
Since 0.40.0 (FAA-65) the kit is a set of modules, and this file re-exports every name it defined at 0.39.1, so
|
package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_supervisors.py
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-PassionCode-Commercial
|
|
1
2
|
"""Supervisors (DEC-0032, LC-14): launchd plists, systemd user units and Task Scheduler tasks, installed and
|
|
2
3
|
removed without touching what the operator turned off; release pruning (LC-15). Part of the service kit
|
|
3
4
|
(FAA-65, layer L3)."""
|
|
@@ -25,6 +26,7 @@ from pathlib import Path as _Path # noqa: E402
|
|
|
25
26
|
if str(_Path(__file__).resolve().parent) not in _sys.path: # the kit loads from any working directory (FAA-65)
|
|
26
27
|
_sys.path.insert(0, str(_Path(__file__).resolve().parent))
|
|
27
28
|
import fabric_peer_owner as _po # noqa: E402 - the listener's owner (DEC-0154 HA-2)
|
|
29
|
+
import fabric_socket_proof as _sp # noqa: E402 - the one loopback host rule (FAA-326)
|
|
28
30
|
from fabric_base import (
|
|
29
31
|
DRAIN_SECONDS,
|
|
30
32
|
SUPERVISOR_ENV,
|
|
@@ -462,16 +464,20 @@ def launchd_pid(label: str, domain: Optional[str] = None) -> Optional[int]:
|
|
|
462
464
|
return None
|
|
463
465
|
|
|
464
466
|
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
467
|
+
#: Whether urlsplit's hostname names this machine: the kit's one loopback rule (FAA-326), so 127.1, 2130706433 and a
|
|
468
|
+
#: name under .localhost, which the Node twin's `new URL` reads as loopback, take the checked path here too.
|
|
469
|
+
_loopback_host = _sp.loopback_host
|
|
470
|
+
|
|
471
|
+
|
|
472
|
+
def _loopback_otherwise(host: Optional[str]) -> bool:
|
|
473
|
+
"""A loopback address the kit's rule does not take: one with a zone (`::1%lo0`) or IPv4-mapped (`::ffff:127.0.0.1`).
|
|
474
|
+
urlopen reaches loopback through either, so it is refused unread, as Node refuses it (0.84.0 seam reading)."""
|
|
471
475
|
try:
|
|
472
|
-
|
|
476
|
+
address = ipaddress.ip_address((host or "").split("%", 1)[0])
|
|
473
477
|
except ValueError:
|
|
474
478
|
return False
|
|
479
|
+
mapped = getattr(address, "ipv4_mapped", None)
|
|
480
|
+
return bool(address.is_loopback or (mapped and mapped.is_loopback))
|
|
475
481
|
|
|
476
482
|
|
|
477
483
|
class ForeignUserAnswer:
|
|
@@ -498,7 +504,7 @@ def _read_well_known(origin: str, timeout: float = 2.0,
|
|
|
498
504
|
except ValueError: # a port out of range
|
|
499
505
|
port = None
|
|
500
506
|
if parts.scheme == "http" and port and _loopback_host(parts.hostname):
|
|
501
|
-
# every loopback spelling (127
|
|
507
|
+
# every loopback spelling (127/8 in any form, localhost or a name under it, [::1]) goes on a checked connection,
|
|
502
508
|
# never the unchecked way (FAA-257)
|
|
503
509
|
conn = _po.CheckedHTTPConnection(parts.hostname, port, timeout=timeout, vouch_pid=vouch_pid)
|
|
504
510
|
try:
|
|
@@ -512,6 +518,8 @@ def _read_well_known(origin: str, timeout: float = 2.0,
|
|
|
512
518
|
return None, None
|
|
513
519
|
finally:
|
|
514
520
|
conn.close()
|
|
521
|
+
if _loopback_otherwise(parts.hostname):
|
|
522
|
+
return None, None
|
|
515
523
|
try:
|
|
516
524
|
with urllib.request.urlopen(origin + "/.well-known/fabric-service", timeout=timeout) as response:
|
|
517
525
|
return json.loads(response.read().decode()), None
|
package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_tailnet.py
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
|
+
# SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-PassionCode-Commercial
|
|
2
3
|
"""Who is calling an agent that sits behind `tailscale serve`, and what that person may open (FAA-297). Standard
|
|
3
4
|
library only; the Node twin is fabric-tailnet.mjs, and both answer test/fixtures/tailnet/vectors.json alike.
|
|
4
5
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
|
+
# SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-PassionCode-Commercial
|
|
2
3
|
"""A person's identity at every door of a service published through `tailscale serve` (FAA-324). Standard library
|
|
3
4
|
only; the Node twin is fabric-tailnet-identity.mjs, and both answer test/fixtures/tailnet-identity/vectors.json alike.
|
|
4
5
|
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-PassionCode-Commercial
|
|
1
2
|
"""Dates and times the way the contract reads them, once for the whole kit (FAA-65, layer L0).
|
|
2
3
|
|
|
3
4
|
- ``parse_rfc3339_ms(text)``: strict RFC 3339 (a ``T``, an offset, a day that exists; no space, no leap second) as
|
package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_usage.py
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-PassionCode-Commercial
|
|
1
2
|
"""What a service spends on models (DEC-0021, DEC-0065, DEC-0091): usage receipts, the bounded ledger, the usage
|
|
2
3
|
report and its rules (FAC-SEM-025), OpenRouter attribution (FAC-SEM-098) and every spending limit (DEC-0027).
|
|
3
4
|
Part of the service kit (FAA-65, layer L3)."""
|