|
1 | | -import { generateDockerCompose, subnetsOverlap, writeConfigs, startContainers, stopContainers, fastKillAgentContainer, isAgentExternallyKilled, resetAgentExternallyKilled, AGENT_CONTAINER_NAME, cleanup, runAgentCommand, validateIdNotInSystemRange, getSafeHostUid, getSafeHostGid, getRealUserHome, extractGhHostFromServerUrl, readGitHubPathEntries, mergeGitHubPathEntries, readEnvFile, MIN_REGULAR_UID, ACT_PRESET_BASE_IMAGE, stripScheme, collectDiagnosticLogs, setAwfDockerHost } from './docker-manager'; |
| 1 | +import { generateDockerCompose, subnetsOverlap, writeConfigs, startContainers, stopContainers, fastKillAgentContainer, isAgentExternallyKilled, resetAgentExternallyKilled, AGENT_CONTAINER_NAME, cleanup, runAgentCommand, validateIdNotInSystemRange, getSafeHostUid, getSafeHostGid, getRealUserHome, extractGhHostFromServerUrl, readGitHubPathEntries, mergeGitHubPathEntries, readGitHubEnvEntries, parseGitHubEnvFile, readEnvFile, MIN_REGULAR_UID, ACT_PRESET_BASE_IMAGE, stripScheme, collectDiagnosticLogs, setAwfDockerHost } from './docker-manager'; |
2 | 2 | import { WrapperConfig } from './types'; |
3 | 3 | import * as fs from 'fs'; |
4 | 4 | import * as path from 'path'; |
@@ -4329,6 +4329,185 @@ describe('docker-manager', () => { |
4329 | 4329 | }); |
4330 | 4330 | }); |
4331 | 4331 |
|
| 4332 | + describe('parseGitHubEnvFile', () => { |
| 4333 | + it('should parse simple KEY=VALUE entries', () => { |
| 4334 | + const result = parseGitHubEnvFile('GOROOT=/usr/local/go\nJAVA_HOME=/usr/lib/jvm/java-17\n'); |
| 4335 | + expect(result).toEqual({ |
| 4336 | + GOROOT: '/usr/local/go', |
| 4337 | + JAVA_HOME: '/usr/lib/jvm/java-17', |
| 4338 | + }); |
| 4339 | + }); |
| 4340 | + |
| 4341 | + it('should handle values containing = characters', () => { |
| 4342 | + const result = parseGitHubEnvFile('MY_VAR=key=value=extra\n'); |
| 4343 | + expect(result).toEqual({ MY_VAR: 'key=value=extra' }); |
| 4344 | + }); |
| 4345 | + |
| 4346 | + it('should handle heredoc multiline values', () => { |
| 4347 | + const content = 'MULTI_LINE<<EOF\nline1\nline2\nline3\nEOF\n'; |
| 4348 | + const result = parseGitHubEnvFile(content); |
| 4349 | + expect(result).toEqual({ MULTI_LINE: 'line1\nline2\nline3' }); |
| 4350 | + }); |
| 4351 | + |
| 4352 | + it('should handle CRLF line endings', () => { |
| 4353 | + const result = parseGitHubEnvFile('GOROOT=/usr/local/go\r\nJAVA_HOME=/usr/lib/jvm\r\n'); |
| 4354 | + expect(result).toEqual({ |
| 4355 | + GOROOT: '/usr/local/go', |
| 4356 | + JAVA_HOME: '/usr/lib/jvm', |
| 4357 | + }); |
| 4358 | + }); |
| 4359 | + |
| 4360 | + it('should handle mixed simple and heredoc entries', () => { |
| 4361 | + const content = 'SIMPLE=value\nHEREDOC<<END\nmulti\nline\nEND\nANOTHER=val2\n'; |
| 4362 | + const result = parseGitHubEnvFile(content); |
| 4363 | + expect(result).toEqual({ |
| 4364 | + SIMPLE: 'value', |
| 4365 | + HEREDOC: 'multi\nline', |
| 4366 | + ANOTHER: 'val2', |
| 4367 | + }); |
| 4368 | + }); |
| 4369 | + |
| 4370 | + it('should skip empty lines', () => { |
| 4371 | + const result = parseGitHubEnvFile('\n\nGOROOT=/go\n\n'); |
| 4372 | + expect(result).toEqual({ GOROOT: '/go' }); |
| 4373 | + }); |
| 4374 | + |
| 4375 | + it('should return empty object for empty content', () => { |
| 4376 | + expect(parseGitHubEnvFile('')).toEqual({}); |
| 4377 | + }); |
| 4378 | + |
| 4379 | + it('should handle unterminated heredoc gracefully', () => { |
| 4380 | + const content = 'BROKEN<<EOF\nline1\nline2'; |
| 4381 | + const result = parseGitHubEnvFile(content); |
| 4382 | + expect(result).toEqual({ BROKEN: 'line1\nline2' }); |
| 4383 | + }); |
| 4384 | + }); |
| 4385 | + |
| 4386 | + describe('readGitHubEnvEntries', () => { |
| 4387 | + let tmpDir: string; |
| 4388 | + |
| 4389 | + beforeEach(() => { |
| 4390 | + tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'awf-github-env-')); |
| 4391 | + }); |
| 4392 | + |
| 4393 | + afterEach(() => { |
| 4394 | + fs.rmSync(tmpDir, { recursive: true, force: true }); |
| 4395 | + }); |
| 4396 | + |
| 4397 | + it('should return empty object when GITHUB_ENV is not set', () => { |
| 4398 | + const original = process.env.GITHUB_ENV; |
| 4399 | + delete process.env.GITHUB_ENV; |
| 4400 | + |
| 4401 | + try { |
| 4402 | + const result = readGitHubEnvEntries(); |
| 4403 | + expect(result).toEqual({}); |
| 4404 | + } finally { |
| 4405 | + if (original !== undefined) process.env.GITHUB_ENV = original; |
| 4406 | + else delete process.env.GITHUB_ENV; |
| 4407 | + } |
| 4408 | + }); |
| 4409 | + |
| 4410 | + it('should read entries from GITHUB_ENV file', () => { |
| 4411 | + const original = process.env.GITHUB_ENV; |
| 4412 | + const envFile = path.join(tmpDir, 'github_env'); |
| 4413 | + fs.writeFileSync(envFile, 'GOROOT=/usr/local/go\nCARGO_HOME=/home/.cargo\n'); |
| 4414 | + process.env.GITHUB_ENV = envFile; |
| 4415 | + |
| 4416 | + try { |
| 4417 | + const result = readGitHubEnvEntries(); |
| 4418 | + expect(result.GOROOT).toBe('/usr/local/go'); |
| 4419 | + expect(result.CARGO_HOME).toBe('/home/.cargo'); |
| 4420 | + } finally { |
| 4421 | + if (original !== undefined) process.env.GITHUB_ENV = original; |
| 4422 | + else delete process.env.GITHUB_ENV; |
| 4423 | + } |
| 4424 | + }); |
| 4425 | + |
| 4426 | + it('should return empty object when file does not exist', () => { |
| 4427 | + const original = process.env.GITHUB_ENV; |
| 4428 | + process.env.GITHUB_ENV = '/nonexistent/path/github_env'; |
| 4429 | + |
| 4430 | + try { |
| 4431 | + const result = readGitHubEnvEntries(); |
| 4432 | + expect(result).toEqual({}); |
| 4433 | + } finally { |
| 4434 | + if (original !== undefined) process.env.GITHUB_ENV = original; |
| 4435 | + else delete process.env.GITHUB_ENV; |
| 4436 | + } |
| 4437 | + }); |
| 4438 | + }); |
| 4439 | + |
| 4440 | + describe('toolchain var fallback to GITHUB_ENV', () => { |
| 4441 | + let tmpDir: string; |
| 4442 | + const testConfig: WrapperConfig = { |
| 4443 | + allowedDomains: ['github.com'], |
| 4444 | + agentCommand: 'echo "test"', |
| 4445 | + logLevel: 'info', |
| 4446 | + keepContainers: false, |
| 4447 | + workDir: '/tmp/awf-toolchain-test', |
| 4448 | + buildLocal: false, |
| 4449 | + imageRegistry: 'ghcr.io/github/gh-aw-firewall', |
| 4450 | + imageTag: 'latest', |
| 4451 | + }; |
| 4452 | + const testNetworkConfig = { |
| 4453 | + subnet: '172.30.0.0/24', |
| 4454 | + squidIp: '172.30.0.10', |
| 4455 | + agentIp: '172.30.0.20', |
| 4456 | + }; |
| 4457 | + |
| 4458 | + beforeEach(() => { |
| 4459 | + tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'awf-toolchain-')); |
| 4460 | + fs.mkdirSync(testConfig.workDir, { recursive: true }); |
| 4461 | + }); |
| 4462 | + |
| 4463 | + afterEach(() => { |
| 4464 | + fs.rmSync(tmpDir, { recursive: true, force: true }); |
| 4465 | + fs.rmSync(testConfig.workDir, { recursive: true, force: true }); |
| 4466 | + }); |
| 4467 | + |
| 4468 | + it('should recover AWF_GOROOT from GITHUB_ENV when process.env.GOROOT is absent', () => { |
| 4469 | + const savedGoroot = process.env.GOROOT; |
| 4470 | + const savedGithubEnv = process.env.GITHUB_ENV; |
| 4471 | + delete process.env.GOROOT; |
| 4472 | + |
| 4473 | + const envFile = path.join(tmpDir, 'github_env'); |
| 4474 | + fs.writeFileSync(envFile, 'GOROOT=/opt/hostedtoolcache/go/1.22/x64\n'); |
| 4475 | + process.env.GITHUB_ENV = envFile; |
| 4476 | + |
| 4477 | + try { |
| 4478 | + const result = generateDockerCompose(testConfig, testNetworkConfig); |
| 4479 | + const env = result.services.agent.environment as Record<string, string>; |
| 4480 | + expect(env.AWF_GOROOT).toBe('/opt/hostedtoolcache/go/1.22/x64'); |
| 4481 | + } finally { |
| 4482 | + if (savedGoroot !== undefined) process.env.GOROOT = savedGoroot; |
| 4483 | + else delete process.env.GOROOT; |
| 4484 | + if (savedGithubEnv !== undefined) process.env.GITHUB_ENV = savedGithubEnv; |
| 4485 | + else delete process.env.GITHUB_ENV; |
| 4486 | + } |
| 4487 | + }); |
| 4488 | + |
| 4489 | + it('should prefer process.env over GITHUB_ENV for toolchain vars', () => { |
| 4490 | + const savedGoroot = process.env.GOROOT; |
| 4491 | + const savedGithubEnv = process.env.GITHUB_ENV; |
| 4492 | + process.env.GOROOT = '/usr/local/go-from-env'; |
| 4493 | + |
| 4494 | + const envFile = path.join(tmpDir, 'github_env'); |
| 4495 | + fs.writeFileSync(envFile, 'GOROOT=/opt/go-from-file\n'); |
| 4496 | + process.env.GITHUB_ENV = envFile; |
| 4497 | + |
| 4498 | + try { |
| 4499 | + const result = generateDockerCompose(testConfig, testNetworkConfig); |
| 4500 | + const env = result.services.agent.environment as Record<string, string>; |
| 4501 | + expect(env.AWF_GOROOT).toBe('/usr/local/go-from-env'); |
| 4502 | + } finally { |
| 4503 | + if (savedGoroot !== undefined) process.env.GOROOT = savedGoroot; |
| 4504 | + else delete process.env.GOROOT; |
| 4505 | + if (savedGithubEnv !== undefined) process.env.GITHUB_ENV = savedGithubEnv; |
| 4506 | + else delete process.env.GITHUB_ENV; |
| 4507 | + } |
| 4508 | + }); |
| 4509 | + }); |
| 4510 | + |
4332 | 4511 | describe('mergeGitHubPathEntries', () => { |
4333 | 4512 | it('should return current PATH when no github path entries', () => { |
4334 | 4513 | const result = mergeGitHubPathEntries('/usr/bin:/usr/local/bin', []); |
|
0 commit comments