@elie-laloum/outpost 11.1.2 → 11.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +34 -0
- package/README.md +2 -1
- package/SECURITY.md +5 -1
- package/dist/adapters/agents/antigravity/antigravity-adapter.js +9 -0
- package/dist/adapters/agents/antigravity/antigravity-adapter.js.map +1 -1
- package/dist/adapters/agents/antigravity/antigravity-hook-plan.d.ts +3 -0
- package/dist/adapters/agents/antigravity/antigravity-hook-plan.js +39 -0
- package/dist/adapters/agents/antigravity/antigravity-hook-plan.js.map +1 -0
- package/dist/adapters/agents/antigravity/antigravity-hooks.constants.d.ts +3 -0
- package/dist/adapters/agents/antigravity/antigravity-hooks.constants.js +394 -0
- package/dist/adapters/agents/antigravity/antigravity-hooks.constants.js.map +1 -0
- package/dist/adapters/agents/antigravity/antigravity-hooks.d.ts +2 -0
- package/dist/adapters/agents/antigravity/antigravity-hooks.js +6 -0
- package/dist/adapters/agents/antigravity/antigravity-hooks.js.map +1 -0
- package/dist/adapters/agents/antigravity/antigravity-hooks.types.d.ts +114 -0
- package/dist/adapters/agents/antigravity/antigravity-hooks.types.js +2 -0
- package/dist/adapters/agents/antigravity/antigravity-hooks.types.js.map +1 -0
- package/dist/adapters/agents/antigravity/antigravity.types.d.ts +1 -0
- package/dist/adapters/agents/antigravity/antigravity.types.js.map +1 -1
- package/dist/adapters/agents/authentication.js +1 -0
- package/dist/adapters/agents/authentication.js.map +1 -1
- package/dist/adapters/agents/claude/claude-adapter.js +15 -0
- package/dist/adapters/agents/claude/claude-adapter.js.map +1 -1
- package/dist/adapters/agents/claude/claude-hook-plan.constants.d.ts +1 -0
- package/dist/adapters/agents/claude/claude-hook-plan.constants.js +20 -0
- package/dist/adapters/agents/claude/claude-hook-plan.constants.js.map +1 -0
- package/dist/adapters/agents/claude/claude-hook-plan.d.ts +4 -0
- package/dist/adapters/agents/claude/claude-hook-plan.js +60 -0
- package/dist/adapters/agents/claude/claude-hook-plan.js.map +1 -0
- package/dist/adapters/agents/claude/claude-hooks.constants.d.ts +3 -0
- package/dist/adapters/agents/claude/claude-hooks.constants.js +2968 -0
- package/dist/adapters/agents/claude/claude-hooks.constants.js.map +1 -0
- package/dist/adapters/agents/claude/claude-hooks.d.ts +2 -0
- package/dist/adapters/agents/claude/claude-hooks.js +6 -0
- package/dist/adapters/agents/claude/claude-hooks.js.map +1 -0
- package/dist/adapters/agents/claude/claude-hooks.types.d.ts +900 -0
- package/dist/adapters/agents/claude/claude-hooks.types.js +2 -0
- package/dist/adapters/agents/claude/claude-hooks.types.js.map +1 -0
- package/dist/adapters/agents/claude/claude-profile.d.ts +1 -0
- package/dist/adapters/agents/claude/claude-profile.js +23 -11
- package/dist/adapters/agents/claude/claude-profile.js.map +1 -1
- package/dist/adapters/agents/codex/codex-adapter.js +17 -1
- package/dist/adapters/agents/codex/codex-adapter.js.map +1 -1
- package/dist/adapters/agents/codex/codex-authentication.js +1 -0
- package/dist/adapters/agents/codex/codex-authentication.js.map +1 -1
- package/dist/adapters/agents/codex/codex-conversations.constants.d.ts +1 -0
- package/dist/adapters/agents/codex/codex-conversations.constants.js +2 -0
- package/dist/adapters/agents/codex/codex-conversations.constants.js.map +1 -0
- package/dist/adapters/agents/codex/codex-conversations.js +8 -5
- package/dist/adapters/agents/codex/codex-conversations.js.map +1 -1
- package/dist/adapters/agents/codex/codex-hook-plan.d.ts +3 -0
- package/dist/adapters/agents/codex/codex-hook-plan.js +72 -0
- package/dist/adapters/agents/codex/codex-hook-plan.js.map +1 -0
- package/dist/adapters/agents/codex/codex-hooks.constants.d.ts +3 -0
- package/dist/adapters/agents/codex/codex-hooks.constants.js +942 -0
- package/dist/adapters/agents/codex/codex-hooks.constants.js.map +1 -0
- package/dist/adapters/agents/codex/codex-hooks.d.ts +2 -0
- package/dist/adapters/agents/codex/codex-hooks.js +6 -0
- package/dist/adapters/agents/codex/codex-hooks.js.map +1 -0
- package/dist/adapters/agents/codex/codex-hooks.types.d.ts +255 -0
- package/dist/adapters/agents/codex/codex-hooks.types.js +2 -0
- package/dist/adapters/agents/codex/codex-hooks.types.js.map +1 -0
- package/dist/adapters/agents/codex/codex-provider.js +2 -2
- package/dist/adapters/agents/codex/codex-provider.js.map +1 -1
- package/dist/adapters/agents/copilot/copilot-adapter.js +14 -0
- package/dist/adapters/agents/copilot/copilot-adapter.js.map +1 -1
- package/dist/adapters/agents/copilot/copilot-hook-plan.d.ts +3 -0
- package/dist/adapters/agents/copilot/copilot-hook-plan.js +26 -0
- package/dist/adapters/agents/copilot/copilot-hook-plan.js.map +1 -0
- package/dist/adapters/agents/copilot/copilot-hooks.constants.d.ts +3 -0
- package/dist/adapters/agents/copilot/copilot-hooks.constants.js +528 -0
- package/dist/adapters/agents/copilot/copilot-hooks.constants.js.map +1 -0
- package/dist/adapters/agents/copilot/copilot-hooks.d.ts +2 -0
- package/dist/adapters/agents/copilot/copilot-hooks.js +6 -0
- package/dist/adapters/agents/copilot/copilot-hooks.js.map +1 -0
- package/dist/adapters/agents/copilot/copilot-hooks.types.d.ts +166 -0
- package/dist/adapters/agents/copilot/copilot-hooks.types.js +2 -0
- package/dist/adapters/agents/copilot/copilot-hooks.types.js.map +1 -0
- package/dist/adapters/agents/copilot/copilot.types.d.ts +1 -0
- package/dist/adapters/agents/copilot/copilot.types.js.map +1 -1
- package/dist/adapters/agents/hook-groups.d.ts +2 -0
- package/dist/adapters/agents/hook-groups.js +17 -0
- package/dist/adapters/agents/hook-groups.js.map +1 -0
- package/dist/adapters/agents/kimi/kimi-adapter.js +16 -1
- package/dist/adapters/agents/kimi/kimi-adapter.js.map +1 -1
- package/dist/adapters/agents/kimi/kimi-hook-plan.d.ts +3 -0
- package/dist/adapters/agents/kimi/kimi-hook-plan.js +33 -0
- package/dist/adapters/agents/kimi/kimi-hook-plan.js.map +1 -0
- package/dist/adapters/agents/kimi/kimi-hooks.constants.d.ts +3 -0
- package/dist/adapters/agents/kimi/kimi-hooks.constants.js +747 -0
- package/dist/adapters/agents/kimi/kimi-hooks.constants.js.map +1 -0
- package/dist/adapters/agents/kimi/kimi-hooks.d.ts +2 -0
- package/dist/adapters/agents/kimi/kimi-hooks.js +6 -0
- package/dist/adapters/agents/kimi/kimi-hooks.js.map +1 -0
- package/dist/adapters/agents/kimi/kimi-hooks.types.d.ts +226 -0
- package/dist/adapters/agents/kimi/kimi-hooks.types.js +2 -0
- package/dist/adapters/agents/kimi/kimi-hooks.types.js.map +1 -0
- package/dist/adapters/agents/kimi/kimi-request.js +2 -0
- package/dist/adapters/agents/kimi/kimi-request.js.map +1 -1
- package/dist/adapters/agents/kimi/kimi.constants.d.ts +1 -0
- package/dist/adapters/agents/kimi/kimi.constants.js +1 -0
- package/dist/adapters/agents/kimi/kimi.constants.js.map +1 -1
- package/dist/adapters/agents/kimi/kimi.types.d.ts +1 -0
- package/dist/adapters/agents/kimi/kimi.types.js.map +1 -1
- package/dist/adapters/agents/native-hooks.d.ts +4 -0
- package/dist/adapters/agents/native-hooks.js +63 -0
- package/dist/adapters/agents/native-hooks.js.map +1 -0
- package/dist/adapters/agents/native-hooks.types.d.ts +22 -0
- package/dist/adapters/agents/native-hooks.types.js +2 -0
- package/dist/adapters/agents/native-hooks.types.js.map +1 -0
- package/dist/adapters/agents/settings.types.d.ts +2 -0
- package/dist/adapters/agents/settings.types.js.map +1 -1
- package/dist/adapters/decisions/system-one-provider.constants.d.ts +1 -1
- package/dist/adapters/decisions/system-one-provider.constants.js +1 -1
- package/dist/adapters/decisions/system-one-provider.constants.js.map +1 -1
- package/dist/adapters/decisions/system-one-provider.js +8 -21
- package/dist/adapters/decisions/system-one-provider.js.map +1 -1
- package/dist/adapters/models/anthropic-model-provider.constants.d.ts +1 -0
- package/dist/adapters/models/anthropic-model-provider.constants.js +4 -0
- package/dist/adapters/models/anthropic-model-provider.constants.js.map +1 -1
- package/dist/adapters/models/anthropic-model-provider.js +7 -1
- package/dist/adapters/models/anthropic-model-provider.js.map +1 -1
- package/dist/adapters/models/http-failure.d.ts +3 -0
- package/dist/adapters/models/http-failure.js +43 -0
- package/dist/adapters/models/http-failure.js.map +1 -0
- package/dist/adapters/models/http-provider.js +14 -20
- package/dist/adapters/models/http-provider.js.map +1 -1
- package/dist/adapters/models/model-protocol.types.d.ts +1 -0
- package/dist/adapters/models/model-protocol.types.js.map +1 -1
- package/dist/adapters/models/model.constants.d.ts +2 -0
- package/dist/adapters/models/model.constants.js +17 -0
- package/dist/adapters/models/model.constants.js.map +1 -1
- package/dist/adapters/models/openai-chat-stream.js +3 -1
- package/dist/adapters/models/openai-chat-stream.js.map +1 -1
- package/dist/adapters/models/openai-responses.js +4 -0
- package/dist/adapters/models/openai-responses.js.map +1 -1
- package/dist/adapters/secrets/aws.js +5 -4
- package/dist/adapters/secrets/aws.js.map +1 -1
- package/dist/adapters/secrets/azure.constants.d.ts +1 -0
- package/dist/adapters/secrets/azure.constants.js +2 -0
- package/dist/adapters/secrets/azure.constants.js.map +1 -0
- package/dist/adapters/secrets/azure.js +2 -1
- package/dist/adapters/secrets/azure.js.map +1 -1
- package/dist/adapters/secrets/gcp.constants.d.ts +1 -0
- package/dist/adapters/secrets/gcp.constants.js +2 -0
- package/dist/adapters/secrets/gcp.constants.js.map +1 -0
- package/dist/adapters/secrets/gcp.js +11 -9
- package/dist/adapters/secrets/gcp.js.map +1 -1
- package/dist/adapters/secrets/infisical.js +3 -2
- package/dist/adapters/secrets/infisical.js.map +1 -1
- package/dist/adapters/secrets/onepassword.constants.d.ts +1 -0
- package/dist/adapters/secrets/onepassword.constants.js +2 -0
- package/dist/adapters/secrets/onepassword.constants.js.map +1 -0
- package/dist/adapters/secrets/onepassword.js +2 -1
- package/dist/adapters/secrets/onepassword.js.map +1 -1
- package/dist/adapters/secrets/secret-source.js +3 -1
- package/dist/adapters/secrets/secret-source.js.map +1 -1
- package/dist/adapters/secrets/vault-response.js +5 -5
- package/dist/adapters/secrets/vault-response.js.map +1 -1
- package/dist/adapters/secrets/vault.js +4 -3
- package/dist/adapters/secrets/vault.js.map +1 -1
- package/dist/adapters/testing/scripted-agent.d.ts +3 -1
- package/dist/adapters/testing/scripted-agent.js +3 -1
- package/dist/adapters/testing/scripted-agent.js.map +1 -1
- package/dist/adapters/tools/edit-tools.js +3 -3
- package/dist/adapters/tools/edit-tools.js.map +1 -1
- package/dist/adapters/tools/git-tools.js +16 -1
- package/dist/adapters/tools/git-tools.js.map +1 -1
- package/dist/adapters/tools/mcp-launcher.constants.d.ts +1 -1
- package/dist/adapters/tools/mcp-launcher.constants.js +29 -7
- package/dist/adapters/tools/mcp-launcher.constants.js.map +1 -1
- package/dist/adapters/tools/mcp-resources.js +5 -1
- package/dist/adapters/tools/mcp-resources.js.map +1 -1
- package/dist/adapters/tools/mcp.constants.d.ts +0 -6
- package/dist/adapters/tools/mcp.constants.js +0 -6
- package/dist/adapters/tools/mcp.constants.js.map +1 -1
- package/dist/adapters/tools/mcp.js +1 -0
- package/dist/adapters/tools/mcp.js.map +1 -1
- package/dist/adapters/tools/sandbox-files.constants.d.ts +1 -0
- package/dist/adapters/tools/sandbox-files.constants.js +17 -0
- package/dist/adapters/tools/sandbox-files.constants.js.map +1 -0
- package/dist/adapters/tools/sandbox-files.d.ts +1 -0
- package/dist/adapters/tools/sandbox-files.js +14 -1
- package/dist/adapters/tools/sandbox-files.js.map +1 -1
- package/dist/adapters/tools/tools.constants.js +1 -0
- package/dist/adapters/tools/tools.constants.js.map +1 -1
- package/dist/adapters/triggers/github-webhook.js +14 -11
- package/dist/adapters/triggers/github-webhook.js.map +1 -1
- package/dist/adapters/triggers/gitlab-webhook.js +16 -13
- package/dist/adapters/triggers/gitlab-webhook.js.map +1 -1
- package/dist/adapters/triggers/slack-request.js +10 -7
- package/dist/adapters/triggers/slack-request.js.map +1 -1
- package/dist/adapters/triggers/standard-webhook.js +10 -7
- package/dist/adapters/triggers/standard-webhook.js.map +1 -1
- package/dist/application/agent-authentication.js +4 -1
- package/dist/application/agent-authentication.js.map +1 -1
- package/dist/application/agent-turn.js +20 -5
- package/dist/application/agent-turn.js.map +1 -1
- package/dist/application/cli-hooks.constants.d.ts +2 -0
- package/dist/application/cli-hooks.constants.js +69 -0
- package/dist/application/cli-hooks.constants.js.map +1 -0
- package/dist/application/cli-hooks.d.ts +3 -0
- package/dist/application/cli-hooks.js +168 -0
- package/dist/application/cli-hooks.js.map +1 -0
- package/dist/application/cli-steering.js +33 -2
- package/dist/application/cli-steering.js.map +1 -1
- package/dist/application/custom-turn.js +10 -1
- package/dist/application/custom-turn.js.map +1 -1
- package/dist/application/diagnostic-probe.d.ts +1 -1
- package/dist/application/diagnostic-probe.js +7 -3
- package/dist/application/diagnostic-probe.js.map +1 -1
- package/dist/application/dispatch-observation.js +4 -0
- package/dist/application/dispatch-observation.js.map +1 -1
- package/dist/application/doctor-agent.d.ts +1 -1
- package/dist/application/doctor-agent.js +2 -2
- package/dist/application/doctor-agent.js.map +1 -1
- package/dist/application/doctor-deadline.d.ts +1 -0
- package/dist/application/doctor-deadline.js +10 -0
- package/dist/application/doctor-deadline.js.map +1 -0
- package/dist/application/doctor-image.js +9 -7
- package/dist/application/doctor-image.js.map +1 -1
- package/dist/application/doctor-sandbox.js +4 -4
- package/dist/application/doctor-sandbox.js.map +1 -1
- package/dist/application/doctor.constants.d.ts +2 -0
- package/dist/application/doctor.constants.js +2 -0
- package/dist/application/doctor.constants.js.map +1 -1
- package/dist/application/doctor.js +12 -8
- package/dist/application/doctor.js.map +1 -1
- package/dist/application/doctor.types.d.ts +2 -0
- package/dist/application/doctor.types.js.map +1 -1
- package/dist/application/file-sandbox.js +49 -11
- package/dist/application/file-sandbox.js.map +1 -1
- package/dist/application/harness-context.js +4 -2
- package/dist/application/harness-context.js.map +1 -1
- package/dist/application/harness-hook-transforms.d.ts +8 -0
- package/dist/application/harness-hook-transforms.js +115 -0
- package/dist/application/harness-hook-transforms.js.map +1 -0
- package/dist/application/harness-hooks.d.ts +5 -3
- package/dist/application/harness-hooks.js +37 -50
- package/dist/application/harness-hooks.js.map +1 -1
- package/dist/application/harness-loop.d.ts +2 -1
- package/dist/application/harness-loop.js +95 -21
- package/dist/application/harness-loop.js.map +1 -1
- package/dist/application/harness-subagent.d.ts +1 -1
- package/dist/application/harness-subagent.js +63 -12
- package/dist/application/harness-subagent.js.map +1 -1
- package/dist/application/harness.types.d.ts +3 -0
- package/dist/application/harness.types.js.map +1 -1
- package/dist/application/hook-invocation.d.ts +4 -0
- package/dist/application/hook-invocation.js +59 -0
- package/dist/application/hook-invocation.js.map +1 -0
- package/dist/application/queue-worker.js +51 -9
- package/dist/application/queue-worker.js.map +1 -1
- package/dist/application/queue-worker.types.d.ts +1 -0
- package/dist/application/queue-worker.types.js.map +1 -1
- package/dist/application/recipes/native-schemas.constants.js +1439 -218
- package/dist/application/recipes/native-schemas.constants.js.map +1 -1
- package/dist/application/recovery-inspection.js +4 -1
- package/dist/application/recovery-inspection.js.map +1 -1
- package/dist/application/remote-download.js +15 -5
- package/dist/application/remote-download.js.map +1 -1
- package/dist/application/remote-paths.d.ts +1 -0
- package/dist/application/remote-paths.js +7 -0
- package/dist/application/remote-paths.js.map +1 -0
- package/dist/application/remote-validation.js +40 -9
- package/dist/application/remote-validation.js.map +1 -1
- package/dist/application/remote-workspace.js +17 -2
- package/dist/application/remote-workspace.js.map +1 -1
- package/dist/application/repetition-watchdog.js +3 -1
- package/dist/application/repetition-watchdog.js.map +1 -1
- package/dist/application/sandbox-attach.js +38 -9
- package/dist/application/sandbox-attach.js.map +1 -1
- package/dist/application/sandbox-dispatch.js +7 -1
- package/dist/application/sandbox-dispatch.js.map +1 -1
- package/dist/application/schedules.js +2 -0
- package/dist/application/schedules.js.map +1 -1
- package/dist/application/secrets.js +4 -0
- package/dist/application/secrets.js.map +1 -1
- package/dist/application/tool-execution.js +28 -8
- package/dist/application/tool-execution.js.map +1 -1
- package/dist/application/transport-retention.js +3 -3
- package/dist/application/transport-retention.js.map +1 -1
- package/dist/application/workspace-fingerprint.d.ts +1 -0
- package/dist/application/workspace-fingerprint.js +19 -4
- package/dist/application/workspace-fingerprint.js.map +1 -1
- package/dist/cli/doctor-command.js +12 -2
- package/dist/cli/doctor-command.js.map +1 -1
- package/dist/cli/image.js +2 -0
- package/dist/cli/image.js.map +1 -1
- package/dist/cli/main.constants.d.ts +14 -2
- package/dist/cli/main.constants.js +27 -1
- package/dist/cli/main.constants.js.map +1 -1
- package/dist/cli/project-settings.js +7 -1
- package/dist/cli/project-settings.js.map +1 -1
- package/dist/cli/recipe-yaml.js +8 -0
- package/dist/cli/recipe-yaml.js.map +1 -1
- package/dist/cli/recovery-command.js +3 -0
- package/dist/cli/recovery-command.js.map +1 -1
- package/dist/cli/recovery-unlock-command.d.ts +2 -0
- package/dist/cli/recovery-unlock-command.js +19 -0
- package/dist/cli/recovery-unlock-command.js.map +1 -0
- package/dist/cli/scaffold-files.js +4 -1
- package/dist/cli/scaffold-files.js.map +1 -1
- package/dist/cli/scaffold-validation.js +3 -0
- package/dist/cli/scaffold-validation.js.map +1 -1
- package/dist/cli/scaffold.js +2 -0
- package/dist/cli/scaffold.js.map +1 -1
- package/dist/domain/agent-hook.types.d.ts +28 -0
- package/dist/domain/agent-hook.types.js +2 -0
- package/dist/domain/agent-hook.types.js.map +1 -0
- package/dist/domain/agent-profile-hooks.d.ts +2 -0
- package/dist/domain/agent-profile-hooks.js +52 -0
- package/dist/domain/agent-profile-hooks.js.map +1 -0
- package/dist/domain/agent-profile-permissions.js +11 -1
- package/dist/domain/agent-profile-permissions.js.map +1 -1
- package/dist/domain/agent-profile.constants.d.ts +1 -0
- package/dist/domain/agent-profile.constants.js +9 -0
- package/dist/domain/agent-profile.constants.js.map +1 -1
- package/dist/domain/agent-profile.js +6 -1
- package/dist/domain/agent-profile.js.map +1 -1
- package/dist/domain/agent-profile.types.d.ts +11 -0
- package/dist/domain/agent-profile.types.js.map +1 -1
- package/dist/domain/agent.types.d.ts +2 -0
- package/dist/domain/agent.types.js.map +1 -1
- package/dist/domain/container-image.d.ts +1 -0
- package/dist/domain/container-image.js +8 -0
- package/dist/domain/container-image.js.map +1 -0
- package/dist/domain/context.constants.d.ts +1 -0
- package/dist/domain/context.constants.js +1 -0
- package/dist/domain/context.constants.js.map +1 -1
- package/dist/domain/context.js +6 -1
- package/dist/domain/context.js.map +1 -1
- package/dist/domain/egress.js +6 -1
- package/dist/domain/egress.js.map +1 -1
- package/dist/domain/glob.js +1 -1
- package/dist/domain/glob.js.map +1 -1
- package/dist/domain/harness.js +4 -1
- package/dist/domain/harness.js.map +1 -1
- package/dist/domain/hook-command.d.ts +2 -0
- package/dist/domain/hook-command.js +26 -0
- package/dist/domain/hook-command.js.map +1 -0
- package/dist/domain/hook-command.types.d.ts +7 -0
- package/dist/domain/hook-command.types.js +2 -0
- package/dist/domain/hook-command.types.js.map +1 -0
- package/dist/domain/hook-decision.d.ts +2 -0
- package/dist/domain/hook-decision.js +38 -0
- package/dist/domain/hook-decision.js.map +1 -0
- package/dist/domain/hook.constants.d.ts +3 -0
- package/dist/domain/hook.constants.js +31 -1
- package/dist/domain/hook.constants.js.map +1 -1
- package/dist/domain/hook.js +49 -5
- package/dist/domain/hook.js.map +1 -1
- package/dist/domain/hook.types.d.ts +82 -5
- package/dist/domain/hook.types.js.map +1 -1
- package/dist/domain/mcp-server.constants.d.ts +6 -0
- package/dist/domain/mcp-server.constants.js +6 -0
- package/dist/domain/mcp-server.constants.js.map +1 -1
- package/dist/domain/mcp-server.js +1 -0
- package/dist/domain/mcp-server.js.map +1 -1
- package/dist/domain/permissions.types.d.ts +1 -0
- package/dist/domain/permissions.types.js.map +1 -1
- package/dist/domain/pricing.js +4 -2
- package/dist/domain/pricing.js.map +1 -1
- package/dist/domain/redaction.js +6 -3
- package/dist/domain/redaction.js.map +1 -1
- package/dist/domain/secret-fault.d.ts +4 -0
- package/dist/domain/secret-fault.js +11 -0
- package/dist/domain/secret-fault.js.map +1 -0
- package/dist/domain/secrets.js +3 -2
- package/dist/domain/secrets.js.map +1 -1
- package/dist/domain/steering.js +2 -0
- package/dist/domain/steering.js.map +1 -1
- package/dist/domain/steering.types.d.ts +1 -1
- package/dist/domain/steering.types.js.map +1 -1
- package/dist/domain/transport.js +5 -1
- package/dist/domain/transport.js.map +1 -1
- package/dist/domain/trigger-payload.d.ts +4 -0
- package/dist/domain/trigger-payload.js +15 -0
- package/dist/domain/trigger-payload.js.map +1 -0
- package/dist/domain/workflow/checkpoint.js +19 -2
- package/dist/domain/workflow/checkpoint.js.map +1 -1
- package/dist/domain/workflow/retry.constants.d.ts +1 -0
- package/dist/domain/workflow/retry.constants.js +1 -0
- package/dist/domain/workflow/retry.constants.js.map +1 -1
- package/dist/domain/workflow/retry.js +6 -2
- package/dist/domain/workflow/retry.js.map +1 -1
- package/dist/domain/workflow/task-runner.js +5 -3
- package/dist/domain/workflow/task-runner.js.map +1 -1
- package/dist/domain/workflow/workflow-state.js +2 -1
- package/dist/domain/workflow/workflow-state.js.map +1 -1
- package/dist/domain/workflow.types.d.ts +1 -0
- package/dist/domain/workflow.types.js.map +1 -1
- package/dist/index.d.ts +15 -1
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -1
- package/dist/infrastructure/conversations/transcript-store.js +32 -5
- package/dist/infrastructure/conversations/transcript-store.js.map +1 -1
- package/dist/infrastructure/files.d.ts +1 -0
- package/dist/infrastructure/files.js +8 -4
- package/dist/infrastructure/files.js.map +1 -1
- package/dist/infrastructure/git/integration-candidate.js +3 -2
- package/dist/infrastructure/git/integration-candidate.js.map +1 -1
- package/dist/infrastructure/git/lock-recovery.d.ts +3 -0
- package/dist/infrastructure/git/lock-recovery.js +58 -0
- package/dist/infrastructure/git/lock-recovery.js.map +1 -0
- package/dist/infrastructure/git/lock-recovery.types.d.ts +11 -0
- package/dist/infrastructure/git/lock-recovery.types.js +2 -0
- package/dist/infrastructure/git/lock-recovery.types.js.map +1 -0
- package/dist/infrastructure/git/managed-worktree.js +5 -8
- package/dist/infrastructure/git/managed-worktree.js.map +1 -1
- package/dist/infrastructure/git/verification-command.js +35 -30
- package/dist/infrastructure/git/verification-command.js.map +1 -1
- package/dist/infrastructure/git/workspace-lease.js +12 -5
- package/dist/infrastructure/git/workspace-lease.js.map +1 -1
- package/dist/infrastructure/hook-configuration.constants.d.ts +1 -0
- package/dist/infrastructure/hook-configuration.constants.js +59 -0
- package/dist/infrastructure/hook-configuration.constants.js.map +1 -0
- package/dist/infrastructure/hook-configuration.d.ts +3 -0
- package/dist/infrastructure/hook-configuration.js +16 -0
- package/dist/infrastructure/hook-configuration.js.map +1 -0
- package/dist/infrastructure/hook-configuration.types.d.ts +14 -0
- package/dist/infrastructure/hook-configuration.types.js +2 -0
- package/dist/infrastructure/hook-configuration.types.js.map +1 -0
- package/dist/infrastructure/http-transport.constants.d.ts +1 -0
- package/dist/infrastructure/http-transport.constants.js +14 -0
- package/dist/infrastructure/http-transport.constants.js.map +1 -0
- package/dist/infrastructure/http-transport.d.ts +7 -0
- package/dist/infrastructure/http-transport.js +19 -0
- package/dist/infrastructure/http-transport.js.map +1 -0
- package/dist/infrastructure/input-failure.d.ts +4 -0
- package/dist/infrastructure/input-failure.js +14 -0
- package/dist/infrastructure/input-failure.js.map +1 -0
- package/dist/infrastructure/inspection-file.d.ts +1 -0
- package/dist/infrastructure/inspection-file.js +8 -2
- package/dist/infrastructure/inspection-file.js.map +1 -1
- package/dist/infrastructure/local-transport.js +16 -11
- package/dist/infrastructure/local-transport.js.map +1 -1
- package/dist/infrastructure/process.constants.d.ts +1 -0
- package/dist/infrastructure/process.constants.js +1 -0
- package/dist/infrastructure/process.constants.js.map +1 -1
- package/dist/infrastructure/process.d.ts +1 -0
- package/dist/infrastructure/process.js +48 -8
- package/dist/infrastructure/process.js.map +1 -1
- package/dist/infrastructure/reservation-ledger.d.ts +2 -0
- package/dist/infrastructure/reservation-ledger.js +84 -0
- package/dist/infrastructure/reservation-ledger.js.map +1 -0
- package/dist/infrastructure/reservation-recovery.d.ts +4 -0
- package/dist/infrastructure/reservation-recovery.js +28 -0
- package/dist/infrastructure/reservation-recovery.js.map +1 -0
- package/dist/infrastructure/s3-tombstones.d.ts +3 -0
- package/dist/infrastructure/s3-tombstones.js +46 -0
- package/dist/infrastructure/s3-tombstones.js.map +1 -0
- package/dist/infrastructure/s3-tombstones.types.d.ts +6 -0
- package/dist/infrastructure/s3-tombstones.types.js +2 -0
- package/dist/infrastructure/s3-tombstones.types.js.map +1 -0
- package/dist/infrastructure/s3-transport.d.ts +2 -0
- package/dist/infrastructure/s3-transport.js +4 -2
- package/dist/infrastructure/s3-transport.js.map +1 -1
- package/dist/infrastructure/sse.js +6 -3
- package/dist/infrastructure/sse.js.map +1 -1
- package/dist/infrastructure/task-queue-bullmq-connection.d.ts +3 -0
- package/dist/infrastructure/task-queue-bullmq-connection.js +32 -0
- package/dist/infrastructure/task-queue-bullmq-connection.js.map +1 -0
- package/dist/infrastructure/task-queue-bullmq-connection.types.d.ts +8 -0
- package/dist/infrastructure/task-queue-bullmq-connection.types.js +2 -0
- package/dist/infrastructure/task-queue-bullmq-connection.types.js.map +1 -0
- package/dist/infrastructure/task-queue-bullmq-resources.js +21 -15
- package/dist/infrastructure/task-queue-bullmq-resources.js.map +1 -1
- package/dist/infrastructure/task-queue-bullmq-state.d.ts +1 -0
- package/dist/infrastructure/task-queue-bullmq-state.js +1 -0
- package/dist/infrastructure/task-queue-bullmq-state.js.map +1 -1
- package/dist/infrastructure/task-queue-bullmq.constants.d.ts +2 -1
- package/dist/infrastructure/task-queue-bullmq.constants.js +2 -1
- package/dist/infrastructure/task-queue-bullmq.constants.js.map +1 -1
- package/dist/infrastructure/task-queue-bullmq.js +10 -1
- package/dist/infrastructure/task-queue-bullmq.js.map +1 -1
- package/dist/infrastructure/task-queue.js +13 -4
- package/dist/infrastructure/task-queue.js.map +1 -1
- package/dist/infrastructure/transfer-copy.d.ts +1 -0
- package/dist/infrastructure/transfer-copy.js +16 -1
- package/dist/infrastructure/transfer-copy.js.map +1 -1
- package/dist/infrastructure/transport-archive.d.ts +3 -3
- package/dist/infrastructure/transport-archive.js +71 -48
- package/dist/infrastructure/transport-archive.js.map +1 -1
- package/dist/infrastructure/transport-archive.types.d.ts +3 -0
- package/dist/infrastructure/transport-archive.types.js.map +1 -1
- package/dist/infrastructure/transport-checkpoint.js +14 -4
- package/dist/infrastructure/transport-checkpoint.js.map +1 -1
- package/dist/infrastructure/transport-envelope.d.ts +1 -0
- package/dist/infrastructure/transport-envelope.js +22 -5
- package/dist/infrastructure/transport-envelope.js.map +1 -1
- package/dist/infrastructure/transport-reservations.constants.d.ts +2 -0
- package/dist/infrastructure/transport-reservations.constants.js +3 -0
- package/dist/infrastructure/transport-reservations.constants.js.map +1 -0
- package/dist/infrastructure/transport-reservations.d.ts +1 -2
- package/dist/infrastructure/transport-reservations.js +18 -22
- package/dist/infrastructure/transport-reservations.js.map +1 -1
- package/dist/infrastructure/transport-reservations.types.d.ts +23 -2
- package/dist/infrastructure/transport-reservations.types.js.map +1 -1
- package/dist/infrastructure/trigger-server.js +12 -9
- package/dist/infrastructure/trigger-server.js.map +1 -1
- package/dist/infrastructure/trigger-server.types.d.ts +1 -1
- package/dist/infrastructure/trigger-server.types.js.map +1 -1
- package/dist/infrastructure/workflow-checkpoint.constants.d.ts +1 -0
- package/dist/infrastructure/workflow-checkpoint.constants.js +1 -0
- package/dist/infrastructure/workflow-checkpoint.constants.js.map +1 -1
- package/dist/infrastructure/workspace-lock.constants.d.ts +2 -1
- package/dist/infrastructure/workspace-lock.constants.js +2 -1
- package/dist/infrastructure/workspace-lock.constants.js.map +1 -1
- package/dist/infrastructure/workspace-lock.js +48 -10
- package/dist/infrastructure/workspace-lock.js.map +1 -1
- package/dist/providers/cloud-cache.js +14 -9
- package/dist/providers/cloud-cache.js.map +1 -1
- package/dist/providers/cloud-cache.types.d.ts +1 -0
- package/dist/providers/cloud-cache.types.js.map +1 -1
- package/dist/providers/cloud-files.js +3 -4
- package/dist/providers/cloud-files.js.map +1 -1
- package/dist/providers/cloud-input.constants.d.ts +2 -2
- package/dist/providers/cloud-input.constants.js +2 -1
- package/dist/providers/cloud-input.constants.js.map +1 -1
- package/dist/providers/cloud-input.d.ts +2 -2
- package/dist/providers/cloud-input.js +14 -3
- package/dist/providers/cloud-input.js.map +1 -1
- package/dist/providers/container-command.js +30 -5
- package/dist/providers/container-command.js.map +1 -1
- package/dist/providers/container-egress.constants.d.ts +7 -0
- package/dist/providers/container-egress.constants.js +8 -0
- package/dist/providers/container-egress.constants.js.map +1 -0
- package/dist/providers/container-egress.d.ts +7 -0
- package/dist/providers/container-egress.js +101 -0
- package/dist/providers/container-egress.js.map +1 -0
- package/dist/providers/container-files.js +10 -11
- package/dist/providers/container-files.js.map +1 -1
- package/dist/providers/container-mounts.js +3 -0
- package/dist/providers/container-mounts.js.map +1 -1
- package/dist/providers/container-network.js +16 -1
- package/dist/providers/container-network.js.map +1 -1
- package/dist/providers/container-plan.js +7 -10
- package/dist/providers/container-plan.js.map +1 -1
- package/dist/providers/container-recovery.js +8 -3
- package/dist/providers/container-recovery.js.map +1 -1
- package/dist/providers/container.js +36 -5
- package/dist/providers/container.js.map +1 -1
- package/dist/providers/container.types.d.ts +1 -0
- package/dist/providers/container.types.js.map +1 -1
- package/dist/providers/daytona-command.constants.js +4 -1
- package/dist/providers/daytona-command.constants.js.map +1 -1
- package/dist/providers/daytona-command.js +39 -16
- package/dist/providers/daytona-command.js.map +1 -1
- package/dist/providers/daytona-files.js +5 -5
- package/dist/providers/daytona-files.js.map +1 -1
- package/dist/providers/daytona-output.js +11 -3
- package/dist/providers/daytona-output.js.map +1 -1
- package/dist/providers/daytona.js +11 -9
- package/dist/providers/daytona.js.map +1 -1
- package/dist/providers/egress/address.d.ts +3 -0
- package/dist/providers/egress/address.js +26 -0
- package/dist/providers/egress/address.js.map +1 -0
- package/dist/providers/egress/egress.constants.d.ts +22 -0
- package/dist/providers/egress/egress.constants.js +23 -0
- package/dist/providers/egress/egress.constants.js.map +1 -0
- package/dist/providers/egress/egress.types.d.ts +11 -0
- package/dist/providers/egress/egress.types.js +2 -0
- package/dist/providers/egress/egress.types.js.map +1 -0
- package/dist/providers/egress/firewall.d.ts +3 -0
- package/dist/providers/egress/firewall.js +29 -0
- package/dist/providers/egress/firewall.js.map +1 -0
- package/dist/providers/egress/main.d.ts +1 -0
- package/dist/providers/egress/main.js +90 -0
- package/dist/providers/egress/main.js.map +1 -0
- package/dist/providers/egress/policy.d.ts +5 -0
- package/dist/providers/egress/policy.js +54 -0
- package/dist/providers/egress/policy.js.map +1 -0
- package/dist/providers/egress/proxy.d.ts +2 -0
- package/dist/providers/egress/proxy.js +129 -0
- package/dist/providers/egress/proxy.js.map +1 -0
- package/dist/providers/egress/tls-hello.d.ts +1 -0
- package/dist/providers/egress/tls-hello.js +75 -0
- package/dist/providers/egress/tls-hello.js.map +1 -0
- package/dist/providers/firecracker-command.js +12 -6
- package/dist/providers/firecracker-command.js.map +1 -1
- package/dist/providers/local-files.d.ts +2 -0
- package/dist/providers/local-files.js +24 -0
- package/dist/providers/local-files.js.map +1 -0
- package/dist/providers/local.js +2 -20
- package/dist/providers/local.js.map +1 -1
- package/dist/providers/vercel-command.js +33 -9
- package/dist/providers/vercel-command.js.map +1 -1
- package/dist/providers/vercel.js +11 -9
- package/dist/providers/vercel.js.map +1 -1
- package/dist/testing.d.ts +1 -1
- package/dist/testing.js +1 -1
- package/dist/testing.js.map +1 -1
- package/package.json +2 -2
- package/recipe-configuration.schema.json +2164 -35
- package/recipe.schema.json +2512 -404
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { setTimeout } from "node:timers/promises";
|
|
2
|
+
import { invariant, OutpostError } from "../domain/errors.js";
|
|
3
|
+
import { containerEgress, defaultEgressImage, } from "./container-egress.constants.js";
|
|
4
|
+
import { egressRuntime } from "./egress/egress.constants.js";
|
|
5
|
+
export function containerUserNamespace(engine, config, user) {
|
|
6
|
+
if (engine !== "podman" ||
|
|
7
|
+
config.userns === false ||
|
|
8
|
+
(process.getuid?.() === 0 && config.userns !== "keep-id"))
|
|
9
|
+
return [];
|
|
10
|
+
return [
|
|
11
|
+
"--userns",
|
|
12
|
+
config.user ? `keep-id:uid=${user.uid},gid=${user.gid}` : "keep-id",
|
|
13
|
+
];
|
|
14
|
+
}
|
|
15
|
+
export function createContainerEgress(call, name, config, engine, user) {
|
|
16
|
+
const companion = `${name}-egress`;
|
|
17
|
+
let attempted = false;
|
|
18
|
+
return {
|
|
19
|
+
name: companion,
|
|
20
|
+
async start(signal) {
|
|
21
|
+
invariant(config.egress?.mode === "allowlist", "Container egress requires an allowlist");
|
|
22
|
+
invariant(user.uid !== egressRuntime.uid, `UID ${egressRuntime.uid} is reserved for the egress proxy`);
|
|
23
|
+
const image = config.egressImage ?? defaultEgressImage;
|
|
24
|
+
invariant(image, "The default Outpost egress image has not been published; build images/egress and set egressImage");
|
|
25
|
+
const extra = signal ? { signal } : {};
|
|
26
|
+
attempted = true;
|
|
27
|
+
await call([
|
|
28
|
+
"create",
|
|
29
|
+
"--name",
|
|
30
|
+
companion,
|
|
31
|
+
"--network",
|
|
32
|
+
"bridge",
|
|
33
|
+
"--label",
|
|
34
|
+
`${containerEgress.label}=${name}`,
|
|
35
|
+
"--user",
|
|
36
|
+
"0:0",
|
|
37
|
+
...containerUserNamespace(engine, config, user),
|
|
38
|
+
"--cap-drop",
|
|
39
|
+
"ALL",
|
|
40
|
+
"--cap-add",
|
|
41
|
+
"NET_ADMIN",
|
|
42
|
+
"--cap-add",
|
|
43
|
+
"SETUID",
|
|
44
|
+
"--cap-add",
|
|
45
|
+
"SETGID",
|
|
46
|
+
"--security-opt",
|
|
47
|
+
"no-new-privileges",
|
|
48
|
+
"--read-only",
|
|
49
|
+
"--tmpfs",
|
|
50
|
+
"/run/outpost:rw,noexec,nosuid,size=1m,mode=0700",
|
|
51
|
+
"--env",
|
|
52
|
+
`OUTPOST_EGRESS_POLICY=${JSON.stringify(config.egress)}`,
|
|
53
|
+
"--entrypoint",
|
|
54
|
+
"node",
|
|
55
|
+
image,
|
|
56
|
+
containerEgress.entrypoint,
|
|
57
|
+
], extra);
|
|
58
|
+
await call(["start", companion], extra);
|
|
59
|
+
const deadline = Date.now() + containerEgress.startupMs;
|
|
60
|
+
while (true) {
|
|
61
|
+
signal?.throwIfAborted();
|
|
62
|
+
try {
|
|
63
|
+
await call([
|
|
64
|
+
"exec",
|
|
65
|
+
companion,
|
|
66
|
+
"node",
|
|
67
|
+
containerEgress.entrypoint,
|
|
68
|
+
"health",
|
|
69
|
+
String(egressRuntime.version),
|
|
70
|
+
], { ...extra, deadlineMs: 2_000 });
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
catch (cause) {
|
|
74
|
+
signal?.throwIfAborted();
|
|
75
|
+
const running = await call(["inspect", "--format", "{{.State.Running}}", companion], extra);
|
|
76
|
+
if (running.stdout.trim() !== "true" || Date.now() >= deadline)
|
|
77
|
+
throw new OutpostError("provider", "Container egress could not establish its firewall and proxy; sandbox execution refused", { engine }, cause);
|
|
78
|
+
await setTimeout(containerEgress.pollMs, undefined, extra);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
async release() {
|
|
83
|
+
if (!attempted)
|
|
84
|
+
return;
|
|
85
|
+
const found = await call([
|
|
86
|
+
"container",
|
|
87
|
+
"ls",
|
|
88
|
+
"--all",
|
|
89
|
+
"--filter",
|
|
90
|
+
`name=^${companion}$`,
|
|
91
|
+
"--format",
|
|
92
|
+
"{{.Names}}",
|
|
93
|
+
]);
|
|
94
|
+
if (!found.stdout.trim())
|
|
95
|
+
return;
|
|
96
|
+
invariant(found.stdout.trim() === companion, "Egress container identity mismatch");
|
|
97
|
+
await call(["rm", "--force", companion]);
|
|
98
|
+
},
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
//# sourceMappingURL=container-egress.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"container-egress.js","sourceRoot":"","sources":["../../src/providers/container-egress.ts"],"names":[],"mappings":"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","sourcesContent":["import { setTimeout } from \"node:timers/promises\";\nimport { invariant, OutpostError } from \"../domain/errors.ts\";\nimport {\n containerEgress,\n defaultEgressImage,\n} from \"./container-egress.constants.ts\";\nimport { egressRuntime } from \"./egress/egress.constants.ts\";\nimport type {\n ContainerCall,\n ContainerEngine,\n ContainerOptions,\n ContainerUser,\n} from \"./container.types.ts\";\n\nexport function containerUserNamespace(\n engine: ContainerEngine,\n config: ContainerOptions,\n user: ContainerUser,\n): string[] {\n if (\n engine !== \"podman\" ||\n config.userns === false ||\n (process.getuid?.() === 0 && config.userns !== \"keep-id\")\n )\n return [];\n return [\n \"--userns\",\n config.user ? `keep-id:uid=${user.uid},gid=${user.gid}` : \"keep-id\",\n ];\n}\n\nexport function createContainerEgress(\n call: ContainerCall,\n name: string,\n config: ContainerOptions,\n engine: ContainerEngine,\n user: ContainerUser,\n) {\n const companion = `${name}-egress`;\n let attempted = false;\n return {\n name: companion,\n async start(signal?: AbortSignal): Promise<void> {\n invariant(\n config.egress?.mode === \"allowlist\",\n \"Container egress requires an allowlist\",\n );\n invariant(\n user.uid !== egressRuntime.uid,\n `UID ${egressRuntime.uid} is reserved for the egress proxy`,\n );\n const image = config.egressImage ?? defaultEgressImage;\n invariant(\n image,\n \"The default Outpost egress image has not been published; build images/egress and set egressImage\",\n );\n const extra = signal ? { signal } : {};\n attempted = true;\n await call(\n [\n \"create\",\n \"--name\",\n companion,\n \"--network\",\n \"bridge\",\n \"--label\",\n `${containerEgress.label}=${name}`,\n \"--user\",\n \"0:0\",\n ...containerUserNamespace(engine, config, user),\n \"--cap-drop\",\n \"ALL\",\n \"--cap-add\",\n \"NET_ADMIN\",\n \"--cap-add\",\n \"SETUID\",\n \"--cap-add\",\n \"SETGID\",\n \"--security-opt\",\n \"no-new-privileges\",\n \"--read-only\",\n \"--tmpfs\",\n \"/run/outpost:rw,noexec,nosuid,size=1m,mode=0700\",\n \"--env\",\n `OUTPOST_EGRESS_POLICY=${JSON.stringify(config.egress)}`,\n \"--entrypoint\",\n \"node\",\n image,\n containerEgress.entrypoint,\n ],\n extra,\n );\n await call([\"start\", companion], extra);\n const deadline = Date.now() + containerEgress.startupMs;\n while (true) {\n signal?.throwIfAborted();\n try {\n await call(\n [\n \"exec\",\n companion,\n \"node\",\n containerEgress.entrypoint,\n \"health\",\n String(egressRuntime.version),\n ],\n { ...extra, deadlineMs: 2_000 },\n );\n return;\n } catch (cause) {\n signal?.throwIfAborted();\n const running = await call(\n [\"inspect\", \"--format\", \"{{.State.Running}}\", companion],\n extra,\n );\n if (running.stdout.trim() !== \"true\" || Date.now() >= deadline)\n throw new OutpostError(\n \"provider\",\n \"Container egress could not establish its firewall and proxy; sandbox execution refused\",\n { engine },\n cause,\n );\n await setTimeout(containerEgress.pollMs, undefined, extra);\n }\n }\n },\n async release(): Promise<void> {\n if (!attempted) return;\n const found = await call([\n \"container\",\n \"ls\",\n \"--all\",\n \"--filter\",\n `name=^${companion}$`,\n \"--format\",\n \"{{.Names}}\",\n ]);\n if (!found.stdout.trim()) return;\n invariant(\n found.stdout.trim() === companion,\n \"Egress container identity mismatch\",\n );\n await call([\"rm\", \"--force\", companion]);\n },\n };\n}\n"]}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
|
-
import {
|
|
2
|
+
import { mkdir, mkdtemp } from "node:fs/promises";
|
|
3
3
|
import { tmpdir } from "node:os";
|
|
4
4
|
import { basename, dirname, join, posix, resolve } from "node:path";
|
|
5
5
|
import { invariant, OutpostError } from "../domain/errors.js";
|
|
6
6
|
import { quote } from "../infrastructure/process.js";
|
|
7
|
-
import { copyTransfer, removeTransferDirectory, transferDestination, } from "../infrastructure/transfer-copy.js";
|
|
7
|
+
import { copyTransfer, removeTransferDirectory, transferDestination, transferTarget, } from "../infrastructure/transfer-copy.js";
|
|
8
8
|
import { transfer } from "../infrastructure/transfer.js";
|
|
9
|
+
import { transferDefaults } from "../infrastructure/transfer.constants.js";
|
|
9
10
|
import { containerArchive } from "./container-archive.js";
|
|
10
11
|
export function containerFiles(runtime, archive = containerArchive) {
|
|
11
12
|
const { call, name } = runtime;
|
|
@@ -15,6 +16,7 @@ export function containerFiles(runtime, archive = containerArchive) {
|
|
|
15
16
|
if (runtime.isClosed())
|
|
16
17
|
throw new OutpostError("provider", "Container sandbox is closed");
|
|
17
18
|
const absolute = resolve(source);
|
|
19
|
+
const target = posix.resolve(runtime.root, destination);
|
|
18
20
|
const scratch = `/tmp/outpost-transfer-${randomUUID()}`;
|
|
19
21
|
const entry = basename(absolute);
|
|
20
22
|
invariant(entry, "Upload a directory's contents using a non-root path");
|
|
@@ -23,9 +25,11 @@ export function containerFiles(runtime, archive = containerArchive) {
|
|
|
23
25
|
try {
|
|
24
26
|
await archive(runtime, {
|
|
25
27
|
executable: "tar",
|
|
28
|
+
deadlineMs: options.deadlineMs ?? transferDefaults.deadlineMs,
|
|
26
29
|
arguments: ["-cf", "-", "-C", dirname(absolute), "--", entry],
|
|
27
30
|
}, {
|
|
28
31
|
executable: "tar",
|
|
32
|
+
deadlineMs: options.deadlineMs ?? transferDefaults.deadlineMs,
|
|
29
33
|
arguments: [
|
|
30
34
|
"-xpf",
|
|
31
35
|
"-",
|
|
@@ -40,7 +44,7 @@ export function containerFiles(runtime, archive = containerArchive) {
|
|
|
40
44
|
name,
|
|
41
45
|
"sh",
|
|
42
46
|
"-c",
|
|
43
|
-
`mkdir -p ${quote(posix.dirname(
|
|
47
|
+
`mkdir -p ${quote(posix.dirname(target))} && cp -a -- ${quote(posix.join(scratch, entry) + (contents ? "/." : ""))} ${quote(target)}`,
|
|
44
48
|
], { signal });
|
|
45
49
|
}
|
|
46
50
|
finally {
|
|
@@ -66,6 +70,7 @@ export function containerFiles(runtime, archive = containerArchive) {
|
|
|
66
70
|
try {
|
|
67
71
|
await archive(runtime, {
|
|
68
72
|
executable: "tar",
|
|
73
|
+
deadlineMs: options.deadlineMs ?? transferDefaults.deadlineMs,
|
|
69
74
|
arguments: [
|
|
70
75
|
"-xpf",
|
|
71
76
|
"-",
|
|
@@ -76,6 +81,7 @@ export function containerFiles(runtime, archive = containerArchive) {
|
|
|
76
81
|
],
|
|
77
82
|
}, {
|
|
78
83
|
executable: "tar",
|
|
84
|
+
deadlineMs: options.deadlineMs ?? transferDefaults.deadlineMs,
|
|
79
85
|
arguments: [
|
|
80
86
|
"-cf",
|
|
81
87
|
"-",
|
|
@@ -85,14 +91,7 @@ export function containerFiles(runtime, archive = containerArchive) {
|
|
|
85
91
|
entry,
|
|
86
92
|
],
|
|
87
93
|
}, false, signal);
|
|
88
|
-
const
|
|
89
|
-
if (cause.code === "ENOENT")
|
|
90
|
-
return undefined;
|
|
91
|
-
throw cause;
|
|
92
|
-
});
|
|
93
|
-
const target = existing?.isDirectory() && !source.endsWith("/.")
|
|
94
|
-
? join(destination, entry)
|
|
95
|
-
: destination;
|
|
94
|
+
const target = await transferTarget(entry, destination, source.endsWith("/."));
|
|
96
95
|
await mkdir(dirname(target), { recursive: true });
|
|
97
96
|
await copyTransfer(join(scratch, entry), target, signal);
|
|
98
97
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"container-files.js","sourceRoot":"","sources":["../../src/providers/container-files.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"container-files.js","sourceRoot":"","sources":["../../src/providers/container-files.ts"],"names":[],"mappings":"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","sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport { mkdir, mkdtemp } from \"node:fs/promises\";\nimport { tmpdir } from \"node:os\";\nimport { basename, dirname, join, posix, resolve } from \"node:path\";\nimport type { SandboxLease } from \"../domain/sandbox.types.ts\";\nimport { invariant, OutpostError } from \"../domain/errors.ts\";\nimport { quote } from \"../infrastructure/process.ts\";\nimport {\n copyTransfer,\n removeTransferDirectory,\n transferDestination,\n transferTarget,\n} from \"../infrastructure/transfer-copy.ts\";\nimport { transfer } from \"../infrastructure/transfer.ts\";\nimport { transferDefaults } from \"../infrastructure/transfer.constants.ts\";\nimport { containerArchive } from \"./container-archive.ts\";\nimport type { ContainerRuntime } from \"./container.types.ts\";\n\nexport function containerFiles(\n runtime: ContainerRuntime,\n archive = containerArchive,\n): Pick<SandboxLease, \"upload\" | \"download\"> {\n const { call, name } = runtime;\n return {\n upload(source, destination, options = {}) {\n return transfer(options, async (signal) => {\n if (runtime.isClosed())\n throw new OutpostError(\"provider\", \"Container sandbox is closed\");\n const absolute = resolve(source);\n const target = posix.resolve(runtime.root, destination);\n const scratch = `/tmp/outpost-transfer-${randomUUID()}`;\n const entry = basename(absolute);\n invariant(entry, \"Upload a directory's contents using a non-root path\");\n const contents = /[\\\\/]\\.$/.test(source);\n await call([\"exec\", name, \"mkdir\", \"-m\", \"700\", scratch], { signal });\n try {\n await archive(\n runtime,\n {\n executable: \"tar\",\n deadlineMs: options.deadlineMs ?? transferDefaults.deadlineMs,\n arguments: [\"-cf\", \"-\", \"-C\", dirname(absolute), \"--\", entry],\n },\n {\n executable: \"tar\",\n deadlineMs: options.deadlineMs ?? transferDefaults.deadlineMs,\n arguments: [\n \"-xpf\",\n \"-\",\n \"--ignore-zeros\",\n \"--no-same-owner\",\n \"-C\",\n scratch,\n ],\n },\n true,\n signal,\n );\n await call(\n [\n \"exec\",\n name,\n \"sh\",\n \"-c\",\n `mkdir -p ${quote(posix.dirname(target))} && cp -a -- ${quote(posix.join(scratch, entry) + (contents ? \"/.\" : \"\"))} ${quote(target)}`,\n ],\n { signal },\n );\n } finally {\n await call([\n \"exec\",\n name,\n \"sh\",\n \"-c\",\n `chmod -R u+rwX ${quote(scratch)} && rm -rf -- ${quote(scratch)}`,\n ]);\n }\n });\n },\n download(source, destination, options = {}) {\n return transfer(options, async (signal) => {\n if (runtime.isClosed())\n throw new OutpostError(\"provider\", \"Container sandbox is closed\");\n await transferDestination(destination);\n const absolute = posix.resolve(runtime.root, source);\n const entry = posix.basename(absolute);\n invariant(\n entry,\n \"Download a directory's contents using a non-root path\",\n );\n const scratch = await mkdtemp(join(tmpdir(), \"outpost-transfer-\"));\n try {\n await archive(\n runtime,\n {\n executable: \"tar\",\n deadlineMs: options.deadlineMs ?? transferDefaults.deadlineMs,\n arguments: [\n \"-xpf\",\n \"-\",\n \"--ignore-zeros\",\n \"--no-same-owner\",\n \"-C\",\n scratch,\n ],\n },\n {\n executable: \"tar\",\n deadlineMs: options.deadlineMs ?? transferDefaults.deadlineMs,\n arguments: [\n \"-cf\",\n \"-\",\n \"-C\",\n posix.dirname(absolute),\n \"--\",\n entry,\n ],\n },\n false,\n signal,\n );\n const target = await transferTarget(\n entry,\n destination,\n source.endsWith(\"/.\"),\n );\n await mkdir(dirname(target), { recursive: true });\n await copyTransfer(join(scratch, entry), target, signal);\n } finally {\n await removeTransferDirectory(scratch);\n }\n });\n },\n };\n}\n"]}
|
|
@@ -70,6 +70,9 @@ export async function containerMounts(context, config, platform, root, home) {
|
|
|
70
70
|
fileParents.add(folder);
|
|
71
71
|
}
|
|
72
72
|
invariant(!source.includes(",") && !target.includes(","), "Mount paths cannot contain commas");
|
|
73
|
+
invariant(config.label === false ||
|
|
74
|
+
platform !== "linux" ||
|
|
75
|
+
(!source.includes(":") && !target.includes(":")), "SELinux-labelled mount paths cannot contain colons; use label: false for --mount syntax");
|
|
73
76
|
if (config.label === false || platform !== "linux")
|
|
74
77
|
volumes.push("--mount", `type=bind,source=${source},target=${target}${volume.readOnly ? ",readonly" : ""}`);
|
|
75
78
|
else
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"container-mounts.js","sourceRoot":"","sources":["../../src/providers/container-mounts.ts"],"names":[],"mappings":"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","sourcesContent":["import { stat } from \"node:fs/promises\";\nimport { isAbsolute, posix, relative } from \"node:path\";\nimport { invariant, OutpostError } from \"../domain/errors.ts\";\nimport type { SandboxContext, Volume } from \"../domain/sandbox.types.ts\";\nimport { expandPath } from \"../infrastructure/files.ts\";\nimport { inside } from \"../infrastructure/files.ts\";\nimport { canonicalWorkspacePath } from \"../infrastructure/workspace-lock.ts\";\nimport { validateIsolatedMount } from \"./container-isolation.ts\";\nimport type { ContainerMounts, ContainerOptions } from \"./container.types.ts\";\n\nexport async function containerMounts(\n context: SandboxContext,\n config: ContainerOptions,\n platform: NodeJS.Platform,\n root: string,\n home: string,\n): Promise<ContainerMounts> {\n const env: Record<string, string> = {\n ...context.variables,\n HOME: home,\n ...(context.workspaceIdentity === undefined\n ? {\n GIT_CONFIG_COUNT: \"1\",\n GIT_CONFIG_KEY_0: \"safe.directory\",\n GIT_CONFIG_VALUE_0: \"*\",\n }\n : {}),\n };\n const internal: Volume[] =\n config.repositoryMode === \"isolated\"\n ? []\n : [{ source: context.directory, target: root }];\n if (config.repositoryMode !== \"isolated\" && context.gitDirectories.length) {\n const common = context.gitDirectories.at(-1)!;\n const offset = relative(common, context.gitDirectories[0]!);\n const nested =\n !isAbsolute(offset) &&\n offset !== \"..\" &&\n !offset.startsWith(\"..\\\\\") &&\n !offset.startsWith(\"../\");\n internal.push({\n source: common,\n target: \"/outpost/git/common\",\n });\n if (!nested)\n internal.push({\n source: context.gitDirectories[0]!,\n target: \"/outpost/git/worktree\",\n });\n env.GIT_DIR = nested\n ? posix.join(\"/outpost/git/common\", offset.replaceAll(\"\\\\\", \"/\"))\n : \"/outpost/git/worktree\";\n env.GIT_COMMON_DIR = \"/outpost/git/common\";\n env.GIT_WORK_TREE = root;\n }\n const volumes: string[] = [];\n const fileParents = new Set<string>();\n for (const volume of [...internal, ...(config.volumes ?? [])]) {\n const source = expandPath(volume.source, context.repository);\n const info = await stat(source).catch(() => undefined);\n if (!info)\n throw new OutpostError(\n \"provider\",\n `Mount source is unavailable: ${source}`,\n );\n const destination = volume.target.replaceAll(\"\\\\\", \"/\");\n const target =\n destination === \"~\"\n ? home\n : destination.startsWith(\"~/\")\n ? posix.resolve(home, destination.slice(2))\n : posix.resolve(root, destination);\n if (context.workspaceIdentity !== undefined && !internal.includes(volume)) {\n const canonicalSource = await canonicalWorkspacePath(source);\n const control = await canonicalWorkspacePath(context.repository);\n invariant(\n !inside(canonicalSource, control) && !inside(control, canonicalSource),\n \"File workspace mounts cannot expose runtime control storage\",\n );\n invariant(\n target !== root && !root.startsWith(`${target}/`),\n \"Custom mounts cannot replace the owned workspace root\",\n );\n }\n if (config.repositoryMode === \"isolated\")\n await validateIsolatedMount(context, source, target);\n if (info.isFile() && !internal.includes(volume)) {\n const parent = posix.dirname(target);\n invariant(\n parent === home || parent.startsWith(home + \"/\"),\n \"File mounts must live inside the agent home; mount the containing directory for other destinations\",\n );\n for (let folder = parent; folder !== home; folder = posix.dirname(folder))\n fileParents.add(folder);\n }\n invariant(\n !source.includes(\",\") && !target.includes(\",\"),\n \"Mount paths cannot contain commas\",\n );\n if (config.label === false || platform !== \"linux\")\n volumes.push(\n \"--mount\",\n `type=bind,source=${source},target=${target}${volume.readOnly ? \",readonly\" : \"\"}`,\n );\n else\n volumes.push(\n \"--volume\",\n `${source}:${target}:${volume.readOnly ? \"ro,\" : \"\"}${config.label ?? \"z\"}`,\n );\n }\n\n return { env, volumes, fileParents };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"container-mounts.js","sourceRoot":"","sources":["../../src/providers/container-mounts.ts"],"names":[],"mappings":"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","sourcesContent":["import { stat } from \"node:fs/promises\";\nimport { isAbsolute, posix, relative } from \"node:path\";\nimport { invariant, OutpostError } from \"../domain/errors.ts\";\nimport type { SandboxContext, Volume } from \"../domain/sandbox.types.ts\";\nimport { expandPath } from \"../infrastructure/files.ts\";\nimport { inside } from \"../infrastructure/files.ts\";\nimport { canonicalWorkspacePath } from \"../infrastructure/workspace-lock.ts\";\nimport { validateIsolatedMount } from \"./container-isolation.ts\";\nimport type { ContainerMounts, ContainerOptions } from \"./container.types.ts\";\n\nexport async function containerMounts(\n context: SandboxContext,\n config: ContainerOptions,\n platform: NodeJS.Platform,\n root: string,\n home: string,\n): Promise<ContainerMounts> {\n const env: Record<string, string> = {\n ...context.variables,\n HOME: home,\n ...(context.workspaceIdentity === undefined\n ? {\n GIT_CONFIG_COUNT: \"1\",\n GIT_CONFIG_KEY_0: \"safe.directory\",\n GIT_CONFIG_VALUE_0: \"*\",\n }\n : {}),\n };\n const internal: Volume[] =\n config.repositoryMode === \"isolated\"\n ? []\n : [{ source: context.directory, target: root }];\n if (config.repositoryMode !== \"isolated\" && context.gitDirectories.length) {\n const common = context.gitDirectories.at(-1)!;\n const offset = relative(common, context.gitDirectories[0]!);\n const nested =\n !isAbsolute(offset) &&\n offset !== \"..\" &&\n !offset.startsWith(\"..\\\\\") &&\n !offset.startsWith(\"../\");\n internal.push({\n source: common,\n target: \"/outpost/git/common\",\n });\n if (!nested)\n internal.push({\n source: context.gitDirectories[0]!,\n target: \"/outpost/git/worktree\",\n });\n env.GIT_DIR = nested\n ? posix.join(\"/outpost/git/common\", offset.replaceAll(\"\\\\\", \"/\"))\n : \"/outpost/git/worktree\";\n env.GIT_COMMON_DIR = \"/outpost/git/common\";\n env.GIT_WORK_TREE = root;\n }\n const volumes: string[] = [];\n const fileParents = new Set<string>();\n for (const volume of [...internal, ...(config.volumes ?? [])]) {\n const source = expandPath(volume.source, context.repository);\n const info = await stat(source).catch(() => undefined);\n if (!info)\n throw new OutpostError(\n \"provider\",\n `Mount source is unavailable: ${source}`,\n );\n const destination = volume.target.replaceAll(\"\\\\\", \"/\");\n const target =\n destination === \"~\"\n ? home\n : destination.startsWith(\"~/\")\n ? posix.resolve(home, destination.slice(2))\n : posix.resolve(root, destination);\n if (context.workspaceIdentity !== undefined && !internal.includes(volume)) {\n const canonicalSource = await canonicalWorkspacePath(source);\n const control = await canonicalWorkspacePath(context.repository);\n invariant(\n !inside(canonicalSource, control) && !inside(control, canonicalSource),\n \"File workspace mounts cannot expose runtime control storage\",\n );\n invariant(\n target !== root && !root.startsWith(`${target}/`),\n \"Custom mounts cannot replace the owned workspace root\",\n );\n }\n if (config.repositoryMode === \"isolated\")\n await validateIsolatedMount(context, source, target);\n if (info.isFile() && !internal.includes(volume)) {\n const parent = posix.dirname(target);\n invariant(\n parent === home || parent.startsWith(home + \"/\"),\n \"File mounts must live inside the agent home; mount the containing directory for other destinations\",\n );\n for (let folder = parent; folder !== home; folder = posix.dirname(folder))\n fileParents.add(folder);\n }\n invariant(\n !source.includes(\",\") && !target.includes(\",\"),\n \"Mount paths cannot contain commas\",\n );\n invariant(\n config.label === false ||\n platform !== \"linux\" ||\n (!source.includes(\":\") && !target.includes(\":\")),\n \"SELinux-labelled mount paths cannot contain colons; use label: false for --mount syntax\",\n );\n if (config.label === false || platform !== \"linux\")\n volumes.push(\n \"--mount\",\n `type=bind,source=${source},target=${target}${volume.readOnly ? \",readonly\" : \"\"}`,\n );\n else\n volumes.push(\n \"--volume\",\n `${source}:${target}:${volume.readOnly ? \"ro,\" : \"\"}${config.label ?? \"z\"}`,\n );\n }\n\n return { env, volumes, fileParents };\n}\n"]}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { validateEgress } from "../domain/egress.js";
|
|
2
2
|
import { invariant } from "../domain/errors.js";
|
|
3
|
+
import { egressCidr } from "./egress/address.js";
|
|
3
4
|
export function containerNetworks(options) {
|
|
4
5
|
const policy = validateEgress(options.egress);
|
|
5
6
|
const networks = typeof options.networks === "string"
|
|
@@ -7,7 +8,21 @@ export function containerNetworks(options) {
|
|
|
7
8
|
: [...(options.networks ?? [])];
|
|
8
9
|
if (!policy)
|
|
9
10
|
return networks;
|
|
10
|
-
|
|
11
|
+
if (policy.mode === "allowlist") {
|
|
12
|
+
for (const cidr of [
|
|
13
|
+
...(policy.allowCidrs ?? []),
|
|
14
|
+
...(policy.denyCidrs ?? []),
|
|
15
|
+
]) {
|
|
16
|
+
try {
|
|
17
|
+
egressCidr(cidr);
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
invariant(false, "IPv4-mapped egress CIDRs require a prefix of at least 96");
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
invariant(networks.length === 0, "egress allowlist conflicts with configured networks");
|
|
24
|
+
return [];
|
|
25
|
+
}
|
|
11
26
|
invariant(networks.every((network) => network === "none"), "egress deny-all conflicts with configured networks");
|
|
12
27
|
return ["none"];
|
|
13
28
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"container-network.js","sourceRoot":"","sources":["../../src/providers/container-network.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"container-network.js","sourceRoot":"","sources":["../../src/providers/container-network.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAEhD,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAEjD,MAAM,UAAU,iBAAiB,CAC/B,OAAyB;IAEzB,MAAM,MAAM,GAAG,cAAc,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IAC9C,MAAM,QAAQ,GACZ,OAAO,OAAO,CAAC,QAAQ,KAAK,QAAQ;QAClC,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC;QACpB,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC,CAAC;IACpC,IAAI,CAAC,MAAM;QAAE,OAAO,QAAQ,CAAC;IAC7B,IAAI,MAAM,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;QAChC,KAAK,MAAM,IAAI,IAAI;YACjB,GAAG,CAAC,MAAM,CAAC,UAAU,IAAI,EAAE,CAAC;YAC5B,GAAG,CAAC,MAAM,CAAC,SAAS,IAAI,EAAE,CAAC;SAC5B,EAAE,CAAC;YACF,IAAI,CAAC;gBACH,UAAU,CAAC,IAAI,CAAC,CAAC;YACnB,CAAC;YAAC,MAAM,CAAC;gBACP,SAAS,CACP,KAAK,EACL,0DAA0D,CAC3D,CAAC;YACJ,CAAC;QACH,CAAC;QACD,SAAS,CACP,QAAQ,CAAC,MAAM,KAAK,CAAC,EACrB,qDAAqD,CACtD,CAAC;QACF,OAAO,EAAE,CAAC;IACZ,CAAC;IACD,SAAS,CACP,QAAQ,CAAC,KAAK,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,KAAK,MAAM,CAAC,EAC/C,oDAAoD,CACrD,CAAC;IACF,OAAO,CAAC,MAAM,CAAC,CAAC;AAClB,CAAC","sourcesContent":["import { validateEgress } from \"../domain/egress.ts\";\nimport { invariant } from \"../domain/errors.ts\";\nimport type { ContainerOptions } from \"./container.types.ts\";\nimport { egressCidr } from \"./egress/address.ts\";\n\nexport function containerNetworks(\n options: ContainerOptions,\n): readonly string[] {\n const policy = validateEgress(options.egress);\n const networks =\n typeof options.networks === \"string\"\n ? [options.networks]\n : [...(options.networks ?? [])];\n if (!policy) return networks;\n if (policy.mode === \"allowlist\") {\n for (const cidr of [\n ...(policy.allowCidrs ?? []),\n ...(policy.denyCidrs ?? []),\n ]) {\n try {\n egressCidr(cidr);\n } catch {\n invariant(\n false,\n \"IPv4-mapped egress CIDRs require a prefix of at least 96\",\n );\n }\n }\n invariant(\n networks.length === 0,\n \"egress allowlist conflicts with configured networks\",\n );\n return [];\n }\n invariant(\n networks.every((network) => network === \"none\"),\n \"egress deny-all conflicts with configured networks\",\n );\n return [\"none\"];\n}\n"]}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { containerUserNamespace } from "./container-egress.js";
|
|
1
2
|
export function containerPlan({ config, engine, user, root, name, image, volumes, fileParents, }) {
|
|
2
3
|
const networks = typeof config.networks === "string"
|
|
3
4
|
? [config.networks]
|
|
@@ -9,19 +10,15 @@ export function containerPlan({ config, engine, user, root, name, image, volumes
|
|
|
9
10
|
"--init",
|
|
10
11
|
"--user",
|
|
11
12
|
`${user.uid}:${user.gid}`,
|
|
12
|
-
...(engine === "podman" &&
|
|
13
|
-
|
|
14
|
-
(
|
|
15
|
-
? [
|
|
16
|
-
"--userns",
|
|
17
|
-
config.user ? `keep-id:uid=${user.uid},gid=${user.gid}` : "keep-id",
|
|
18
|
-
]
|
|
19
|
-
: []),
|
|
13
|
+
...(engine === "podman" && config.egress?.mode === "allowlist"
|
|
14
|
+
? ["--userns", `container:${name}-egress`]
|
|
15
|
+
: containerUserNamespace(engine, config, user)),
|
|
20
16
|
"--workdir",
|
|
21
17
|
config.repositoryMode === "isolated" ? "/" : root,
|
|
22
18
|
"--cap-drop",
|
|
23
19
|
"ALL",
|
|
24
|
-
...(
|
|
20
|
+
...(engine === "podman" ||
|
|
21
|
+
fileParents.size ||
|
|
25
22
|
config.caches?.length ||
|
|
26
23
|
config.repositoryMode === "isolated"
|
|
27
24
|
? ["--cap-add", "CHOWN"]
|
|
@@ -30,7 +27,7 @@ export function containerPlan({ config, engine, user, root, name, image, volumes
|
|
|
30
27
|
"no-new-privileges",
|
|
31
28
|
"--tmpfs",
|
|
32
29
|
engine === "podman"
|
|
33
|
-
? "/home/agent:rw,mode=
|
|
30
|
+
? "/home/agent:rw,mode=0700"
|
|
34
31
|
: `/home/agent:rw,uid=${fileParents.size ? 0 : user.uid},gid=${fileParents.size ? 0 : user.gid},mode=0700`,
|
|
35
32
|
...volumes,
|
|
36
33
|
...networks.flatMap((network) => ["--network", network]),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"container-plan.js","sourceRoot":"","sources":["../../src/providers/container-plan.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"container-plan.js","sourceRoot":"","sources":["../../src/providers/container-plan.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAE/D,MAAM,UAAU,aAAa,CAAC,EAC5B,MAAM,EACN,MAAM,EACN,IAAI,EACJ,IAAI,EACJ,IAAI,EACJ,KAAK,EACL,OAAO,EACP,WAAW,GACU;IACrB,MAAM,QAAQ,GACZ,OAAO,MAAM,CAAC,QAAQ,KAAK,QAAQ;QACjC,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC;QACnB,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC;IAC9B,MAAM,IAAI,GAAG;QACX,QAAQ;QACR,QAAQ;QACR,IAAI;QACJ,QAAQ;QACR,QAAQ;QACR,GAAG,IAAI,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,EAAE;QACzB,GAAG,CAAC,MAAM,KAAK,QAAQ,IAAI,MAAM,CAAC,MAAM,EAAE,IAAI,KAAK,WAAW;YAC5D,CAAC,CAAC,CAAC,UAAU,EAAE,aAAa,IAAI,SAAS,CAAC;YAC1C,CAAC,CAAC,sBAAsB,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC;QACjD,WAAW;QACX,MAAM,CAAC,cAAc,KAAK,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI;QACjD,YAAY;QACZ,KAAK;QACL,GAAG,CAAC,MAAM,KAAK,QAAQ;YACvB,WAAW,CAAC,IAAI;YAChB,MAAM,CAAC,MAAM,EAAE,MAAM;YACrB,MAAM,CAAC,cAAc,KAAK,UAAU;YAClC,CAAC,CAAC,CAAC,WAAW,EAAE,OAAO,CAAC;YACxB,CAAC,CAAC,EAAE,CAAC;QACP,gBAAgB;QAChB,mBAAmB;QACnB,SAAS;QACT,MAAM,KAAK,QAAQ;YACjB,CAAC,CAAC,0BAA0B;YAC5B,CAAC,CAAC,sBAAsB,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,QAAQ,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,YAAY;QAC5G,GAAG,OAAO;QACV,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;QACxD,GAAG,CAAC,MAAM,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,aAAa,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QAC3E,GAAG,CAAC,MAAM,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;QACnE,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QACvD,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,UAAU,EAAE,GAAG,MAAM,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAC/D,cAAc;QACd,OAAO;QACP,KAAK;QACL,UAAU;KACX,CAAC;IAEF,OAAO,IAAI,CAAC;AACd,CAAC","sourcesContent":["import type { ContainerPlanOptions } from \"./container.types.ts\";\nimport { containerUserNamespace } from \"./container-egress.ts\";\n\nexport function containerPlan({\n config,\n engine,\n user,\n root,\n name,\n image,\n volumes,\n fileParents,\n}: ContainerPlanOptions): string[] {\n const networks =\n typeof config.networks === \"string\"\n ? [config.networks]\n : (config.networks ?? []);\n const args = [\n \"create\",\n \"--name\",\n name,\n \"--init\",\n \"--user\",\n `${user.uid}:${user.gid}`,\n ...(engine === \"podman\" && config.egress?.mode === \"allowlist\"\n ? [\"--userns\", `container:${name}-egress`]\n : containerUserNamespace(engine, config, user)),\n \"--workdir\",\n config.repositoryMode === \"isolated\" ? \"/\" : root,\n \"--cap-drop\",\n \"ALL\",\n ...(engine === \"podman\" ||\n fileParents.size ||\n config.caches?.length ||\n config.repositoryMode === \"isolated\"\n ? [\"--cap-add\", \"CHOWN\"]\n : []),\n \"--security-opt\",\n \"no-new-privileges\",\n \"--tmpfs\",\n engine === \"podman\"\n ? \"/home/agent:rw,mode=0700\"\n : `/home/agent:rw,uid=${fileParents.size ? 0 : user.uid},gid=${fileParents.size ? 0 : user.gid},mode=0700`,\n ...volumes,\n ...networks.flatMap((network) => [\"--network\", network]),\n ...(config.groups ?? []).flatMap((group) => [\"--group-add\", String(group)]),\n ...(config.devices ?? []).flatMap((device) => [\"--device\", device]),\n ...(config.cpus ? [\"--cpus\", String(config.cpus)] : []),\n ...(config.memoryMb ? [\"--memory\", `${config.memoryMb}m`] : []),\n \"--entrypoint\",\n \"sleep\",\n image,\n \"infinity\",\n ];\n\n return args;\n}\n"]}
|
|
@@ -14,7 +14,7 @@ export async function recoverContainer(engine, executor, resourceId, options = {
|
|
|
14
14
|
"ls",
|
|
15
15
|
"--all",
|
|
16
16
|
"--filter",
|
|
17
|
-
`name=^${resourceId}
|
|
17
|
+
`name=^${resourceId}(-egress)?$`,
|
|
18
18
|
"--format",
|
|
19
19
|
"{{.Names}}",
|
|
20
20
|
],
|
|
@@ -22,7 +22,12 @@ export async function recoverContainer(engine, executor, resourceId, options = {
|
|
|
22
22
|
}, executor);
|
|
23
23
|
if (!result.stdout.trim())
|
|
24
24
|
return;
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
const names = result.stdout.trim().split(/\r?\n/);
|
|
26
|
+
invariant(names.every((name) => name === resourceId || name === `${resourceId}-egress`), "Recoverable container identity mismatch");
|
|
27
|
+
for (const name of [resourceId, `${resourceId}-egress`]) {
|
|
28
|
+
if (!names.includes(name))
|
|
29
|
+
continue;
|
|
30
|
+
await requireSuccess({ executable: engine, arguments: ["rm", "--force", name], ...limits }, executor);
|
|
31
|
+
}
|
|
27
32
|
}
|
|
28
33
|
//# sourceMappingURL=container-recovery.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"container-recovery.js","sourceRoot":"","sources":["../../src/providers/container-recovery.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAEhD,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAE9D,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAG7D,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,MAAuB,EACvB,QAAkB,EAClB,UAAkB,EAClB,UAA2B,EAAE;IAE7B,SAAS,CACP,yBAAyB,CAAC,IAAI,CAAC,UAAU,CAAC,EAC1C,wCAAwC,CACzC,CAAC;IACF,MAAM,MAAM,GAAG;QACb,UAAU,EAAE,OAAO,CAAC,UAAU,IAAI,iBAAiB,CAAC,SAAS;QAC7D,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACtD,CAAC;IACF,MAAM,MAAM,GAAG,MAAM,cAAc,CACjC;QACE,UAAU,EAAE,MAAM;QAClB,SAAS,EAAE;YACT,WAAW;YACX,IAAI;YACJ,OAAO;YACP,UAAU;YACV,SAAS,UAAU,
|
|
1
|
+
{"version":3,"file":"container-recovery.js","sourceRoot":"","sources":["../../src/providers/container-recovery.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAEhD,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAE9D,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAG7D,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,MAAuB,EACvB,QAAkB,EAClB,UAAkB,EAClB,UAA2B,EAAE;IAE7B,SAAS,CACP,yBAAyB,CAAC,IAAI,CAAC,UAAU,CAAC,EAC1C,wCAAwC,CACzC,CAAC;IACF,MAAM,MAAM,GAAG;QACb,UAAU,EAAE,OAAO,CAAC,UAAU,IAAI,iBAAiB,CAAC,SAAS;QAC7D,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACtD,CAAC;IACF,MAAM,MAAM,GAAG,MAAM,cAAc,CACjC;QACE,UAAU,EAAE,MAAM;QAClB,SAAS,EAAE;YACT,WAAW;YACX,IAAI;YACJ,OAAO;YACP,UAAU;YACV,SAAS,UAAU,aAAa;YAChC,UAAU;YACV,YAAY;SACb;QACD,GAAG,MAAM;KACV,EACD,QAAQ,CACT,CAAC;IACF,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE;QAAE,OAAO;IAClC,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAClD,SAAS,CACP,KAAK,CAAC,KAAK,CACT,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,KAAK,UAAU,IAAI,IAAI,KAAK,GAAG,UAAU,SAAS,CACjE,EACD,yCAAyC,CAC1C,CAAC;IACF,KAAK,MAAM,IAAI,IAAI,CAAC,UAAU,EAAE,GAAG,UAAU,SAAS,CAAC,EAAE,CAAC;QACxD,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC;YAAE,SAAS;QACpC,MAAM,cAAc,CAClB,EAAE,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC,IAAI,EAAE,SAAS,EAAE,IAAI,CAAC,EAAE,GAAG,MAAM,EAAE,EACrE,QAAQ,CACT,CAAC;IACJ,CAAC;AACH,CAAC","sourcesContent":["import { invariant } from \"../domain/errors.ts\";\nimport type { TransferOptions } from \"../domain/sandbox.types.ts\";\nimport { requireSuccess } from \"../infrastructure/process.ts\";\nimport type { Executor } from \"../infrastructure/process.types.ts\";\nimport { containerDefaults } from \"./container.constants.ts\";\nimport type { ContainerEngine } from \"./container.types.ts\";\n\nexport async function recoverContainer(\n engine: ContainerEngine,\n executor: Executor,\n resourceId: string,\n options: TransferOptions = {},\n): Promise<void> {\n invariant(\n /^outpost-[a-f0-9-]{36}$/.test(resourceId),\n \"Invalid recoverable container identity\",\n );\n const limits = {\n deadlineMs: options.deadlineMs ?? containerDefaults.cleanupMs,\n ...(options.signal ? { signal: options.signal } : {}),\n };\n const result = await requireSuccess(\n {\n executable: engine,\n arguments: [\n \"container\",\n \"ls\",\n \"--all\",\n \"--filter\",\n `name=^${resourceId}(-egress)?$`,\n \"--format\",\n \"{{.Names}}\",\n ],\n ...limits,\n },\n executor,\n );\n if (!result.stdout.trim()) return;\n const names = result.stdout.trim().split(/\\r?\\n/);\n invariant(\n names.every(\n (name) => name === resourceId || name === `${resourceId}-egress`,\n ),\n \"Recoverable container identity mismatch\",\n );\n for (const name of [resourceId, `${resourceId}-egress`]) {\n if (!names.includes(name)) continue;\n await requireSuccess(\n { executable: engine, arguments: [\"rm\", \"--force\", name], ...limits },\n executor,\n );\n }\n}\n"]}
|
|
@@ -1,8 +1,12 @@
|
|
|
1
|
+
import { validateContainerImage } from "../domain/container-image.js";
|
|
1
2
|
import { recoverContainer } from "./container-recovery.js";
|
|
2
3
|
import { execFileSync } from "node:child_process";
|
|
3
4
|
import { randomUUID } from "node:crypto";
|
|
4
5
|
import { basename } from "node:path";
|
|
5
6
|
import { containerNetworks } from "./container-network.js";
|
|
7
|
+
import { validateEgress } from "../domain/egress.js";
|
|
8
|
+
import { createContainerEgress } from "./container-egress.js";
|
|
9
|
+
import { egressVariables } from "./egress/egress.constants.js";
|
|
6
10
|
import { invariant } from "../domain/errors.js";
|
|
7
11
|
import { executeProcess, quote, requireSuccess, } from "../infrastructure/process.js";
|
|
8
12
|
import { registerCleanup } from "../infrastructure/shutdown.js";
|
|
@@ -21,11 +25,22 @@ export function imageName(repository) {
|
|
|
21
25
|
.replace(/[^a-z0-9_.-]/g, "-") || "workspace"}`;
|
|
22
26
|
}
|
|
23
27
|
export function containerProvider(engine, options = {}, executor = executeProcess, platform = process.platform) {
|
|
28
|
+
if (options.image !== undefined)
|
|
29
|
+
validateContainerImage(options.image);
|
|
30
|
+
const policy = validateEgress(options.egress);
|
|
24
31
|
const config = {
|
|
25
32
|
...options,
|
|
33
|
+
...(policy ? { egress: policy } : {}),
|
|
26
34
|
networks: containerNetworks(options),
|
|
27
35
|
caches: (options.caches ?? []).map((cache) => ({ ...cache })),
|
|
28
36
|
};
|
|
37
|
+
if (config.egressImage !== undefined) {
|
|
38
|
+
invariant(config.egress?.mode === "allowlist", "egressImage requires an egress allowlist");
|
|
39
|
+
invariant(typeof config.egressImage === "string" &&
|
|
40
|
+
config.egressImage.length > 0 &&
|
|
41
|
+
!config.egressImage.startsWith("-") &&
|
|
42
|
+
!/\s/.test(config.egressImage), "Invalid egressImage reference");
|
|
43
|
+
}
|
|
29
44
|
invariant(config.repositoryMode === undefined ||
|
|
30
45
|
config.repositoryMode === "mounted" ||
|
|
31
46
|
config.repositoryMode === "isolated", "repositoryMode must be mounted or isolated");
|
|
@@ -67,11 +82,18 @@ export function containerProvider(engine, options = {}, executor = executeProces
|
|
|
67
82
|
? containerDefaults.isolatedRoot
|
|
68
83
|
: containerDefaults.root, home = containerDefaults.home;
|
|
69
84
|
const { env, volumes, fileParents } = await containerMounts(context, config, platform, root, home);
|
|
85
|
+
const egress = config.egress?.mode === "allowlist"
|
|
86
|
+
? createContainerEgress(call, name, config, engine, user)
|
|
87
|
+
: undefined;
|
|
88
|
+
if (egress)
|
|
89
|
+
Object.assign(env, egressVariables);
|
|
70
90
|
const caches = await cacheMounts(config.caches ?? [], context.repository, image, user, context.workspaceIdentity);
|
|
71
91
|
for (const cache of caches)
|
|
72
92
|
volumes.push("--volume", `${cache.volume}:${cache.target}:nocopy`);
|
|
73
93
|
const args = containerPlan({
|
|
74
|
-
config
|
|
94
|
+
config: egress
|
|
95
|
+
? { ...config, networks: [`container:${egress.name}`] }
|
|
96
|
+
: config,
|
|
75
97
|
engine,
|
|
76
98
|
user,
|
|
77
99
|
root,
|
|
@@ -81,10 +103,17 @@ export function containerProvider(engine, options = {}, executor = executeProces
|
|
|
81
103
|
fileParents,
|
|
82
104
|
});
|
|
83
105
|
let closed = false, releasing;
|
|
106
|
+
let attempted = false;
|
|
84
107
|
let unregister = () => { };
|
|
85
108
|
const release = () => {
|
|
86
109
|
closed = true;
|
|
87
|
-
releasing ??=
|
|
110
|
+
releasing ??= (async () => {
|
|
111
|
+
if (attempted) {
|
|
112
|
+
await call(["rm", "--force", name]);
|
|
113
|
+
attempted = false;
|
|
114
|
+
}
|
|
115
|
+
await egress?.release();
|
|
116
|
+
})()
|
|
88
117
|
.then(() => {
|
|
89
118
|
unregister();
|
|
90
119
|
})
|
|
@@ -106,6 +135,8 @@ export function containerProvider(engine, options = {}, executor = executeProces
|
|
|
106
135
|
], context.signal ? { signal: context.signal } : {});
|
|
107
136
|
await context.registerRecovery?.(name);
|
|
108
137
|
context.signal?.throwIfAborted();
|
|
138
|
+
await egress?.start(context.signal);
|
|
139
|
+
attempted = true;
|
|
109
140
|
await call(args, {
|
|
110
141
|
...(context.signal ? { signal: context.signal } : {}),
|
|
111
142
|
});
|
|
@@ -132,7 +163,7 @@ export function containerProvider(engine, options = {}, executor = executeProces
|
|
|
132
163
|
"-c",
|
|
133
164
|
`mkdir -p ${quote(parent)} && chown ${user.uid}:${user.gid} ${quote(parent)}`,
|
|
134
165
|
]);
|
|
135
|
-
if (fileParents.size)
|
|
166
|
+
if (engine === "podman" || fileParents.size)
|
|
136
167
|
await call([
|
|
137
168
|
"exec",
|
|
138
169
|
"--user",
|
|
@@ -170,8 +201,8 @@ export function containerProvider(engine, options = {}, executor = executeProces
|
|
|
170
201
|
throw cause;
|
|
171
202
|
}
|
|
172
203
|
unregister = registerCleanup(release, () => {
|
|
173
|
-
if (
|
|
174
|
-
execFileSync(engine, ["rm", "--force", name], {
|
|
204
|
+
if (attempted)
|
|
205
|
+
execFileSync(engine, ["rm", "--force", name, ...(egress ? [egress.name] : [])], {
|
|
175
206
|
timeout: containerDefaults.cleanupMs,
|
|
176
207
|
stdio: "ignore",
|
|
177
208
|
windowsHide: true,
|