Skip to content

[BUG] azure-containerapps-sandbox: FileInfo drops isSymlink/symlinkTarget, mis-maps isDir, and types mode as str #48523

Description

  • Package Name: azure-containerapps-sandbox
  • Package Version: 0.1.0b4
  • Operating System: Windows 11 (build 26220.8764)
  • Python Version: 3.12

Describe the bug

FileInfo loses type information that the service actually returns. The data-plane GET .../files/stat response carries isSymlink and symlinkTarget, and FileInfo has no field for either — so a caller using the typed surface cannot tell a symlink from a regular file. isDir is also mis-mapped, and mode is annotated as str but arrives as an int.

Three defects, in one model:

Wire field Value returned by the service FileInfo
isSymlink true for a symlink absent — no field at all
symlinkTarget e.g. /etc/hostname absent — no field at all
isDir true for a directory is_directory is False
mode 420 / 511 / 493 (int) typed str | None, populated with the int

This matters beyond tidiness because read_file follows symlinks. Reading a path that happens to be a symlink returns the target's contents, from anywhere in the guest filesystem. A caller that wants to refuse symlinked paths has the information available on the wire and no supported way to reach it — mode is permission bits only (0o644 / 0o777 / 0o755, no S_IFLNK), and is_directory cannot be trusted.

To Reproduce

  1. Create a sandbox and seed a regular file, a symlink and a directory:
sc.write_file("/work/real.txt", "REAL-CONTENT", create_dirs=True)
sc.exec("ln -sf /etc/hostname /work/link-out.txt; mkdir -p /work/sub", working_directory="/work")
  1. Stat each through the typed surface:
for p in ["/work/real.txt", "/work/link-out.txt", "/work/sub"]:
    f = sc.stat_file(p)
    print(p, f.size, f.is_directory, repr(f.mode))
/work/real.txt      12   False  420
/work/link-out.txt  13   False  511
/work/sub           4096 False  493

/work/sub is a directory and reports is_directory=False; the symlink is indistinguishable from the regular file; every mode is an int despite the str | None annotation.

  1. Compare against the raw response for the same three paths:
{"name":"real.txt",     "size":12,   "mode":420, "isDir":false, "isSymlink":false, "modifiedTime":1786404028}
{"name":"link-out.txt", "size":13,   "mode":511, "isDir":false, "isSymlink":true, "symlinkTarget":"/etc/hostname", "modifiedTime":1786404028}
{"name":"sub",          "size":4096, "mode":493, "isDir":true,  "isSymlink":false, "modifiedTime":1786404028}
  1. Confirm the follow behaviour:
sc.read_file("/work/link-out.txt")   # b'adc-sandbox\n' — the contents of /etc/hostname

list_files returns the same FileInfo shape and so loses the same fields.

Expected behavior

FileInfo exposes what the service sends:

  • an is_symlink: bool and a symlink_target: str | None, so a caller can identify and refuse a symlink;
  • is_directory reflecting the wire's isDir;
  • mode typed as int | None, matching what is sent — or documented as permission bits only, since it carries no file-type bits and cannot be used for type discrimination.

Additional context

Environment: swedencentral, api-version as shipped in 0.1.0b4, sandbox created from the python-3.13 public disk-image preset. Reproduced against a live sandbox group, not a mock.

The workaround available today is to bypass FileInfo and read the raw stat payload, which means depending on wire shape the typed surface is supposed to insulate callers from.

Metadata

Metadata

Assignees

No one assigned

    Labels

    issue-addressedWorkflow: The Azure SDK team believes it to be addressed and ready to close.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions