lastlight 0.16.0 → 0.16.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +71 -692
- package/dist/cli-config.js.map +1 -0
- package/dist/cli-format.js.map +1 -0
- package/dist/{cli/cli-server.d.ts → cli-server.d.ts} +39 -1
- package/dist/{cli/cli-server.js → cli-server.js} +105 -5
- package/dist/cli-server.js.map +1 -0
- package/dist/cli-timeline.js.map +1 -0
- package/dist/{cli/cli.js → cli.js} +9 -7
- package/dist/cli.js.map +1 -0
- package/dist/{cli/fork-cli.d.ts → fork-cli.d.ts} +3 -3
- package/dist/{cli/fork-cli.js → fork-cli.js} +28 -27
- package/dist/fork-cli.js.map +1 -0
- package/dist/{cli/oauth-cli.js → oauth-cli.js} +1 -1
- package/dist/oauth-cli.js.map +1 -0
- package/dist/{cli/setup.js → setup.js} +10 -4
- package/dist/setup.js.map +1 -0
- package/dist/{cli/skills-install.d.ts → skills-install.d.ts} +6 -0
- package/dist/{cli/skills-install.js → skills-install.js} +6 -2
- package/dist/skills-install.js.map +1 -0
- package/package.json +20 -65
- package/plugins/lastlight/.claude-plugin/plugin.json +1 -1
- package/agent-context/rules.md +0 -80
- package/agent-context/security.md +0 -69
- package/agent-context/soul.md +0 -21
- package/config/default.yaml +0 -119
- package/deploy/.env.production.example +0 -100
- package/deploy/entrypoint.sh +0 -82
- package/deploy/native/README.md +0 -160
- package/deploy/native/install.sh +0 -110
- package/deploy/native/lastlight.env.example +0 -95
- package/deploy/native/lastlight.service +0 -50
- package/deploy/sandbox-entrypoint.sh +0 -93
- package/dist/admin/auth.d.ts +0 -51
- package/dist/admin/auth.js +0 -121
- package/dist/admin/auth.js.map +0 -1
- package/dist/admin/chat-session-reader.d.ts +0 -39
- package/dist/admin/chat-session-reader.js +0 -84
- package/dist/admin/chat-session-reader.js.map +0 -1
- package/dist/admin/docker.d.ts +0 -61
- package/dist/admin/docker.js +0 -187
- package/dist/admin/docker.js.map +0 -1
- package/dist/admin/index.d.ts +0 -9
- package/dist/admin/index.js +0 -59
- package/dist/admin/index.js.map +0 -1
- package/dist/admin/routes.d.ts +0 -81
- package/dist/admin/routes.js +0 -1381
- package/dist/admin/routes.js.map +0 -1
- package/dist/admin/sessions.d.ts +0 -89
- package/dist/admin/sessions.js +0 -204
- package/dist/admin/sessions.js.map +0 -1
- package/dist/admin/tail.d.ts +0 -12
- package/dist/admin/tail.js +0 -145
- package/dist/admin/tail.js.map +0 -1
- package/dist/admin/version.d.ts +0 -22
- package/dist/admin/version.js +0 -92
- package/dist/admin/version.js.map +0 -1
- package/dist/cli/cli-config.js.map +0 -1
- package/dist/cli/cli-format.js.map +0 -1
- package/dist/cli/cli-server.js.map +0 -1
- package/dist/cli/cli-timeline.js.map +0 -1
- package/dist/cli/cli.js.map +0 -1
- package/dist/cli/fork-cli.js.map +0 -1
- package/dist/cli/oauth-cli.js.map +0 -1
- package/dist/cli/setup.js.map +0 -1
- package/dist/cli/skills-install.js.map +0 -1
- package/dist/config/config-resolve.d.ts +0 -28
- package/dist/config/config-resolve.js +0 -47
- package/dist/config/config-resolve.js.map +0 -1
- package/dist/config/config.d.ts +0 -157
- package/dist/config/config.js +0 -581
- package/dist/config/config.js.map +0 -1
- package/dist/config/core-pin.d.ts +0 -16
- package/dist/config/core-pin.js +0 -85
- package/dist/config/core-pin.js.map +0 -1
- package/dist/config/overlay-assets.d.ts +0 -20
- package/dist/config/overlay-assets.js +0 -114
- package/dist/config/overlay-assets.js.map +0 -1
- package/dist/config/overlay-bootstrap.d.ts +0 -44
- package/dist/config/overlay-bootstrap.js +0 -304
- package/dist/config/overlay-bootstrap.js.map +0 -1
- package/dist/connectors/github-webhook.d.ts +0 -45
- package/dist/connectors/github-webhook.js +0 -321
- package/dist/connectors/github-webhook.js.map +0 -1
- package/dist/connectors/index.d.ts +0 -18
- package/dist/connectors/index.js +0 -41
- package/dist/connectors/index.js.map +0 -1
- package/dist/connectors/messaging/base.d.ts +0 -42
- package/dist/connectors/messaging/base.js +0 -139
- package/dist/connectors/messaging/base.js.map +0 -1
- package/dist/connectors/messaging/delivery.d.ts +0 -14
- package/dist/connectors/messaging/delivery.js +0 -38
- package/dist/connectors/messaging/delivery.js.map +0 -1
- package/dist/connectors/messaging/index.d.ts +0 -4
- package/dist/connectors/messaging/index.js +0 -4
- package/dist/connectors/messaging/index.js.map +0 -1
- package/dist/connectors/messaging/session-manager.d.ts +0 -53
- package/dist/connectors/messaging/session-manager.js +0 -255
- package/dist/connectors/messaging/session-manager.js.map +0 -1
- package/dist/connectors/messaging/types.d.ts +0 -58
- package/dist/connectors/messaging/types.js +0 -7
- package/dist/connectors/messaging/types.js.map +0 -1
- package/dist/connectors/slack/connector.d.ts +0 -142
- package/dist/connectors/slack/connector.js +0 -494
- package/dist/connectors/slack/connector.js.map +0 -1
- package/dist/connectors/slack/index.d.ts +0 -2
- package/dist/connectors/slack/index.js +0 -3
- package/dist/connectors/slack/index.js.map +0 -1
- package/dist/connectors/slack/mrkdwn.d.ts +0 -19
- package/dist/connectors/slack/mrkdwn.js +0 -240
- package/dist/connectors/slack/mrkdwn.js.map +0 -1
- package/dist/connectors/types.d.ts +0 -61
- package/dist/connectors/types.js +0 -2
- package/dist/connectors/types.js.map +0 -1
- package/dist/cron/fanout.d.ts +0 -33
- package/dist/cron/fanout.js +0 -55
- package/dist/cron/fanout.js.map +0 -1
- package/dist/cron/jobs.d.ts +0 -18
- package/dist/cron/jobs.js +0 -37
- package/dist/cron/jobs.js.map +0 -1
- package/dist/cron/scheduler.d.ts +0 -45
- package/dist/cron/scheduler.js +0 -105
- package/dist/cron/scheduler.js.map +0 -1
- package/dist/engine/agent-executor.d.ts +0 -34
- package/dist/engine/agent-executor.js +0 -246
- package/dist/engine/agent-executor.js.map +0 -1
- package/dist/engine/chat/chat-runner.d.ts +0 -132
- package/dist/engine/chat/chat-runner.js +0 -424
- package/dist/engine/chat/chat-runner.js.map +0 -1
- package/dist/engine/chat/chat-skills.d.ts +0 -45
- package/dist/engine/chat/chat-skills.js +0 -184
- package/dist/engine/chat/chat-skills.js.map +0 -1
- package/dist/engine/chat/chat.d.ts +0 -54
- package/dist/engine/chat/chat.js +0 -316
- package/dist/engine/chat/chat.js.map +0 -1
- package/dist/engine/chat/message-batcher.d.ts +0 -32
- package/dist/engine/chat/message-batcher.js +0 -109
- package/dist/engine/chat/message-batcher.js.map +0 -1
- package/dist/engine/dispatcher.d.ts +0 -73
- package/dist/engine/dispatcher.js +0 -663
- package/dist/engine/dispatcher.js.map +0 -1
- package/dist/engine/event-shim.d.ts +0 -117
- package/dist/engine/event-shim.js +0 -435
- package/dist/engine/event-shim.js.map +0 -1
- package/dist/engine/executors/orchestrator.d.ts +0 -81
- package/dist/engine/executors/orchestrator.js +0 -365
- package/dist/engine/executors/orchestrator.js.map +0 -1
- package/dist/engine/executors/shared.d.ts +0 -189
- package/dist/engine/executors/shared.js +0 -616
- package/dist/engine/executors/shared.js.map +0 -1
- package/dist/engine/github/git-auth.d.ts +0 -62
- package/dist/engine/github/git-auth.js +0 -161
- package/dist/engine/github/git-auth.js.map +0 -1
- package/dist/engine/github/github-app-client.d.ts +0 -23
- package/dist/engine/github/github-app-client.js +0 -33
- package/dist/engine/github/github-app-client.js.map +0 -1
- package/dist/engine/github/github-tools.d.ts +0 -18
- package/dist/engine/github/github-tools.js +0 -263
- package/dist/engine/github/github-tools.js.map +0 -1
- package/dist/engine/github/github.d.ts +0 -1193
- package/dist/engine/github/github.js +0 -357
- package/dist/engine/github/github.js.map +0 -1
- package/dist/engine/github/profiles.d.ts +0 -279
- package/dist/engine/github/profiles.js +0 -42
- package/dist/engine/github/profiles.js.map +0 -1
- package/dist/engine/github/review-poster.d.ts +0 -98
- package/dist/engine/github/review-poster.js +0 -177
- package/dist/engine/github/review-poster.js.map +0 -1
- package/dist/engine/llm.d.ts +0 -79
- package/dist/engine/llm.js +0 -269
- package/dist/engine/llm.js.map +0 -1
- package/dist/engine/oauth.d.ts +0 -43
- package/dist/engine/oauth.js +0 -103
- package/dist/engine/oauth.js.map +0 -1
- package/dist/engine/router.d.ts +0 -29
- package/dist/engine/router.js +0 -680
- package/dist/engine/router.js.map +0 -1
- package/dist/engine/screen/classifier.d.ts +0 -93
- package/dist/engine/screen/classifier.js +0 -215
- package/dist/engine/screen/classifier.js.map +0 -1
- package/dist/engine/screen/screen.d.ts +0 -41
- package/dist/engine/screen/screen.js +0 -93
- package/dist/engine/screen/screen.js.map +0 -1
- package/dist/evals-api.d.ts +0 -24
- package/dist/evals-api.js +0 -22
- package/dist/evals-api.js.map +0 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.js +0 -940
- package/dist/index.js.map +0 -1
- package/dist/managed-repos.d.ts +0 -30
- package/dist/managed-repos.js +0 -72
- package/dist/managed-repos.js.map +0 -1
- package/dist/notify/blocks.d.ts +0 -23
- package/dist/notify/blocks.js +0 -118
- package/dist/notify/blocks.js.map +0 -1
- package/dist/notify/index.d.ts +0 -17
- package/dist/notify/index.js +0 -7
- package/dist/notify/index.js.map +0 -1
- package/dist/notify/model.d.ts +0 -57
- package/dist/notify/model.js +0 -89
- package/dist/notify/model.js.map +0 -1
- package/dist/notify/notifier.d.ts +0 -18
- package/dist/notify/notifier.js +0 -100
- package/dist/notify/notifier.js.map +0 -1
- package/dist/notify/render.d.ts +0 -21
- package/dist/notify/render.js +0 -59
- package/dist/notify/render.js.map +0 -1
- package/dist/notify/transports/github.d.ts +0 -26
- package/dist/notify/transports/github.js +0 -27
- package/dist/notify/transports/github.js.map +0 -1
- package/dist/notify/transports/slack.d.ts +0 -27
- package/dist/notify/transports/slack.js +0 -37
- package/dist/notify/transports/slack.js.map +0 -1
- package/dist/notify/types.d.ts +0 -119
- package/dist/notify/types.js +0 -16
- package/dist/notify/types.js.map +0 -1
- package/dist/providers.d.ts +0 -125
- package/dist/providers.js +0 -279
- package/dist/providers.js.map +0 -1
- package/dist/sandbox/docker.d.ts +0 -180
- package/dist/sandbox/docker.js +0 -517
- package/dist/sandbox/docker.js.map +0 -1
- package/dist/sandbox/egress-allowlist.d.ts +0 -74
- package/dist/sandbox/egress-allowlist.js +0 -164
- package/dist/sandbox/egress-allowlist.js.map +0 -1
- package/dist/sandbox/egress-firewall-config.d.ts +0 -127
- package/dist/sandbox/egress-firewall-config.js +0 -434
- package/dist/sandbox/egress-firewall-config.js.map +0 -1
- package/dist/sandbox/images.d.ts +0 -23
- package/dist/sandbox/images.js +0 -55
- package/dist/sandbox/images.js.map +0 -1
- package/dist/sandbox/index.d.ts +0 -112
- package/dist/sandbox/index.js +0 -332
- package/dist/sandbox/index.js.map +0 -1
- package/dist/sandbox/sandbox.d.ts +0 -214
- package/dist/sandbox/sandbox.js +0 -453
- package/dist/sandbox/sandbox.js.map +0 -1
- package/dist/sandbox/smol.d.ts +0 -162
- package/dist/sandbox/smol.js +0 -485
- package/dist/sandbox/smol.js.map +0 -1
- package/dist/session-log.d.ts +0 -63
- package/dist/session-log.js +0 -290
- package/dist/session-log.js.map +0 -1
- package/dist/state/approval-store.d.ts +0 -88
- package/dist/state/approval-store.js +0 -149
- package/dist/state/approval-store.js.map +0 -1
- package/dist/state/build-assets.d.ts +0 -50
- package/dist/state/build-assets.js +0 -154
- package/dist/state/build-assets.js.map +0 -1
- package/dist/state/db.d.ts +0 -81
- package/dist/state/db.js +0 -155
- package/dist/state/db.js.map +0 -1
- package/dist/state/execution-store.d.ts +0 -257
- package/dist/state/execution-store.js +0 -527
- package/dist/state/execution-store.js.map +0 -1
- package/dist/state/migrate.d.ts +0 -15
- package/dist/state/migrate.js +0 -175
- package/dist/state/migrate.js.map +0 -1
- package/dist/state/workflow-run-store.d.ts +0 -216
- package/dist/state/workflow-run-store.js +0 -403
- package/dist/state/workflow-run-store.js.map +0 -1
- package/dist/telemetry/index.d.ts +0 -38
- package/dist/telemetry/index.js +0 -253
- package/dist/telemetry/index.js.map +0 -1
- package/dist/telemetry/pi-events.d.ts +0 -12
- package/dist/telemetry/pi-events.js +0 -134
- package/dist/telemetry/pi-events.js.map +0 -1
- package/dist/workflows/dag.d.ts +0 -37
- package/dist/workflows/dag.js +0 -118
- package/dist/workflows/dag.js.map +0 -1
- package/dist/workflows/loader.d.ts +0 -53
- package/dist/workflows/loader.js +0 -421
- package/dist/workflows/loader.js.map +0 -1
- package/dist/workflows/loop-eval.d.ts +0 -28
- package/dist/workflows/loop-eval.js +0 -74
- package/dist/workflows/loop-eval.js.map +0 -1
- package/dist/workflows/phase-executor.d.ts +0 -222
- package/dist/workflows/phase-executor.js +0 -1153
- package/dist/workflows/phase-executor.js.map +0 -1
- package/dist/workflows/phase-ref.d.ts +0 -50
- package/dist/workflows/phase-ref.js +0 -91
- package/dist/workflows/phase-ref.js.map +0 -1
- package/dist/workflows/resume.d.ts +0 -58
- package/dist/workflows/resume.js +0 -313
- package/dist/workflows/resume.js.map +0 -1
- package/dist/workflows/runner.d.ts +0 -63
- package/dist/workflows/runner.js +0 -381
- package/dist/workflows/runner.js.map +0 -1
- package/dist/workflows/schema.d.ts +0 -344
- package/dist/workflows/schema.js +0 -460
- package/dist/workflows/schema.js.map +0 -1
- package/dist/workflows/simple.d.ts +0 -90
- package/dist/workflows/simple.js +0 -393
- package/dist/workflows/simple.js.map +0 -1
- package/dist/workflows/target-policy.d.ts +0 -74
- package/dist/workflows/target-policy.js +0 -80
- package/dist/workflows/target-policy.js.map +0 -1
- package/dist/workflows/templates.d.ts +0 -88
- package/dist/workflows/templates.js +0 -127
- package/dist/workflows/templates.js.map +0 -1
- package/dist/workflows/triggers.d.ts +0 -21
- package/dist/workflows/triggers.js +0 -45
- package/dist/workflows/triggers.js.map +0 -1
- package/dist/workflows/verdict.d.ts +0 -19
- package/dist/workflows/verdict.js +0 -30
- package/dist/workflows/verdict.js.map +0 -1
- package/dist/worktree/manager.d.ts +0 -43
- package/dist/worktree/manager.js +0 -127
- package/dist/worktree/manager.js.map +0 -1
- package/docker-compose.yml +0 -274
- package/sandbox.Dockerfile +0 -68
- package/skills/README.md +0 -42
- package/skills/browser-qa/SKILL.md +0 -208
- package/skills/browser-qa/scripts/agent-browser.mjs +0 -531
- package/skills/building/SKILL.md +0 -95
- package/skills/chat/SKILL.md +0 -36
- package/skills/code-review/SKILL.md +0 -82
- package/skills/debug-production/SKILL.md +0 -108
- package/skills/demo/SKILL.md +0 -228
- package/skills/demo/scripts/compose-demo.sh +0 -243
- package/skills/issue-answer/SKILL.md +0 -91
- package/skills/issue-comment/SKILL.md +0 -49
- package/skills/issue-triage/SKILL.md +0 -149
- package/skills/issue-triage/references/AGENT-BRIEF.md +0 -65
- package/skills/pr-comment/SKILL.md +0 -64
- package/skills/pr-review/SKILL.md +0 -148
- package/skills/pr-review/references/findings-schema.md +0 -89
- package/skills/qa-test/SKILL.md +0 -97
- package/skills/repo-health/SKILL.md +0 -67
- package/skills/security-feedback/SKILL.md +0 -173
- package/skills/security-feedback/references/templates.md +0 -77
- package/skills/security-review/SKILL.md +0 -215
- package/skills/security-review/references/issue-format.md +0 -302
- package/skills/verify/SKILL.md +0 -118
- package/workflows/answer.yaml +0 -44
- package/workflows/build.yaml +0 -129
- package/workflows/cron-health.yaml +0 -6
- package/workflows/cron-review.yaml +0 -8
- package/workflows/cron-security.yaml +0 -6
- package/workflows/cron-triage.yaml +0 -8
- package/workflows/demo.yaml +0 -62
- package/workflows/examples/bash-smoke.yaml +0 -41
- package/workflows/examples/parallel-review.yaml +0 -36
- package/workflows/examples/tdd-loop.yaml +0 -17
- package/workflows/explore.yaml +0 -80
- package/workflows/issue-comment.yaml +0 -15
- package/workflows/issue-triage.yaml +0 -22
- package/workflows/pr-comment.yaml +0 -16
- package/workflows/pr-fix.yaml +0 -17
- package/workflows/pr-review.yaml +0 -50
- package/workflows/prompts/answer.md +0 -68
- package/workflows/prompts/architect.md +0 -44
- package/workflows/prompts/classifier.md +0 -60
- package/workflows/prompts/classify-adds-info.md +0 -17
- package/workflows/prompts/demo.md +0 -125
- package/workflows/prompts/executor.md +0 -42
- package/workflows/prompts/explore-ask.md +0 -99
- package/workflows/prompts/explore-publish.md +0 -31
- package/workflows/prompts/explore-read.md +0 -120
- package/workflows/prompts/explore-synthesize.md +0 -88
- package/workflows/prompts/fix.md +0 -18
- package/workflows/prompts/guardrails.md +0 -96
- package/workflows/prompts/pr-fix.md +0 -26
- package/workflows/prompts/pr.md +0 -39
- package/workflows/prompts/qa-browser.md +0 -95
- package/workflows/prompts/qa-synth.md +0 -44
- package/workflows/prompts/qa-test.md +0 -60
- package/workflows/prompts/re-reviewer.md +0 -33
- package/workflows/prompts/reviewer.md +0 -60
- package/workflows/prompts/verify-browser.md +0 -93
- package/workflows/prompts/verify-synth.md +0 -44
- package/workflows/prompts/verify.md +0 -63
- package/workflows/qa-test.yaml +0 -94
- package/workflows/repo-health.yaml +0 -15
- package/workflows/security-feedback.yaml +0 -25
- package/workflows/security-review.yaml +0 -37
- package/workflows/verify.yaml +0 -93
- /package/dist/{cli/cli-config.d.ts → cli-config.d.ts} +0 -0
- /package/dist/{cli/cli-config.js → cli-config.js} +0 -0
- /package/dist/{cli/cli-format.d.ts → cli-format.d.ts} +0 -0
- /package/dist/{cli/cli-format.js → cli-format.js} +0 -0
- /package/dist/{cli/cli-timeline.d.ts → cli-timeline.d.ts} +0 -0
- /package/dist/{cli/cli-timeline.js → cli-timeline.js} +0 -0
- /package/dist/{cli/cli.d.ts → cli.d.ts} +0 -0
- /package/dist/{cli/oauth-cli.d.ts → oauth-cli.d.ts} +0 -0
- /package/dist/{cli/setup.d.ts → setup.d.ts} +0 -0
|
@@ -1,434 +0,0 @@
|
|
|
1
|
-
import { mkdirSync, writeFileSync } from "fs";
|
|
2
|
-
import { join } from "path";
|
|
3
|
-
import { DEFAULT_ALLOWLIST, mergeAllowlist } from "./egress-allowlist.js";
|
|
4
|
-
/**
|
|
5
|
-
* Egress firewall config generation for the docker sandbox backend.
|
|
6
|
-
*
|
|
7
|
-
* Architecture (replaces the earlier tinyproxy CONNECT-proxy):
|
|
8
|
-
*
|
|
9
|
-
* sandbox-egress (internal: true, subnet 172.30.0.0/24)
|
|
10
|
-
* ├─ sandbox containers (docker run --dns <coredns-ip>)
|
|
11
|
-
* ├─ coredns-strict 172.30.0.10 → returns nginx-strict IP for allowlist hosts, NXDOMAIN otherwise
|
|
12
|
-
* ├─ coredns-open 172.30.0.11 → returns nginx-open IP for ANY hostname (except hard-deny SSRF magnets)
|
|
13
|
-
* ├─ nginx-egress-strict 172.30.0.20 → ssl_preread, SNI must match allowlist; tunnel upstream via proxy-egress
|
|
14
|
-
* └─ nginx-egress-open 172.30.0.21 → tunnel any SNI; client DNS already gated through coredns-open
|
|
15
|
-
*
|
|
16
|
-
* Why this instead of a forward proxy (tinyproxy/smokescreen): clients
|
|
17
|
-
* inside the sandbox (especially the OpenAI/Anthropic SDKs that build
|
|
18
|
-
* their own undici dispatchers) don't honour HTTP_PROXY / HTTPS_PROXY.
|
|
19
|
-
* Forcing them to cooperate is a losing battle. By spoofing DNS and
|
|
20
|
-
* peeking SNI at the network layer, the sandbox sees no proxy at all —
|
|
21
|
-
* it dials `api.openai.com:443` directly. The firewall intercepts the
|
|
22
|
-
* connection by virtue of being the only thing the spoofed DNS pointed
|
|
23
|
-
* at.
|
|
24
|
-
*
|
|
25
|
-
* Inspired by Vercel Sandbox's egress firewall (SNI peeking, no env
|
|
26
|
-
* vars). Their implementation also handles TLS termination for
|
|
27
|
-
* credentials brokering and Postgres STARTTLS — we don't (yet).
|
|
28
|
-
*
|
|
29
|
-
* ## Wildcards
|
|
30
|
-
*
|
|
31
|
-
* Entries in egress-allowlist.ts with a leading dot (`".github.com"`)
|
|
32
|
-
* match the apex plus every subdomain. nginx's `map` directive supports
|
|
33
|
-
* this syntax natively. CoreDNS uses the `template` plugin with an
|
|
34
|
-
* anchored regex to do the same.
|
|
35
|
-
*/
|
|
36
|
-
/** Fixed IPs assigned in docker-compose.yml so `--dns` and nginx upstreams can reference them. */
|
|
37
|
-
export const COREDNS_STRICT_IP = "172.30.0.10";
|
|
38
|
-
export const COREDNS_OPEN_IP = "172.30.0.11";
|
|
39
|
-
export const NGINX_STRICT_IP = "172.30.0.20";
|
|
40
|
-
export const NGINX_OPEN_IP = "172.30.0.21";
|
|
41
|
-
/**
|
|
42
|
-
* Static IP of the in-network OTEL collector (docker backend). Sandboxes
|
|
43
|
-
* dial it directly by IP — it lives on `sandbox-egress` alongside the
|
|
44
|
-
* firewalls, so no DNS lookup (and therefore no coredns allowlist entry)
|
|
45
|
-
* is involved. The collector is the ONLY OTLP endpoint a sandbox ever
|
|
46
|
-
* sees: it terminates the sandbox's telemetry and re-exports to the real
|
|
47
|
-
* backend over `proxy-egress` using credentials that stay host-side. This
|
|
48
|
-
* is why the strict SNI firewall no longer needs to know about collector
|
|
49
|
-
* hosts or non-443 ports — that hop happens on the trusted outbound leg,
|
|
50
|
-
* not through `ssl_preread`.
|
|
51
|
-
*/
|
|
52
|
-
export const OTEL_COLLECTOR_IP = "172.30.0.30";
|
|
53
|
-
/** OTLP/HTTP + OTLP/gRPC receiver ports the in-network collector listens on. */
|
|
54
|
-
export const OTEL_COLLECTOR_OTLP_HTTP_PORT = 4318;
|
|
55
|
-
export const OTEL_COLLECTOR_OTLP_GRPC_PORT = 4317;
|
|
56
|
-
/** Endpoint a docker sandbox is told to export OTLP to (HTTP/protobuf). */
|
|
57
|
-
export const OTEL_COLLECTOR_SANDBOX_ENDPOINT = `http://${OTEL_COLLECTOR_IP}:${OTEL_COLLECTOR_OTLP_HTTP_PORT}`;
|
|
58
|
-
/**
|
|
59
|
-
* UID the `otel/opentelemetry-collector` image runs as (its Dockerfile
|
|
60
|
-
* `USER`). The collector reads the OTLP config (which can hold backend auth
|
|
61
|
-
* headers) as this non-root user. To let it read a mode-0600 file from the
|
|
62
|
-
* shared volume WITHOUT running as root or making the secret world-readable,
|
|
63
|
-
* the harness's own `lastlight` user is pinned to this same UID (see the
|
|
64
|
-
* Dockerfile `useradd -u`), so the collector reads files it wrote as their
|
|
65
|
-
* owner. The Dockerfile and the collector image tag in docker-compose.yml
|
|
66
|
-
* must move together if a future image bumps the UID — enforced by a test in
|
|
67
|
-
* docker-compose.test.ts.
|
|
68
|
-
*/
|
|
69
|
-
export const OTEL_COLLECTOR_UID = 10001;
|
|
70
|
-
/** Subnet for sandbox-egress. Compose declares this CIDR so the IPs above are valid. */
|
|
71
|
-
export const SANDBOX_EGRESS_SUBNET = "172.30.0.0/24";
|
|
72
|
-
/**
|
|
73
|
-
* Hostnames the open coredns explicitly NXDOMAINs even in unrestricted
|
|
74
|
-
* mode — known SSRF magnets. nginx's `ssl_preread` SNI inspection alone
|
|
75
|
-
* can't catch hostnames that resolve to private IPs (the DNS server
|
|
76
|
-
* we control gets the first say), so this is the right layer to enforce
|
|
77
|
-
* "no cloud metadata, no internal services" even with `unrestricted_egress`.
|
|
78
|
-
*/
|
|
79
|
-
const OPEN_MODE_HARD_DENY = [
|
|
80
|
-
"metadata.google.internal",
|
|
81
|
-
"169.254.169.254", // GCP / AWS / Azure metadata service IP literal
|
|
82
|
-
];
|
|
83
|
-
/**
|
|
84
|
-
* Convert one allowlist entry to its nginx `map` line.
|
|
85
|
-
*
|
|
86
|
-
* "openai.com" → '.openai.com $ssl_preread_server_name:443;'
|
|
87
|
-
*
|
|
88
|
-
* Every entry is treated as apex+subdomain (see egress-allowlist.ts).
|
|
89
|
-
* The generated line uses nginx's `.foo.com` leading-dot syntax,
|
|
90
|
-
* which is its built-in "match this domain and all subdomains" form.
|
|
91
|
-
* Upstream is whatever SNI the client sent — we don't know which
|
|
92
|
-
* subdomain they're targeting at config-gen time.
|
|
93
|
-
*/
|
|
94
|
-
function nginxMapLine(entry) {
|
|
95
|
-
return ` .${entry} $ssl_preread_server_name:443;`;
|
|
96
|
-
}
|
|
97
|
-
/**
|
|
98
|
-
* Build one CoreDNS `match` regex per allowlist entry. All entries
|
|
99
|
-
* share a SINGLE `template` block (see renderCorefileStrict) because
|
|
100
|
-
* CoreDNS only honours one `template` per zone — multiple blocks
|
|
101
|
-
* silently shadow each other.
|
|
102
|
-
*
|
|
103
|
-
* The `(^|\.)` prefix matches the apex (`openai.com.`) or any subdomain
|
|
104
|
-
* (`api.openai.com.`) — same semantics as nginx's leading-dot form.
|
|
105
|
-
*/
|
|
106
|
-
function corednsMatchLineForEntry(entry) {
|
|
107
|
-
const escapedHost = entry.replaceAll(".", "\\.");
|
|
108
|
-
return ` match (^|\\.)${escapedHost}\\.$`;
|
|
109
|
-
}
|
|
110
|
-
/** Build the strict nginx.conf — ssl_preread + map on SNI allowlist. */
|
|
111
|
-
export function renderNginxStrictConf() {
|
|
112
|
-
const mapLines = mergeAllowlist(DEFAULT_ALLOWLIST).map(nginxMapLine).join("\n");
|
|
113
|
-
return `# Generated by lastlight at harness boot. DO NOT EDIT BY HAND —
|
|
114
|
-
# source of truth is src/sandbox/egress-allowlist.ts.
|
|
115
|
-
|
|
116
|
-
error_log /dev/stderr warn;
|
|
117
|
-
pid /tmp/nginx.pid;
|
|
118
|
-
|
|
119
|
-
events { worker_connections 1024; }
|
|
120
|
-
|
|
121
|
-
# Streams (TCP/UDP). \`ssl_preread\` reads the TLS ClientHello without
|
|
122
|
-
# terminating the session, exposing the SNI hostname as
|
|
123
|
-
# \`$ssl_preread_server_name\`. We \`map\` that to an upstream — anything
|
|
124
|
-
# unmatched is sunk to 127.0.0.1:1 (no listener, instant reset).
|
|
125
|
-
stream {
|
|
126
|
-
log_format basic '$remote_addr -> $ssl_preread_server_name -> $upstream_addr status=$status';
|
|
127
|
-
access_log /dev/stdout basic;
|
|
128
|
-
|
|
129
|
-
# Runtime resolver for upstream hostnames (docker's embedded DNS).
|
|
130
|
-
resolver 127.0.0.11 valid=30s ipv6=off;
|
|
131
|
-
|
|
132
|
-
# Allowlist. The \`hostnames\` directive enables nginx's wildcard
|
|
133
|
-
# hostname match: a key like ".github.com" matches "github.com" AND
|
|
134
|
-
# any subdomain. WITHOUT \`hostnames\`, map does exact string match
|
|
135
|
-
# only and ".github.com" never matches anything real (we hit this
|
|
136
|
-
# exact bug in prod — every allowlisted host fell through to the
|
|
137
|
-
# black hole).
|
|
138
|
-
map $ssl_preread_server_name $upstream_target {
|
|
139
|
-
hostnames;
|
|
140
|
-
${mapLines}
|
|
141
|
-
# Anything else → black hole. The connection resets immediately;
|
|
142
|
-
# no data ever leaves the sandbox-egress network.
|
|
143
|
-
default 127.0.0.1:1;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
server {
|
|
147
|
-
listen 443;
|
|
148
|
-
ssl_preread on;
|
|
149
|
-
proxy_pass $upstream_target;
|
|
150
|
-
proxy_connect_timeout 5s;
|
|
151
|
-
proxy_timeout 60s;
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
`;
|
|
155
|
-
}
|
|
156
|
-
/** Build the open nginx.conf — no SNI allowlist, just tunnel whatever DNS pointed at. */
|
|
157
|
-
export function renderNginxOpenConf() {
|
|
158
|
-
return `# Generated by lastlight at harness boot. DO NOT EDIT BY HAND.
|
|
159
|
-
# This nginx is used only by phases that declared \`unrestricted_egress: true\`.
|
|
160
|
-
# No SNI allowlist — every host is tunnelled. The corresponding coredns-open
|
|
161
|
-
# refuses to resolve the cloud-metadata hostnames so SSRF to them is blocked
|
|
162
|
-
# even in this mode.
|
|
163
|
-
|
|
164
|
-
error_log /dev/stderr warn;
|
|
165
|
-
pid /tmp/nginx.pid;
|
|
166
|
-
|
|
167
|
-
events { worker_connections 1024; }
|
|
168
|
-
|
|
169
|
-
stream {
|
|
170
|
-
log_format basic '$remote_addr -> $ssl_preread_server_name -> $upstream_addr status=$status';
|
|
171
|
-
access_log /dev/stdout basic;
|
|
172
|
-
resolver 127.0.0.11 valid=30s ipv6=off;
|
|
173
|
-
|
|
174
|
-
server {
|
|
175
|
-
listen 443;
|
|
176
|
-
ssl_preread on;
|
|
177
|
-
# $ssl_preread_server_name is whatever SNI the client sent. Tunnel
|
|
178
|
-
# to that hostname on :443. No allowlist check.
|
|
179
|
-
proxy_pass $ssl_preread_server_name:443;
|
|
180
|
-
proxy_connect_timeout 5s;
|
|
181
|
-
proxy_timeout 60s;
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
`;
|
|
185
|
-
}
|
|
186
|
-
/** Build the Corefile that returns the strict nginx IP for allowlist hosts. */
|
|
187
|
-
export function renderCorefileStrict() {
|
|
188
|
-
// ALL allowlist entries share a SINGLE template block. CoreDNS only
|
|
189
|
-
// honours one `template` per (class, type, zone), so multiple blocks
|
|
190
|
-
// silently overwrite each other — we learned this in prod when only
|
|
191
|
-
// the first host in the list resolved.
|
|
192
|
-
const matchLines = mergeAllowlist(DEFAULT_ALLOWLIST).map(corednsMatchLineForEntry).join("\n");
|
|
193
|
-
return `# Generated by lastlight from src/sandbox/egress-allowlist.ts.
|
|
194
|
-
# All allowlist hosts live in a single \`template IN A\` block (multiple
|
|
195
|
-
# template blocks per zone are NOT additive — they shadow each other).
|
|
196
|
-
# Queries that don't match any \`match\` regex fall through to the
|
|
197
|
-
# catch-all NXDOMAIN at the end.
|
|
198
|
-
.:53 {
|
|
199
|
-
template IN A {
|
|
200
|
-
${matchLines}
|
|
201
|
-
answer "{{ .Name }} 60 IN A ${NGINX_STRICT_IP}"
|
|
202
|
-
}
|
|
203
|
-
# Catch-all: NXDOMAIN for everything else (including AAAA queries,
|
|
204
|
-
# since nginx-egress only binds 443 on IPv4).
|
|
205
|
-
template IN ANY {
|
|
206
|
-
rcode NXDOMAIN
|
|
207
|
-
}
|
|
208
|
-
errors
|
|
209
|
-
log
|
|
210
|
-
}
|
|
211
|
-
`;
|
|
212
|
-
}
|
|
213
|
-
/** Build the Corefile that returns the open nginx IP for ANY hostname (except hard-denies). */
|
|
214
|
-
export function renderCorefileOpen() {
|
|
215
|
-
// Hard-deny hosts each get their OWN zone block. CoreDNS routes queries
|
|
216
|
-
// to the longest-suffix-matching zone, so `metadata.google.internal:53`
|
|
217
|
-
// catches both the apex and every subdomain before the catch-all `.`
|
|
218
|
-
// zone ever sees them. We do NOT use a multi-`template` layout inside
|
|
219
|
-
// the catch-all zone because CoreDNS only honours one template per
|
|
220
|
-
// (class, type) and prior templates with non-matching `match` clauses
|
|
221
|
-
// silently drop the query — leaving sandboxes with no DNS answer at
|
|
222
|
-
// all (which is exactly what failed in prod the first time explore
|
|
223
|
-
// ran on the open path).
|
|
224
|
-
const hardDenyZones = OPEN_MODE_HARD_DENY.map((host) => `# Hard-deny zone for ${host} (SSRF floor — NXDOMAIN even in unrestricted mode).
|
|
225
|
-
${host}:53 {
|
|
226
|
-
template IN ANY {
|
|
227
|
-
rcode NXDOMAIN
|
|
228
|
-
}
|
|
229
|
-
errors
|
|
230
|
-
log
|
|
231
|
-
}
|
|
232
|
-
`).join("\n");
|
|
233
|
-
return `# Generated by lastlight. Used by sandbox phases with unrestricted_egress: true.
|
|
234
|
-
# Returns nginx-egress-open's IP for every hostname EXCEPT the SSRF hard-denies
|
|
235
|
-
# (cloud metadata literals etc).
|
|
236
|
-
.:53 {
|
|
237
|
-
# Everything → nginx-egress-open IP. Hard-deny names are intercepted
|
|
238
|
-
# by the per-host zones declared below (longest-suffix zone match).
|
|
239
|
-
template IN A {
|
|
240
|
-
answer "{{ .Name }} 60 IN A ${NGINX_OPEN_IP}"
|
|
241
|
-
}
|
|
242
|
-
# AAAA returns empty (we route only via IPv4).
|
|
243
|
-
template IN AAAA {
|
|
244
|
-
rcode NOERROR
|
|
245
|
-
}
|
|
246
|
-
errors
|
|
247
|
-
log
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
${hardDenyZones}`;
|
|
251
|
-
}
|
|
252
|
-
/**
|
|
253
|
-
* Write the four config files under $STATE_DIR/proxy/. Idempotent.
|
|
254
|
-
* Returns the directory path. Compose bind-mounts this dir into the
|
|
255
|
-
* coredns + nginx containers read-only.
|
|
256
|
-
*/
|
|
257
|
-
export function writeEgressFirewallConfigs(stateDir) {
|
|
258
|
-
const dir = join(stateDir, "proxy");
|
|
259
|
-
mkdirSync(dir, { recursive: true });
|
|
260
|
-
writeFileSync(join(dir, "nginx-strict.conf"), renderNginxStrictConf());
|
|
261
|
-
writeFileSync(join(dir, "nginx-open.conf"), renderNginxOpenConf());
|
|
262
|
-
writeFileSync(join(dir, "Corefile.strict"), renderCorefileStrict());
|
|
263
|
-
writeFileSync(join(dir, "Corefile.open"), renderCorefileOpen());
|
|
264
|
-
return dir;
|
|
265
|
-
}
|
|
266
|
-
/**
|
|
267
|
-
* Parse an OTLP headers string (`key1=val1,key2=val2`, the OTEL spec format
|
|
268
|
-
* used by `OTEL_EXPORTER_OTLP_HEADERS`) into an ordered list of pairs.
|
|
269
|
-
* Malformed segments (no `=`, empty key) are dropped. Values keep any inner
|
|
270
|
-
* `=` so bearer tokens survive intact.
|
|
271
|
-
*/
|
|
272
|
-
function parseOtlpHeaders(raw) {
|
|
273
|
-
if (!raw)
|
|
274
|
-
return [];
|
|
275
|
-
const out = [];
|
|
276
|
-
for (const segment of raw.split(",")) {
|
|
277
|
-
const eq = segment.indexOf("=");
|
|
278
|
-
if (eq <= 0)
|
|
279
|
-
continue;
|
|
280
|
-
const key = segment.slice(0, eq).trim();
|
|
281
|
-
const value = segment.slice(eq + 1).trim();
|
|
282
|
-
// Reject CR/LF in either part: a real newline in an HTTP header value is
|
|
283
|
-
// header injection on the collector→backend leg, and would also break the
|
|
284
|
-
// YAML scalar. A header carrying a newline is corruption/injection, not a
|
|
285
|
-
// valid OTLP config — drop the pair rather than emit something dangerous.
|
|
286
|
-
if (!key || /[\r\n]/.test(key) || /[\r\n]/.test(value))
|
|
287
|
-
continue;
|
|
288
|
-
out.push([key, value]);
|
|
289
|
-
}
|
|
290
|
-
return out;
|
|
291
|
-
}
|
|
292
|
-
/**
|
|
293
|
-
* YAML double-quoted-scalar escape. Backslash and quote are the cases that
|
|
294
|
-
* appear in tokens/URLs; CR/LF/TAB are escaped too as a hard guarantee that
|
|
295
|
-
* we NEVER emit a syntactically invalid collector config regardless of input
|
|
296
|
-
* (header values are already CR/LF-filtered in parseOtlpHeaders, but a stray
|
|
297
|
-
* control char in any other field must not be able to break the file).
|
|
298
|
-
*/
|
|
299
|
-
function yamlQuote(s) {
|
|
300
|
-
return `"${s
|
|
301
|
-
.replace(/\\/g, "\\\\")
|
|
302
|
-
.replace(/"/g, '\\"')
|
|
303
|
-
.replace(/\n/g, "\\n")
|
|
304
|
-
.replace(/\r/g, "\\r")
|
|
305
|
-
.replace(/\t/g, "\\t")}"`;
|
|
306
|
-
}
|
|
307
|
-
/** OTLP signals the collector pipelines cover, in stable output order. */
|
|
308
|
-
const OTLP_SIGNALS = ["traces", "metrics", "logs"];
|
|
309
|
-
/**
|
|
310
|
-
* Resolve one signal's backend per the OTEL env precedence: a
|
|
311
|
-
* signal-specific endpoint/headers var wins, otherwise the generic one.
|
|
312
|
-
* Returns null when neither is set — that signal's pipeline then drops to
|
|
313
|
-
* the `debug` exporter instead of being misrouted to another signal's URL.
|
|
314
|
-
*/
|
|
315
|
-
function resolveSignalBackend(env, signal) {
|
|
316
|
-
const SIG = signal.toUpperCase();
|
|
317
|
-
const specificEndpoint = (env[`OTEL_EXPORTER_OTLP_${SIG}_ENDPOINT`] || "").trim();
|
|
318
|
-
const genericEndpoint = (env.OTEL_EXPORTER_OTLP_ENDPOINT || "").trim();
|
|
319
|
-
if (!specificEndpoint && !genericEndpoint)
|
|
320
|
-
return null;
|
|
321
|
-
const specificHeaders = (env[`OTEL_EXPORTER_OTLP_${SIG}_HEADERS`] || "").trim();
|
|
322
|
-
const genericHeaders = env.OTEL_EXPORTER_OTLP_HEADERS;
|
|
323
|
-
return specificEndpoint
|
|
324
|
-
? { endpointField: `${signal}_endpoint`, endpoint: specificEndpoint, headers: parseOtlpHeaders(specificHeaders || genericHeaders) }
|
|
325
|
-
: { endpointField: "endpoint", endpoint: genericEndpoint, headers: parseOtlpHeaders(specificHeaders || genericHeaders) };
|
|
326
|
-
}
|
|
327
|
-
/**
|
|
328
|
-
* Render the in-network OTEL collector config (docker backend).
|
|
329
|
-
*
|
|
330
|
-
* `opts.active` gates whether the collector forwards anywhere. It MUST track
|
|
331
|
-
* the harness's effective `otel.enabled && otel.forwardToSandbox` — when
|
|
332
|
-
* false, every pipeline is wired to a `debug` exporter (drops data) and NO
|
|
333
|
-
* backend endpoint or credential is emitted, even if `OTEL_EXPORTER_OTLP_*`
|
|
334
|
-
* env vars are present. This is the security floor: the collector listens on
|
|
335
|
-
* a static IP that sandboxes can reach, so if forwarding weren't gated, a
|
|
336
|
-
* sandbox could POST directly to it and exfil to the real backend regardless
|
|
337
|
-
* of the documented `LASTLIGHT_OTEL_ENABLED` / `FORWARD_TO_SANDBOX` opt-outs.
|
|
338
|
-
*
|
|
339
|
-
* When active, the collector re-exports to the REAL backend — the standard
|
|
340
|
-
* `OTEL_EXPORTER_OTLP_ENDPOINT` / `OTEL_EXPORTER_OTLP_HEADERS` plus their
|
|
341
|
-
* per-signal `OTEL_EXPORTER_OTLP_<SIGNAL>_ENDPOINT` / `_HEADERS` overrides,
|
|
342
|
-
* resolved with the spec's precedence. Each signal gets its own exporter so
|
|
343
|
-
* a split traces/metrics/logs setup is routed correctly rather than all
|
|
344
|
-
* collapsing onto whichever endpoint won a fallback chain. Those credentials
|
|
345
|
-
* live here, in a file on the host mounted read-only into the collector, and
|
|
346
|
-
* are NEVER forwarded into an untrusted sandbox. The sandbox can only
|
|
347
|
-
* influence span *content* sent to the harness's own fixed backend — it
|
|
348
|
-
* cannot redirect where the collector exports, so this adds no SSRF/exfil
|
|
349
|
-
* surface.
|
|
350
|
-
*
|
|
351
|
-
* A signal with no configured endpoint (neither specific nor generic) is
|
|
352
|
-
* likewise wired to `debug` so the collector still boots cleanly and accepts
|
|
353
|
-
* connections — sandboxes simply never send what isn't routed.
|
|
354
|
-
*/
|
|
355
|
-
export function renderOtelCollectorConfig(opts) {
|
|
356
|
-
const env = opts.env ?? process.env;
|
|
357
|
-
const exporterBlocks = [];
|
|
358
|
-
const pipelineBlocks = [];
|
|
359
|
-
let needsDebug = false;
|
|
360
|
-
for (const signal of OTLP_SIGNALS) {
|
|
361
|
-
// When inactive, resolve NO backend — every signal drops to debug and
|
|
362
|
-
// not a single OTEL_* value reaches the generated file.
|
|
363
|
-
const backend = opts.active ? resolveSignalBackend(env, signal) : null;
|
|
364
|
-
let exporterName;
|
|
365
|
-
if (!backend) {
|
|
366
|
-
exporterName = "debug";
|
|
367
|
-
needsDebug = true;
|
|
368
|
-
}
|
|
369
|
-
else {
|
|
370
|
-
exporterName = `otlphttp/${signal}`;
|
|
371
|
-
const headerLines = backend.headers.length
|
|
372
|
-
? `\n headers:\n${backend.headers.map(([k, v]) => ` ${yamlQuote(k)}: ${yamlQuote(v)}`).join("\n")}`
|
|
373
|
-
: "";
|
|
374
|
-
exporterBlocks.push(` ${exporterName}:\n ${backend.endpointField}: ${yamlQuote(backend.endpoint)}${headerLines}`);
|
|
375
|
-
}
|
|
376
|
-
pipelineBlocks.push(` ${signal}:\n receivers: [otlp]\n processors: [batch]\n exporters: [${exporterName}]`);
|
|
377
|
-
}
|
|
378
|
-
if (needsDebug)
|
|
379
|
-
exporterBlocks.push(` debug:\n verbosity: normal`);
|
|
380
|
-
const statusComment = opts.active
|
|
381
|
-
? `# Sandboxes export OTLP to this collector (reached by its internal IP on
|
|
382
|
-
# sandbox-egress); the collector re-exports to the configured backend over
|
|
383
|
-
# proxy-egress. Backend credentials below stay host-side — they are never
|
|
384
|
-
# forwarded into a sandbox.`
|
|
385
|
-
: `# Telemetry forwarding is DISABLED (LASTLIGHT_OTEL_ENABLED is off, or
|
|
386
|
-
# LASTLIGHT_OTEL_FORWARD_TO_SANDBOX is false). The collector still listens so
|
|
387
|
-
# sandboxes don't get connection errors, but every signal drops to a local
|
|
388
|
-
# debug exporter — nothing is forwarded to any backend, and no OTEL_* endpoint
|
|
389
|
-
# or credential is emitted here. This is the egress floor for the static
|
|
390
|
-
# collector IP regardless of any OTEL_* env vars present.`;
|
|
391
|
-
return `# Generated by lastlight at harness boot. DO NOT EDIT BY HAND —
|
|
392
|
-
# source of truth is src/sandbox/egress-firewall-config.ts.
|
|
393
|
-
#
|
|
394
|
-
${statusComment}
|
|
395
|
-
receivers:
|
|
396
|
-
otlp:
|
|
397
|
-
protocols:
|
|
398
|
-
http:
|
|
399
|
-
endpoint: 0.0.0.0:${OTEL_COLLECTOR_OTLP_HTTP_PORT}
|
|
400
|
-
grpc:
|
|
401
|
-
endpoint: 0.0.0.0:${OTEL_COLLECTOR_OTLP_GRPC_PORT}
|
|
402
|
-
|
|
403
|
-
processors:
|
|
404
|
-
batch: {}
|
|
405
|
-
|
|
406
|
-
exporters:
|
|
407
|
-
${exporterBlocks.join("\n")}
|
|
408
|
-
|
|
409
|
-
service:
|
|
410
|
-
pipelines:
|
|
411
|
-
${pipelineBlocks.join("\n")}
|
|
412
|
-
`;
|
|
413
|
-
}
|
|
414
|
-
/**
|
|
415
|
-
* Write the in-network collector config to $STATE_DIR/proxy/otel-collector.yaml.
|
|
416
|
-
* Mode 0600 — it can contain backend auth headers. Called at harness boot
|
|
417
|
-
* (and by the compose `egress-init` one-shot) so the file exists before the
|
|
418
|
-
* `otel-collector` service reads it. `opts.active` gates forwarding — see
|
|
419
|
-
* `renderOtelCollectorConfig`. The harness passes its parsed
|
|
420
|
-
* `otel.enabled && otel.forwardToSandbox`; the env-only callers compute it
|
|
421
|
-
* via `otelForwardActiveFromEnv`.
|
|
422
|
-
*/
|
|
423
|
-
export function writeOtelCollectorConfig(stateDir, opts) {
|
|
424
|
-
const dir = join(stateDir, "proxy");
|
|
425
|
-
mkdirSync(dir, { recursive: true });
|
|
426
|
-
const path = join(dir, "otel-collector.yaml");
|
|
427
|
-
// Mode 0600 — it can carry backend auth headers. In the docker deployment
|
|
428
|
-
// the writer (harness/egress-init, gosu'd to `lastlight`) and the collector
|
|
429
|
-
// share UID 10001 (see OTEL_COLLECTOR_UID + the Dockerfile pin), so the
|
|
430
|
-
// collector reads this file as its owner without it being world-readable.
|
|
431
|
-
writeFileSync(path, renderOtelCollectorConfig(opts), { mode: 0o600 });
|
|
432
|
-
return path;
|
|
433
|
-
}
|
|
434
|
-
//# sourceMappingURL=egress-firewall-config.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"egress-firewall-config.js","sourceRoot":"","sources":["../../src/sandbox/egress-firewall-config.ts"],"names":[],"mappings":"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"}
|
package/dist/sandbox/images.d.ts
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Sandbox image names + the docker availability probes. Kept in this
|
|
3
|
-
* dependency-light module (only `child_process`, no `./docker.js`) so callers
|
|
4
|
-
* like the workflow runner can check image availability without importing the
|
|
5
|
-
* full `DockerSandbox` machinery — `docker.ts` runs `promisify(execFile)` at
|
|
6
|
-
* module load, which trips test suites that mock `child_process`.
|
|
7
|
-
*/
|
|
8
|
-
/** The lean default sandbox image (`sandbox.Dockerfile`). */
|
|
9
|
-
export declare const SANDBOX_IMAGE = "lastlight-sandbox:latest";
|
|
10
|
-
/**
|
|
11
|
-
* The enriched browser-QA image (Playwright + Chromium baked in). Built only
|
|
12
|
-
* when QA is enabled (`sandbox-qa.Dockerfile`); a phase opts into it with
|
|
13
|
-
* `sandbox_image: qa`. Fixed name, deliberately not overridable.
|
|
14
|
-
*/
|
|
15
|
-
export declare const SANDBOX_IMAGE_QA = "lastlight-sandbox-qa:latest";
|
|
16
|
-
/** Check if Docker sandbox mode is available (docker up + lean image built). */
|
|
17
|
-
export declare function isSandboxAvailable(): boolean;
|
|
18
|
-
/**
|
|
19
|
-
* Whether the browser-QA sandbox image is present on this host. Used by the
|
|
20
|
-
* runner to gracefully skip a `sandbox_image: qa` phase when the image hasn't
|
|
21
|
-
* been built (the lean default deploy), rather than failing the run.
|
|
22
|
-
*/
|
|
23
|
-
export declare function qaImageAvailable(): boolean;
|
package/dist/sandbox/images.js
DELETED
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
import { execFileSync } from "child_process";
|
|
2
|
-
/**
|
|
3
|
-
* Sandbox image names + the docker availability probes. Kept in this
|
|
4
|
-
* dependency-light module (only `child_process`, no `./docker.js`) so callers
|
|
5
|
-
* like the workflow runner can check image availability without importing the
|
|
6
|
-
* full `DockerSandbox` machinery — `docker.ts` runs `promisify(execFile)` at
|
|
7
|
-
* module load, which trips test suites that mock `child_process`.
|
|
8
|
-
*/
|
|
9
|
-
/** The lean default sandbox image (`sandbox.Dockerfile`). */
|
|
10
|
-
export const SANDBOX_IMAGE = "lastlight-sandbox:latest";
|
|
11
|
-
/**
|
|
12
|
-
* The enriched browser-QA image (Playwright + Chromium baked in). Built only
|
|
13
|
-
* when QA is enabled (`sandbox-qa.Dockerfile`); a phase opts into it with
|
|
14
|
-
* `sandbox_image: qa`. Fixed name, deliberately not overridable.
|
|
15
|
-
*/
|
|
16
|
-
export const SANDBOX_IMAGE_QA = "lastlight-sandbox-qa:latest";
|
|
17
|
-
/** Check if Docker sandbox mode is available (docker up + lean image built). */
|
|
18
|
-
export function isSandboxAvailable() {
|
|
19
|
-
return dockerAvailable() && sandboxImageExists(SANDBOX_IMAGE);
|
|
20
|
-
}
|
|
21
|
-
/** Cached check — only probe for the QA image once per process. */
|
|
22
|
-
let _qaImageAvailable = null;
|
|
23
|
-
/**
|
|
24
|
-
* Whether the browser-QA sandbox image is present on this host. Used by the
|
|
25
|
-
* runner to gracefully skip a `sandbox_image: qa` phase when the image hasn't
|
|
26
|
-
* been built (the lean default deploy), rather than failing the run.
|
|
27
|
-
*/
|
|
28
|
-
export function qaImageAvailable() {
|
|
29
|
-
if (_qaImageAvailable === null) {
|
|
30
|
-
_qaImageAvailable = dockerAvailable() && sandboxImageExists(SANDBOX_IMAGE_QA);
|
|
31
|
-
}
|
|
32
|
-
return _qaImageAvailable;
|
|
33
|
-
}
|
|
34
|
-
function dockerAvailable() {
|
|
35
|
-
try {
|
|
36
|
-
execFileSync("docker", ["info"], { stdio: "ignore", timeout: 5000 });
|
|
37
|
-
return true;
|
|
38
|
-
}
|
|
39
|
-
catch {
|
|
40
|
-
return false;
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
function sandboxImageExists(imageName) {
|
|
44
|
-
try {
|
|
45
|
-
const out = execFileSync("docker", ["images", "-q", imageName], {
|
|
46
|
-
encoding: "utf-8",
|
|
47
|
-
stdio: ["pipe", "pipe", "pipe"],
|
|
48
|
-
});
|
|
49
|
-
return out.trim().length > 0;
|
|
50
|
-
}
|
|
51
|
-
catch {
|
|
52
|
-
return false;
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
//# sourceMappingURL=images.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"images.js","sourceRoot":"","sources":["../../src/sandbox/images.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAE7C;;;;;;GAMG;AAEH,6DAA6D;AAC7D,MAAM,CAAC,MAAM,aAAa,GAAG,0BAA0B,CAAC;AAExD;;;;GAIG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,6BAA6B,CAAC;AAE9D,gFAAgF;AAChF,MAAM,UAAU,kBAAkB;IAChC,OAAO,eAAe,EAAE,IAAI,kBAAkB,CAAC,aAAa,CAAC,CAAC;AAChE,CAAC;AAED,mEAAmE;AACnE,IAAI,iBAAiB,GAAmB,IAAI,CAAC;AAE7C;;;;GAIG;AACH,MAAM,UAAU,gBAAgB;IAC9B,IAAI,iBAAiB,KAAK,IAAI,EAAE,CAAC;QAC/B,iBAAiB,GAAG,eAAe,EAAE,IAAI,kBAAkB,CAAC,gBAAgB,CAAC,CAAC;IAChF,CAAC;IACD,OAAO,iBAAiB,CAAC;AAC3B,CAAC;AAED,SAAS,eAAe;IACtB,IAAI,CAAC;QACH,YAAY,CAAC,QAAQ,EAAE,CAAC,MAAM,CAAC,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;QACrE,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,SAAS,kBAAkB,CAAC,SAAiB;IAC3C,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,YAAY,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE,IAAI,EAAE,SAAS,CAAC,EAAE;YAC9D,QAAQ,EAAE,OAAO;YACjB,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;SAChC,CAAC,CAAC;QACH,OAAO,GAAG,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC;IAC/B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC"}
|
package/dist/sandbox/index.d.ts
DELETED
|
@@ -1,112 +0,0 @@
|
|
|
1
|
-
import { DockerSandbox } from "./docker.js";
|
|
2
|
-
export { DockerSandbox } from "./docker.js";
|
|
3
|
-
export { SANDBOX_IMAGE, SANDBOX_IMAGE_QA, isSandboxAvailable, qaImageAvailable, } from "./images.js";
|
|
4
|
-
/**
|
|
5
|
-
* Clean up orphaned sandbox containers from previous runs.
|
|
6
|
-
* Called on startup to remove containers that survived a harness restart.
|
|
7
|
-
*/
|
|
8
|
-
export declare function cleanupOrphanedSandboxes(): void;
|
|
9
|
-
export declare function sandboxAvailable(): boolean;
|
|
10
|
-
/**
|
|
11
|
-
* Set up the per-task worktree directory (mkdir + optional pre-clone) without
|
|
12
|
-
* touching Docker. Used by the non-docker sandbox modes (gondolin / none) where
|
|
13
|
-
* agentic-pi runs in-process or in a VM rather than a container, but still
|
|
14
|
-
* wants a per-task workspace cloned from the target branch.
|
|
15
|
-
*/
|
|
16
|
-
export declare function setupTaskWorktree(opts: {
|
|
17
|
-
taskId: string;
|
|
18
|
-
stateDir: string;
|
|
19
|
-
sandboxDir?: string;
|
|
20
|
-
prePopulate?: {
|
|
21
|
-
owner: string;
|
|
22
|
-
repo: string;
|
|
23
|
-
branch: string;
|
|
24
|
-
token: string;
|
|
25
|
-
/** Owning run id — stamped into a marker so a reused per-PR workspace
|
|
26
|
-
* refreshes across runs but is preserved between phases of one run. */
|
|
27
|
-
runId?: string;
|
|
28
|
-
/** Clone shallowly (`--depth 1 --single-branch`) for read-only workflows. */
|
|
29
|
-
shallow?: boolean;
|
|
30
|
-
};
|
|
31
|
-
}): string;
|
|
32
|
-
/**
|
|
33
|
-
* Create a sandbox for a task. Returns the sandbox and a cleanup function.
|
|
34
|
-
* If Docker is not available, returns null (caller should fall back to direct execution).
|
|
35
|
-
*/
|
|
36
|
-
export declare function createTaskSandbox(opts: {
|
|
37
|
-
taskId: string;
|
|
38
|
-
stateDir: string;
|
|
39
|
-
sandboxDir?: string;
|
|
40
|
-
env?: Record<string, string>;
|
|
41
|
-
/**
|
|
42
|
-
* When set, the harness clones the repo into workDir at the named branch
|
|
43
|
-
* before starting the sandbox container. The agent then enters a
|
|
44
|
-
* workspace that's already checked out, avoiding a redundant
|
|
45
|
-
* `clone_repo` MCP call inside the session.
|
|
46
|
-
*
|
|
47
|
-
* Token must be alphanumeric (shape asserted upstream) and is embedded
|
|
48
|
-
* into the clone URL just for this one-shot operation — git's own
|
|
49
|
-
* credential.helper inside the sandbox covers subsequent push/pull.
|
|
50
|
-
*/
|
|
51
|
-
prePopulate?: {
|
|
52
|
-
owner: string;
|
|
53
|
-
repo: string;
|
|
54
|
-
branch: string;
|
|
55
|
-
token: string;
|
|
56
|
-
/** Owning run id — stamped into a marker so a reused per-PR workspace
|
|
57
|
-
* refreshes across runs but is preserved between phases of one run. */
|
|
58
|
-
runId?: string;
|
|
59
|
-
/** Clone shallowly (`--depth 1 --single-branch`) for read-only workflows. */
|
|
60
|
-
shallow?: boolean;
|
|
61
|
-
};
|
|
62
|
-
/**
|
|
63
|
-
* IP of the coredns sidecar to use as the sandbox's DNS resolver.
|
|
64
|
-
* Selects the egress policy: `172.30.0.10` (coredns-strict) for the
|
|
65
|
-
* default allowlist, `172.30.0.11` (coredns-open) for phases that
|
|
66
|
-
* declared `unrestricted_egress: true`. Passed to `docker run` as
|
|
67
|
-
* `--dns <ip>`. See src/sandbox/egress-firewall-config.ts.
|
|
68
|
-
*/
|
|
69
|
-
dnsIp?: string;
|
|
70
|
-
/**
|
|
71
|
-
* Override the container image. Defaults to the lean `SANDBOX_IMAGE`; a
|
|
72
|
-
* browser-QA phase passes `SANDBOX_IMAGE_QA`. The caller is responsible for
|
|
73
|
-
* ensuring the image exists (see `qaImageAvailable`).
|
|
74
|
-
*/
|
|
75
|
-
imageName?: string;
|
|
76
|
-
}): Promise<{
|
|
77
|
-
sandbox: DockerSandbox;
|
|
78
|
-
workDir: string;
|
|
79
|
-
cleanup: () => Promise<void>;
|
|
80
|
-
} | null>;
|
|
81
|
-
type PrePopulate = {
|
|
82
|
-
owner: string;
|
|
83
|
-
repo: string;
|
|
84
|
-
branch: string;
|
|
85
|
-
token: string;
|
|
86
|
-
runId?: string;
|
|
87
|
-
shallow?: boolean;
|
|
88
|
-
recreateFromBase?: boolean;
|
|
89
|
-
};
|
|
90
|
-
/**
|
|
91
|
-
* Clone the repo into `<workDir>/<repo>` at the given branch.
|
|
92
|
-
*
|
|
93
|
-
* Cases:
|
|
94
|
-
* - **Fresh dir** (no `.git`): clone. `--depth 1 --single-branch` for
|
|
95
|
-
* read-only workflows (`pre.shallow`), `--depth 50` otherwise. For
|
|
96
|
-
* `recreateFromBase` the branch is cut from the default branch directly
|
|
97
|
-
* (never `clone --branch <feature>`).
|
|
98
|
-
* - **Same run revisiting the workspace** (`.git` exists, run marker matches
|
|
99
|
-
* `pre.runId`): preserve — this is a later phase of the same run reading
|
|
100
|
-
* what an earlier phase wrote (architect's `plan.md`, the reviewer's
|
|
101
|
-
* checkout). No git ops.
|
|
102
|
-
* - **A fresh run reusing an old per-target workspace** (`.git` exists, marker
|
|
103
|
-
* differs/absent):
|
|
104
|
-
* - default (pr-review / pr-fix): fetch + hard-reset to the remote branch +
|
|
105
|
-
* `git clean` that **keeps `node_modules`** so the next `npm install` is
|
|
106
|
-
* incremental (the re-review fast path from issue #107).
|
|
107
|
-
* - `recreateFromBase` (build): delete the stale checkout and re-clone from
|
|
108
|
-
* the default branch — a re-triggered incomplete build starts again off
|
|
109
|
-
* current `main` (issue #153).
|
|
110
|
-
*/
|
|
111
|
-
export { prePopulateWorkspace as __prePopulateWorkspaceForTest };
|
|
112
|
-
export declare function prePopulateWorkspace(workDir: string, pre: PrePopulate): void;
|