@poolzin/pool-bot 2026.2.24 → 2026.2.26
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 +21 -0
- package/dist/acp/client.js +207 -18
- package/dist/acp/event-mapper.js +87 -22
- package/dist/acp/meta.js +12 -6
- package/dist/acp/secret-file.js +22 -0
- package/dist/agents/agent-paths.js +8 -9
- package/dist/agents/agent-scope.js +17 -5
- package/dist/agents/auth-profiles/oauth.js +148 -64
- package/dist/agents/auth-profiles/session-override.js +13 -7
- package/dist/agents/bash-process-registry.test-helpers.js +29 -0
- package/dist/agents/bash-tools.exec-approval-request.js +20 -0
- package/dist/agents/bash-tools.exec-host-gateway.js +240 -0
- package/dist/agents/bash-tools.exec-host-node.js +235 -0
- package/dist/agents/bash-tools.exec-runtime.js +2 -25
- package/dist/agents/bash-tools.exec-types.js +1 -0
- package/dist/agents/bash-tools.process.js +224 -218
- package/dist/agents/bedrock-discovery.js +3 -1
- package/dist/agents/byteplus-models.js +97 -0
- package/dist/agents/chutes-oauth.js +1 -0
- package/dist/agents/cli-runner/helpers.js +4 -0
- package/dist/agents/compaction.js +41 -14
- package/dist/agents/content-blocks.js +16 -0
- package/dist/agents/doubao-models.js +121 -0
- package/dist/agents/failover-error.js +2 -0
- package/dist/agents/huggingface-models.js +5 -3
- package/dist/agents/live-model-filter.js +5 -0
- package/dist/agents/minimax-vlm.js +10 -8
- package/dist/agents/model-auth.js +6 -0
- package/dist/agents/model-catalog.js +3 -1
- package/dist/agents/model-fallback.js +96 -101
- package/dist/agents/model-selection.js +7 -1
- package/dist/agents/models-config.providers.js +364 -165
- package/dist/agents/ollama-stream.js +117 -4
- package/dist/agents/opencode-zen-models.js +22 -11
- package/dist/agents/pi-embedded-helpers/errors.js +55 -33
- package/dist/agents/pi-embedded-helpers/messaging-dedupe.js +10 -5
- package/dist/agents/pi-embedded-helpers/thinking.js +10 -5
- package/dist/agents/pi-embedded-helpers.js +1 -1
- package/dist/agents/pi-embedded-payloads.js +1 -0
- package/dist/agents/pi-embedded-runner/compact.js +29 -7
- package/dist/agents/pi-embedded-runner/extensions.js +28 -26
- package/dist/agents/pi-embedded-runner/google.js +20 -8
- package/dist/agents/pi-embedded-runner/run/attempt.js +95 -36
- package/dist/agents/pi-embedded-runner/run.js +71 -12
- package/dist/agents/pi-embedded-runner/run.overflow-compaction.fixture.js +34 -0
- package/dist/agents/pi-embedded-runner/run.overflow-compaction.mocks.shared.js +11 -2
- package/dist/agents/pi-embedded-runner/session-manager-cache.js +11 -7
- package/dist/agents/pi-embedded-runner/system-prompt.js +2 -0
- package/dist/agents/pi-embedded-runner/thinking.js +42 -0
- package/dist/agents/pi-embedded-runner/tool-name-allowlist.js +19 -0
- package/dist/agents/pi-embedded-runner/utils.js +7 -10
- package/dist/agents/pi-embedded-subscribe.handlers.lifecycle.js +45 -56
- package/dist/agents/pi-embedded-subscribe.handlers.tools.js +2 -2
- package/dist/agents/pi-embedded-subscribe.js +9 -4
- package/dist/agents/pi-embedded-subscribe.tools.js +68 -14
- package/dist/agents/pi-embedded-utils.js +3 -0
- package/dist/agents/pi-extensions/compaction-safeguard-runtime.js +4 -20
- package/dist/agents/pi-extensions/compaction-safeguard.js +75 -33
- package/dist/agents/pi-settings.js +40 -0
- package/dist/agents/pi-tools.policy.js +2 -1
- package/dist/agents/provider/config-loader.js +1 -1
- package/dist/agents/sandbox/browser.js +170 -33
- package/dist/agents/sandbox/config-hash.js +14 -27
- package/dist/agents/sandbox/config.js +21 -2
- package/dist/agents/sandbox/constants.js +2 -0
- package/dist/agents/sandbox/docker.js +16 -2
- package/dist/agents/sandbox/novnc-auth.js +62 -0
- package/dist/agents/sandbox/sanitize-env-vars.js +1 -1
- package/dist/agents/sandbox/shared.js +10 -6
- package/dist/agents/sandbox-paths.js +24 -11
- package/dist/agents/schema/clean-for-gemini.js +132 -85
- package/dist/agents/session-slug.js +10 -5
- package/dist/agents/session-tool-result-guard-wrapper.js +1 -0
- package/dist/agents/session-tool-result-guard.js +3 -1
- package/dist/agents/session-transcript-repair.js +40 -6
- package/dist/agents/skills/bundled-dir.js +19 -5
- package/dist/agents/skills/env-overrides.js +124 -43
- package/dist/agents/skills/frontmatter.js +6 -6
- package/dist/agents/skills/plugin-skills.js +14 -7
- package/dist/agents/skills/workspace.js +1 -0
- package/dist/agents/skills.test-helpers.js +13 -0
- package/dist/agents/stable-stringify.js +12 -0
- package/dist/agents/subagent-announce.js +251 -49
- package/dist/agents/subagent-lifecycle-events.js +19 -0
- package/dist/agents/subagent-registry-cleanup.js +31 -0
- package/dist/agents/subagent-registry-completion.js +68 -0
- package/dist/agents/subagent-registry-queries.js +117 -0
- package/dist/agents/subagent-registry-state.js +46 -0
- package/dist/agents/subagent-registry.js +252 -221
- package/dist/agents/subagent-registry.mocks.shared.js +12 -0
- package/dist/agents/subagent-registry.store.js +1 -0
- package/dist/agents/subagent-registry.types.js +1 -0
- package/dist/agents/subagent-spawn.js +195 -7
- package/dist/agents/system-prompt.js +22 -6
- package/dist/agents/test-helpers/assistant-message-fixtures.js +29 -0
- package/dist/agents/test-helpers/fast-coding-tools.js +1 -18
- package/dist/agents/test-helpers/fast-core-tools.js +1 -17
- package/dist/agents/test-helpers/pi-tools-sandbox-context.js +27 -0
- package/dist/agents/timeout.js +18 -6
- package/dist/agents/tool-call-id.js +1 -1
- package/dist/agents/tool-display-common.js +162 -29
- package/dist/agents/tool-images.js +82 -9
- package/dist/agents/tool-policy-shared.js +108 -0
- package/dist/agents/tool-policy.js +51 -26
- package/dist/agents/tools/browser-tool.js +160 -54
- package/dist/agents/tools/canvas-tool.js +27 -1
- package/dist/agents/tools/common.js +45 -0
- package/dist/agents/tools/cron-tool.test-helpers.js +12 -0
- package/dist/agents/tools/discord-actions-guild.js +4 -1
- package/dist/agents/tools/discord-actions-moderation-shared.js +27 -0
- package/dist/agents/tools/gateway-tool.js +3 -1
- package/dist/agents/tools/image-tool.js +214 -99
- package/dist/agents/tools/nodes-utils.js +1 -10
- package/dist/agents/tools/sessions-history-tool.js +140 -108
- package/dist/agents/tools/sessions-send-helpers.js +12 -6
- package/dist/agents/tools/sessions-spawn-tool.js +8 -2
- package/dist/agents/tools/subagents-tool.js +2 -1
- package/dist/agents/tools/whatsapp-actions.js +10 -2
- package/dist/agents/tools/whatsapp-target-auth.js +18 -0
- package/dist/agents/transcript-policy.js +22 -8
- package/dist/agents/venice-models.js +11 -3
- package/dist/agents/workspace.js +222 -46
- package/dist/auto-reply/commands-registry.data.js +51 -0
- package/dist/auto-reply/commands-registry.js +19 -21
- package/dist/auto-reply/fallback-state.js +114 -0
- package/dist/auto-reply/group-activation.js +10 -5
- package/dist/auto-reply/inbound-debounce.js +10 -5
- package/dist/auto-reply/model-runtime.js +68 -0
- package/dist/auto-reply/reply/abort.js +1 -1
- package/dist/auto-reply/reply/agent-runner-execution.js +40 -5
- package/dist/auto-reply/reply/agent-runner.js +165 -39
- package/dist/auto-reply/reply/bash-command.js +41 -39
- package/dist/auto-reply/reply/command-gates.js +25 -0
- package/dist/auto-reply/reply/commands-allowlist.js +111 -72
- package/dist/auto-reply/reply/commands-bash.js +6 -5
- package/dist/auto-reply/reply/commands-config.js +30 -28
- package/dist/auto-reply/reply/commands-core.js +2 -1
- package/dist/auto-reply/reply/commands-info.js +1 -0
- package/dist/auto-reply/reply/commands-models.js +65 -14
- package/dist/auto-reply/reply/commands-session.js +237 -82
- package/dist/auto-reply/reply/commands-setunset-standard.js +13 -0
- package/dist/auto-reply/reply/commands-setunset.js +45 -0
- package/dist/auto-reply/reply/commands-subagents/action-agents.js +44 -0
- package/dist/auto-reply/reply/commands-subagents/action-focus.js +64 -0
- package/dist/auto-reply/reply/commands-subagents/action-help.js +4 -0
- package/dist/auto-reply/reply/commands-subagents/action-info.js +45 -0
- package/dist/auto-reply/reply/commands-subagents/action-kill.js +60 -0
- package/dist/auto-reply/reply/commands-subagents/action-list.js +44 -0
- package/dist/auto-reply/reply/commands-subagents/action-log.js +29 -0
- package/dist/auto-reply/reply/commands-subagents/action-send.js +119 -0
- package/dist/auto-reply/reply/commands-subagents/action-spawn.js +52 -0
- package/dist/auto-reply/reply/commands-subagents/action-unfocus.js +30 -0
- package/dist/auto-reply/reply/commands-subagents/shared.js +303 -0
- package/dist/auto-reply/reply/commands-subagents.js +51 -587
- package/dist/auto-reply/reply/commands-tts.js +10 -5
- package/dist/auto-reply/reply/config-value.js +10 -5
- package/dist/auto-reply/reply/directive-handling.model-picker.js +12 -6
- package/dist/auto-reply/reply/directive-handling.persist.js +9 -21
- package/dist/auto-reply/reply/directive-handling.shared.js +24 -4
- package/dist/auto-reply/reply/followup-runner.js +1 -0
- package/dist/auto-reply/reply/get-reply-directives-utils.js +23 -14
- package/dist/auto-reply/reply/get-reply-directives.js +17 -28
- package/dist/auto-reply/reply/get-reply-inline-actions.js +1 -0
- package/dist/auto-reply/reply/get-reply.js +71 -12
- package/dist/auto-reply/reply/model-selection.js +80 -39
- package/dist/auto-reply/reply/queue/enqueue.js +10 -5
- package/dist/auto-reply/reply/queue/state.js +13 -12
- package/dist/auto-reply/reply/reply-payloads.js +67 -36
- package/dist/auto-reply/reply/reply-reference.js +9 -8
- package/dist/auto-reply/reply/route-reply.js +15 -8
- package/dist/auto-reply/reply/session-reset-prompt.js +1 -1
- package/dist/auto-reply/reply/session.js +22 -6
- package/dist/auto-reply/reply/strip-inbound-meta.js +147 -0
- package/dist/auto-reply/reply/subagents-utils.js +56 -30
- package/dist/auto-reply/reply/typing.js +46 -21
- package/dist/auto-reply/send-policy.js +14 -7
- package/dist/auto-reply/status.js +140 -16
- package/dist/auto-reply/templating.js +10 -5
- package/dist/auto-reply/thinking.js +7 -16
- package/dist/auto-reply/tokens.js +21 -5
- package/dist/browser/bridge-server.js +36 -20
- package/dist/browser/cdp.helpers.js +7 -14
- package/dist/browser/cdp.js +35 -15
- package/dist/browser/chrome.profile-decoration.js +7 -4
- package/dist/browser/config.js +30 -0
- package/dist/browser/extension-relay-auth.js +55 -0
- package/dist/browser/extension-relay.js +74 -29
- package/dist/browser/navigation-guard.js +39 -0
- package/dist/browser/paths.js +77 -0
- package/dist/browser/profiles.js +13 -8
- package/dist/browser/pw-ai-module.js +10 -5
- package/dist/browser/pw-session.js +76 -39
- package/dist/browser/pw-tools-core.interactions.js +14 -7
- package/dist/browser/pw-tools-core.state.js +12 -6
- package/dist/browser/routes/agent.act.js +431 -424
- package/dist/browser/routes/agent.shared.js +47 -3
- package/dist/browser/routes/agent.snapshot.js +122 -116
- package/dist/browser/routes/agent.storage.js +303 -297
- package/dist/browser/routes/tabs.js +154 -100
- package/dist/browser/server-context.js +7 -0
- package/dist/browser/server-lifecycle.js +37 -0
- package/dist/build-info.json +3 -3
- package/dist/channels/allow-from.js +26 -0
- package/dist/channels/allowlists/resolve-utils.js +43 -19
- package/dist/channels/channel-config.js +14 -7
- package/dist/channels/draft-stream-loop.js +7 -0
- package/dist/channels/model-overrides.js +82 -0
- package/dist/channels/plugins/account-action-gate.js +13 -0
- package/dist/channels/plugins/message-actions.js +10 -0
- package/dist/channels/plugins/normalize/imessage.js +14 -7
- package/dist/channels/plugins/normalize/slack.js +10 -5
- package/dist/channels/plugins/normalize/telegram.js +14 -7
- package/dist/channels/plugins/outbound/discord.js +80 -8
- package/dist/channels/plugins/outbound/signal.js +11 -11
- package/dist/channels/plugins/setup-helpers.js +10 -5
- package/dist/channels/sender-label.js +14 -7
- package/dist/channels/session.js +4 -2
- package/dist/channels/status-reactions.js +297 -0
- package/dist/channels/telegram/api.js +18 -0
- package/dist/cli/argv.js +84 -21
- package/dist/cli/banner.js +3 -2
- package/dist/cli/browser-cli-actions-input/register.files-downloads.js +65 -56
- package/dist/cli/cli-name.js +11 -11
- package/dist/cli/cli-utils.js +13 -3
- package/dist/cli/command-format.js +1 -1
- package/dist/cli/config-cli.js +1 -1
- package/dist/cli/daemon-cli/lifecycle-core.js +31 -19
- package/dist/cli/daemon-cli/lifecycle.js +64 -2
- package/dist/cli/daemon-cli/restart-health.js +126 -0
- package/dist/cli/daemon-cli/status.gather.js +9 -13
- package/dist/cli/daemon-cli/status.print.js +2 -10
- package/dist/cli/deps.js +27 -22
- package/dist/cli/exec-approvals-cli.js +92 -124
- package/dist/cli/gateway-cli/run-loop.js +23 -5
- package/dist/cli/memory-cli.js +158 -61
- package/dist/cli/node-cli/register.js +14 -5
- package/dist/cli/nodes-cli/register.push.js +63 -0
- package/dist/cli/nodes-media-utils.js +26 -0
- package/dist/cli/outbound-send-deps.js +2 -9
- package/dist/cli/outbound-send-mapping.js +11 -0
- package/dist/cli/pairing-cli.js +40 -14
- package/dist/cli/plugins-cli.js +250 -73
- package/dist/cli/ports.js +11 -10
- package/dist/cli/program/build-program.js +3 -1
- package/dist/cli/program/command-registry.js +214 -136
- package/dist/cli/program/command-tree.js +16 -0
- package/dist/cli/program/help.js +43 -12
- package/dist/cli/program/preaction.js +13 -9
- package/dist/cli/program/register.configure.js +3 -18
- package/dist/cli/program/register.maintenance.js +2 -2
- package/dist/cli/program/register.onboard.js +2 -0
- package/dist/cli/program/register.status-health-sessions.js +16 -17
- package/dist/cli/program/register.subclis.js +93 -52
- package/dist/cli/route.js +12 -8
- package/dist/cli/system-cli.js +36 -46
- package/dist/cli/test-runtime-capture.js +24 -0
- package/dist/cli/update-cli/shared.js +22 -9
- package/dist/cli/update-cli/update-command.js +89 -14
- package/dist/cli/update-cli/wizard.js +6 -12
- package/dist/commands/agent/run-context.js +18 -5
- package/dist/commands/agent/session-store.js +17 -4
- package/dist/commands/agent.js +185 -89
- package/dist/commands/agents.bindings.js +14 -7
- package/dist/commands/agents.commands.add.js +13 -9
- package/dist/commands/agents.commands.identity.js +12 -6
- package/dist/commands/agents.commands.list.js +11 -6
- package/dist/commands/agents.config.js +8 -10
- package/dist/commands/agents.providers.js +12 -6
- package/dist/commands/auth-choice-options.js +103 -75
- package/dist/commands/auth-choice.apply.byteplus.js +55 -0
- package/dist/commands/auth-choice.apply.js +4 -0
- package/dist/commands/auth-choice.apply.minimax.js +61 -13
- package/dist/commands/auth-choice.apply.openai.js +3 -1
- package/dist/commands/auth-choice.apply.volcengine.js +55 -0
- package/dist/commands/auth-choice.preferred-provider.js +2 -0
- package/dist/commands/channels/remove.js +13 -6
- package/dist/commands/channels/shared.js +4 -14
- package/dist/commands/channels.mock-harness.js +23 -0
- package/dist/commands/configure.commands.js +14 -0
- package/dist/commands/configure.gateway.js +2 -4
- package/dist/commands/configure.js +1 -1
- package/dist/commands/configure.shared.js +11 -0
- package/dist/commands/daemon-install-helpers.js +2 -2
- package/dist/commands/daemon-install-runtime-warning.js +11 -0
- package/dist/commands/dashboard.js +12 -10
- package/dist/commands/docs.js +14 -8
- package/dist/commands/doctor-config-flow.js +11 -9
- package/dist/commands/doctor-legacy-config.js +281 -0
- package/dist/commands/doctor-state-integrity.js +99 -23
- package/dist/commands/doctor-update.js +12 -9
- package/dist/commands/models/list.list-command.js +7 -5
- package/dist/commands/models/set-image.js +2 -21
- package/dist/commands/node-daemon-install-helpers.js +10 -8
- package/dist/commands/onboard-auth.config-minimax.js +54 -80
- package/dist/commands/onboard-auth.config-opencode.js +2 -18
- package/dist/commands/onboard-auth.credentials.js +90 -13
- package/dist/commands/onboard-auth.js +1 -1
- package/dist/commands/onboard-auth.models.js +6 -5
- package/dist/commands/onboard-hooks.js +1 -1
- package/dist/commands/onboard-non-interactive/api-keys.js +14 -7
- package/dist/commands/onboard-non-interactive/local/auth-choice.js +64 -49
- package/dist/commands/onboard-provider-auth-flags.js +14 -0
- package/dist/commands/onboard-remote.js +14 -7
- package/dist/commands/onboard.js +11 -13
- package/dist/commands/sandbox-display.js +6 -5
- package/dist/commands/sessions.test-helpers.js +61 -0
- package/dist/commands/status-all/diagnosis.js +14 -10
- package/dist/commands/status-all/format.js +1 -0
- package/dist/commands/status.gateway-probe.js +1 -16
- package/dist/commands/systemd-linger.js +12 -6
- package/dist/config/agent-limits.js +2 -0
- package/dist/config/commands.js +32 -15
- package/dist/config/config-paths.js +9 -11
- package/dist/config/config.js +1 -1
- package/dist/config/defaults.js +22 -2
- package/dist/config/discord-preview-streaming.js +104 -0
- package/dist/config/env-substitution.js +62 -34
- package/dist/config/env-vars.js +45 -7
- package/dist/config/includes.js +4 -0
- package/dist/config/io.js +656 -171
- package/dist/config/legacy.migrations.part-1.js +189 -78
- package/dist/config/legacy.shared.js +3 -1
- package/dist/config/merge-patch.js +54 -4
- package/dist/config/prototype-keys.js +4 -0
- package/dist/config/redact-snapshot.js +404 -76
- package/dist/config/schema.help.js +44 -7
- package/dist/config/schema.js +58 -570
- package/dist/config/schema.labels.js +38 -6
- package/dist/config/sessions/delivery-info.js +10 -3
- package/dist/config/sessions/main-session.js +10 -5
- package/dist/config/sessions/session-file.js +33 -0
- package/dist/config/sessions/session-key.js +10 -5
- package/dist/config/sessions/store.js +1 -1
- package/dist/config/sessions.js +1 -0
- package/dist/config/validation.js +140 -85
- package/dist/config/zod-schema.agent-runtime.js +11 -0
- package/dist/config/zod-schema.hooks.js +40 -11
- package/dist/config/zod-schema.installs.js +20 -0
- package/dist/config/zod-schema.js +156 -20
- package/dist/config/zod-schema.providers-core.js +78 -4
- package/dist/config/zod-schema.providers.js +6 -1
- package/dist/config/zod-schema.session.js +41 -2
- package/dist/cron/run-log.js +3 -0
- package/dist/cron/schedule.js +21 -10
- package/dist/cron/service/ops.js +35 -21
- package/dist/cron/service/timer.js +116 -16
- package/dist/cron/stagger.js +3 -1
- package/dist/daemon/cmd-argv.js +21 -0
- package/dist/daemon/cmd-set.js +58 -0
- package/dist/daemon/service-types.js +1 -0
- package/dist/discord/api.js +12 -6
- package/dist/discord/draft-chunking.js +22 -0
- package/dist/discord/draft-stream.js +124 -0
- package/dist/discord/monitor/agent-components.js +1 -1
- package/dist/discord/monitor/commands.js +5 -0
- package/dist/discord/monitor/exec-approvals.js +357 -162
- package/dist/discord/monitor/gateway-plugin.js +2 -1
- package/dist/discord/monitor/listeners.js +37 -27
- package/dist/discord/monitor/message-handler.js +4 -1
- package/dist/discord/monitor/message-handler.preflight.js +65 -8
- package/dist/discord/monitor/message-handler.process.js +246 -217
- package/dist/discord/monitor/message-utils.js +143 -6
- package/dist/discord/monitor/model-picker-preferences.js +143 -0
- package/dist/discord/monitor/model-picker.js +651 -0
- package/dist/discord/monitor/native-command.js +573 -16
- package/dist/discord/monitor/provider.allowlist.js +223 -0
- package/dist/discord/monitor/provider.js +275 -347
- package/dist/discord/monitor/provider.lifecycle.js +100 -0
- package/dist/discord/monitor/reply-delivery.js +123 -16
- package/dist/discord/monitor/thread-bindings.discord-api.js +215 -0
- package/dist/discord/monitor/thread-bindings.js +4 -0
- package/dist/discord/monitor/thread-bindings.lifecycle.js +177 -0
- package/dist/discord/monitor/thread-bindings.manager.js +423 -0
- package/dist/discord/monitor/thread-bindings.messages.js +55 -0
- package/dist/discord/monitor/thread-bindings.state.js +358 -0
- package/dist/discord/monitor/thread-bindings.types.js +6 -0
- package/dist/discord/resolve-users.js +33 -21
- package/dist/discord/send.channels.js +15 -0
- package/dist/discord/send.js +3 -2
- package/dist/discord/send.outbound.js +82 -26
- package/dist/discord/send.permissions.js +83 -30
- package/dist/discord/send.reactions.js +8 -4
- package/dist/discord/token.js +10 -5
- package/dist/discord/voice/command.js +263 -0
- package/dist/discord/voice/manager.js +531 -0
- package/dist/gateway/auth.js +72 -13
- package/dist/gateway/call.js +152 -83
- package/dist/gateway/canvas-capability.js +75 -0
- package/dist/gateway/client.js +28 -4
- package/dist/gateway/config-reload.js +3 -4
- package/dist/gateway/control-plane-audit.js +28 -0
- package/dist/gateway/control-plane-rate-limit.js +53 -0
- package/dist/gateway/control-ui.js +219 -96
- package/dist/gateway/events.js +1 -0
- package/dist/gateway/hooks-mapping.js +88 -38
- package/dist/gateway/hooks.js +109 -54
- package/dist/gateway/http-auth-helpers.js +3 -2
- package/dist/gateway/http-common.js +22 -0
- package/dist/gateway/http-endpoint-helpers.js +1 -0
- package/dist/gateway/method-scopes.js +169 -0
- package/dist/gateway/net.js +74 -9
- package/dist/gateway/node-invoke-system-run-approval.js +14 -35
- package/dist/gateway/node-registry.js +10 -5
- package/dist/gateway/openai-http.js +1 -0
- package/dist/gateway/openresponses-http.js +121 -110
- package/dist/gateway/origin-check.js +1 -18
- package/dist/gateway/probe-auth.js +2 -0
- package/dist/gateway/protocol/index.js +4 -2
- package/dist/gateway/protocol/schema/cron.js +1 -0
- package/dist/gateway/protocol/schema/devices.js +1 -0
- package/dist/gateway/protocol/schema/protocol-schemas.js +4 -1
- package/dist/gateway/protocol/schema/push.js +18 -0
- package/dist/gateway/protocol/schema/sessions.js +6 -0
- package/dist/gateway/protocol/schema.js +1 -0
- package/dist/gateway/role-policy.js +17 -0
- package/dist/gateway/server/ws-connection/connect-policy.js +37 -0
- package/dist/gateway/server/ws-connection/message-handler.js +175 -148
- package/dist/gateway/server-chat.js +83 -25
- package/dist/gateway/server-constants.js +10 -9
- package/dist/gateway/server-cron.js +1 -0
- package/dist/gateway/server-http.js +247 -54
- package/dist/gateway/server-maintenance.js +20 -5
- package/dist/gateway/server-methods/agent.js +162 -24
- package/dist/gateway/server-methods/chat.js +465 -130
- package/dist/gateway/server-methods/config.js +193 -152
- package/dist/gateway/server-methods/devices.js +17 -3
- package/dist/gateway/server-methods/models.js +11 -1
- package/dist/gateway/server-methods/nodes.helpers.js +12 -0
- package/dist/gateway/server-methods/nodes.js +251 -69
- package/dist/gateway/server-methods/push.js +53 -0
- package/dist/gateway/server-methods/sessions.js +64 -8
- package/dist/gateway/server-methods/usage.js +162 -75
- package/dist/gateway/server-node-events.js +29 -0
- package/dist/gateway/server-reload-handlers.js +2 -3
- package/dist/gateway/server-runtime-config.js +39 -13
- package/dist/gateway/server-runtime-state.js +2 -0
- package/dist/gateway/server-startup-memory.js +17 -11
- package/dist/gateway/server-ws-runtime.js +1 -0
- package/dist/gateway/server.impl.js +296 -139
- package/dist/gateway/session-preview.test-helpers.js +11 -0
- package/dist/gateway/session-utils.fs.js +32 -34
- package/dist/gateway/sessions-resolve.js +17 -5
- package/dist/gateway/startup-auth.js +126 -0
- package/dist/gateway/test-helpers.agent-results.js +15 -0
- package/dist/gateway/test-helpers.mocks.js +37 -14
- package/dist/gateway/test-helpers.openai-mock.js +14 -7
- package/dist/gateway/test-helpers.server.js +161 -77
- package/dist/gateway/tools-invoke-http.js +21 -10
- package/dist/hooks/bundled/bootstrap-extra-files/handler.js +3 -1
- package/dist/hooks/bundled/command-logger/handler.js +7 -2
- package/dist/hooks/bundled/session-memory/handler.js +170 -38
- package/dist/hooks/frontmatter.js +6 -6
- package/dist/hooks/gmail-watcher-lifecycle.js +23 -0
- package/dist/hooks/gmail-watcher.js +11 -6
- package/dist/hooks/internal-hooks.js +11 -1
- package/dist/hooks/llm-slug-generator.js +4 -1
- package/dist/hooks/workspace.js +47 -17
- package/dist/imessage/accounts.js +9 -20
- package/dist/imessage/monitor/inbound-processing.js +2 -1
- package/dist/infra/archive-path.js +49 -0
- package/dist/infra/archive.js +174 -73
- package/dist/infra/control-ui-assets.js +14 -6
- package/dist/infra/device-pairing.js +204 -144
- package/dist/infra/env.js +10 -5
- package/dist/infra/exec-approvals-allowlist.js +141 -70
- package/dist/infra/exec-approvals-analysis.js +78 -20
- package/dist/infra/exec-approvals.js +5 -17
- package/dist/infra/exec-safe-bin-policy.js +277 -0
- package/dist/infra/fixed-window-rate-limit.js +33 -0
- package/dist/infra/fs-safe.js +71 -39
- package/dist/infra/gateway-lock.js +6 -2
- package/dist/infra/git-root.js +61 -0
- package/dist/infra/heartbeat-active-hours.js +2 -2
- package/dist/infra/heartbeat-reason.js +40 -0
- package/dist/infra/heartbeat-runner.js +72 -32
- package/dist/infra/heartbeat-wake.js +6 -12
- package/dist/infra/host-env-security-policy.json +19 -0
- package/dist/infra/host-env-security.js +66 -0
- package/dist/infra/install-source-utils.js +91 -7
- package/dist/infra/net/ssrf.js +131 -38
- package/dist/infra/node-pairing.js +50 -105
- package/dist/infra/npm-integrity.js +45 -0
- package/dist/infra/npm-pack-install.js +40 -0
- package/dist/infra/outbound/bound-delivery-router.js +88 -0
- package/dist/infra/outbound/channel-adapters.js +20 -7
- package/dist/infra/outbound/channel-selection.js +12 -6
- package/dist/infra/outbound/envelope.js +1 -1
- package/dist/infra/outbound/format.js +12 -6
- package/dist/infra/outbound/message-action-runner.js +107 -327
- package/dist/infra/outbound/message.js +59 -36
- package/dist/infra/outbound/outbound-policy.js +52 -25
- package/dist/infra/outbound/outbound-send-service.js +58 -71
- package/dist/infra/outbound/payloads.js +14 -7
- package/dist/infra/outbound/session-binding-service.js +123 -0
- package/dist/infra/pairing-files.js +10 -0
- package/dist/infra/path-guards.js +25 -0
- package/dist/infra/plain-object.js +9 -0
- package/dist/infra/provider-usage.fetch.codex.js +7 -15
- package/dist/infra/provider-usage.fetch.gemini.js +14 -11
- package/dist/infra/provider-usage.fetch.shared.js +30 -1
- package/dist/infra/provider-usage.fetch.zai.js +10 -9
- package/dist/infra/push-apns.js +365 -0
- package/dist/infra/restart-sentinel.js +16 -1
- package/dist/infra/restart.js +229 -26
- package/dist/infra/retry-policy.js +4 -2
- package/dist/infra/retry.js +9 -5
- package/dist/infra/scp-host.js +54 -0
- package/dist/infra/session-cost-usage.js +107 -59
- package/dist/infra/session-maintenance-warning.js +3 -1
- package/dist/infra/shell-env.js +98 -34
- package/dist/infra/ssh-config.js +12 -6
- package/dist/infra/system-run-command.js +49 -4
- package/dist/infra/update-channels.js +10 -5
- package/dist/infra/update-startup.js +86 -9
- package/dist/line/accounts.js +5 -7
- package/dist/line/bot-access.js +8 -20
- package/dist/line/bot-handlers.js +3 -1
- package/dist/link-understanding/detect.js +15 -7
- package/dist/media/constants.js +15 -6
- package/dist/media/image-ops.js +7 -0
- package/dist/media/inbound-path-policy.js +114 -0
- package/dist/media/input-files.js +16 -0
- package/dist/media/local-roots.js +3 -2
- package/dist/media-understanding/apply.js +4 -1
- package/dist/media-understanding/concurrency.js +8 -20
- package/dist/memory/backend-config.js +45 -6
- package/dist/memory/embeddings.js +10 -4
- package/dist/memory/fs-utils.js +23 -0
- package/dist/memory/manager-search.js +12 -6
- package/dist/memory/manager-sync-ops.js +12 -2
- package/dist/memory/qmd-manager.js +466 -53
- package/dist/memory/query-expansion.js +167 -3
- package/dist/memory/status-format.js +10 -5
- package/dist/memory/sync-memory-files.js +1 -1
- package/dist/memory/test-manager.js +8 -0
- package/dist/node-host/invoke-system-run.js +281 -0
- package/dist/node-host/invoke.js +55 -337
- package/dist/pairing/pairing-store.js +22 -0
- package/dist/plugin-sdk/allow-from.js +1 -1
- package/dist/plugin-sdk/command-auth.js +3 -1
- package/dist/plugin-sdk/index.js +6 -3
- package/dist/plugin-sdk/temp-path.js +47 -0
- package/dist/plugin-sdk/webhook-targets.js +32 -0
- package/dist/plugins/bundled-dir.js +9 -6
- package/dist/plugins/discovery.js +217 -23
- package/dist/plugins/hook-runner-global.js +16 -0
- package/dist/plugins/hooks.js +50 -0
- package/dist/plugins/install.js +28 -16
- package/dist/plugins/loader.js +192 -26
- package/dist/plugins/logger.js +8 -0
- package/dist/plugins/manifest-registry.js +3 -0
- package/dist/plugins/path-safety.js +34 -0
- package/dist/plugins/registry.js +5 -2
- package/dist/plugins/runtime/index.js +271 -206
- package/dist/plugins/runtime.js +3 -17
- package/dist/plugins/update.js +78 -12
- package/dist/process/spawn-utils.js +14 -7
- package/dist/providers/github-copilot-models.js +4 -1
- package/dist/providers/github-copilot-token.js +11 -6
- package/dist/providers/qwen-portal-oauth.js +14 -6
- package/dist/routing/account-id.js +30 -0
- package/dist/routing/resolve-route.js +3 -7
- package/dist/routing/session-key.js +2 -16
- package/dist/security/audit-channel.js +100 -20
- package/dist/security/audit-extra.async.js +505 -179
- package/dist/security/audit-extra.js +12 -2
- package/dist/security/audit-extra.sync.js +421 -35
- package/dist/security/audit-fs.js +31 -13
- package/dist/security/audit.js +180 -370
- package/dist/security/dm-policy-shared.js +68 -0
- package/dist/security/external-content.js +46 -14
- package/dist/security/fix.js +49 -85
- package/dist/security/scan-paths.js +20 -0
- package/dist/security/secret-equal.js +3 -7
- package/dist/security/windows-acl.js +30 -15
- package/dist/shared/entry-status.js +6 -0
- package/dist/shared/frontmatter.js +5 -5
- package/dist/shared/node-list-parse.js +13 -0
- package/dist/shared/node-match.js +11 -4
- package/dist/shared/operator-scope-compat.js +42 -0
- package/dist/shared/text-chunking.js +29 -0
- package/dist/signal/accounts.js +7 -20
- package/dist/signal/monitor/event-handler.js +3 -1
- package/dist/slack/accounts.js +6 -19
- package/dist/slack/actions.js +11 -3
- package/dist/slack/blocks.test-helpers.js +31 -0
- package/dist/slack/monitor/auth.js +1 -1
- package/dist/slack/monitor/message-handler/dispatch.js +50 -29
- package/dist/slack/monitor/mrkdwn.js +8 -0
- package/dist/slack/monitor/replies.js +15 -7
- package/dist/slack/monitor/slash.js +22 -13
- package/dist/slack/resolve-channels.js +10 -5
- package/dist/slack/send.js +102 -12
- package/dist/slack/stream-mode.js +10 -0
- package/dist/slack/streaming.js +4 -2
- package/dist/telegram/accounts.js +19 -14
- package/dist/telegram/bot/helpers.js +3 -5
- package/dist/telegram/bot-access.js +35 -36
- package/dist/telegram/bot-handlers.js +120 -148
- package/dist/telegram/bot-message-context.js +68 -9
- package/dist/telegram/bot-message-dispatch.js +477 -210
- package/dist/telegram/bot-native-commands.js +16 -0
- package/dist/telegram/draft-stream.js +44 -8
- package/dist/telegram/inline-buttons.js +5 -15
- package/dist/telegram/monitor.js +11 -7
- package/dist/telegram/network-config.js +19 -7
- package/dist/telegram/reasoning-lane-coordinator.js +128 -0
- package/dist/telegram/send.js +3 -2
- package/dist/telegram/sent-message-cache.js +5 -6
- package/dist/telegram/status-reaction-variants.js +208 -0
- package/dist/telegram/sticker-cache.js +11 -9
- package/dist/terminal/prompt-select-styled.js +9 -0
- package/dist/terminal/theme.js +12 -12
- package/dist/test-utils/command-runner.js +6 -0
- package/dist/test-utils/internal-hook-event-payload.js +10 -0
- package/dist/test-utils/model-auth-mock.js +12 -0
- package/dist/test-utils/provider-usage-fetch.js +14 -0
- package/dist/test-utils/temp-home.js +33 -0
- package/dist/tts/tts.js +80 -567
- package/dist/tui/components/chat-log.js +50 -8
- package/dist/tui/theme/theme.js +10 -12
- package/dist/tui/tui-command-handlers.js +36 -27
- package/dist/tui/tui-event-handlers.js +122 -32
- package/dist/tui/tui-local-shell.js +16 -6
- package/dist/tui/tui.js +236 -48
- package/dist/utils/account-id.js +2 -4
- package/dist/utils/boolean.js +10 -5
- package/dist/utils/directive-tags.js +11 -0
- package/dist/utils/mask-api-key.js +10 -0
- package/dist/utils/queue-helpers.js +67 -12
- package/dist/utils/run-with-concurrency.js +39 -0
- package/dist/web/auto-reply/deliver-reply.js +8 -4
- package/dist/web/auto-reply/mentions.js +10 -5
- package/dist/web/auto-reply/monitor/group-members.js +14 -7
- package/dist/web/auto-reply/monitor/process-message.js +45 -24
- package/dist/web/inbound/access-control.js +5 -2
- package/dist/web/login-qr.js +12 -6
- package/dist/web/media.js +126 -15
- package/docs/tools/slash-commands.md +5 -1
- package/extensions/bluebubbles/src/monitor-processing.ts +580 -139
- package/extensions/bluebubbles/src/monitor.ts +208 -1950
- package/extensions/feishu/src/external-keys.ts +19 -0
- package/extensions/lobster/src/windows-spawn.ts +193 -0
- package/extensions/matrix/src/matrix/actions/limits.ts +6 -0
- package/extensions/mattermost/src/mattermost/reactions.test-helpers.ts +83 -0
- package/package.json +1 -1
|
@@ -17,10 +17,11 @@ import { getQueueSize } from "../process/command-queue.js";
|
|
|
17
17
|
import { normalizeAgentId, toAgentStoreSessionKey } from "../routing/session-key.js";
|
|
18
18
|
import { defaultRuntime } from "../runtime.js";
|
|
19
19
|
import { escapeRegExp } from "../utils.js";
|
|
20
|
-
import { formatErrorMessage } from "./errors.js";
|
|
20
|
+
import { formatErrorMessage, hasErrnoCode } from "./errors.js";
|
|
21
21
|
import { isWithinActiveHours } from "./heartbeat-active-hours.js";
|
|
22
22
|
import { buildCronEventPrompt, isCronSystemEvent, isExecCompletionEvent, } from "./heartbeat-events-filter.js";
|
|
23
23
|
import { emitHeartbeatEvent, resolveIndicatorType } from "./heartbeat-events.js";
|
|
24
|
+
import { resolveHeartbeatReasonKind } from "./heartbeat-reason.js";
|
|
24
25
|
import { resolveHeartbeatVisibility } from "./heartbeat-visibility.js";
|
|
25
26
|
import { requestHeartbeatNow, setHeartbeatWakeHandler, } from "./heartbeat-wake.js";
|
|
26
27
|
import { deliverOutboundPayloads } from "./outbound/deliver.js";
|
|
@@ -322,6 +323,56 @@ function normalizeHeartbeatReply(payload, responsePrefix, ackMaxChars) {
|
|
|
322
323
|
}
|
|
323
324
|
return { shouldSkip: false, text: finalText, hasMedia };
|
|
324
325
|
}
|
|
326
|
+
function resolveHeartbeatReasonFlags(reason) {
|
|
327
|
+
const reasonKind = resolveHeartbeatReasonKind(reason);
|
|
328
|
+
return {
|
|
329
|
+
isExecEventReason: reasonKind === "exec-event",
|
|
330
|
+
isCronEventReason: reasonKind === "cron",
|
|
331
|
+
isWakeReason: reasonKind === "wake" || reasonKind === "hook",
|
|
332
|
+
};
|
|
333
|
+
}
|
|
334
|
+
async function resolveHeartbeatPreflight(params) {
|
|
335
|
+
const reasonFlags = resolveHeartbeatReasonFlags(params.reason);
|
|
336
|
+
const session = resolveHeartbeatSession(params.cfg, params.agentId, params.heartbeat, params.forcedSessionKey);
|
|
337
|
+
const pendingEventEntries = peekSystemEventEntries(session.sessionKey);
|
|
338
|
+
const hasTaggedCronEvents = pendingEventEntries.some((event) => event.contextKey?.startsWith("cron:"));
|
|
339
|
+
const shouldInspectPendingEvents = reasonFlags.isExecEventReason || reasonFlags.isCronEventReason || hasTaggedCronEvents;
|
|
340
|
+
const shouldBypassFileGates = reasonFlags.isExecEventReason ||
|
|
341
|
+
reasonFlags.isCronEventReason ||
|
|
342
|
+
reasonFlags.isWakeReason ||
|
|
343
|
+
hasTaggedCronEvents;
|
|
344
|
+
const basePreflight = {
|
|
345
|
+
...reasonFlags,
|
|
346
|
+
session,
|
|
347
|
+
pendingEventEntries,
|
|
348
|
+
hasTaggedCronEvents,
|
|
349
|
+
shouldInspectPendingEvents,
|
|
350
|
+
};
|
|
351
|
+
if (shouldBypassFileGates) {
|
|
352
|
+
return basePreflight;
|
|
353
|
+
}
|
|
354
|
+
const workspaceDir = resolveAgentWorkspaceDir(params.cfg, params.agentId);
|
|
355
|
+
const heartbeatFilePath = path.join(workspaceDir, DEFAULT_HEARTBEAT_FILENAME);
|
|
356
|
+
try {
|
|
357
|
+
const heartbeatFileContent = await fs.readFile(heartbeatFilePath, "utf-8");
|
|
358
|
+
if (isHeartbeatContentEffectivelyEmpty(heartbeatFileContent)) {
|
|
359
|
+
return {
|
|
360
|
+
...basePreflight,
|
|
361
|
+
skipReason: "empty-heartbeat-file",
|
|
362
|
+
};
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
catch (err) {
|
|
366
|
+
if (hasErrnoCode(err, "ENOENT")) {
|
|
367
|
+
// Missing HEARTBEAT.md is intentional in some setups (for example, when
|
|
368
|
+
// heartbeat instructions live outside the file), so keep the run active.
|
|
369
|
+
// The heartbeat prompt already says "if it exists".
|
|
370
|
+
return basePreflight;
|
|
371
|
+
}
|
|
372
|
+
// For other read errors, proceed with heartbeat as before.
|
|
373
|
+
}
|
|
374
|
+
return basePreflight;
|
|
375
|
+
}
|
|
325
376
|
export async function runHeartbeatOnce(opts) {
|
|
326
377
|
const cfg = opts.cfg ?? loadConfig();
|
|
327
378
|
const agentId = normalizeAgentId(opts.agentId ?? resolveDefaultAgentId(cfg));
|
|
@@ -343,34 +394,24 @@ export async function runHeartbeatOnce(opts) {
|
|
|
343
394
|
if (queueSize > 0) {
|
|
344
395
|
return { status: "skipped", reason: "requests-in-flight" };
|
|
345
396
|
}
|
|
346
|
-
//
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
emitHeartbeatEvent({
|
|
362
|
-
status: "skipped",
|
|
363
|
-
reason: "empty-heartbeat-file",
|
|
364
|
-
durationMs: Date.now() - startedAt,
|
|
365
|
-
});
|
|
366
|
-
return { status: "skipped", reason: "empty-heartbeat-file" };
|
|
367
|
-
}
|
|
368
|
-
}
|
|
369
|
-
catch {
|
|
370
|
-
// File doesn't exist or can't be read - proceed with heartbeat.
|
|
371
|
-
// The LLM prompt says "if it exists" so this is expected behavior.
|
|
397
|
+
// Preflight centralizes trigger classification, event inspection, and HEARTBEAT.md gating.
|
|
398
|
+
const preflight = await resolveHeartbeatPreflight({
|
|
399
|
+
cfg,
|
|
400
|
+
agentId,
|
|
401
|
+
heartbeat,
|
|
402
|
+
forcedSessionKey: opts.sessionKey,
|
|
403
|
+
reason: opts.reason,
|
|
404
|
+
});
|
|
405
|
+
if (preflight.skipReason) {
|
|
406
|
+
emitHeartbeatEvent({
|
|
407
|
+
status: "skipped",
|
|
408
|
+
reason: preflight.skipReason,
|
|
409
|
+
durationMs: Date.now() - startedAt,
|
|
410
|
+
});
|
|
411
|
+
return { status: "skipped", reason: preflight.skipReason };
|
|
372
412
|
}
|
|
373
|
-
const { entry, sessionKey, storePath } =
|
|
413
|
+
const { entry, sessionKey, storePath } = preflight.session;
|
|
414
|
+
const { isCronEventReason, pendingEventEntries } = preflight;
|
|
374
415
|
const previousUpdatedAt = entry?.updatedAt;
|
|
375
416
|
const delivery = resolveHeartbeatDeliveryTarget({ cfg, entry, heartbeat });
|
|
376
417
|
const heartbeatAccountId = heartbeat?.accountId?.trim();
|
|
@@ -402,10 +443,7 @@ export async function runHeartbeatOnce(opts) {
|
|
|
402
443
|
// Check if this is an exec event or cron event with pending system events.
|
|
403
444
|
// If so, use a specialized prompt that instructs the model to relay the result
|
|
404
445
|
// instead of the standard heartbeat prompt with "reply HEARTBEAT_OK".
|
|
405
|
-
const
|
|
406
|
-
const pendingEventEntries = peekSystemEventEntries(sessionKey);
|
|
407
|
-
const hasTaggedCronEvents = pendingEventEntries.some((event) => event.contextKey?.startsWith("cron:"));
|
|
408
|
-
const shouldInspectPendingEvents = isExecEvent || isCronEventReason || hasTaggedCronEvents;
|
|
446
|
+
const shouldInspectPendingEvents = preflight.shouldInspectPendingEvents;
|
|
409
447
|
const pendingEvents = shouldInspectPendingEvents
|
|
410
448
|
? pendingEventEntries.map((event) => event.text)
|
|
411
449
|
: [];
|
|
@@ -459,6 +497,7 @@ export async function runHeartbeatOnce(opts) {
|
|
|
459
497
|
channel: delivery.channel,
|
|
460
498
|
to: delivery.to,
|
|
461
499
|
accountId: delivery.accountId,
|
|
500
|
+
threadId: delivery.threadId,
|
|
462
501
|
payloads: [{ text: heartbeatOkText }],
|
|
463
502
|
agentId,
|
|
464
503
|
deps: opts.deps,
|
|
@@ -635,6 +674,7 @@ export async function runHeartbeatOnce(opts) {
|
|
|
635
674
|
to: delivery.to,
|
|
636
675
|
accountId: deliveryAccountId,
|
|
637
676
|
agentId,
|
|
677
|
+
threadId: delivery.threadId,
|
|
638
678
|
payloads: [
|
|
639
679
|
...reasoningPayloads,
|
|
640
680
|
...(shouldSkipMain
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { isHeartbeatActionWakeReason, normalizeHeartbeatWakeReason, resolveHeartbeatReasonKind, } from "./heartbeat-reason.js";
|
|
1
2
|
let handler = null;
|
|
2
3
|
let handlerGeneration = 0;
|
|
3
4
|
const pendingWakes = new Map();
|
|
@@ -8,34 +9,27 @@ let timerDueAt = null;
|
|
|
8
9
|
let timerKind = null;
|
|
9
10
|
const DEFAULT_COALESCE_MS = 250;
|
|
10
11
|
const DEFAULT_RETRY_MS = 1_000;
|
|
11
|
-
const HOOK_REASON_PREFIX = "hook:";
|
|
12
12
|
const REASON_PRIORITY = {
|
|
13
13
|
RETRY: 0,
|
|
14
14
|
INTERVAL: 1,
|
|
15
15
|
DEFAULT: 2,
|
|
16
16
|
ACTION: 3,
|
|
17
17
|
};
|
|
18
|
-
function isActionWakeReason(reason) {
|
|
19
|
-
return reason === "manual" || reason === "exec-event" || reason.startsWith(HOOK_REASON_PREFIX);
|
|
20
|
-
}
|
|
21
18
|
function resolveReasonPriority(reason) {
|
|
22
|
-
|
|
19
|
+
const kind = resolveHeartbeatReasonKind(reason);
|
|
20
|
+
if (kind === "retry") {
|
|
23
21
|
return REASON_PRIORITY.RETRY;
|
|
24
22
|
}
|
|
25
|
-
if (
|
|
23
|
+
if (kind === "interval") {
|
|
26
24
|
return REASON_PRIORITY.INTERVAL;
|
|
27
25
|
}
|
|
28
|
-
if (
|
|
26
|
+
if (isHeartbeatActionWakeReason(reason)) {
|
|
29
27
|
return REASON_PRIORITY.ACTION;
|
|
30
28
|
}
|
|
31
29
|
return REASON_PRIORITY.DEFAULT;
|
|
32
30
|
}
|
|
33
31
|
function normalizeWakeReason(reason) {
|
|
34
|
-
|
|
35
|
-
return "requested";
|
|
36
|
-
}
|
|
37
|
-
const trimmed = reason.trim();
|
|
38
|
-
return trimmed.length > 0 ? trimmed : "requested";
|
|
32
|
+
return normalizeHeartbeatWakeReason(reason);
|
|
39
33
|
}
|
|
40
34
|
function normalizeWakeTarget(value) {
|
|
41
35
|
const trimmed = typeof value === "string" ? value.trim() : "";
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"blockedKeys": [
|
|
3
|
+
"NODE_OPTIONS",
|
|
4
|
+
"NODE_PATH",
|
|
5
|
+
"PYTHONHOME",
|
|
6
|
+
"PYTHONPATH",
|
|
7
|
+
"PERL5LIB",
|
|
8
|
+
"PERL5OPT",
|
|
9
|
+
"RUBYLIB",
|
|
10
|
+
"RUBYOPT",
|
|
11
|
+
"BASH_ENV",
|
|
12
|
+
"ENV",
|
|
13
|
+
"SHELL",
|
|
14
|
+
"GCONV_PATH",
|
|
15
|
+
"IFS",
|
|
16
|
+
"SSLKEYLOGFILE"
|
|
17
|
+
],
|
|
18
|
+
"blockedPrefixes": ["DYLD_", "LD_", "BASH_FUNC_"]
|
|
19
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import HOST_ENV_SECURITY_POLICY_JSON from "./host-env-security-policy.json" with { type: "json" };
|
|
2
|
+
const PORTABLE_ENV_VAR_KEY = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
3
|
+
const HOST_ENV_SECURITY_POLICY = HOST_ENV_SECURITY_POLICY_JSON;
|
|
4
|
+
export const HOST_DANGEROUS_ENV_KEY_VALUES = Object.freeze(HOST_ENV_SECURITY_POLICY.blockedKeys.map((key) => key.toUpperCase()));
|
|
5
|
+
export const HOST_DANGEROUS_ENV_PREFIXES = Object.freeze(HOST_ENV_SECURITY_POLICY.blockedPrefixes.map((prefix) => prefix.toUpperCase()));
|
|
6
|
+
export const HOST_DANGEROUS_ENV_KEYS = new Set(HOST_DANGEROUS_ENV_KEY_VALUES);
|
|
7
|
+
export function normalizeEnvVarKey(rawKey, options) {
|
|
8
|
+
const key = rawKey.trim();
|
|
9
|
+
if (!key) {
|
|
10
|
+
return null;
|
|
11
|
+
}
|
|
12
|
+
if (options?.portable && !PORTABLE_ENV_VAR_KEY.test(key)) {
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
return key;
|
|
16
|
+
}
|
|
17
|
+
export function isDangerousHostEnvVarName(rawKey) {
|
|
18
|
+
const key = normalizeEnvVarKey(rawKey);
|
|
19
|
+
if (!key) {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
const upper = key.toUpperCase();
|
|
23
|
+
if (HOST_DANGEROUS_ENV_KEYS.has(upper)) {
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
26
|
+
return HOST_DANGEROUS_ENV_PREFIXES.some((prefix) => upper.startsWith(prefix));
|
|
27
|
+
}
|
|
28
|
+
export function sanitizeHostExecEnv(params) {
|
|
29
|
+
const baseEnv = params?.baseEnv ?? process.env;
|
|
30
|
+
const overrides = params?.overrides ?? undefined;
|
|
31
|
+
const blockPathOverrides = params?.blockPathOverrides ?? true;
|
|
32
|
+
const merged = {};
|
|
33
|
+
for (const [rawKey, value] of Object.entries(baseEnv)) {
|
|
34
|
+
if (typeof value !== "string") {
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
const key = normalizeEnvVarKey(rawKey, { portable: true });
|
|
38
|
+
if (!key || isDangerousHostEnvVarName(key)) {
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
merged[key] = value;
|
|
42
|
+
}
|
|
43
|
+
if (!overrides) {
|
|
44
|
+
return merged;
|
|
45
|
+
}
|
|
46
|
+
for (const [rawKey, value] of Object.entries(overrides)) {
|
|
47
|
+
if (typeof value !== "string") {
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
const key = normalizeEnvVarKey(rawKey, { portable: true });
|
|
51
|
+
if (!key) {
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
const upper = key.toUpperCase();
|
|
55
|
+
// PATH is part of the security boundary (command resolution + safe-bin checks). Never allow
|
|
56
|
+
// request-scoped PATH overrides from agents/gateways.
|
|
57
|
+
if (blockPathOverrides && upper === "PATH") {
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
if (isDangerousHostEnvVarName(upper)) {
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
merged[key] = value;
|
|
64
|
+
}
|
|
65
|
+
return merged;
|
|
66
|
+
}
|
|
@@ -23,8 +23,86 @@ export async function resolveArchiveSourcePath(archivePath) {
|
|
|
23
23
|
}
|
|
24
24
|
return { ok: true, path: resolved };
|
|
25
25
|
}
|
|
26
|
+
function toOptionalString(value) {
|
|
27
|
+
if (typeof value !== "string") {
|
|
28
|
+
return undefined;
|
|
29
|
+
}
|
|
30
|
+
const trimmed = value.trim();
|
|
31
|
+
return trimmed.length > 0 ? trimmed : undefined;
|
|
32
|
+
}
|
|
33
|
+
function parseResolvedSpecFromId(id) {
|
|
34
|
+
const at = id.lastIndexOf("@");
|
|
35
|
+
if (at <= 0 || at >= id.length - 1) {
|
|
36
|
+
return undefined;
|
|
37
|
+
}
|
|
38
|
+
const name = id.slice(0, at).trim();
|
|
39
|
+
const version = id.slice(at + 1).trim();
|
|
40
|
+
if (!name || !version) {
|
|
41
|
+
return undefined;
|
|
42
|
+
}
|
|
43
|
+
return `${name}@${version}`;
|
|
44
|
+
}
|
|
45
|
+
function normalizeNpmPackEntry(entry) {
|
|
46
|
+
if (!entry || typeof entry !== "object") {
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
const rec = entry;
|
|
50
|
+
const name = toOptionalString(rec.name);
|
|
51
|
+
const version = toOptionalString(rec.version);
|
|
52
|
+
const id = toOptionalString(rec.id);
|
|
53
|
+
const resolvedSpec = (name && version ? `${name}@${version}` : undefined) ??
|
|
54
|
+
(id ? parseResolvedSpecFromId(id) : undefined);
|
|
55
|
+
return {
|
|
56
|
+
filename: toOptionalString(rec.filename),
|
|
57
|
+
metadata: {
|
|
58
|
+
name,
|
|
59
|
+
version,
|
|
60
|
+
resolvedSpec,
|
|
61
|
+
integrity: toOptionalString(rec.integrity),
|
|
62
|
+
shasum: toOptionalString(rec.shasum),
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
function parseNpmPackJsonOutput(raw) {
|
|
67
|
+
const trimmed = raw.trim();
|
|
68
|
+
if (!trimmed) {
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
const candidates = [trimmed];
|
|
72
|
+
const arrayStart = trimmed.indexOf("[");
|
|
73
|
+
if (arrayStart > 0) {
|
|
74
|
+
candidates.push(trimmed.slice(arrayStart));
|
|
75
|
+
}
|
|
76
|
+
for (const candidate of candidates) {
|
|
77
|
+
let parsed;
|
|
78
|
+
try {
|
|
79
|
+
parsed = JSON.parse(candidate);
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
const entries = Array.isArray(parsed) ? parsed : [parsed];
|
|
85
|
+
let fallback = null;
|
|
86
|
+
for (let i = entries.length - 1; i >= 0; i -= 1) {
|
|
87
|
+
const normalized = normalizeNpmPackEntry(entries[i]);
|
|
88
|
+
if (!normalized) {
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
if (!fallback) {
|
|
92
|
+
fallback = normalized;
|
|
93
|
+
}
|
|
94
|
+
if (normalized.filename) {
|
|
95
|
+
return normalized;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
if (fallback) {
|
|
99
|
+
return fallback;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
26
104
|
export async function packNpmSpecToArchive(params) {
|
|
27
|
-
const res = await runCommandWithTimeout(["npm", "pack", params.spec, "--ignore-scripts"], {
|
|
105
|
+
const res = await runCommandWithTimeout(["npm", "pack", params.spec, "--ignore-scripts", "--json"], {
|
|
28
106
|
timeoutMs: Math.max(params.timeoutMs, 300_000),
|
|
29
107
|
cwd: params.cwd,
|
|
30
108
|
env: {
|
|
@@ -35,13 +113,19 @@ export async function packNpmSpecToArchive(params) {
|
|
|
35
113
|
if (res.code !== 0) {
|
|
36
114
|
return { ok: false, error: `npm pack failed: ${res.stderr.trim() || res.stdout.trim()}` };
|
|
37
115
|
}
|
|
38
|
-
const
|
|
39
|
-
|
|
40
|
-
.
|
|
41
|
-
|
|
42
|
-
|
|
116
|
+
const parsedJson = parseNpmPackJsonOutput(res.stdout || "");
|
|
117
|
+
const packed = parsedJson?.filename ??
|
|
118
|
+
(res.stdout || "")
|
|
119
|
+
.split("\n")
|
|
120
|
+
.map((line) => line.trim())
|
|
121
|
+
.filter(Boolean)
|
|
122
|
+
.pop();
|
|
43
123
|
if (!packed) {
|
|
44
124
|
return { ok: false, error: "npm pack produced no archive" };
|
|
45
125
|
}
|
|
46
|
-
return {
|
|
126
|
+
return {
|
|
127
|
+
ok: true,
|
|
128
|
+
archivePath: path.join(params.cwd, packed),
|
|
129
|
+
metadata: parsedJson?.metadata ?? {},
|
|
130
|
+
};
|
|
47
131
|
}
|
package/dist/infra/net/ssrf.js
CHANGED
|
@@ -8,7 +8,11 @@ export class SsrFBlockedError extends Error {
|
|
|
8
8
|
this.name = "SsrFBlockedError";
|
|
9
9
|
}
|
|
10
10
|
}
|
|
11
|
-
const BLOCKED_HOSTNAMES = new Set([
|
|
11
|
+
const BLOCKED_HOSTNAMES = new Set([
|
|
12
|
+
"localhost",
|
|
13
|
+
"localhost.localdomain",
|
|
14
|
+
"metadata.google.internal",
|
|
15
|
+
]);
|
|
12
16
|
function normalizeHostnameSet(values) {
|
|
13
17
|
if (!values || values.length === 0) {
|
|
14
18
|
return new Set();
|
|
@@ -39,16 +43,72 @@ function matchesHostnameAllowlist(hostname, allowlist) {
|
|
|
39
43
|
}
|
|
40
44
|
return allowlist.some((pattern) => isHostnameAllowedByPattern(hostname, pattern));
|
|
41
45
|
}
|
|
46
|
+
function parseStrictIpv4Octet(part) {
|
|
47
|
+
if (!/^[0-9]+$/.test(part)) {
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
const value = Number.parseInt(part, 10);
|
|
51
|
+
if (Number.isNaN(value) || value < 0 || value > 255) {
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
// Accept only canonical decimal octets (no leading zeros, no alternate radices).
|
|
55
|
+
if (part !== String(value)) {
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
return value;
|
|
59
|
+
}
|
|
42
60
|
function parseIpv4(address) {
|
|
43
61
|
const parts = address.split(".");
|
|
44
62
|
if (parts.length !== 4) {
|
|
45
63
|
return null;
|
|
46
64
|
}
|
|
47
|
-
const
|
|
48
|
-
|
|
49
|
-
|
|
65
|
+
for (const part of parts) {
|
|
66
|
+
if (parseStrictIpv4Octet(part) === null) {
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return parts.map((part) => Number.parseInt(part, 10));
|
|
71
|
+
}
|
|
72
|
+
function classifyIpv4Part(part) {
|
|
73
|
+
if (/^0x[0-9a-f]+$/i.test(part)) {
|
|
74
|
+
return "hex";
|
|
75
|
+
}
|
|
76
|
+
if (/^0x/i.test(part)) {
|
|
77
|
+
return "invalid-hex";
|
|
78
|
+
}
|
|
79
|
+
if (/^[0-9]+$/.test(part)) {
|
|
80
|
+
return "decimal";
|
|
81
|
+
}
|
|
82
|
+
return "non-numeric";
|
|
83
|
+
}
|
|
84
|
+
function isUnsupportedLegacyIpv4Literal(address) {
|
|
85
|
+
const parts = address.split(".");
|
|
86
|
+
if (parts.length === 0 || parts.length > 4) {
|
|
87
|
+
return false;
|
|
88
|
+
}
|
|
89
|
+
if (parts.some((part) => part.length === 0)) {
|
|
90
|
+
return true;
|
|
91
|
+
}
|
|
92
|
+
const partKinds = parts.map(classifyIpv4Part);
|
|
93
|
+
if (partKinds.some((kind) => kind === "non-numeric")) {
|
|
94
|
+
return false;
|
|
50
95
|
}
|
|
51
|
-
|
|
96
|
+
if (partKinds.some((kind) => kind === "invalid-hex")) {
|
|
97
|
+
return true;
|
|
98
|
+
}
|
|
99
|
+
if (parts.length !== 4) {
|
|
100
|
+
return true;
|
|
101
|
+
}
|
|
102
|
+
for (const part of parts) {
|
|
103
|
+
if (/^0x/i.test(part)) {
|
|
104
|
+
return true;
|
|
105
|
+
}
|
|
106
|
+
const value = Number.parseInt(part, 10);
|
|
107
|
+
if (Number.isNaN(value) || value > 255 || part !== String(value)) {
|
|
108
|
+
return true;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return false;
|
|
52
112
|
}
|
|
53
113
|
function stripIpv6ZoneId(address) {
|
|
54
114
|
const index = address.indexOf("%");
|
|
@@ -148,6 +208,12 @@ const EMBEDDED_IPV4_RULES = [
|
|
|
148
208
|
matches: (hextets) => hextets[0] === 0x2001 && hextets[1] === 0x0000,
|
|
149
209
|
extract: (hextets) => [hextets[6] ^ 0xffff, hextets[7] ^ 0xffff],
|
|
150
210
|
},
|
|
211
|
+
{
|
|
212
|
+
// ISATAP IID format: 000000ug00000000:5efe:w.x.y.z (RFC 5214 section 6.1).
|
|
213
|
+
// Match only the IID marker bits to avoid over-broad :5efe: detection.
|
|
214
|
+
matches: (hextets) => (hextets[4] & 0xfcff) === 0 && hextets[5] === 0x5efe,
|
|
215
|
+
extract: (hextets) => [hextets[6], hextets[7]],
|
|
216
|
+
},
|
|
151
217
|
];
|
|
152
218
|
function extractIpv4FromEmbeddedIpv6(hextets) {
|
|
153
219
|
for (const rule of EMBEDDED_IPV4_RULES) {
|
|
@@ -159,31 +225,49 @@ function extractIpv4FromEmbeddedIpv6(hextets) {
|
|
|
159
225
|
}
|
|
160
226
|
return null;
|
|
161
227
|
}
|
|
162
|
-
function
|
|
163
|
-
const [
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
|
|
228
|
+
function ipv4ToUint(parts) {
|
|
229
|
+
const [a, b, c, d] = parts;
|
|
230
|
+
return (((a << 24) >>> 0) | (b << 16) | (c << 8) | d) >>> 0;
|
|
231
|
+
}
|
|
232
|
+
function ipv4RangeFromCidr(cidr) {
|
|
233
|
+
const base = ipv4ToUint(cidr.base);
|
|
234
|
+
const hostBits = 32 - cidr.prefixLength;
|
|
235
|
+
const mask = cidr.prefixLength === 0 ? 0 : (0xffffffff << hostBits) >>> 0;
|
|
236
|
+
const start = (base & mask) >>> 0;
|
|
237
|
+
const end = (start | (~mask >>> 0)) >>> 0;
|
|
238
|
+
return [start, end];
|
|
239
|
+
}
|
|
240
|
+
const BLOCKED_IPV4_SPECIAL_USE_CIDRS = [
|
|
241
|
+
{ base: [0, 0, 0, 0], prefixLength: 8 },
|
|
242
|
+
{ base: [10, 0, 0, 0], prefixLength: 8 },
|
|
243
|
+
{ base: [100, 64, 0, 0], prefixLength: 10 },
|
|
244
|
+
{ base: [127, 0, 0, 0], prefixLength: 8 },
|
|
245
|
+
{ base: [169, 254, 0, 0], prefixLength: 16 },
|
|
246
|
+
{ base: [172, 16, 0, 0], prefixLength: 12 },
|
|
247
|
+
{ base: [192, 0, 0, 0], prefixLength: 24 },
|
|
248
|
+
{ base: [192, 0, 2, 0], prefixLength: 24 },
|
|
249
|
+
{ base: [192, 88, 99, 0], prefixLength: 24 },
|
|
250
|
+
{ base: [192, 168, 0, 0], prefixLength: 16 },
|
|
251
|
+
{ base: [198, 18, 0, 0], prefixLength: 15 },
|
|
252
|
+
{ base: [198, 51, 100, 0], prefixLength: 24 },
|
|
253
|
+
{ base: [203, 0, 113, 0], prefixLength: 24 },
|
|
254
|
+
{ base: [224, 0, 0, 0], prefixLength: 4 },
|
|
255
|
+
{ base: [240, 0, 0, 0], prefixLength: 4 },
|
|
256
|
+
];
|
|
257
|
+
const BLOCKED_IPV4_SPECIAL_USE_RANGES = BLOCKED_IPV4_SPECIAL_USE_CIDRS.map(ipv4RangeFromCidr);
|
|
258
|
+
function isBlockedIpv4SpecialUse(parts) {
|
|
259
|
+
if (parts.length !== 4) {
|
|
260
|
+
return false;
|
|
181
261
|
}
|
|
182
|
-
|
|
183
|
-
|
|
262
|
+
const value = ipv4ToUint(parts);
|
|
263
|
+
for (const [start, end] of BLOCKED_IPV4_SPECIAL_USE_RANGES) {
|
|
264
|
+
if (value >= start && value <= end) {
|
|
265
|
+
return true;
|
|
266
|
+
}
|
|
184
267
|
}
|
|
185
268
|
return false;
|
|
186
269
|
}
|
|
270
|
+
// Returns true for private/internal and special-use non-global addresses.
|
|
187
271
|
export function isPrivateIpAddress(address) {
|
|
188
272
|
let normalized = address.trim().toLowerCase();
|
|
189
273
|
if (normalized.startsWith("[") && normalized.endsWith("]")) {
|
|
@@ -219,7 +303,7 @@ export function isPrivateIpAddress(address) {
|
|
|
219
303
|
}
|
|
220
304
|
const embeddedIpv4 = extractIpv4FromEmbeddedIpv6(hextets);
|
|
221
305
|
if (embeddedIpv4) {
|
|
222
|
-
return
|
|
306
|
+
return isBlockedIpv4SpecialUse(embeddedIpv4);
|
|
223
307
|
}
|
|
224
308
|
// IPv6 private/internal ranges
|
|
225
309
|
// - link-local: fe80::/10
|
|
@@ -238,16 +322,23 @@ export function isPrivateIpAddress(address) {
|
|
|
238
322
|
return false;
|
|
239
323
|
}
|
|
240
324
|
const ipv4 = parseIpv4(normalized);
|
|
241
|
-
if (
|
|
242
|
-
return
|
|
325
|
+
if (ipv4) {
|
|
326
|
+
return isBlockedIpv4SpecialUse(ipv4);
|
|
243
327
|
}
|
|
244
|
-
|
|
328
|
+
// Reject non-canonical IPv4 literal forms (octal/hex/short/packed) by default.
|
|
329
|
+
if (isUnsupportedLegacyIpv4Literal(normalized)) {
|
|
330
|
+
return true;
|
|
331
|
+
}
|
|
332
|
+
return false;
|
|
245
333
|
}
|
|
246
334
|
export function isBlockedHostname(hostname) {
|
|
247
335
|
const normalized = normalizeHostname(hostname);
|
|
248
336
|
if (!normalized) {
|
|
249
337
|
return false;
|
|
250
338
|
}
|
|
339
|
+
return isBlockedHostnameNormalized(normalized);
|
|
340
|
+
}
|
|
341
|
+
function isBlockedHostnameNormalized(normalized) {
|
|
251
342
|
if (BLOCKED_HOSTNAMES.has(normalized)) {
|
|
252
343
|
return true;
|
|
253
344
|
}
|
|
@@ -255,6 +346,13 @@ export function isBlockedHostname(hostname) {
|
|
|
255
346
|
normalized.endsWith(".local") ||
|
|
256
347
|
normalized.endsWith(".internal"));
|
|
257
348
|
}
|
|
349
|
+
export function isBlockedHostnameOrIp(hostname) {
|
|
350
|
+
const normalized = normalizeHostname(hostname);
|
|
351
|
+
if (!normalized) {
|
|
352
|
+
return false;
|
|
353
|
+
}
|
|
354
|
+
return isBlockedHostnameNormalized(normalized) || isPrivateIpAddress(normalized);
|
|
355
|
+
}
|
|
258
356
|
export function createPinnedLookup(params) {
|
|
259
357
|
const normalizedHost = normalizeHostname(params.hostname);
|
|
260
358
|
const fallback = params.fallback ?? dnsLookupCb;
|
|
@@ -306,13 +404,8 @@ export async function resolvePinnedHostnameWithPolicy(hostname, params = {}) {
|
|
|
306
404
|
if (!matchesHostnameAllowlist(normalized, hostnameAllowlist)) {
|
|
307
405
|
throw new SsrFBlockedError(`Blocked hostname (not in allowlist): ${hostname}`);
|
|
308
406
|
}
|
|
309
|
-
if (!allowPrivateNetwork && !isExplicitAllowed) {
|
|
310
|
-
|
|
311
|
-
throw new SsrFBlockedError(`Blocked hostname: ${hostname}`);
|
|
312
|
-
}
|
|
313
|
-
if (isPrivateIpAddress(normalized)) {
|
|
314
|
-
throw new SsrFBlockedError("Blocked: private/internal IP address");
|
|
315
|
-
}
|
|
407
|
+
if (!allowPrivateNetwork && !isExplicitAllowed && isBlockedHostnameOrIp(normalized)) {
|
|
408
|
+
throw new SsrFBlockedError("Blocked hostname or private/internal/special-use IP address");
|
|
316
409
|
}
|
|
317
410
|
const lookupFn = params.lookupFn ?? dnsLookup;
|
|
318
411
|
const results = await lookupFn(normalized, { all: true });
|
|
@@ -322,7 +415,7 @@ export async function resolvePinnedHostnameWithPolicy(hostname, params = {}) {
|
|
|
322
415
|
if (!allowPrivateNetwork && !isExplicitAllowed) {
|
|
323
416
|
for (const entry of results) {
|
|
324
417
|
if (isPrivateIpAddress(entry.address)) {
|
|
325
|
-
throw new SsrFBlockedError("Blocked: resolves to private/internal IP address");
|
|
418
|
+
throw new SsrFBlockedError("Blocked: resolves to private/internal/special-use IP address");
|
|
326
419
|
}
|
|
327
420
|
}
|
|
328
421
|
}
|