lastlight 0.1.15 → 0.2.1
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 +265 -118
- package/agent-context/rules.md +62 -9
- package/agent-context/security.md +69 -0
- package/config/default.yaml +89 -0
- package/deploy/.env.production.example +20 -2
- package/deploy/entrypoint.sh +16 -17
- package/deploy/native/README.md +160 -0
- package/deploy/native/install.sh +110 -0
- package/deploy/native/lastlight.env.example +95 -0
- package/deploy/native/lastlight.service +50 -0
- package/deploy/sandbox-entrypoint.sh +59 -42
- package/dist/admin/auth.d.ts +1 -1
- package/dist/admin/auth.js +3 -1
- package/dist/admin/auth.js.map +1 -1
- package/dist/admin/chat-session-reader.d.ts +11 -14
- package/dist/admin/chat-session-reader.js +27 -51
- package/dist/admin/chat-session-reader.js.map +1 -1
- package/dist/admin/docker.d.ts +37 -0
- package/dist/admin/docker.js +86 -1
- package/dist/admin/docker.js.map +1 -1
- package/dist/admin/index.js +38 -3
- package/dist/admin/index.js.map +1 -1
- package/dist/admin/log-search.test.d.ts +1 -0
- package/dist/admin/log-search.test.js +78 -0
- package/dist/admin/log-search.test.js.map +1 -0
- package/dist/admin/routes.d.ts +52 -3
- package/dist/admin/routes.js +780 -63
- package/dist/admin/routes.js.map +1 -1
- package/dist/admin/routes.test.js +680 -14
- package/dist/admin/routes.test.js.map +1 -1
- package/dist/admin/server-logs.test.d.ts +1 -0
- package/dist/admin/server-logs.test.js +58 -0
- package/dist/admin/server-logs.test.js.map +1 -0
- package/dist/admin/sessions.d.ts +26 -39
- package/dist/admin/sessions.js +86 -310
- package/dist/admin/sessions.js.map +1 -1
- package/dist/admin/sessions.test.d.ts +1 -0
- package/dist/admin/sessions.test.js +78 -0
- package/dist/admin/sessions.test.js.map +1 -0
- package/dist/admin/version.d.ts +15 -0
- package/dist/admin/version.js +73 -0
- package/dist/admin/version.js.map +1 -0
- package/dist/admin/version.test.d.ts +1 -0
- package/dist/admin/version.test.js +71 -0
- package/dist/admin/version.test.js.map +1 -0
- package/dist/cli-config.d.ts +55 -0
- package/dist/cli-config.js +119 -0
- package/dist/cli-config.js.map +1 -0
- package/dist/cli-config.test.d.ts +1 -0
- package/dist/cli-config.test.js +92 -0
- package/dist/cli-config.test.js.map +1 -0
- package/dist/cli-format.d.ts +19 -0
- package/dist/cli-format.js +107 -0
- package/dist/cli-format.js.map +1 -0
- package/dist/cli-server.d.ts +73 -0
- package/dist/cli-server.js +347 -0
- package/dist/cli-server.js.map +1 -0
- package/dist/cli-server.test.d.ts +1 -0
- package/dist/cli-server.test.js +38 -0
- package/dist/cli-server.test.js.map +1 -0
- package/dist/cli-timeline.d.ts +35 -0
- package/dist/cli-timeline.js +373 -0
- package/dist/cli-timeline.js.map +1 -0
- package/dist/cli-timeline.test.d.ts +1 -0
- package/dist/cli-timeline.test.js +104 -0
- package/dist/cli-timeline.test.js.map +1 -0
- package/dist/cli.d.ts +0 -19
- package/dist/cli.js +910 -194
- package/dist/cli.js.map +1 -1
- package/dist/config-overlay.test.d.ts +1 -0
- package/dist/config-overlay.test.js +112 -0
- package/dist/config-overlay.test.js.map +1 -0
- package/dist/config-resolve.d.ts +28 -0
- package/dist/config-resolve.js +47 -0
- package/dist/config-resolve.js.map +1 -0
- package/dist/config-resolve.test.d.ts +1 -0
- package/dist/config-resolve.test.js +68 -0
- package/dist/config-resolve.test.js.map +1 -0
- package/dist/config.d.ts +62 -49
- package/dist/config.js +452 -76
- package/dist/config.js.map +1 -1
- package/dist/config.test.js +201 -32
- package/dist/config.test.js.map +1 -1
- package/dist/connectors/github-webhook.js +83 -5
- package/dist/connectors/github-webhook.js.map +1 -1
- package/dist/connectors/github-webhook.test.d.ts +1 -0
- package/dist/connectors/github-webhook.test.js +156 -0
- package/dist/connectors/github-webhook.test.js.map +1 -0
- package/dist/connectors/messaging/session-manager.d.ts +18 -0
- package/dist/connectors/messaging/session-manager.js +83 -2
- package/dist/connectors/messaging/session-manager.js.map +1 -1
- package/dist/connectors/messaging/session-manager.test.d.ts +1 -0
- package/dist/connectors/messaging/session-manager.test.js +144 -0
- package/dist/connectors/messaging/session-manager.test.js.map +1 -0
- package/dist/connectors/slack/connector.d.ts +9 -0
- package/dist/connectors/slack/connector.js +15 -0
- package/dist/connectors/slack/connector.js.map +1 -1
- package/dist/connectors/slack/mrkdwn.js +81 -0
- package/dist/connectors/slack/mrkdwn.js.map +1 -1
- package/dist/connectors/slack/mrkdwn.test.js +49 -0
- package/dist/connectors/slack/mrkdwn.test.js.map +1 -1
- package/dist/connectors/types.d.ts +1 -1
- package/dist/cron/fanout.d.ts +33 -0
- package/dist/cron/fanout.js +55 -0
- package/dist/cron/fanout.js.map +1 -0
- package/dist/cron/fanout.test.d.ts +1 -0
- package/dist/cron/fanout.test.js +73 -0
- package/dist/cron/fanout.test.js.map +1 -0
- package/dist/cron/jobs.d.ts +5 -0
- package/dist/cron/jobs.js +10 -3
- package/dist/cron/jobs.js.map +1 -1
- package/dist/cron/scheduler.d.ts +12 -0
- package/dist/cron/scheduler.js +27 -1
- package/dist/cron/scheduler.js.map +1 -1
- package/dist/engine/agent-executor.d.ts +158 -0
- package/dist/engine/agent-executor.js +1140 -0
- package/dist/engine/agent-executor.js.map +1 -0
- package/dist/engine/agent-executor.test.d.ts +1 -0
- package/dist/engine/agent-executor.test.js +395 -0
- package/dist/engine/agent-executor.test.js.map +1 -0
- package/dist/engine/chat-runner.d.ts +123 -0
- package/dist/engine/chat-runner.js +379 -0
- package/dist/engine/chat-runner.js.map +1 -0
- package/dist/engine/chat-runner.test.d.ts +1 -0
- package/dist/engine/chat-runner.test.js +104 -0
- package/dist/engine/chat-runner.test.js.map +1 -0
- package/dist/engine/chat-skills.d.ts +45 -0
- package/dist/engine/chat-skills.js +184 -0
- package/dist/engine/chat-skills.js.map +1 -0
- package/dist/engine/chat-skills.test.d.ts +1 -0
- package/dist/engine/chat-skills.test.js +20 -0
- package/dist/engine/chat-skills.test.js.map +1 -0
- package/dist/engine/chat.d.ts +20 -23
- package/dist/engine/chat.js +251 -155
- package/dist/engine/chat.js.map +1 -1
- package/dist/engine/chat.test.d.ts +1 -0
- package/dist/engine/chat.test.js +42 -0
- package/dist/engine/chat.test.js.map +1 -0
- package/dist/engine/classifier.d.ts +35 -2
- package/dist/engine/classifier.js +170 -31
- package/dist/engine/classifier.js.map +1 -1
- package/dist/engine/classifier.test.d.ts +1 -0
- package/dist/engine/classifier.test.js +115 -0
- package/dist/engine/classifier.test.js.map +1 -0
- package/dist/engine/dispatcher.d.ts +60 -0
- package/dist/engine/dispatcher.js +601 -0
- package/dist/engine/dispatcher.js.map +1 -0
- package/dist/engine/dispatcher.test.d.ts +1 -0
- package/dist/engine/dispatcher.test.js +511 -0
- package/dist/engine/dispatcher.test.js.map +1 -0
- package/dist/engine/event-shim.d.ts +117 -0
- package/dist/engine/event-shim.js +435 -0
- package/dist/engine/event-shim.js.map +1 -0
- package/dist/engine/event-shim.test.d.ts +1 -0
- package/dist/engine/event-shim.test.js +194 -0
- package/dist/engine/event-shim.test.js.map +1 -0
- package/dist/engine/git-auth.d.ts +13 -17
- package/dist/engine/git-auth.js +99 -42
- package/dist/engine/git-auth.js.map +1 -1
- package/dist/engine/git-auth.test.d.ts +1 -0
- package/dist/engine/git-auth.test.js +117 -0
- package/dist/engine/git-auth.test.js.map +1 -0
- package/dist/engine/github-app-client.d.ts +7 -0
- package/dist/engine/github-app-client.js +16 -0
- package/dist/engine/github-app-client.js.map +1 -0
- package/dist/engine/github-app-client.test.d.ts +1 -0
- package/dist/engine/github-app-client.test.js +44 -0
- package/dist/engine/github-app-client.test.js.map +1 -0
- package/dist/engine/github-tools.d.ts +12 -0
- package/dist/engine/github-tools.js +261 -0
- package/dist/engine/github-tools.js.map +1 -0
- package/dist/engine/github.d.ts +1027 -43
- package/dist/engine/github.js +153 -14
- package/dist/engine/github.js.map +1 -1
- package/dist/engine/llm.d.ts +47 -0
- package/dist/engine/llm.js +221 -0
- package/dist/engine/llm.js.map +1 -0
- package/dist/engine/llm.test.d.ts +1 -0
- package/dist/engine/llm.test.js +189 -0
- package/dist/engine/llm.test.js.map +1 -0
- package/dist/engine/profiles.d.ts +249 -0
- package/dist/engine/profiles.js +42 -0
- package/dist/engine/profiles.js.map +1 -0
- package/dist/engine/router.d.ts +12 -6
- package/dist/engine/router.js +339 -81
- package/dist/engine/router.js.map +1 -1
- package/dist/engine/router.test.js +428 -78
- package/dist/engine/router.test.js.map +1 -1
- package/dist/engine/screen.d.ts +41 -0
- package/dist/engine/screen.js +93 -0
- package/dist/engine/screen.js.map +1 -0
- package/dist/engine/screen.test.d.ts +1 -0
- package/dist/engine/screen.test.js +82 -0
- package/dist/engine/screen.test.js.map +1 -0
- package/dist/index.js +377 -432
- package/dist/index.js.map +1 -1
- package/dist/managed-repos.d.ts +7 -9
- package/dist/managed-repos.js +12 -15
- package/dist/managed-repos.js.map +1 -1
- package/dist/managed-repos.test.js +24 -19
- package/dist/managed-repos.test.js.map +1 -1
- package/dist/notify/index.d.ts +15 -0
- package/dist/notify/index.js +6 -0
- package/dist/notify/index.js.map +1 -0
- package/dist/notify/model.d.ts +57 -0
- package/dist/notify/model.js +89 -0
- package/dist/notify/model.js.map +1 -0
- package/dist/notify/model.test.d.ts +1 -0
- package/dist/notify/model.test.js +109 -0
- package/dist/notify/model.test.js.map +1 -0
- package/dist/notify/notifier.d.ts +17 -0
- package/dist/notify/notifier.js +87 -0
- package/dist/notify/notifier.js.map +1 -0
- package/dist/notify/notifier.test.d.ts +1 -0
- package/dist/notify/notifier.test.js +100 -0
- package/dist/notify/notifier.test.js.map +1 -0
- package/dist/notify/render.d.ts +21 -0
- package/dist/notify/render.js +59 -0
- package/dist/notify/render.js.map +1 -0
- package/dist/notify/render.test.d.ts +1 -0
- package/dist/notify/render.test.js +65 -0
- package/dist/notify/render.test.js.map +1 -0
- package/dist/notify/transports/github.d.ts +26 -0
- package/dist/notify/transports/github.js +26 -0
- package/dist/notify/transports/github.js.map +1 -0
- package/dist/notify/transports/slack.d.ts +26 -0
- package/dist/notify/transports/slack.js +28 -0
- package/dist/notify/transports/slack.js.map +1 -0
- package/dist/notify/transports.test.d.ts +1 -0
- package/dist/notify/transports.test.js +71 -0
- package/dist/notify/transports.test.js.map +1 -0
- package/dist/notify/types.d.ts +95 -0
- package/dist/notify/types.js +16 -0
- package/dist/notify/types.js.map +1 -0
- package/dist/sandbox/docker-compose.test.d.ts +1 -0
- package/dist/sandbox/docker-compose.test.js +128 -0
- package/dist/sandbox/docker-compose.test.js.map +1 -0
- package/dist/sandbox/docker.d.ts +97 -9
- package/dist/sandbox/docker.js +192 -41
- package/dist/sandbox/docker.js.map +1 -1
- package/dist/sandbox/docker.test.d.ts +1 -0
- package/dist/sandbox/docker.test.js +137 -0
- package/dist/sandbox/docker.test.js.map +1 -0
- package/dist/sandbox/egress-allowlist.d.ts +69 -0
- package/dist/sandbox/egress-allowlist.js +164 -0
- package/dist/sandbox/egress-allowlist.js.map +1 -0
- package/dist/sandbox/egress-allowlist.test.d.ts +1 -0
- package/dist/sandbox/egress-allowlist.test.js +65 -0
- package/dist/sandbox/egress-allowlist.test.js.map +1 -0
- package/dist/sandbox/egress-firewall-config.d.ts +127 -0
- package/dist/sandbox/egress-firewall-config.js +434 -0
- package/dist/sandbox/egress-firewall-config.js.map +1 -0
- package/dist/sandbox/egress-firewall-config.test.d.ts +1 -0
- package/dist/sandbox/egress-firewall-config.test.js +244 -0
- package/dist/sandbox/egress-firewall-config.test.js.map +1 -0
- package/dist/sandbox/images.d.ts +23 -0
- package/dist/sandbox/images.js +55 -0
- package/dist/sandbox/images.js.map +1 -0
- package/dist/sandbox/index.d.ts +82 -3
- package/dist/sandbox/index.js +223 -93
- package/dist/sandbox/index.js.map +1 -1
- package/dist/sandbox/index.test.d.ts +1 -0
- package/dist/sandbox/index.test.js +157 -0
- package/dist/sandbox/index.test.js.map +1 -0
- package/dist/session-log.d.ts +63 -0
- package/dist/session-log.js +290 -0
- package/dist/session-log.js.map +1 -0
- package/dist/session-log.test.d.ts +1 -0
- package/dist/session-log.test.js +85 -0
- package/dist/session-log.test.js.map +1 -0
- package/dist/setup.d.ts +30 -1
- package/dist/setup.js +241 -25
- package/dist/setup.js.map +1 -1
- package/dist/setup.test.js +138 -6
- package/dist/setup.test.js.map +1 -1
- package/dist/state/approval-store.d.ts +86 -0
- package/dist/state/approval-store.js +140 -0
- package/dist/state/approval-store.js.map +1 -0
- package/dist/state/build-assets.d.ts +50 -0
- package/dist/state/build-assets.js +154 -0
- package/dist/state/build-assets.js.map +1 -0
- package/dist/state/build-assets.test.d.ts +1 -0
- package/dist/state/build-assets.test.js +106 -0
- package/dist/state/build-assets.test.js.map +1 -0
- package/dist/state/db.d.ts +65 -333
- package/dist/state/db.js +112 -835
- package/dist/state/db.js.map +1 -1
- package/dist/state/db.test.js +127 -91
- package/dist/state/db.test.js.map +1 -1
- package/dist/state/execution-store.d.ts +257 -0
- package/dist/state/execution-store.js +527 -0
- package/dist/state/execution-store.js.map +1 -0
- package/dist/state/migrate.d.ts +15 -0
- package/dist/state/migrate.js +175 -0
- package/dist/state/migrate.js.map +1 -0
- package/dist/state/workflow-run-store.d.ts +195 -0
- package/dist/state/workflow-run-store.js +363 -0
- package/dist/state/workflow-run-store.js.map +1 -0
- package/dist/state/workflow-run-store.test.d.ts +1 -0
- package/dist/state/workflow-run-store.test.js +264 -0
- package/dist/state/workflow-run-store.test.js.map +1 -0
- package/dist/telemetry/index.d.ts +38 -0
- package/dist/telemetry/index.js +253 -0
- package/dist/telemetry/index.js.map +1 -0
- package/dist/telemetry/index.test.d.ts +1 -0
- package/dist/telemetry/index.test.js +73 -0
- package/dist/telemetry/index.test.js.map +1 -0
- package/dist/telemetry/pi-events.d.ts +12 -0
- package/dist/telemetry/pi-events.js +134 -0
- package/dist/telemetry/pi-events.js.map +1 -0
- package/dist/telemetry/pi-events.test.d.ts +1 -0
- package/dist/telemetry/pi-events.test.js +69 -0
- package/dist/telemetry/pi-events.test.js.map +1 -0
- package/dist/workflows/dag.d.ts +13 -1
- package/dist/workflows/dag.js +7 -3
- package/dist/workflows/dag.js.map +1 -1
- package/dist/workflows/dag.test.js +22 -0
- package/dist/workflows/dag.test.js.map +1 -1
- package/dist/workflows/golden-build.test.d.ts +1 -0
- package/dist/workflows/golden-build.test.js +45 -0
- package/dist/workflows/golden-build.test.js.map +1 -0
- package/dist/workflows/loader-overlay.test.d.ts +1 -0
- package/dist/workflows/loader-overlay.test.js +101 -0
- package/dist/workflows/loader-overlay.test.js.map +1 -0
- package/dist/workflows/loader.d.ts +36 -11
- package/dist/workflows/loader.js +311 -87
- package/dist/workflows/loader.js.map +1 -1
- package/dist/workflows/loader.test.js +114 -10
- package/dist/workflows/loader.test.js.map +1 -1
- package/dist/workflows/loop-eval.js +2 -0
- package/dist/workflows/loop-eval.js.map +1 -1
- package/dist/workflows/loop-eval.test.js +14 -0
- package/dist/workflows/loop-eval.test.js.map +1 -1
- package/dist/workflows/phase-executor.d.ts +145 -0
- package/dist/workflows/phase-executor.js +691 -0
- package/dist/workflows/phase-executor.js.map +1 -0
- package/dist/workflows/phase-executor.test.d.ts +1 -0
- package/dist/workflows/phase-executor.test.js +434 -0
- package/dist/workflows/phase-executor.test.js.map +1 -0
- package/dist/workflows/phase-ref.d.ts +44 -0
- package/dist/workflows/phase-ref.js +78 -0
- package/dist/workflows/phase-ref.js.map +1 -0
- package/dist/workflows/phase-ref.test.d.ts +1 -0
- package/dist/workflows/phase-ref.test.js +24 -0
- package/dist/workflows/phase-ref.test.js.map +1 -0
- package/dist/workflows/resume.d.ts +5 -11
- package/dist/workflows/resume.js +88 -7
- package/dist/workflows/resume.js.map +1 -1
- package/dist/workflows/runner.d.ts +34 -27
- package/dist/workflows/runner.js +252 -930
- package/dist/workflows/runner.js.map +1 -1
- package/dist/workflows/runner.test.js +346 -35
- package/dist/workflows/runner.test.js.map +1 -1
- package/dist/workflows/schema.d.ts +52 -10
- package/dist/workflows/schema.js +147 -7
- package/dist/workflows/schema.js.map +1 -1
- package/dist/workflows/simple.d.ts +67 -3
- package/dist/workflows/simple.js +248 -87
- package/dist/workflows/simple.js.map +1 -1
- package/dist/workflows/simple.test.d.ts +1 -0
- package/dist/workflows/simple.test.js +107 -0
- package/dist/workflows/simple.test.js.map +1 -0
- package/dist/workflows/templates.d.ts +29 -0
- package/dist/workflows/templates.js +42 -4
- package/dist/workflows/templates.js.map +1 -1
- package/dist/workflows/templates.test.js +103 -0
- package/dist/workflows/templates.test.js.map +1 -1
- package/dist/workflows/triggers.d.ts +21 -0
- package/dist/workflows/triggers.js +44 -0
- package/dist/workflows/triggers.js.map +1 -0
- package/dist/workflows/verdict.d.ts +19 -0
- package/dist/workflows/verdict.js +30 -0
- package/dist/workflows/verdict.js.map +1 -0
- package/dist/workflows/verdict.test.d.ts +1 -0
- package/dist/workflows/verdict.test.js +44 -0
- package/dist/workflows/verdict.test.js.map +1 -0
- package/dist/worktree/manager.d.ts +1 -1
- package/dist/worktree/manager.js +14 -14
- package/dist/worktree/manager.js.map +1 -1
- package/dist/worktree/manager.test.d.ts +1 -0
- package/dist/worktree/manager.test.js +87 -0
- package/dist/worktree/manager.test.js.map +1 -0
- package/docker-compose.yml +206 -5
- package/package.json +19 -9
- package/sandbox.Dockerfile +97 -18
- package/skills/README.md +40 -0
- package/skills/browser-qa/SKILL.md +193 -0
- package/skills/browser-qa/scripts/agent-browser.mjs +380 -0
- package/skills/building/SKILL.md +95 -0
- package/skills/chat/SKILL.md +30 -11
- package/skills/code-review/SKILL.md +59 -0
- package/skills/debug-production/SKILL.md +108 -0
- package/skills/demo/SKILL.md +194 -0
- package/skills/demo/scripts/compose-demo.sh +205 -0
- package/skills/issue-answer/SKILL.md +90 -0
- package/skills/issue-comment/SKILL.md +38 -24
- package/skills/issue-triage/SKILL.md +103 -37
- package/skills/issue-triage/references/AGENT-BRIEF.md +61 -0
- package/skills/pr-comment/SKILL.md +64 -0
- package/skills/pr-review/SKILL.md +65 -49
- package/skills/qa-test/SKILL.md +97 -0
- package/skills/repo-health/SKILL.md +48 -45
- package/skills/security-feedback/SKILL.md +173 -0
- package/skills/security-feedback/references/templates.md +77 -0
- package/skills/security-review/SKILL.md +213 -0
- package/skills/security-review/references/issue-format.md +302 -0
- package/skills/verify/SKILL.md +118 -0
- package/workflows/answer.yaml +37 -0
- package/workflows/build.yaml +32 -22
- package/workflows/cron-security.yaml +6 -0
- package/workflows/demo.yaml +55 -0
- package/workflows/explore.yaml +9 -0
- package/workflows/pr-comment.yaml +16 -0
- package/workflows/pr-fix.yaml +3 -0
- package/workflows/pr-review.yaml +4 -1
- package/workflows/prompts/answer.md +67 -0
- package/workflows/prompts/architect.md +24 -7
- package/workflows/prompts/demo.md +100 -0
- package/workflows/prompts/executor.md +29 -20
- package/workflows/prompts/explore-ask.md +51 -22
- package/workflows/prompts/explore-publish.md +2 -2
- package/workflows/prompts/explore-read.md +24 -10
- package/workflows/prompts/explore-synthesize.md +15 -8
- package/workflows/prompts/fix.md +9 -10
- package/workflows/prompts/guardrails.md +26 -8
- package/workflows/prompts/pr-fix.md +6 -7
- package/workflows/prompts/pr.md +11 -10
- package/workflows/prompts/qa-browser.md +95 -0
- package/workflows/prompts/qa-synth.md +44 -0
- package/workflows/prompts/qa-test.md +60 -0
- package/workflows/prompts/re-reviewer.md +8 -9
- package/workflows/prompts/reviewer.md +10 -9
- package/workflows/prompts/verify-browser.md +93 -0
- package/workflows/prompts/verify-synth.md +44 -0
- package/workflows/prompts/verify.md +63 -0
- package/workflows/qa-test.yaml +87 -0
- package/workflows/security-feedback.yaml +25 -0
- package/workflows/security-review.yaml +29 -0
- package/workflows/verify.yaml +85 -0
- package/deploy/mcp-config.tmpl.json +0 -14
- package/dist/cron/rate-limits.d.ts +0 -26
- package/dist/cron/rate-limits.js +0 -193
- package/dist/cron/rate-limits.js.map +0 -1
- package/dist/engine/executor.d.ts +0 -75
- package/dist/engine/executor.js +0 -292
- package/dist/engine/executor.js.map +0 -1
- package/mcp-github-app/package.json +0 -18
- package/mcp-github-app/src/auth.js +0 -66
- package/mcp-github-app/src/github.js +0 -371
- package/mcp-github-app/src/index.js +0 -534
- package/skills/devops/webhook-subscriptions/SKILL.md +0 -180
- package/skills/github/DESCRIPTION.md +0 -3
- package/skills/github/codebase-inspection/SKILL.md +0 -115
- package/skills/github/github-auth/SKILL.md +0 -54
- package/skills/github/github-auth/scripts/gh-env.sh +0 -66
- package/skills/github/github-code-review/SKILL.md +0 -480
- package/skills/github/github-code-review/references/review-output-template.md +0 -74
- package/skills/github/github-issues/SKILL.md +0 -369
- package/skills/github/github-issues/templates/bug-report.md +0 -35
- package/skills/github/github-issues/templates/feature-request.md +0 -31
- package/skills/github/github-pr-workflow/SKILL.md +0 -395
- package/skills/github/github-pr-workflow/references/ci-troubleshooting.md +0 -183
- package/skills/github/github-pr-workflow/references/conventional-commits.md +0 -71
- package/skills/github/github-pr-workflow/templates/pr-body-bugfix.md +0 -35
- package/skills/github/github-pr-workflow/templates/pr-body-feature.md +0 -33
- package/skills/github/github-repo-management/SKILL.md +0 -515
- package/skills/github/github-repo-management/references/github-api-cheatsheet.md +0 -161
- package/skills/github-orchestrator/SKILL.md +0 -103
- package/skills/mcp/DESCRIPTION.md +0 -3
- package/skills/mcp/mcporter/SKILL.md +0 -122
- package/skills/mcp/native-mcp/SKILL.md +0 -356
- package/skills/software-development/architect/SKILL.md +0 -154
- package/skills/software-development/assure-guardrails/SKILL.md +0 -239
- package/skills/software-development/plan/SKILL.md +0 -64
- package/skills/software-development/requesting-code-review/SKILL.md +0 -291
- package/skills/software-development/subagent-driven-development/SKILL.md +0 -433
- package/skills/software-development/systematic-debugging/SKILL.md +0 -366
- package/skills/software-development/test-driven-development/SKILL.md +0 -342
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import { isIP } from "node:net";
|
|
2
|
+
/**
|
|
3
|
+
* Single source of truth for sandbox HTTP egress allowlists.
|
|
4
|
+
*
|
|
5
|
+
* Both sandbox backends consume this list:
|
|
6
|
+
* - gondolin: passed verbatim to `agenticRun({ allowedHttpHosts })` so the
|
|
7
|
+
* QEMU-layer HTTP interceptor 502s anything off-list.
|
|
8
|
+
* - docker: nginx-egress + coredns configs are generated from these hosts
|
|
9
|
+
* at harness boot. Sandbox containers spawn with `--dns <coredns-ip>`;
|
|
10
|
+
* coredns sinkholes allowlisted hostnames to the nginx firewall IP,
|
|
11
|
+
* which peeks SNI and tunnels to the real upstream. See
|
|
12
|
+
* `src/sandbox/egress-firewall-config.ts` for the full architecture.
|
|
13
|
+
*
|
|
14
|
+
* The lists are intentionally split so callers can compose tighter policies
|
|
15
|
+
* (e.g. a read-only profile that doesn't need package registries). The
|
|
16
|
+
* everyday default is `DEFAULT_ALLOWLIST`.
|
|
17
|
+
*
|
|
18
|
+
* ## Convention: every entry matches the apex AND all subdomains
|
|
19
|
+
*
|
|
20
|
+
* `openai.com` → matches openai.com, api.openai.com, platform.openai.com, …
|
|
21
|
+
* `npmjs.org` → matches npmjs.org, registry.npmjs.org, auth.npmjs.org, …
|
|
22
|
+
*
|
|
23
|
+
* Bare hostnames only — no leading dot, no `*.` prefix. The config
|
|
24
|
+
* generator emits the right syntax for each backend (nginx's
|
|
25
|
+
* `.example.com` map form, CoreDNS regex `(^|\.)example\.com\.$`).
|
|
26
|
+
*
|
|
27
|
+
* Exact-only matching isn't currently supported because we haven't
|
|
28
|
+
* needed it — every host in the list is one we want apex+subdomain
|
|
29
|
+
* access to. If we ever do, we'd add an explicit type (e.g. an `exact:`
|
|
30
|
+
* prefix) so the loose-by-default convention stays unambiguous.
|
|
31
|
+
*
|
|
32
|
+
* A workflow phase can declare `unrestricted_egress: true` to bypass the
|
|
33
|
+
* allowlist entirely — see `src/workflows` for the phase schema.
|
|
34
|
+
*/
|
|
35
|
+
/** GitHub HTTPS endpoints used by `git`, `gh`, and agentic-pi's github tools. */
|
|
36
|
+
export const GITHUB_HOSTS = [
|
|
37
|
+
// Covers github.com plus api.github.com, codeload.github.com, raw.…, gist.…
|
|
38
|
+
"github.com",
|
|
39
|
+
// *.githubusercontent.com — release artifacts, raw blobs, avatars.
|
|
40
|
+
"githubusercontent.com",
|
|
41
|
+
];
|
|
42
|
+
/**
|
|
43
|
+
* LLM provider hosts.
|
|
44
|
+
*
|
|
45
|
+
* Required for the docker backend because `agentic-pi run` executes inside
|
|
46
|
+
* the sandbox container there (`src/sandbox/docker.ts` runs `agentic-pi run
|
|
47
|
+
* --sandbox none`), so the LLM HTTP call originates from inside the
|
|
48
|
+
* container. The gondolin backend runs agentic-pi in the harness process,
|
|
49
|
+
* so the call originates from the host and these hosts aren't strictly
|
|
50
|
+
* required inside the VM — they're kept here so a single allowlist can
|
|
51
|
+
* cover both paths without surprises.
|
|
52
|
+
*/
|
|
53
|
+
export const PROVIDER_HOSTS = [
|
|
54
|
+
"anthropic.com",
|
|
55
|
+
"openai.com",
|
|
56
|
+
"openrouter.ai",
|
|
57
|
+
// Fireworks — api.fireworks.ai is the inference endpoint.
|
|
58
|
+
"fireworks.ai",
|
|
59
|
+
];
|
|
60
|
+
/**
|
|
61
|
+
* Public package registries the executor may hit during `npm install`,
|
|
62
|
+
* etc. Apex-plus-subdomain matching covers auth / CDN / mirror
|
|
63
|
+
* subdomains without needing separate entries.
|
|
64
|
+
*/
|
|
65
|
+
export const PACKAGE_REGISTRY_HOSTS = [
|
|
66
|
+
// npm / yarn / pnpm
|
|
67
|
+
"npmjs.org",
|
|
68
|
+
"yarnpkg.com",
|
|
69
|
+
// Python — pypi.org + files.pythonhosted.org are the two big ones.
|
|
70
|
+
"pypi.org",
|
|
71
|
+
"pythonhosted.org",
|
|
72
|
+
// Rust — static.crates.io, index.crates.io, crates.io itself.
|
|
73
|
+
"crates.io",
|
|
74
|
+
// Go modules — covers proxy.golang.org, sum.golang.org, plus golang.org.
|
|
75
|
+
"golang.org",
|
|
76
|
+
// Ruby
|
|
77
|
+
"rubygems.org",
|
|
78
|
+
// Alpine apk + Debian apt — apex covers the regional mirror subdomains.
|
|
79
|
+
"alpinelinux.org",
|
|
80
|
+
"debian.org",
|
|
81
|
+
];
|
|
82
|
+
/**
|
|
83
|
+
* Combined allowlist used by both backends when a phase has not opted into
|
|
84
|
+
* unrestricted egress. Order is preserved across imports so generated
|
|
85
|
+
* configs are stable.
|
|
86
|
+
*/
|
|
87
|
+
export const DEFAULT_ALLOWLIST = [
|
|
88
|
+
...GITHUB_HOSTS,
|
|
89
|
+
...PROVIDER_HOSTS,
|
|
90
|
+
...PACKAGE_REGISTRY_HOSTS,
|
|
91
|
+
];
|
|
92
|
+
/**
|
|
93
|
+
* Sentinel value recognized by agentic-pi/gondolin (post the `"*"` patch)
|
|
94
|
+
* meaning "allow every host". Used when a phase sets `unrestricted_egress`.
|
|
95
|
+
*
|
|
96
|
+
* On the docker backend, unrestricted egress routes through the open
|
|
97
|
+
* nginx-egress + coredns-open pair — this sentinel is for gondolin only.
|
|
98
|
+
*/
|
|
99
|
+
export const ALLOW_ALL_SENTINEL = "*";
|
|
100
|
+
const INTERNAL_HOSTNAMES = new Set(["localhost", "metadata.google.internal"]);
|
|
101
|
+
function isPrivateOrInternalIp(host) {
|
|
102
|
+
const ip = host.replace(/^\[|\]$/g, "");
|
|
103
|
+
const family = isIP(ip);
|
|
104
|
+
if (family === 4) {
|
|
105
|
+
const octets = ip.split(".").map((part) => Number(part));
|
|
106
|
+
if (octets.length !== 4 || octets.some((part) => !Number.isInteger(part) || part < 0 || part > 255))
|
|
107
|
+
return true;
|
|
108
|
+
const [a, b] = octets;
|
|
109
|
+
return a === 0
|
|
110
|
+
|| a === 10
|
|
111
|
+
|| a === 127
|
|
112
|
+
|| (a === 169 && b === 254)
|
|
113
|
+
|| (a === 172 && b >= 16 && b <= 31)
|
|
114
|
+
|| (a === 192 && b === 168);
|
|
115
|
+
}
|
|
116
|
+
if (family === 6) {
|
|
117
|
+
const lower = ip.toLowerCase();
|
|
118
|
+
const mappedIpv4 = lower.match(/^::ffff:(\d+\.\d+\.\d+\.\d+)$/)?.[1];
|
|
119
|
+
if (mappedIpv4)
|
|
120
|
+
return isPrivateOrInternalIp(mappedIpv4);
|
|
121
|
+
if (lower.startsWith("::ffff:"))
|
|
122
|
+
return true;
|
|
123
|
+
return lower === "::"
|
|
124
|
+
|| lower === "::1"
|
|
125
|
+
|| lower.startsWith("fe8")
|
|
126
|
+
|| lower.startsWith("fe9")
|
|
127
|
+
|| lower.startsWith("fea")
|
|
128
|
+
|| lower.startsWith("feb")
|
|
129
|
+
|| lower.startsWith("fc")
|
|
130
|
+
|| lower.startsWith("fd");
|
|
131
|
+
}
|
|
132
|
+
return false;
|
|
133
|
+
}
|
|
134
|
+
export function normalizeAllowlistHost(host) {
|
|
135
|
+
const trimmed = host.trim().toLowerCase();
|
|
136
|
+
if (!trimmed)
|
|
137
|
+
return null;
|
|
138
|
+
let parsed = trimmed;
|
|
139
|
+
try {
|
|
140
|
+
parsed = new URL(trimmed.includes("://") ? trimmed : `https://${trimmed}`).hostname.toLowerCase();
|
|
141
|
+
}
|
|
142
|
+
catch {
|
|
143
|
+
parsed = trimmed.split("/")[0] || "";
|
|
144
|
+
if (!parsed.startsWith("["))
|
|
145
|
+
parsed = parsed.split(":")[0] || "";
|
|
146
|
+
}
|
|
147
|
+
parsed = parsed.replace(/^\.+|\.+$/g, "").replace(/^\[|\]$/g, "");
|
|
148
|
+
if (!parsed || parsed.includes("*") || INTERNAL_HOSTNAMES.has(parsed) || isPrivateOrInternalIp(parsed))
|
|
149
|
+
return null;
|
|
150
|
+
return parsed;
|
|
151
|
+
}
|
|
152
|
+
export function mergeAllowlist(base, extra = []) {
|
|
153
|
+
const out = [];
|
|
154
|
+
const seen = new Set();
|
|
155
|
+
for (const candidate of [...base, ...extra]) {
|
|
156
|
+
const host = normalizeAllowlistHost(candidate);
|
|
157
|
+
if (host && !seen.has(host)) {
|
|
158
|
+
seen.add(host);
|
|
159
|
+
out.push(host);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
return out;
|
|
163
|
+
}
|
|
164
|
+
//# sourceMappingURL=egress-allowlist.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"egress-allowlist.js","sourceRoot":"","sources":["../../src/sandbox/egress-allowlist.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { ALLOW_ALL_SENTINEL, DEFAULT_ALLOWLIST, GITHUB_HOSTS, PACKAGE_REGISTRY_HOSTS, PROVIDER_HOSTS, mergeAllowlist, normalizeAllowlistHost, } from "./egress-allowlist.js";
|
|
3
|
+
describe("egress-allowlist source of truth", () => {
|
|
4
|
+
it("groups are non-empty and disjoint", () => {
|
|
5
|
+
for (const group of [GITHUB_HOSTS, PROVIDER_HOSTS, PACKAGE_REGISTRY_HOSTS]) {
|
|
6
|
+
expect(group.length).toBeGreaterThan(0);
|
|
7
|
+
}
|
|
8
|
+
const all = [...GITHUB_HOSTS, ...PROVIDER_HOSTS, ...PACKAGE_REGISTRY_HOSTS];
|
|
9
|
+
expect(new Set(all).size).toBe(all.length);
|
|
10
|
+
});
|
|
11
|
+
it("DEFAULT_ALLOWLIST is the union of the three groups in declaration order", () => {
|
|
12
|
+
const expected = [...GITHUB_HOSTS, ...PROVIDER_HOSTS, ...PACKAGE_REGISTRY_HOSTS];
|
|
13
|
+
expect([...DEFAULT_ALLOWLIST]).toEqual(expected);
|
|
14
|
+
});
|
|
15
|
+
it("covers the critical host categories the runtime depends on", () => {
|
|
16
|
+
// GitHub apex covers api.github.com, codeload.github.com, raw.…
|
|
17
|
+
expect(GITHUB_HOSTS).toContain("github.com");
|
|
18
|
+
// Provider hosts — the docker backend dials these from inside the
|
|
19
|
+
// sandbox container.
|
|
20
|
+
expect(PROVIDER_HOSTS).toContain("openai.com");
|
|
21
|
+
expect(PROVIDER_HOSTS).toContain("anthropic.com");
|
|
22
|
+
// npm — covers registry.npmjs.org, auth.npmjs.org, www.npmjs.org.
|
|
23
|
+
expect(PACKAGE_REGISTRY_HOSTS).toContain("npmjs.org");
|
|
24
|
+
});
|
|
25
|
+
it("entries are bare hostnames (no leading dot, no wildcard prefix)", () => {
|
|
26
|
+
// Convention is "every entry matches apex+subdomains" — see file
|
|
27
|
+
// docstring. The config generator emits the right syntax for each
|
|
28
|
+
// backend. If someone tries to write `.github.com` or `*.github.com`
|
|
29
|
+
// here, fail fast.
|
|
30
|
+
for (const host of DEFAULT_ALLOWLIST) {
|
|
31
|
+
expect(host).toMatch(/^[A-Za-z0-9][A-Za-z0-9.-]*[A-Za-z0-9]$/);
|
|
32
|
+
expect(host.startsWith(".")).toBe(false);
|
|
33
|
+
expect(host.includes("*")).toBe(false);
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
it("ALLOW_ALL_SENTINEL is the wildcard string the gondolin matcher honours", () => {
|
|
37
|
+
expect(ALLOW_ALL_SENTINEL).toBe("*");
|
|
38
|
+
});
|
|
39
|
+
it("normalizes and merges extra allowlist hosts", () => {
|
|
40
|
+
expect(normalizeAllowlistHost("https://Collector.Example.com:4318/v1/traces")).toBe("collector.example.com");
|
|
41
|
+
expect(normalizeAllowlistHost("169.254.169.254")).toBeNull();
|
|
42
|
+
expect(mergeAllowlist(["github.com"], ["GitHub.com", "otel.example.com"])).toEqual([
|
|
43
|
+
"github.com",
|
|
44
|
+
"otel.example.com",
|
|
45
|
+
]);
|
|
46
|
+
});
|
|
47
|
+
it("rejects private and internal collector endpoints", () => {
|
|
48
|
+
for (const host of [
|
|
49
|
+
"0.0.0.0",
|
|
50
|
+
"127.0.0.1",
|
|
51
|
+
"10.0.0.4",
|
|
52
|
+
"172.16.0.1",
|
|
53
|
+
"192.168.1.10",
|
|
54
|
+
"http://[::1]:4318",
|
|
55
|
+
"http://[fe80::1]:4318",
|
|
56
|
+
"http://[fd00::1]:4318",
|
|
57
|
+
"http://[::ffff:127.0.0.1]:4318",
|
|
58
|
+
"metadata.google.internal",
|
|
59
|
+
"localhost",
|
|
60
|
+
]) {
|
|
61
|
+
expect(normalizeAllowlistHost(host), host).toBeNull();
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
//# sourceMappingURL=egress-allowlist.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"egress-allowlist.test.js","sourceRoot":"","sources":["../../src/sandbox/egress-allowlist.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EACL,kBAAkB,EAClB,iBAAiB,EACjB,YAAY,EACZ,sBAAsB,EACtB,cAAc,EACd,cAAc,EACd,sBAAsB,GACvB,MAAM,uBAAuB,CAAC;AAE/B,QAAQ,CAAC,kCAAkC,EAAE,GAAG,EAAE;IAChD,EAAE,CAAC,mCAAmC,EAAE,GAAG,EAAE;QAC3C,KAAK,MAAM,KAAK,IAAI,CAAC,YAAY,EAAE,cAAc,EAAE,sBAAsB,CAAC,EAAE,CAAC;YAC3E,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;QAC1C,CAAC;QACD,MAAM,GAAG,GAAG,CAAC,GAAG,YAAY,EAAE,GAAG,cAAc,EAAE,GAAG,sBAAsB,CAAC,CAAC;QAC5E,MAAM,CAAC,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IAC7C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yEAAyE,EAAE,GAAG,EAAE;QACjF,MAAM,QAAQ,GAAG,CAAC,GAAG,YAAY,EAAE,GAAG,cAAc,EAAE,GAAG,sBAAsB,CAAC,CAAC;QACjF,MAAM,CAAC,CAAC,GAAG,iBAAiB,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IACnD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4DAA4D,EAAE,GAAG,EAAE;QACpE,gEAAgE;QAChE,MAAM,CAAC,YAAY,CAAC,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC;QAC7C,kEAAkE;QAClE,qBAAqB;QACrB,MAAM,CAAC,cAAc,CAAC,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC;QAC/C,MAAM,CAAC,cAAc,CAAC,CAAC,SAAS,CAAC,eAAe,CAAC,CAAC;QAClD,kEAAkE;QAClE,MAAM,CAAC,sBAAsB,CAAC,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;IACxD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iEAAiE,EAAE,GAAG,EAAE;QACzE,iEAAiE;QACjE,kEAAkE;QAClE,qEAAqE;QACrE,mBAAmB;QACnB,KAAK,MAAM,IAAI,IAAI,iBAAiB,EAAE,CAAC;YACrC,MAAM,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,wCAAwC,CAAC,CAAC;YAC/D,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACzC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACzC,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wEAAwE,EAAE,GAAG,EAAE;QAChF,MAAM,CAAC,kBAAkB,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACvC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6CAA6C,EAAE,GAAG,EAAE;QACrD,MAAM,CAAC,sBAAsB,CAAC,8CAA8C,CAAC,CAAC,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAC;QAC7G,MAAM,CAAC,sBAAsB,CAAC,iBAAiB,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC;QAC7D,MAAM,CAAC,cAAc,CAAC,CAAC,YAAY,CAAC,EAAE,CAAC,YAAY,EAAE,kBAAkB,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;YACjF,YAAY;YACZ,kBAAkB;SACnB,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kDAAkD,EAAE,GAAG,EAAE;QAC1D,KAAK,MAAM,IAAI,IAAI;YACjB,SAAS;YACT,WAAW;YACX,UAAU;YACV,YAAY;YACZ,cAAc;YACd,mBAAmB;YACnB,uBAAuB;YACvB,uBAAuB;YACvB,gCAAgC;YAChC,0BAA0B;YAC1B,WAAW;SACZ,EAAE,CAAC;YACF,MAAM,CAAC,sBAAsB,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC,CAAC,QAAQ,EAAE,CAAC;QACxD,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Egress firewall config generation for the docker sandbox backend.
|
|
3
|
+
*
|
|
4
|
+
* Architecture (replaces the earlier tinyproxy CONNECT-proxy):
|
|
5
|
+
*
|
|
6
|
+
* sandbox-egress (internal: true, subnet 172.30.0.0/24)
|
|
7
|
+
* ├─ sandbox containers (docker run --dns <coredns-ip>)
|
|
8
|
+
* ├─ coredns-strict 172.30.0.10 → returns nginx-strict IP for allowlist hosts, NXDOMAIN otherwise
|
|
9
|
+
* ├─ coredns-open 172.30.0.11 → returns nginx-open IP for ANY hostname (except hard-deny SSRF magnets)
|
|
10
|
+
* ├─ nginx-egress-strict 172.30.0.20 → ssl_preread, SNI must match allowlist; tunnel upstream via proxy-egress
|
|
11
|
+
* └─ nginx-egress-open 172.30.0.21 → tunnel any SNI; client DNS already gated through coredns-open
|
|
12
|
+
*
|
|
13
|
+
* Why this instead of a forward proxy (tinyproxy/smokescreen): clients
|
|
14
|
+
* inside the sandbox (especially the OpenAI/Anthropic SDKs that build
|
|
15
|
+
* their own undici dispatchers) don't honour HTTP_PROXY / HTTPS_PROXY.
|
|
16
|
+
* Forcing them to cooperate is a losing battle. By spoofing DNS and
|
|
17
|
+
* peeking SNI at the network layer, the sandbox sees no proxy at all —
|
|
18
|
+
* it dials `api.openai.com:443` directly. The firewall intercepts the
|
|
19
|
+
* connection by virtue of being the only thing the spoofed DNS pointed
|
|
20
|
+
* at.
|
|
21
|
+
*
|
|
22
|
+
* Inspired by Vercel Sandbox's egress firewall (SNI peeking, no env
|
|
23
|
+
* vars). Their implementation also handles TLS termination for
|
|
24
|
+
* credentials brokering and Postgres STARTTLS — we don't (yet).
|
|
25
|
+
*
|
|
26
|
+
* ## Wildcards
|
|
27
|
+
*
|
|
28
|
+
* Entries in egress-allowlist.ts with a leading dot (`".github.com"`)
|
|
29
|
+
* match the apex plus every subdomain. nginx's `map` directive supports
|
|
30
|
+
* this syntax natively. CoreDNS uses the `template` plugin with an
|
|
31
|
+
* anchored regex to do the same.
|
|
32
|
+
*/
|
|
33
|
+
/** Fixed IPs assigned in docker-compose.yml so `--dns` and nginx upstreams can reference them. */
|
|
34
|
+
export declare const COREDNS_STRICT_IP = "172.30.0.10";
|
|
35
|
+
export declare const COREDNS_OPEN_IP = "172.30.0.11";
|
|
36
|
+
export declare const NGINX_STRICT_IP = "172.30.0.20";
|
|
37
|
+
export declare const NGINX_OPEN_IP = "172.30.0.21";
|
|
38
|
+
/**
|
|
39
|
+
* Static IP of the in-network OTEL collector (docker backend). Sandboxes
|
|
40
|
+
* dial it directly by IP — it lives on `sandbox-egress` alongside the
|
|
41
|
+
* firewalls, so no DNS lookup (and therefore no coredns allowlist entry)
|
|
42
|
+
* is involved. The collector is the ONLY OTLP endpoint a sandbox ever
|
|
43
|
+
* sees: it terminates the sandbox's telemetry and re-exports to the real
|
|
44
|
+
* backend over `proxy-egress` using credentials that stay host-side. This
|
|
45
|
+
* is why the strict SNI firewall no longer needs to know about collector
|
|
46
|
+
* hosts or non-443 ports — that hop happens on the trusted outbound leg,
|
|
47
|
+
* not through `ssl_preread`.
|
|
48
|
+
*/
|
|
49
|
+
export declare const OTEL_COLLECTOR_IP = "172.30.0.30";
|
|
50
|
+
/** OTLP/HTTP + OTLP/gRPC receiver ports the in-network collector listens on. */
|
|
51
|
+
export declare const OTEL_COLLECTOR_OTLP_HTTP_PORT = 4318;
|
|
52
|
+
export declare const OTEL_COLLECTOR_OTLP_GRPC_PORT = 4317;
|
|
53
|
+
/** Endpoint a docker sandbox is told to export OTLP to (HTTP/protobuf). */
|
|
54
|
+
export declare const OTEL_COLLECTOR_SANDBOX_ENDPOINT = "http://172.30.0.30:4318";
|
|
55
|
+
/**
|
|
56
|
+
* UID the `otel/opentelemetry-collector` image runs as (its Dockerfile
|
|
57
|
+
* `USER`). The collector reads the OTLP config (which can hold backend auth
|
|
58
|
+
* headers) as this non-root user. To let it read a mode-0600 file from the
|
|
59
|
+
* shared volume WITHOUT running as root or making the secret world-readable,
|
|
60
|
+
* the harness's own `lastlight` user is pinned to this same UID (see the
|
|
61
|
+
* Dockerfile `useradd -u`), so the collector reads files it wrote as their
|
|
62
|
+
* owner. The Dockerfile and the collector image tag in docker-compose.yml
|
|
63
|
+
* must move together if a future image bumps the UID — enforced by a test in
|
|
64
|
+
* docker-compose.test.ts.
|
|
65
|
+
*/
|
|
66
|
+
export declare const OTEL_COLLECTOR_UID = 10001;
|
|
67
|
+
/** Subnet for sandbox-egress. Compose declares this CIDR so the IPs above are valid. */
|
|
68
|
+
export declare const SANDBOX_EGRESS_SUBNET = "172.30.0.0/24";
|
|
69
|
+
/** Build the strict nginx.conf — ssl_preread + map on SNI allowlist. */
|
|
70
|
+
export declare function renderNginxStrictConf(): string;
|
|
71
|
+
/** Build the open nginx.conf — no SNI allowlist, just tunnel whatever DNS pointed at. */
|
|
72
|
+
export declare function renderNginxOpenConf(): string;
|
|
73
|
+
/** Build the Corefile that returns the strict nginx IP for allowlist hosts. */
|
|
74
|
+
export declare function renderCorefileStrict(): string;
|
|
75
|
+
/** Build the Corefile that returns the open nginx IP for ANY hostname (except hard-denies). */
|
|
76
|
+
export declare function renderCorefileOpen(): string;
|
|
77
|
+
/**
|
|
78
|
+
* Write the four config files under $STATE_DIR/proxy/. Idempotent.
|
|
79
|
+
* Returns the directory path. Compose bind-mounts this dir into the
|
|
80
|
+
* coredns + nginx containers read-only.
|
|
81
|
+
*/
|
|
82
|
+
export declare function writeEgressFirewallConfigs(stateDir: string): string;
|
|
83
|
+
/**
|
|
84
|
+
* Render the in-network OTEL collector config (docker backend).
|
|
85
|
+
*
|
|
86
|
+
* `opts.active` gates whether the collector forwards anywhere. It MUST track
|
|
87
|
+
* the harness's effective `otel.enabled && otel.forwardToSandbox` — when
|
|
88
|
+
* false, every pipeline is wired to a `debug` exporter (drops data) and NO
|
|
89
|
+
* backend endpoint or credential is emitted, even if `OTEL_EXPORTER_OTLP_*`
|
|
90
|
+
* env vars are present. This is the security floor: the collector listens on
|
|
91
|
+
* a static IP that sandboxes can reach, so if forwarding weren't gated, a
|
|
92
|
+
* sandbox could POST directly to it and exfil to the real backend regardless
|
|
93
|
+
* of the documented `LASTLIGHT_OTEL_ENABLED` / `FORWARD_TO_SANDBOX` opt-outs.
|
|
94
|
+
*
|
|
95
|
+
* When active, the collector re-exports to the REAL backend — the standard
|
|
96
|
+
* `OTEL_EXPORTER_OTLP_ENDPOINT` / `OTEL_EXPORTER_OTLP_HEADERS` plus their
|
|
97
|
+
* per-signal `OTEL_EXPORTER_OTLP_<SIGNAL>_ENDPOINT` / `_HEADERS` overrides,
|
|
98
|
+
* resolved with the spec's precedence. Each signal gets its own exporter so
|
|
99
|
+
* a split traces/metrics/logs setup is routed correctly rather than all
|
|
100
|
+
* collapsing onto whichever endpoint won a fallback chain. Those credentials
|
|
101
|
+
* live here, in a file on the host mounted read-only into the collector, and
|
|
102
|
+
* are NEVER forwarded into an untrusted sandbox. The sandbox can only
|
|
103
|
+
* influence span *content* sent to the harness's own fixed backend — it
|
|
104
|
+
* cannot redirect where the collector exports, so this adds no SSRF/exfil
|
|
105
|
+
* surface.
|
|
106
|
+
*
|
|
107
|
+
* A signal with no configured endpoint (neither specific nor generic) is
|
|
108
|
+
* likewise wired to `debug` so the collector still boots cleanly and accepts
|
|
109
|
+
* connections — sandboxes simply never send what isn't routed.
|
|
110
|
+
*/
|
|
111
|
+
export declare function renderOtelCollectorConfig(opts: {
|
|
112
|
+
active: boolean;
|
|
113
|
+
env?: NodeJS.ProcessEnv;
|
|
114
|
+
}): string;
|
|
115
|
+
/**
|
|
116
|
+
* Write the in-network collector config to $STATE_DIR/proxy/otel-collector.yaml.
|
|
117
|
+
* Mode 0600 — it can contain backend auth headers. Called at harness boot
|
|
118
|
+
* (and by the compose `egress-init` one-shot) so the file exists before the
|
|
119
|
+
* `otel-collector` service reads it. `opts.active` gates forwarding — see
|
|
120
|
+
* `renderOtelCollectorConfig`. The harness passes its parsed
|
|
121
|
+
* `otel.enabled && otel.forwardToSandbox`; the env-only callers compute it
|
|
122
|
+
* via `otelForwardActiveFromEnv`.
|
|
123
|
+
*/
|
|
124
|
+
export declare function writeOtelCollectorConfig(stateDir: string, opts: {
|
|
125
|
+
active: boolean;
|
|
126
|
+
env?: NodeJS.ProcessEnv;
|
|
127
|
+
}): string;
|