Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions tests/fixtures/awf-runner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ export interface AwfOptions {
allowHostPorts?: string; // Ports or port ranges to allow for host access (e.g., '3000' or '3000-8000')
allowFullFilesystemAccess?: boolean; // Allow full filesystem access (disables selective mounting security)
enableApiProxy?: boolean; // Enable API proxy sidecar for LLM credential management
envAll?: boolean; // Pass all host environment variables to container (--env-all)
cliEnv?: Record<string, string>; // Explicit -e KEY=VALUE flags passed to AWF CLI
}

export interface AwfResult {
Expand Down Expand Up @@ -110,6 +112,18 @@ export class AwfRunner {
args.push('--enable-api-proxy');
}

// Add --env-all flag
if (options.envAll) {
args.push('--env-all');
}

// Add explicit -e KEY=VALUE flags
if (options.cliEnv) {
for (const [key, value] of Object.entries(options.cliEnv)) {
args.push('-e', `${key}=${value}`);
}
}

// Add -- separator before command
args.push('--');

Expand Down Expand Up @@ -264,6 +278,18 @@ export class AwfRunner {
args.push('--enable-api-proxy');
}

// Add --env-all flag
if (options.envAll) {
args.push('--env-all');
}

// Add explicit -e KEY=VALUE flags
if (options.cliEnv) {
for (const [key, value] of Object.entries(options.cliEnv)) {
args.push('-e', `${key}=${value}`);
}
}

// Add -- separator before command
args.push('--');

Expand Down
121 changes: 121 additions & 0 deletions tests/integration/environment-variables.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -159,4 +159,125 @@ describe('Environment Variable Handling', () => {
expect(result).toSucceed();
expect(result.stdout).toContain('12345');
}, 120000);

describe('--env-all flag', () => {
test('should pass host environment variables into container', async () => {
const result = await runner.runWithSudo(
'echo $AWF_TEST_CUSTOM_VAR',
{
allowDomains: ['github.com'],
logLevel: 'debug',
timeout: 60000,
envAll: true,
env: {
AWF_TEST_CUSTOM_VAR: 'env_all_works',
},
}
);

expect(result).toSucceed();
expect(result.stdout).toContain('env_all_works');
}, 120000);

test('should set proxy environment variables inside container', async () => {
const result = await runner.runWithSudo(
'bash -c "echo HTTP_PROXY=$HTTP_PROXY && echo HTTPS_PROXY=$HTTPS_PROXY"',
{
allowDomains: ['github.com'],
logLevel: 'debug',
timeout: 60000,
envAll: true,
}
);

expect(result).toSucceed();
expect(result.stdout).toMatch(/HTTP_PROXY=http:\/\/172\.30\.0\.10:3128/);
expect(result.stdout).toMatch(/HTTPS_PROXY=http:\/\/172\.30\.0\.10:3128/);
}, 120000);

test('should set JAVA_TOOL_OPTIONS with JVM proxy properties', async () => {
const result = await runner.runWithSudo(
'bash -c "echo $JAVA_TOOL_OPTIONS"',
{
allowDomains: ['github.com'],
logLevel: 'debug',
timeout: 60000,
envAll: true,
}
);

expect(result).toSucceed();
expect(result.stdout).toContain('-Dhttp.proxyHost=');
expect(result.stdout).toContain('-Dhttp.proxyPort=');
expect(result.stdout).toContain('-Dhttps.proxyHost=');
expect(result.stdout).toContain('-Dhttps.proxyPort=');
}, 120000);

test('should work together with explicit -e flags', async () => {
const result = await runner.runWithSudo(
'bash -c "echo HOST_VAR=$AWF_TEST_HOST_VAR && echo CLI_VAR=$AWF_TEST_CLI_VAR"',
{
allowDomains: ['github.com'],
logLevel: 'debug',
timeout: 60000,
envAll: true,
env: {
AWF_TEST_HOST_VAR: 'from_host',
},
cliEnv: {
AWF_TEST_CLI_VAR: 'from_cli_flag',
},
}
);

expect(result).toSucceed();
expect(result.stdout).toContain('HOST_VAR=from_host');
expect(result.stdout).toContain('CLI_VAR=from_cli_flag');
}, 120000);

test('explicit -e should override --env-all for same variable', async () => {
const result = await runner.runWithSudo(
'echo $AWF_TEST_OVERRIDE_VAR',
{
allowDomains: ['github.com'],
logLevel: 'debug',
timeout: 60000,
envAll: true,
env: {
AWF_TEST_OVERRIDE_VAR: 'original_value',
},
cliEnv: {
AWF_TEST_OVERRIDE_VAR: 'overridden_value',
},
}
);

expect(result).toSucceed();
expect(result.stdout).toContain('overridden_value');
expect(result.stdout).not.toContain('original_value');
}, 120000);

test('should exclude system variables like PATH from passthrough', async () => {
const sentinel = '/tmp/awf-sentinel-path-marker';
const result = await runner.runWithSudo(
'echo $PATH',
{
allowDomains: ['github.com'],
logLevel: 'debug',
timeout: 60000,
envAll: true,
env: {
// Prepend sentinel to host PATH so sudo/node still work
PATH: `${sentinel}:${process.env.PATH}`,
},
}
);

expect(result).toSucceed();
// Container PATH should include its own default entries
expect(result.stdout).toContain('/usr/local/bin');
Comment on lines +268 to +278
Copy link

Copilot AI Feb 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PATH passthrough test description says PATH should be excluded from --env-all, but the assertion only checks that $PATH contains /usr/local/bin (which is always true because the container PATH is explicitly set in docker-manager). This test would still pass even if --env-all incorrectly forwarded the host PATH. Consider setting a sentinel PATH in options.env (so it’s present in the host env under sudo) and asserting the container PATH does not contain that sentinel (and/or that AWF_HOST_PATH contains it).

This issue also appears in the following locations of the same file:

  • line 182
  • line 198
  • line 163
Suggested change
envAll: true,
}
);
expect(result).toSucceed();
expect(result.stdout).toContain('/usr/local/bin');
envAll: true,
env: {
// Sentinel value to ensure host PATH is not passed through to the container
PATH: 'SENTINEL_PATH_FOR_ENV_ALL_TEST',
},
}
);
expect(result).toSucceed();
// Container PATH should include its default entries
expect(result.stdout).toContain('/usr/local/bin');
// But it must not contain the host sentinel PATH value
expect(result.stdout).not.toContain('SENTINEL_PATH_FOR_ENV_ALL_TEST');

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. Added a sentinel path marker prepended to the host PATH (so sudo/node still work), then assert the container PATH does NOT contain the sentinel. This proves --env-all correctly excludes PATH from passthrough.

// Host PATH sentinel must NOT leak into the container
expect(result.stdout).not.toContain(sentinel);
}, 120000);
});
});
Loading