364364 """Test store operations on public bucket without credentials"""
365365 print("\n=== Testing Public Bucket Operations ===")
366366
367- store_url = make_s3_url(bucket)
367+ store_url = make_s3_url(bucket, public='true' )
368368
369369 # Verify store info works without credentials
370370 client.succeed(f"nix store info --store '{store_url}' >&2")
@@ -383,15 +383,139 @@ in
383383 verify_packages_in_store(client, [PKGS['A'], PKGS['B']], should_exist=False)
384384
385385 # Test copy from public bucket without credentials
386- client.succeed(
386+ output = client.succeed(
387387 f"nix copy --debug --no-check-sigs "
388388 f"--from '{store_url}' {PKGS['A']} {PKGS['B']} 2>&1"
389389 )
390390
391+ # Verify the public flag is working (should see the debug message)
392+ if "S3 request without authentication (marked as public bucket)" not in output:
393+ print("Debug output:")
394+ print(output)
395+ raise Exception("Expected to see public bucket debug message")
396+
397+ # Verify no credential provider was created
398+ if "creating new AWS credential provider" in output:
399+ print("Debug output:")
400+ print(output)
401+ raise Exception("Should NOT create credential provider for public bucket")
402+
391403 # Verify packages were copied successfully
392404 verify_packages_in_store(client, [PKGS['A'], PKGS['B']])
393405
394406 print(" ✓ nix copy from public bucket works without credentials")
407+ print(" ✓ No credential lookup attempted (public=true flag working)")
408+
409+ @setup_s3(public=True)
410+ def test_fetchurl_public_bucket(bucket):
411+ """Test that fetchurl of public S3 URL does not trigger credential attempts"""
412+ print("\n=== Testing fetchurl with Public S3 URL ===")
413+
414+ client.wait_for_unit("network-addresses-eth1.service")
415+
416+ # Upload a test file to the public bucket
417+ test_content = "Public S3 test file content for fetchurl\n"
418+ server.succeed(f"echo -n '{test_content}' > /tmp/public-test-file.txt")
419+
420+ # Calculate expected hash on server where file exists
421+ file_hash = server.succeed(
422+ "nix hash file --type sha256 --base32 /tmp/public-test-file.txt"
423+ ).strip()
424+
425+ server.succeed(f"mc cp /tmp/public-test-file.txt minio/{bucket}/public-test.txt")
426+
427+ print(" ✓ Uploaded test file to public bucket")
428+
429+ # Test 1: builtins.fetchurl (immediate fetch in evaluator)
430+ # ======================================================
431+ s3_url = make_s3_url(bucket, path="/public-test.txt", public='true')
432+
433+ output = client.succeed(
434+ f"nix eval --debug --impure --expr "
435+ f"'builtins.fetchurl {{ name = \"public-s3-test\"; url = \"{s3_url}\"; }}' 2>&1"
436+ )
437+
438+ # Verify the public flag is working (should see the debug message)
439+ if "S3 request without authentication (marked as public bucket)" not in output:
440+ print("Debug output:")
441+ print(output)
442+ raise Exception("Expected to see public bucket debug message for fetchurl")
443+
444+ # Verify no credential provider was created
445+ if "creating new AWS credential provider" in output:
446+ print("Debug output:")
447+ print(output)
448+ raise Exception("fetchurl should NOT create credential provider for public S3 URL")
449+
450+ # Verify no credential pre-resolution happened (that's for private buckets only)
451+ if "Pre-resolving AWS credentials" in output:
452+ print("Debug output:")
453+ print(output)
454+ raise Exception("Should not attempt credential pre-resolution for public buckets")
455+
456+ print(" ✓ builtins.fetchurl works with public S3 URL")
457+ print(" ✓ No credential lookup attempted (public=true flag working)")
458+ print(" ✓ No credential pre-resolution attempted")
459+
460+ # Test 2: import <nix/fetchurl.nix> (fixed-output derivation with fork)
461+ # =====================================================================
462+ print("\n Testing import <nix/fetchurl.nix> with public S3 URL...")
463+
464+ # Build derivation with unique test ID (using hash calculated earlier)
465+ test_id = random.randint(0, 10000)
466+ test_url = make_s3_url(bucket, path="/public-test.txt", public='true', test_id=test_id)
467+
468+ fetchurl_expr = """
469+ import <nix/fetchurl.nix> {{
470+ name = "public-s3-fork-test-{id}";
471+ url = "{url}";
472+ sha256 = "{hash}";
473+ }}
474+ """.format(id=test_id, url=test_url, hash=file_hash)
475+
476+ build_output = client.succeed(
477+ f"nix build --debug --impure --no-link --expr '{fetchurl_expr}' 2>&1"
478+ )
479+
480+ # Verify fork behavior - should create fresh FileTransfer
481+ if "builtin:fetchurl creating fresh FileTransfer instance" not in build_output:
482+ print("Debug output:")
483+ print(build_output)
484+ raise Exception("Expected to find FileTransfer creation in forked process")
485+
486+ print(" ✓ Forked process creates fresh FileTransfer")
487+
488+ # Verify public bucket handling in forked process
489+ if "S3 request without authentication (marked as public bucket)" not in build_output:
490+ print("Debug output:")
491+ print(build_output)
492+ raise Exception("Expected to see public bucket debug message in forked process")
493+
494+ print(" ✓ Public bucket flag respected in forked process")
495+
496+ # Verify no credential provider was created (neither in parent nor child)
497+ if "creating new AWS credential provider" in build_output:
498+ print("Debug output:")
499+ print(build_output)
500+ raise Exception("Should NOT create credential provider for public S3 URL in fixed-output derivation")
501+
502+ print(" ✓ No credential provider created in parent or child process")
503+
504+ # Verify no credential pre-resolution happened
505+ # (public buckets should skip this entirely, unlike private buckets)
506+ if "Pre-resolving AWS credentials" in build_output:
507+ print("Debug output:")
508+ print(build_output)
509+ raise Exception("Should not attempt credential pre-resolution for public buckets")
510+
511+ if "Using pre-resolved AWS credentials from parent process" in build_output:
512+ print("Debug output:")
513+ print(build_output)
514+ raise Exception("Should not have pre-resolved credentials to use for public buckets")
515+
516+ print(" ✓ No credential pre-resolution attempted (public bucket optimization)")
517+ print("\n ✓ import <nix/fetchurl.nix> works with public S3 URL")
518+ print(" ✓ Fork + build path correctly skips all credential operations")
395519
396520 @setup_s3(populate_bucket=[PKGS['A']])
397521 def test_url_format_variations(bucket):
787911 test_fork_credential_preresolution()
788912 test_store_operations()
789913 test_public_bucket_operations()
914+ test_fetchurl_public_bucket()
790915 test_url_format_variations()
791916 test_concurrent_fetches()
792917 test_compression_narinfo_gzip()
0 commit comments