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
9 changes: 2 additions & 7 deletions .github/workflows/security-alert-burndown.campaign.g.lock.yml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

57 changes: 52 additions & 5 deletions .github/workflows/security-alert-burndown.campaign.g.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,58 @@ steps:
with:
github-token: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
script: |

const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs');
setupGlobals(core, github, context, exec, io);
const { main } = require('/opt/gh-aw/actions/campaign_discovery.cjs');
await main();
const fs = require("fs");
const path = require("path");

const campaignId = process.env.GH_AW_CAMPAIGN_ID;
const trackerLabel = process.env.GH_AW_TRACKER_LABEL;
const discoveryRepos = process.env.GH_AW_DISCOVERY_REPOS;
const cursorPath = process.env.GH_AW_CURSOR_PATH;
const maxItems = parseInt(process.env.GH_AW_MAX_DISCOVERY_ITEMS ?? "50", 10);
Comment on lines +63 to +67
Copy link

Copilot AI Mar 8, 2026

Choose a reason for hiding this comment

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

cursorPath is read from GH_AW_CURSOR_PATH but never used, and the discovery step does a full rescan every run. This conflicts with the workflow’s own instructions to use a durable cursor/checkpoint to avoid rescanning and to update the cursor file each run. Please either implement read/write of the cursor at cursorPath (e.g., boundary on updated_at + tie-breaker) or remove the cursor env var and the incremental-discovery requirements if they’re no longer applicable.

Copilot uses AI. Check for mistakes.
const maxPages = parseInt(process.env.GH_AW_MAX_DISCOVERY_PAGES ?? "3", 10);
const projectUrl = process.env.GH_AW_PROJECT_URL;
const workflows = (process.env.GH_AW_WORKFLOWS ?? "").split(",").map(w => w.trim()).filter(Boolean);

if (!campaignId || !trackerLabel || !discoveryRepos) {
core.setFailed("Missing required environment variables: GH_AW_CAMPAIGN_ID, GH_AW_TRACKER_LABEL, GH_AW_DISCOVERY_REPOS");
return;
}

const repos = discoveryRepos.split(",").map(r => r.trim()).filter(Boolean);
const allItems = [];

