Skip to content

Refactor: Workflow security and trigger updates#133

Closed
ModeSevenIndustrialSolutions wants to merge 4 commits intolfreleng-actions:mainfrom
modeseven-lfreleng-actions:wf-trigger-updates
Closed

Refactor: Workflow security and trigger updates#133
ModeSevenIndustrialSolutions wants to merge 4 commits intolfreleng-actions:mainfrom
modeseven-lfreleng-actions:wf-trigger-updates

Conversation

@ModeSevenIndustrialSolutions
Copy link
Contributor

@ModeSevenIndustrialSolutions ModeSevenIndustrialSolutions commented Feb 18, 2026

Summary

Refactor workflow security and trigger handling across the GitHub2Gerrit project.

Commits

1. Improve Grype vulnerability scan output and failure handling

  • Run Grype in both SARIF and table output formats
  • Upload both artifacts for retention (90 days)
  • Add SBOM + vulnerability summary to GITHUB_STEP_SUMMARY
  • Use continue-on-error for SARIF scan to ensure artifacts are always collected
  • Add explicit "Fail on Grype findings" step that checks SARIF outcome

2. Support pull_request trigger alongside pull_request_target

  • Update get_operation_mode() in models.py to accept both trigger types
  • Update Change-ID reuse logic and close-PR policy in core.py
  • Using pull_request is preferred for security (avoids granting secrets to untrusted fork code)
  • pull_request_target remains accepted for backward compatibility
  • Test updates: rename test_close_pr_not_invoked_for_non_target_eventtest_close_pr_not_invoked_for_non_pr_event (uses workflow_dispatch)
  • New test: test_close_pr_invoked_for_pull_request_event

3. Add deployment template workflows

  • workflow-templates/github2gerrit.yaml — standalone workflow with pull_request trigger
  • workflow-templates/gerrit-merge-github2gerrit.yaml — extended with Gerrit notification + status reporting
  • workflow-templates/gerrit-verify-github2gerrit.yaml — verification for patchset-created events
  • All templates include fork PR guards (if: github.event_name != 'pull_request' || ...head.repo.full_name == github.repository)
  • Fixed boolean expressions: ALLOW_DUPLICATES/PRESERVE_GITHUB_PRS now use github.event_name != 'workflow_dispatch' || inputs.x to correctly preserve false values

4. Remove old reusable workflow and add metadata job comments

  • Remove old github2gerrit.yaml reusable workflow (workflow_call trigger)
  • Add explanatory comment to repository-metadata job in build-test-release.yaml

Copilot review feedback addressed

  • ✅ Boolean expression bug: && inputs.x || true always evaluates to true → fixed
  • ✅ Grype security regression: continue-on-error without failure check → added explicit fail step
  • ✅ Fork PR secrets: jobs now skip fork PRs where secrets are unavailable
  • ✅ Test coverage: new test for pull_request event closure
  • repository-metadata job: explanatory comment added

Copilot AI review requested due to automatic review settings February 18, 2026 13:01
@github-actions github-actions bot added the refactor Refactoring of code label Feb 18, 2026
Copy link

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

This pull request refactors the GitHub Actions workflows for the GitHub2Gerrit integration, transitioning from pull_request_target to pull_request triggers for improved security. The changes ensure that only trusted automation bot PRs (dependabot, pre-commit-ci) are processed, as these bots push branches to the base repository rather than from forks. The PR also adds two new specialized workflows for Gerrit merge and verification operations, and updates the Python code to support both trigger types for backward compatibility.

