Skip to content
Closed
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
70 changes: 70 additions & 0 deletions src/docker-manager.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -509,6 +509,76 @@ describe('docker-manager', () => {
expect(volumes.some((v: string) => v.includes('/dev/null') && v.includes('.docker/config.json'))).toBe(true);
});

it('should hide GitHub Actions runner credentials in normal mode', () => {
const result = generateDockerCompose(mockConfig, mockNetworkConfig);
const agent = result.services.agent;
const volumes = agent.volumes as string[];
const home = process.env.HOME || '/root';

// Runner credential files
expect(volumes).toContain(`/dev/null:${home}/actions-runner/.credentials:ro`);
expect(volumes).toContain(`/dev/null:${home}/actions-runner/.credentials_rsaparams:ro`);
expect(volumes).toContain(`/dev/null:${home}/actions-runner/cached/.credentials:ro`);
expect(volumes).toContain(`/dev/null:${home}/actions-runner/cached/.credentials_rsaparams:ro`);
});

it('should hide MCP config in normal mode', () => {
const result = generateDockerCompose(mockConfig, mockNetworkConfig);
const agent = result.services.agent;
const volumes = agent.volumes as string[];
const home = process.env.HOME || '/root';

expect(volumes).toContain(`/dev/null:${home}/.copilot/mcp-config.json:ro`);
});

it('should hide GitHub Actions runner credentials in chroot mode', () => {
const configWithChroot = {
...mockConfig,
enableChroot: true,
};
const result = generateDockerCompose(configWithChroot, mockNetworkConfig);
const agent = result.services.agent;
const volumes = agent.volumes as string[];
const home = process.env.HOME || '/root';

expect(volumes).toContain(`/dev/null:/host${home}/actions-runner/.credentials:ro`);
expect(volumes).toContain(`/dev/null:/host${home}/actions-runner/.credentials_rsaparams:ro`);
expect(volumes).toContain(`/dev/null:/host${home}/actions-runner/cached/.credentials:ro`);
expect(volumes).toContain(`/dev/null:/host${home}/actions-runner/cached/.credentials_rsaparams:ro`);
});

it('should hide MCP config in chroot mode', () => {
const configWithChroot = {
...mockConfig,
enableChroot: true,
};
const result = generateDockerCompose(configWithChroot, mockNetworkConfig);
const agent = result.services.agent;
const volumes = agent.volumes as string[];
const home = process.env.HOME || '/root';

expect(volumes).toContain(`/dev/null:/host${home}/.copilot/mcp-config.json:ro`);
});

it('should exclude GH_AW_MCP_CONFIG from env-all passthrough', () => {
const originalVal = process.env.GH_AW_MCP_CONFIG;
process.env.GH_AW_MCP_CONFIG = '/home/runner/.copilot/mcp-config.json';

try {
const configWithEnvAll = { ...mockConfig, envAll: true };
const result = generateDockerCompose(configWithEnvAll, mockNetworkConfig);
const env = result.services.agent.environment as Record<string, string>;

expect(env.GH_AW_MCP_CONFIG).toBeUndefined();
} finally {
if (originalVal !== undefined) {
process.env.GH_AW_MCP_CONFIG = originalVal;
} else {
delete process.env.GH_AW_MCP_CONFIG;
}
}
});

it('should use custom volume mounts when specified', () => {
const configWithMounts = {
...mockConfig,
Expand Down
15 changes: 15 additions & 0 deletions src/docker-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,7 @@ export function generateDockerCompose(
'SUDO_USER', // Sudo metadata
'SUDO_UID', // Sudo metadata
'SUDO_GID', // Sudo metadata
'GH_AW_MCP_CONFIG', // Points to MCP config path containing auth tokens
]);

// Start with required/overridden environment variables
Expand Down Expand Up @@ -666,6 +667,13 @@ export function generateDockerCompose(
`${effectiveHome}/.kube/config`,
`${effectiveHome}/.azure/credentials`,
`${effectiveHome}/.config/gcloud/credentials.db`,
// GitHub Actions runner credentials (JWT tokens, RSA keys)
`${effectiveHome}/actions-runner/.credentials`,
`${effectiveHome}/actions-runner/.credentials_rsaparams`,
`${effectiveHome}/actions-runner/cached/.credentials`,
`${effectiveHome}/actions-runner/cached/.credentials_rsaparams`,
// MCP configuration (contains authorization tokens)
`${effectiveHome}/.copilot/mcp-config.json`,
Comment on lines +670 to +676
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

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

The PR description claims this change "Closes #66, closes #179, closes #182, closes #195, closes #202, closes #208, closes #217, closes #218", but most of these are unrelated issues/PRs:

These issue references appear to be incorrect. Only issues that specifically report missing credential hiding (like runner tokens or MCP config exposure) should be referenced. Please verify which issues this PR actually resolves and update the description accordingly.

Copilot uses AI. Check for mistakes.
];

credentialFiles.forEach(credFile => {
Expand Down Expand Up @@ -697,6 +705,13 @@ export function generateDockerCompose(
`/dev/null:/host${userHome}/.kube/config:ro`,
`/dev/null:/host${userHome}/.azure/credentials:ro`,
`/dev/null:/host${userHome}/.config/gcloud/credentials.db:ro`,
// GitHub Actions runner credentials (JWT tokens, RSA keys)
`/dev/null:/host${userHome}/actions-runner/.credentials:ro`,
`/dev/null:/host${userHome}/actions-runner/.credentials_rsaparams:ro`,
`/dev/null:/host${userHome}/actions-runner/cached/.credentials:ro`,
`/dev/null:/host${userHome}/actions-runner/cached/.credentials_rsaparams:ro`,
// MCP configuration (contains authorization tokens)
`/dev/null:/host${userHome}/.copilot/mcp-config.json:ro`,
];

chrootCredentialFiles.forEach(mount => {
Expand Down
Loading