for (const repoPath of repos) {
const parts = repoPath.split("/");
if (parts.length !== 2) { core.warning(`Invalid repo format: "${repoPath}" — skipping`); continue; }
const [owner, repo] = parts;
let page = 1;
while (page <= maxPages && allItems.length < maxItems) {
const perPage = Math.min(30, maxItems - allItems.length);
try {
const response = await github.rest.issues.listForRepo({ owner, repo, labels: trackerLabel, state: "all", sort: "updated", direction: "desc", per_page: perPage, page });
Comment on lines +79 to +88
Copy link

Copilot AI Mar 8, 2026

Choose a reason for hiding this comment

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

GH_AW_MAX_DISCOVERY_PAGES is enforced per-repo (while (page <= maxPages) inside the repo loop). If GH_AW_DISCOVERY_REPOS contains multiple repos, the step can exceed the intended per-run page budget (e.g., 3 pages * N repos). Consider tracking a global page counter across all repos (or rename the variable / document that the budget is per-repo) to ensure the configured pagination budget is actually respected.

Suggested change
for (const repoPath of repos) {
const parts = repoPath.split("/");
if (parts.length !== 2) { core.warning(`Invalid repo format: "${repoPath}" — skipping`); continue; }
const [owner, repo] = parts;
let page = 1;
while (page <= maxPages && allItems.length < maxItems) {
const perPage = Math.min(30, maxItems - allItems.length);
try {
const response = await github.rest.issues.listForRepo({ owner, repo, labels: trackerLabel, state: "all", sort: "updated", direction: "desc", per_page: perPage, page });
let pagesUsed = 0;
for (const repoPath of repos) {
const parts = repoPath.split("/");
if (parts.length !== 2) { core.warning(`Invalid repo format: "${repoPath}" — skipping`); continue; }
const [owner, repo] = parts;
let page = 1;
while (allItems.length < maxItems && pagesUsed < maxPages) {
const perPage = Math.min(30, maxItems - allItems.length);
try {
const response = await github.rest.issues.listForRepo({ owner, repo, labels: trackerLabel, state: "all", sort: "updated", direction: "desc", per_page: perPage, page });
pagesUsed++;

Copilot uses AI. Check for mistakes.
if (response.data.length === 0) break;
for (const item of response.data) {
if (allItems.length >= maxItems) break;
allItems.push({ id: item.id, number: item.number, title: item.title, state: item.state, html_url: item.html_url, created_at: item.created_at, updated_at: item.updated_at, labels: item.labels.map(l => typeof l === "string" ? l : (l.name ?? "")), repo: `${owner}/${repo}`, is_pr: !!item.pull_request });
}
if (response.data.length < perPage) break;
page++;
} catch (err) { core.error(`Failed to search ${owner}/${repo} page ${page}: ${err.message}`); break; }
}
}

const GH_AW_TMP_DIR = "/tmp/gh-aw";
const discoveryOutputPath = path.join(GH_AW_TMP_DIR, "campaign-discovery.json");
const discoveryData = { campaign_id: campaignId, timestamp: new Date().toISOString(), tracker_label: trackerLabel, project_url: projectUrl, workflows, items_count: allItems.length, items: allItems };
try {
fs.mkdirSync(GH_AW_TMP_DIR, { recursive: true });
fs.writeFileSync(discoveryOutputPath, JSON.stringify(discoveryData, null, 2));
} catch (err) { core.warning(`Failed to write discovery data: ${err.message}`); }
Copy link

Copilot AI Mar 8, 2026

Choose a reason for hiding this comment

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

If writing campaign-discovery.json fails, the step only logs a warning but still sets discovery_file to the (potentially non-existent) path and continues as success. Since downstream logic expects this file to exist, this should fail the step (e.g., core.setFailed(...) / rethrow) when the directory creation or write fails, or otherwise guarantee the file exists before setting outputs.

Suggested change
} catch (err) { core.warning(`Failed to write discovery data: ${err.message}`); }
} catch (err) {
core.setFailed(`Failed to write discovery data: ${err.message}`);
return;
}

Copilot uses AI. Check for mistakes.

core.setOutput("items_count", String(allItems.length));
core.setOutput("campaign_id", campaignId);
core.setOutput("discovery_file", discoveryOutputPath);
core.info(`✓ Campaign discovery complete: ${allItems.length} item(s) found for campaign "${campaignId}"`);
---

<!-- This file was automatically generated by gh-aw. DO NOT EDIT. -->
Expand Down
6 changes: 3 additions & 3 deletions actions/setup/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ This action copies workflow script files to the agent environment.
This action runs in all workflow jobs to provide scripts that can be used instead of being inlined in the workflow. This includes scripts for activation jobs, agent jobs, and safe-output jobs.

The action copies:
- 117 `.cjs` JavaScript files from the `js/` directory
- 226 `.cjs` JavaScript files from the `js/` directory
- 7 `.sh` shell scripts from the `sh/` directory

All files are copied to the destination directory (default: `/tmp/gh-aw/actions`). These files are generated by running `make actions-build` and are committed to the repository.
Expand Down Expand Up @@ -35,7 +35,7 @@ Default: `/tmp/gh-aw/actions`

### `files-copied`

The number of files copied to the destination directory (should be 124: 117 JavaScript files + 7 shell scripts).
The number of files copied to the destination directory (should be 233: 226 JavaScript files + 7 shell scripts).

## Example

Expand All @@ -56,7 +56,7 @@ steps:

This action copies files from `actions/setup/`, including:

### JavaScript Files (117 files from `js/`)
### JavaScript Files (226 files from `js/`)
- Activation job scripts (check_stop_time, check_skip_if_match, check_command_position, etc.)
- Agent job scripts (compute_text, create_issue, create_pull_request, etc.)
- Safe output scripts (safe_outputs_*, safe_inputs_*, messages, etc.)
Expand Down
Loading