Skip to content

Commit e3683ab

Browse files
Mossakaclaude
andcommitted
fix: expand credential hiding list for runner tokens and MCP config
Add missing credential files to the /dev/null mount list in both normal and chroot modes: - GitHub Actions runner .credentials and .credentials_rsaparams - GitHub Actions runner cached credentials - MCP config file (.copilot/mcp-config.json) containing auth tokens Also exclude GH_AW_MCP_CONFIG from --env-all passthrough to prevent trivial discovery of the MCP config path. Closes #66, closes #179, closes #182, closes #195, closes #202, closes #208, closes #217, closes #218 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 999a1c8 commit e3683ab

2 files changed

Lines changed: 85 additions & 0 deletions

File tree

src/docker-manager.test.ts

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -509,6 +509,76 @@ describe('docker-manager', () => {
509509
expect(volumes.some((v: string) => v.includes('/dev/null') && v.includes('.docker/config.json'))).toBe(true);
510510
});
511511

512+
it('should hide GitHub Actions runner credentials in normal mode', () => {
513+
const result = generateDockerCompose(mockConfig, mockNetworkConfig);
514+
const agent = result.services.agent;
515+
const volumes = agent.volumes as string[];
516+
const home = process.env.HOME || '/root';
517+
518+
// Runner credential files
519+
expect(volumes).toContain(`/dev/null:${home}/actions-runner/.credentials:ro`);
520+
expect(volumes).toContain(`/dev/null:${home}/actions-runner/.credentials_rsaparams:ro`);
521+
expect(volumes).toContain(`/dev/null:${home}/actions-runner/cached/.credentials:ro`);
522+
expect(volumes).toContain(`/dev/null:${home}/actions-runner/cached/.credentials_rsaparams:ro`);
523+
});
524+
525+
it('should hide MCP config in normal mode', () => {
526+
const result = generateDockerCompose(mockConfig, mockNetworkConfig);
527+
const agent = result.services.agent;
528+
const volumes = agent.volumes as string[];
529+
const home = process.env.HOME || '/root';
530+
531+
expect(volumes).toContain(`/dev/null:${home}/.copilot/mcp-config.json:ro`);
532+
});
533+
534+
it('should hide GitHub Actions runner credentials in chroot mode', () => {
535+
const configWithChroot = {
536+
...mockConfig,
537+
enableChroot: true,
538+
};
539+
const result = generateDockerCompose(configWithChroot, mockNetworkConfig);
540+
const agent = result.services.agent;
541+
const volumes = agent.volumes as string[];
542+
const home = process.env.HOME || '/root';
543+
544+
expect(volumes).toContain(`/dev/null:/host${home}/actions-runner/.credentials:ro`);
545+
expect(volumes).toContain(`/dev/null:/host${home}/actions-runner/.credentials_rsaparams:ro`);
546+
expect(volumes).toContain(`/dev/null:/host${home}/actions-runner/cached/.credentials:ro`);
547+
expect(volumes).toContain(`/dev/null:/host${home}/actions-runner/cached/.credentials_rsaparams:ro`);
548+
});
549+
550+
it('should hide MCP config in chroot mode', () => {
551+
const configWithChroot = {
552+
...mockConfig,
553+
enableChroot: true,
554+
};
555+
const result = generateDockerCompose(configWithChroot, mockNetworkConfig);
556+
const agent = result.services.agent;
557+
const volumes = agent.volumes as string[];
558+
const home = process.env.HOME || '/root';
559+
560+
expect(volumes).toContain(`/dev/null:/host${home}/.copilot/mcp-config.json:ro`);
561+
});
562+
563+
it('should exclude GH_AW_MCP_CONFIG from env-all passthrough', () => {
564+
const originalVal = process.env.GH_AW_MCP_CONFIG;
565+
process.env.GH_AW_MCP_CONFIG = '/home/runner/.copilot/mcp-config.json';
566+
567+
try {
568+
const configWithEnvAll = { ...mockConfig, envAll: true };
569+
const result = generateDockerCompose(configWithEnvAll, mockNetworkConfig);
570+
const env = result.services.agent.environment as Record<string, string>;
571+
572+
expect(env.GH_AW_MCP_CONFIG).toBeUndefined();
573+
} finally {
574+
if (originalVal !== undefined) {
575+
process.env.GH_AW_MCP_CONFIG = originalVal;
576+
} else {
577+
delete process.env.GH_AW_MCP_CONFIG;
578+
}
579+
}
580+
});
581+
512582
it('should use custom volume mounts when specified', () => {
513583
const configWithMounts = {
514584
...mockConfig,

src/docker-manager.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,7 @@ export function generateDockerCompose(
318318
'SUDO_USER', // Sudo metadata
319319
'SUDO_UID', // Sudo metadata
320320
'SUDO_GID', // Sudo metadata
321+
'GH_AW_MCP_CONFIG', // Points to MCP config path containing auth tokens
321322
]);
322323

323324
// Start with required/overridden environment variables
@@ -666,6 +667,13 @@ export function generateDockerCompose(
666667
`${effectiveHome}/.kube/config`,
667668
`${effectiveHome}/.azure/credentials`,
668669
`${effectiveHome}/.config/gcloud/credentials.db`,
670+
// GitHub Actions runner credentials (JWT tokens, RSA keys)
671+
`${effectiveHome}/actions-runner/.credentials`,
672+
`${effectiveHome}/actions-runner/.credentials_rsaparams`,
673+
`${effectiveHome}/actions-runner/cached/.credentials`,
674+
`${effectiveHome}/actions-runner/cached/.credentials_rsaparams`,
675+
// MCP configuration (contains authorization tokens)
676+
`${effectiveHome}/.copilot/mcp-config.json`,
669677
];
670678

671679
credentialFiles.forEach(credFile => {
@@ -697,6 +705,13 @@ export function generateDockerCompose(
697705
`/dev/null:/host${userHome}/.kube/config:ro`,
698706
`/dev/null:/host${userHome}/.azure/credentials:ro`,
699707
`/dev/null:/host${userHome}/.config/gcloud/credentials.db:ro`,
708+
// GitHub Actions runner credentials (JWT tokens, RSA keys)
709+
`/dev/null:/host${userHome}/actions-runner/.credentials:ro`,
710+
`/dev/null:/host${userHome}/actions-runner/.credentials_rsaparams:ro`,
711+
`/dev/null:/host${userHome}/actions-runner/cached/.credentials:ro`,
712+
`/dev/null:/host${userHome}/actions-runner/cached/.credentials_rsaparams:ro`,
713+
// MCP configuration (contains authorization tokens)
714+
`/dev/null:/host${userHome}/.copilot/mcp-config.json:ro`,
700715
];
701716

702717
chrootCredentialFiles.forEach(mount => {

0 commit comments

Comments
 (0)