Changes:

  • Updated Python code to support both pull_request and pull_request_target event triggers
  • Refactored github2gerrit.yaml from a reusable workflow to a standalone workflow using the safer pull_request trigger
  • Added gerrit-merge-github2gerrit.yaml workflow with Gerrit notification and status reporting jobs
  • Added gerrit-verify-github2gerrit.yaml workflow for Gerrit patchset verification and reconciliation

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
src/github2gerrit/models.py Updated get_operation_mode() to accept both pull_request and pull_request_target events with security documentation
src/github2gerrit/core.py Extended Change-ID reuse logic and PR closure policy to support both event types
.github/workflows/github2gerrit.yaml Completely refactored to standalone workflow with pull_request trigger and simplified inputs using external action
.github/workflows/gerrit-verify-github2gerrit.yaml New workflow for Gerrit-triggered verification without voting
.github/workflows/gerrit-merge-github2gerrit.yaml New workflow with Gerrit notification, metadata collection, and status reporting jobs

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

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Addressed all three Copilot review findings in the amended commit:

  1. Test file changes: Updated tests/test_core_close_pr_policy.py — renamed test_close_pr_not_invoked_for_non_target_event to test_close_pr_not_invoked_for_non_pr_event (now uses workflow_dispatch instead of pull_request), and added a new test_close_pr_invoked_for_pull_request_event test that verifies pull_request events trigger PR closure.

  2. repository-metadata job: Added an explanatory comment clarifying it runs for observability/traceability and its outputs are consumed by external dashboards/reports.

  3. Test breakage: The new test_close_pr_invoked_for_pull_request_event test confirms that pull_request events now correctly trigger closure, and the existing non-target-event test was updated to use workflow_dispatch instead.

Copy link

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

Copilot reviewed 8 out of 8 changed files in this pull request and generated 5 comments.


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

Comment on lines +140 to +163
- name: "Security scan with Grype (SARIF)"
# yamllint disable-line rule:line-length
uses: anchore/scan-action@7037fa011853d5a11690026fb85feee79f4c946c # v7.3.2
id: grype-sarif
# The first Grype audit should not be blocking and should never fail
# That way we always get the required artefact; the second job will
# exit with an error, as required (below)
continue-on-error: true
with:
sbom: "${{ steps.sbom.outputs.sbom_json_path }}"
output-format: "sarif"
output-file: "grype-results.sarif"
fail-build: "true"

- name: "Summary step"
- name: "Security scan with Grype (Text/Table)"
# yamllint disable-line rule:line-length
uses: anchore/scan-action@7037fa011853d5a11690026fb85feee79f4c946c # v7.3.2
id: grype-table
if: always()
with:
sbom: "${{ steps.sbom.outputs.sbom_json_path }}"
output-format: "table"
output-file: "grype-results.txt"
fail-build: "false"
Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

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

The Grype scan no longer fails the workflow on vulnerabilities: the SARIF scan sets fail-build: "true" but also continue-on-error: true, and the follow-up table scan sets fail-build: "false". As written, this job will always succeed even when Grype finds findings, which is a security regression vs a blocking scan. Either remove continue-on-error from the blocking scan, or add an explicit failing step based on steps.grype-sarif.outcome/exit code (and keep SARIF upload non-blocking separately).

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This has been addressed. The current PR now includes a "Check Grype scan results" step that checks steps.grype-sarif.outcome == 'failure' and exits with error code 1. The continue-on-error: true on the SARIF step allows subsequent steps (table output, artifact upload, summary) to complete before the explicit failure step fires. This is the intended pattern.

# secrets and write access to untrusted fork code. The default
# AUTOMATION_ONLY=true setting ensures only trusted bot PRs (dependabot,
# pre-commit-ci) are processed — these bots push branches to the base
# repository, not from forks, so pull_request has full access to secrets.
Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

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

This workflow uses the pull_request trigger but always passes Gerrit auth secrets (secrets.GERRIT_SSH_PRIVKEY_G2G). For PRs coming from forks, GitHub Actions will not provide repository secrets, so the action will receive an empty key and is likely to fail noisily. Consider adding a job-level guard to only run when github.event.pull_request.head.repo.full_name == github.repository (or similar), or otherwise explicitly handle the "no secrets on forks" case to avoid unexpected failures.

Suggested change
# repository, not from forks, so pull_request has full access to secrets.
# repository, not from forks, so pull_request has full access to secrets.
# NOTE: Jobs that use Gerrit auth secrets MUST also include a job-level
# `if:` condition to skip execution for fork-based PRs, for example:
# if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Stale — the workflow-templates/ directory has been removed from this PR. These templates require further testing and will be submitted separately.

