6969 { nodes } :
7070 # python
7171 ''
72+ import functools
7273 import json
7374 import random
7475 import re
159160 versioned: If True, enable versioning on the bucket before populating
160161 """
161162 def decorator(test_func):
162- def wrapper():
163+ @functools.wraps(test_func)
164+ def wrapper(*args, **kwargs):
163165 bucket = str(uuid.uuid4())
164166 server.succeed(f"mc mb minio/{bucket}")
165167 try:
171173 store_url = make_s3_url(bucket)
172174 for pkg in populate_bucket:
173175 server.succeed(f"{ENV_WITH_CREDS} nix copy --to '{store_url}' {pkg}")
174- test_func(bucket)
176+ test_func(bucket, *args, **kwargs )
175177 finally:
176178 server.succeed(f"mc rb --force minio/{bucket}")
177179 # Clean up client store - only delete if path exists
180182 return wrapper
181183 return decorator
182184
185+ def parametrize_url_schemes(test_func):
186+ """Decorator that runs a test with both s3:// and https:// URL schemes
187+
188+ The decorated test receives a 'url_maker' callable that generates
189+ the appropriate store URL for a given bucket. Each URL scheme gets
190+ a fresh bucket (when combined with setup_s3).
191+
192+ Usage:
193+ @parametrize_url_schemes
194+ @setup_s3(populate_bucket=[PKGS['A']], public=True)
195+ def test_something(bucket, url_maker):
196+ store_url = url_maker(bucket)
197+ # test code uses store_url
198+ """
199+ @functools.wraps(test_func)
200+ def wrapper():
201+ url_schemes = [
202+ ("s3://", lambda b: make_s3_url(b)),
203+ ("https://", lambda b: f"http://server:9000/{b}")
204+ ]
205+
206+ for scheme_name, url_maker in url_schemes:
207+ print(f"\n → Testing with {scheme_name} URLs")
208+ try:
209+ test_func(url_maker)
210+ except Exception as e:
211+ print(f" ✗ Failed with {scheme_name} URLs")
212+ raise Exception(f"Test failed for {scheme_name} URLs: {e}") from e
213+ print(f" ✓ All checks passed with {scheme_name} URLs")
214+
215+ return wrapper
216+
183217 # ============================================================================
184218 # Test Functions
185219 # ============================================================================
359393 print(" ✓ nix copy works")
360394 print(" ✓ Credentials cached on client")
361395
396+ @parametrize_url_schemes
362397 @setup_s3(populate_bucket=[PKGS['A'], PKGS['B']], public=True)
363- def test_public_bucket_operations(bucket):
364- """Test store operations on public bucket without credentials """
398+ def test_public_bucket_operations(bucket, url_maker ):
399+ """Test store operations on public bucket using both s3:// and https:// URLs """
365400 print("\n=== Testing Public Bucket Operations ===")
366401
367- store_url = make_s3_url (bucket)
402+ store_url = url_maker (bucket)
368403
369404 # Verify store info works without credentials
370405 client.succeed(f"nix store info --store '{store_url}' >&2")
371- print(" ✓ nix store info works without credentials ")
406+ print(" ✓ nix store info works")
372407
373408 # Get and validate store info JSON
374409 info_json = client.succeed(f"nix store info --json --store '{store_url}'")
@@ -383,15 +418,123 @@ in
383418 verify_packages_in_store(client, [PKGS['A'], PKGS['B']], should_exist=False)
384419
385420 # Test copy from public bucket without credentials
386- client.succeed(
421+ output = client.succeed(
387422 f"nix copy --debug --no-check-sigs "
388423 f"--from '{store_url}' {PKGS['A']} {PKGS['B']} 2>&1"
389424 )
390425
426+ # For HTTPS URLs, verify no credential provider was created
427+ # For s3:// URLs, credential provider might be created but works due to fallback
428+ if store_url.startswith("http://") or store_url.startswith("https://"):
429+ if "creating new AWS credential provider" in output:
430+ print("Debug output:")
431+ print(output)
432+ raise Exception("HTTPS URLs should NOT create AWS credential provider")
433+ print(" ✓ No credential provider created (HTTPS URL)")
434+ else:
435+ print(" ✓ S3 URL works with public bucket")
436+
391437 # Verify packages were copied successfully
392438 verify_packages_in_store(client, [PKGS['A'], PKGS['B']])
439+ print(" ✓ Packages successfully copied from public bucket")
440+
441+ @parametrize_url_schemes
442+ @setup_s3(public=True)
443+ def test_fetchurl_public_bucket(bucket, url_maker):
444+ """Test fetchurl with public S3 URLs using both s3:// and https:// schemes"""
445+ print("\n=== Testing fetchurl with Public S3 URLs ===")
446+
447+ client.wait_for_unit("network-addresses-eth1.service")
448+
449+ # Upload a test file to the public bucket
450+ test_content = "Public S3 test file content\n"
451+ server.succeed(f"echo -n '{test_content}' > /tmp/public-test-file.txt")
452+
453+ # Calculate expected hash
454+ file_hash = server.succeed(
455+ "nix hash file --type sha256 --base32 /tmp/public-test-file.txt"
456+ ).strip()
457+
458+ server.succeed(f"mc cp /tmp/public-test-file.txt minio/{bucket}/public-test.txt")
459+ print(" ✓ Uploaded test file to public bucket")
460+
461+ # Build file URL based on bucket URL
462+ bucket_url = url_maker(bucket)
463+ if bucket_url.startswith("http://") or bucket_url.startswith("https://"):
464+ file_url = f"{bucket_url}/public-test.txt"
465+ else:
466+ # s3:// URL
467+ file_url = make_s3_url(bucket, path="/public-test.txt")
468+
469+ # Test 1: builtins.fetchurl
470+ # ============================
471+ output = client.succeed(
472+ f"nix eval --debug --impure --expr "
473+ f"'builtins.fetchurl {{ name = \"public-test\"; url = \"{file_url}\"; }}' 2>&1"
474+ )
475+
476+ # For HTTPS URLs, verify no AWS credential handling
477+ if file_url.startswith("http://") or file_url.startswith("https://"):
478+ if "creating new AWS credential provider" in output:
479+ print("Debug output:")
480+ print(output)
481+ raise Exception("HTTPS URLs should not trigger AWS credential providers")
482+
483+ if "Pre-resolving AWS credentials" in output:
484+ print("Debug output:")
485+ print(output)
486+ raise Exception("HTTPS URLs should not trigger credential pre-resolution")
487+
488+ print(" ✓ No AWS credential handling for HTTPS URL")
489+ else:
490+ print(" ✓ S3 URL works with public bucket")
491+
492+ print(" ✓ builtins.fetchurl successful")
493+
494+ # Test 2: import <nix/fetchurl.nix> (fixed-output derivation)
495+ # ===========================================================
496+ print("\n Testing import <nix/fetchurl.nix>...")
497+
498+ test_id = random.randint(0, 10000)
499+ test_url = f"{file_url}?test_id={test_id}"
500+
501+ fetchurl_expr = """
502+ import <nix/fetchurl.nix> {{
503+ name = "public-fork-test-{id}";
504+ url = "{url}";
505+ sha256 = "{hash}";
506+ }}
507+ """.format(id=test_id, url=test_url, hash=file_hash)
508+
509+ build_output = client.succeed(
510+ f"nix build --debug --impure --no-link --expr '{fetchurl_expr}' 2>&1"
511+ )
512+
513+ # Verify fork behavior
514+ if "builtin:fetchurl creating fresh FileTransfer instance" not in build_output:
515+ print("Debug output:")
516+ print(build_output)
517+ raise Exception("Expected FileTransfer creation in forked process")
518+
519+ print(" ✓ Forked process creates fresh FileTransfer")
520+
521+ # For HTTPS URLs, verify no AWS credential handling in fork
522+ if file_url.startswith("http://") or file_url.startswith("https://"):
523+ if "creating new AWS credential provider" in build_output:
524+ print("Debug output:")
525+ print(build_output)
526+ raise Exception("HTTPS URLs should not create AWS credential providers in fork")
527+
528+ if "Pre-resolving AWS credentials" in build_output or "Using pre-resolved AWS credentials" in build_output:
529+ print("Debug output:")
530+ print(build_output)
531+ raise Exception("HTTPS URLs should not trigger credential pre-resolution")
532+
533+ print(" ✓ No AWS credential handling in forked process")
534+ else:
535+ print(" ✓ S3 URL works in forked process")
393536
394- print(" ✓ nix copy from public bucket works without credentials ")
537+ print(" ✓ import < nix/fetchurl.nix> successful ")
395538
396539 @setup_s3(populate_bucket=[PKGS['A']])
397540 def test_url_format_variations(bucket):
787930 test_fork_credential_preresolution()
788931 test_store_operations()
789932 test_public_bucket_operations()
933+ test_fetchurl_public_bucket()
790934 test_url_format_variations()
791935 test_concurrent_fetches()
792936 test_compression_narinfo_gzip()
0 commit comments