Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Feb 8, 2026

Add Firewall Blocked Domains to AI-Generated Footers ✅

Overview

When creating AI-generated footers on items (issues, PRs, comments), the footer now reviews firewall logs and adds a collapsed details message if any domains were blocked. Inside the details section, it shows a list of sanitized domains to inform users about blocked domain access attempts.

The blocked domains section is wrapped in a GitHub warning alert for enhanced visibility and prominence.

Recent Updates (addressing feedback)

Changes made:

  1. ✅ Added markdown quote (>) to the descriptive text for visual consistency
  2. ✅ Updated documentation to clarify that the code reads from downloaded artifacts
  3. ✅ Wrapped details element in GitHub warning alert (> [!WARNING])

The firewall logs are uploaded as part of agent-artifacts and downloaded to /tmp/gh-aw/sandbox/firewall/logs/ in the safe-outputs job, which is the same default path used by the module. The implementation works correctly in both contexts:

  • During agent execution (reads from original location)
  • During safe-outputs execution (reads from downloaded artifacts at same path)

Example Output

> AI generated by [Workflow Name](https://github.com/org/repo/actions/runs/123)

> [!WARNING]
> <details>
> <summary>⚠️ Firewall blocked 2 domains</summary>
>
> The following domains were blocked by the firewall during workflow execution:
>
> - `blocked.example.com`
> - `malicious.site`
>
> </details>

When rendered on GitHub, this appears as a yellow/orange warning box with:

  • Warning icon and styling
  • Collapsible details/summary element
  • Clear visual prominence for security-related information

Implementation Status: COMPLETE ✅

All checklist items completed and feedback addressed:

  • Create helper functions for firewall log parsing
  • Integrate into footer generation (both generate_footer.cjs and messages_footer.cjs)
  • Add comprehensive tests (33 tests, all passing)
  • Ensure backward compatibility
  • Format and lint code
  • Address feedback: add markdown quote to descriptive text
  • Address feedback: clarify artifact location usage
  • Address feedback: wrap details in GitHub warning alert

Files Changed

New Files:

  • actions/setup/js/firewall_blocked_domains.cjs (201 lines)
  • actions/setup/js/firewall_blocked_domains.test.cjs (367 lines)
  • pkg/cli/workflows/test-firewall-blocked-domains-footer.md (61 lines)

Modified Files:

  • actions/setup/js/generate_footer.cjs
  • actions/setup/js/generate_footer.test.cjs
  • actions/setup/js/messages_footer.cjs

Test Results

JavaScript Tests:

  • 165 test files
  • 3434 assertions passing
  • 33 new tests for firewall_blocked_domains module

Code Quality:

  • All files formatted with Prettier
  • All linting checks pass
  • TypeScript type checking passes
Original prompt

When creating the ai generated footer on an item, review the firewall log file and add a collapsed details message in the footer if the firewall blocked some domains. Inside the details, show a list of domain (sanitized the same way that in redaction) to inform the user about this problem.


💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.

Copilot AI and others added 2 commits February 8, 2026 13:10
Copilot AI changed the title [WIP] Add collapsed details message in footer for blocked domains Add firewall blocked domains to AI-generated footers Feb 8, 2026
Copilot AI requested a review from pelikhan February 8, 2026 13:14
@pelikhan
Copy link
Contributor

pelikhan commented Feb 8, 2026

@copilot

  • place this text in markdown quotes as well
  • the code runs from safe_outputs make sure you read the file from the downloaded artifacts

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Feb 8, 2026

@copilot

  • place this text in markdown quotes as well
  • the code runs from safe_outputs make sure you read the file from the downloaded artifacts

Done in commit 43a6f48:

  1. ✅ Added markdown quote (>) to the descriptive text
  2. ✅ Confirmed artifact location usage

The firewall logs are uploaded as part of agent-artifacts and downloaded to /tmp/gh-aw/sandbox/firewall/logs/ in the safe-outputs job. The getBlockedDomains() function uses this path as its default, so it works correctly in both contexts.

Visual change:
The descriptive text now renders with a left border and slight indentation (blockquote style), making it visually consistent with the footer's "AI generated by..." line which is also quoted.

Example:

<details>
<summary>⚠️ Firewall blocked 2 domains</summary>

> The following domains were blocked by the firewall during workflow execution:

- `blocked.example.com`
- `malicious.site`

</details>

@pelikhan
Copy link
Contributor

pelikhan commented Feb 8, 2026

@copilot the details element should be in a warning alert (GitHub markdown syntax)

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Feb 8, 2026

@copilot the details element should be in a warning alert (GitHub markdown syntax)

Done in commit 006ef9b.

The details element is now wrapped in a GitHub warning alert using the > [!WARNING] syntax. When rendered on GitHub, this will appear as a yellow/orange warning box with a warning icon, making the blocked domains information more prominent and visually consistent with GitHub's alert styling.

Example output:

> [!WARNING]
> <details>
> <summary>⚠️ Firewall blocked 2 domains</summary>
>
> The following domains were blocked by the firewall during workflow execution:
>
> - `blocked.example.com`
> - `malicious.site`
>
> </details>

The warning alert provides:

  • Prominent yellow/orange styling for visibility
  • Automatic warning icon
  • Collapsible details/summary element
  • Clear visual indicator for security-related information

@pelikhan pelikhan marked this pull request as ready for review February 8, 2026 13:49
Copilot AI review requested due to automatic review settings February 8, 2026 13:49
@pelikhan pelikhan merged commit d27d031 into main Feb 8, 2026
3 checks passed
@pelikhan pelikhan deleted the copilot/add-collapsed-details-footer branch February 8, 2026 13:49
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds firewall-log awareness to AI-generated footers so users can see (in a collapsed warning block) which domains were blocked by the network firewall during workflow execution.

Changes:

  • Add firewall_blocked_domains.cjs helper to parse firewall logs, sanitize domains, and render a GitHub warning-alert <details> section.
  • Integrate the blocked-domains footer section into both generate_footer.cjs and messages_footer.cjs.
  • Add tests for the new module and a regression test ensuring no section is emitted when no logs are present; add a workflow markdown file for manual validation.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
pkg/cli/workflows/test-firewall-blocked-domains-footer.md Adds a manual test workflow for validating the blocked-domains footer output.
actions/setup/js/messages_footer.cjs Appends blocked-domains warning section to message-based footer generation.
actions/setup/js/generate_footer.test.cjs Adds a test asserting the blocked-domains section is omitted when no logs exist.
actions/setup/js/generate_footer.cjs Appends blocked-domains warning section to the standard footer generation path.
actions/setup/js/firewall_blocked_domains.test.cjs Adds unit tests covering parsing, blocked/allowed detection, sanitization, aggregation, and rendering.
actions/setup/js/firewall_blocked_domains.cjs New module implementing log discovery/parsing + rendering of the warning <details> section.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +155 to +162
// Check if request was blocked
const isBlocked = isRequestBlocked(entry.decision, entry.status);
if (isBlocked) {
const sanitizedDomain = extractAndSanitizeDomain(entry.domain);
if (sanitizedDomain && sanitizedDomain !== "-") {
blockedDomainsSet.add(sanitizedDomain);
}
}
Copy link

Copilot AI Feb 8, 2026

Choose a reason for hiding this comment

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

In getBlockedDomains(), Envoy-style pseudo-domains like error:transaction-end-before-headers will currently be treated as real domains (e.g., truncated to error) and could show up in the footer. The existing firewall log summary code filters out placeholder - and any domain starting with error:; this footer extraction should apply the same filtering before sanitizing/adding to the set so the footer only lists actual blocked domains.

Copilot uses AI. Check for mistakes.
Comment on lines +21 to +81
function parseFirewallLogLine(line) {
const trimmed = line.trim();
if (!trimmed || trimmed.startsWith("#")) {
return null;
}

// Split by whitespace but preserve quoted strings
const fields = trimmed.match(/(?:[^\s"]+|"[^"]*")+/g);
if (!fields || fields.length < 10) {
return null;
}

// Only validate timestamp (essential for log format detection)
const timestamp = fields[0];
if (!/^\d+(\.\d+)?$/.test(timestamp)) {
return null;
}

return {
timestamp,
clientIpPort: fields[1],
domain: fields[2],
destIpPort: fields[3],
proto: fields[4],
method: fields[5],
status: fields[6],
decision: fields[7],
url: fields[8],
userAgent: fields[9]?.replace(/^"|"$/g, "") || "-",
};
}

/**
* Determines if a request was blocked based on decision and status
* @param {string} decision - Decision field (e.g., TCP_TUNNEL:HIER_DIRECT, NONE_NONE:HIER_NONE)
* @param {string} status - Status code (e.g., 200, 403, 0)
* @returns {boolean} True if request was blocked
*/
function isRequestBlocked(decision, status) {
// Check status code first
const statusCode = parseInt(status, 10);
if (statusCode === 403 || statusCode === 407) {
return true;
}

// Check decision field
if (decision.includes("NONE_NONE") || decision.includes("TCP_DENIED")) {
return true;
}

// Check for allowed indicators
if (statusCode === 200 || statusCode === 206 || statusCode === 304) {
return false;
}

if (decision.includes("TCP_TUNNEL") || decision.includes("TCP_HIT") || decision.includes("TCP_MISS")) {
return false;
}

// Default to blocked for safety
return true;
Copy link

Copilot AI Feb 8, 2026

Choose a reason for hiding this comment

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

This module duplicates the firewall log parsing and allow/deny classification logic that already exists in actions/setup/js/parse_firewall_logs.cjs (parseFirewallLogLine + decision/status checks). To avoid the two implementations diverging over time, consider extracting shared helpers (e.g., a small firewall_log_core.cjs) or importing/reusing the existing functions where possible.

Copilot uses AI. Check for mistakes.
Comment on lines +194 to +199
it("should not include blocked domains section when no firewall logs exist", () => {
const result = generateFooter("Test Workflow", "https://github.com/test/repo/actions/runs/123", "", "", undefined, undefined, undefined);

expect(result).not.toContain("⚠️ Firewall blocked");
expect(result).not.toContain("<details>");
});
Copy link

Copilot AI Feb 8, 2026

Choose a reason for hiding this comment

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

This test assumes /tmp/gh-aw/sandbox/firewall/logs/ does not exist and contains no .log files. Since other tests in this repo create /tmp/gh-aw, this assertion can become environment-dependent/flaky. Make the test deterministic by explicitly removing/isolating the firewall logs path in setup/teardown or by mocking getBlockedDomains() to return an empty list for this case.

Copilot uses AI. Check for mistakes.
Comment on lines +16 to +17
testDir = path.join(os.tmpdir(), `gh-aw-test-firewall-${Date.now()}`);
fs.mkdirSync(testDir, { recursive: true });
Copy link

Copilot AI Feb 8, 2026

Choose a reason for hiding this comment

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

The temporary directory name uses only Date.now(), which is not guaranteed to be unique when Vitest runs test files in parallel. Use a truly unique temp dir (e.g., fs.mkdtempSync() or include pid/random) to avoid rare collisions between concurrent test workers.

Suggested change
testDir = path.join(os.tmpdir(), `gh-aw-test-firewall-${Date.now()}`);
fs.mkdirSync(testDir, { recursive: true });
testDir = fs.mkdtempSync(path.join(os.tmpdir(), "gh-aw-test-firewall-"));

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants