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
1 change: 0 additions & 1 deletion .github/pull_request_template.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,3 @@
> Example: `feat: add role`

- [ ] I have formatted my PR title correctly.
- [ ] I have added `[skip ci]` to the title (Maintainers only, if no release is needed).
60 changes: 50 additions & 10 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,23 +14,44 @@
# Runs at 00:00 on the 1st and 15th of every month
- cron: '0 0 1,15 * *'
workflow_dispatch:
inputs:
trigger_release:
type: boolean
default: false
description: 'Create release PR'
auto_merge:
type: boolean
default: false
description: 'Enable auto-merge for release PR'

concurrency:
# Groups by PR number or branch ref. Unique enough to prevent collisions.
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}-${{ github.event_name }}
# Releases get their own group and never cancel each other.
# Main branch workflows (including release publishes) never cancel each other.
group: ${{ github.event_name == 'workflow_dispatch' && inputs.trigger_release == true && format('release-{0}', github.workflow) || format('{0}-{1}-{2}', github.workflow, github.event.pull_request.number || github.ref, github.event_name) }}
cancel-in-progress: ${{ github.ref != format('refs/heads/{0}', github.event.repository.default_branch) }}

jobs:
# Logic Gate: Determine if this is an external contributor
setup:
runs-on: ubuntu-latest
if: |
(github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository) ||
(github.event_name == 'pull_request_target' && github.event.pull_request.head.repo.full_name != github.repository) ||
(github.event_name != 'pull_request' && github.event_name != 'pull_request_target')
github.event_name == 'pull_request' ||
github.event_name == 'pull_request_target' ||
github.event_name == 'push' ||
github.event_name == 'merge_group' ||
github.event_name == 'schedule' ||
github.event_name == 'workflow_dispatch'
outputs:
is_external: ${{ steps.check.outputs.external }}
steps:
- name: Validate workflow_dispatch
if: github.event_name == 'workflow_dispatch'
run: |
if [[ "${{ github.ref }}" != "refs/heads/${{ github.event.repository.default_branch }}" ]]; then
echo "::error::workflow_dispatch can only run on main branch"
exit 1
fi
- id: check
run: |
if [[ "${{ github.event_name }}" == "pull_request_target" && "${{ github.event.pull_request.head.repo.full_name }}" != "${{ github.repository }}" ]]; then
Expand All @@ -48,25 +69,44 @@
steps:
- run: echo "External PR approved by environment gate."

# Unified CI: Runs for internal events OR after external approval
# Release Gatekeeper: Only runs for workflow_dispatch with trigger_release. Requires manual approval.
release-approval:
runs-on: ubuntu-latest
if: github.event_name == 'workflow_dispatch' && inputs.trigger_release == true
environment: release # Configure in Settings → Environments
steps:
- name: Audit release trigger
run: |
echo "::notice::Release triggered by ${{ github.actor }}"
echo "Event: ${{ github.event_name }}"
echo "Ref: ${{ github.ref }}"
echo "Inputs: trigger_release=${{ inputs.trigger_release }}, auto_merge=${{ inputs.auto_merge }}"
- run: echo "Release approved by environment gate"

# Unified CI: Runs for internal events OR after external approval OR after release approval
ci:

Check warning

Code scanning / CodeQL

Workflow does not contain permissions Medium

Actions job or workflow does not limit the permissions of the GITHUB_TOKEN. Consider setting an explicit permissions block, using the following as a minimal starting point: {}
needs: [setup, external-approval]
# Run if it's NOT external, OR if it IS external and the approval job finished
needs: [setup, external-approval, release-approval]
# always() allows job to run even when dependencies are skipped, but we still require explicit success checks
# Run if setup succeeds AND (not external OR external-approval succeeds) AND (not release OR release-approval succeeds)
if: |
always() &&
(needs.setup.result == 'success') &&
(needs.setup.outputs.is_external == 'false' || needs.external-approval.result == 'success') &&
(needs.setup.result == 'success')
uses: redhat-cop/openshift_virtualization_migration_ci/.github/workflows/ci-ansible-collection.yml@main
(github.event_name != 'workflow_dispatch' || inputs.trigger_release != true || needs.release-approval.result == 'success')
uses: redhat-cop/openshift_virtualization_migration_ci/.github/workflows/ci-ansible-collection.yml@v2
permissions:
contents: write
packages: write
security-events: write
actions: read
pull-requests: write
with:
# Use head.sha for PRs to get the actual commit, otherwise fallback to global sha
ref: ${{ github.event.pull_request.head.sha || github.sha }}
repo: ${{ github.event.pull_request.head.repo.full_name || github.repository }}
publish_to_automation_hub: false
trigger_release: ${{ inputs.trigger_release || false }}
auto_merge: ${{ inputs.auto_merge || false }}
publish_to_automation_hub: true
secrets:
automation_hub_token: ${{ secrets.AUTOMATION_HUB_TOKEN }}
release_app_id: ${{ secrets.RELEASE_APP_ID }}
Expand Down
Loading
Loading