From 17c72856cead1763a2051a91a030fc5c5eca6bce Mon Sep 17 00:00:00 2001 From: Brandon Payton Date: Fri, 10 Jul 2026 23:53:57 -0400 Subject: [PATCH 01/13] wget: add HTTPS retrieval formula --- Formula/wget.rb | 86 +++++++++++++++++++++++++++++++++++++++++++++++++ README.md | 1 + 2 files changed, 87 insertions(+) create mode 100644 Formula/wget.rb diff --git a/Formula/wget.rb b/Formula/wget.rb new file mode 100644 index 0000000..9efea45 --- /dev/null +++ b/Formula/wget.rb @@ -0,0 +1,86 @@ +require_relative "../Kandelo/formula_support/kandelo_formula_support" + +class Wget < Formula + include KandeloFormulaSupport + + desc "GNU network file retriever for Kandelo" + homepage "https://www.gnu.org/software/wget/" + url "https://ftpmirror.gnu.org/gnu/wget/wget-1.25.0.tar.gz" + mirror "https://ftp.gnu.org/gnu/wget/wget-1.25.0.tar.gz" + sha256 "766e48423e79359ea31e41db9e5c289675947a7fcf2efdcedb726ac9d0da3784" + license "GPL-3.0-or-later" + + depends_on "automattic/kandelo-homebrew/openssl" + depends_on "automattic/kandelo-homebrew/zlib" + + skip_clean "bin/wget" + + def install + kandelo_require_arch!("wasm32") + openssl = formula_opt_prefix("automattic/kandelo-homebrew/openssl") + zlib = formula_opt_prefix("automattic/kandelo-homebrew/zlib") + + instrumented = buildpath/"src/wget.instrumented" + kandelo_wasm_build do |root| + ENV["CPPFLAGS"] = "-I#{openssl}/include -I#{zlib}/include" + ENV["LDFLAGS"] = "-L#{openssl}/lib -L#{zlib}/lib" + ENV["OPENSSL_CFLAGS"] = "-I#{openssl}/include" + ENV["OPENSSL_LIBS"] = "-L#{openssl}/lib -lssl -lcrypto -ldl" + ENV["ZLIB_CFLAGS"] = "-I#{zlib}/include" + ENV["ZLIB_LIBS"] = "-L#{zlib}/lib -lz" + + # The SDK site owns target facts; this gnulib runtime probe is package-specific. + ENV["gl_cv_func_strerror_0_works"] = "yes" + + system kandelo_configure, *kandelo_std_configure_args, + "--disable-nls", + "--disable-iri", + "--disable-pcre", + "--disable-pcre2", + "--disable-xattr", + "--without-libpsl", + "--without-metalink", + "--without-libuuid", + "--with-ssl=openssl" + system "make", "-j#{ENV.make_jobs}" + system "#{root}/scripts/run-wasm-fork-instrument.sh", buildpath/"src/wget", "-o", instrumented + end + + kandelo_install_bin(buildpath/"src", "wget.instrumented", "wget") + end + + test do + version_output = kandelo_run_wasm(bin/"wget", ["--version"]) + assert_match(/^GNU Wget 1\.25\.0 /, version_output) + assert_match(%r{(?:\A|\s)\+ssl/openssl(?:\s|\z)}, version_output) + + page = kandelo_run_wasm( + bin/"wget", + [ + "--quiet", + "--no-hsts", + "--timeout=20", + "--tries=1", + "--output-document=-", + "https://example.com/", + ], + network: true, + ) + assert_match(%r{Example Domain}, page) + + failure = kandelo_run_wasm( + bin/"wget", + [ + "--no-hsts", + "--timeout=2", + "--tries=1", + "--output-document=-", + "http://127.0.0.1:1/", + ], + merge_stderr: true, + network: true, + expected_status: 4, + ) + assert_match(/Connection refused/, failure) + end +end diff --git a/README.md b/README.md index 58d0db0..0dc6dbb 100644 --- a/README.md +++ b/README.md @@ -63,6 +63,7 @@ Current migration controls and pilots include: - `ctags`, Universal Ctags' maintained tag generator, `readtags` query client, and optscript interpreter with complete C and C++ workflows. - `tar`, the GNU archive creation and extraction CLI. +- `wget`, GNU HTTP and HTTPS retrieval linked against the tap TLS and compression roots. The SDK is not yet a Homebrew dependency. Trusted builds supply an `HOMEBREW_KANDELO_ROOT` checkout containing the SDK, sysroot, kernel, and Node From 4d0b0e040803093a3f5bc0ca9fbaa7efdeeb7da1 Mon Sep 17 00:00:00 2001 From: Brandon Payton Date: Sat, 11 Jul 2026 00:41:13 -0400 Subject: [PATCH 02/13] wget: install standard configuration and manuals --- Formula/wget.rb | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/Formula/wget.rb b/Formula/wget.rb index 9efea45..4e3c7cd 100644 --- a/Formula/wget.rb +++ b/Formula/wget.rb @@ -33,6 +33,7 @@ def install ENV["gl_cv_func_strerror_0_works"] = "yes" system kandelo_configure, *kandelo_std_configure_args, + "--sysconfdir=#{etc}", "--disable-nls", "--disable-iri", "--disable-pcre", @@ -47,12 +48,22 @@ def install end kandelo_install_bin(buildpath/"src", "wget.instrumented", "wget") + etc.install buildpath/"doc/sample.wgetrc" => "wgetrc" + man1.install buildpath/"doc/wget.1" end test do - version_output = kandelo_run_wasm(bin/"wget", ["--version"]) + assert_path_exists etc/"wgetrc" + assert_path_exists man1/"wget.1" + + test_wgetrc = testpath/"wgetrc" + test_wgetrc.binwrite((etc/"wgetrc").binread) + version_output = kandelo_run_wasm( + bin/"wget", ["--config=wgetrc", "--version"], env: { "KERNEL_CWD" => testpath } + ) assert_match(/^GNU Wget 1\.25\.0 /, version_output) assert_match(%r{(?:\A|\s)\+ssl/openssl(?:\s|\z)}, version_output) + assert_match(/#{Regexp.escape((etc/"wgetrc").to_s)} \(system\)/, version_output) page = kandelo_run_wasm( bin/"wget", From 64c8bc9fc7c908f17d12e50742121f8d82fca5c1 Mon Sep 17 00:00:00 2001 From: Brandon Payton Date: Sat, 11 Jul 2026 11:19:26 -0400 Subject: [PATCH 03/13] wget: make runtime paths and capabilities verifiable --- Formula/wget.rb | 124 +++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 112 insertions(+), 12 deletions(-) diff --git a/Formula/wget.rb b/Formula/wget.rb index 4e3c7cd..73d6700 100644 --- a/Formula/wget.rb +++ b/Formula/wget.rb @@ -3,6 +3,12 @@ class Wget < Formula include KandeloFormulaSupport + GUEST_HOMEBREW_PREFIX = "/home/linuxbrew/.linuxbrew".freeze + GUEST_OPT_PREFIX = "#{GUEST_HOMEBREW_PREFIX}/opt/wget".freeze + GUEST_OPENSSL_PREFIX = "#{GUEST_HOMEBREW_PREFIX}/opt/openssl".freeze + GUEST_ZLIB_PREFIX = "#{GUEST_HOMEBREW_PREFIX}/opt/zlib".freeze + GUEST_WGETRC = "#{GUEST_HOMEBREW_PREFIX}/etc/wgetrc".freeze + desc "GNU network file retriever for Kandelo" homepage "https://www.gnu.org/software/wget/" url "https://ftpmirror.gnu.org/gnu/wget/wget-1.25.0.tar.gz" @@ -20,8 +26,24 @@ def install openssl = formula_opt_prefix("automattic/kandelo-homebrew/openssl") zlib = formula_opt_prefix("automattic/kandelo-homebrew/zlib") - instrumented = buildpath/"src/wget.instrumented" kandelo_wasm_build do |root| + path_maps = { + buildpath.to_s => "/usr/src/wget", + root.to_s => "/usr/src/kandelo", + openssl.to_s => GUEST_OPENSSL_PREFIX, + zlib.to_s => GUEST_ZLIB_PREFIX, + prefix.to_s => GUEST_OPT_PREFIX, + } + prefix_map_flags = path_maps.map do |source, destination| + "-ffile-prefix-map=#{source}=#{destination} " \ + "-fdebug-prefix-map=#{source}=#{destination} " \ + "-fmacro-prefix-map=#{source}=#{destination}" + end + + # Wget records its compiler and flags in `wget --version`; use the stable + # SDK tool name and map build locations to guest/source identities. + ENV["CC"] = "#{kandelo_arch}posix-cc" + ENV["CFLAGS"] = "-O2 #{prefix_map_flags.join(" ")}" ENV["CPPFLAGS"] = "-I#{openssl}/include -I#{zlib}/include" ENV["LDFLAGS"] = "-L#{openssl}/lib -L#{zlib}/lib" ENV["OPENSSL_CFLAGS"] = "-I#{openssl}/include" @@ -32,8 +54,9 @@ def install # The SDK site owns target facts; this gnulib runtime probe is package-specific. ENV["gl_cv_func_strerror_0_works"] = "yes" - system kandelo_configure, *kandelo_std_configure_args, - "--sysconfdir=#{etc}", + system kandelo_configure, + "--prefix=#{GUEST_OPT_PREFIX}", + "--sysconfdir=#{GUEST_HOMEBREW_PREFIX}/etc", "--disable-nls", "--disable-iri", "--disable-pcre", @@ -44,10 +67,74 @@ def install "--without-libuuid", "--with-ssl=openssl" system "make", "-j#{ENV.make_jobs}" - system "#{root}/scripts/run-wasm-fork-instrument.sh", buildpath/"src/wget", "-o", instrumented + + # Upstream deliberately exposes the full compile/link flags in --version. + # Preserve that information while replacing host staging paths with the + # same stable identities used in debug metadata. + version_source = buildpath/"src/version.c" + version_contents = version_source.read + path_maps.each { |source, destination| version_contents.gsub!(source, destination) } + version_source.atomic_write(version_contents) + [buildpath/"src/version.o", buildpath/"src/wget-version.o", buildpath/"src/wget"].each do |object| + object.delete if object.exist? + end + system "make", "-C", "src", "wget" + + artifact = kandelo_fork_instrument(buildpath/"src/wget") + artifact_guards = "#{root}/scripts/wasm-artifact-guards.sh" + system "bash", "-c", <<~SH + set -euo pipefail + . #{artifact_guards.shellescape} + wasm_require_no_legacy_asyncify #{artifact.to_s.shellescape} + if ! wasm_imports_kernel_fork #{artifact.to_s.shellescape}; then + echo "ERROR: Wget no longer imports kernel_fork" >&2 + exit 1 + fi + wasm_require_fork_instrumentation_if_needed #{artifact.to_s.shellescape} + if ! wasm_has_complete_fork_instrumentation #{artifact.to_s.shellescape}; then + echo "ERROR: Wget has incomplete fork instrumentation" >&2 + exit 1 + fi + SH + + expected_abi = (Pathname(root)/"crates/shared/src/lib.rs").read[ + /^pub const ABI_VERSION: u32 = ([0-9]+);$/, + 1, + ] + odie "could not read Kandelo ABI version" if expected_abi.nil? + + abi_probe = <<~JS + import { readFileSync } from "node:fs"; + import { pathToFileURL } from "node:url"; + const { extractAbiVersion } = await import(pathToFileURL(process.argv[1]).href); + const bytes = readFileSync(process.argv[2]); + const program = bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength); + const abi = extractAbiVersion(program); + if (abi === null) process.exit(2); + process.stdout.write(String(abi)); + JS + artifact_abi = cd(root) do + Utils.safe_popen_read( + "node", "--import", "tsx/esm", "--input-type=module", "--eval", abi_probe, + Pathname(root)/"host/src/constants.ts", artifact + ).strip + end + odie "Wget ABI #{artifact_abi} does not match Kandelo ABI #{expected_abi}" if artifact_abi != expected_abi + + binary = artifact.binread + { + "Wget build path" => buildpath.to_s, + "Wget Cellar path" => prefix.to_s, + "Wget host etc path" => etc.to_s, + "Kandelo checkout path" => root.to_s, + "Nix store path" => "/nix/store/", + "temporary build path" => "/private/tmp/", + }.each do |description, marker| + odie "Wget embeds #{description}: #{marker}" if binary.include?(marker) + end end - kandelo_install_bin(buildpath/"src", "wget.instrumented", "wget") + kandelo_install_bin(buildpath/"src", "wget", "wget") etc.install buildpath/"doc/sample.wgetrc" => "wgetrc" man1.install buildpath/"doc/wget.1" end @@ -57,27 +144,39 @@ def install assert_path_exists man1/"wget.1" test_wgetrc = testpath/"wgetrc" - test_wgetrc.binwrite((etc/"wgetrc").binread) + test_wgetrc.binwrite((etc/"wgetrc").binread + "\nquiet = on\n") + version_guest_files = { GUEST_WGETRC => test_wgetrc } + guest_files = { GUEST_WGETRC => etc/"wgetrc" } version_output = kandelo_run_wasm( - bin/"wget", ["--config=wgetrc", "--version"], env: { "KERNEL_CWD" => testpath } + bin/"wget", ["--version"], guest_files: version_guest_files ) assert_match(/^GNU Wget 1\.25\.0 /, version_output) assert_match(%r{(?:\A|\s)\+ssl/openssl(?:\s|\z)}, version_output) - assert_match(/#{Regexp.escape((etc/"wgetrc").to_s)} \(system\)/, version_output) + %w[-gpgme -iri -metalink -nls -psl].each do |feature| + assert_includes version_output.split, feature + end + assert_match(/#{Regexp.escape(GUEST_WGETRC)} \(system\)/o, version_output) + refute_includes version_output, prefix.to_s + refute_includes version_output, etc.to_s + refute_includes version_output, formula_opt_prefix("automattic/kandelo-homebrew/openssl").to_s + refute_includes version_output, formula_opt_prefix("automattic/kandelo-homebrew/zlib").to_s - page = kandelo_run_wasm( + compressed_page = kandelo_run_wasm( bin/"wget", [ "--quiet", "--no-hsts", + "--compression=auto", "--timeout=20", "--tries=1", "--output-document=-", - "https://example.com/", + "https://nghttp2.org/httpbin/gzip", ], - network: true, + guest_files: guest_files, + network: true, ) - assert_match(%r{Example Domain}, page) + assert_match(/"gzipped":\s*true/, compressed_page) + assert_match(/"Accept-Encoding":\s*"gzip"/, compressed_page) failure = kandelo_run_wasm( bin/"wget", @@ -89,6 +188,7 @@ def install "http://127.0.0.1:1/", ], merge_stderr: true, + guest_files: guest_files, network: true, expected_status: 4, ) From dfdcb95e213b2ac319bd1714c1439537fc614658 Mon Sep 17 00:00:00 2001 From: Brandon Payton Date: Sat, 11 Jul 2026 11:48:02 -0400 Subject: [PATCH 04/13] wget: reject dependency builder paths --- Formula/wget.rb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Formula/wget.rb b/Formula/wget.rb index 73d6700..54527b0 100644 --- a/Formula/wget.rb +++ b/Formula/wget.rb @@ -127,11 +127,16 @@ def install "Wget Cellar path" => prefix.to_s, "Wget host etc path" => etc.to_s, "Kandelo checkout path" => root.to_s, + "OpenSSL build prefix" => openssl.to_s, + "zlib build prefix" => zlib.to_s, "Nix store path" => "/nix/store/", "temporary build path" => "/private/tmp/", + "CI workspace path" => "/home/runner/work/", + "OpenSSL Cellar path" => "/Cellar/openssl/", }.each do |description, marker| odie "Wget embeds #{description}: #{marker}" if binary.include?(marker) end + odie "Wget embeds a builder home path" if binary.match?(%r{/Users/[^/]+/}) end kandelo_install_bin(buildpath/"src", "wget", "wget") From 314fe666fc7d58bb7c4b800df1d7397c8622e624 Mon Sep 17 00:00:00 2001 From: Brandon Payton Date: Sat, 11 Jul 2026 22:36:39 -0400 Subject: [PATCH 05/13] wget: load support through the installed tap --- Formula/wget.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Formula/wget.rb b/Formula/wget.rb index 54527b0..1f03d66 100644 --- a/Formula/wget.rb +++ b/Formula/wget.rb @@ -1,4 +1,4 @@ -require_relative "../Kandelo/formula_support/kandelo_formula_support" +require (Tap.fetch("automattic", "kandelo-homebrew").path/"Kandelo/formula_support/kandelo_formula_support").to_s class Wget < Formula include KandeloFormulaSupport From 58649cabc12e3243b12e11ecd68e19b230bc60aa Mon Sep 17 00:00:00 2001 From: Brandon Payton Date: Sat, 11 Jul 2026 23:28:27 -0400 Subject: [PATCH 06/13] wget: share final artifact validation --- Formula/wget.rb | 63 ++++++------------------------------------------- 1 file changed, 7 insertions(+), 56 deletions(-) diff --git a/Formula/wget.rb b/Formula/wget.rb index 1f03d66..beafc30 100644 --- a/Formula/wget.rb +++ b/Formula/wget.rb @@ -16,6 +16,8 @@ class Wget < Formula sha256 "766e48423e79359ea31e41db9e5c289675947a7fcf2efdcedb726ac9d0da3784" license "GPL-3.0-or-later" + depends_on "binaryen" => :build + depends_on "wabt" => :build depends_on "automattic/kandelo-homebrew/openssl" depends_on "automattic/kandelo-homebrew/zlib" @@ -81,62 +83,11 @@ def install system "make", "-C", "src", "wget" artifact = kandelo_fork_instrument(buildpath/"src/wget") - artifact_guards = "#{root}/scripts/wasm-artifact-guards.sh" - system "bash", "-c", <<~SH - set -euo pipefail - . #{artifact_guards.shellescape} - wasm_require_no_legacy_asyncify #{artifact.to_s.shellescape} - if ! wasm_imports_kernel_fork #{artifact.to_s.shellescape}; then - echo "ERROR: Wget no longer imports kernel_fork" >&2 - exit 1 - fi - wasm_require_fork_instrumentation_if_needed #{artifact.to_s.shellescape} - if ! wasm_has_complete_fork_instrumentation #{artifact.to_s.shellescape}; then - echo "ERROR: Wget has incomplete fork instrumentation" >&2 - exit 1 - fi - SH - - expected_abi = (Pathname(root)/"crates/shared/src/lib.rs").read[ - /^pub const ABI_VERSION: u32 = ([0-9]+);$/, - 1, - ] - odie "could not read Kandelo ABI version" if expected_abi.nil? - - abi_probe = <<~JS - import { readFileSync } from "node:fs"; - import { pathToFileURL } from "node:url"; - const { extractAbiVersion } = await import(pathToFileURL(process.argv[1]).href); - const bytes = readFileSync(process.argv[2]); - const program = bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength); - const abi = extractAbiVersion(program); - if (abi === null) process.exit(2); - process.stdout.write(String(abi)); - JS - artifact_abi = cd(root) do - Utils.safe_popen_read( - "node", "--import", "tsx/esm", "--input-type=module", "--eval", abi_probe, - Pathname(root)/"host/src/constants.ts", artifact - ).strip - end - odie "Wget ABI #{artifact_abi} does not match Kandelo ABI #{expected_abi}" if artifact_abi != expected_abi - - binary = artifact.binread - { - "Wget build path" => buildpath.to_s, - "Wget Cellar path" => prefix.to_s, - "Wget host etc path" => etc.to_s, - "Kandelo checkout path" => root.to_s, - "OpenSSL build prefix" => openssl.to_s, - "zlib build prefix" => zlib.to_s, - "Nix store path" => "/nix/store/", - "temporary build path" => "/private/tmp/", - "CI workspace path" => "/home/runner/work/", - "OpenSSL Cellar path" => "/Cellar/openssl/", - }.each do |description, marker| - odie "Wget embeds #{description}: #{marker}" if binary.include?(marker) - end - odie "Wget embeds a builder home path" if binary.match?(%r{/Users/[^/]+/}) + kandelo_validate_wasm_artifact( + artifact, + fork: :required, + forbidden_paths: [etc, openssl, zlib], + ) end kandelo_install_bin(buildpath/"src", "wget", "wget") From fa63899ab2f3b0185f9ec0947f42e6e067060ad9 Mon Sep 17 00:00:00 2001 From: Brandon Payton Date: Sat, 11 Jul 2026 23:45:14 -0400 Subject: [PATCH 07/13] wget: preserve mapped guest artifact paths --- Formula/wget.rb | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Formula/wget.rb b/Formula/wget.rb index beafc30..0384407 100644 --- a/Formula/wget.rb +++ b/Formula/wget.rb @@ -83,10 +83,13 @@ def install system "make", "-C", "src", "wget" artifact = kandelo_fork_instrument(buildpath/"src/wget") + host_only_paths = path_maps.filter_map do |source, destination| + source if source != destination + end kandelo_validate_wasm_artifact( artifact, fork: :required, - forbidden_paths: [etc, openssl, zlib], + forbidden_paths: host_only_paths, ) end From c3054a852ebf73281ad3616d2d305318244fdea3 Mon Sep 17 00:00:00 2001 From: Brandon Payton Date: Sat, 11 Jul 2026 23:53:59 -0400 Subject: [PATCH 08/13] wget: install the upstream Info manual --- Formula/wget.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Formula/wget.rb b/Formula/wget.rb index 0384407..46f2e58 100644 --- a/Formula/wget.rb +++ b/Formula/wget.rb @@ -95,11 +95,13 @@ def install kandelo_install_bin(buildpath/"src", "wget", "wget") etc.install buildpath/"doc/sample.wgetrc" => "wgetrc" + info.install buildpath/"doc/wget.info" man1.install buildpath/"doc/wget.1" end test do assert_path_exists etc/"wgetrc" + assert_path_exists info/"wget.info" assert_path_exists man1/"wget.1" test_wgetrc = testpath/"wgetrc" From c93bb7d779a7725115163ea4ab675b9ed574e3e5 Mon Sep 17 00:00:00 2001 From: Brandon Payton Date: Sun, 12 Jul 2026 00:02:48 -0400 Subject: [PATCH 09/13] wget: accept stable guest paths on Linux builders --- Formula/wget.rb | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/Formula/wget.rb b/Formula/wget.rb index 46f2e58..758ab6c 100644 --- a/Formula/wget.rb +++ b/Formula/wget.rb @@ -117,10 +117,15 @@ def install assert_includes version_output.split, feature end assert_match(/#{Regexp.escape(GUEST_WGETRC)} \(system\)/o, version_output) - refute_includes version_output, prefix.to_s - refute_includes version_output, etc.to_s - refute_includes version_output, formula_opt_prefix("automattic/kandelo-homebrew/openssl").to_s - refute_includes version_output, formula_opt_prefix("automattic/kandelo-homebrew/zlib").to_s + [ + [prefix.to_s, GUEST_OPT_PREFIX], + [etc.to_s, File.dirname(GUEST_WGETRC)], + [formula_opt_prefix("automattic/kandelo-homebrew/openssl").to_s, GUEST_OPENSSL_PREFIX], + [formula_opt_prefix("automattic/kandelo-homebrew/zlib").to_s, GUEST_ZLIB_PREFIX], + ].each do |source, destination| + assert_includes version_output, destination + refute_includes version_output, source if source != destination + end compressed_page = kandelo_run_wasm( bin/"wget", From f3fddc8bb65ba294e89d56d11efeb8200bf5716e Mon Sep 17 00:00:00 2001 From: Brandon Payton Date: Sun, 12 Jul 2026 04:44:10 -0400 Subject: [PATCH 10/13] wget: verify background fork completion --- Formula/wget.rb | 61 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/Formula/wget.rb b/Formula/wget.rb index 758ab6c..e87b87c 100644 --- a/Formula/wget.rb +++ b/Formula/wget.rb @@ -1,4 +1,5 @@ require (Tap.fetch("automattic", "kandelo-homebrew").path/"Kandelo/formula_support/kandelo_formula_support").to_s +require "socket" class Wget < Formula include KandeloFormulaSupport @@ -144,6 +145,66 @@ def install assert_match(/"gzipped":\s*true/, compressed_page) assert_match(/"Accept-Encoding":\s*"gzip"/, compressed_page) + background_dir = testpath/"background" + background_dir.mkpath + background_payload = "Kandelo Wget background child completed\n" + server = TCPServer.new("127.0.0.1", 0) + server_error = nil + server_thread = Thread.new do + client = nil + begin + client = server.accept + request = +"" + request << client.readpartial(1024) until request.include?("\r\n\r\n") + raise "unexpected Wget request: #{request.lines.first.inspect}" unless request.start_with?("GET /background ") + + client.write([ + "HTTP/1.1 200 OK", + "Content-Type: text/plain", + "Content-Length: #{background_payload.bytesize}", + "Connection: close", + "", + background_payload, + ].join("\r\n")) + rescue => e + server_error = e + ensure + client&.close + end + end + + begin + background_output = kandelo_run_wasm( + bin/"wget", + [ + "--background", + "--no-hsts", + "--timeout=10", + "--tries=1", + "--output-document=/work/background.txt", + "--output-file=/work/wget.log", + "http://127.0.0.1:#{server.addr[1]}/background", + ], + env: { "TIMEOUT" => "15000" }, + merge_stderr: true, + network: true, + guest_files: guest_files, + writable_host_directories: { "/work" => background_dir }, + expected_fork_descendants: 1, + ) + background_pid = background_output[/Continuing in background, pid ([1-9]\d*)\./, 1] + refute_nil background_pid + assert server_thread.join(2), "background Wget child did not complete its HTTP request" + raise server_error if server_error + + assert_equal background_payload, (background_dir/"background.txt").read + assert_match(/saved/, (background_dir/"wget.log").read) + ensure + server.close + server_thread.kill if server_thread.alive? + server_thread.join + end + failure = kandelo_run_wasm( bin/"wget", [ From 2167012efde393da954eaad621fb70ec31323d0d Mon Sep 17 00:00:00 2001 From: Brandon Payton Date: Sun, 12 Jul 2026 15:13:35 -0400 Subject: [PATCH 11/13] wget: consume SDK-owned strerror behavior --- Formula/wget.rb | 3 --- 1 file changed, 3 deletions(-) diff --git a/Formula/wget.rb b/Formula/wget.rb index e87b87c..7054bc3 100644 --- a/Formula/wget.rb +++ b/Formula/wget.rb @@ -54,9 +54,6 @@ def install ENV["ZLIB_CFLAGS"] = "-I#{zlib}/include" ENV["ZLIB_LIBS"] = "-L#{zlib}/lib -lz" - # The SDK site owns target facts; this gnulib runtime probe is package-specific. - ENV["gl_cv_func_strerror_0_works"] = "yes" - system kandelo_configure, "--prefix=#{GUEST_OPT_PREFIX}", "--sysconfdir=#{GUEST_HOMEBREW_PREFIX}/etc", From a679344b51fd82bafba2301f48c41e0ef2df9a57 Mon Sep 17 00:00:00 2001 From: Brandon Payton Date: Sun, 12 Jul 2026 15:40:15 -0400 Subject: [PATCH 12/13] wget: make HTTPS formula tests self-contained --- Formula/wget.rb | 113 +++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 98 insertions(+), 15 deletions(-) diff --git a/Formula/wget.rb b/Formula/wget.rb index 7054bc3..3407950 100644 --- a/Formula/wget.rb +++ b/Formula/wget.rb @@ -1,5 +1,7 @@ require (Tap.fetch("automattic", "kandelo-homebrew").path/"Kandelo/formula_support/kandelo_formula_support").to_s +require "openssl" require "socket" +require "zlib" class Wget < Formula include KandeloFormulaSupport @@ -125,22 +127,103 @@ def install refute_includes version_output, source if source != destination end - compressed_page = kandelo_run_wasm( - bin/"wget", - [ - "--quiet", - "--no-hsts", - "--compression=auto", - "--timeout=20", - "--tries=1", - "--output-document=-", - "https://nghttp2.org/httpbin/gzip", - ], - guest_files: guest_files, - network: true, + ca_key = OpenSSL::PKey::RSA.new(2048) + ca_cert = OpenSSL::X509::Certificate.new + ca_cert.version = 2 + ca_cert.serial = 1 + ca_cert.subject = OpenSSL::X509::Name.parse("/CN=Kandelo Wget Test CA") + ca_cert.issuer = ca_cert.subject + ca_cert.public_key = ca_key.public_key + ca_cert.not_before = Time.now - 60 + ca_cert.not_after = Time.now + 3600 + ca_extensions = OpenSSL::X509::ExtensionFactory.new + ca_extensions.subject_certificate = ca_cert + ca_extensions.issuer_certificate = ca_cert + ca_cert.add_extension(ca_extensions.create_extension("basicConstraints", "CA:TRUE", true)) + ca_cert.add_extension(ca_extensions.create_extension("keyUsage", "keyCertSign,cRLSign", true)) + ca_cert.add_extension(ca_extensions.create_extension("subjectKeyIdentifier", "hash")) + ca_cert.sign(ca_key, OpenSSL::Digest.new("SHA256")) + + server_key = OpenSSL::PKey::RSA.new(2048) + server_cert = OpenSSL::X509::Certificate.new + server_cert.version = 2 + server_cert.serial = 2 + server_cert.subject = OpenSSL::X509::Name.parse("/CN=127.0.0.1") + server_cert.issuer = ca_cert.subject + server_cert.public_key = server_key.public_key + server_cert.not_before = Time.now - 60 + server_cert.not_after = Time.now + 3600 + server_extensions = OpenSSL::X509::ExtensionFactory.new + server_extensions.subject_certificate = server_cert + server_extensions.issuer_certificate = ca_cert + server_cert.add_extension(server_extensions.create_extension("basicConstraints", "CA:FALSE", true)) + server_cert.add_extension( + server_extensions.create_extension("keyUsage", "digitalSignature,keyEncipherment", true), ) - assert_match(/"gzipped":\s*true/, compressed_page) - assert_match(/"Accept-Encoding":\s*"gzip"/, compressed_page) + server_cert.add_extension(server_extensions.create_extension("extendedKeyUsage", "serverAuth")) + server_cert.add_extension(server_extensions.create_extension("subjectAltName", "IP:127.0.0.1")) + server_cert.sign(ca_key, OpenSSL::Digest.new("SHA256")) + + ca_file = testpath/"wget-test-ca.pem" + ca_file.write(ca_cert.to_pem) + compressed_payload = Zlib.gzip("{\"gzipped\":true}\n") + tls_server = TCPServer.new("127.0.0.1", 0) + tls_context = OpenSSL::SSL::SSLContext.new + tls_context.cert = server_cert + tls_context.key = server_key + ssl_server = OpenSSL::SSL::SSLServer.new(tls_server, tls_context) + tls_error = nil + tls_thread = Thread.new do + client = nil + begin + client = ssl_server.accept + request = +"" + request << client.readpartial(1024) until request.include?("\r\n\r\n") + raise "unexpected Wget TLS request: #{request.lines.first.inspect}" unless request.start_with?("GET /gzip ") + raise "Wget did not request gzip compression" unless request.match?(/^Accept-Encoding:\s*gzip\s*$/i) + + client.write([ + "HTTP/1.1 200 OK", + "Content-Type: application/json", + "Content-Encoding: gzip", + "Content-Length: #{compressed_payload.bytesize}", + "Connection: close", + "", + "", + ].join("\r\n")) + client.write(compressed_payload) + rescue => e + tls_error = e + ensure + client&.close + end + end + + begin + compressed_page = kandelo_run_wasm( + bin/"wget", + [ + "--quiet", + "--no-hsts", + "--compression=auto", + "--ca-certificate=/etc/wget-test-ca.pem", + "--timeout=10", + "--tries=1", + "--output-document=-", + "https://127.0.0.1:#{tls_server.addr[1]}/gzip", + ], + guest_files: guest_files.merge("/etc/wget-test-ca.pem" => ca_file), + network: true, + ) + assert tls_thread.join(2), "Wget did not complete its HTTPS request" + raise tls_error if tls_error + + assert_equal "{\"gzipped\":true}\n", compressed_page + ensure + tls_server.close + tls_thread.kill if tls_thread.alive? + tls_thread.join + end background_dir = testpath/"background" background_dir.mkpath From 406bb59fad373048512231697d9204d6f0ccda24 Mon Sep 17 00:00:00 2001 From: Brandon Payton Date: Sun, 12 Jul 2026 16:06:39 -0400 Subject: [PATCH 13/13] wget: test background downloads on reachable HTTPS --- Formula/wget.rb | 192 ++++++++++-------------------------------------- 1 file changed, 37 insertions(+), 155 deletions(-) diff --git a/Formula/wget.rb b/Formula/wget.rb index 3407950..b706d02 100644 --- a/Formula/wget.rb +++ b/Formula/wget.rb @@ -1,7 +1,4 @@ require (Tap.fetch("automattic", "kandelo-homebrew").path/"Kandelo/formula_support/kandelo_formula_support").to_s -require "openssl" -require "socket" -require "zlib" class Wget < Formula include KandeloFormulaSupport @@ -127,163 +124,48 @@ def install refute_includes version_output, source if source != destination end - ca_key = OpenSSL::PKey::RSA.new(2048) - ca_cert = OpenSSL::X509::Certificate.new - ca_cert.version = 2 - ca_cert.serial = 1 - ca_cert.subject = OpenSSL::X509::Name.parse("/CN=Kandelo Wget Test CA") - ca_cert.issuer = ca_cert.subject - ca_cert.public_key = ca_key.public_key - ca_cert.not_before = Time.now - 60 - ca_cert.not_after = Time.now + 3600 - ca_extensions = OpenSSL::X509::ExtensionFactory.new - ca_extensions.subject_certificate = ca_cert - ca_extensions.issuer_certificate = ca_cert - ca_cert.add_extension(ca_extensions.create_extension("basicConstraints", "CA:TRUE", true)) - ca_cert.add_extension(ca_extensions.create_extension("keyUsage", "keyCertSign,cRLSign", true)) - ca_cert.add_extension(ca_extensions.create_extension("subjectKeyIdentifier", "hash")) - ca_cert.sign(ca_key, OpenSSL::Digest.new("SHA256")) - - server_key = OpenSSL::PKey::RSA.new(2048) - server_cert = OpenSSL::X509::Certificate.new - server_cert.version = 2 - server_cert.serial = 2 - server_cert.subject = OpenSSL::X509::Name.parse("/CN=127.0.0.1") - server_cert.issuer = ca_cert.subject - server_cert.public_key = server_key.public_key - server_cert.not_before = Time.now - 60 - server_cert.not_after = Time.now + 3600 - server_extensions = OpenSSL::X509::ExtensionFactory.new - server_extensions.subject_certificate = server_cert - server_extensions.issuer_certificate = ca_cert - server_cert.add_extension(server_extensions.create_extension("basicConstraints", "CA:FALSE", true)) - server_cert.add_extension( - server_extensions.create_extension("keyUsage", "digitalSignature,keyEncipherment", true), + compressed_page = kandelo_run_wasm( + bin/"wget", + [ + "--quiet", + "--no-hsts", + "--compression=auto", + "--timeout=20", + "--tries=1", + "--output-document=-", + "https://nghttp2.org/httpbin/gzip", + ], + guest_files: guest_files, + network: true, ) - server_cert.add_extension(server_extensions.create_extension("extendedKeyUsage", "serverAuth")) - server_cert.add_extension(server_extensions.create_extension("subjectAltName", "IP:127.0.0.1")) - server_cert.sign(ca_key, OpenSSL::Digest.new("SHA256")) - - ca_file = testpath/"wget-test-ca.pem" - ca_file.write(ca_cert.to_pem) - compressed_payload = Zlib.gzip("{\"gzipped\":true}\n") - tls_server = TCPServer.new("127.0.0.1", 0) - tls_context = OpenSSL::SSL::SSLContext.new - tls_context.cert = server_cert - tls_context.key = server_key - ssl_server = OpenSSL::SSL::SSLServer.new(tls_server, tls_context) - tls_error = nil - tls_thread = Thread.new do - client = nil - begin - client = ssl_server.accept - request = +"" - request << client.readpartial(1024) until request.include?("\r\n\r\n") - raise "unexpected Wget TLS request: #{request.lines.first.inspect}" unless request.start_with?("GET /gzip ") - raise "Wget did not request gzip compression" unless request.match?(/^Accept-Encoding:\s*gzip\s*$/i) - - client.write([ - "HTTP/1.1 200 OK", - "Content-Type: application/json", - "Content-Encoding: gzip", - "Content-Length: #{compressed_payload.bytesize}", - "Connection: close", - "", - "", - ].join("\r\n")) - client.write(compressed_payload) - rescue => e - tls_error = e - ensure - client&.close - end - end - - begin - compressed_page = kandelo_run_wasm( - bin/"wget", - [ - "--quiet", - "--no-hsts", - "--compression=auto", - "--ca-certificate=/etc/wget-test-ca.pem", - "--timeout=10", - "--tries=1", - "--output-document=-", - "https://127.0.0.1:#{tls_server.addr[1]}/gzip", - ], - guest_files: guest_files.merge("/etc/wget-test-ca.pem" => ca_file), - network: true, - ) - assert tls_thread.join(2), "Wget did not complete its HTTPS request" - raise tls_error if tls_error - - assert_equal "{\"gzipped\":true}\n", compressed_page - ensure - tls_server.close - tls_thread.kill if tls_thread.alive? - tls_thread.join - end + assert_match(/"gzipped":\s*true/, compressed_page) + assert_match(/"Accept-Encoding":\s*"gzip"/, compressed_page) background_dir = testpath/"background" background_dir.mkpath background_payload = "Kandelo Wget background child completed\n" - server = TCPServer.new("127.0.0.1", 0) - server_error = nil - server_thread = Thread.new do - client = nil - begin - client = server.accept - request = +"" - request << client.readpartial(1024) until request.include?("\r\n\r\n") - raise "unexpected Wget request: #{request.lines.first.inspect}" unless request.start_with?("GET /background ") - - client.write([ - "HTTP/1.1 200 OK", - "Content-Type: text/plain", - "Content-Length: #{background_payload.bytesize}", - "Connection: close", - "", - background_payload, - ].join("\r\n")) - rescue => e - server_error = e - ensure - client&.close - end - end - - begin - background_output = kandelo_run_wasm( - bin/"wget", - [ - "--background", - "--no-hsts", - "--timeout=10", - "--tries=1", - "--output-document=/work/background.txt", - "--output-file=/work/wget.log", - "http://127.0.0.1:#{server.addr[1]}/background", - ], - env: { "TIMEOUT" => "15000" }, - merge_stderr: true, - network: true, - guest_files: guest_files, - writable_host_directories: { "/work" => background_dir }, - expected_fork_descendants: 1, - ) - background_pid = background_output[/Continuing in background, pid ([1-9]\d*)\./, 1] - refute_nil background_pid - assert server_thread.join(2), "background Wget child did not complete its HTTP request" - raise server_error if server_error - - assert_equal background_payload, (background_dir/"background.txt").read - assert_match(/saved/, (background_dir/"wget.log").read) - ensure - server.close - server_thread.kill if server_thread.alive? - server_thread.join - end + background_output = kandelo_run_wasm( + bin/"wget", + [ + "--background", + "--no-hsts", + "--timeout=10", + "--tries=1", + "--output-document=/work/background.txt", + "--output-file=/work/wget.log", + "https://nghttp2.org/httpbin/base64/S2FuZGVsbyBXZ2V0IGJhY2tncm91bmQgY2hpbGQgY29tcGxldGVkCg==", + ], + env: { "TIMEOUT" => "15000" }, + merge_stderr: true, + network: true, + guest_files: guest_files, + writable_host_directories: { "/work" => background_dir }, + expected_fork_descendants: 1, + ) + background_pid = background_output[/Continuing in background, pid ([1-9]\d*)\./, 1] + refute_nil background_pid + assert_equal background_payload, (background_dir/"background.txt").read + assert_match(/saved/, (background_dir/"wget.log").read) failure = kandelo_run_wasm( bin/"wget",