Skip to content

Conversation

@csssuf
Copy link
Contributor

@csssuf csssuf commented Dec 14, 2025

ostree-ext explicitly handles authfile paths as relative; this works fine for most callers of get_global_authfile, as they only read the returned open file descriptor, and ignore the path. However, pulling logically bound images requires passing the actual authfile path to Podman, so we must resolve the absolute path in this case - otherwise, we see errors like the following:

[root@fedora ~]# bootc upgrade
layers already present: 69; layers needed: 1 (242.2 MB)
Fetched layers: 230.95 MiB in 3 seconds (90.88 MiB/s)
  Deploying: done (3 seconds)
  Fetching bound image: quay.io/prometheus/node-exporter:v1.10.2: done (0 seconds)
error: Upgrading: Staging: Pulling bound images: Pulling bound images: Failed to pull image: Subprocess failed: ExitStatus(unix_wait_status(32000))
Error: credential file is not accessible: faccessat etc/ostree/auth.json: no such file or directory

Since cap_std::fs::Dir intentionally does not expose its filesystem path, we must resort to reconstructing it from a file descriptor. We could do this by inspectingthe file descriptor for sysroot and combining that with the relative path returned by get_global_authfile, but since get_global_authfile returns the descriptor of the actual authfile, we can simply read that directly.

ostree-ext explicitly handles authfile paths as relative; this works
fine for most callers of get_global_authfile, as they only read the
returned open file descriptor, and ignore the path. However, pulling
logically bound images requires passing the actual authfile path to
Podman, so we must resolve the absolute path in this case - otherwise,
we see errors like the following:

```
[root@fedora ~]# bootc upgrade
layers already present: 69; layers needed: 1 (242.2 MB)
Fetched layers: 230.95 MiB in 3 seconds (90.88 MiB/s)
  Deploying: done (3 seconds)
  Fetching bound image: quay.io/prometheus/node-exporter:v1.10.2: done (0 seconds)
error: Upgrading: Staging: Pulling bound images: Pulling bound images: Failed to pull image: Subprocess failed: ExitStatus(unix_wait_status(32000))
Error: credential file is not accessible: faccessat etc/ostree/auth.json: no such file or directory
```

Since cap_std::fs::Dir intentionally does not expose its filesystem
path, we must resort to reconstructing it from a file descriptor. We
could do this by inspectingthe file descriptor for `sysroot` and
combining that with the relative path returned by get_global_authfile,
but since get_global_authfile returns the descriptor of the actual
authfile, we can simply read that directly.

Signed-off-by: James Forcier <csssuf@csssuf.net>
@bootc-bot bootc-bot bot requested a review from ckyrouac December 14, 2025 17:24
Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request addresses an issue with pulling logically bound images where a relative authfile path was being passed to Podman. The change correctly resolves the absolute path of the authfile by reading the symbolic link from /proc/self/fd/{fd}. The approach is sound and directly fixes the described problem. I have one suggestion to improve the error handling to provide more context, which will be helpful for debugging.

@cgwalters
Copy link
Collaborator

Hm, this is a CI gap for sure in terms of LBIs with auth. #1847 would help here.

Copy link
Collaborator

@cgwalters cgwalters left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for finding this bug and trying a patch!

Can you explain if you built and tested this, or was this more of a drive-by?

let authfile_fd =
ostree_ext::globals::get_global_authfile(&self.sysroot)?.map(|(_authfile, fd)| fd);
if let Some(fd) = authfile_fd {
let authfile_path = std::fs::read_link(format!("/proc/self/fd/{}", fd.as_raw_fd()))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this will work because the fd should have O_CLOEXEC and won't be passed to the child by default.

The general pattern we use here instead is using https://docs.rs/cap-std-ext/latest/cap_std_ext/cmdext/trait.CapStdExtCommandExt.html#tymethod.take_fd_n

In fact we should just make this code identical to the one in containers-image-proxy-rs: https://github.com/bootc-dev/containers-image-proxy-rs/blob/b5e0861ad5065f47eaf9cda0d48da3529cc1bc43/src/imageproxy.rs#L310

Copy link
Contributor Author

@csssuf csssuf Dec 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't believe we rely on passing it to the child here - we only use the fd in the current process to look up the absolute path through /proc, and just pass the path to the child since podman's --authfile option expects a path.

Using /proc here does feel a little hacky, but as far as I can tell cap_std::fs::Dir is very deliberate in not exposing the underlying path, but open to other suggestions here - would copying the contents as in the imageproxy implementation be preferable to resolving the absolute path this way?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I pushed a followup commit here, can you review it?

@csssuf
Copy link
Contributor Author

csssuf commented Dec 15, 2025

I have built and tested it! From an earlier testing iteration with a debug print still in there:

[root@fedora ~]# bootc-local upgrade
Fetched layers: 0 B in 0 seconds (0 B/s)
  Deploying: done (3 seconds)
  Fetching bound image: quay.io/prometheus/node-exporter:v1.10.2
authfile_path: "/etc/ostree/auth.json"
  Fetching bound image: quay.io/prometheus/node-exporter:v1.10.2: done (1 second)
Bound images stored: 1
Pruned images: 0 (layers: 0, objsize: 726.8 MB)
Queued for next boot: 10.0.2.2:8000/localhost/test-bound-image
  Version: 43.20251213.0
  Digest: sha256:5cf3430f72d9dae0fc223f41ee13b5eec04e5d270369688a5b1415ce5047448b
Total new layers: 70    Size: 2.1 GB
Removed layers:   0     Size: 0 bytes
Added layers:     0     Size: 0 bytes
[root@fedora ~]#

@cgwalters cgwalters self-assigned this Dec 16, 2025
We should match exactly the logic we use with containers-image-proxy.

- If bootc doesn't have auth setup, then we need to not let podman
  fall back to the defaults
- Always pass a copy of the auth in a tempfile so we aren't
  reliant on absolute paths as we're continually trying to
  reduce our usage of those.

Signed-off-by: Colin Walters <walters@verbum.org>
@cgwalters cgwalters force-pushed the jmf/lbi-authfile-absolute-path branch from 040be24 to 37382b6 Compare December 16, 2025 16:51
@cgwalters cgwalters assigned ckyrouac and unassigned cgwalters Dec 16, 2025
@cgwalters
Copy link
Collaborator

Since we have two people who wrote code here I think SOP should be for a 3rd to review so passing this over to @ckyrouac for final review/approval

@cgwalters
Copy link
Collaborator

/gemini review

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request addresses an issue with pulling logically bound images when an authfile is present. The fix involves creating a temporary authfile and passing its file descriptor to Podman via the REGISTRY_AUTH_FILE environment variable, which correctly handles authentication without issues related to relative paths. The changes are logical and well-implemented. The accompanying test modifications are also appropriate for verifying the fix.

I have a couple of suggestions to simplify the code that creates the temporary authfile by removing an unnecessary BufWriter.

@cgwalters cgwalters merged commit 3c861fb into bootc-dev:main Dec 16, 2025
53 of 65 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants