@fased/fased 0.1.67 → 0.1.69
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 +27 -0
- package/README.md +20 -22
- package/config/sat-runtime.env +6 -2
- package/config/signer-protocol-v2.json +10 -0
- package/dist/agents/tools/wallet-action-tool.js +2 -0
- package/dist/agents/tools/wallet-tool.js +5 -3
- package/dist/brand.js +1 -1
- package/dist/build-info.json +3 -3
- package/dist/canvas-host/a2ui/.bundle.hash +1 -1
- package/dist/cli/program/register.wallet.js +119 -5
- package/dist/commands/wallet.js +1286 -74
- package/dist/config/sat-runtime-ids.js +6 -1
- package/dist/control-ui/assets/{app-De8gTtZU.js → app-BLFLoFPk.js} +1526 -1526
- package/dist/control-ui/assets/{federation-DgA9e-Pn.js → federation-SGMAnM_8.js} +2 -2
- package/dist/control-ui/assets/{index-DYYBRBOS.js → index-S88kp5ZQ.js} +3 -3
- package/dist/control-ui/assets/{mining-Dg-3ll0F.js → mining-ClI8RW4u.js} +2 -2
- package/dist/control-ui/assets/{wallet-DvStR_AT.js → wallet-CRIhDQbW.js} +325 -156
- package/dist/control-ui/index.html +1 -1
- package/dist/control-ui/version.json +1 -1
- package/dist/gateway/server-http.js +394 -55
- package/dist/mining/mainnet-sync.js +67 -5
- package/dist/operator/operator-readiness.js +1 -1
- package/dist/plugin-sdk/{actions-DRu135h0.js → actions-B-Vwj64K.js} +3 -3
- package/dist/plugin-sdk/{allow-list-DyAxs4yw.js → allow-list-Bf45HfoP.js} +1 -1
- package/dist/plugin-sdk/{audio-preflight-Dq_rJtqH.js → audio-preflight-CS7Q_7-R.js} +26 -25
- package/dist/plugin-sdk/{audit-C5d2z5U1.js → audit-CUULWG22.js} +1 -1
- package/dist/plugin-sdk/{channel-access-configure-DaI5wevh.js → channel-access-configure-BoUsC-Ys.js} +1 -1
- package/dist/plugin-sdk/{channel-adapters.discord-BS4S4Svh.js → channel-adapters.discord-DSiR4X2Y.js} +1 -1
- package/dist/plugin-sdk/channel-plugin-common.d.ts +2 -2
- package/dist/plugin-sdk/channel-plugin-common.js +1 -1
- package/dist/plugin-sdk/{chunk-CyoyqpbG.js → chunk-CBpl-AiQ.js} +1 -1
- package/dist/plugin-sdk/{chunk-items-Dunoq4Er.js → chunk-items-BLBZNORg.js} +1 -1
- package/dist/plugin-sdk/command-status.js +26 -25
- package/dist/plugin-sdk/{commands-registry-BfqdEWdF.js → commands-registry-G5KXSi_y.js} +1 -1
- package/dist/plugin-sdk/{config-schema--vl89M7d.js → config-schema-BiBOUW89.js} +431 -125
- package/dist/plugin-sdk/device-pair.d.ts +1 -1
- package/dist/plugin-sdk/{diagnostic-DLL_zekv.js → diagnostic-sYs6Agr-.js} +1 -1
- package/dist/plugin-sdk/{directory-live-CSuYxdwk.js → directory-live-BXMpuYAF.js} +1 -1
- package/dist/plugin-sdk/{directory-live-Dw7ZgC9_.js → directory-live-Rn1BzPof.js} +1 -1
- package/dist/plugin-sdk/discord.d.ts +4 -4
- package/dist/plugin-sdk/discord.js +20 -20
- package/dist/plugin-sdk/{draft-stream-controls-BqchW1vi.js → draft-stream-controls-CMNdKSx-.js} +1 -1
- package/dist/plugin-sdk/{guilds-CDhRIX57.js → guilds-Dkwl0yHv.js} +1 -1
- package/dist/plugin-sdk/{handle-action-hvwapMKg.js → handle-action-CRdM6B-8.js} +15 -15
- package/dist/plugin-sdk/index.d.ts +15 -15
- package/dist/plugin-sdk/index.js +28 -27
- package/dist/plugin-sdk/{login-Ca583Okc.js → login-D7WnK8-P.js} +1 -1
- package/dist/plugin-sdk/{login-qr-CGciBSNP.js → login-qr-CRueOKZK.js} +2 -114
- package/dist/plugin-sdk/{markdown-tables-DCOXEUfZ.js → markdown-tables-d7GlUs5R.js} +1 -1
- package/dist/plugin-sdk/{media-CAdQF5TG.js → media-BAoaxCrt.js} +1 -1
- package/dist/plugin-sdk/{monitor-DrTy_4CL.js → monitor-WXdn4mR-.js} +34 -33
- package/dist/plugin-sdk/{monitor-CV1sr0p2.js → monitor-xzVAPbg2.js} +44 -43
- package/dist/plugin-sdk/{openresponses-http-BAjgURZa.js → openresponses-http-DnI1LFgq.js} +26 -25
- package/dist/plugin-sdk/{outbound-attachment-QqTnIhZL.js → outbound-attachment-CyXM3cAv.js} +1 -1
- package/dist/plugin-sdk/{outbound-BgVDdHxx.js → outbound-zB6llMGW.js} +6 -6
- package/dist/plugin-sdk/{pairing-message-BjIJYVvp.d.ts → pairing-message-CiTcdD6m.d.ts} +1 -1
- package/dist/plugin-sdk/{pairing-store-BChahgI2.js → pairing-store-B6J2C0vP.js} +1 -1
- package/dist/plugin-sdk/{pi-model-discovery-runtime-DxTMz_XF.js → pi-model-discovery-runtime-6JzLw9Gk.js} +1 -1
- package/dist/plugin-sdk/{probe-CJb5uR8B.js → probe-BM7Oe40M.js} +2 -2
- package/dist/plugin-sdk/{probe-l_whvGLY.js → probe-CMPksimh.js} +1 -1
- package/dist/plugin-sdk/{probe-BFroeK3g.js → probe-oVp12D6L.js} +1 -1
- package/dist/plugin-sdk/provider-web-search-config-contract.d.ts +1 -1
- package/dist/plugin-sdk/{pw-ai-DlxqX6Es.js → pw-ai-DZYLDC-S.js} +1 -1
- package/dist/plugin-sdk/qr-image-B4MlMG4N.js +115 -0
- package/dist/plugin-sdk/{replies-ChYo5ZQM.js → replies-CY-V0Zob.js} +3 -3
- package/dist/plugin-sdk/{resolve-channels-87LZrFk_.js → resolve-channels-1HtDcMqh.js} +2 -2
- package/dist/plugin-sdk/{resolve-channels-_-nV-EK2.js → resolve-channels-CU72Qh2j.js} +1 -1
- package/dist/plugin-sdk/{resolve-outbound-target-D-KGgHJZ.js → resolve-outbound-target-nQSBVYz9.js} +2 -2
- package/dist/plugin-sdk/{resolve-route-C8tvQm8Z.js → resolve-route-Dufnu2cT.js} +1 -1
- package/dist/plugin-sdk/{resolve-users-DN9VQBwv.js → resolve-users-Bk_ss2vC.js} +1 -1
- package/dist/plugin-sdk/{resolve-users-V6dHh_2B.js → resolve-users-IevCOk4W.js} +2 -2
- package/dist/plugin-sdk/{runtime-2B9_WKoI.js → runtime-CXSQwMaR.js} +1 -1
- package/dist/plugin-sdk/{runtime-dependency-nup8niQL.js → runtime-dependency-DczkvPxn.js} +9 -9
- package/dist/plugin-sdk/sat-runtime.d.ts +105 -10
- package/dist/plugin-sdk/sat-runtime.js +26 -25
- package/dist/plugin-sdk/{send-DCO441U7.js → send-BXBS_mRK.js} +8 -8
- package/dist/plugin-sdk/{send-CFzGKJXo.js → send-D-HfKQZm.js} +4 -4
- package/dist/plugin-sdk/{send-B6KkGKZD.js → send-D1j12ZgX.js} +5 -5
- package/dist/plugin-sdk/{send-q9HXrSwK.js → send-DWKm6yay.js} +10 -10
- package/dist/plugin-sdk/{send-gDoGA-7e.js → send-Di1Jit3L.js} +7 -7
- package/dist/plugin-sdk/{skill-commands-FKEPLS7T.js → skill-commands-iJtvpqgb.js} +2 -2
- package/dist/plugin-sdk/{slack-DSC6T2KW.js → slack-CkIRVDUK.js} +45 -44
- package/dist/plugin-sdk/{slack-actions-DhbMcp8M.js → slack-actions-BzUEszJa.js} +10 -10
- package/dist/plugin-sdk/slack.d.ts +4 -4
- package/dist/plugin-sdk/slack.js +6 -6
- package/dist/plugin-sdk/{sticker-cache-C0l_5IKg.js → sticker-cache-Dpap5ce_.js} +2 -2
- package/dist/plugin-sdk/{tables-B3jr0Pvq.js → tables-_1W36GII.js} +2 -2
- package/dist/plugin-sdk/{targets-CtSbTxYX.js → targets-DDbNnLnB.js} +2 -2
- package/dist/plugin-sdk/{telegram-actions-BwGBIVDE.js → telegram-actions-Cewdga8H.js} +30 -29
- package/dist/plugin-sdk/telegram.d.ts +4 -4
- package/dist/plugin-sdk/telegram.js +3 -3
- package/dist/plugin-sdk/{thread-bindings.lifecycle-QbkNl-m6.js → thread-bindings.lifecycle-Y9T3CQGf.js} +3 -3
- package/dist/plugin-sdk/{thread-bindings.state-D9hg_M1c.js → thread-bindings.state-D2oOWDpv.js} +1 -1
- package/dist/plugin-sdk/{tmp-fased-dir-DXnGKKgi.d.ts → tmp-fased-dir-BSEHc8MQ.d.ts} +8 -2
- package/dist/plugin-sdk/{types-eG9aYqXF.d.ts → types-BakzIzGN.d.ts} +1 -1
- package/dist/plugin-sdk/{types-Cegc86EP.d.ts → types-CzF0YQqK.d.ts} +3 -3
- package/dist/plugin-sdk/{web-C_AH5PyB.js → web-DGWi7i3B.js} +33 -32
- package/dist/plugin-sdk/{whatsapp-actions-Bj_rOncr.js → whatsapp-actions-Blu9-eX-.js} +9 -9
- package/dist/plugin-sdk/{whatsapp-heartbeat-B1WHkJIg.js → whatsapp-heartbeat-DjmQM7hq.js} +2 -2
- package/dist/plugin-sdk/whatsapp.d.ts +9 -9
- package/dist/plugin-sdk/whatsapp.js +7 -7
- package/dist/plugin-sdk/{wsl-J-HscWxS.js → wsl-CTvIWvZz.js} +1 -1
- package/dist/plugin-sdk/{zod-schema.providers-core-FaYR6KdD.d.ts → zod-schema.providers-core-CIzCjXH9.d.ts} +61 -61
- package/dist/wallet/local-socket-signer-lifecycle.js +107 -3
- package/dist/wallet/local-socket-signer-protocol.js +97 -10
- package/dist/wallet/mining-wallet-retirement.js +256 -0
- package/dist/wallet/providers/local-socket-signer-adapter.js +10 -0
- package/dist/wallet/signer-network-admin.js +11 -118
- package/dist/wallet/signer-protocol-v2.generated.js +10 -0
- package/dist/wallet/solana-assets.js +9 -3
- package/dist/wallet/solana-rpc-read-fetch.js +65 -0
- package/dist/wallet/wallet-agent-selection.js +6 -10
- package/dist/wallet/wallet-provider-registry.js +70 -29
- package/dist/wallet/wallet-send-approvals.js +6 -2
- package/dist/wallet/wallet-status.js +63 -1
- package/dist/web/login-qr.js +1 -1
- package/dist/wizard/onboarding.js +86 -84
- package/dist/wizard/onboarding.wallet.js +10 -1
- package/extensions/acpx/package.json +1 -1
- package/extensions/bluebubbles/package.json +1 -1
- package/extensions/copilot-proxy/package.json +1 -1
- package/extensions/diagnostics-otel/package.json +1 -1
- package/extensions/fased-federation/package.json +1 -1
- package/extensions/google-gemini-cli-auth/package.json +1 -1
- package/extensions/imessage/package.json +1 -1
- package/extensions/irc/package.json +1 -1
- package/extensions/line/package.json +1 -1
- package/extensions/llm-task/package.json +1 -1
- package/extensions/lobster/package.json +1 -1
- package/extensions/matrix/CHANGELOG.md +12 -0
- package/extensions/matrix/package.json +1 -1
- package/extensions/mattermost/package.json +1 -1
- package/extensions/memory-core/package.json +2 -2
- package/extensions/memory-lancedb/package.json +1 -1
- package/extensions/minimax-portal-auth/package.json +1 -1
- package/extensions/msteams/CHANGELOG.md +12 -0
- package/extensions/msteams/package.json +1 -1
- package/extensions/nextcloud-talk/package.json +1 -1
- package/extensions/nostr/CHANGELOG.md +12 -0
- package/extensions/nostr/package.json +1 -1
- package/extensions/open-prose/package.json +1 -1
- package/extensions/sat-mining/package.json +1 -1
- package/extensions/signal/package.json +1 -1
- package/extensions/synology-chat/package.json +1 -1
- package/extensions/tlon/package.json +1 -1
- package/extensions/twitch/CHANGELOG.md +12 -0
- package/extensions/twitch/package.json +1 -1
- package/extensions/voice-call/CHANGELOG.md +12 -0
- package/extensions/voice-call/package.json +1 -1
- package/extensions/zalo/CHANGELOG.md +12 -0
- package/extensions/zalo/package.json +1 -1
- package/extensions/zalouser/CHANGELOG.md +12 -0
- package/extensions/zalouser/package.json +1 -1
- package/install.sh +286 -107
- package/package.json +4 -2
- package/scripts/fased-managed-updater.mjs +10 -2
- package/scripts/install-fased-signerd.sh +4 -8
- package/scripts/install-managed-runtime.mjs +10 -7
- package/scripts/install-runtime-profile.sh +27 -0
- package/scripts/start-managed.sh +13 -1
- /package/dist/plugin-sdk/{active-listener-B_NMtgPL.js → active-listener-p9Ooc1qj.js} +0 -0
- /package/dist/plugin-sdk/{blocks-input-Bg-8S2pl.js → blocks-input-DiZaqaN7.js} +0 -0
- /package/dist/plugin-sdk/{channel-access-CcFRdRPO.js → channel-access-B0aZBSd2.js} +0 -0
- /package/dist/plugin-sdk/{channel-activity-DBDMQ3yI.js → channel-activity-F07DjroV.js} +0 -0
- /package/dist/plugin-sdk/{channel-core-CFRs8LPy.js → channel-core-DoF4X04L.js} +0 -0
- /package/dist/plugin-sdk/{client-pI228AVT.js → client-DLY-kWF_.js} +0 -0
- /package/dist/plugin-sdk/{command-poll-backoff-yJU83wEq.js → command-poll-backoff-NAePk3eL.js} +0 -0
- /package/dist/plugin-sdk/{date-time-uUevHscU.js → date-time-ChY_tHoG.js} +0 -0
- /package/dist/plugin-sdk/{draft-stream-loop-CrOPfV3F.js → draft-stream-loop-DMBwjjd1.js} +0 -0
- /package/dist/plugin-sdk/{fetch-BtmoPIlf.js → fetch-B0v6OTUZ.js} +0 -0
- /package/dist/plugin-sdk/{filesystem-manager-DoI8IBNF.js → filesystem-manager-BzuIJ9K9.js} +0 -0
- /package/dist/plugin-sdk/{gateway-registry-DZDsqicG.js → gateway-registry-Bgl2GFgy.js} +0 -0
- /package/dist/plugin-sdk/{inbound-context-DrAcXE0y.js → inbound-context-CQnfFFQ9.js} +0 -0
- /package/dist/plugin-sdk/{pi-model-discovery-BX_JLcEJ.js → pi-model-discovery-BHNVyRny.js} +0 -0
- /package/dist/plugin-sdk/{polls-DKQXVfJp.js → polls-DXd67TD8.js} +0 -0
- /package/dist/plugin-sdk/{proxy-DWpYcsvR.js → proxy-CLRUdShp.js} +0 -0
- /package/dist/plugin-sdk/{qmd-manager-CgRaTxUq.js → qmd-manager-B8Vnu0ND.js} +0 -0
- /package/dist/plugin-sdk/{render-e7fENCYH.js → render-DrBfVs0u.js} +0 -0
- /package/dist/plugin-sdk/{reply-reference-Bqk-7HXE.js → reply-reference-BnAk5Wjb.js} +0 -0
- /package/dist/plugin-sdk/{retry-policy-C6SjKjQA.js → retry-policy-CXh1owkc.js} +0 -0
- /package/dist/plugin-sdk/{sandbox-paths-Dx2lUqCu.js → sandbox-paths-Bzh1CuZc.js} +0 -0
- /package/dist/plugin-sdk/{session-DHD4ZKyG.js → session-iuGR_rdi.js} +0 -0
- /package/dist/plugin-sdk/{shared-CBgp_GBw.js → shared-D1AD2Ejn.js} +0 -0
- /package/dist/plugin-sdk/{target-errors-Ckufe179.js → target-errors-DfS1sLR9.js} +0 -0
- /package/dist/plugin-sdk/{tool-loop-detection-Bp8bPJLs.js → tool-loop-detection-sDZl27w7.js} +0 -0
- /package/dist/plugin-sdk/{ui-Be8cLHIS.js → ui-GQDYm_jw.js} +0 -0
- /package/dist/plugin-sdk/{with-timeout-ckWB8rTo.js → with-timeout-CVV8tytk.js} +0 -0
package/install.sh
CHANGED
|
@@ -36,16 +36,61 @@ if [[ "$install_entry_legacy_ts_authkey" -eq 1 ]]; then
|
|
|
36
36
|
fi
|
|
37
37
|
|
|
38
38
|
if [[ "$install_entry_is_stream" -eq 1 && "$install_entry_hosting" -eq 1 ]]; then
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
39
|
+
if [[ "${#install_entry_args[@]}" -ne 1 || "${install_entry_args[0]:-}" != "--hosting" ]]; then
|
|
40
|
+
echo "Streamed VPS Hosting accepts only the exact fresh-install selector: --hosting" >&2
|
|
41
|
+
echo "Use an exact tagged, attested installer for repair, release overrides, or advanced selectors." >&2
|
|
42
|
+
exit 1
|
|
43
|
+
fi
|
|
44
|
+
install_entry_exported_env=()
|
|
45
|
+
mapfile -t install_entry_exported_env < <(compgen -e)
|
|
46
|
+
for install_entry_env_name in "${install_entry_exported_env[@]}"; do
|
|
47
|
+
if [[ "$install_entry_env_name" == FASED_* ]]; then
|
|
48
|
+
echo "Refusing Fased environment overrides during streamed VPS Hosting: ${install_entry_env_name}" >&2
|
|
49
|
+
exit 1
|
|
50
|
+
fi
|
|
51
|
+
done
|
|
52
|
+
install_entry_unsafe_env=(
|
|
53
|
+
HTTP_PROXY HTTPS_PROXY ALL_PROXY NO_PROXY http_proxy https_proxy all_proxy no_proxy
|
|
54
|
+
CURL_HOME CURL_CA_BUNDLE SSL_CERT_FILE SSL_CERT_DIR GIT_SSL_NO_VERIFY
|
|
55
|
+
GH_HOST GH_REPO GH_CONFIG_DIR TMPDIR LD_PRELOAD LD_LIBRARY_PATH BASH_ENV ENV CDPATH
|
|
56
|
+
)
|
|
57
|
+
for install_entry_env_name in "${install_entry_unsafe_env[@]}"; do
|
|
58
|
+
if [[ -n "${!install_entry_env_name+x}" ]]; then
|
|
59
|
+
echo "Refusing unsafe environment override during streamed VPS Hosting: ${install_entry_env_name}" >&2
|
|
60
|
+
exit 1
|
|
61
|
+
fi
|
|
62
|
+
done
|
|
63
|
+
install_entry_existing_hosting_paths=(
|
|
64
|
+
/etc/fased
|
|
65
|
+
/opt/fased
|
|
66
|
+
/var/lib/fased-installer
|
|
67
|
+
/var/lib/fased-gateway
|
|
68
|
+
/var/lib/fased-signerd
|
|
69
|
+
/etc/systemd/system/fased-gateway.service
|
|
70
|
+
/etc/systemd/system/fased-signerd.service
|
|
71
|
+
/usr/local/libexec/fased-gateway-launch
|
|
72
|
+
/usr/local/libexec/fased-host-updater
|
|
73
|
+
)
|
|
74
|
+
for install_entry_existing_path in "${install_entry_existing_hosting_paths[@]}"; do
|
|
75
|
+
if [[ -e "$install_entry_existing_path" || -L "$install_entry_existing_path" ]]; then
|
|
76
|
+
echo "Streamed VPS Hosting is only for a fresh host; existing Fased state was found." >&2
|
|
77
|
+
echo "Use the exact tagged repair or the installed updater instead of the mutable main bootstrap." >&2
|
|
78
|
+
exit 1
|
|
79
|
+
fi
|
|
80
|
+
done
|
|
81
|
+
PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
|
|
82
|
+
LANG="C.UTF-8"
|
|
83
|
+
LC_ALL="C.UTF-8"
|
|
84
|
+
export PATH LANG LC_ALL
|
|
85
|
+
unset -f curl gh jq tar sha256sum awk stat find grep flock install mv cp chown chmod sync 2>/dev/null || true
|
|
86
|
+
hash -r 2>/dev/null || true
|
|
43
87
|
fi
|
|
44
88
|
|
|
45
|
-
# A Hosting request
|
|
89
|
+
# A Hosting file request enters the attest-and-extract bootstrap unless it is
|
|
46
90
|
# the exact inner invocation carrying the root-owned verified bundle marker.
|
|
47
|
-
# Streamed Hosting
|
|
48
|
-
# and
|
|
91
|
+
# Streamed Hosting reaches this block only for the exact fresh --hosting
|
|
92
|
+
# selector validated above. Repair and advanced Hosting selectors remain
|
|
93
|
+
# exact-tag-only.
|
|
49
94
|
if [[ "$install_entry_is_stream" -eq 1 || \
|
|
50
95
|
( "$install_entry_hosting" -eq 1 && -z "$install_entry_verified_bundle" ) ]]; then
|
|
51
96
|
install_repo_url="${FASED_INSTALL_REPO:-https://github.com/fased-ai/fased.git}"
|
|
@@ -98,6 +143,10 @@ if [[ "$install_entry_is_stream" -eq 1 || \
|
|
|
98
143
|
esac
|
|
99
144
|
done
|
|
100
145
|
|
|
146
|
+
if [[ "$hosting_bootstrap" -eq 1 && "$hosting_repair_bootstrap" -eq 0 && -z "$hosting_release" ]]; then
|
|
147
|
+
hosting_release="latest"
|
|
148
|
+
fi
|
|
149
|
+
|
|
101
150
|
bootstrap_as_root() {
|
|
102
151
|
if [[ "$(id -u)" -eq 0 ]]; then
|
|
103
152
|
"$@"
|
|
@@ -123,7 +172,7 @@ if [[ "$install_entry_is_stream" -eq 1 || \
|
|
|
123
172
|
local source_tmp=""
|
|
124
173
|
keyring_tmp="$(mktemp)"
|
|
125
174
|
source_tmp="$(mktemp)"
|
|
126
|
-
curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg -o "$keyring_tmp"
|
|
175
|
+
curl -q -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg -o "$keyring_tmp"
|
|
127
176
|
printf 'deb [arch=%s signed-by=/etc/apt/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main\n' "$(dpkg --print-architecture)" >"$source_tmp"
|
|
128
177
|
bootstrap_as_root install -d -m 0755 /etc/apt/keyrings
|
|
129
178
|
bootstrap_as_root install -m 0644 "$keyring_tmp" /etc/apt/keyrings/githubcli-archive-keyring.gpg
|
|
@@ -157,7 +206,7 @@ if [[ "$install_entry_is_stream" -eq 1 || \
|
|
|
157
206
|
}
|
|
158
207
|
|
|
159
208
|
resolve_public_latest_release_tag() {
|
|
160
|
-
curl -fsSL --proto '=https' --tlsv1.2 \
|
|
209
|
+
curl -q -fsSL --proto '=https' --tlsv1.2 \
|
|
161
210
|
-H 'Accept: application/vnd.github+json' \
|
|
162
211
|
-H 'X-GitHub-Api-Version: 2022-11-28' \
|
|
163
212
|
-H 'User-Agent: fased-installer' \
|
|
@@ -175,11 +224,10 @@ if [[ "$install_entry_is_stream" -eq 1 || \
|
|
|
175
224
|
echo "Refusing a caller-supplied verified bundle marker." >&2
|
|
176
225
|
exit 1
|
|
177
226
|
fi
|
|
178
|
-
|
|
179
|
-
echo "VPS Hosting
|
|
180
|
-
echo "Pass --release vX.Y.Z (recommended) or --release latest." >&2
|
|
227
|
+
[[ -n "$hosting_release" ]] || {
|
|
228
|
+
echo "VPS Hosting release resolution failed before verification." >&2
|
|
181
229
|
exit 1
|
|
182
|
-
|
|
230
|
+
}
|
|
183
231
|
|
|
184
232
|
install_hosting_bootstrap_tools() {
|
|
185
233
|
[[ "$auto_install" -eq 1 ]] || return 0
|
|
@@ -225,22 +273,37 @@ if [[ "$install_entry_is_stream" -eq 1 || \
|
|
|
225
273
|
fi
|
|
226
274
|
|
|
227
275
|
local architecture=""
|
|
276
|
+
local signer_platform=""
|
|
228
277
|
case "$(uname -m)" in
|
|
229
|
-
x86_64|amd64)
|
|
230
|
-
|
|
278
|
+
x86_64|amd64)
|
|
279
|
+
architecture="x64"
|
|
280
|
+
signer_platform="linux-amd64"
|
|
281
|
+
;;
|
|
282
|
+
aarch64|arm64)
|
|
283
|
+
architecture="arm64"
|
|
284
|
+
signer_platform="linux-arm64"
|
|
285
|
+
;;
|
|
231
286
|
*)
|
|
232
287
|
echo "Unsupported Hosting architecture: $(uname -m)" >&2
|
|
233
288
|
exit 1
|
|
234
289
|
;;
|
|
235
290
|
esac
|
|
236
|
-
local asset="fased-hosted-app-linux-${architecture}-v${release_version}.tar.gz"
|
|
291
|
+
local asset="fased-hosted-app-v2-linux-${architecture}-v${release_version}.tar.gz"
|
|
237
292
|
local release_url="https://github.com/fased-ai/fased/releases/download/v${release_version}"
|
|
238
293
|
local release_parent="/var/lib/fased-installer/releases/v${release_version}"
|
|
239
294
|
local staging="${release_parent}/.staging.$$"
|
|
240
295
|
local preflight=""
|
|
241
296
|
preflight="$(mktemp -d "${TMPDIR:-/tmp}/fased-hosting-bootstrap.XXXXXX")"
|
|
242
297
|
local archive="${preflight}/${asset}"
|
|
298
|
+
local dependency_archive=""
|
|
299
|
+
local dependency_asset=""
|
|
300
|
+
local dependency_expected=""
|
|
301
|
+
local dependency_hash=""
|
|
302
|
+
local signer_binary=""
|
|
303
|
+
local signer_asset=""
|
|
304
|
+
local signer_expected=""
|
|
243
305
|
local release_manifest="${preflight}/fased-hosted-release-v2.json"
|
|
306
|
+
local release_manifest_bundle="${preflight}/fased-hosted-release-v2.json.attestation.json"
|
|
244
307
|
local expected=""
|
|
245
308
|
local actual=""
|
|
246
309
|
local manifest_digest=""
|
|
@@ -248,16 +311,43 @@ if [[ "$install_entry_is_stream" -eq 1 || \
|
|
|
248
311
|
local manifest_signer_commit=""
|
|
249
312
|
|
|
250
313
|
umask 077
|
|
251
|
-
|
|
252
|
-
|
|
314
|
+
hosting_bootstrap_cleanup() {
|
|
315
|
+
local status="$?"
|
|
316
|
+
rm -rf -- "${preflight:-}" "${staging:-}"
|
|
317
|
+
if [[ "$status" -ne 0 ]]; then
|
|
318
|
+
if [[ -e /var/lib/fased-installer || -L /var/lib/fased-installer ]]; then
|
|
319
|
+
echo "Hosting bootstrap stopped without activating Fased services." >&2
|
|
320
|
+
echo "Persistent installer state exists; retry only with the exact tagged, attested repair procedure." >&2
|
|
321
|
+
else
|
|
322
|
+
echo "Hosting bootstrap stopped before persistent Fased state was created; fix the reported problem and rerun the exact --hosting command." >&2
|
|
323
|
+
fi
|
|
324
|
+
fi
|
|
325
|
+
return "$status"
|
|
326
|
+
}
|
|
327
|
+
trap hosting_bootstrap_cleanup EXIT
|
|
328
|
+
curl -q -fL --proto '=https' --tlsv1.2 "$release_url/fased-hosted-release-v2.json" -o "$release_manifest"
|
|
329
|
+
curl -q -fL --proto '=https' --tlsv1.2 "$release_url/fased-hosted-release-v2.json.attestation.json" -o "$release_manifest_bundle"
|
|
253
330
|
GH_PROMPT_DISABLED=1 gh attestation verify "$release_manifest" \
|
|
254
331
|
--repo fased-ai/fased \
|
|
332
|
+
--bundle "$release_manifest_bundle" \
|
|
255
333
|
--signer-workflow fased-ai/fased/.github/workflows/hosted-runtime-release.yml \
|
|
256
334
|
--source-ref "refs/tags/v${release_version}" \
|
|
257
335
|
--deny-self-hosted-runners >/dev/null
|
|
258
336
|
local manifest_selection=""
|
|
259
|
-
manifest_selection="$(jq -er --arg version "$release_version" --arg architecture "$architecture" '
|
|
260
|
-
if
|
|
337
|
+
manifest_selection="$(jq -er --arg version "$release_version" --arg architecture "$architecture" --arg signer_platform "$signer_platform" '
|
|
338
|
+
if (keys == ["application", "release", "schemaVersion", "signer"]) and
|
|
339
|
+
.schemaVersion == 2 and
|
|
340
|
+
(.release | keys == ["commit", "tag", "version"]) and
|
|
341
|
+
(.application | keys == ["linux"]) and
|
|
342
|
+
(.application.linux | keys == ["arm64", "x64"]) and
|
|
343
|
+
(.application.linux[$architecture] | keys == ["artifact", "dependencies"]) and
|
|
344
|
+
(.application.linux[$architecture].artifact | keys == ["asset", "sha256"]) and
|
|
345
|
+
(.application.linux[$architecture].dependencies | keys == ["asset", "dependencyHash", "sha256"]) and
|
|
346
|
+
(.signer | keys == ["capabilities", "capabilitiesDigest", "platforms", "release"]) and
|
|
347
|
+
(.signer.release | keys == ["buildInputDigest", "commit", "development", "version"]) and
|
|
348
|
+
(.signer.platforms | keys == ["darwin-amd64", "darwin-arm64", "linux-amd64", "linux-arm64"]) and
|
|
349
|
+
(.signer.platforms[$signer_platform] | keys == ["asset", "sha256"]) and
|
|
350
|
+
(.signer.capabilitiesDigest | test("^sha256:[a-f0-9]{64}$")) and
|
|
261
351
|
(.release.version == $version) and (.release.tag == ("v" + $version)) and
|
|
262
352
|
(.release.commit | test("^[a-f0-9]{40}$")) and
|
|
263
353
|
(.signer.release.version == $version) and
|
|
@@ -265,38 +355,107 @@ if [[ "$install_entry_is_stream" -eq 1 || \
|
|
|
265
355
|
(.signer.release.development == false) and
|
|
266
356
|
(.signer.release.buildInputDigest | test("^sha256:[a-f0-9]{64}$")) and
|
|
267
357
|
(.application.linux[$architecture].artifact.asset | test("^[A-Za-z0-9][A-Za-z0-9._-]+$")) and
|
|
268
|
-
(.application.linux[$architecture].artifact.sha256 | test("^[a-f0-9]{64}$"))
|
|
358
|
+
(.application.linux[$architecture].artifact.sha256 | test("^[a-f0-9]{64}$")) and
|
|
359
|
+
(.application.linux[$architecture].dependencies.asset | test("^[A-Za-z0-9][A-Za-z0-9._-]+$")) and
|
|
360
|
+
(.application.linux[$architecture].dependencies.sha256 | test("^[a-f0-9]{64}$")) and
|
|
361
|
+
(.application.linux[$architecture].dependencies.dependencyHash | test("^[a-f0-9]{64}$")) and
|
|
362
|
+
(.signer.platforms[$signer_platform].asset | test("^[A-Za-z0-9][A-Za-z0-9._-]+$")) and
|
|
363
|
+
(.signer.platforms[$signer_platform].sha256 | test("^[a-f0-9]{64}$"))
|
|
269
364
|
then [
|
|
270
365
|
.release.commit,
|
|
271
366
|
.signer.release.commit,
|
|
272
367
|
.application.linux[$architecture].artifact.asset,
|
|
273
|
-
.application.linux[$architecture].artifact.sha256
|
|
368
|
+
.application.linux[$architecture].artifact.sha256,
|
|
369
|
+
.application.linux[$architecture].dependencies.asset,
|
|
370
|
+
.application.linux[$architecture].dependencies.sha256,
|
|
371
|
+
.application.linux[$architecture].dependencies.dependencyHash,
|
|
372
|
+
.signer.platforms[$signer_platform].asset,
|
|
373
|
+
.signer.platforms[$signer_platform].sha256
|
|
274
374
|
] | @tsv
|
|
275
375
|
else error("invalid hosted release manifest") end
|
|
276
376
|
' "$release_manifest")" || {
|
|
277
377
|
echo "Hosted release manifest does not bind this exact app and signer release." >&2
|
|
278
378
|
exit 1
|
|
279
379
|
}
|
|
280
|
-
IFS=$'\t' read -r manifest_commit manifest_signer_commit asset expected <<<"$manifest_selection"
|
|
281
|
-
[[ "$manifest_commit" == "$manifest_signer_commit" &&
|
|
380
|
+
IFS=$'\t' read -r manifest_commit manifest_signer_commit asset expected dependency_asset dependency_expected dependency_hash signer_asset signer_expected <<<"$manifest_selection"
|
|
381
|
+
[[ "$manifest_commit" == "$manifest_signer_commit" && \
|
|
382
|
+
"$asset" == "fased-hosted-app-v2-linux-${architecture}-v${release_version}.tar.gz" && \
|
|
383
|
+
"$dependency_asset" == "fased-hosted-deps-linux-${architecture}-${dependency_hash}.tar.gz" && \
|
|
384
|
+
"$signer_asset" == "fased-signerd-${signer_platform}" ]] || {
|
|
282
385
|
echo "Hosted release manifest selects a mixed commit or unexpected app artifact." >&2
|
|
283
386
|
exit 1
|
|
284
387
|
}
|
|
285
388
|
archive="${preflight}/${asset}"
|
|
286
|
-
|
|
389
|
+
dependency_archive="${preflight}/${dependency_asset}"
|
|
390
|
+
signer_binary="${preflight}/${signer_asset}"
|
|
391
|
+
curl -q -fL --proto '=https' --tlsv1.2 "$release_url/$asset" -o "$archive"
|
|
392
|
+
curl -q -fL --proto '=https' --tlsv1.2 "$release_url/$dependency_asset" -o "$dependency_archive"
|
|
393
|
+
curl -q -fL --proto '=https' --tlsv1.2 "$release_url/$signer_asset" -o "$signer_binary"
|
|
287
394
|
actual="$(sha256sum "$archive" | awk '{print tolower($1)}')"
|
|
395
|
+
local dependency_actual=""
|
|
396
|
+
local signer_actual=""
|
|
397
|
+
dependency_actual="$(sha256sum "$dependency_archive" | awk '{print tolower($1)}')"
|
|
398
|
+
signer_actual="$(sha256sum "$signer_binary" | awk '{print tolower($1)}')"
|
|
288
399
|
manifest_digest="$(sha256sum "$release_manifest" | awk '{print tolower($1)}')"
|
|
289
|
-
if [[ ! "$expected" =~ ^[a-f0-9]{64}$ || "$actual" != "$expected"
|
|
290
|
-
|
|
400
|
+
if [[ ! "$expected" =~ ^[a-f0-9]{64}$ || "$actual" != "$expected" || \
|
|
401
|
+
! "$dependency_expected" =~ ^[a-f0-9]{64}$ || "$dependency_actual" != "$dependency_expected" || \
|
|
402
|
+
! "$signer_expected" =~ ^[a-f0-9]{64}$ || "$signer_actual" != "$signer_expected" ]]; then
|
|
403
|
+
echo "Hosted app, dependency, or signer release checksum verification failed." >&2
|
|
291
404
|
exit 1
|
|
292
405
|
fi
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
406
|
+
local entry=""
|
|
407
|
+
while IFS= read -r entry; do
|
|
408
|
+
entry="${entry%/}"
|
|
409
|
+
if [[ -z "$entry" || "$entry" == /* || "$entry" == *\\* || \
|
|
410
|
+
( "$entry" != "package" && "$entry" != package/* ) || \
|
|
411
|
+
"$entry" == *"/../"* || "$entry" == ../* || "$entry" == */.. || \
|
|
412
|
+
"$entry" == *"/./"* || "$entry" == ./* || "$entry" == */. ]]; then
|
|
413
|
+
echo "Hosted app archive contains an unsafe path: $entry" >&2
|
|
414
|
+
exit 1
|
|
415
|
+
fi
|
|
416
|
+
done < <(tar -tzf "$archive")
|
|
417
|
+
while IFS= read -r entry; do
|
|
418
|
+
entry="${entry%/}"
|
|
419
|
+
if [[ -z "$entry" || "$entry" == /* || "$entry" == *\\* || \
|
|
420
|
+
( "$entry" != "node_modules" && "$entry" != node_modules/* ) || \
|
|
421
|
+
"$entry" == *"/../"* || "$entry" == ../* || "$entry" == */.. || \
|
|
422
|
+
"$entry" == *"/./"* || "$entry" == ./* || "$entry" == */. ]]; then
|
|
423
|
+
echo "Hosted dependency archive contains an unsafe path: $entry" >&2
|
|
424
|
+
exit 1
|
|
425
|
+
fi
|
|
426
|
+
done < <(tar -tzf "$dependency_archive")
|
|
427
|
+
|
|
428
|
+
local verified_extract="$preflight/verified-app"
|
|
429
|
+
install -d -m 0700 "$verified_extract"
|
|
430
|
+
tar -xzf "$archive" -C "$verified_extract" --no-same-owner --no-same-permissions
|
|
431
|
+
local verified_package_root="$verified_extract/package"
|
|
432
|
+
[[ -f "$verified_package_root/install.sh" && -f "$verified_package_root/package.json" && \
|
|
433
|
+
! -L "$verified_package_root/install.sh" && -f "$verified_package_root/dist/build-info.json" && \
|
|
434
|
+
! -L "$verified_package_root/dist/build-info.json" ]] || {
|
|
435
|
+
echo "Attested Hosting bundle is incomplete or has an invalid entrypoint." >&2
|
|
436
|
+
exit 1
|
|
437
|
+
}
|
|
438
|
+
local packaged_version=""
|
|
439
|
+
local packaged_commit=""
|
|
440
|
+
local build_info_version=""
|
|
441
|
+
packaged_version="$(awk -F'"' '/^[[:space:]]*"version"[[:space:]]*:/ { print $4; exit }' "$verified_package_root/package.json")"
|
|
442
|
+
packaged_commit="$(awk -F'"' '/^[[:space:]]*"commit"[[:space:]]*:/ { print $4; exit }' "$verified_package_root/dist/build-info.json")"
|
|
443
|
+
build_info_version="$(awk -F'"' '/^[[:space:]]*"version"[[:space:]]*:/ { print $4; exit }' "$verified_package_root/dist/build-info.json")"
|
|
444
|
+
[[ "$packaged_version" == "$release_version" && "$build_info_version" == "$release_version" && \
|
|
445
|
+
"$packaged_commit" =~ ^[a-f0-9]{40}$ && "$packaged_commit" == "$manifest_commit" ]] || {
|
|
446
|
+
echo "Attested Hosting application identity does not match the unified release manifest." >&2
|
|
447
|
+
exit 1
|
|
448
|
+
}
|
|
449
|
+
if find "$verified_package_root" -xdev ! -type f ! -type d -print -quit | grep -q . || \
|
|
450
|
+
find "$verified_package_root" -xdev -type f -links +1 -print -quit | grep -q . || \
|
|
451
|
+
find "$verified_package_root" -xdev \( ! -user root -o -perm /022 \) -print -quit | grep -q .; then
|
|
452
|
+
echo "Attested Hosting bundle violates the file, link, ownership, or writable-mode policy." >&2
|
|
453
|
+
exit 1
|
|
454
|
+
fi
|
|
455
|
+
|
|
456
|
+
# Only after the exact unified manifest, app/dependency layers, signer
|
|
457
|
+
# binary, archive layout, and build identity are verified may the
|
|
458
|
+
# bootstrap create persistent Fased root state.
|
|
300
459
|
install -d -m 0700 -o root -g root /var/lib/fased-installer /var/lib/fased-installer/releases "$release_parent"
|
|
301
460
|
exec 9>/var/lib/fased-installer/install.lock
|
|
302
461
|
chmod 0600 /var/lib/fased-installer/install.lock
|
|
@@ -335,52 +494,9 @@ if [[ "$install_entry_is_stream" -eq 1 || \
|
|
|
335
494
|
exit 1
|
|
336
495
|
fi
|
|
337
496
|
|
|
338
|
-
local entry=""
|
|
339
|
-
while IFS= read -r entry; do
|
|
340
|
-
entry="${entry%/}"
|
|
341
|
-
if [[ -z "$entry" || "$entry" == /* || "$entry" == *\\* || \
|
|
342
|
-
( "$entry" != "package" && "$entry" != package/* ) || \
|
|
343
|
-
"$entry" == *"/../"* || "$entry" == ../* || "$entry" == */.. || \
|
|
344
|
-
"$entry" == *"/./"* || "$entry" == ./* || "$entry" == */. ]]; then
|
|
345
|
-
echo "Hosted release archive contains an unsafe path: $entry" >&2
|
|
346
|
-
exit 1
|
|
347
|
-
fi
|
|
348
|
-
done < <(tar -tzf "$archive")
|
|
349
|
-
|
|
350
497
|
install -d -m 0700 -o root -g root "$staging/extract"
|
|
351
|
-
|
|
498
|
+
cp -a "$verified_package_root" "$staging/extract/package"
|
|
352
499
|
local package_root="$staging/extract/package"
|
|
353
|
-
[[ -f "$package_root/install.sh" && -f "$package_root/package.json" && ! -L "$package_root/install.sh" ]] || {
|
|
354
|
-
echo "Attested Hosting bundle is incomplete." >&2
|
|
355
|
-
exit 1
|
|
356
|
-
}
|
|
357
|
-
local packaged_version=""
|
|
358
|
-
packaged_version="$(awk -F'"' '/^[[:space:]]*"version"[[:space:]]*:/ { print $4; exit }' "$package_root/package.json")"
|
|
359
|
-
[[ "$packaged_version" == "$release_version" ]] || {
|
|
360
|
-
echo "Attested Hosting bundle version does not match v${release_version}." >&2
|
|
361
|
-
exit 1
|
|
362
|
-
}
|
|
363
|
-
[[ -f "$package_root/dist/build-info.json" && ! -L "$package_root/dist/build-info.json" ]] || {
|
|
364
|
-
echo "Attested Hosting bundle is missing immutable build identity." >&2
|
|
365
|
-
exit 1
|
|
366
|
-
}
|
|
367
|
-
local packaged_commit=""
|
|
368
|
-
local build_info_version=""
|
|
369
|
-
packaged_commit="$(awk -F'"' '/^[[:space:]]*"commit"[[:space:]]*:/ { print $4; exit }' "$package_root/dist/build-info.json")"
|
|
370
|
-
build_info_version="$(awk -F'"' '/^[[:space:]]*"version"[[:space:]]*:/ { print $4; exit }' "$package_root/dist/build-info.json")"
|
|
371
|
-
[[ "$packaged_commit" =~ ^[a-f0-9]{40}$ && "$build_info_version" == "$release_version" ]] || {
|
|
372
|
-
echo "Attested Hosting bundle build identity is invalid or does not match v${release_version}." >&2
|
|
373
|
-
exit 1
|
|
374
|
-
}
|
|
375
|
-
[[ "$packaged_commit" == "$manifest_commit" ]] || {
|
|
376
|
-
echo "Attested Hosting application commit does not match the unified release manifest." >&2
|
|
377
|
-
exit 1
|
|
378
|
-
}
|
|
379
|
-
if find "$package_root" -xdev ! -type f ! -type d -print -quit | grep -q . || \
|
|
380
|
-
find "$package_root" -xdev -type f -links +1 -print -quit | grep -q .; then
|
|
381
|
-
echo "Attested Hosting bundle contains a symlink, special file, or hardlinked regular file." >&2
|
|
382
|
-
exit 1
|
|
383
|
-
fi
|
|
384
500
|
chown -R root:root "$staging"
|
|
385
501
|
chmod -R go-w "$staging"
|
|
386
502
|
if find "$staging" -xdev \( ! -user root -o -perm /022 \) -print -quit | grep -q .; then
|
|
@@ -3956,14 +4072,22 @@ EOF
|
|
|
3956
4072
|
|
|
3957
4073
|
install_fixed_host_gateway_service() {
|
|
3958
4074
|
local target_user="${FASED_INSTALL_USER:-app}"
|
|
4075
|
+
local gateway_user="${FASED_GATEWAY_USER:-fased-gateway}"
|
|
4076
|
+
local gateway_group="${FASED_GATEWAY_GROUP:-fased-gateway}"
|
|
4077
|
+
local config_group="${FASED_CONFIG_GROUP:-fased-config}"
|
|
3959
4078
|
local target_home
|
|
3960
4079
|
target_home="$(getent passwd "$target_user" | cut -d: -f6)"
|
|
3961
4080
|
[[ -n "$target_home" ]] || target_home="/home/$target_user"
|
|
3962
4081
|
local target_repo_dir="${1:-$target_home/fased}"
|
|
3963
|
-
[[ "$target_user" != "root" && "$target_user" =~ ^[A-Za-z0-9_.@-]+$ ]] || {
|
|
3964
|
-
echo "Invalid hosted Gateway
|
|
4082
|
+
[[ "$target_user" != "root" && "$target_user" != "$gateway_user" && "$target_user" =~ ^[A-Za-z0-9_.@-]+$ && "$gateway_user" =~ ^[A-Za-z0-9_.@-]+$ ]] || {
|
|
4083
|
+
echo "Invalid or overlapping hosted operator and Gateway accounts." >&2
|
|
3965
4084
|
exit 1
|
|
3966
4085
|
}
|
|
4086
|
+
|
|
4087
|
+
install -d -m 2770 -o "$target_user" -g "$config_group" "${target_home}/.fased"
|
|
4088
|
+
chgrp -R "$config_group" "${target_home}/.fased"
|
|
4089
|
+
chmod -R g+rwX,o-rwx "${target_home}/.fased"
|
|
4090
|
+
find "${target_home}/.fased" -type d -exec chmod g+s {} +
|
|
3967
4091
|
[[ "$target_repo_dir" == "$target_home/"* && "$target_repo_dir" =~ ^/[A-Za-z0-9_./@-]+$ ]] || {
|
|
3968
4092
|
echo "Hosted Gateway checkout must remain below the app account home." >&2
|
|
3969
4093
|
exit 1
|
|
@@ -3981,8 +4105,9 @@ EOF
|
|
|
3981
4105
|
chown root:root /usr/local/libexec/fased-gateway-launch
|
|
3982
4106
|
chmod 0755 /usr/local/libexec/fased-gateway-launch
|
|
3983
4107
|
|
|
3984
|
-
# The root-owned unit has fixed inputs.
|
|
3985
|
-
#
|
|
4108
|
+
# The root-owned unit has fixed inputs. The non-login Gateway identity can read the
|
|
4109
|
+
# operator-installed runtime and share application configuration through fased-config,
|
|
4110
|
+
# but it is not a member of the restricted signer-operator socket group.
|
|
3986
4111
|
cat >/etc/systemd/system/fased-gateway.service <<EOF
|
|
3987
4112
|
[Unit]
|
|
3988
4113
|
Description=Fased Gateway (managed)
|
|
@@ -3991,19 +4116,21 @@ Wants=fased-signerd.service network-online.target
|
|
|
3991
4116
|
|
|
3992
4117
|
[Service]
|
|
3993
4118
|
Type=simple
|
|
3994
|
-
User=${
|
|
3995
|
-
Group=${
|
|
4119
|
+
User=${gateway_user}
|
|
4120
|
+
Group=${gateway_group}
|
|
4121
|
+
SupplementaryGroups=${config_group}
|
|
3996
4122
|
WorkingDirectory=${target_repo_dir}
|
|
3997
4123
|
Environment=HOME=${target_home}
|
|
3998
4124
|
Environment=FASED_GATEWAY_MODE=managed
|
|
3999
4125
|
Environment=FASED_MANAGED_INTERNAL=1
|
|
4126
|
+
Environment=FASED_GATEWAY_SERVICE=1
|
|
4000
4127
|
Environment=FASED_GATEWAY_PORT=18789
|
|
4001
4128
|
Environment=FASED_HOST_PROFILE=hosting
|
|
4002
4129
|
Environment=FASED_WALLET_LOCAL_SIGNER_SOCKET=/run/fased-signerd/app.sock
|
|
4003
4130
|
ExecStart=/usr/local/libexec/fased-gateway-launch
|
|
4004
4131
|
Restart=always
|
|
4005
4132
|
RestartSec=5
|
|
4006
|
-
UMask=
|
|
4133
|
+
UMask=0007
|
|
4007
4134
|
NoNewPrivileges=true
|
|
4008
4135
|
PrivateTmp=true
|
|
4009
4136
|
PrivateDevices=true
|
|
@@ -4214,8 +4341,15 @@ EOF
|
|
|
4214
4341
|
|
|
4215
4342
|
ensure_host_boundary_accounts() {
|
|
4216
4343
|
local target_user="${FASED_INSTALL_USER:-app}"
|
|
4344
|
+
local gateway_user="${FASED_GATEWAY_USER:-fased-gateway}"
|
|
4217
4345
|
local signer_user="${FASED_SIGNER_USER:-fased-signer}"
|
|
4218
4346
|
local gateway_group="${FASED_GATEWAY_GROUP:-fased-gateway}"
|
|
4347
|
+
local operator_group="${FASED_OPERATOR_GROUP:-fased-operator}"
|
|
4348
|
+
local config_group="${FASED_CONFIG_GROUP:-fased-config}"
|
|
4349
|
+
[[ "$target_user" != "$gateway_user" && "$target_user" != "$signer_user" && "$gateway_user" != "$signer_user" ]] || {
|
|
4350
|
+
echo "Hosting operator, Gateway, and signer accounts must be distinct." >&2
|
|
4351
|
+
exit 1
|
|
4352
|
+
}
|
|
4219
4353
|
if ! id -u "$target_user" >/dev/null 2>&1; then
|
|
4220
4354
|
if need_cmd useradd; then
|
|
4221
4355
|
useradd -m -s /bin/bash "$target_user"
|
|
@@ -4224,6 +4358,15 @@ ensure_host_boundary_accounts() {
|
|
|
4224
4358
|
fi
|
|
4225
4359
|
fi
|
|
4226
4360
|
getent group "$gateway_group" >/dev/null 2>&1 || groupadd --system "$gateway_group"
|
|
4361
|
+
getent group "$operator_group" >/dev/null 2>&1 || groupadd --system "$operator_group"
|
|
4362
|
+
getent group "$config_group" >/dev/null 2>&1 || groupadd --system "$config_group"
|
|
4363
|
+
if ! id -u "$gateway_user" >/dev/null 2>&1; then
|
|
4364
|
+
if need_cmd useradd; then
|
|
4365
|
+
useradd --system --gid "$gateway_group" --home-dir /var/lib/fased-gateway --shell /usr/sbin/nologin "$gateway_user"
|
|
4366
|
+
else
|
|
4367
|
+
adduser --system --ingroup "$gateway_group" --home /var/lib/fased-gateway --shell /usr/sbin/nologin "$gateway_user"
|
|
4368
|
+
fi
|
|
4369
|
+
fi
|
|
4227
4370
|
if ! id -u "$signer_user" >/dev/null 2>&1; then
|
|
4228
4371
|
if need_cmd useradd; then
|
|
4229
4372
|
useradd --system --home-dir /var/lib/fased-signerd --shell /usr/sbin/nologin "$signer_user"
|
|
@@ -4231,8 +4374,13 @@ ensure_host_boundary_accounts() {
|
|
|
4231
4374
|
adduser --system --home /var/lib/fased-signerd --shell /usr/sbin/nologin "$signer_user"
|
|
4232
4375
|
fi
|
|
4233
4376
|
fi
|
|
4377
|
+
usermod -g "$gateway_group" -s /usr/sbin/nologin "$gateway_user"
|
|
4378
|
+
passwd -l "$gateway_user" >/dev/null 2>&1 || true
|
|
4234
4379
|
passwd -l "$signer_user" >/dev/null 2>&1 || true
|
|
4235
|
-
usermod -aG "$
|
|
4380
|
+
usermod -aG "$config_group" "$gateway_user"
|
|
4381
|
+
usermod -aG "$operator_group,$config_group" "$target_user"
|
|
4382
|
+
gpasswd -d "$target_user" "$gateway_group" >/dev/null 2>&1 || true
|
|
4383
|
+
gpasswd -d "$gateway_user" "$operator_group" >/dev/null 2>&1 || true
|
|
4236
4384
|
for admin_group in sudo wheel; do
|
|
4237
4385
|
if getent group "$admin_group" >/dev/null 2>&1; then
|
|
4238
4386
|
gpasswd -d "$target_user" "$admin_group" >/dev/null 2>&1 || true
|
|
@@ -4241,7 +4389,8 @@ ensure_host_boundary_accounts() {
|
|
|
4241
4389
|
rm -f \
|
|
4242
4390
|
"/etc/sudoers.d/fased-install-${target_user}" \
|
|
4243
4391
|
"/etc/sudoers.d/fased-host-maintenance-${target_user}" \
|
|
4244
|
-
"/etc/sudoers.d/fased-gateway-${target_user}-maintenance"
|
|
4392
|
+
"/etc/sudoers.d/fased-gateway-${target_user}-maintenance" \
|
|
4393
|
+
"/etc/sudoers.d/fased-signer-wallet-import-${target_user}"
|
|
4245
4394
|
if need_cmd sudo && runuser -u "$target_user" -- sudo -n true >/dev/null 2>&1; then
|
|
4246
4395
|
echo "Hosting security boundary cannot use an app account with passwordless sudo: $target_user" >&2
|
|
4247
4396
|
echo "Remove custom sudoers access for this dedicated account, then rerun the exact tagged repair from the provider root console." >&2
|
|
@@ -4251,14 +4400,22 @@ ensure_host_boundary_accounts() {
|
|
|
4251
4400
|
|
|
4252
4401
|
install_host_signer_and_updater_services() {
|
|
4253
4402
|
local target_user="${FASED_INSTALL_USER:-app}"
|
|
4403
|
+
local gateway_user="${FASED_GATEWAY_USER:-fased-gateway}"
|
|
4254
4404
|
local signer_user="${FASED_SIGNER_USER:-fased-signer}"
|
|
4255
4405
|
local gateway_group="${FASED_GATEWAY_GROUP:-fased-gateway}"
|
|
4406
|
+
local operator_group="${FASED_OPERATOR_GROUP:-fased-operator}"
|
|
4256
4407
|
local gateway_gid
|
|
4408
|
+
local gateway_uid
|
|
4409
|
+
local operator_uid
|
|
4410
|
+
local signer_uid
|
|
4257
4411
|
local version
|
|
4258
4412
|
gateway_gid="$(getent group "$gateway_group" | cut -d: -f3)"
|
|
4413
|
+
gateway_uid="$(id -u "$gateway_user")"
|
|
4414
|
+
operator_uid="$(id -u "$target_user")"
|
|
4415
|
+
signer_uid="$(id -u "$signer_user")"
|
|
4259
4416
|
version="$(node -p "require(process.argv[1]).version" "$FASED_DIR/package.json" 2>/dev/null || true)"
|
|
4260
|
-
[[ "$gateway_gid" =~ ^[0-9]+$ && "$version" =~ ^[0-9]+\.[0-9]+\.[0-9]+([.-][0-9A-Za-z.-]+)?$ ]] || {
|
|
4261
|
-
echo "Could not resolve hosted signer group or release version." >&2
|
|
4417
|
+
[[ "$gateway_gid" =~ ^[0-9]+$ && "$gateway_uid" =~ ^[0-9]+$ && "$operator_uid" =~ ^[0-9]+$ && "$signer_uid" =~ ^[0-9]+$ && "$version" =~ ^[0-9]+\.[0-9]+\.[0-9]+([.-][0-9A-Za-z.-]+)?$ ]] || {
|
|
4418
|
+
echo "Could not resolve hosted signer principals, socket group, or release version." >&2
|
|
4262
4419
|
exit 1
|
|
4263
4420
|
}
|
|
4264
4421
|
if [[ -n "${FASED_HOST_SIGNER_BINARY:-}" ]]; then
|
|
@@ -4266,6 +4423,19 @@ install_host_signer_and_updater_services() {
|
|
|
4266
4423
|
echo "The root updater must fetch and attest the exact tagged signer artifact." >&2
|
|
4267
4424
|
exit 1
|
|
4268
4425
|
fi
|
|
4426
|
+
local sat_runtime_value=""
|
|
4427
|
+
if [[ -n "${FASED_SAT_PROGRAM_ID:-}${FASED_SAT_BOND_PROGRAM_ID:-}${FASED_SAT_MINT_ADDRESS:-}${FASED_SAT_MINT_PROGRAM_ID:-}" ]]; then
|
|
4428
|
+
for sat_runtime_value in \
|
|
4429
|
+
"${FASED_SAT_PROGRAM_ID:-}" \
|
|
4430
|
+
"${FASED_SAT_BOND_PROGRAM_ID:-}" \
|
|
4431
|
+
"${FASED_SAT_MINT_ADDRESS:-}" \
|
|
4432
|
+
"${FASED_SAT_MINT_PROGRAM_ID:-}"; do
|
|
4433
|
+
[[ "$sat_runtime_value" =~ ^[1-9A-HJ-NP-Za-km-z]{32,44}$ ]] || {
|
|
4434
|
+
echo "Hosted signer SAT runtime requires one complete valid signed-manifest ID tuple." >&2
|
|
4435
|
+
exit 1
|
|
4436
|
+
}
|
|
4437
|
+
done
|
|
4438
|
+
fi
|
|
4269
4439
|
local existing_signer_dropins
|
|
4270
4440
|
existing_signer_dropins="$(systemctl show fased-signerd.service --property=DropInPaths --value 2>/dev/null || true)"
|
|
4271
4441
|
if [[ -n "$existing_signer_dropins" ]]; then
|
|
@@ -4282,6 +4452,7 @@ install_host_signer_and_updater_services() {
|
|
|
4282
4452
|
install -m 0755 -o root -g root "$FASED_DIR/scripts/fased-host-updater.mjs" /usr/local/libexec/fased-host-updater.mjs
|
|
4283
4453
|
install -m 0755 -o root -g root "$FASED_DIR/scripts/fased-host-updaterctl.mjs" /usr/local/libexec/fased-host-updaterctl.mjs
|
|
4284
4454
|
rm -f /usr/local/libexec/fased-host-bootstrapd.mjs /usr/local/libexec/fased-host-bootstrapctl.mjs
|
|
4455
|
+
rm -f /usr/local/sbin/fased-signer-wallet-import
|
|
4285
4456
|
rm -rf /run/fased-host-bootstrap
|
|
4286
4457
|
rm -f /var/log/fased-host-bootstrap.log
|
|
4287
4458
|
install -m 0755 -o root -g root "$FASED_DIR/scripts/migrate-hosted-signer-v2.mjs" /usr/local/libexec/migrate-hosted-signer-v2.mjs
|
|
@@ -4301,6 +4472,20 @@ install_host_signer_and_updater_services() {
|
|
|
4301
4472
|
if [[ ! -f /etc/fased/signerd-webauthn.env ]]; then
|
|
4302
4473
|
install -m 0644 -o root -g root /dev/null /etc/fased/signerd-webauthn.env
|
|
4303
4474
|
fi
|
|
4475
|
+
install -m 0644 -o root -g root /dev/null /etc/fased/signerd-sat-runtime.env
|
|
4476
|
+
if [[ -n "${FASED_SAT_PROGRAM_ID:-}" ]]; then
|
|
4477
|
+
cat >/etc/fased/signerd-sat-runtime.env <<EOF
|
|
4478
|
+
FASED_SAT_PROGRAM_ID=${FASED_SAT_PROGRAM_ID}
|
|
4479
|
+
FASED_SAT_BOND_PROGRAM_ID=${FASED_SAT_BOND_PROGRAM_ID}
|
|
4480
|
+
FASED_SAT_MINT_ADDRESS=${FASED_SAT_MINT_ADDRESS}
|
|
4481
|
+
FASED_SAT_MINT_PROGRAM_ID=${FASED_SAT_MINT_PROGRAM_ID}
|
|
4482
|
+
FASED_SAT_RUNTIME_MANIFEST_PATH=${FASED_SAT_RUNTIME_MANIFEST_PATH:-}
|
|
4483
|
+
FASED_SAT_RUNTIME_MANIFEST_SHA256=${FASED_SAT_RUNTIME_MANIFEST_SHA256:-}
|
|
4484
|
+
FASED_SAT_RUNTIME_MANIFEST_SIGNATURE_PATH=${FASED_SAT_RUNTIME_MANIFEST_SIGNATURE_PATH:-}
|
|
4485
|
+
EOF
|
|
4486
|
+
chown root:root /etc/fased/signerd-sat-runtime.env
|
|
4487
|
+
chmod 0644 /etc/fased/signerd-sat-runtime.env
|
|
4488
|
+
fi
|
|
4304
4489
|
install -d -m 0755 -o root -g root /etc/systemd/system/fased-gateway.service.d
|
|
4305
4490
|
cat >/etc/systemd/system/fased-gateway.service.d/20-fased-update-gate.conf <<'EOF'
|
|
4306
4491
|
[Unit]
|
|
@@ -4390,7 +4575,7 @@ Wants=network-online.target
|
|
|
4390
4575
|
Type=simple
|
|
4391
4576
|
User=${signer_user}
|
|
4392
4577
|
Group=${signer_user}
|
|
4393
|
-
SupplementaryGroups=${gateway_group}
|
|
4578
|
+
SupplementaryGroups=${gateway_group} ${operator_group}
|
|
4394
4579
|
RuntimeDirectory=fased-signerd
|
|
4395
4580
|
RuntimeDirectoryMode=0755
|
|
4396
4581
|
StateDirectory=fased-signerd
|
|
@@ -4398,7 +4583,8 @@ StateDirectoryMode=0700
|
|
|
4398
4583
|
UMask=0077
|
|
4399
4584
|
Environment=HOME=/var/lib/fased-signerd
|
|
4400
4585
|
EnvironmentFile=-/etc/fased/signerd-webauthn.env
|
|
4401
|
-
|
|
4586
|
+
EnvironmentFile=-/etc/fased/signerd-sat-runtime.env
|
|
4587
|
+
ExecStart=/opt/fased/signer/fased-signerd -socket /run/fased-signerd/app.sock -operator-socket /run/fased-signerd/operator.sock -control-socket /run/fased-signerd/control.sock -socket-mode 0660 -socket-group ${gateway_group} -operator-socket-group ${operator_group} -application-uid ${gateway_uid} -operator-uid ${operator_uid} -control-uid ${signer_uid} -state-db /var/lib/fased-signerd/state.db -master-key /var/lib/fased-signerd/master.key -update-gate /var/lib/fased-signer-update-gate/active -pid-file /run/fased-signerd/fased-signerd.pid -audit-log /var/lib/fased-signerd/audit.jsonl
|
|
4402
4588
|
Restart=always
|
|
4403
4589
|
RestartSec=3
|
|
4404
4590
|
NoNewPrivileges=true
|
|
@@ -4443,22 +4629,10 @@ EOF
|
|
|
4443
4629
|
cat <<'EOF'
|
|
4444
4630
|
Hosted signer owner handoff
|
|
4445
4631
|
---------------------------
|
|
4446
|
-
Fresh
|
|
4447
|
-
|
|
4448
|
-
|
|
4449
|
-
|
|
4450
|
-
1. Copy /usr/local/share/fased/signer-policies/network.json.template to a
|
|
4451
|
-
root-owned mode-0600 file, set the exact RPC endpoints, then run:
|
|
4452
|
-
/usr/local/sbin/fased-signer-network --wallet-id <native-id> --network-file /root/fased-network.json
|
|
4453
|
-
2. /usr/local/sbin/fased-signer-enroll [authenticator-label]
|
|
4454
|
-
3. cp /usr/local/share/fased/signer-policies/<role>.json.template /root/fased-<role>-policy.json
|
|
4455
|
-
4. Set walletId to the canonical native signer ID (lowercase, separators become
|
|
4456
|
-
underscores; do not use a different friendly registry ID), replace every
|
|
4457
|
-
REPLACE_WITH_ value, review the exact destinations/caps, then run:
|
|
4458
|
-
chmod 0600 /root/fased-<role>-policy.json
|
|
4459
|
-
/usr/local/sbin/fased-signer-policy --initial-install --policy-file /root/fased-<role>-policy.json
|
|
4460
|
-
|
|
4461
|
-
Copying a template or enrolling a passkey does not enable signing.
|
|
4632
|
+
Fresh wallets receive their versioned Agent, Mining, or Vault baseline from the
|
|
4633
|
+
native signer after the primary RPC is verified. Normal setup does not require a
|
|
4634
|
+
root policy or network helper. Optional approval-device enrollment and advanced
|
|
4635
|
+
custom policy changes remain separate owner operations.
|
|
4462
4636
|
EOF
|
|
4463
4637
|
}
|
|
4464
4638
|
|
|
@@ -4794,6 +4968,11 @@ if [[ -n "${FASED_SAT_PROGRAM_ID:-}" && -n "${FASED_SAT_BOND_PROGRAM_ID:-}" && -
|
|
|
4794
4968
|
persist_managed_env_var "FASED_SAT_BOND_PROGRAM_ID" "$FASED_SAT_BOND_PROGRAM_ID"
|
|
4795
4969
|
persist_managed_env_var "FASED_SAT_MINT_ADDRESS" "$FASED_SAT_MINT_ADDRESS"
|
|
4796
4970
|
persist_managed_env_var "FASED_SAT_MINT_PROGRAM_ID" "$FASED_SAT_MINT_PROGRAM_ID"
|
|
4971
|
+
if [[ -n "${FASED_SAT_RUNTIME_MANIFEST_PATH:-}" && -n "${FASED_SAT_RUNTIME_MANIFEST_SHA256:-}" && -n "${FASED_SAT_RUNTIME_MANIFEST_SIGNATURE_PATH:-}" ]]; then
|
|
4972
|
+
persist_managed_env_var "FASED_SAT_RUNTIME_MANIFEST_PATH" "$FASED_SAT_RUNTIME_MANIFEST_PATH"
|
|
4973
|
+
persist_managed_env_var "FASED_SAT_RUNTIME_MANIFEST_SHA256" "$FASED_SAT_RUNTIME_MANIFEST_SHA256"
|
|
4974
|
+
persist_managed_env_var "FASED_SAT_RUNTIME_MANIFEST_SIGNATURE_PATH" "$FASED_SAT_RUNTIME_MANIFEST_SIGNATURE_PATH"
|
|
4975
|
+
fi
|
|
4797
4976
|
else
|
|
4798
4977
|
:
|
|
4799
4978
|
fi
|