From 910f8cef337cc995d0ee77700bc4fa5e227fbe70 Mon Sep 17 00:00:00 2001 From: Shubhika Garg Date: Wed, 17 Jun 2026 10:06:46 +0200 Subject: [PATCH 1/5] ci: skip ci when no mandatory ci label present on PR - Add check-labels job that runs first on the PR events - Fail early if none of the mandatory CI labels are present (BUILD-ONLY, documentation, 4G-LTE, 5G-NR, nrUE, CI, retrigger-ci) - Skip detect-changes, require-maintainer-approval and trigger-jenkins when no mandatory CI label is found - Push events are unaffected by the label check - For labeled events, only retrigger-ci triggers the pipeline; any other label addition is skipped Co-authored-by: Shubhika Garg Signed-off-by: Jaroslava Fiedlerova --- .github/workflows/jenkins-dispatch.yml | 36 ++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/.github/workflows/jenkins-dispatch.yml b/.github/workflows/jenkins-dispatch.yml index 839d60c59b..86b79863d1 100644 --- a/.github/workflows/jenkins-dispatch.yml +++ b/.github/workflows/jenkins-dispatch.yml @@ -17,12 +17,43 @@ permissions: pull-requests: write jobs: + check-labels: + runs-on: ubuntu-24.04 + + if: github.event_name == 'pull_request_target' + + steps: + - name: Check for mandatory CI label + run: | + PR_LABELS=$(echo '${{ toJson(github.event.pull_request.labels) }}' | jq -r '.[].name') + + for label in \ + "${{ vars.BUILD_ONLY_LABEL }}" \ + "${{ vars.DOC_LABEL }}" \ + "${{ vars.NR_LABEL }}" \ + "${{ vars.NRUE_LABEL }}" \ + "${{ vars.LTE_LABEL }}" \ + "${{ vars.CI_LABEL }}" \ + "${{ vars.RETRIGGER_CI_LABEL }}"; do + if echo "$PR_LABELS" | grep -qxF "$label"; then + exit 0 + fi + done + + exit 1 + detect-changes: + needs: check-labels runs-on: ubuntu-24.04 if: | - github.event.action != 'labeled' || - github.event.label.name == vars.RETRIGGER_CI_LABEL + always() && ( + github.event_name == 'push' || + needs.check-labels.result == 'success' + ) && ( + github.event.action != 'labeled' || + github.event.label.name == vars.RETRIGGER_CI_LABEL + ) outputs: protected_files_changed: ${{ steps.filter.outputs.protected }} @@ -61,6 +92,7 @@ jobs: trigger-jenkins: needs: + - check-labels - detect-changes - require-maintainer-approval From 840abd0048ef80eb321531028f0162cb00b1e0de Mon Sep 17 00:00:00 2001 From: Shubhika Garg Date: Wed, 17 Jun 2026 13:38:12 +0200 Subject: [PATCH 2/5] ci: Add check for unsigned commits in the PR - Add verify-signed-commits job that runs on PR - check-labels and all downstream jobs are skipped if signed commmit verifications fails - Fetch all commits in the PR via GitHub API and check verification status - Fail and print the unsigned commit SHAs if any unsigned commits are found. Co-authored-by: Shubhika Garg Signed-off-by: Jaroslava Fiedlerova --- .github/workflows/jenkins-dispatch.yml | 29 ++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/.github/workflows/jenkins-dispatch.yml b/.github/workflows/jenkins-dispatch.yml index 86b79863d1..f8b91c89de 100644 --- a/.github/workflows/jenkins-dispatch.yml +++ b/.github/workflows/jenkins-dispatch.yml @@ -17,7 +17,36 @@ permissions: pull-requests: write jobs: + verify-signed-commits: + runs-on: ubuntu-24.04 + + if: github.event_name == 'pull_request_target' + + steps: + - name: Check all commits are signed + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + UNSIGNED=$(gh api repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}/commits \ + --paginate --jq '[.[] | select(.commit.verification.verified == false) | .sha[:7]] | join(", ")') + + if [ -n "$UNSIGNED" ]; then + echo -e "$UNSIGNED commits are missing signature" + gh pr comment ${{ github.event.pull_request.number }} --repo ${{ github.repository }} --body "$(cat < Date: Thu, 18 Jun 2026 11:36:42 +0200 Subject: [PATCH 3/5] doc: improve commit signing guidelines in CONTRIBUTING.md Signed-off-by: Shubhika Garg --- CONTRIBUTING.md | 125 +++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 109 insertions(+), 16 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 441caa5b43..ef3bcb1663 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,6 +1,6 @@ -# Contributing to OpenAirInterface +# Contributing to Duranta We want to make contributing to this project as easy and transparent as possible. @@ -18,41 +18,134 @@ We want to make contributing to this project as easy and transparent as possible ## Commit Guidelines +Every pull request must pass two CI checks before it can be merged: + +1. **[Developer Certificate of Origin (DCO)](https://en.wikipedia.org/wiki/Developer_Certificate_of_Origin)**: + Each commit must include a `Signed-off-by:` trailer in the commit message. + Use `git commit -s` (or `--signoff`). + +2. **[Verified commits](https://docs.github.com/en/authentication/managing-commit-signature-verification/about-commit-signature-verification)**: + Each commit must be cryptographically signed using SSH or GPG keys to confirm + its origin. + ### Signing Commits -To sign commits: +GitHub supports commit signing using either SSH keys or GPG keys. +For more information, see the +[GitHub documentation](https://docs.github.com/en/authentication/managing-commit-signature-verification/signing-commits). -You can also get the verified label on your commits via using [SSH keys or GPG -keys](https://docs.github.com/en/authentication/managing-commit-signature-verification/signing-commits) +Before configuring commit signing: + +- Generate an SSH key pair or GPG key pair. +- Add your public key to your GitHub account. +- Verify your GitHub email address (required for “Verified” commits to work). +- If using SSH signing, ensure the key is registered in GitHub for: + - Authentication (SSH and GPG keys) + - Signing commits (Signing Keys) + +> **NOTE:** +> Adding an SSH key for repo access does not automatically enable commit signing. +> The key must also be added under GitHub's Signing Keys settings. + + +To ensure commits show as Verified on GitHub: + +- Your `git config user.email` must match a GitHub email +- That email must be verified in your GitHub account + +For more information, see the +[GitHub Docs](https://docs.github.com/en/account-and-profile/how-tos/email-preferences/verifying-your-email-address) + +Configure your repository's `.git/config`: + +```ini +# Edit the git configuration -``` -# Edit .git/config in the git repository you are working on -# Add the user section [user] name = YOUR NAME - email = YOUR EMAIL ADDRESS + email = YOUR VERIFIED EMAIL ADDRESS -# If you use a signing key, use the below configuration instead -[user] - name = YOUR NAME - email = YOUR EMAIL ADDRESS - signingkey = LOCATION OF SSH KEYS or GPG KEY + # REQUIRED for commit signing + # Use ONE signing method (SSH or GPG) + + signingkey = YOUR_SIGNING_KEY + + # Examples: + # SSH signing: + # signingkey = ~/.ssh/id_ed25519.pub + + # GPG signing: + # signingkey = YOUR_GPG_KEY_ID [gpg] - format = ssh + # REQUIRED: defines signing method (SSH or GPG) + + format = YOUR_SIGNING_FORMAT + + # Examples: + # SSH signing: + # format = ssh + + # GPG signing: + # format = openpgp [commit] gpgsign = true ``` -> **NOTE:** If your commits are not signed the CI framework will not accept the PR. +> The private key is used automatically by SSH/Git when signing commits (SSH only). +#### Verifying Signed Commits + +You can verify that commits are properly signed locally using: + +```bash +git log --show-signature +``` + +GitHub should also display a Verified badge next to signed commits once the +signing key has been correctly configured in your account. + +##### SSH Signature Verification (`allowed_signers`) + +For SSH commit signing, local Git verification may require an `allowed_signers` +file. This is only used for local verification in Git and is not required +by GitHub. + +If you see errors such as: + +```text +No principal matched +Can't check signature +error: gpg.ssh.allowedSignersFile needs to be configured +``` +you may need to configure it. + +Create the file and add your signing identity: + +```bash +mkdir -p ~/.config/git +touch ~/.config/git/allowed_signers +echo "user@example.com ssh-ed25519 AAAACexamplekeystringhere" > ~/.config/git/allowed_signers +``` + +Enable it in local repository Git config: + +```bash +git config gpg.ssh.allowedSignersFile ~/.config/git/allowed_signers +``` + +> **NOTE:** +> This is only for local Git signature verification and does not affect GitHub, +> or remote repository behavior. + +> **NOTE:** If your commits are not signed, the CI framework will not accept the PR. For more information regarding contribution guidelines please check [this document](doc/code-style-contrib.md) ## License -By contributing to OpenAirInterface, you agree that your contributions will be +By contributing to Duranta, you agree that your contributions will be licensed under 1. [CSSL v1.0 license](LICENSES/preferred/CSSL-v1.0.txt): for RAN and UE From 328968cecf9135fa212e0b38008214104fd0ee39 Mon Sep 17 00:00:00 2001 From: Shubhika Garg Date: Thu, 18 Jun 2026 11:45:45 +0200 Subject: [PATCH 4/5] ci: ensure retrigger-ci label is cleaned up after every CI run - Previously the label was only removed when it was the labeled event that triggered the workflow. If a PR was synchronized or reopened while the label was already present, it would not be removed by the workflow. - Created a dedicated cleanup job that depends on all other jobs with if: always(), ensuring it runs regardless of whether upstream jobs succeeded, failed, or were skipped. - Now the cleanup runs on every pull_request_target event and removes the label if present, ensuring it is always cleared after CI completes. Co-authored-by: Jaroslava Fiedlerova Signed-off-by: Shubhika Garg --- .github/workflows/jenkins-dispatch.yml | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/.github/workflows/jenkins-dispatch.yml b/.github/workflows/jenkins-dispatch.yml index f8b91c89de..a2deca8d03 100644 --- a/.github/workflows/jenkins-dispatch.yml +++ b/.github/workflows/jenkins-dispatch.yml @@ -166,8 +166,24 @@ jobs: -H "X-Github-Hook-Installation-Target-Type: repository" \ --data @/tmp/filtered_payload.json + cleanup: + needs: + - verify-signed-commits + - check-labels + - detect-changes + - require-maintainer-approval + - trigger-jenkins + + if: always() && github.event_name == 'pull_request_target' + + runs-on: ubuntu-24.04 + + steps: - name: Remove retrigger-ci label - if: always() && github.event.action == 'labeled' && github.event.label.name == vars.RETRIGGER_CI_LABEL - run: gh pr edit ${{ github.event.pull_request.number }} --remove-label "${{ vars.RETRIGGER_CI_LABEL }}" + run: | + PR_LABELS=$(echo '${{ toJson(github.event.pull_request.labels) }}' | jq -r '.[].name') + if echo "$PR_LABELS" | grep -qxF "${{ vars.RETRIGGER_CI_LABEL }}"; then + gh pr edit ${{ github.event.pull_request.number }} --remove-label "${{ vars.RETRIGGER_CI_LABEL }}" --repo ${{ github.repository }} + fi env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} From f63c444bb72305a6a371a1b86d45fdd4eb29c6ad Mon Sep 17 00:00:00 2001 From: Shubhika Garg Date: Fri, 3 Jul 2026 13:19:58 +0200 Subject: [PATCH 5/5] ci: ensure maintainer approval job is evaluated correctly on push events - The require-maintainer-approval job was being skipped on push event when upstream jobs (verify-signed-commits and check-labels) were skipped, even though detect-changes job successfully marked protected files as changed. - GitHub Actions may skip dependent jobs due to upstream skipped states before evaluating custom conditions. - Adding always() ensures the job condition is evaluated regardless of the status of upstream jobs, while still enforcing the rule that the job only runs when protected_files_changed == true. Signed-off-by: Shubhika Garg --- .github/workflows/jenkins-dispatch.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/jenkins-dispatch.yml b/.github/workflows/jenkins-dispatch.yml index a2deca8d03..4ca7bc6d23 100644 --- a/.github/workflows/jenkins-dispatch.yml +++ b/.github/workflows/jenkins-dispatch.yml @@ -109,8 +109,9 @@ jobs: require-maintainer-approval: needs: detect-changes - if: needs.detect-changes.outputs.protected_files_changed == 'true' - + if: | + always() && + needs.detect-changes.outputs.protected_files_changed == 'true' runs-on: ubuntu-24.04 environment: