chore: rely on nss-rs for NSS initialization and test DB #1230
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # Run QNS (QUIC Network Simulator) on PRs to test interop between the | |
| # changes in the PR and its base branch. | |
| name: QNS PR | |
| on: | |
| pull_request: | |
| types: [opened, synchronize, reopened, ready_for_review] | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.event.pull_request.number }} | |
| cancel-in-progress: true | |
| permissions: | |
| contents: read | |
| env: | |
| DELIM: "vs." | |
| TIMEOUT: 20 | |
| jobs: | |
| docker-image: | |
| name: Build Docker images for QNS | |
| if: github.actor != 'dependabot[bot]' | |
| runs-on: ubuntu-24.04 | |
| strategy: | |
| matrix: | |
| include: | |
| - name: pr | |
| ref: ${{ github.event.pull_request.head.sha }} | |
| - name: baseline | |
| ref: ${{ github.event.pull_request.base.sha }} | |
| steps: | |
| - uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0 | |
| with: | |
| cache-binary: true | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| with: | |
| persist-credentials: false | |
| ref: ${{ matrix.ref }} | |
| - uses: docker/metadata-action@030e881283bb7a6894de51c315a6bfe6a94e05cf # v6.0.0 | |
| id: meta | |
| with: | |
| images: ghcr.io/${{ github.repository }}-qns-${{ matrix.name }} | |
| tags: type=ref,event=pr | |
| - uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0 | |
| with: | |
| context: . | |
| push: false | |
| tags: ${{ steps.meta.outputs.tags }} | |
| file: qns/Dockerfile | |
| build-args: RUST_VERSION=stable | |
| # GITHUB_TOKEN is used to avoid GitHub rate limits when fetching | |
| # nss-versions.env from mozilla/actions. It is safe to pass here | |
| # because PR runs require manual approval before any untrusted code | |
| # executes. | |
| secrets: github_token=${{ secrets.GITHUB_TOKEN }} | |
| platforms: linux/amd64 | |
| outputs: type=docker,dest=/tmp/${{ matrix.name }}.tar | |
| cache-from: type=gha | |
| cache-to: type=gha,mode=min | |
| - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | |
| with: | |
| name: ${{ matrix.name }} Docker image | |
| path: /tmp/${{ matrix.name }}.tar | |
| implementations: | |
| name: Determine interop pairs | |
| needs: docker-image | |
| runs-on: ubuntu-24.04 | |
| outputs: | |
| pairs: ${{ steps.config.outputs.pairs }} | |
| implementations: ${{ steps.config.outputs.implementations }} | |
| env: | |
| URL: https://github.com/mozilla/neqo | |
| ROLE: both | |
| steps: | |
| - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 | |
| with: | |
| pattern: "* Docker image" | |
| path: /tmp | |
| merge-multiple: true | |
| - env: | |
| REPO: ${{ github.repository }} | |
| PR_NUMBER: ${{ github.event.pull_request.number }} | |
| run: | | |
| for IMAGE in pr baseline; do | |
| docker load --input "/tmp/$IMAGE.tar" | |
| echo "${IMAGE^^}_IMAGE=ghcr.io/$REPO-qns-$IMAGE:pr-$PR_NUMBER" >> "$GITHUB_ENV" | |
| done | |
| - id: config | |
| run: | | |
| # Add neqo-pr, neqo-baseline, and some non-default implementations | |
| # tquic: https://github.com/quic-interop/quic-interop-runner/pull/385/files | |
| # openssl: https://github.com/quic-interop/quic-interop-runner/pull/402/files | |
| # linuxquic: https://github.com/quic-interop/quic-interop-runner/pull/428 | |
| # quic-zig: https://github.com/quic-interop/quic-interop-runner/pull/491 | |
| cat <<EOF > additional.json | |
| { | |
| "neqo-pr": { | |
| "image": "$PR_IMAGE", | |
| "url": "$URL", | |
| "role": "$ROLE" | |
| }, | |
| "neqo-baseline": { | |
| "image": "$BASELINE_IMAGE", | |
| "url": "$URL", | |
| "role": "$ROLE" | |
| }, | |
| "tquic": { | |
| "image": "tquicgroup/tquic:latest", | |
| "url": "https://github.com/Tencent/tquic/", | |
| "role": "both" | |
| }, | |
| "openssl": { | |
| "image": "quay.io/openssl-ci/openssl-quic-interop", | |
| "url": "https://github.com/openssl/openssl", | |
| "role": "client" | |
| }, | |
| "linuxquic": { | |
| "image": "quay.io/lxin/linuxquic-interop:latest", | |
| "url": "https://github.com/lxin/quic", | |
| "role": "both" | |
| }, | |
| "quic-zig": { | |
| "image": "ghcr.io/endel/quic-zig:latest", | |
| "url": "https://github.com/endel/quic-zig", | |
| "role": "both" | |
| } | |
| } | |
| EOF | |
| curl -o runner.json https://raw.githubusercontent.com/quic-interop/quic-interop-runner/master/implementations_quic.json | |
| jq '. += input' runner.json additional.json > implementations_quic.json | |
| { | |
| echo "implementations<<EOF" | |
| cat implementations_quic.json | |
| echo "EOF" | |
| } >> "$GITHUB_OUTPUT" | |
| # Determine valid interop pairs: all combinations involving neqo-pr or neqo-baseline | |
| # shellcheck disable=SC2016 | |
| jq < implementations_quic.json '[ | |
| [to_entries[] | select(.value.role=="server" or .value.role=="both").key] as $servers | | |
| [to_entries[] | select(.value.role=="client" or .value.role=="both").key] as $clients | | |
| $clients[] as $client | | |
| $servers[] as $server | | |
| $client + " '"$DELIM"' " + $server | | |
| select((contains("neqo-pr") or contains("neqo-baseline")) and ($client != $server)) | |
| ]' > pairs.json | |
| { | |
| echo "pairs<<EOF" | |
| cat pairs.json | |
| echo "EOF" | |
| } >> "$GITHUB_OUTPUT" | |
| run-qns: | |
| name: Run QNS | |
| needs: implementations | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| pair: ${{ fromJson(needs.implementations.outputs.pairs) }} | |
| runs-on: ubuntu-24.04 | |
| steps: | |
| # quic-interop-runner requires Docker v28.1. GitHub's ubuntu-24.04 comes | |
| # with v28.0.4. Install newer version. | |
| - name: Set up Docker | |
| uses: docker/setup-docker-action@b2189fbf2a6592b51fee7cdd93ee2bfaeba733db # v5.1.0 | |
| with: | |
| version: "v28.1.0" | |
| - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 | |
| with: | |
| name: "pr Docker image" | |
| path: /tmp | |
| - run: docker load --input "/tmp/pr.tar" | |
| - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 | |
| if: contains(matrix.pair, 'neqo-baseline') | |
| with: | |
| name: "baseline Docker image" | |
| path: /tmp | |
| - if: contains(matrix.pair, 'neqo-baseline') | |
| run: docker load --input /tmp/baseline.tar | |
| - id: depair | |
| env: | |
| PAIR: ${{ matrix.pair }} | |
| run: | | |
| PAIR="${PAIR/ $DELIM /%}" | |
| echo "client=$(echo "$PAIR" | cut -d% -f1)" >> "$GITHUB_OUTPUT" | |
| echo "server=$(echo "$PAIR" | cut -d% -f2)" >> "$GITHUB_OUTPUT" | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| with: | |
| persist-credentials: false | |
| # TODO: Replace once https://github.com/quic-interop/quic-interop-runner/pull/356 is merged. | |
| - uses: ./.github/actions/quic-interop-runner | |
| timeout-minutes: ${{ fromJSON(env.TIMEOUT) }} | |
| continue-on-error: true | |
| id: run | |
| with: | |
| client: ${{ steps.depair.outputs.client }} | |
| server: ${{ steps.depair.outputs.server }} | |
| implementations: ${{ needs.implementations.outputs.implementations }} | |
| - if: always() | |
| env: | |
| RESULT: ${{ steps.run.outputs.result }} | |
| run: test "$RESULT" != "error" | |
| report: | |
| name: Report results | |
| if: ${{ !cancelled() }} | |
| needs: [docker-image, run-qns, implementations] | |
| runs-on: ubuntu-24.04 | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| with: | |
| persist-credentials: false | |
| - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 | |
| with: | |
| pattern: "*results" | |
| path: results | |
| - run: sudo apt-get install -y --no-install-recommends wdiff cmark-gfm | |
| - env: | |
| PAIRS: ${{ needs.implementations.outputs.pairs }} | |
| BASE_SHA: ${{ github.event.pull_request.base.sha }} | |
| BASE_REF: ${{ github.event.pull_request.base.ref || 'main' }} | |
| PR: "neqo-pr" | |
| run: | | |
| # shellcheck disable=SC2153 | |
| mapfile -t LIST < <(echo "$PAIRS" | jq '.[]' | sort) | |
| for PREFIX in "${LIST[@]}"; do | |
| PREFIX=$(echo "$PREFIX" | tr -d '"') | |
| # Skip neqo-baseline results as they're only used as baseline | |
| [[ "$PREFIX" == *"neqo-baseline"* ]] && continue | |
| CLIENT=$(echo "$PREFIX" | cut -f1 -d " ") | |
| SERVER=$(echo "$PREFIX" | cut -f3 -d " ") | |
| if [ "$CLIENT" == "$PR" ]; then | |
| ROLE=client | |
| else | |
| ROLE=server | |
| fi | |
| RUN="results/${PREFIX} results" | |
| PAIR="$CLIENT $DELIM $SERVER" | |
| if [ ! -e "$RUN/result.json" ]; then | |
| echo "* $PAIR: run cancelled after $TIMEOUT min" >> "$ROLE.failed.md" | |
| continue | |
| fi | |
| BASELINE_RUN="${RUN/$PR/neqo-baseline}" | |
| if [ ! -s "$BASELINE_RUN/result.json" ]; then | |
| echo "* $PAIR: baseline result missing" >> "$ROLE.failed.md" | |
| continue | |
| fi | |
| for BRANCH in "$RUN" "$BASELINE_RUN"; do | |
| if [ ! -s "$BRANCH/result.json" ]; then | |
| echo "* $PAIR: $BRANCH result missing" >> "$ROLE.failed.md" | |
| continue 2 | |
| fi | |
| # Skip if .results is null or missing | |
| if ! jq -e '.results' "$BRANCH/result.json" > /dev/null 2>&1; then | |
| echo "* $PAIR: $BRANCH has no results" >> "$ROLE.failed.md" | |
| continue 2 | |
| fi | |
| jq < "$BRANCH/result.json" ' | |
| . as $data | | |
| .results[][].result //= "failed" | | |
| { | |
| results: [.results[] | group_by(.result)[] | {(.[0].result): [.[] | .abbr]}] | | |
| add | |
| } | | |
| . + {log_url: $data.log_url} | |
| ' > "$BRANCH/$ROLE.grouped.json" | |
| done | |
| for ROLE in client server; do | |
| [ ! -e "$RUN/$ROLE.grouped.json" ] && continue | |
| for GROUP in $(jq -r < "$RUN/$ROLE.grouped.json" '.results | keys[]'); do | |
| PR_RESULT=$(jq < "$RUN/$ROLE.grouped.json" -r '.results.'"$GROUP"'[]' | fmt -w 1000) | |
| LOG=$(jq -r < "$RUN/$ROLE.grouped.json" -r '.log_url') | |
| # Get baseline from neqo-baseline if available | |
| BASELINE=$(mktemp) | |
| BASELINE_GROUPED="$BASELINE_RUN/$ROLE.grouped.json" | |
| if [ -s "$BASELINE_GROUPED" ]; then | |
| jq < "$BASELINE_GROUPED" -r '.results.'"$GROUP"'[]' | fmt -w 1000 > "$BASELINE" | |
| fi | |
| [ -n "$PR_RESULT" ] || continue | |
| DIFF=$(wdiff -n "$BASELINE" - <<< "$PR_RESULT" || true) | |
| ADD="" | |
| ADD_DELIM="" | |
| DEL="" | |
| DEL_DELIM="" | |
| if [ "$GROUP" == "failed" ]; then | |
| ADD=":warning:" | |
| ADD_DELIM="\*\*" | |
| DEL=":rocket:" | |
| DEL_DELIM="~~" | |
| elif [ "$GROUP" == "succeeded" ]; then | |
| ADD=":rocket:" | |
| ADD_DELIM="~~" | |
| DEL=":warning:" | |
| DEL_DELIM="\*\*" | |
| fi | |
| RESULT=$(echo "$DIFF" | sed -E "s/\[-/ $DEL$DEL_DELIM/g; s/-\]/$DEL_DELIM /g; s/\{\+/ $ADD$ADD_DELIM/g; s/\+\}/$ADD_DELIM /g") | |
| echo "* [$PAIR]($LOG): $RESULT" >> "$ROLE.$GROUP.md" | |
| done | |
| done | |
| done | |
| { | |
| echo "### Failed Interop Tests" | |
| if [ -e client.failed.md ] || [ -e server.failed.md ]; then | |
| echo -n "[QUIC Interop Runner](https://github.com/quic-interop/quic-interop-runner), *client* vs. *server*" | |
| if [ "$BASE_SHA" ]; then | |
| echo -n ", differences relative to \`$BASE_REF\` at ${BASE_SHA}" | |
| fi | |
| echo "." | |
| echo | |
| echo "<table><tr><th align=\"left\">$PR as client</th><th align=\"left\">$PR as server</th></tr>" | |
| echo -n "<tr><td valign=\"top\">" | |
| if [ -e client.failed.md ]; then | |
| cmark-gfm -e strikethrough -e autolink client.failed.md | tr -d '\n' | sed 's/<\/*ul>//g; s/<li>//g; s/<\/li>/<br>/g' | |
| fi | |
| echo -n "</td><td valign=\"top\">" | |
| if [ -e server.failed.md ]; then | |
| cmark-gfm -e strikethrough -e autolink server.failed.md | tr -d '\n' | sed 's/<\/*ul>//g; s/<li>//g; s/<\/li>/<br>/g' | |
| fi | |
| echo "</td></tr></table>" | |
| else | |
| echo -n "None " | |
| if [ -e "client.succeeded.md" ] || [ -e "server.succeeded.md" ] || [ -e "client.unsupported.md" ] || [ -e "server.unsupported.md" ]; then | |
| echo ":tada:" | |
| else | |
| echo ":question:" | |
| fi | |
| fi | |
| echo "<details><summary>All results</summary>" | |
| echo | |
| for GROUP in succeeded unsupported; do | |
| echo "### ${GROUP^} Interop Tests" | |
| echo "[QUIC Interop Runner](https://github.com/quic-interop/quic-interop-runner), *client* vs. *server*" | |
| echo "#### $PR as client" | |
| cat "client.$GROUP.md" 2>/dev/null || echo "None :question:" | |
| echo "#### $PR as server" | |
| cat "server.$GROUP.md" 2>/dev/null || echo "None :question:" | |
| done | |
| echo | |
| echo "</details>" | |
| } >> comment.md | |
| - uses: ./.github/actions/pr-comment-data-export | |
| with: | |
| name: ${{ github.workflow }} | |
| contents: comment.md |