Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 23 additions & 6 deletions src/main/java/land/oras/auth/RegistriesConf.java
Original file line number Diff line number Diff line change
Expand Up @@ -89,16 +89,33 @@ public static RegistriesConf newConf(List<Path> configPaths) {

/**
* Create a new RegistriesConf instance by loading configuration from standard paths.
* If the {@code CONTAINERS_REGISTRIES_CONF} environment variable is set it is used exclusively.
* Otherwise, the user-local config (under {@code $HOME}) is tried first, then {@code /etc/containers/registries.conf}.
*
* @return A new RegistriesConf instance.
*/
public static RegistriesConf newConf() {
String containersRegistriesConf = System.getenv("CONTAINERS_REGISTRIES_CONF");
if (containersRegistriesConf != null) {
LOG.debug("Using registries config from CONTAINERS_REGISTRIES_CONF: {}", containersRegistriesConf);
return newConf(List.of(Path.of(containersRegistriesConf)));
}
return newConf(defaultConfPaths());
}

/**
* Returns the ordered list of registries.conf paths to search when {@code CONTAINERS_REGISTRIES_CONF} is not set.
* The user-local path (under {@code $HOME}) is tried first; the system-wide path is always included as fallback.
*
* @return list of candidate paths.
*/
private static List<Path> defaultConfPaths() {
Path globalPath = Path.of("/etc/containers/registries.conf");
List<Path> paths = List.of(
System.getenv("HOME") != null
? Path.of(System.getenv("HOME"), ".config", "containers", "registries.conf")
: globalPath,
globalPath);
return newConf(paths);
String home = System.getenv("HOME");
if (home != null) {
return List.of(Path.of(home, ".config", "containers", "registries.conf"), globalPath);
}
return List.of(globalPath);
}

/**
Expand Down
1 change: 1 addition & 0 deletions src/test/java/land/oras/TestUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ public static synchronized void createRegistriesConfFile(Path homeDir, String co
public static synchronized void withHome(Path homeDir, Runnable action) throws Exception {
new EnvironmentVariables()
.set("HOME", homeDir.toAbsolutePath().toString())
.remove("CONTAINERS_REGISTRIES_CONF")
.execute(() -> {
try {
action.run();
Expand Down
63 changes: 63 additions & 0 deletions src/test/java/land/oras/auth/RegistriesConfTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,15 @@

import static org.junit.jupiter.api.Assertions.*;

import java.nio.file.Files;
import java.nio.file.Path;
import land.oras.TestUtils;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import org.junit.jupiter.api.parallel.Execution;
import org.junit.jupiter.api.parallel.ExecutionMode;
import uk.org.webcompere.systemstubs.environment.EnvironmentVariables;

/**
* Test class of {@link RegistriesConf}.
Expand Down Expand Up @@ -73,4 +75,65 @@ void shouldReadUnqualifiedSearchRegistriesFromHome() throws Exception {
assertEquals("docker.io", conf.getUnqualifiedRegistries().get(0));
});
}

@Test
void shouldFallBackToGlobalPathWhenHomeIsAbsent() throws Exception {
new EnvironmentVariables()
.remove("HOME")
.remove("CONTAINERS_REGISTRIES_CONF")
.execute(() -> {
RegistriesConf conf = RegistriesConf.newConf();
assertNotNull(conf);
// /etc/containers/registries.conf does not exist in the test environment,
// so the result is an empty config — but the code path is exercised.
assertTrue(conf.getUnqualifiedRegistries().isEmpty());
assertTrue(conf.getAliases().isEmpty());
});
}

@Test
void shouldUseContainersRegistriesConfWhenSet(@TempDir Path customDir) throws Exception {
// language=toml
String customContent =
"""
unqualified-search-registries = ["quay.io"]

[aliases]
"busybox"="quay.io/library/busybox"
""";
Path customFile = customDir.resolve("registries.conf");
Files.writeString(customFile, customContent);

new EnvironmentVariables()
.set("CONTAINERS_REGISTRIES_CONF", customFile.toAbsolutePath().toString())
.execute(() -> {
RegistriesConf conf = RegistriesConf.newConf();
assertNotNull(conf);
assertEquals(1, conf.getUnqualifiedRegistries().size());
assertEquals("quay.io", conf.getUnqualifiedRegistries().get(0));
assertTrue(conf.hasAlias("busybox"));
assertEquals("quay.io/library/busybox", conf.getAliases().get("busybox"));
});
}

@Test
void containersRegistriesConfTakesPrecedenceOverHome(@TempDir Path customDir) throws Exception {
// language=toml
String customContent = """
unqualified-search-registries = ["custom.io"]
""";
Path customFile = customDir.resolve("registries.conf");
Files.writeString(customFile, customContent);

new EnvironmentVariables()
.set("CONTAINERS_REGISTRIES_CONF", customFile.toAbsolutePath().toString())
.set("HOME", homeDir.toAbsolutePath().toString())
.execute(() -> {
RegistriesConf conf = RegistriesConf.newConf();
// Must reflect the custom file, not the HOME-based one (which has "docker.io")
assertEquals(1, conf.getUnqualifiedRegistries().size());
assertEquals("custom.io", conf.getUnqualifiedRegistries().get(0));
assertFalse(conf.hasAlias("alpine"));
});
}
}
Loading