Comment on lines +11 to +16
# Security: uses pull_request (not pull_request_target) to avoid granting
# secrets and write access to untrusted fork code. The default
# AUTOMATION_ONLY=true setting ensures only trusted bot PRs (dependabot,
# pre-commit-ci) are processed — these bots push branches to the base
# repository, not from forks, so pull_request has full access to secrets.
pull_request:
Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

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

Because this runs on pull_request and always supplies Gerrit secrets, PRs from forks will not have access to secrets.GERRIT_SSH_PRIVKEY_G2G and the workflow is likely to fail (secrets are not provided to forked PR workflows). Add a job-level if to restrict execution to same-repo PRs (or handle missing secrets explicitly) to prevent noisy failures.

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Stale — the workflow-templates/ directory has been removed from this PR. These templates require further testing and will be submitted separately.

Copy link

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

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


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

@ModeSevenIndustrialSolutions
Copy link
Contributor Author

Addressing Copilot review feedback (second cycle)

All 5 unresolved findings from the second Copilot review have been fixed. Details below:


1. Boolean expression bug in workflow-templates/github2gerrit.yaml (line 126)

Finding: ALLOW_DUPLICATES/PRESERVE_GITHUB_PRS use github.event_name == 'workflow_dispatch' && inputs.x || true, which always evaluates to true when the input is false (because false || truetrue).

Fix: Changed to github.event_name != 'workflow_dispatch' || inputs.allow_duplicates. This evaluates to true for PR events (correct default) and preserves the actual input value for workflow_dispatch.


2. Same boolean expression bug in workflow-templates/gerrit-merge-github2gerrit.yaml (line 193)

Finding: Same && inputs.x || true pattern.

Fix: Same correction applied — github.event_name != 'workflow_dispatch' || inputs.x.


3. Grype scan security regression in .github/workflows/build-test.yaml (line 163)

Finding: The SARIF scan sets fail-build: "true" but also continue-on-error: true, and the table scan sets fail-build: "false". The job always succeeds even when Grype finds vulnerabilities.

Fix: Added an explicit "Fail on Grype findings" step at the end that checks steps.grype-sarif.outcome == 'failure' and exits non-zero. The continue-on-error on the SARIF step is intentional — it ensures artifacts (SARIF + table) are always collected before the job fails.


4. Fork PR secrets issue in workflow-templates/github2gerrit.yaml (line 15)

Finding: Fork PRs will lack secrets.GERRIT_SSH_PRIVKEY_G2G, causing noisy failures.

Fix: Added a job-level if: guard on the github2gerrit job:

if: >-
  github.event_name != 'pull_request' ||
  github.event.pull_request.head.repo.full_name == github.repository

Also added a documentation note in the trigger comment block.


5. Fork PR secrets issue in workflow-templates/gerrit-merge-github2gerrit.yaml (line 16)

Finding: Same fork PR secrets issue.

Fix: Added a combined if: guard on the github2gerrit job (which already had if: always() for the notify dependency):

if: >-
  always() && (
    github.event_name != 'pull_request' ||
    github.event.pull_request.head.repo.full_name == github.repository
  )

Also added a documentation note in the trigger comment block.

This comment was marked as outdated.

Run Grype in both SARIF and table output formats to provide machine-readable
results alongside human-readable summaries. Upload both artifacts for
retention. Add a dedicated summary step that writes SBOM and vulnerability
information to GITHUB_STEP_SUMMARY.

The SARIF scan uses continue-on-error to ensure artifacts are always
collected, with an explicit "Fail on Grype findings" step that checks
the SARIF outcome and exits non-zero when vulnerabilities are found.

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Matthew Watkins <mwatkins@linuxfoundation.org>
Update get_operation_mode() in models.py and the Change-ID reuse logic
plus close-PR policy in core.py to accept both pull_request and
pull_request_target event names. Using pull_request is preferred for
security (avoids granting secrets and write access to untrusted fork
code), while pull_request_target remains accepted for backward
compatibility.

Update tests to match the new behaviour:
- Rename test_close_pr_not_invoked_for_non_target_event to
  test_close_pr_not_invoked_for_non_pr_event (uses workflow_dispatch)
- Add test_close_pr_invoked_for_pull_request_event verifying that
  pull_request events now trigger PR closure

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Matthew Watkins <mwatkins@linuxfoundation.org>
Add three workflow template files for downstream projects to adopt:

- github2gerrit.yaml: Standalone workflow using the safer pull_request
  trigger (instead of pull_request_target) with workflow_dispatch for
  Gerrit-initiated operations.

- gerrit-merge-github2gerrit.yaml: Extended workflow with Gerrit
  notification, repository metadata collection, and status reporting
  jobs for merge operations.

- gerrit-verify-github2gerrit.yaml: Verification workflow triggered
  by gerrit_to_platform on patchset-created events for reconciliation.

All template workflows include:
- Fork PR guards to skip when secrets are unavailable
- Correct boolean expressions for workflow_dispatch inputs
- Concurrency groups scoped by event type

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Matthew Watkins <mwatkins@linuxfoundation.org>
Remove the old github2gerrit.yaml reusable workflow (workflow_call
trigger) which is replaced by the standalone template workflows in
workflow-templates/.

Add explanatory comment to the repository-metadata job in
build-test-release.yaml clarifying that it runs for debugging,
troubleshooting, and traceability (not as a dependency of other jobs).

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Matthew Watkins <mwatkins@linuxfoundation.org>
Copy link

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

Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.


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

Comment on lines +32 to +33
permissions:
actions: write # Required for cache deletion when clear_cache is true
Copy link

Copilot AI Feb 25, 2026

Choose a reason for hiding this comment

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

Workflow-level permissions: actions: write is unnecessary here because every job defines its own permissions block (and python-build already requests actions: write). Keeping write permissions at the workflow level increases the chance future jobs inherit broader rights unintentionally; consider removing the top-level permissions block or setting it to {} and relying on job-scoped permissions only.

Suggested change
permissions:
actions: write # Required for cache deletion when clear_cache is true
permissions: {}

Copilot uses AI. Check for mistakes.
uses: lfreleng-actions/python-audit-action@ec8d84ca14c0413a2b2c6612a3e15b9803f9de75 # v0.2.5
uses: lfreleng-actions/python-audit-action@ec8d84ca14c0413a2b2c6612a3e15b9803f9de75 # v0.2.5
with:
python_version: "${{ matrix.python-version }}"
Copy link

Copilot AI Feb 25, 2026

Choose a reason for hiding this comment

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

python-audit no longer sets permit_fail: true for lfreleng-actions/python-audit-action. This is a behavior change from the previous configuration (which explicitly allowed audit failures for dev/non-PyPI packages) and may cause CI to start failing on projects that previously passed. If the intent is still to allow non-blocking audits in this workflow, reintroduce permit_fail: true (or the action’s current equivalent).

Suggested change
python_version: "${{ matrix.python-version }}"
python_version: "${{ matrix.python-version }}"
permit_fail: true

Copilot uses AI. Check for mistakes.
Comment on lines +290 to +295
# Check Grype scan results
echo "::error::Grype found vulnerabilities" \
"at or above severity threshold"
echo "Review the Grype Summary above or download the" \
"grype-scan-results artifact for details"
exit 1
Copy link

Copilot AI Feb 25, 2026

Choose a reason for hiding this comment

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

The comments state the table scan is set to not block releases, but the workflow still fails the sbom job when steps.grype-sarif.outcome == 'failure' (and the SARIF scan has fail-build: "true"). As written, vulnerability findings will block tag-based releases. Either remove/relax this check in the release workflow, or set the SARIF scan to not fail the step (e.g., fail-build: "false") if releases should proceed.

Suggested change
# Check Grype scan results
echo "::error::Grype found vulnerabilities" \
"at or above severity threshold"
echo "Review the Grype Summary above or download the" \
"grype-scan-results artifact for details"
exit 1
# Check Grype scan results (non-blocking)
echo "::warning::Grype found vulnerabilities at or above severity threshold."
echo "Review the Grype Summary above or download the grype-scan-results artifact for details."

Copilot uses AI. Check for mistakes.
@ModeSevenIndustrialSolutions
Copy link
Contributor Author

Resubmitting this PR separately, since the original change/scope intention has been radically modified.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

refactor Refactoring of code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants