fix(security): Remediate 16 audit findings in intake workflows#5
Closed
michaeloboyle wants to merge 8 commits intoagenticsorg:mainfrom
Closed
fix(security): Remediate 16 audit findings in intake workflows#5michaeloboyle wants to merge 8 commits intoagenticsorg:mainfrom
michaeloboyle wants to merge 8 commits intoagenticsorg:mainfrom
Conversation
Add GitHub issue template for project submissions, 6 workflows for the full intake lifecycle (triage, scoring, escalation vote, validation vote, approval registration, retraction), scoring template, label setup script, and approved projects registry. Implements the process defined in the Open Source Committee governance doc. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…lows Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…utput Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ct voting Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…gex, harden script - SEC-013: Add bot filtering to validation-vote.yml vote tallying - SEC-012: Exclude issue author from voting in validation-vote.yml - SEC-014: Add repo format validation and confirmation prompt to setup-labels.sh Note: escalation-vote.yml and retraction.yml fixes were applied in prior commits. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR remediates security audit findings across the project intake GitHub Actions workflows by tightening access control, reducing injection risk, and hardening registry update behavior, plus adding supporting docs and admin tooling for the intake process.
Changes:
- Hardened issue-comment-driven workflows with concurrency controls, bot filtering, rate limiting, and updated voting semantics.
- Added input sanitization and basic schema validation around registry read/write operations.
- Pinned GitHub Actions to SHAs, added Dependabot for GitHub Actions, and added/update docs + label setup script.
Reviewed changes
Copilot reviewed 13 out of 13 changed files in this pull request and generated 12 comments.
Show a summary per file
| File | Description |
|---|---|
.github/workflows/on-submission.yml |
Adds sanitization and auto-triage labeling + welcome comment on new submissions. |
.github/workflows/scoring.yml |
Adds member-gated /score parsing and auto-posted formatted score comments. |
.github/workflows/escalation-vote.yml |
Adds member-gated escalation vote tallying with quorum, bot filtering, and rate limiting. |
.github/workflows/validation-vote.yml |
Adds member-gated validation vote tallying with quorum, bot filtering, rate limiting, and updated outcome logic. |
.github/workflows/approve-project.yml |
Registers approved projects into data/approved-projects.json with schema checks and concurrency protection. |
.github/workflows/retraction.yml |
Adds /retract proposals and /vote retract vs /vote no-retract tallying with registry update + serialization. |
.github/dependabot.yml |
Enables weekly Dependabot updates for GitHub Actions. |
.github/ISSUE_TEMPLATE/project-submission.yml |
Adds structured issue form for project submissions. |
.github/ISSUE_TEMPLATE/config.yml |
Disables blank issues and adds membership contact link. |
scripts/setup-labels.sh |
Adds admin script to create/overwrite required labels with basic input validation. |
docs/scoring-template.md |
Adds committee scoring rubric and command reference. |
README.md |
Documents the intake workflow, commands, labels, and setup. |
data/approved-projects.json |
Initializes approved projects registry. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+56
to
+68
| // Tally votes (one per unique user, last vote wins) | ||
| const votes = {}; | ||
| for (const c of comments) { | ||
| if (c.user.type === 'Bot') continue; | ||
| if (c.user.login === submitter) continue; | ||
| const body = c.body.trim(); | ||
| if (/^\/vote escalate\s*$/.test(body)) { | ||
| votes[c.user.login] = 'escalate'; | ||
| } | ||
| if (/^\/vote no-escalate\s*$/.test(body)) { | ||
| votes[c.user.login] = 'no-escalate'; | ||
| } | ||
| } |
Comment on lines
+57
to
+66
| // Tally votes (one per unique user, last vote wins) | ||
| const votes = {}; | ||
| for (const c of comments) { | ||
| if (c.user.type === 'Bot') continue; | ||
| if (c.user.login === submitter) continue; | ||
| const body = c.body.trim(); | ||
| if (/^\/vote approve\s*$/.test(body)) votes[c.user.login] = 'approve'; | ||
| if (/^\/vote decline\s*$/.test(body)) votes[c.user.login] = 'decline'; | ||
| if (/^\/vote defer\s*$/.test(body)) votes[c.user.login] = 'defer'; | ||
| } |
Comment on lines
+109
to
+117
| // SEC-010: Strict majority required, ties default to DEFERRED | ||
| let outcome, outcomeLabel; | ||
| if (approve > decline && approve > defer) { | ||
| outcome = 'APPROVED'; | ||
| outcomeLabel = 'status:approved'; | ||
| } else if (decline > approve && decline > defer) { | ||
| outcome = 'DECLINED'; | ||
| outcomeLabel = 'status:declined'; | ||
| } else { |
Comment on lines
+103
to
+117
| // Count unique retraction and no-retract votes | ||
| const retractVoters = new Set(); | ||
| const keepVoters = new Set(); | ||
| for (const c of comments) { | ||
| if (c.user.type === 'Bot') continue; | ||
| const body = c.body.trim(); | ||
| if (body === '/vote retract') { | ||
| retractVoters.add(c.user.login); | ||
| keepVoters.delete(c.user.login); | ||
| } | ||
| if (body === '/vote no-retract') { | ||
| keepVoters.add(c.user.login); | ||
| retractVoters.delete(c.user.login); | ||
| } | ||
| } |
Comment on lines
+43
to
+48
| for (const c of criteria) { | ||
| const match = comment.match(new RegExp(`${c}:\\s*(\\d)`)); | ||
| if (match) { | ||
| const val = parseInt(match[1]); | ||
| if (val < 0 || val > 5) { valid = false; break; } | ||
| scores[c] = val; |
Comment on lines
+161
to
+169
| const idx = registry.findIndex(p => p.issue_number === issueNumber); | ||
| if (idx !== -1) { | ||
| registry[idx].status = 'retracted'; | ||
| registry[idx].retracted_date = new Date().toISOString().split('T')[0]; | ||
| fs.writeFileSync(registryPath, JSON.stringify(registry, null, 2) + '\n'); | ||
|
|
||
| core.setOutput('updated_registry', 'true'); | ||
| core.setOutput('issue_number', String(issueNumber)); | ||
| } |
Comment on lines
+101
to
+116
| // Generate ID from issue number (avoids race condition with registry.length) | ||
| const id = `proj-${String(issueNumber).padStart(3, '0')}`; | ||
|
|
||
| // Add entry | ||
| registry.push({ | ||
| id, | ||
| name: sanitize(descText, 80) || `Submission #${issueNumber}`, | ||
| repo_url: repoUrl, | ||
| category, | ||
| approved_date: new Date().toISOString().split('T')[0], | ||
| submitter: context.payload.issue.user.login, | ||
| description: sanitize(descText, 500), | ||
| total_score: avgScore, | ||
| issue_number: issueNumber, | ||
| status: 'active' | ||
| }); |
| // SEC-007: Sanitize user input before embedding in comments | ||
| function sanitize(input, maxLen = 100) { | ||
| return input | ||
| .replace(/[[\](){}|`*_~#>!\\]/g, '') |
| | `/vote decline` | Validation vote: decline the submission | | ||
| | `/vote defer` | Validation vote: defer pending more info | | ||
| | `/retract` | Propose retraction of a previously approved project | | ||
| | `/vote retract` | Vote to retract approval | |
| | `/retract` | Propose retraction of a previously approved project | | ||
| | `/vote retract` | Vote to retract approval | | ||
|
|
||
| All votes require a quorum of 3 and pass by simple majority. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Remediates all 16 security findings from the audit review of PR #4.
CRITICAL (2 fixed)
core.exportVariable()withcore.setOutput()in approve-project.yml and retraction.yml to eliminate shell injection patternHIGH (4 fixed)
author_associationaccess control (MEMBER/OWNER/COLLABORATOR) to all 5 voting/scoring script blocks across 4 workflowsregistry-updateconcurrency group, issue-based project IDs (proj-{issueNumber}), andgit pull --rebasebefore push.github/dependabot.ymlMEDIUM (5 fixed)
sanitize()function for user inputs, repo URL validation, JSON schema validation on registry read>not>=), ties default to DEFERRED/vote no-retractsupport, retraction requires majority of votes cast (not just quorum of retract votes)LOW (3 fixed)
INFO (2 noted, not code changes)
Commits
bfb19caSEC-003 add access control to voting and scoring workflows09ecfa3SEC-001/002 replace core.exportVariable with core.setOutput8092372SEC-007/009 add input sanitization and schema validation10feafaSEC-006 pin actions to SHA hashes, add dependabot02f3b3eSEC-008 add concurrency groups and rate limiting1f0d8bfSEC-010/011 strict majority tie-breaking, add no-retract votinga5e2101SEC-012/013/014 filter bots, exclude submitter, fix regex, harden scriptTest plan
/scoreas non-member, verify access denied/scoreas member, verify parsing and table/vote approvefrom issue submitter, verify excluded from tally/vote no-retractflowsetup-labels.shwith invalid input, verify rejectionCloses security review on #4.
Co-Authored-By: Claude Opus 4.6 noreply@anthropic.com