Skip to content
Closed
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
222 changes: 222 additions & 0 deletions .github/workflows/gitlab_ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,222 @@
---

name: Mirror to Gitlab to trigger CI

on:
push:
pull_request_target:
types: [opened, synchronize, reopened, labeled]
schedule:
- cron: '2 5 * * 1'

jobs:
check_permission:
runs-on: ubuntu-latest
if: >-
(github.repository_owner == 'Parallel-in-Time') &&
((github.event_name == 'push') ||
(github.event_name == 'schedule') ||
((github.event_name == 'pull_request_target') &&
(contains(github.event.pull_request.labels.*.name, 'gitlab-mirror'))
)
)
steps:
- name: Query permissions of triggering actor
id: query_permission_triggering_actor
if: github.event_name == 'pull_request_target'
uses: actions-cool/check-user-permission@v2
with:
username: ${{ github.triggering_actor }}
require: 'write'
token: ${{ secrets.GITHUB_TOKEN }}
- name: Interpret the queried result
if: github.event_name == 'pull_request_target'
run: |
echo "Current permission level is ${{ steps.query_permission_triggering_actor.outputs.user-permission }}"
echo "Job originally triggered by ${{ github.actor }}"
echo "Checking permission returned ${{ steps.query_permission_triggering_actor.outputs.require-result }}"
if ${{ steps.query_permission_triggering_actor.outputs.require-result }}
then
echo 'Permissions granted'
exit 0
else
echo 'Not enough permissions. Please ask a member of Parallel-in-Time to rerun the job.'
exit 1
fi
- name: Pass if workflow from push or schedule
if: >-
(github.event_name == 'push') ||
(github.event_name == 'schedule')
run: exit 0
# - name: Fail for other triggers
# if: >-
# (github.event_name != 'push') &&
# (github.event_name != 'schedule') &&
# (github.event_name != 'pull_request_target')
# run: exit 1

mirror_to_gitlab:
Comment on lines +14 to +58

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: {}

Copilot Autofix

AI 3 months ago

To fix the problem, we should explicitly define a permissions block that scopes the GITHUB_TOKEN to the minimal rights needed. Since both check_permission and mirror_to_gitlab (and the elided get_artifacts_from_other_workflow job) only need to read repository contents and interact with pull requests (e.g., for statuses/comments via the external GitLab action), we can set minimal read access at the workflow root, then elevate to pull-requests: write only for the job that needs it, if any. However, the safest and simplest fix without risking breaking current behavior is to add a workflow-level permissions block granting contents: read and pull-requests: write, which is a common least-privilege baseline for CI that mirrors PRs and may report back to them.

Concretely, in .github/workflows/gitlab_ci.yml, we will insert a top-level permissions: section right after the name: and before on:. This will apply to all jobs (including check_permission, mirror_to_gitlab, and get_artifacts_from_other_workflow) since none defines its own permissions. The block will be:

permissions:
  contents: read
  pull-requests: write

No additional imports or methods are required; GitHub Actions interprets this YAML key natively. This change documents and restricts the GITHUB_TOKEN while preserving typical functionality: reading the repository, checking out code, and allowing the GitLab mirroring action to update PRs if it currently does so.

Suggested changeset 1
.github/workflows/gitlab_ci.yml

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/.github/workflows/gitlab_ci.yml b/.github/workflows/gitlab_ci.yml
--- a/.github/workflows/gitlab_ci.yml
+++ b/.github/workflows/gitlab_ci.yml
@@ -2,6 +2,10 @@
 
 name: Mirror to Gitlab to trigger CI
 
+permissions:
+  contents: read
+  pull-requests: write
+
 on:
   push:
   pull_request_target:
EOF
@@ -2,6 +2,10 @@

name: Mirror to Gitlab to trigger CI

permissions:
contents: read
pull-requests: write

