Skip to content

Commit 8205cfd

Browse files
Copilotlpcox
andauthored
fix(smoke-services): add GitHub Actions services block and use --allow-host-service-ports (#1729)
* Initial plan * fix(smoke-services): add services block and --allow-host-service-ports * fix(postprocess): correct match count and misleading comment in services regex" Agent-Logs-Url: https://github.com/github/gh-aw-firewall/sessions/66779f5a-5f09-4a5a-ad70-18101d2c76ce Co-authored-by: lpcox <15877973+lpcox@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: lpcox <15877973+lpcox@users.noreply.github.com>
1 parent 5bb5fd9 commit 8205cfd

2 files changed

Lines changed: 127 additions & 2 deletions

File tree

.github/workflows/smoke-services.lock.yml

Lines changed: 24 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

scripts/ci/postprocess-smoke-workflows.ts

Lines changed: 103 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,109 @@ for (const workflowPath of workflowPaths) {
275275
}
276276
}
277277

278-
// Remove unused "Setup Scripts" step from update_cache_memory jobs.
278+
// For smoke-services: inject GitHub Actions services block (Redis + PostgreSQL) into the
279+
// agent job and replace --enable-host-access with --allow-host-service-ports 6379,5432.
280+
// The gh-aw compiler does not natively support GitHub Actions `services:` in the
281+
// frontmatter, so we inject them via post-processing. These services are required for
282+
// the smoke test to connect to Redis and PostgreSQL via host.docker.internal.
283+
const isServicesSmoke = workflowPath.includes('smoke-services.lock.yml');
284+
if (isServicesSmoke) {
285+
// Inject services block after the agent job's "runs-on: ubuntu-latest" line.
286+
// The agent job uses `needs: activation` (single value) to distinguish it from the
287+
// detection job which uses a multi-line `needs:` array.
288+
const agentJobServicesBlock =
289+
' services:\n' +
290+
' redis:\n' +
291+
' image: redis:7-alpine\n' +
292+
' ports:\n' +
293+
' - 6379:6379\n' +
294+
' options: >-\n' +
295+
' --health-cmd "redis-cli ping"\n' +
296+
' --health-interval 10s\n' +
297+
' --health-timeout 5s\n' +
298+
' --health-retries 5\n' +
299+
' postgres:\n' +
300+
' image: postgres:15-alpine\n' +
301+
' env:\n' +
302+
' POSTGRES_USER: postgres\n' +
303+
' POSTGRES_PASSWORD: testpass\n' +
304+
' POSTGRES_DB: smoketest\n' +
305+
' ports:\n' +
306+
' - 5432:5432\n' +
307+
' options: >-\n' +
308+
' --health-cmd pg_isready\n' +
309+
' --health-interval 10s\n' +
310+
' --health-timeout 5s\n' +
311+
' --health-retries 5\n';
312+
313+
// Match the agent job's needs/runs-on block (unique pattern: single-value needs)
314+
// followed immediately by permissions or services. Use flexible whitespace to
315+
// tolerate compiler indentation changes and handle both fresh and already-processed files.
316+
// The agent job has `needs: activation` (single string value); the detection job uses
317+
// a multi-value array (`needs:\n - activation\n - agent`), making this unique.
318+
const agentJobNeedsRunsOnRegex =
319+
/^( {2}agent:\n {4}needs: activation\n {4}runs-on: ubuntu-latest\n)( {4}permissions:)/m;
320+
const agentJobWithServicesRegex =
321+
/^( {2}agent:\n {4}needs: activation\n {4}runs-on: ubuntu-latest\n {4}services:)/m;
322+
323+
if (!agentJobWithServicesRegex.test(content)) {
324+
if (agentJobNeedsRunsOnRegex.test(content)) {
325+
// No services block yet — inject it
326+
content = content.replace(
327+
agentJobNeedsRunsOnRegex,
328+
`$1${agentJobServicesBlock}$2`
329+
);
330+
modified = true;
331+
console.log(` Injected services block (Redis + PostgreSQL) into agent job`);
332+
} else {
333+
console.warn(
334+
` WARNING: Could not find agent job pattern to inject services block. ` +
335+
`The compiled lock file may have changed structure. Manual review required.`
336+
);
337+
}
338+
} else {
339+
console.log(` Services block already present in agent job`);
340+
}
341+
342+
// Replace --enable-host-access with --allow-host-service-ports 6379,5432
343+
// only in the agent job's awf invocation (not the detection job).
344+
// The agent job's command is identifiable by its long --allow-domains list enclosed
345+
// in single quotes (the detection job uses a shorter unquoted domain list). We match
346+
// only within a single line and bound the match with the later --build-local flag to
347+
// avoid cross-line over-matching.
348+
// --allow-domains '...' <other flags> --enable-host-access --build-local
349+
const agentJobEnableHostAccessRegex =
350+
/(--allow-domains '[^']*' [^\n]* )--enable-host-access( --build-local)/;
351+
const agentJobHostServicePortsRegex =
352+
/(--allow-domains '[^']*' [^\n]* )--allow-host-service-ports 6379,5432( --build-local)/;
353+
354+
if (!agentJobHostServicePortsRegex.test(content)) {
355+
if (agentJobEnableHostAccessRegex.test(content)) {
356+
const matchCount = (content.match(new RegExp(agentJobEnableHostAccessRegex.source, 'g')) || []).length;
357+
if (matchCount > 1) {
358+
console.warn(
359+
` WARNING: Found ${matchCount} matches for agent job --enable-host-access pattern. ` +
360+
`Only the first will be replaced. Manual review recommended.`
361+
);
362+
}
363+
content = content.replace(
364+
agentJobEnableHostAccessRegex,
365+
`$1--allow-host-service-ports 6379,5432$2`
366+
);
367+
modified = true;
368+
console.log(` Replaced --enable-host-access with --allow-host-service-ports 6379,5432 in agent job`);
369+
} else {
370+
console.warn(
371+
` WARNING: Could not find --enable-host-access in agent job awf command. ` +
372+
`The compiled lock file may have changed structure. Manual review required.`
373+
);
374+
}
375+
} else {
376+
console.log(` --allow-host-service-ports 6379,5432 already present in agent job`);
377+
}
378+
}
379+
380+
279381
// The step downloads a private action but is never used in these jobs,
280382
// causing 401 Unauthorized failures when permissions: {} is set.
281383
const updateCacheSetupMatches = content.match(updateCacheSetupScriptRegex);

0 commit comments

Comments
 (0)