Skip to content

Fix gazelle_python_manifest test failure on Linux due to incorrect runfiles path handling #3397

@timfallmk

Description

@timfallmk

Problem Summary

The gazelle_python_manifest.test generated by the gazelle_python_manifest macro fails on Linux CI but passes on macOS due to incorrect file path handling in the test implementation.

Error Message on Linux

FAIL: TestGazelleManifestIsUpdated (0.00s)
test.go:46: decoding manifest file: failed to decode manifest file:
open tools/python/urf/gazelle_python.yaml: no such file or directory

Root Cause

The test code has an inconsistency in how it accesses data files:

  • Correctly uses runfiles for the manifest generator hash file via runfiles.Rlocation()
  • Incorrectly uses direct file access for the manifest and requirements files
  • Uses $(rootpath) instead of $(rlocationpath) in the Bazel rule definition

This works on macOS because its Bazel sandbox is more lenient, but fails on Linux where the sandbox strictly enforces file access through the runfiles tree.

Technical Details

Why It Fails on Linux But Not macOS

  1. macOS Bazel Sandbox: More lenient, allows accessing workspace files even with rundir = "."
  2. Linux Bazel Sandbox: Stricter isolation, only allows access to files in the runfiles tree
  3. The Path Issue:
    • $(rootpath) expands to workspace-relative paths like gazelle/manifest/gazelle_python.yaml
    • In Linux sandbox, this path doesn't exist - the file is only in the runfiles tree at _main/gazelle/manifest/gazelle_python.yaml
    • The test needs to use runfiles.Rlocation() to find the actual file location

Code Issues

Issue 1: gazelle/manifest/defs.bzl (Lines 120, 122)

Current (incorrect):

attrs = {
    "env": {
        "_TEST_MANIFEST": "$(rootpath {})".format(manifest),  # ❌ Wrong
        "_TEST_MANIFEST_GENERATOR_HASH": "$(rlocationpath {})".format(manifest_generator_hash),  # ✅ Correct
        "_TEST_REQUIREMENTS": "$(rootpath {})".format(requirements),  # ❌ Wrong
    },
}

Should be:

attrs = {
    "env": {
        "_TEST_MANIFEST": "$(rlocationpath {})".format(manifest),  # ✅ Fixed
        "_TEST_MANIFEST_GENERATOR_HASH": "$(rlocationpath {})".format(manifest_generator_hash),  # ✅ Already correct
        "_TEST_REQUIREMENTS": "$(rlocationpath {})".format(requirements),  # ✅ Fixed
    },
}

Issue 2: gazelle/manifest/test/test.go (Lines 53, 73, 84-86)

The test code resolves the paths using runfiles.Rlocation() but then doesn't use the resolved paths:

Current (incorrect):

// Lines 35-38: Correctly resolves the path
requirementsPathResolved, err := runfiles.Rlocation(requirementsPath)
if err != nil {
    t.Fatalf("failed to resolve runfiles path of requirements: %v", err)
}

// Line 73: But then uses the UNRESOLVED path! ❌
requirements, err := os.Open(requirementsPath)  // Bug: should use requirementsPathResolved

Similar issues at:

  • Line 53: manifestFile.Decode(manifestPath) should use manifestPathResolved
  • Line 73: os.Open(requirementsPath) should use requirementsPathResolved
  • Lines 84-86: filepath.EvalSymlinks(manifestPath) should use manifestPathResolved

Example: How It Should Work

The test already has the correct pattern for _TEST_MANIFEST_GENERATOR_HASH:

// ✅ This is the correct pattern (lines 61-65):
manifestGeneratorHashPath, err := runfiles.Rlocation(
    os.Getenv("_TEST_MANIFEST_GENERATOR_HASH"))
if err != nil {
    t.Fatalf("failed to resolve runfiles path of manifest: %v", err)
}

// Then uses the resolved path:
manifestGeneratorHash, err := os.Open(manifestGeneratorHashPath)  // ✅ Correct

The same pattern needs to be applied to _TEST_MANIFEST and _TEST_REQUIREMENTS.

Why This Fix Works

  1. $(rootpath) expands to a workspace-relative path

    • Only works in lenient sandboxes that allow direct workspace access
    • Fails in strict Linux sandboxes
  2. $(rlocationpath) expands to a runfiles-compatible path

  3. runfiles.Rlocation() resolves the runfiles path to the actual file location in the sandbox

Reproduction

To reproduce the issue:

# On Linux (e.g., in Docker or Linux CI)
cd gazelle/examples/bzlmod_build_file_generation
bazel test //:gazelle_python_manifest.test

# Result: FAIL with "no such file or directory"

References


Credit: Issue reported and investigated by @timfallmk

Metadata

Metadata

Assignees

No one assigned

    Labels

    gazelleGazelle plugin related issues

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions