@@ -9,6 +9,7 @@ permissions:
99 contents : read
1010jobs :
1111 linux :
12+ if : github.event_name != 'workflow_dispatch'
1213 runs-on : ubuntu-24.04
1314 timeout-minutes : 90
1415 steps :
4445 retention-days : 14
4546 if-no-files-found : error
4647 macos :
48+ permissions :
49+ contents : read
50+ actions : read
4751 runs-on : macos-15
4852 timeout-minutes : 90
4953 steps :
@@ -67,12 +71,125 @@ jobs:
6771 - name : Bootstrap
6872 run : ./bootstrap
6973 - name : Installed matrix
74+ if : github.event_name != 'workflow_dispatch'
7075 run : |
7176 prefix=()
7277 if ! python3 -c 'import socket; s=socket.socket(); s.bind(("127.0.0.1",443)); s.close()'; then
7378 prefix=(sudo env "PATH=$PATH" GIT_CONFIG_COUNT=1 GIT_CONFIG_KEY_0=safe.directory "GIT_CONFIG_VALUE_0=$PWD")
7479 fi
7580 "${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
81+ # Branch-only checkpoint: remove before merging to v3. This is not matrix proof.
82+ - name : Diagnose installed shared TLS-off external HTTP1 on Darwin
83+ if : github.event_name == 'workflow_dispatch'
84+ env :
85+ GH_TOKEN : ${{ github.token }}
86+ run : |
87+ python3 - <<'PY_DIAGNOSTIC'
88+ import hashlib, importlib.util, json, os, platform, shlex, shutil, subprocess, sys
89+ from pathlib import Path
90+ checkout = Path.cwd().resolve()
91+ sys.path.insert(0, str(checkout / 'scripts/lib'))
92+ import package_matrix as matrix
93+ from package_commands import Commands, runtime_environment
94+ from package_integration import compile_probe
95+ import release_artifact as identity
96+ from release_checks import extract_archive
97+ from release_ci import verify_download
98+ spec = importlib.util.spec_from_file_location('audit', checkout / 'scripts/audit-v3-installed-package.py')
99+ audit = importlib.util.module_from_spec(spec)
100+ spec.loader.exec_module(audit)
101+ assert platform.system() == 'Darwin'
102+ output = Path(os.environ['RUNNER_TEMP']) / 'package-evidence/header-deadline-diagnostic'
103+ output.mkdir()
104+ build, prefix, integration = [output / name for name in ('build', 'prefix', 'integration-shared')]
105+ for directory in (build, prefix, integration):
106+ directory.mkdir()
107+ command = Commands(output)
108+ provider = output.parent / 'prerequisites/provider'
109+ compiler, cc = os.environ['V3_CXX'], os.environ['V3_CC']
110+ toolchain = Path(os.environ['V3_PACKAGE_TOOLCHAIN'])
111+ env = audit.clean_environment()
112+ for key in ('GH_TOKEN', 'GITHUB_TOKEN', 'V3_RELEASE_IDENTITY'):
113+ env.pop(key, None)
114+ env.update(CXX=compiler, CC=cc, CXXFLAGS='-O0 -g',
115+ CPPFLAGS='-DHTTPSERVER_DIAG_HEADER_DEADLINE',
116+ LDFLAGS='-Wl,-rpath,' + str(provider / 'lib'))
117+ receipt = dict(kind='diagnostic-only; not complete package validation', tls='no', linkage='shared',
118+ revision=command(['git', 'rev-parse', 'HEAD'], checkout, env).strip(),
119+ compiler=command([compiler, '--version'], checkout, env),
120+ provider_header_sha256=hashlib.sha256((provider / 'include/openssl/opensslv.h').read_bytes()).hexdigest())
121+ try:
122+ expected = dict(repository=os.environ['GITHUB_REPOSITORY'], run_id='39969790346', run_attempt='1',
123+ workflow_head='c0cfdabc8040273d60c610269a93d1c687ed8517', artifact_id='12508482722')
124+ endpoint = 'repos/' + expected['repository'] + '/actions/artifacts/' + expected['artifact_id']
125+ metadata = json.loads(subprocess.check_output(['gh', 'api', endpoint], text=True))
126+ run = json.loads(subprocess.check_output(['gh', 'api', 'repos/' + expected['repository'] +
127+ '/actions/runs/' + expected['run_id'] + '/attempts/' + expected['run_attempt']], text=True))
128+ (output / 'selected-artifact-metadata.json').write_text(json.dumps(metadata, indent=2) + '\n')
129+ (output / 'selected-run-metadata.json').write_text(json.dumps(run, indent=2) + '\n')
130+ downloaded = output / 'selected-archive.zip'
131+ with downloaded.open('xb') as destination:
132+ subprocess.run(['gh', 'api', endpoint + '/zip'], stdout=destination, check=True)
133+ zip_digest = 'sha256:a08eb79186b13cf12ac8c639f424e13a7de1ee09df5547aab2b4200a951a5f05'
134+ verify_download(downloaded, metadata, run, expected, zip_digest, output / 'selected')
135+ selected = json.loads((output / 'selected/selected.json').read_text())
136+ archive = output / 'selected/libhttpserver-3.0.0.tar.gz'
137+ assert selected['commit'] == selected['source']['head'] == expected['workflow_head']
138+ assert selected['archive'] == archive.name and archive.stat().st_size == 3053890
139+ assert identity.sha256(archive) == selected['sha256'] == '43124552f20bd00fceddc714856d605ca9caf017a849a991c34f16f437fcab83'
140+ source = extract_archive(archive, output / 'source')
141+ originals = identity.source_files(source)
142+ assert originals and all(selected['files_sha256'].get(name) == digest for name, digest in originals.items())
143+ (output / 'original-source-hashes.json').write_text(json.dumps(originals, indent=2) + '\n')
144+ overlay = {}
145+ names = ['src/detail/' + name + '.cpp' for name in ('connection_engine', 'connection_engine_websocket',
146+ 'io_external_adapter', 'io_operation', 'io_poll_backend', 'io_poll_sys', 'io_timer_sweep')]
147+ names += ['test/integ/external_http1_e2e_test.cpp', 'src/httpserver/detail/deadline_trace.hpp']
148+ for name in names:
149+ original = originals.get(name)
150+ if name.endswith('/deadline_trace.hpp'):
151+ assert original is None and name not in selected['source']['files_sha256']
152+ else:
153+ assert original == selected['source']['files_sha256'][name]
154+ overlay[name] = dict(original_sha256=original, diagnostic_sha256=identity.sha256(checkout / name))
155+ shutil.copyfile(checkout / name, source / name)
156+ modified = identity.source_files(source)
157+ assert set(modified) - set(originals) == {'src/httpserver/detail/deadline_trace.hpp'}
158+ assert {name for name in originals if modified[name] != originals[name]} == set(names[:-1])
159+ (output / 'diagnostic-source-hashes.json').write_text(json.dumps(modified, indent=2) + '\n')
160+ receipt['source_archive'] = dict(**expected, artifact_zip_sha256=zip_digest,
161+ archive_sha256=selected['sha256'], source_root=str(source), overlay=overlay,
162+ provenance='verified original archive plus explicit diagnostic overlay; not immutable release proof')
163+ command(['bash', source / 'configure', '--enable-v3-tls=no', '--disable-examples', '--prefix=' + str(prefix)], build, env)
164+ command(['make', '-j2'], build, env)
165+ command(['make', 'install'], build, env)
166+ runtime = runtime_environment({key: value for key, value in audit.clean_environment().items()
167+ if key not in ('GH_TOKEN', 'GITHUB_TOKEN', 'V3_RELEASE_IDENTITY')}, prefix, provider, [], toolchain)
168+ runtime.update(PKG_CONFIG_PATH='', PKG_CONFIG_LIBDIR=str(prefix / 'lib/pkgconfig'))
169+ os.environ.update({key: runtime[key] for key in ('LD_LIBRARY_PATH', 'DYLD_LIBRARY_PATH', 'V3_PACKAGE_TOOLCHAIN')})
170+ cflags = shlex.split(command(['pkg-config', '--cflags', 'libhttpserver'], integration, runtime))
171+ libraries = shlex.split(command(['pkg-config', '--libs', 'libhttpserver'], integration, runtime))
172+ libraries += ['-pthread', '-Wl,-rpath,' + str(prefix / 'lib'), '-Wl,-rpath,' + str(provider / 'lib')]
173+ flags = cflags + ['-DHTTPSERVER_COMPILATION', '-DHTTPSERVER_DIAG_HEADER_DEADLINE',
174+ '-I' + str(source / 'src'), '-I' + str(source / 'test')]
175+ definition = matrix.load()['suites']['external_http1_e2e']
176+ units = [source / 'test' / name for name in definition['sources']]
177+ executable = integration / 'external_http1_e2e'
178+ receipt['compile'] = compile_probe(compiler, units, flags, libraries, executable, command, runtime, source, build, prefix, True)
179+ graph = audit.dependency_graph([str(executable)])
180+ matrix.check_linkage(graph, 'shared', prefix)
181+ receipt['dependencies'] = graph
182+ result = command([str(executable)], source / 'test', runtime, timeout=180, allow_failure=True)
183+ print(result, end='', flush=True)
184+ receipt['exit'] = command.records[-1]['exit']
185+ receipt['suite'] = matrix.suite_result(result, receipt['exit'])
186+ receipt['status'] = 'diagnostic suite passed; full matrix not run'
187+ except Exception as error:
188+ receipt.update(status='diagnostic failed', error=str(error))
189+ raise
190+ finally:
191+ (output / 'diagnostic.json').write_text(json.dumps(receipt, indent=2) + '\n')
192+ PY_DIAGNOSTIC
76193 - name : Make privileged proof readable by artifact upload
77194 if : always()
78195 run : |
89206 retention-days : 14
90207 if-no-files-found : error
91208 mingw64 :
209+ if : github.event_name != 'workflow_dispatch'
92210 runs-on : windows-2022
93211 timeout-minutes : 90
94212 defaults :
@@ -148,6 +266,7 @@ jobs:
148266 retention-days : 14
149267 if-no-files-found : error
150268 freebsd :
269+ if : github.event_name != 'workflow_dispatch'
151270 runs-on : ubuntu-24.04
152271 timeout-minutes : 180
153272 steps :
0 commit comments