Repository navigation
v3 installed package validation #31
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
| name: v3 installed package validation | |
| on: | |
| push: | |
| branches: [v3, master] | |
| pull_request: | |
| branches: [v3, master] | |
| workflow_dispatch: | |
| permissions: | |
| contents: read | |
| jobs: | |
| linux: | |
| if: github.event_name != 'workflow_dispatch' | |
| runs-on: ubuntu-24.04 | |
| timeout-minutes: 90 | |
| steps: | |
| - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 | |
| - name: Prerequisites | |
| run: sudo apt-get update && sudo apt-get install -y clang autoconf automake libtool pkg-config python3 perl libcurl4-openssl-dev binutils python3-venv | |
| - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 | |
| with: | |
| node-version: '24.15.0' | |
| - name: Selected client environment and executable Git provenance | |
| run: | | |
| mkdir -p "$RUNNER_TEMP/package-evidence" | |
| exec > >(tee "$RUNNER_TEMP/package-evidence/clients.log") 2>&1 | |
| python3 -c 'import subprocess; subprocess.run(["git", "--version"], check=True)' | |
| python3 -m venv "$RUNNER_TEMP/package-evidence/clients" | |
| "$RUNNER_TEMP/package-evidence/clients/bin/python" -m pip install -r test/integ/http2-client-requirements.txt | |
| - name: Build selected prerequisites | |
| run: python3 scripts/prepare-v3-package-ci.py --output "$RUNNER_TEMP/package-evidence/prerequisites" | |
| - name: Bootstrap | |
| run: ./bootstrap | |
| - name: Installed matrix | |
| run: | | |
| prefix=() | |
| if ! python3 -c 'import socket; s=socket.socket(); s.bind(("127.0.0.1",443)); s.close()'; then | |
| prefix=(sudo env "PATH=$PATH" GIT_CONFIG_COUNT=1 GIT_CONFIG_KEY_0=safe.directory "GIT_CONFIG_VALUE_0=$PWD") | |
| fi | |
| "${prefix[@]}" python3 scripts/check-v3-installed-consumer.py --output "$RUNNER_TEMP/package-evidence/matrix" --provider-prefix "$RUNNER_TEMP/package-evidence/prerequisites/provider" --pkg-config-dir /usr/lib/x86_64-linux-gnu/pkgconfig --pkg-config-dir /usr/share/pkgconfig --client-python "$RUNNER_TEMP/package-evidence/clients/bin/python" --node node --compiler clang++ --cc clang --jobs 2 | |
| - if: always() | |
| uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 | |
| with: | |
| name: v3-package-linux-${{ github.sha }} | |
| path: ${{ runner.temp }}/package-evidence | |
| retention-days: 14 | |
| if-no-files-found: error | |
| macos: | |
| permissions: | |
| contents: read | |
| actions: read | |
| runs-on: macos-15 | |
| timeout-minutes: 90 | |
| steps: | |
| - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 | |
| with: | |
| ref: ${{ github.event_name == 'workflow_dispatch' && 'c0cfdabc8040273d60c610269a93d1c687ed8517' || github.sha }} | |
| - name: Prerequisites | |
| run: brew install autoconf automake libtool pkg-config python curl llvm | |
| - name: Select complete C++20 compiler and runtime | |
| run: bash scripts/ci-macos-toolchain.sh | |
| - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 | |
| with: | |
| node-version: '24.15.0' | |
| - name: Selected client environment and executable Git provenance | |
| run: | | |
| mkdir -p "$RUNNER_TEMP/package-evidence" | |
| exec > >(tee "$RUNNER_TEMP/package-evidence/clients.log") 2>&1 | |
| python3 -c 'import subprocess; subprocess.run(["git", "--version"], check=True)' | |
| python3 -m venv "$RUNNER_TEMP/package-evidence/clients" | |
| "$RUNNER_TEMP/package-evidence/clients/bin/python" -m pip install -r test/integ/http2-client-requirements.txt | |
| - name: Build selected prerequisites | |
| run: python3 scripts/prepare-v3-package-ci.py --output "$RUNNER_TEMP/package-evidence/prerequisites" | |
| - name: Bootstrap | |
| run: ./bootstrap | |
| - name: Installed matrix | |
| if: github.event_name != 'workflow_dispatch' | |
| run: | | |
| prefix=() | |
| if ! python3 -c 'import socket; s=socket.socket(); s.bind(("127.0.0.1",443)); s.close()'; then | |
| prefix=(sudo env "PATH=$PATH" GIT_CONFIG_COUNT=1 GIT_CONFIG_KEY_0=safe.directory "GIT_CONFIG_VALUE_0=$PWD") | |
| fi | |
| "${prefix[@]}" python3 scripts/check-v3-installed-consumer.py --output "$RUNNER_TEMP/package-evidence/matrix" --provider-prefix "$RUNNER_TEMP/package-evidence/prerequisites/provider" --pkg-config-dir "$(brew --prefix)/share/pkgconfig" --client-python "$RUNNER_TEMP/package-evidence/clients/bin/python" --node node --compiler "$V3_CXX" --cc "$V3_CC" --toolchain-prefix "$V3_PACKAGE_TOOLCHAIN" --jobs 2 | |
| # Branch-only checkpoint: remove before merging to v3. This is not matrix proof. | |
| - name: Diagnose installed shared TLS-off external HTTP1 on Darwin | |
| if: github.event_name == 'workflow_dispatch' | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| run: | | |
| python3 - <<'PY_DIAGNOSTIC' | |
| import hashlib, importlib.util, json, os, platform, subprocess, sys | |
| from pathlib import Path | |
| checkout = Path.cwd().resolve() | |
| sys.path.insert(0, str(checkout / 'scripts/lib')) | |
| from package_commands import Commands | |
| import release_artifact as identity | |
| from release_ci import selected_archive, verify_download | |
| spec = importlib.util.spec_from_file_location('audit', checkout / 'scripts/audit-v3-installed-package.py') | |
| audit = importlib.util.module_from_spec(spec) | |
| spec.loader.exec_module(audit) | |
| assert platform.system() == 'Darwin' | |
| output = Path(os.environ['RUNNER_TEMP']) / 'package-evidence/header-deadline-diagnostic' | |
| output.mkdir() | |
| runner_commands = output / 'runner' | |
| runner_commands.mkdir() | |
| command = Commands(runner_commands) | |
| provider = output.parent / 'prerequisites/provider' | |
| compiler = os.environ['V3_CXX'] | |
| env = audit.clean_environment() | |
| for key in ('GH_TOKEN', 'GITHUB_TOKEN', 'V3_RELEASE_IDENTITY'): | |
| env.pop(key, None) | |
| receipt = dict(kind='diagnostic-only; not complete package validation', tls='no', linkage='shared', | |
| control='unmodified c0 package_lane prefix through first two private shared TLS-off suites', | |
| driver_revision=os.environ['GITHUB_SHA'], | |
| runner_context=dict(uid=os.getuid(), euid=os.geteuid(), gid=os.getgid(), egid=os.getegid(), cwd=str(checkout)), | |
| revision=command(['git', 'rev-parse', 'HEAD'], checkout, env).strip(), | |
| compiler=command([compiler, '--version'], checkout, env), | |
| provider_header_sha256=hashlib.sha256((provider / 'include/openssl/opensslv.h').read_bytes()).hexdigest()) | |
| try: | |
| expected = dict(repository=os.environ['GITHUB_REPOSITORY'], run_id='39969790346', run_attempt='1', | |
| workflow_head='c0cfdabc8040273d60c610269a93d1c687ed8517', artifact_id='12508482722') | |
| endpoint = 'repos/' + expected['repository'] + '/actions/artifacts/' + expected['artifact_id'] | |
| metadata = json.loads(subprocess.check_output(['gh', 'api', endpoint], text=True)) | |
| run = json.loads(subprocess.check_output(['gh', 'api', 'repos/' + expected['repository'] + | |
| '/actions/runs/' + expected['run_id'] + '/attempts/' + expected['run_attempt']], text=True)) | |
| (output / 'selected-artifact-metadata.json').write_text(json.dumps(metadata, indent=2) + '\n') | |
| (output / 'selected-run-metadata.json').write_text(json.dumps(run, indent=2) + '\n') | |
| downloaded = output / 'selected-archive.zip' | |
| with downloaded.open('xb') as destination: | |
| subprocess.run(['gh', 'api', endpoint + '/zip'], stdout=destination, check=True) | |
| zip_digest = 'sha256:a08eb79186b13cf12ac8c639f424e13a7de1ee09df5547aab2b4200a951a5f05' | |
| verify_download(downloaded, metadata, run, expected, zip_digest, output / 'selected') | |
| selected = json.loads((output / 'selected/selected.json').read_text()) | |
| archive = output / 'selected/libhttpserver-3.0.0.tar.gz' | |
| assert selected['commit'] == selected['source']['head'] == expected['workflow_head'] | |
| assert selected['archive'] == archive.name and archive.stat().st_size == 3053890 | |
| assert identity.sha256(archive) == selected['sha256'] == '43124552f20bd00fceddc714856d605ca9caf017a849a991c34f16f437fcab83' | |
| snapshot = identity.source_identity(checkout) | |
| assert snapshot == selected['source'] | |
| release = selected_archive(checkout, snapshot, archive, selected['sha256'], output / 'source') | |
| assert release['source'] == selected['source'] and release['files_sha256'] == selected['files_sha256'] | |
| source = Path(release['source_root']) | |
| (output / 'artifact-identity.json').write_text(json.dumps(release, indent=2) + '\n') | |
| identity.verified(source, output / 'artifact-identity.json') | |
| assert not (source / 'src/httpserver/detail/deadline_trace.hpp').exists() | |
| receipt['source_archive'] = dict(**expected, artifact_zip_sha256=zip_digest, | |
| archive_sha256=selected['sha256'], source_root=str(source), | |
| provenance='original selected c0 extraction via existing selected_archive; no trace overlay') | |
| receipt['status'] = 'unmodified extraction ready; privileged prefix control pending' | |
| except Exception as error: | |
| receipt.update(status='diagnostic failed', error=str(error)) | |
| raise | |
| finally: | |
| (output / 'diagnostic.json').write_text(json.dumps(receipt, indent=2) + '\n') | |
| PY_DIAGNOSTIC | |
| diagnostic_script="$RUNNER_TEMP/package-evidence/header-deadline-build.py" | |
| cat > "$diagnostic_script" <<'PY_PRIVILEGED' | |
| import argparse, importlib.util, json, os, sys, time | |
| from pathlib import Path | |
| checkout = Path.cwd().resolve() | |
| output = Path(os.environ['RUNNER_TEMP']) / 'package-evidence/header-deadline-diagnostic' | |
| receipt = json.loads((output / 'diagnostic.json').read_text()) | |
| source = Path(receipt['source_archive']['source_root']) | |
| sys.path.insert(0, str(source / 'scripts/lib')) | |
| import package_commands as commands | |
| import package_integration as integration | |
| import package_matrix as matrix | |
| import package_traffic | |
| import package_process | |
| import release_artifact as identity | |
| spec = importlib.util.spec_from_file_location('installed_control', source / 'scripts/check-v3-installed-consumer.py') | |
| installed = importlib.util.module_from_spec(spec) | |
| spec.loader.exec_module(installed) | |
| os.environ['V3_RELEASE_IDENTITY'] = str(output / 'artifact-identity.json') | |
| release = identity.verified(source) | |
| provider = output.parent / 'prerequisites/provider' | |
| os.environ.update(V3_TLS_CFLAGS='-I' + str(provider / 'include'), | |
| V3_TLS_LIBS='-L' + str(provider / 'lib') + ' -lssl -lcrypto', | |
| V3_OPENSSL=str(provider / 'bin/openssl'), LD_LIBRARY_PATH=str(provider / 'lib'), | |
| DYLD_LIBRARY_PATH=str(provider / 'lib'), PATH=str(provider / 'bin') + os.pathsep + os.environ['PATH']) | |
| args = argparse.Namespace(compiler=os.environ['V3_CXX'], cc=os.environ['V3_CC'], make='make', jobs=2, | |
| optimized=False, provider_prefix=provider.resolve(), prerequisite_prefix=[], | |
| pkg_config_dir=[Path(os.environ['V3_DIAGNOSTIC_PKG_CONFIG_DIR']).resolve()], | |
| toolchain_prefix=Path(os.environ['V3_PACKAGE_TOOLCHAIN']).resolve(), | |
| client_python=str(output.parent / 'clients/bin/python'), node='node') | |
| receipt['privileged_context'] = dict(uid=os.getuid(), euid=os.geteuid(), gid=os.getgid(), egid=os.getegid(), | |
| cwd=str(checkout), compiler=args.compiler, cc=args.cc, toolchain=str(args.toolchain_prefix), | |
| provider_prefix=str(provider), path=os.environ['PATH'], git_safe_directory=os.environ['GIT_CONFIG_VALUE_0']) | |
| modules = (installed, installed.audit, commands, integration, matrix, package_traffic, package_process, identity) | |
| receipt['helper_bindings'] = {str(Path(module.__file__).relative_to(source)): identity.sha256(module.__file__) | |
| for module in modules} | |
| assert all(release['files_sha256'].get(name) == digest for name, digest in receipt['helper_bindings'].items()) | |
| prefix_names = ('native_http1_e2e', 'external_http1_e2e') | |
| original_suites = matrix.suites | |
| original_run_suites = installed.run_suites | |
| original_tree = commands._CommandTree | |
| matrix_output = output / 'matrix' | |
| matrix_output.mkdir() | |
| target_argv = [str(matrix_output / 'tls-no/integration-shared/external_http1_e2e/external_http1_e2e')] | |
| sampling = dict(triggered=False, status='not-triggered', threshold_seconds=3.0) | |
| sample_delay_seconds = 3.0 | |
| class PrefixComplete(Exception): | |
| pass | |
| def selected_suites(inventory, host, mode): | |
| suites = original_suites(inventory, host, mode) | |
| return {name: suites[name] for name in prefix_names} | |
| def stop_after_prefix(*arguments, **keywords): | |
| assert arguments[2:4] == ('no', 'shared') | |
| result = original_run_suites(*arguments, **keywords) | |
| stored = json.loads((arguments[4] / 'suites.json').read_text()) | |
| assert list(result) == list(prefix_names) and stored == result | |
| assert all(row['status'] == 'passed' for row in stored.values()) | |
| receipt['validated_prefix'] = stored | |
| raise PrefixComplete() | |
| def retain_sampling(): | |
| (output / 'sampling.json').write_text(json.dumps(sampling, indent=2) + '\n') | |
| def collect_sample(pid, cwd, env, deadline): | |
| tool = Path('/usr/bin/sample') | |
| if not tool.is_file(): | |
| sampling.update(status='unavailable', error='required native /usr/bin/sample collector absent') | |
| return | |
| directory = output / 'sampler' | |
| directory.mkdir() | |
| command = commands.Commands(directory) | |
| command([str(tool), str(pid), '1', '10', '-file', str(output / 'stalled-external.sample.txt')], | |
| cwd, env, timeout=min(5.0, max(0.1, deadline - time.monotonic()))) | |
| dump = output / 'stalled-external.sample.txt' | |
| if not dump.is_file() or not 0 < dump.stat().st_size <= 8 * 1024 * 1024: | |
| raise RuntimeError('native sample output missing, empty or exceeds 8 MiB') | |
| sampling.update(status='collected; sampling may alter the target outcome', | |
| sample_file=str(dump), bytes=dump.stat().st_size, sha256=identity.sha256(dump)) | |
| class ObservedTree(original_tree): | |
| def __init__(self, argv, cwd, env): | |
| super().__init__(argv, cwd, env) | |
| self.is_target = argv == target_argv | |
| self.started = time.monotonic() | |
| self.sample_cwd, self.sample_env = cwd, dict(env) | |
| if self.is_target: | |
| receipt['target_launch_context'] = dict(pid=self.child.pid, uid=os.getuid(), euid=os.geteuid(), | |
| gid=os.getgid(), egid=os.getegid(), cwd=str(cwd), direct_original_popen=True, | |
| runtime={key: env.get(key) for key in ('PATH', 'DYLD_LIBRARY_PATH', 'LD_LIBRARY_PATH', 'V3_PACKAGE_TOOLCHAIN')}) | |
| def exited(self, deadline=None): | |
| exited = super().exited(deadline) | |
| if self.is_target and not exited and not sampling['triggered'] and time.monotonic() - self.started >= sample_delay_seconds: | |
| assert self.job is None and self.child.returncode is None | |
| sampling.update(triggered=True, status='started', pid=self.child.pid, | |
| ownership='original non-reaping anchor; synchronous hook owns cleanup') | |
| retain_sampling() | |
| try: | |
| collect_sample(self.child.pid, self.sample_cwd, self.sample_env, deadline) | |
| except Exception as error: | |
| sampling.update(status='collection-failed', error=str(error)) | |
| assert self.child.returncode is None | |
| exited = super().exited(deadline) | |
| sampling['anchor_reserved_after_collection'] = True | |
| retain_sampling() | |
| return exited | |
| try: | |
| assert os.geteuid() == 0 and sys.platform == 'darwin' | |
| assert not any(key in os.environ for key in ('GH_TOKEN', 'GITHUB_TOKEN')) | |
| matrix.suites = selected_suites | |
| installed.run_suites = stop_after_prefix | |
| commands._CommandTree = ObservedTree | |
| installed.package_lane(args, source, matrix_output, 'no', matrix.load()) | |
| raise AssertionError('bounded prefix did not stop before remaining matrix work') | |
| except PrefixComplete: | |
| identity.verified(source) | |
| receipt['status'] = 'partial original prefix passed; not a package matrix gate or behavior fix' | |
| if sampling['triggered'] and sampling['status'] != 'collected; sampling may alter the target outcome': | |
| receipt.update(status='original prefix passed; required native collection incomplete', error=sampling.get('error')) | |
| raise RuntimeError('required native collection incomplete') | |
| except Exception as error: | |
| receipt.update(status='original prefix failed; propagated unchanged', error=str(error)) | |
| raise | |
| finally: | |
| matrix.suites = original_suites | |
| installed.run_suites = original_run_suites | |
| commands._CommandTree = original_tree | |
| receipt['sampling'] = sampling | |
| receipt['source_unchanged'] = identity.source_files(source) == release['files_sha256'] | |
| retain_sampling() | |
| (output / 'diagnostic.json').write_text(json.dumps(receipt, indent=2) + '\n') | |
| PY_PRIVILEGED | |
| diagnostic_python=$(command -v python3) | |
| env -u GH_TOKEN -u GITHUB_TOKEN sudo env "PATH=$PATH" \ | |
| GIT_CONFIG_COUNT=1 GIT_CONFIG_KEY_0=safe.directory "GIT_CONFIG_VALUE_0=$PWD" \ | |
| "RUNNER_TEMP=$RUNNER_TEMP" "V3_CXX=$V3_CXX" "V3_CC=$V3_CC" "V3_PACKAGE_TOOLCHAIN=$V3_PACKAGE_TOOLCHAIN" \ | |
| "V3_DIAGNOSTIC_PKG_CONFIG_DIR=$(brew --prefix)/share/pkgconfig" "$diagnostic_python" "$diagnostic_script" | |
| - name: Make privileged proof readable by artifact upload | |
| if: always() | |
| run: | | |
| if [ -d "$RUNNER_TEMP/package-evidence" ]; then | |
| sudo chown -R "$(id -u):$(id -g)" "$RUNNER_TEMP/package-evidence" | |
| fi | |
| - if: always() | |
| uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 | |
| with: | |
| name: v3-package-macos-${{ github.sha }} | |
| path: | | |
| ${{ runner.temp }}/package-evidence | |
| ${{ runner.temp }}/v3-toolchain | |
| retention-days: 14 | |
| if-no-files-found: error | |
| mingw64: | |
| if: github.event_name != 'workflow_dispatch' | |
| runs-on: windows-2022 | |
| timeout-minutes: 90 | |
| defaults: | |
| run: | |
| shell: msys2 {0} | |
| steps: | |
| - name: Keep selected Git source bytes unchanged | |
| shell: pwsh | |
| run: git config --global core.autocrlf false | |
| - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 | |
| - uses: msys2/setup-msys2@e9898307ac31d1a803454791be09ab9973336e1c | |
| with: | |
| msystem: MINGW64 | |
| path-type: inherit | |
| update: true | |
| install: >- | |
| autotools base-devel perl git | |
| mingw-w64-x86_64-clang mingw-w64-x86_64-gcc mingw-w64-x86_64-binutils | |
| mingw-w64-x86_64-python mingw-w64-x86_64-pkgconf mingw-w64-x86_64-libtool mingw-w64-x86_64-curl mingw-w64-x86_64-libsystre | |
| - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 | |
| with: | |
| node-version: '24.15.0' | |
| - name: Selected client environment and executable Git provenance | |
| run: | | |
| mkdir -p "$RUNNER_TEMP/package-evidence" | |
| exec > >(tee "$RUNNER_TEMP/package-evidence/clients.log") 2>&1 | |
| export PATH="/c/Program Files/Git/cmd:$PATH" | |
| /mingw64/bin/python - <<'GIT_PROBE' | |
| import shutil, subprocess | |
| print('selected native Git:', shutil.which('git'), flush=True) | |
| for arguments in (['--version'], ['rev-parse', '--verify', 'HEAD^{commit}']): | |
| result = subprocess.run(['git'] + arguments, capture_output=True, text=True) | |
| print('git', *arguments, 'exit=' + str(result.returncode), flush=True) | |
| print(result.stdout[-2048:], end='', flush=True) | |
| print(result.stderr[-2048:], end='', flush=True) | |
| result.check_returncode() | |
| GIT_PROBE | |
| /mingw64/bin/python -m venv "$RUNNER_TEMP/package-evidence/clients" | |
| "$(cygpath -m "$RUNNER_TEMP/package-evidence/clients/bin/python.exe")" -m pip install -r test/integ/http2-client-requirements.txt | |
| - name: Build selected prerequisites | |
| run: | | |
| export PATH="/c/Program Files/Git/cmd:$PATH" | |
| /mingw64/bin/python scripts/prepare-v3-package-ci.py --output "$RUNNER_TEMP/package-evidence/prerequisites" | |
| - name: Bootstrap | |
| run: ./bootstrap | |
| - name: Installed matrix (native Python; IOCP and WSAPoll) | |
| run: | | |
| export PATH="/c/Program Files/Git/cmd:$PATH" | |
| /mingw64/bin/python scripts/check-v3-installed-consumer.py --output "$RUNNER_TEMP/package-evidence/matrix" \ | |
| --provider-prefix "$(cygpath -m "$RUNNER_TEMP/package-evidence/prerequisites/provider")" --toolchain-prefix "$(cygpath -m /mingw64)" \ | |
| --client-python "$(cygpath -m "$RUNNER_TEMP/package-evidence/clients/bin/python.exe")" --node node --compiler clang++ --cc clang --jobs 2 | |
| - if: always() | |
| uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 | |
| with: | |
| name: v3-package-mingw64-${{ github.sha }} | |
| path: ${{ runner.temp }}/package-evidence | |
| retention-days: 14 | |
| if-no-files-found: error | |
| freebsd: | |
| if: github.event_name != 'workflow_dispatch' | |
| runs-on: ubuntu-24.04 | |
| timeout-minutes: 180 | |
| steps: | |
| - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 | |
| - name: freebsd_instance | |
| uses: vmactions/freebsd-vm@c9f815bc7aa0d34c9fdd0619b034a32d6ca7b57e | |
| with: | |
| release: '14.3' | |
| mem: 8192 | |
| cpu: 2 | |
| prepare: pkg install -y bash autoconf automake libtool pkgconf python3 gmake curl binutils perl5 llvm19 git node24 | |
| run: | | |
| set -eu | |
| export RUNNER_TEMP=/tmp/v3-package-${{ github.run_id }}-${{ github.run_attempt }} | |
| mkdir -p "$RUNNER_TEMP/package-evidence" | |
| trap 'cp -R "$RUNNER_TEMP/package-evidence" ./package-evidence' EXIT | |
| # Guest root must trust only the host checkout, including in Python's Git children. | |
| export GIT_CONFIG_COUNT=1 GIT_CONFIG_KEY_0=safe.directory GIT_CONFIG_VALUE_0="$PWD" | |
| git_log="$RUNNER_TEMP/package-evidence/git-provenance.log" | |
| { | |
| printf 'checkout=%s\n' "$PWD" && command -v git && git --version && | |
| git rev-parse --verify 'HEAD^{commit}' | |
| } > "$git_log" 2>&1 || { cat "$git_log" >&2; exit 1; } | |
| cat "$git_log" | |
| if [ "$(node --version)" != v24.15.0 ]; then | |
| mkdir -p "$RUNNER_TEMP/node-source" | |
| node_logs="$RUNNER_TEMP/package-evidence/node-source" | |
| mkdir -p "$node_logs" | |
| curl --fail --location https://nodejs.org/dist/v24.15.0/node-v24.15.0.tar.gz -o "$RUNNER_TEMP/node-source/node-v24.15.0.tar.gz" | |
| test "$(sha256 -q "$RUNNER_TEMP/node-source/node-v24.15.0.tar.gz")" = 729de494dd2872e5a3a6c32a1cd156a5413d4aca2772b2d873ee86bb5531bcd9 | |
| tar -xzf "$RUNNER_TEMP/node-source/node-v24.15.0.tar.gz" -C "$RUNNER_TEMP/node-source" | |
| ( | |
| cd "$RUNNER_TEMP/node-source/node-v24.15.0" | |
| { | |
| node_llvm_bin="$(llvm-config19 --bindir)" | |
| export CC="$node_llvm_bin/clang" CXX="$node_llvm_bin/clang++" | |
| printf 'CC=%s\nCXX=%s\n' "$CC" "$CXX" | |
| "$CC" --version | |
| "$CXX" --version | |
| } > "$node_logs/compiler.log" 2>&1 | |
| ./configure --prefix="$RUNNER_TEMP/node" > "$node_logs/configure.log" 2>&1 | |
| gmake -j2 > "$node_logs/build.log" 2>&1 | |
| gmake install >> "$node_logs/build.log" 2>&1 | |
| ) | |
| export PATH="$RUNNER_TEMP/node/bin:$PATH" | |
| fi | |
| test "$(node --version)" = v24.15.0 | |
| python3 -c 'import subprocess; subprocess.run(["git", "--version"], check=True)' | |
| python3 -m venv "$RUNNER_TEMP/package-evidence/clients" | |
| "$RUNNER_TEMP/package-evidence/clients/bin/python" -m pip install -r test/integ/http2-client-requirements.txt | |
| python3 scripts/prepare-v3-package-ci.py --output "$RUNNER_TEMP/package-evidence/prerequisites" --make gmake | |
| ./bootstrap | |
| python3 scripts/check-v3-installed-consumer.py --output "$RUNNER_TEMP/package-evidence/matrix" \ | |
| --provider-prefix "$RUNNER_TEMP/package-evidence/prerequisites/provider" \ | |
| --client-python "$RUNNER_TEMP/package-evidence/clients/bin/python" --node node --pkg-config-dir /usr/local/share/pkgconfig --compiler clang++ --cc clang --make gmake --jobs 2 | |
| - name: Recover FreeBSD evidence | |
| if: always() | |
| run: | | |
| mkdir -p package-evidence | |
| scp -O -r "freebsd:/tmp/v3-package-${{ github.run_id }}-${{ github.run_attempt }}/package-evidence" ./ | |
| - if: always() | |
| uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 | |
| with: | |
| name: v3-package-freebsd-${{ github.sha }} | |
| path: package-evidence | |
| retention-days: 14 | |
| if-no-files-found: error |