fix ci
Some checks failed
Dev CI / Backend — Lint (push) Failing after 1m5s
Dev CI / Backend — Unit Tests (push) Has been skipped
Dev CI / Security gate (push) Failing after 1m20s
Dev CI / Frontend — Lint & Type-check (push) Successful in 1m46s
Dev CI / Frontend — Unit Tests (push) Successful in 1m21s
Dev CI / Notify Failure (push) Has been skipped
Some checks failed
Dev CI / Backend — Lint (push) Failing after 1m5s
Dev CI / Backend — Unit Tests (push) Has been skipped
Dev CI / Security gate (push) Failing after 1m20s
Dev CI / Frontend — Lint & Type-check (push) Successful in 1m46s
Dev CI / Frontend — Unit Tests (push) Successful in 1m21s
Dev CI / Notify Failure (push) Has been skipped
This commit is contained in:
parent
b745f14445
commit
e055af9afe
@ -3,20 +3,13 @@ description: Dependency, secrets, infrastructure and workflow checks for Gitea 1
|
|||||||
runs:
|
runs:
|
||||||
using: composite
|
using: composite
|
||||||
steps:
|
steps:
|
||||||
- uses: https://github.com/actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
|
- uses: ./.gitea/actions/setup-node
|
||||||
with:
|
|
||||||
node-version: '22'
|
|
||||||
- uses: ./.gitea/actions/setup-trivy
|
- uses: ./.gitea/actions/setup-trivy
|
||||||
- name: Validate workflows and deployment checks
|
- name: Validate workflows and deployment checks
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
archive="$RUNNER_TEMP/actionlint.tar.gz"
|
actionlint_bin=$(bash scripts/ci/install-tool.sh actionlint)
|
||||||
curl --fail --silent --show-error --location --retry 3 --max-time 120 \
|
ACTIONLINT_BIN="$actionlint_bin" bash scripts/ci/validate-workflows.sh
|
||||||
https://github.com/rhysd/actionlint/releases/download/v1.7.12/actionlint_1.7.12_linux_amd64.tar.gz \
|
|
||||||
--output "$archive"
|
|
||||||
echo "8aca8db96f1b94770f1b0d72b6dddcb1ebb8123cb3712530b08cc387b349a3d8 $archive" | sha256sum --check --strict
|
|
||||||
tar -xzf "$archive" -C "$RUNNER_TEMP" actionlint
|
|
||||||
ACTIONLINT_BIN="$RUNNER_TEMP/actionlint" bash scripts/ci/validate-workflows.sh
|
|
||||||
- name: Audit dependencies, secrets and infrastructure
|
- name: Audit dependencies, secrets and infrastructure
|
||||||
shell: bash
|
shell: bash
|
||||||
run: bash scripts/ci/security-audit.sh
|
run: bash scripts/ci/security-audit.sh
|
||||||
|
|||||||
11
.gitea/actions/setup-node/action.yml
Normal file
11
.gitea/actions/setup-node/action.yml
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
name: Install and activate Node 22
|
||||||
|
description: Set up Node and verify the executable selected by the Gitea runner.
|
||||||
|
runs:
|
||||||
|
using: composite
|
||||||
|
steps:
|
||||||
|
- uses: https://github.com/actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
|
||||||
|
with:
|
||||||
|
node-version: '22'
|
||||||
|
- name: Activate and verify Node 22
|
||||||
|
shell: bash
|
||||||
|
run: bash scripts/ci/activate-node.sh
|
||||||
@ -1,16 +1,9 @@
|
|||||||
name: Install verified Trivy
|
name: Install verified Trivy
|
||||||
description: Install a pinned scanner with a checked SHA256, without elevated privileges.
|
description: Install a pinned native scanner with a checked SHA256.
|
||||||
runs:
|
runs:
|
||||||
using: composite
|
using: composite
|
||||||
steps:
|
steps:
|
||||||
- shell: bash
|
- shell: bash
|
||||||
run: |
|
run: |
|
||||||
set -euo pipefail
|
trivy_bin=$(bash scripts/ci/install-tool.sh trivy)
|
||||||
install_dir="$RUNNER_TEMP/trivy-bin"
|
"$trivy_bin" --version
|
||||||
mkdir -p "$install_dir"
|
|
||||||
curl --fail --silent --show-error --location --retry 3 --max-time 120 \
|
|
||||||
https://github.com/aquasecurity/trivy/releases/download/v0.74.0/trivy_0.74.0_Linux-64bit.tar.gz \
|
|
||||||
--output "$install_dir/trivy.tar.gz"
|
|
||||||
echo "2ae6fe3ee734b7fdf11335663e18c75ea12dccc76062f09f164a3b0f8be4371a $install_dir/trivy.tar.gz" | sha256sum --check --strict
|
|
||||||
tar -xzf "$install_dir/trivy.tar.gz" -C "$install_dir" trivy
|
|
||||||
echo "$install_dir" >> "$GITHUB_PATH"
|
|
||||||
|
|||||||
@ -30,7 +30,6 @@ on:
|
|||||||
|
|
||||||
env:
|
env:
|
||||||
REGISTRY: rg.fr-par.scw.cloud/weworkstudio
|
REGISTRY: rg.fr-par.scw.cloud/weworkstudio
|
||||||
NODE_VERSION: '22'
|
|
||||||
K8S_NAMESPACE: xpeditis-prod
|
K8S_NAMESPACE: xpeditis-prod
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
@ -54,9 +53,7 @@ jobs:
|
|||||||
- uses: https://github.com/actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
|
- uses: https://github.com/actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- uses: https://github.com/actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
|
- uses: ./.gitea/actions/setup-node
|
||||||
with:
|
|
||||||
node-version: ${{ env.NODE_VERSION }}
|
|
||||||
- run: npm ci --legacy-peer-deps
|
- run: npm ci --legacy-peer-deps
|
||||||
- run: npm run lint -- --no-fix
|
- run: npm run lint -- --no-fix
|
||||||
|
|
||||||
@ -70,9 +67,7 @@ jobs:
|
|||||||
- uses: https://github.com/actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
|
- uses: https://github.com/actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- uses: https://github.com/actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
|
- uses: ./.gitea/actions/setup-node
|
||||||
with:
|
|
||||||
node-version: ${{ env.NODE_VERSION }}
|
|
||||||
- run: npm ci --legacy-peer-deps
|
- run: npm ci --legacy-peer-deps
|
||||||
- run: npm run lint
|
- run: npm run lint
|
||||||
- run: npm run type-check
|
- run: npm run type-check
|
||||||
@ -88,9 +83,7 @@ jobs:
|
|||||||
- uses: https://github.com/actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
|
- uses: https://github.com/actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- uses: https://github.com/actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
|
- uses: ./.gitea/actions/setup-node
|
||||||
with:
|
|
||||||
node-version: ${{ env.NODE_VERSION }}
|
|
||||||
- run: npm ci --legacy-peer-deps
|
- run: npm ci --legacy-peer-deps
|
||||||
- run: npm test -- --ci --runInBand
|
- run: npm test -- --ci --runInBand
|
||||||
|
|
||||||
@ -105,9 +98,7 @@ jobs:
|
|||||||
- uses: https://github.com/actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
|
- uses: https://github.com/actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- uses: https://github.com/actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
|
- uses: ./.gitea/actions/setup-node
|
||||||
with:
|
|
||||||
node-version: ${{ env.NODE_VERSION }}
|
|
||||||
- run: npm ci --legacy-peer-deps
|
- run: npm ci --legacy-peer-deps
|
||||||
- run: npm test -- --ci --runInBand
|
- run: npm test -- --ci --runInBand
|
||||||
|
|
||||||
@ -149,6 +140,10 @@ jobs:
|
|||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
# Cet arbre Git est identique à celui de la release preprod vérifiée.
|
# Cet arbre Git est identique à celui de la release preprod vérifiée.
|
||||||
ref: ${{ github.sha }}
|
ref: ${{ github.sha }}
|
||||||
|
- uses: https://github.com/docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # v3
|
||||||
|
with:
|
||||||
|
platforms: amd64,arm64
|
||||||
|
cache-image: false
|
||||||
- uses: https://github.com/docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3
|
- uses: https://github.com/docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3
|
||||||
- uses: https://github.com/docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3
|
- uses: https://github.com/docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3
|
||||||
with:
|
with:
|
||||||
@ -173,7 +168,7 @@ jobs:
|
|||||||
- name: Contrôle — l'URL de preprod ne doit pas figurer dans le bundle
|
- name: Contrôle — l'URL de preprod ne doit pas figurer dans le bundle
|
||||||
run: |
|
run: |
|
||||||
IMAGE="${{ env.REGISTRY }}/xpeditis-frontend@${{ steps.build.outputs.digest }}"
|
IMAGE="${{ env.REGISTRY }}/xpeditis-frontend@${{ steps.build.outputs.digest }}"
|
||||||
CID=$(docker create "$IMAGE")
|
CID=$(docker create --platform linux/amd64 "$IMAGE")
|
||||||
trap 'docker rm "$CID" >/dev/null' EXIT
|
trap 'docker rm "$CID" >/dev/null' EXIT
|
||||||
docker cp "$CID:/app/.next" /tmp/next-check
|
docker cp "$CID:/app/.next" /tmp/next-check
|
||||||
test -d /tmp/next-check
|
test -d /tmp/next-check
|
||||||
@ -260,14 +255,8 @@ jobs:
|
|||||||
|
|
||||||
- name: Installer le client Hetzner
|
- name: Installer le client Hetzner
|
||||||
run: |
|
run: |
|
||||||
mkdir -p "$RUNNER_TEMP/hcloud-bin"
|
hcloud_bin=$(bash scripts/ci/install-tool.sh hcloud)
|
||||||
curl --fail --silent --show-error --location --retry 3 --max-time 120 \
|
"$hcloud_bin" version
|
||||||
https://github.com/hetznercloud/cli/releases/download/v1.49.0/hcloud-linux-amd64.tar.gz \
|
|
||||||
--output "$RUNNER_TEMP/hcloud.tar.gz"
|
|
||||||
echo "dc6e5b0e6eaf9ef2baa5473a3eb49a11e80e72cdf2a01fdf7b0af975410e79cc $RUNNER_TEMP/hcloud.tar.gz" | sha256sum --check --strict
|
|
||||||
tar -xzf "$RUNNER_TEMP/hcloud.tar.gz" -C "$RUNNER_TEMP/hcloud-bin" hcloud
|
|
||||||
echo "$RUNNER_TEMP/hcloud-bin" >> "$GITHUB_PATH"
|
|
||||||
"$RUNNER_TEMP/hcloud-bin/hcloud" version
|
|
||||||
|
|
||||||
- name: Ouvrir le port 22 pour l'IP de ce runner
|
- name: Ouvrir le port 22 pour l'IP de ce runner
|
||||||
env:
|
env:
|
||||||
|
|||||||
@ -19,7 +19,6 @@ on:
|
|||||||
|
|
||||||
env:
|
env:
|
||||||
REGISTRY: rg.fr-par.scw.cloud/weworkstudio
|
REGISTRY: rg.fr-par.scw.cloud/weworkstudio
|
||||||
NODE_VERSION: '22'
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
security:
|
security:
|
||||||
@ -42,9 +41,7 @@ jobs:
|
|||||||
- uses: https://github.com/actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
|
- uses: https://github.com/actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- uses: https://github.com/actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
|
- uses: ./.gitea/actions/setup-node
|
||||||
with:
|
|
||||||
node-version: ${{ env.NODE_VERSION }}
|
|
||||||
- run: npm ci --legacy-peer-deps
|
- run: npm ci --legacy-peer-deps
|
||||||
- run: npm run lint -- --no-fix
|
- run: npm run lint -- --no-fix
|
||||||
|
|
||||||
@ -58,9 +55,7 @@ jobs:
|
|||||||
- uses: https://github.com/actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
|
- uses: https://github.com/actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- uses: https://github.com/actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
|
- uses: ./.gitea/actions/setup-node
|
||||||
with:
|
|
||||||
node-version: ${{ env.NODE_VERSION }}
|
|
||||||
- run: npm ci --legacy-peer-deps
|
- run: npm ci --legacy-peer-deps
|
||||||
- run: npm run lint
|
- run: npm run lint
|
||||||
- run: npm run type-check
|
- run: npm run type-check
|
||||||
@ -77,9 +72,7 @@ jobs:
|
|||||||
- uses: https://github.com/actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
|
- uses: https://github.com/actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- uses: https://github.com/actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
|
- uses: ./.gitea/actions/setup-node
|
||||||
with:
|
|
||||||
node-version: ${{ env.NODE_VERSION }}
|
|
||||||
- run: npm ci --legacy-peer-deps
|
- run: npm ci --legacy-peer-deps
|
||||||
- run: npm test -- --ci --runInBand
|
- run: npm test -- --ci --runInBand
|
||||||
|
|
||||||
@ -94,9 +87,7 @@ jobs:
|
|||||||
- uses: https://github.com/actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
|
- uses: https://github.com/actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- uses: https://github.com/actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
|
- uses: ./.gitea/actions/setup-node
|
||||||
with:
|
|
||||||
node-version: ${{ env.NODE_VERSION }}
|
|
||||||
- run: npm ci --legacy-peer-deps
|
- run: npm ci --legacy-peer-deps
|
||||||
- run: npm test -- --ci --runInBand
|
- run: npm test -- --ci --runInBand
|
||||||
|
|
||||||
@ -133,9 +124,7 @@ jobs:
|
|||||||
- uses: https://github.com/actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
|
- uses: https://github.com/actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- uses: https://github.com/actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
|
- uses: ./.gitea/actions/setup-node
|
||||||
with:
|
|
||||||
node-version: ${{ env.NODE_VERSION }}
|
|
||||||
- run: npm ci --legacy-peer-deps
|
- run: npm ci --legacy-peer-deps
|
||||||
- name: Run integration tests
|
- name: Run integration tests
|
||||||
env:
|
env:
|
||||||
@ -178,7 +167,8 @@ jobs:
|
|||||||
run: echo "short=$(echo ${{ github.sha }} | cut -c1-7)" >> $GITHUB_OUTPUT
|
run: echo "short=$(echo ${{ github.sha }} | cut -c1-7)" >> $GITHUB_OUTPUT
|
||||||
- uses: https://github.com/docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # v3
|
- uses: https://github.com/docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # v3
|
||||||
with:
|
with:
|
||||||
platforms: arm64
|
platforms: amd64,arm64
|
||||||
|
cache-image: false
|
||||||
- uses: https://github.com/docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3
|
- uses: https://github.com/docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3
|
||||||
- uses: https://github.com/docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3
|
- uses: https://github.com/docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3
|
||||||
with:
|
with:
|
||||||
@ -213,7 +203,8 @@ jobs:
|
|||||||
run: echo "short=$(echo ${{ github.sha }} | cut -c1-7)" >> $GITHUB_OUTPUT
|
run: echo "short=$(echo ${{ github.sha }} | cut -c1-7)" >> $GITHUB_OUTPUT
|
||||||
- uses: https://github.com/docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # v3
|
- uses: https://github.com/docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # v3
|
||||||
with:
|
with:
|
||||||
platforms: arm64
|
platforms: amd64,arm64
|
||||||
|
cache-image: false
|
||||||
- uses: https://github.com/docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3
|
- uses: https://github.com/docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3
|
||||||
- uses: https://github.com/docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3
|
- uses: https://github.com/docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3
|
||||||
with:
|
with:
|
||||||
@ -251,7 +242,8 @@ jobs:
|
|||||||
run: echo "short=$(echo ${{ github.sha }} | cut -c1-7)" >> $GITHUB_OUTPUT
|
run: echo "short=$(echo ${{ github.sha }} | cut -c1-7)" >> $GITHUB_OUTPUT
|
||||||
- uses: https://github.com/docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # v3
|
- uses: https://github.com/docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # v3
|
||||||
with:
|
with:
|
||||||
platforms: arm64
|
platforms: amd64,arm64
|
||||||
|
cache-image: false
|
||||||
- uses: https://github.com/docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3
|
- uses: https://github.com/docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3
|
||||||
- uses: https://github.com/docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3
|
- uses: https://github.com/docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3
|
||||||
with:
|
with:
|
||||||
|
|||||||
@ -6,9 +6,6 @@ on:
|
|||||||
pull_request:
|
pull_request:
|
||||||
branches: [dev]
|
branches: [dev]
|
||||||
|
|
||||||
env:
|
|
||||||
NODE_VERSION: '22'
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
security:
|
security:
|
||||||
name: Security gate
|
name: Security gate
|
||||||
@ -29,9 +26,7 @@ jobs:
|
|||||||
- uses: https://github.com/actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
|
- uses: https://github.com/actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- uses: https://github.com/actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
|
- uses: ./.gitea/actions/setup-node
|
||||||
with:
|
|
||||||
node-version: ${{ env.NODE_VERSION }}
|
|
||||||
- run: npm ci --legacy-peer-deps
|
- run: npm ci --legacy-peer-deps
|
||||||
- run: npm run lint -- --no-fix
|
- run: npm run lint -- --no-fix
|
||||||
|
|
||||||
@ -45,9 +40,7 @@ jobs:
|
|||||||
- uses: https://github.com/actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
|
- uses: https://github.com/actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- uses: https://github.com/actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
|
- uses: ./.gitea/actions/setup-node
|
||||||
with:
|
|
||||||
node-version: ${{ env.NODE_VERSION }}
|
|
||||||
- run: npm ci --legacy-peer-deps
|
- run: npm ci --legacy-peer-deps
|
||||||
- run: npm run lint
|
- run: npm run lint
|
||||||
- run: npm run type-check
|
- run: npm run type-check
|
||||||
@ -63,9 +56,7 @@ jobs:
|
|||||||
- uses: https://github.com/actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
|
- uses: https://github.com/actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- uses: https://github.com/actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
|
- uses: ./.gitea/actions/setup-node
|
||||||
with:
|
|
||||||
node-version: ${{ env.NODE_VERSION }}
|
|
||||||
- run: npm ci --legacy-peer-deps
|
- run: npm ci --legacy-peer-deps
|
||||||
- run: npm test -- --ci --runInBand
|
- run: npm test -- --ci --runInBand
|
||||||
|
|
||||||
@ -80,9 +71,7 @@ jobs:
|
|||||||
- uses: https://github.com/actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
|
- uses: https://github.com/actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- uses: https://github.com/actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
|
- uses: ./.gitea/actions/setup-node
|
||||||
with:
|
|
||||||
node-version: ${{ env.NODE_VERSION }}
|
|
||||||
- run: npm ci --legacy-peer-deps
|
- run: npm ci --legacy-peer-deps
|
||||||
- run: npm test -- --ci --runInBand
|
- run: npm test -- --ci --runInBand
|
||||||
|
|
||||||
|
|||||||
@ -8,9 +8,6 @@ on:
|
|||||||
pull_request:
|
pull_request:
|
||||||
branches: [preprod, main]
|
branches: [preprod, main]
|
||||||
|
|
||||||
env:
|
|
||||||
NODE_VERSION: '22'
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
security:
|
security:
|
||||||
name: Security gate
|
name: Security gate
|
||||||
@ -31,9 +28,7 @@ jobs:
|
|||||||
- uses: https://github.com/actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
|
- uses: https://github.com/actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- uses: https://github.com/actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
|
- uses: ./.gitea/actions/setup-node
|
||||||
with:
|
|
||||||
node-version: ${{ env.NODE_VERSION }}
|
|
||||||
- run: npm ci --legacy-peer-deps
|
- run: npm ci --legacy-peer-deps
|
||||||
- run: npm run lint -- --no-fix
|
- run: npm run lint -- --no-fix
|
||||||
|
|
||||||
@ -47,9 +42,7 @@ jobs:
|
|||||||
- uses: https://github.com/actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
|
- uses: https://github.com/actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- uses: https://github.com/actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
|
- uses: ./.gitea/actions/setup-node
|
||||||
with:
|
|
||||||
node-version: ${{ env.NODE_VERSION }}
|
|
||||||
- run: npm ci --legacy-peer-deps
|
- run: npm ci --legacy-peer-deps
|
||||||
- run: npm run lint
|
- run: npm run lint
|
||||||
- run: npm run type-check
|
- run: npm run type-check
|
||||||
@ -65,9 +58,7 @@ jobs:
|
|||||||
- uses: https://github.com/actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
|
- uses: https://github.com/actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- uses: https://github.com/actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
|
- uses: ./.gitea/actions/setup-node
|
||||||
with:
|
|
||||||
node-version: ${{ env.NODE_VERSION }}
|
|
||||||
- run: npm ci --legacy-peer-deps
|
- run: npm ci --legacy-peer-deps
|
||||||
- run: npm test -- --ci --runInBand
|
- run: npm test -- --ci --runInBand
|
||||||
|
|
||||||
@ -82,9 +73,7 @@ jobs:
|
|||||||
- uses: https://github.com/actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
|
- uses: https://github.com/actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- uses: https://github.com/actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
|
- uses: ./.gitea/actions/setup-node
|
||||||
with:
|
|
||||||
node-version: ${{ env.NODE_VERSION }}
|
|
||||||
- run: npm ci --legacy-peer-deps
|
- run: npm ci --legacy-peer-deps
|
||||||
- run: npm test -- --ci --runInBand
|
- run: npm test -- --ci --runInBand
|
||||||
|
|
||||||
@ -121,9 +110,7 @@ jobs:
|
|||||||
- uses: https://github.com/actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
|
- uses: https://github.com/actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- uses: https://github.com/actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
|
- uses: ./.gitea/actions/setup-node
|
||||||
with:
|
|
||||||
node-version: ${{ env.NODE_VERSION }}
|
|
||||||
- run: npm ci --legacy-peer-deps
|
- run: npm ci --legacy-peer-deps
|
||||||
- name: Run integration tests
|
- name: Run integration tests
|
||||||
env:
|
env:
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
La version du serveur `https://gitea.ops.xpeditis.com` a été vérifiée via
|
La version du serveur `https://gitea.ops.xpeditis.com` a été vérifiée via
|
||||||
`/api/v1/version` : **1.22.6**. Les pipelines ciblent Gitea Actions / act_runner,
|
`/api/v1/version` : **1.22.6**. Les pipelines ciblent Gitea Actions / act_runner,
|
||||||
avec des jobs exécutés dans des conteneurs Linux AMD64.
|
avec des jobs exécutés dans des conteneurs Linux AMD64 ou ARM64.
|
||||||
|
|
||||||
## Workflows et contrôles
|
## Workflows et contrôles
|
||||||
|
|
||||||
@ -32,7 +32,7 @@ lorsqu'aucun correctif n'est disponible. Les erreurs de scanner ou de registre
|
|||||||
échouent aussi : aucune exclusion générale ni échec masqué n'est ajouté.
|
échouent aussi : aucune exclusion générale ni échec masqué n'est ajouté.
|
||||||
Les installations applicatives utilisent `npm ci`, le runtime est Node 22 et les
|
Les installations applicatives utilisent `npm ci`, le runtime est Node 22 et les
|
||||||
actions sont épinglées par SHA. Trivy, Actionlint et Hetzner CLI sont téléchargés
|
actions sont épinglées par SHA. Trivy, Actionlint et Hetzner CLI sont téléchargés
|
||||||
avec vérification SHA256. Le lint backend ne réécrit plus les fichiers.
|
avec détection native AMD64/ARM64 et vérification SHA256. Le lint backend ne réécrit plus les fichiers.
|
||||||
|
|
||||||
Les rapports sont joints aux exécutions **Gitea Actions** avec
|
Les rapports sont joints aux exécutions **Gitea Actions** avec
|
||||||
`actions/upload-artifact` **v3**, compatible avec le protocole de cette version
|
`actions/upload-artifact` **v3**, compatible avec le protocole de cette version
|
||||||
@ -74,7 +74,7 @@ Gitea 1.22 ignore notamment `concurrency`, `permissions`, `environment`, les dé
|
|||||||
YAML de jobs et `workflow_dispatch`. Ces paramètres ne sont donc pas présentés
|
YAML de jobs et `workflow_dispatch`. Ces paramètres ne sont donc pas présentés
|
||||||
comme des protections effectives dans les workflows adaptés.
|
comme des protections effectives dans les workflows adaptés.
|
||||||
|
|
||||||
1. Activer Actions dans le dépôt et disposer d'un runner Docker Linux AMD64 avec
|
1. Activer Actions dans le dépôt et disposer d'un runner Docker Linux AMD64 ou ARM64 avec
|
||||||
le label `ubuntu-latest`, Git, Bash, Python 3, curl, tar, timeout et les outils
|
le label `ubuntu-latest`, Git, Bash, Python 3, curl, tar, timeout et les outils
|
||||||
Docker. Les builds multiarchitecture ont besoin du support QEMU/binfmt.
|
Docker. Les builds multiarchitecture ont besoin du support QEMU/binfmt.
|
||||||
Les services d'intégration sont joints via `postgres` et `redis`, sans ports
|
Les services d'intégration sont joints via `postgres` et `redis`, sans ports
|
||||||
@ -142,7 +142,7 @@ ces configurations ne signale plus ce secret après modification.
|
|||||||
|
|
||||||
## Validation
|
## Validation
|
||||||
|
|
||||||
Les 19 tests offline de promotion et santé passent : arbre différent, marqueurs
|
Les 25 tests offline de promotion et santé passent : arbre différent, marqueurs
|
||||||
manquants, panne du registre, digest invalide, mauvaise branche, saisie hostile et
|
manquants, panne du registre, digest invalide, mauvaise branche, saisie hostile et
|
||||||
échec HTTP sont refusés. Les tests vérifient aussi que les échecs et délais des
|
échec HTTP sont refusés. Les tests vérifient aussi que les échecs et délais des
|
||||||
audits restent bloquants et que le rapport masque les valeurs de secrets. Actionlint valide la syntaxe après normalisation des URLs
|
audits restent bloquants et que le rapport masque les valeurs de secrets. Actionlint valide la syntaxe après normalisation des URLs
|
||||||
@ -152,6 +152,19 @@ d'actions Gitea ; ce contrôle ne remplace pas une exécution avec act_runner.
|
|||||||
ACTIONLINT_BIN=/chemin/vers/actionlint bash scripts/ci/validate-workflows.sh
|
ACTIONLINT_BIN=/chemin/vers/actionlint bash scripts/ci/validate-workflows.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
|
La correction du 23 septembre 2026 a aussi été exécutée dans un conteneur Linux
|
||||||
|
ARM64 : Trivy 0.74.0, Actionlint 1.7.12 et Hetzner CLI 1.49.0 démarrent avec leurs
|
||||||
|
archives officielles vérifiées. `activate-node.sh` place le Node 22 natif du cache
|
||||||
|
en tête du PATH et vérifie son exécution ; un Node 18 préinstallé ne peut plus
|
||||||
|
être sélectionné silencieusement. Node 22.23.2 a été vérifié dans l'étape suivante.
|
||||||
|
Le téléchargement/affichage de version dans `setup-node` ne suffit pas à confirmer
|
||||||
|
le runtime utilisé par les étapes shell ; la nouvelle étape affiche le chemin
|
||||||
|
absolu et la version réellement activés.
|
||||||
|
|
||||||
|
L'installateur commun est `scripts/ci/install-tool.sh`. Chaque architecture a sa
|
||||||
|
propre archive et son empreinte. QEMU couvre AMD64 et ARM64 dans les builds préprod
|
||||||
|
et frontend prod, dont la cible reste AMD64 même si le runner est ARM64.
|
||||||
|
|
||||||
Les installations ont été vérifiées avec `npm ci --dry-run --offline
|
Les installations ont été vérifiées avec `npm ci --dry-run --offline
|
||||||
--ignore-scripts --legacy-peer-deps`. Les builds Docker, les tests applicatifs sous
|
--ignore-scripts --legacy-peer-deps`. Les builds Docker, les tests applicatifs sous
|
||||||
Node 22, le transport réel des artefacts et les déploiements sont encore à valider
|
Node 22, le transport réel des artefacts et les déploiements sont encore à valider
|
||||||
|
|||||||
23
scripts/ci/activate-node.sh
Normal file
23
scripts/ci/activate-node.sh
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
case "$(uname -m)" in
|
||||||
|
aarch64|arm64) arch=arm64 ;;
|
||||||
|
x86_64|amd64) arch=x64 ;;
|
||||||
|
*) echo 'Unsupported Node architecture' >&2; exit 1 ;;
|
||||||
|
esac
|
||||||
|
cache="${RUNNER_TOOL_CACHE:-${AGENT_TOOLSDIRECTORY:-/opt/hostedtoolcache}}"
|
||||||
|
# Select the newest installed Node 22 for this architecture, independent of the
|
||||||
|
# container's preinstalled Node 18 and setup-node's misleading version output.
|
||||||
|
node_bin=$(printf '%s\n' "$cache"/node/22.*/"$arch"/bin | sort -Vr | head -n 1)
|
||||||
|
if [[ ! -x "$node_bin/node" ]]; then
|
||||||
|
echo "Node 22 is missing from the tool cache: $cache/node (architecture $arch)" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
export PATH="$node_bin:$PATH"
|
||||||
|
hash -r
|
||||||
|
node -e 'if (process.versions.node.split(".")[0] !== "22") process.exit(1)'
|
||||||
|
printf '%s\n' "$node_bin" >> "${GITHUB_PATH:?}"
|
||||||
|
printf 'PATH=%s\n' "$PATH" >> "${GITHUB_ENV:?}"
|
||||||
|
printf 'Active Node executable: %s\n' "$(command -v node)"
|
||||||
|
node --version
|
||||||
|
npm --version
|
||||||
47
scripts/ci/install-tool.sh
Normal file
47
scripts/ci/install-tool.sh
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Pinned Linux tools for either native architecture; never execute a foreign binary.
|
||||||
|
set -euo pipefail
|
||||||
|
tool="${1:?Usage: install-tool.sh trivy|actionlint|hcloud [--print-source]}"
|
||||||
|
[[ "$(uname -s)" == Linux ]] || { echo 'CI tools require Linux' >&2; exit 1; }
|
||||||
|
case "$(uname -m)" in
|
||||||
|
x86_64|amd64) arch=amd64 ;;
|
||||||
|
aarch64|arm64) arch=arm64 ;;
|
||||||
|
*) echo 'Unsupported runner architecture' >&2; exit 1 ;;
|
||||||
|
esac
|
||||||
|
case "$tool:$arch" in
|
||||||
|
trivy:amd64)
|
||||||
|
url=https://github.com/aquasecurity/trivy/releases/download/v0.74.0/trivy_0.74.0_Linux-64bit.tar.gz
|
||||||
|
sha=2ae6fe3ee734b7fdf11335663e18c75ea12dccc76062f09f164a3b0f8be4371a ;;
|
||||||
|
trivy:arm64)
|
||||||
|
url=https://github.com/aquasecurity/trivy/releases/download/v0.74.0/trivy_0.74.0_Linux-ARM64.tar.gz
|
||||||
|
sha=b94ce1976bbf3c15b514b605ee88be7c6d94a29be2302847ff01cb794d47aad5 ;;
|
||||||
|
actionlint:amd64)
|
||||||
|
url=https://github.com/rhysd/actionlint/releases/download/v1.7.12/actionlint_1.7.12_linux_amd64.tar.gz
|
||||||
|
sha=8aca8db96f1b94770f1b0d72b6dddcb1ebb8123cb3712530b08cc387b349a3d8 ;;
|
||||||
|
actionlint:arm64)
|
||||||
|
url=https://github.com/rhysd/actionlint/releases/download/v1.7.12/actionlint_1.7.12_linux_arm64.tar.gz
|
||||||
|
sha=325e971b6ba9bfa504672e29be93c24981eeb1c07576d730e9f7c8805afff0c6 ;;
|
||||||
|
hcloud:amd64)
|
||||||
|
url=https://github.com/hetznercloud/cli/releases/download/v1.49.0/hcloud-linux-amd64.tar.gz
|
||||||
|
sha=dc6e5b0e6eaf9ef2baa5473a3eb49a11e80e72cdf2a01fdf7b0af975410e79cc ;;
|
||||||
|
hcloud:arm64)
|
||||||
|
url=https://github.com/hetznercloud/cli/releases/download/v1.49.0/hcloud-linux-arm64.tar.gz
|
||||||
|
sha=183dabe0a03b3eb7b93f8d2f2cf91c478de57f9412f189866eda0fdde7baf88c ;;
|
||||||
|
*) echo "Unsupported tool: $tool" >&2; exit 1 ;;
|
||||||
|
esac
|
||||||
|
if [[ "${2:-}" == --print-source ]]; then
|
||||||
|
printf '%s\n%s\n' "$url" "$sha"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
install_dir="${RUNNER_TEMP:?}/ci-tools/$tool"
|
||||||
|
mkdir -p "$install_dir"
|
||||||
|
echo "Installing $tool for Linux/$arch" >&2
|
||||||
|
curl --fail --silent --show-error --location --retry 3 --max-time 120 \
|
||||||
|
"$url" --output "$install_dir/archive.tar.gz"
|
||||||
|
echo "$sha $install_dir/archive.tar.gz" | sha256sum --check --strict >&2
|
||||||
|
tar -xzf "$install_dir/archive.tar.gz" -C "$install_dir" "$tool"
|
||||||
|
chmod +x "$install_dir/$tool"
|
||||||
|
printf '%s\n' "$install_dir" >> "${GITHUB_PATH:?}"
|
||||||
|
# Older act_runner releases can keep the container PATH ahead of add-path entries.
|
||||||
|
printf 'PATH=%s:%s\n' "$install_dir" "$PATH" >> "${GITHUB_ENV:?}"
|
||||||
|
printf '%s\n' "$install_dir/$tool"
|
||||||
83
scripts/ci/test_tool_setup.py
Normal file
83
scripts/ci/test_tool_setup.py
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
"""Offline architecture/PATH regressions for Gitea Linux runners."""
|
||||||
|
import os
|
||||||
|
from pathlib import Path
|
||||||
|
import subprocess
|
||||||
|
import tempfile
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
SCRIPTS = Path(__file__).resolve().parent
|
||||||
|
|
||||||
|
|
||||||
|
class ToolSetup(unittest.TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
self.temp = tempfile.TemporaryDirectory()
|
||||||
|
self.addCleanup(self.temp.cleanup)
|
||||||
|
self.root = Path(self.temp.name)
|
||||||
|
self.bin = self.root / 'bin'
|
||||||
|
self.bin.mkdir()
|
||||||
|
self.env = dict(os.environ, PATH=f'{self.bin}:{os.environ["PATH"]}',
|
||||||
|
FAKE_ARCH='aarch64', FAKE_OS='Linux',
|
||||||
|
RUNNER_TEMP=str(self.root), RUNNER_TOOL_CACHE=str(self.root / 'cache'),
|
||||||
|
GITHUB_PATH=str(self.root / 'path'), GITHUB_ENV=str(self.root / 'env'))
|
||||||
|
self.mock(self.bin / 'uname', 'if [ "$1" = -s ]; then echo "$FAKE_OS"; else echo "$FAKE_ARCH"; fi\n')
|
||||||
|
|
||||||
|
def mock(self, path, body):
|
||||||
|
path.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
path.write_text('#!/bin/sh\n' + body)
|
||||||
|
path.chmod(0o755)
|
||||||
|
|
||||||
|
def run_script(self, script, *args):
|
||||||
|
return subprocess.run(['bash', str(SCRIPTS / script), *args], env=self.env,
|
||||||
|
capture_output=True, text=True)
|
||||||
|
|
||||||
|
def test_all_native_tool_urls_and_checksums(self):
|
||||||
|
for arch, suffix in [('aarch64', 'arm64'), ('x86_64', 'amd64')]:
|
||||||
|
self.env['FAKE_ARCH'] = arch
|
||||||
|
for tool in ['trivy', 'actionlint', 'hcloud']:
|
||||||
|
with self.subTest(arch=arch, tool=tool):
|
||||||
|
result = self.run_script('install-tool.sh', tool, '--print-source')
|
||||||
|
self.assertEqual(result.returncode, 0, result.stderr)
|
||||||
|
url, checksum = result.stdout.splitlines()
|
||||||
|
expected = 'Linux-ARM64' if tool == 'trivy' and suffix == 'arm64' else (
|
||||||
|
'Linux-64bit' if tool == 'trivy' else suffix)
|
||||||
|
self.assertIn(expected, url)
|
||||||
|
self.assertRegex(checksum, r'^[0-9a-f]{64}$')
|
||||||
|
|
||||||
|
def test_unsupported_architecture_rejected_before_download(self):
|
||||||
|
self.env['FAKE_ARCH'] = 'armv7l'
|
||||||
|
self.assertNotEqual(self.run_script('install-tool.sh', 'trivy', '--print-source').returncode, 0)
|
||||||
|
|
||||||
|
def test_non_linux_rejected(self):
|
||||||
|
self.env['FAKE_OS'] = 'Darwin'
|
||||||
|
self.assertNotEqual(self.run_script('install-tool.sh', 'trivy', '--print-source').returncode, 0)
|
||||||
|
|
||||||
|
def test_wrong_checksum_cannot_install_or_activate_binary(self):
|
||||||
|
self.mock(self.bin / 'curl', 'exit 0\n')
|
||||||
|
self.mock(self.bin / 'sha256sum', 'exit 1\n')
|
||||||
|
self.mock(self.bin / 'tar', f'touch "{self.root}/extracted"\n')
|
||||||
|
self.assertNotEqual(self.run_script('install-tool.sh', 'trivy').returncode, 0)
|
||||||
|
self.assertFalse((self.root / 'extracted').exists())
|
||||||
|
self.assertFalse((self.root / 'path').exists())
|
||||||
|
|
||||||
|
def test_node22_takes_precedence_over_preinstalled_node18(self):
|
||||||
|
self.mock(self.bin / 'node', 'echo v18.20.8\nexit 1\n')
|
||||||
|
self.mock(self.bin / 'npm', 'echo old-npm\nexit 1\n')
|
||||||
|
for version in ['22.9.0', '22.23.2']:
|
||||||
|
node_bin = self.root / 'cache' / 'node' / version / 'arm64' / 'bin'
|
||||||
|
self.mock(node_bin / 'node', f'if [ "$1" = -e ]; then exit 0; fi\necho v{version}\n')
|
||||||
|
self.mock(node_bin / 'npm', 'echo 10.9.0\n')
|
||||||
|
result = self.run_script('activate-node.sh')
|
||||||
|
self.assertEqual(result.returncode, 0, result.stderr)
|
||||||
|
self.assertIn('v22.23.2', result.stdout)
|
||||||
|
self.assertNotIn('v18.', result.stdout)
|
||||||
|
self.assertIn('/22.23.2/arm64/bin', (self.root / 'path').read_text())
|
||||||
|
self.assertTrue((self.root / 'env').read_text().startswith('PATH='))
|
||||||
|
|
||||||
|
def test_missing_native_node22_fails(self):
|
||||||
|
wrong_arch = self.root / 'cache' / 'node' / '22.23.2' / 'x64' / 'bin'
|
||||||
|
self.mock(wrong_arch / 'node', 'exit 0\n')
|
||||||
|
self.assertNotEqual(self.run_script('activate-node.sh').returncode, 0)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
@ -8,4 +8,4 @@ for workflow in .gitea/workflows/*.yml; do
|
|||||||
"$validator" -config-file .gitea/actionlint.yaml -shellcheck='' -stdin-filename "$workflow" -
|
"$validator" -config-file .gitea/actionlint.yaml -shellcheck='' -stdin-filename "$workflow" -
|
||||||
done
|
done
|
||||||
bash -n scripts/ci/*.sh
|
bash -n scripts/ci/*.sh
|
||||||
python3 scripts/ci/test_release_checks.py
|
python3 -B -m unittest discover -s scripts/ci -p 'test_*.py'
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user