terramend 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +661 -0
- package/README.md +145 -0
- package/dist/agents/claude.d.ts +73 -0
- package/dist/agents/claudePretoolGate.d.ts +99 -0
- package/dist/agents/gateServer.d.ts +7 -0
- package/dist/agents/index.d.ts +6 -0
- package/dist/agents/nativeFsDenies.d.ts +28 -0
- package/dist/agents/opencode.d.ts +231 -0
- package/dist/agents/opencodePlugin.d.ts +85 -0
- package/dist/agents/opencodeShared.d.ts +40 -0
- package/dist/agents/postRun.d.ts +132 -0
- package/dist/agents/reviewer.d.ts +38 -0
- package/dist/agents/sessionLabeler.d.ts +97 -0
- package/dist/agents/shared.d.ts +189 -0
- package/dist/agents/subagentModels.d.ts +19 -0
- package/dist/agents/subagentToolGates.d.ts +55 -0
- package/dist/cli.mjs +197426 -0
- package/dist/external.d.ts +227 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +196783 -0
- package/dist/internal/index.d.ts +18 -0
- package/dist/internal.js +1714 -0
- package/dist/lifecycle.d.ts +2 -0
- package/dist/main.d.ts +8 -0
- package/dist/mcp/arkConfig.d.ts +1 -0
- package/dist/mcp/checkSuite.d.ts +25 -0
- package/dist/mcp/checkout.d.ts +77 -0
- package/dist/mcp/comment.d.ts +119 -0
- package/dist/mcp/commitInfo.d.ts +9 -0
- package/dist/mcp/crosswalk.d.ts +105 -0
- package/dist/mcp/dependencies.d.ts +8 -0
- package/dist/mcp/geminiSanitizer.d.ts +28 -0
- package/dist/mcp/git.d.ts +46 -0
- package/dist/mcp/guardrails.d.ts +104 -0
- package/dist/mcp/issue.d.ts +18 -0
- package/dist/mcp/issueComments.d.ts +9 -0
- package/dist/mcp/issueEvents.d.ts +9 -0
- package/dist/mcp/issueInfo.d.ts +9 -0
- package/dist/mcp/labels.d.ts +12 -0
- package/dist/mcp/localContext.d.ts +19 -0
- package/dist/mcp/moduleExtraction.d.ts +71 -0
- package/dist/mcp/moduleTests.d.ts +104 -0
- package/dist/mcp/modules.d.ts +179 -0
- package/dist/mcp/output.d.ts +12 -0
- package/dist/mcp/pathSafety.d.ts +14 -0
- package/dist/mcp/policy.d.ts +48 -0
- package/dist/mcp/pr.d.ts +49 -0
- package/dist/mcp/prInfo.d.ts +9 -0
- package/dist/mcp/providerSchema.d.ts +50 -0
- package/dist/mcp/review.d.ts +199 -0
- package/dist/mcp/reviewComments.d.ts +178 -0
- package/dist/mcp/roots.d.ts +58 -0
- package/dist/mcp/scope.d.ts +15 -0
- package/dist/mcp/selectMode.d.ts +18 -0
- package/dist/mcp/server.d.ts +48 -0
- package/dist/mcp/shared.d.ts +47 -0
- package/dist/mcp/shell.d.ts +37 -0
- package/dist/mcp/staleFix.d.ts +51 -0
- package/dist/mcp/terraform/cost.d.ts +55 -0
- package/dist/mcp/terraform/currency.d.ts +94 -0
- package/dist/mcp/terraform/decisions.d.ts +178 -0
- package/dist/mcp/terraform/findings.d.ts +75 -0
- package/dist/mcp/terraform/plan.d.ts +157 -0
- package/dist/mcp/terraform/scanners.d.ts +131 -0
- package/dist/mcp/terraform/tools.d.ts +63 -0
- package/dist/mcp/terraform/types.d.ts +172 -0
- package/dist/mcp/terraform.d.ts +22 -0
- package/dist/mcp/terratest.d.ts +83 -0
- package/dist/mcp/upload.d.ts +6 -0
- package/dist/models.d.ts +171 -0
- package/dist/modes.d.ts +26 -0
- package/dist/prep/index.d.ts +7 -0
- package/dist/prep/installNodeDependencies.d.ts +2 -0
- package/dist/prep/installPythonDependencies.d.ts +2 -0
- package/dist/prep/types.d.ts +31 -0
- package/dist/reviewQuality.d.ts +64 -0
- package/dist/skills/terraform-best-practices/SKILL.md +369 -0
- package/dist/toolState.d.ts +135 -0
- package/dist/utils/activity.d.ts +40 -0
- package/dist/utils/agent.d.ts +20 -0
- package/dist/utils/agentHangReport.d.ts +38 -0
- package/dist/utils/apiFetch.d.ts +19 -0
- package/dist/utils/apiKeys.d.ts +41 -0
- package/dist/utils/apiUrl.d.ts +20 -0
- package/dist/utils/assets.d.ts +8 -0
- package/dist/utils/billingErrors.d.ts +85 -0
- package/dist/utils/body.d.ts +34 -0
- package/dist/utils/buildTerramendFooter.d.ts +25 -0
- package/dist/utils/byokFallback.d.ts +85 -0
- package/dist/utils/claudeSubscription.d.ts +30 -0
- package/dist/utils/cli.d.ts +10 -0
- package/dist/utils/codexHome.d.ts +29 -0
- package/dist/utils/codexOAuth.d.ts +60 -0
- package/dist/utils/diffCoverage.d.ts +63 -0
- package/dist/utils/errorReport.d.ts +17 -0
- package/dist/utils/exitHandler.d.ts +8 -0
- package/dist/utils/fixDoubleEscapedString.d.ts +1 -0
- package/dist/utils/gitAuth.d.ts +84 -0
- package/dist/utils/gitAuthServer.d.ts +24 -0
- package/dist/utils/github.d.ts +78 -0
- package/dist/utils/globals.d.ts +3 -0
- package/dist/utils/install.d.ts +60 -0
- package/dist/utils/instructions.d.ts +48 -0
- package/dist/utils/leapingComment.d.ts +11 -0
- package/dist/utils/learnings.d.ts +62 -0
- package/dist/utils/learningsTruncate.d.ts +25 -0
- package/dist/utils/lifecycle.d.ts +57 -0
- package/dist/utils/log.d.ts +111 -0
- package/dist/utils/normalizeEnv.d.ts +30 -0
- package/dist/utils/openCodeModels.d.ts +11 -0
- package/dist/utils/overrides.d.ts +40 -0
- package/dist/utils/packageManager.d.ts +49 -0
- package/dist/utils/patchWorkflowRunFields.d.ts +29 -0
- package/dist/utils/payload.d.ts +105 -0
- package/dist/utils/prSummary.d.ts +61 -0
- package/dist/utils/progressComment.d.ts +146 -0
- package/dist/utils/providerErrors.d.ts +31 -0
- package/dist/utils/rangeDiff.d.ts +51 -0
- package/dist/utils/remediationCommand.d.ts +55 -0
- package/dist/utils/retry.d.ts +13 -0
- package/dist/utils/reviewCleanup.d.ts +14 -0
- package/dist/utils/run.d.ts +9 -0
- package/dist/utils/runContext.d.ts +60 -0
- package/dist/utils/runContextData.d.ts +23 -0
- package/dist/utils/runErrorRenderer.d.ts +64 -0
- package/dist/utils/runLifecycle.d.ts +86 -0
- package/dist/utils/runStartupLog.d.ts +15 -0
- package/dist/utils/secrets.d.ts +22 -0
- package/dist/utils/setup.d.ts +90 -0
- package/dist/utils/shell.d.ts +32 -0
- package/dist/utils/skills.d.ts +10 -0
- package/dist/utils/subprocess.d.ts +80 -0
- package/dist/utils/terraformMcp.d.ts +42 -0
- package/dist/utils/time.d.ts +15 -0
- package/dist/utils/timer.d.ts +23 -0
- package/dist/utils/todoTracking.d.ts +16 -0
- package/dist/utils/token.d.ts +39 -0
- package/dist/utils/version.d.ts +2 -0
- package/dist/utils/versioning.d.ts +7 -0
- package/dist/utils/vertex.d.ts +16 -0
- package/dist/utils/workflow.d.ts +13 -0
- package/package.json +119 -0
- package/src/agents/claude.test.ts +1016 -0
- package/src/agents/claude.ts +1246 -0
- package/src/agents/claudePretoolGate.test.ts +28 -0
- package/src/agents/claudePretoolGate.ts +173 -0
- package/src/agents/gateServer.test.ts +204 -0
- package/src/agents/gateServer.ts +124 -0
- package/src/agents/index.ts +10 -0
- package/src/agents/nativeFsDenies.ts +82 -0
- package/src/agents/opencode.test.ts +1440 -0
- package/src/agents/opencode.ts +1312 -0
- package/src/agents/opencodePlugin.ts +222 -0
- package/src/agents/opencodeShared.test.ts +34 -0
- package/src/agents/opencodeShared.ts +121 -0
- package/src/agents/postRun.test.ts +549 -0
- package/src/agents/postRun.ts +535 -0
- package/src/agents/reviewer.ts +104 -0
- package/src/agents/sessionLabeler.test.ts +247 -0
- package/src/agents/sessionLabeler.ts +178 -0
- package/src/agents/shared.test.ts +76 -0
- package/src/agents/shared.ts +292 -0
- package/src/agents/subagentModels.test.ts +113 -0
- package/src/agents/subagentModels.ts +40 -0
- package/src/agents/subagentRegistration.test.ts +41 -0
- package/src/agents/subagentToolGates.ts +114 -0
- package/src/cli.test.ts +129 -0
- package/src/cli.ts +105 -0
- package/src/commands/gha.test.ts +192 -0
- package/src/commands/gha.ts +188 -0
- package/src/commands/mcp.ts +122 -0
- package/src/config.ts +1 -0
- package/src/entry.ts +7 -0
- package/src/entryPost.stdlibOnly.test.ts +109 -0
- package/src/entryPost.ts +99 -0
- package/src/external.test.ts +16 -0
- package/src/external.ts +302 -0
- package/src/index.ts +11 -0
- package/src/internal/index.ts +71 -0
- package/src/lifecycle.ts +2 -0
- package/src/main.test.ts +873 -0
- package/src/main.ts +712 -0
- package/src/mcp/__fixtures__/terramend-scratch-pr-49-review-3485940013.json +110 -0
- package/src/mcp/__fixtures__/terramend-scratch-pr-64-review-3531000326.json +14 -0
- package/src/mcp/__fixtures__/terramend-test-repo-pr-1.diff.json +67 -0
- package/src/mcp/__snapshots__/checkout.test.ts.snap +109 -0
- package/src/mcp/__snapshots__/reviewComments.test.ts.snap +71 -0
- package/src/mcp/arkConfig.ts +7 -0
- package/src/mcp/checkSuite.test.ts +245 -0
- package/src/mcp/checkSuite.ts +255 -0
- package/src/mcp/checkout.test.ts +752 -0
- package/src/mcp/checkout.ts +886 -0
- package/src/mcp/comment.test.ts +772 -0
- package/src/mcp/comment.ts +582 -0
- package/src/mcp/commitInfo.test.ts +127 -0
- package/src/mcp/commitInfo.ts +61 -0
- package/src/mcp/crosswalk.test.ts +106 -0
- package/src/mcp/crosswalk.ts +339 -0
- package/src/mcp/dependencies.test.ts +309 -0
- package/src/mcp/dependencies.ts +189 -0
- package/src/mcp/geminiSanitizer.test.ts +287 -0
- package/src/mcp/geminiSanitizer.ts +207 -0
- package/src/mcp/git.test.ts +1083 -0
- package/src/mcp/git.ts +890 -0
- package/src/mcp/guardrails.test.ts +705 -0
- package/src/mcp/guardrails.ts +465 -0
- package/src/mcp/issue.test.ts +113 -0
- package/src/mcp/issue.ts +73 -0
- package/src/mcp/issueComments.test.ts +69 -0
- package/src/mcp/issueComments.ts +48 -0
- package/src/mcp/issueEvents.test.ts +134 -0
- package/src/mcp/issueEvents.ts +100 -0
- package/src/mcp/issueInfo.test.ts +104 -0
- package/src/mcp/issueInfo.ts +72 -0
- package/src/mcp/labels.test.ts +52 -0
- package/src/mcp/labels.ts +34 -0
- package/src/mcp/localContext.ts +28 -0
- package/src/mcp/localServer.test.ts +75 -0
- package/src/mcp/localServer.ts +131 -0
- package/src/mcp/moduleExtraction.test.ts +261 -0
- package/src/mcp/moduleExtraction.ts +313 -0
- package/src/mcp/moduleTests.test.ts +269 -0
- package/src/mcp/moduleTests.ts +421 -0
- package/src/mcp/modules.test.ts +640 -0
- package/src/mcp/modules.ts +696 -0
- package/src/mcp/output.test.ts +96 -0
- package/src/mcp/output.ts +70 -0
- package/src/mcp/pathSafety.test.ts +44 -0
- package/src/mcp/pathSafety.ts +28 -0
- package/src/mcp/policy.test.ts +282 -0
- package/src/mcp/policy.ts +199 -0
- package/src/mcp/pr.test.ts +387 -0
- package/src/mcp/pr.ts +194 -0
- package/src/mcp/prInfo.test.ts +96 -0
- package/src/mcp/prInfo.ts +91 -0
- package/src/mcp/providerSchema.test.ts +85 -0
- package/src/mcp/providerSchema.ts +175 -0
- package/src/mcp/review.test.ts +936 -0
- package/src/mcp/review.ts +923 -0
- package/src/mcp/reviewComments.test.ts +549 -0
- package/src/mcp/reviewComments.ts +896 -0
- package/src/mcp/roots.test.ts +175 -0
- package/src/mcp/roots.ts +217 -0
- package/src/mcp/scope.test.ts +59 -0
- package/src/mcp/scope.ts +65 -0
- package/src/mcp/security.test.ts +720 -0
- package/src/mcp/selectMode.test.ts +210 -0
- package/src/mcp/selectMode.ts +181 -0
- package/src/mcp/server.test.ts +292 -0
- package/src/mcp/server.ts +403 -0
- package/src/mcp/shared.ts +100 -0
- package/src/mcp/shell.test.ts +520 -0
- package/src/mcp/shell.ts +505 -0
- package/src/mcp/staleFix.test.ts +237 -0
- package/src/mcp/staleFix.ts +277 -0
- package/src/mcp/terraform/cost.ts +163 -0
- package/src/mcp/terraform/currency.test.ts +338 -0
- package/src/mcp/terraform/currency.ts +336 -0
- package/src/mcp/terraform/decisions.ts +527 -0
- package/src/mcp/terraform/findings.ts +333 -0
- package/src/mcp/terraform/plan.ts +348 -0
- package/src/mcp/terraform/scanners.ts +809 -0
- package/src/mcp/terraform/tools.test.ts +1071 -0
- package/src/mcp/terraform/tools.ts +908 -0
- package/src/mcp/terraform/types.ts +305 -0
- package/src/mcp/terraform.test.ts +1957 -0
- package/src/mcp/terraform.ts +23 -0
- package/src/mcp/terratest.test.ts +105 -0
- package/src/mcp/terratest.ts +196 -0
- package/src/mcp/toolFiltering.test.ts +85 -0
- package/src/mcp/upload.test.ts +180 -0
- package/src/mcp/upload.ts +112 -0
- package/src/models.test.ts +300 -0
- package/src/models.ts +708 -0
- package/src/modes.test.ts +107 -0
- package/src/modes.ts +880 -0
- package/src/prep/index.ts +43 -0
- package/src/prep/installNodeDependencies.test.ts +298 -0
- package/src/prep/installNodeDependencies.ts +196 -0
- package/src/prep/installPythonDependencies.test.ts +268 -0
- package/src/prep/installPythonDependencies.ts +199 -0
- package/src/prep/types.ts +38 -0
- package/src/reviewQuality.test.ts +63 -0
- package/src/reviewQuality.ts +134 -0
- package/src/runCli.test.ts +214 -0
- package/src/runCli.ts +282 -0
- package/src/skills/terraform-best-practices/SKILL.md +369 -0
- package/src/toolState.test.ts +45 -0
- package/src/toolState.ts +252 -0
- package/src/utils/activity.test.ts +188 -0
- package/src/utils/activity.ts +210 -0
- package/src/utils/agent.test.ts +251 -0
- package/src/utils/agent.ts +139 -0
- package/src/utils/agentHangReport.test.ts +203 -0
- package/src/utils/agentHangReport.ts +170 -0
- package/src/utils/apiFetch.test.ts +115 -0
- package/src/utils/apiFetch.ts +62 -0
- package/src/utils/apiKeys.test.ts +344 -0
- package/src/utils/apiKeys.ts +206 -0
- package/src/utils/apiUrl.test.ts +30 -0
- package/src/utils/apiUrl.ts +59 -0
- package/src/utils/assets.test.ts +153 -0
- package/src/utils/assets.ts +107 -0
- package/src/utils/billingErrors.test.ts +121 -0
- package/src/utils/billingErrors.ts +189 -0
- package/src/utils/body.test.ts +217 -0
- package/src/utils/body.ts +168 -0
- package/src/utils/buildTerramendFooter.test.ts +38 -0
- package/src/utils/buildTerramendFooter.ts +82 -0
- package/src/utils/byokFallback.test.ts +205 -0
- package/src/utils/byokFallback.ts +128 -0
- package/src/utils/claudeSubscription.test.ts +179 -0
- package/src/utils/claudeSubscription.ts +93 -0
- package/src/utils/cli.ts +31 -0
- package/src/utils/codexHome.test.ts +190 -0
- package/src/utils/codexHome.ts +191 -0
- package/src/utils/codexOAuth.ts +147 -0
- package/src/utils/codexRefreshDetect.test.ts +85 -0
- package/src/utils/codexRefreshDetect.ts +35 -0
- package/src/utils/diffCoverage.test.ts +468 -0
- package/src/utils/diffCoverage.ts +404 -0
- package/src/utils/errorReport.test.ts +135 -0
- package/src/utils/errorReport.ts +83 -0
- package/src/utils/exitHandler.ts +35 -0
- package/src/utils/fixDoubleEscapedString.ts +9 -0
- package/src/utils/ghaCore.ts +13 -0
- package/src/utils/gitAuth.test.ts +322 -0
- package/src/utils/gitAuth.ts +263 -0
- package/src/utils/gitAuthServer.test.ts +260 -0
- package/src/utils/gitAuthServer.ts +182 -0
- package/src/utils/github.test.ts +615 -0
- package/src/utils/github.ts +538 -0
- package/src/utils/globals.ts +9 -0
- package/src/utils/humanEditCapture.test.ts +100 -0
- package/src/utils/humanEditCapture.ts +193 -0
- package/src/utils/install.test.ts +768 -0
- package/src/utils/install.ts +492 -0
- package/src/utils/instructions.test.ts +240 -0
- package/src/utils/instructions.ts +543 -0
- package/src/utils/leapingComment.test.ts +51 -0
- package/src/utils/leapingComment.ts +18 -0
- package/src/utils/learnings.test.ts +87 -0
- package/src/utils/learnings.ts +138 -0
- package/src/utils/learningsTocRender.test.ts +116 -0
- package/src/utils/learningsTruncate.test.ts +39 -0
- package/src/utils/learningsTruncate.ts +42 -0
- package/src/utils/lifecycle.test.ts +195 -0
- package/src/utils/lifecycle.ts +198 -0
- package/src/utils/log.test.ts +402 -0
- package/src/utils/log.ts +432 -0
- package/src/utils/normalizeEnv.test.ts +91 -0
- package/src/utils/normalizeEnv.ts +106 -0
- package/src/utils/openCodeModels.ts +82 -0
- package/src/utils/overrides.test.ts +89 -0
- package/src/utils/overrides.ts +98 -0
- package/src/utils/packageManager.test.ts +321 -0
- package/src/utils/packageManager.ts +257 -0
- package/src/utils/patchWorkflowRunFields.test.ts +92 -0
- package/src/utils/patchWorkflowRunFields.ts +150 -0
- package/src/utils/payload.test.ts +497 -0
- package/src/utils/payload.ts +371 -0
- package/src/utils/postApiFetch.ts +51 -0
- package/src/utils/prSummary.test.ts +224 -0
- package/src/utils/prSummary.ts +147 -0
- package/src/utils/progressComment.ts +261 -0
- package/src/utils/providerErrors.test.ts +315 -0
- package/src/utils/providerErrors.ts +172 -0
- package/src/utils/rangeDiff.test.ts +236 -0
- package/src/utils/rangeDiff.ts +182 -0
- package/src/utils/remediationCommand.test.ts +163 -0
- package/src/utils/remediationCommand.ts +119 -0
- package/src/utils/retry.test.ts +153 -0
- package/src/utils/retry.ts +58 -0
- package/src/utils/reviewCleanup.ts +106 -0
- package/src/utils/run.ts +99 -0
- package/src/utils/runContext.ts +145 -0
- package/src/utils/runContextData.ts +58 -0
- package/src/utils/runErrorRenderer.test.ts +95 -0
- package/src/utils/runErrorRenderer.ts +259 -0
- package/src/utils/runFixture.ts +76 -0
- package/src/utils/runLifecycle.ts +237 -0
- package/src/utils/runStartupLog.ts +60 -0
- package/src/utils/secrets.test.ts +103 -0
- package/src/utils/secrets.ts +177 -0
- package/src/utils/setup.test.ts +509 -0
- package/src/utils/setup.ts +352 -0
- package/src/utils/shell.ts +103 -0
- package/src/utils/skills.test.ts +46 -0
- package/src/utils/skills.ts +67 -0
- package/src/utils/subprocess.test.ts +170 -0
- package/src/utils/subprocess.ts +438 -0
- package/src/utils/terraformMcp.test.ts +63 -0
- package/src/utils/terraformMcp.ts +83 -0
- package/src/utils/time.test.ts +105 -0
- package/src/utils/time.ts +59 -0
- package/src/utils/timer.test.ts +91 -0
- package/src/utils/timer.ts +72 -0
- package/src/utils/todoTracking.test.ts +223 -0
- package/src/utils/todoTracking.ts +167 -0
- package/src/utils/token.test.ts +239 -0
- package/src/utils/token.ts +186 -0
- package/src/utils/version.ts +10 -0
- package/src/utils/versioning.test.ts +34 -0
- package/src/utils/versioning.ts +44 -0
- package/src/utils/vertex.ts +85 -0
- package/src/utils/workflow.ts +25 -0
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Startup log formatting for the resolver pipeline. Computes the
|
|
3
|
+
* "model / agent / push / shell / timeout" block that main.ts prints
|
|
4
|
+
* after resolving the agent + model + payload.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { log } from "#app/utils/cli";
|
|
8
|
+
import type { ResolvedPayload } from "#app/utils/payload";
|
|
9
|
+
import { TIMEOUT_DISABLED } from "#app/utils/time";
|
|
10
|
+
|
|
11
|
+
function resolveTimeoutForLog(timeout: string | undefined): string {
|
|
12
|
+
if (!timeout) return "1h (default)";
|
|
13
|
+
if (timeout === TIMEOUT_DISABLED) return "none (disabled)";
|
|
14
|
+
return timeout;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function resolveModelForLog(ctx: {
|
|
18
|
+
payload: ResolvedPayload;
|
|
19
|
+
resolvedModel: string | undefined;
|
|
20
|
+
}): string {
|
|
21
|
+
const envModel = process.env.TERRAMEND_MODEL?.trim();
|
|
22
|
+
if (envModel) return `${envModel} (override via TERRAMEND_MODEL)`;
|
|
23
|
+
if (ctx.resolvedModel && ctx.payload.model && ctx.payload.model !== ctx.resolvedModel) {
|
|
24
|
+
return `${ctx.resolvedModel} (resolved from ${ctx.payload.model})`;
|
|
25
|
+
}
|
|
26
|
+
if (ctx.resolvedModel) return ctx.resolvedModel;
|
|
27
|
+
if (ctx.payload.model) return `${ctx.payload.model} (unresolved)`;
|
|
28
|
+
return "auto";
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function resolveAgentForLog(ctx: { agentName: string; resolvedModel: string | undefined }): string {
|
|
32
|
+
const envAgent = process.env.TERRAMEND_AGENT?.trim();
|
|
33
|
+
if (envAgent && envAgent === ctx.agentName) {
|
|
34
|
+
return `${ctx.agentName} (override via TERRAMEND_AGENT)`;
|
|
35
|
+
}
|
|
36
|
+
if (ctx.agentName === "claude" && ctx.resolvedModel) {
|
|
37
|
+
return `${ctx.agentName} (auto-selected for ${ctx.resolvedModel})`;
|
|
38
|
+
}
|
|
39
|
+
return ctx.agentName;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Emit the startup block ("» model / agent / push / shell / timeout") after
|
|
44
|
+
* the agent and model are resolved. Single side-effect; no return.
|
|
45
|
+
*/
|
|
46
|
+
export function logRunStartup(ctx: {
|
|
47
|
+
payload: ResolvedPayload;
|
|
48
|
+
resolvedModel: string | undefined;
|
|
49
|
+
agentName: string;
|
|
50
|
+
}): void {
|
|
51
|
+
log.info(
|
|
52
|
+
`» model: ${resolveModelForLog({ payload: ctx.payload, resolvedModel: ctx.resolvedModel })}`,
|
|
53
|
+
);
|
|
54
|
+
log.info(
|
|
55
|
+
`» agent: ${resolveAgentForLog({ agentName: ctx.agentName, resolvedModel: ctx.resolvedModel })}`,
|
|
56
|
+
);
|
|
57
|
+
log.info(`» push: ${ctx.payload.push}`);
|
|
58
|
+
log.info(`» shell: ${ctx.payload.shell}`);
|
|
59
|
+
log.info(`» timeout: ${resolveTimeoutForLog(ctx.payload.timeout)}`);
|
|
60
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { afterEach, describe, expect, it } from "vitest";
|
|
2
|
+
import { filterEnv, isSensitiveEnvName, resolveEnv, setEnvAllowlist } from "#app/utils/secrets";
|
|
3
|
+
|
|
4
|
+
// keys this suite injects into process.env — cleaned up after each test so we
|
|
5
|
+
// don't leak state into other tests sharing the worker.
|
|
6
|
+
const INJECTED = [
|
|
7
|
+
"GITHUB_WORKSPACE",
|
|
8
|
+
"GITHUB_REPOSITORY",
|
|
9
|
+
"GITHUB_TOKEN",
|
|
10
|
+
"GITHUB_FUTURE_UNKNOWN_VAR",
|
|
11
|
+
"RUNNER_TEMP",
|
|
12
|
+
"ANTHROPIC_API_KEY",
|
|
13
|
+
"MY_CUSTOM_VALUE",
|
|
14
|
+
];
|
|
15
|
+
|
|
16
|
+
afterEach(() => {
|
|
17
|
+
for (const k of INJECTED) delete process.env[k];
|
|
18
|
+
// reset any user allowlist set during a test
|
|
19
|
+
setEnvAllowlist("");
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
describe("isSensitiveEnvName", () => {
|
|
23
|
+
it("flags _KEY/_SECRET/_TOKEN/_PASSWORD/_CREDENTIAL suffixes", () => {
|
|
24
|
+
expect(isSensitiveEnvName("ANTHROPIC_API_KEY")).toBe(true);
|
|
25
|
+
expect(isSensitiveEnvName("GITHUB_TOKEN")).toBe(true);
|
|
26
|
+
expect(isSensitiveEnvName("VERCEL_AUTOMATION_BYPASS_SECRET")).toBe(true);
|
|
27
|
+
expect(isSensitiveEnvName("GITHUB_WORKSPACE")).toBe(false);
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
describe("filterEnv GITHUB_* exact allowlist (fail-closed)", () => {
|
|
32
|
+
it("passes through known runner context vars", () => {
|
|
33
|
+
process.env.GITHUB_WORKSPACE = "/work";
|
|
34
|
+
process.env.GITHUB_REPOSITORY = "terramend/terramend";
|
|
35
|
+
process.env.RUNNER_TEMP = "/tmp/runner";
|
|
36
|
+
const env = filterEnv();
|
|
37
|
+
expect(env.GITHUB_WORKSPACE).toBe("/work");
|
|
38
|
+
expect(env.GITHUB_REPOSITORY).toBe("terramend/terramend");
|
|
39
|
+
expect(env.RUNNER_TEMP).toBe("/tmp/runner");
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it("drops an unknown GITHUB_* var that is not in the exact allowlist", () => {
|
|
43
|
+
process.env.GITHUB_FUTURE_UNKNOWN_VAR = "leak-me";
|
|
44
|
+
expect(filterEnv().GITHUB_FUTURE_UNKNOWN_VAR).toBeUndefined();
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it("drops GITHUB_TOKEN even though it shares the GITHUB_ prefix", () => {
|
|
48
|
+
process.env.GITHUB_TOKEN = "ghs_secret";
|
|
49
|
+
expect(filterEnv().GITHUB_TOKEN).toBeUndefined();
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it("drops obviously sensitive vars", () => {
|
|
53
|
+
process.env.ANTHROPIC_API_KEY = "sk-ant-xxx";
|
|
54
|
+
expect(filterEnv().ANTHROPIC_API_KEY).toBeUndefined();
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it("drops arbitrary non-allowlisted vars by default", () => {
|
|
58
|
+
process.env.MY_CUSTOM_VALUE = "x";
|
|
59
|
+
expect(filterEnv().MY_CUSTOM_VALUE).toBeUndefined();
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it("honors an explicit user allowlist opt-in", () => {
|
|
63
|
+
process.env.MY_CUSTOM_VALUE = "x";
|
|
64
|
+
process.env.GITHUB_FUTURE_UNKNOWN_VAR = "y";
|
|
65
|
+
setEnvAllowlist("MY_CUSTOM_VALUE\nGITHUB_FUTURE_UNKNOWN_VAR");
|
|
66
|
+
const env = filterEnv();
|
|
67
|
+
expect(env.MY_CUSTOM_VALUE).toBe("x");
|
|
68
|
+
expect(env.GITHUB_FUTURE_UNKNOWN_VAR).toBe("y");
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it("lets the user allowlist opt a sensitive-named var back in", () => {
|
|
72
|
+
process.env.ANTHROPIC_API_KEY = "sk-ant-xxx";
|
|
73
|
+
setEnvAllowlist("ANTHROPIC_API_KEY");
|
|
74
|
+
expect(filterEnv().ANTHROPIC_API_KEY).toBe("sk-ant-xxx");
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it("passes through safe prefixes (RUNNER_*, JAVA_HOME_*)", () => {
|
|
78
|
+
process.env.RUNNER_TEMP = "/tmp/runner";
|
|
79
|
+
const env = filterEnv();
|
|
80
|
+
expect(env.RUNNER_TEMP).toBe("/tmp/runner");
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
describe("resolveEnv", () => {
|
|
85
|
+
it("returns the full process env for 'inherit'", () => {
|
|
86
|
+
expect(resolveEnv("inherit")).toBe(process.env);
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it("filters for 'restricted' and for the undefined default", () => {
|
|
90
|
+
process.env.ANTHROPIC_API_KEY = "sk-ant-xxx";
|
|
91
|
+
expect(resolveEnv("restricted").ANTHROPIC_API_KEY).toBeUndefined();
|
|
92
|
+
expect(resolveEnv(undefined).ANTHROPIC_API_KEY).toBeUndefined();
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it("merges a custom env object over the restricted base", () => {
|
|
96
|
+
process.env.ANTHROPIC_API_KEY = "sk-ant-xxx";
|
|
97
|
+
process.env.GITHUB_WORKSPACE = "/work";
|
|
98
|
+
const env = resolveEnv({ EXTRA_VAR: "1" });
|
|
99
|
+
expect(env.EXTRA_VAR).toBe("1");
|
|
100
|
+
expect(env.GITHUB_WORKSPACE).toBe("/work"); // restricted base survives
|
|
101
|
+
expect(env.ANTHROPIC_API_KEY).toBeUndefined(); // secrets still filtered
|
|
102
|
+
});
|
|
103
|
+
});
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Secret detection and env filtering utilities
|
|
3
|
+
*
|
|
4
|
+
* subprocess env filtering: default-deny allowlist model.
|
|
5
|
+
* only vars in the safe set or user allowlist are passed to child processes.
|
|
6
|
+
*
|
|
7
|
+
* log redaction: SENSITIVE_PATTERNS are used to identify secret values
|
|
8
|
+
* for redaction in logs and GHA masking (independent of subprocess filtering).
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
// --- log redaction (unchanged, independent of subprocess filtering) ---
|
|
12
|
+
|
|
13
|
+
// patterns for sensitive env var names (used by normalizeEnv)
|
|
14
|
+
export const SENSITIVE_PATTERNS = [
|
|
15
|
+
/_KEY$/i,
|
|
16
|
+
/_SECRET$/i,
|
|
17
|
+
/_TOKEN$/i,
|
|
18
|
+
/_PASSWORD$/i,
|
|
19
|
+
/_CREDENTIAL$/i,
|
|
20
|
+
];
|
|
21
|
+
|
|
22
|
+
export function isSensitiveEnvName(key: string): boolean {
|
|
23
|
+
return SENSITIVE_PATTERNS.some((p) => p.test(key));
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// --- subprocess env filtering ---
|
|
27
|
+
|
|
28
|
+
// prefixes whose vars are safe to pass through (runner metadata, toolchain).
|
|
29
|
+
const SAFE_ENV_PREFIXES = ["RUNNER_", "JAVA_HOME_", "GOROOT_"];
|
|
30
|
+
|
|
31
|
+
// GITHUB_* is an EXACT allowlist rather than a prefix: the set of context vars
|
|
32
|
+
// the runner injects is well-known and closed, so listing them explicitly fails
|
|
33
|
+
// closed on any unknown/future GITHUB_* var (e.g. a sensitive one that doesn't
|
|
34
|
+
// end in _TOKEN/_KEY/_SECRET and would otherwise slip through the prefix).
|
|
35
|
+
// GITHUB_TOKEN/GH_TOKEN are intentionally absent; isSensitiveEnvName() also
|
|
36
|
+
// catches them via the _TOKEN suffix. Users can opt any var in via the allowlist.
|
|
37
|
+
const SAFE_GITHUB_ENV_NAMES = new Set([
|
|
38
|
+
"GITHUB_ACTION",
|
|
39
|
+
"GITHUB_ACTION_PATH",
|
|
40
|
+
"GITHUB_ACTION_REPOSITORY",
|
|
41
|
+
"GITHUB_ACTIONS",
|
|
42
|
+
"GITHUB_ACTOR",
|
|
43
|
+
"GITHUB_ACTOR_ID",
|
|
44
|
+
"GITHUB_API_URL",
|
|
45
|
+
"GITHUB_BASE_REF",
|
|
46
|
+
"GITHUB_ENV",
|
|
47
|
+
"GITHUB_EVENT_NAME",
|
|
48
|
+
"GITHUB_EVENT_PATH",
|
|
49
|
+
"GITHUB_GRAPHQL_URL",
|
|
50
|
+
"GITHUB_HEAD_REF",
|
|
51
|
+
"GITHUB_JOB",
|
|
52
|
+
"GITHUB_OUTPUT",
|
|
53
|
+
"GITHUB_PATH",
|
|
54
|
+
"GITHUB_REF",
|
|
55
|
+
"GITHUB_REF_NAME",
|
|
56
|
+
"GITHUB_REF_PROTECTED",
|
|
57
|
+
"GITHUB_REF_TYPE",
|
|
58
|
+
"GITHUB_REPOSITORY",
|
|
59
|
+
"GITHUB_REPOSITORY_ID",
|
|
60
|
+
"GITHUB_REPOSITORY_OWNER",
|
|
61
|
+
"GITHUB_REPOSITORY_OWNER_ID",
|
|
62
|
+
"GITHUB_RETENTION_DAYS",
|
|
63
|
+
"GITHUB_RUN_ATTEMPT",
|
|
64
|
+
"GITHUB_RUN_ID",
|
|
65
|
+
"GITHUB_RUN_NUMBER",
|
|
66
|
+
"GITHUB_SERVER_URL",
|
|
67
|
+
"GITHUB_SHA",
|
|
68
|
+
"GITHUB_STEP_SUMMARY",
|
|
69
|
+
"GITHUB_TRIGGERING_ACTOR",
|
|
70
|
+
"GITHUB_WORKFLOW",
|
|
71
|
+
"GITHUB_WORKFLOW_REF",
|
|
72
|
+
"GITHUB_WORKFLOW_SHA",
|
|
73
|
+
"GITHUB_WORKSPACE",
|
|
74
|
+
]);
|
|
75
|
+
|
|
76
|
+
// exact var names safe to pass through (system + runner image toolchain)
|
|
77
|
+
const SAFE_ENV_NAMES = new Set([
|
|
78
|
+
// system
|
|
79
|
+
"CI",
|
|
80
|
+
"HOME",
|
|
81
|
+
"LANG",
|
|
82
|
+
"LOGNAME",
|
|
83
|
+
"PATH",
|
|
84
|
+
"SHELL",
|
|
85
|
+
"SHLVL",
|
|
86
|
+
"TERM",
|
|
87
|
+
"TMPDIR",
|
|
88
|
+
"TZ",
|
|
89
|
+
"USER",
|
|
90
|
+
"XDG_CONFIG_HOME",
|
|
91
|
+
"XDG_RUNTIME_DIR",
|
|
92
|
+
"DEBIAN_FRONTEND",
|
|
93
|
+
// runner image toolchain
|
|
94
|
+
"ACCEPT_EULA",
|
|
95
|
+
"AGENT_TOOLSDIRECTORY",
|
|
96
|
+
"ANDROID_HOME",
|
|
97
|
+
"ANDROID_NDK",
|
|
98
|
+
"ANDROID_NDK_HOME",
|
|
99
|
+
"ANDROID_NDK_LATEST_HOME",
|
|
100
|
+
"ANDROID_NDK_ROOT",
|
|
101
|
+
"ANDROID_SDK_ROOT",
|
|
102
|
+
"ANT_HOME",
|
|
103
|
+
"AZURE_EXTENSION_DIR",
|
|
104
|
+
"BOOTSTRAP_HASKELL_NONINTERACTIVE",
|
|
105
|
+
"CHROME_BIN",
|
|
106
|
+
"CHROMEWEBDRIVER",
|
|
107
|
+
"CONDA",
|
|
108
|
+
"DOTNET_MULTILEVEL_LOOKUP",
|
|
109
|
+
"DOTNET_NOLOGO",
|
|
110
|
+
"DOTNET_SKIP_FIRST_TIME_EXPERIENCE",
|
|
111
|
+
"EDGEWEBDRIVER",
|
|
112
|
+
"GECKOWEBDRIVER",
|
|
113
|
+
"GHCUP_INSTALL_BASE_PREFIX",
|
|
114
|
+
"GRADLE_HOME",
|
|
115
|
+
"JAVA_HOME",
|
|
116
|
+
"HOMEBREW_CLEANUP_PERIODIC_FULL_DAYS",
|
|
117
|
+
"HOMEBREW_NO_AUTO_UPDATE",
|
|
118
|
+
"ImageOS",
|
|
119
|
+
"ImageVersion",
|
|
120
|
+
"NVM_DIR",
|
|
121
|
+
"PIPX_BIN_DIR",
|
|
122
|
+
"PIPX_HOME",
|
|
123
|
+
"PSModulePath",
|
|
124
|
+
"SELENIUM_JAR_PATH",
|
|
125
|
+
"SGX_AESM_ADDR",
|
|
126
|
+
"SWIFT_PATH",
|
|
127
|
+
"VCPKG_INSTALLATION_ROOT",
|
|
128
|
+
]);
|
|
129
|
+
|
|
130
|
+
let _userAllowlist: Set<string> | null = null;
|
|
131
|
+
|
|
132
|
+
export function setEnvAllowlist(raw: string): void {
|
|
133
|
+
const names = raw
|
|
134
|
+
.split("\n")
|
|
135
|
+
.map((line) => line.trim())
|
|
136
|
+
.filter(Boolean);
|
|
137
|
+
_userAllowlist = new Set(names);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function isSafeEnvVar(key: string): boolean {
|
|
141
|
+
if (SAFE_ENV_NAMES.has(key)) return true;
|
|
142
|
+
if (SAFE_GITHUB_ENV_NAMES.has(key)) return true;
|
|
143
|
+
return SAFE_ENV_PREFIXES.some((p) => key.startsWith(p));
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/** filter env vars using default-deny allowlist: safe set + user allowlist */
|
|
147
|
+
export function filterEnv(): Record<string, string> {
|
|
148
|
+
const filtered: Record<string, string> = {};
|
|
149
|
+
for (const [key, value] of Object.entries(process.env)) {
|
|
150
|
+
if (value === undefined) continue;
|
|
151
|
+
const userAllowed = _userAllowlist?.has(key) ?? false;
|
|
152
|
+
if (isSensitiveEnvName(key) && !userAllowed) continue;
|
|
153
|
+
if (isSafeEnvVar(key) || userAllowed) {
|
|
154
|
+
filtered[key] = value;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
return filtered;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
export type EnvMode = "restricted" | "inherit" | Record<string, string>;
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* resolve env mode to actual env object
|
|
164
|
+
* - "restricted" (default): filterEnv() — only safe set + user allowlist
|
|
165
|
+
* - "inherit": full process.env
|
|
166
|
+
* - object: custom env merged with restricted base
|
|
167
|
+
*/
|
|
168
|
+
export function resolveEnv(mode: EnvMode | undefined): Record<string, string | undefined> {
|
|
169
|
+
if (mode === "inherit") {
|
|
170
|
+
return process.env;
|
|
171
|
+
}
|
|
172
|
+
if (mode === "restricted" || mode === undefined) {
|
|
173
|
+
return filterEnv();
|
|
174
|
+
}
|
|
175
|
+
// custom env object - merge with restricted base
|
|
176
|
+
return { ...filterEnv(), ...mode };
|
|
177
|
+
}
|