on:
push:
pull_request_target:
Copilot is powered by AI and may make mistakes. Always verify output.
runs-on: ubuntu-latest
if: >-
(github.repository_owner == 'Parallel-in-Time') &&
((github.event_name == 'push') ||
(github.event_name == 'schedule') ||
((github.event_name == 'pull_request_target') &&
(contains(github.event.pull_request.labels.*.name, 'gitlab-mirror'))
)
)
needs:
- check_permission
steps:
- name: set proper sha
run: |
echo "${{ github.event_name }}"
if [ "${{ github.event_name }}" == 'push' ] || [ "${{ github.event_name }}" == 'schedule' ]
then
echo "USED_SHA=${{ github.sha }}" >> "$GITHUB_ENV"
fi
if [ "${{ github.event_name }}" == 'pull_request_target' ]
then
echo "USED_SHA=${{ github.event.pull_request.head.sha }}" >> "$GITHUB_ENV"
fi
- name: Checkout
uses: actions/checkout@v4
with:
ref: "${{ env.USED_SHA }}"
persist-credentials: false
- name: check if merge is possible (merge is used for testing)
if: github.event_name == 'pull_request_target'
run: |
if $(git rev-parse --is-shallow-repository); then
git fetch --unshallow
else
git fetch
fi
echo "Checkout of ${{ github.base_ref }}"
git checkout "${{ github.base_ref }}"
echo "Git pull"
git pull
MIRROR_BRANCH="TEMPORARY_MERGE_PR_${{ github.event.number }}"
echo MIRROR_BRANCH="$MIRROR_BRANCH" >> $GITHUB_ENV
echo "Create new branch $MIRROR_BRANCH and check it out"
git checkout -b "$MIRROR_BRANCH"
echo "Setting git committer info, so that merge-commit can be created"
git config user.email "unused@example.com"
git config user.name "Sync bot"
echo "Merge the two parts of the Merge-Request to test the resulting version"
git merge "${{ github.event.pull_request.head.sha }}"
- name: Mirror and wait for Gitlab-CI
uses: jakob-fritz/github2lab_action@v0.8.1
env:
MODE: 'all' # Either 'mirror', 'get_status', 'get_artifact', or 'all'
GITLAB_TOKEN: ${{ secrets.GITLAB_SECRET }}
FORCE_PUSH: "true"
GITLAB_HOSTNAME: "gitlab.jsc.fz-juelich.de"
GITLAB_PROJECT_ID: "6029"
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
MIRROR_BRANCH: ${{ env.MIRROR_BRANCH }}
- name: Unzip downloaded artifacts
run: |
pwd
ls -lah
cd artifacts
find . -name "*.zip" -type f -exec unzip -o {} \;
ls -lah
rm *.zip
cd ..
ls -lah
- name: Uploading artifacts
uses: actions/upload-artifact@v4
with:
name: Gitlab-Action_artifacts
path: |
./artifacts/*

get_artifacts_from_other_workflow:
Comment on lines +59 to +135

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: {contents: read}

Copilot Autofix

AI 3 months ago

In general, to fix this issue you add a permissions: section either at the top level of the workflow (applies to all jobs) or per job, granting only the scopes actually needed (often contents: read as a baseline). This prevents the jobs from inheriting broader repository defaults.

For this workflow, the simplest fix without changing functionality is to add a top-level permissions: block (between on: and jobs:) that defines a minimal set of permissions. At a minimum, contents: read is needed for checkouts and for actions that read repository data; other capabilities such as managing pull requests or issues are not used directly in the snippet shown. The actions-cool/check-user-permission action and jakob-fritz/github2lab_action both operate using the GITHUB_TOKEN but do not obviously require write permissions here. Therefore we can safely set:

permissions:
  contents: read

This applies to all three jobs (check_permission, mirror_to_gitlab, and get_artifacts_from_other_workflow). No additional imports or methods are needed; this is a pure YAML configuration change within .github/workflows/gitlab_ci.yml.

Suggested changeset 1
.github/workflows/gitlab_ci.yml

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/.github/workflows/gitlab_ci.yml b/.github/workflows/gitlab_ci.yml
--- a/.github/workflows/gitlab_ci.yml
+++ b/.github/workflows/gitlab_ci.yml
@@ -9,6 +9,9 @@
   schedule:
     - cron: '2 5 * * 1'
 
+permissions:
+  contents: read
+
 jobs:
   check_permission:
     runs-on: ubuntu-latest
EOF
@@ -9,6 +9,9 @@
schedule:
- cron: '2 5 * * 1'

permissions:
contents: read

jobs:
check_permission:
runs-on: ubuntu-latest
Copilot is powered by AI and may make mistakes. Always verify output.
runs-on: ubuntu-latest
needs:
- mirror_to_gitlab
steps:
- name: Download artifacts from this workflow
uses: actions/download-artifact@v4
with:
merge-multiple: true
path: ./github_ci_artifacts
- name: Set env-var
id: get_id
uses: actions/github-script@v7
env:
workflow_filename: 'ci_pipeline.yml'
with:
script: |
if (context.eventName == "pull_request_target") {
var used_sha = context.payload.pull_request.head.sha;
var used_event = "pull_request";
} else {
var used_sha = context.sha;
var used_event = context.eventName;
}
const result = await github.request('GET /repos/{owner}/{repo}/actions/workflows/{workflow_id}/runs', {
owner: context.repo.owner,
repo: context.repo.repo,
workflow_id: process.env.workflow_filename,
headers: {
'X-GitHub-Api-Version': '2022-11-28',
'accept': 'application/vnd.github+json'
},
head_sha: used_sha,
event: used_event
})
console.log("SHA of commit " + used_sha);
console.log("Found runs of workflow: " + result.data.total_count);
if (result.data.total_count == 1) {
console.log("Found workflow has id: " + result.data.workflow_runs[0].id);
return result.data.workflow_runs[0].id
} else {
console.log("Logging all found workflow ids:");
for (var i = 0; i < result.data.workflow_runs.length; i++) {
console.log(result.data.workflow_runs[i].id);
}
console.log("Returned workflow id is: " + result.data.workflow_runs[0].id);
return result.data.workflow_runs[0].id
}
- name: Wait for other workflow to finish
env:
RUN_ID: ${{ steps.get_id.outputs.result }}
POLL_TIMEOUT: 10
run: |
ci_conclusion="pending"
echo "Querying status of workflow $RUN_ID for repo $GITHUB_REPOSITORY"
until [ "$ci_conclusion" != "pending" ] && [ "$ci_conclusion" != "in_progress" ] && [ "$ci_conclusion" != "null" ]
do
# Wait some seconds
sleep "$POLL_TIMEOUT"
# Get the current state of the pipeline and the url of the website
run_reply=$(curl --header "'X-GitHub-Api-Version': '2022-11-28', 'accept': 'application/vnd.github+json'" --silent "https://api.github.com/repos/$GITHUB_REPOSITORY/actions/runs/$RUN_ID")
ci_conclusion=$(jq -n "$run_reply" | jq -r .conclusion)
echo "Current pipeline status: ${ci_conclusion}"
http_status=$(jq -n "$run_reply" | jq -r .status)
if [ "$http_status" != 200 ] && [[ "$http_status" =~ ^[0-9]+$ ]]; then
echo "Request returned status: ${http_status}"
exit 1
fi
done
# Set exit code for success or failure (everything non-success)
if [ "$ci_conclusion" = "success" ]; then
exit 0
else
exit 1
fi
- name: Download artifacts from other workflow
uses: actions/download-artifact@v4
with:
merge-multiple: true
run-id: ${{ steps.get_id.outputs.result }}
github-token: ${{ secrets.ACTION_READ_TOKEN }}
path: ./github_ci_artifacts
- name: Uploading artifacts
uses: actions/upload-artifact@v4
with:
name: Github_CI_artifacts
path: |
./github_ci_artifacts/*
Comment on lines +136 to +222

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: {}

Copilot Autofix

AI 3 months ago

In general, the fix is to add an explicit permissions block either at the workflow root (to apply to all jobs) or per job, granting only the minimal permissions needed. For this workflow, contents: read is a safe baseline, and additional permissions can be granted only where clearly required. The mirror_to_gitlab job uses secrets.GITHUB_TOKEN in an action that likely needs to read repo contents and CI status but not push code, so contents: read is appropriate. The get_artifacts_from_other_workflow job uses actions/github-script to list workflow runs and curl plus an explicit token for runs/artifacts; for listing and reading artifacts, actions: read and contents: read are sufficient, and write-level scopes are not needed.

The single best minimally invasive change that satisfies CodeQL is to add a root-level permissions block after the on: key with restrictive settings, e.g. contents: read and actions: read. This will apply to all jobs (check_permission, mirror_to_gitlab, and get_artifacts_from_other_workflow) since none define their own permissions. No other functional changes are necessary because these jobs are already using the default GITHUB_TOKEN; we are only reducing its capabilities to the level needed for read-only operations against code and workflows.

Concretely, in .github/workflows/gitlab_ci.yml, insert:

permissions:
  contents: read
  actions: read

between the on: block (ending at line 10) and the jobs: block (line 12). No imports or additional methods are required.

Suggested changeset 1
.github/workflows/gitlab_ci.yml

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/.github/workflows/gitlab_ci.yml b/.github/workflows/gitlab_ci.yml
--- a/.github/workflows/gitlab_ci.yml
+++ b/.github/workflows/gitlab_ci.yml
@@ -9,6 +9,10 @@
   schedule:
     - cron: '2 5 * * 1'
 
+permissions:
+  contents: read
+  actions: read
+
 jobs:
   check_permission:
     runs-on: ubuntu-latest
EOF
@@ -9,6 +9,10 @@
schedule:
- cron: '2 5 * * 1'

permissions:
contents: read
actions: read

jobs:
check_permission:
runs-on: ubuntu-latest
Copilot is powered by AI and may make mistakes. Always verify output.
4 changes: 3 additions & 1 deletion .github/workflows/postprocess.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,11 @@ jobs:
run: |
genbadge coverage -i coverage.xml -o htmlcov/coverage-badge.svg
- name: Upload coverage reports to Codecov
uses: codecov/codecov-action@v4
uses: codecov/codecov-action@v5
with:
token: ${{ secrets.CODECOV }}
fail_ci_if_error: true
verbose: true

# - name: Generate benchmark report
# uses: pancetta/github-action-benchmark@v1
Expand Down
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,12 @@ implemented.
[PETSc](http://www.mcs.anl.gov/petsc/) (through
[petsc4py](https://bitbucket.org/petsc/petsc4py))
- Continuous integration via [GitHub
<<<<<<< HEAD
Actions](https://github.com/Parallel-in-Time/pySDC/actions) and
[Gitlab CI](https://gitlab.hzdr.de/r.speck/pysdc/-/pipelines) (through the [GitHub2Gitlab Action](https://github.com/jakob-fritz/github2lab_action))
=======
Actions](https://github.com/Parallel-in-Time/pySDC/actions)
>>>>>>> d3e0bb943e63560d7b018cac8a624c1883aa0c7b
- Fully compatible with Python 3.10 - 3.13, runs at least on Ubuntu

## Getting started
Expand Down
3 changes: 3 additions & 0 deletions docs/contrib/02_continuous_integration.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,8 +112,11 @@ pytest -v pySDC/tests

## Running CI on HPC from pull requests

<<<<<<< HEAD
=======
> :warning: **Note:** The GitLab mirror integration is currently disabled due to technical issues. This section describes functionality that is temporarily unavailable.

>>>>>>> d3e0bb943e63560d7b018cac8a624c1883aa0c7b
By syncing the GitHub repository to a certain Gitlab instance, CI-Jobs can be run on HPC machines. This can be helpful for benchmarks or when running on accelerators that are not available as GitHub runners.

For security and accounting reasons, a few extra steps are needed in order to run the contents of a pull request on HPC:
Expand Down
3 changes: 3 additions & 0 deletions pySDC/core/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@
Module containing utility classe(s) from which inherit some of the pySDC base
classes.
"""
<<<<<<< HEAD
=======

>>>>>>> d3e0bb943e63560d7b018cac8a624c1883aa0c7b
from pySDC.core.errors import ReadOnlyError


Expand Down
4 changes: 4 additions & 0 deletions pySDC/core/hooks.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import logging
from collections import namedtuple

<<<<<<< HEAD

=======
>>>>>>> d3e0bb943e63560d7b018cac8a624c1883aa0c7b
# metadata with defaults
meta_data = {
'process': None,
Expand Down
4 changes: 4 additions & 0 deletions pySDC/core/sweeper.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@
from pySDC.core.collocation import CollBase
from pySDC.helpers.pysdc_helper import FrozenClass

<<<<<<< HEAD

=======
>>>>>>> d3e0bb943e63560d7b018cac8a624c1883aa0c7b
# Organize QDeltaGenerator class in dict[type(QDeltaGenerator),set(str)] to retrieve aliases
QDELTA_GENERATORS_ALIASES = {v: set() for v in set(QDELTA_GENERATORS.values())}
for k, v in QDELTA_GENERATORS.items():
Expand Down
3 changes: 3 additions & 0 deletions pySDC/helpers/fieldsIO.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,10 @@
To use MPI collective writing, you need to call first the class methods :class:`Rectilinear.setupMPI` (cf their docstring).
Also, `Rectilinear.setHeader` **must be given the global grids coordinates**, whether the code is run in parallel or not.
"""
<<<<<<< HEAD
=======

>>>>>>> d3e0bb943e63560d7b018cac8a624c1883aa0c7b
import os
import numpy as np
from typing import Type, TypeVar
Expand Down
3 changes: 3 additions & 0 deletions pySDC/helpers/testing.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@

Helpers module for testing utilities
"""
<<<<<<< HEAD
=======

>>>>>>> d3e0bb943e63560d7b018cac8a624c1883aa0c7b
import os
import json
import warnings
Expand Down
3 changes: 3 additions & 0 deletions pySDC/helpers/vtkIO.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@
"""
Helper functions for VTK files IO (to be used with Paraview or PyVista)
"""
<<<<<<< HEAD
=======

>>>>>>> d3e0bb943e63560d7b018cac8a624c1883aa0c7b
import os
import vtk
from vtkmodules.util import numpy_support
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,8 +114,15 @@ def estimate_embedded_error_serial(self, L):
else:
return comm.bcast(abs(L.uold[comm.rank + 1] - L.u[comm.rank + 1]), root=comm.size - 1)
else:
<<<<<<< HEAD
raise NotImplementedError(
f"Don't know how to estimate embedded error for sweeper type \
\"{self.params.sweeper_type}\""
)
=======
raise NotImplementedError(f"Don't know how to estimate embedded error for sweeper type \
\"{self.params.sweeper_type}\"")
>>>>>>> d3e0bb943e63560d7b018cac8a624c1883aa0c7b

def setup_status_variables(self, controller, **kwargs):
"""
Expand Down Expand Up @@ -207,8 +214,15 @@ def post_iteration_processing(self, controller, S, **kwargs):
None
"""
if len(S.levels) > 1 and len(controller.MS) > 1:
<<<<<<< HEAD
raise NotImplementedError(
"Embedded error estimate only works for serial multi-level or parallel single \
level"
)
=======
raise NotImplementedError("Embedded error estimate only works for serial multi-level or parallel single \
level")
>>>>>>> d3e0bb943e63560d7b018cac8a624c1883aa0c7b

if S.status.iter > 0 or self.params.sweeper_type == "RK":
if self.params.averaged:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -139,8 +139,15 @@ def store_values(self, S, **kwargs):
elif type(f) == mesh:
self.prev.f[oldest_val] = f
else:
<<<<<<< HEAD
raise DataError(
f"Unable to store f from datatype {type(f)}, extrapolation based error estimate only\
works with types imex_mesh and mesh"
)
=======
raise DataError(f"Unable to store f from datatype {type(f)}, extrapolation based error estimate only\
works with types imex_mesh and mesh")
>>>>>>> d3e0bb943e63560d7b018cac8a624c1883aa0c7b

# store the rest of the values
self.prev.u[oldest_val] = S.levels[0].u[-1]
Expand Down Expand Up @@ -479,8 +486,15 @@ def post_iteration_processing(self, controller, S, **kwargs):
elif type(lvl.f[0]) == mesh:
f = [lvl.f[i] if self.coeff.f[i] else 0.0 for i in range(len(lvl.f) - 1)]
else:
<<<<<<< HEAD
raise DataError(
f"Unable to store f from datatype {type(lvl.f[0])}, extrapolation based error estimate only\
works with types imex_mesh and mesh"
)
=======
raise DataError(f"Unable to store f from datatype {type(lvl.f[0])}, extrapolation based error estimate only\
works with types imex_mesh and mesh")
>>>>>>> d3e0bb943e63560d7b018cac8a624c1883aa0c7b

# compute the error with the weighted sum
if self.comm:
Expand Down
Loading