Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Set configured file ownership when creating tarballs #2499

Merged
merged 18 commits into from
May 28, 2020
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
4 changes: 4 additions & 0 deletions jib-core/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,12 @@ All notable changes to this project will be documented in this file.

### Added

- Now sets configured file ownership when creating layer tars. ([#2499](https://github.com/GoogleContainerTools/jib/pull/2499))

### Changed

- Previous locally cached application layers will be ignored because of changes to the caching selectors. ([#2499](https://github.com/GoogleContainerTools/jib/pull/2499))

### Fixed

- Fixed authentication failure with Azure Container Registry when using an identity token defined in the `auths` section of Docker config (`~/.docker/config.json`). ([#2488](https://github.com/GoogleContainerTools/jib/pull/2488))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,14 +43,16 @@
* "extractionPath": "/extraction/path/for/layer/entry/1"
* "sourceModificationTime": "2018-10-03T15:48:32.416152Z"
* "targetModificationTime": "1970-01-01T00:00:01Z",
* "permissions": "777"
* "permissions": "777",
* "ownership": "0:0"
* },
* {
* "sourceFile": "source/file/for/layer/entry/2",
* "extractionPath": "/extraction/path/for/layer/entry/2"
* "sourceModificationTime": "2018-10-03T15:48:32.416152Z"
* "targetModificationTime": "1970-01-01T00:00:01Z",
* "permissions": "777"
* "permissions": "777",
* "ownership": "alice:1234"
* }
* ]
* }</pre>
Expand All @@ -66,6 +68,7 @@ static class LayerEntryTemplate implements JsonTemplate, Comparable<LayerEntryTe
private final Instant sourceModificationTime;
private final Instant targetModificationTime;
private final String permissions;
private final String ownership;

@VisibleForTesting
LayerEntryTemplate(FileEntry layerEntry) throws IOException {
Expand All @@ -74,6 +77,7 @@ static class LayerEntryTemplate implements JsonTemplate, Comparable<LayerEntryTe
sourceModificationTime = Files.getLastModifiedTime(layerEntry.getSourceFile()).toInstant();
targetModificationTime = layerEntry.getModificationTime();
permissions = layerEntry.getPermissions().toOctalString();
ownership = layerEntry.getOwnership();
}

@Override
Expand All @@ -97,7 +101,11 @@ public int compareTo(LayerEntryTemplate otherLayerEntryTemplate) {
if (targetModificationTimeComparison != 0) {
return targetModificationTimeComparison;
}
return permissions.compareTo(otherLayerEntryTemplate.permissions);
int permissionsComparison = permissions.compareTo(otherLayerEntryTemplate.permissions);
if (permissionsComparison != 0) {
return permissionsComparison;
}
return ownership.compareTo(otherLayerEntryTemplate.ownership);
}

@Override
Expand All @@ -113,13 +121,19 @@ public boolean equals(Object other) {
&& extractionPath.equals(otherLayerEntryTemplate.extractionPath)
&& sourceModificationTime.equals(otherLayerEntryTemplate.sourceModificationTime)
&& targetModificationTime.equals(otherLayerEntryTemplate.targetModificationTime)
&& permissions.equals(otherLayerEntryTemplate.permissions);
&& permissions.equals(otherLayerEntryTemplate.permissions)
&& ownership.equals(otherLayerEntryTemplate.ownership);
}

@Override
public int hashCode() {
return Objects.hash(
sourceFile, extractionPath, sourceModificationTime, targetModificationTime, permissions);
sourceFile,
extractionPath,
sourceModificationTime,
targetModificationTime,
permissions,
ownership);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,41 @@ private List<TarArchiveEntry> getSortedEntries() {
}
}

private static void setUserAndGroup(TarArchiveEntry entry, FileEntry layerEntry) {
entry.setUserId(0);
entry.setGroupId(0);
entry.setUserName("");
entry.setGroupName("");

if (!layerEntry.getOwnership().isEmpty()) {
// Parse "<user>:<group>" string.
String user = layerEntry.getOwnership();
String group = "";
int colonIndex = user.indexOf(':');
if (colonIndex != -1) {
group = user.substring(colonIndex + 1);
user = user.substring(0, colonIndex);
}

if (!user.isEmpty()) {
// Check if it's a number, and set either UID or user name.
try {
entry.setUserId(Long.parseLong(user));
} catch (NumberFormatException ignored) {
entry.setUserName(user);
}
}
if (!group.isEmpty()) {
// Check if it's a number, and set either GID or group name.
try {
entry.setGroupId(Long.parseLong(group));
} catch (NumberFormatException ignored) {
entry.setGroupName(group);
}
}
}
}

private final ImmutableList<FileEntry> layerEntries;

public ReproducibleLayerBuilder(ImmutableList<FileEntry> layerEntries) {
Expand All @@ -114,6 +149,7 @@ public Blob build() {
// lowest 9 bits) then using a bitwise OR to set them to the layerEntry's permissions.
entry.setMode((entry.getMode() & ~0777) | layerEntry.getPermissions().getPermissionBits());
entry.setModTime(layerEntry.getModificationTime().toEpochMilli());
setUserAndGroup(entry, layerEntry);

uniqueTarArchiveEntries.add(entry);
}
Expand All @@ -126,13 +162,6 @@ public Blob build() {
// Adds all the files to a tar stream.
TarStreamBuilder tarStreamBuilder = new TarStreamBuilder();
for (TarArchiveEntry entry : sortedFilesystemEntries) {
// Strips out all non-reproducible elements from tar archive entries.
// Modification time is configured per entry
entry.setGroupId(0);
entry.setUserId(0);
entry.setUserName("");
entry.setGroupName("");

Verify.verify(!names.contains(entry.getName()));
names.add(entry.getName());

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -187,4 +187,29 @@ public void testGenerateSelector_permissionsModified() throws IOException {
LayerEntriesSelector.generateSelector(ImmutableList.of(layerEntry111)),
LayerEntriesSelector.generateSelector(ImmutableList.of(layerEntry222)));
}

@Test
public void testGenerateSelector_ownersModified() throws IOException {
Path layerFile = temporaryFolder.newFolder("testFolder").toPath().resolve("file");
Files.write(layerFile, "hello".getBytes(StandardCharsets.UTF_8));
FileEntry layerEntry111 =
new FileEntry(
layerFile,
AbsoluteUnixPath.get("/extraction/path"),
FilePermissions.fromOctalString("111"),
FileEntriesLayer.DEFAULT_MODIFICATION_TIME,
"0:0");
FileEntry layerEntry222 =
new FileEntry(
layerFile,
AbsoluteUnixPath.get("/extraction/path"),
FilePermissions.fromOctalString("222"),
FileEntriesLayer.DEFAULT_MODIFICATION_TIME,
"foouser");

// Verify that changing ownership generates a different selector
Assert.assertNotEquals(
LayerEntriesSelector.generateSelector(ImmutableList.of(layerEntry111)),
LayerEntriesSelector.generateSelector(ImmutableList.of(layerEntry222)));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ private static FileEntry defaultLayerEntry(Path source, AbsoluteUnixPath destina
FileEntriesLayer.DEFAULT_MODIFICATION_TIME);
}

@Rule public TemporaryFolder temporaryFolder = new TemporaryFolder();
@Rule public final TemporaryFolder temporaryFolder = new TemporaryFolder();

@Test
public void testBuild() throws URISyntaxException, IOException {
Expand Down Expand Up @@ -360,9 +360,129 @@ public void testBuild_permissions() throws IOException {
}
}

private Path createFile(Path root, String filename, String content, long modificationTime)
throws IOException {
@Test
public void testBuild_ownership() throws IOException {
Path testRoot = temporaryFolder.getRoot().toPath();
Path someFile = createFile(testRoot, "someFile", "content", 54321);

Blob blob =
new ReproducibleLayerBuilder(
ImmutableList.of(
defaultLayerEntry(someFile, AbsoluteUnixPath.get("/file1")),
new FileEntry(
someFile,
AbsoluteUnixPath.get("/file2"),
FilePermissions.fromOctalString("123"),
Instant.EPOCH,
""),
new FileEntry(
someFile,
AbsoluteUnixPath.get("/file3"),
FilePermissions.fromOctalString("123"),
Instant.EPOCH,
":"),
new FileEntry(
someFile,
AbsoluteUnixPath.get("/file4"),
FilePermissions.fromOctalString("123"),
Instant.EPOCH,
"333:"),
new FileEntry(
someFile,
AbsoluteUnixPath.get("/file5"),
FilePermissions.fromOctalString("123"),
Instant.EPOCH,
":555"),
new FileEntry(
someFile,
AbsoluteUnixPath.get("/file6"),
FilePermissions.fromOctalString("123"),
Instant.EPOCH,
"333:555"),
new FileEntry(
someFile,
AbsoluteUnixPath.get("/file7"),
FilePermissions.fromOctalString("123"),
Instant.EPOCH,
"user:"),
new FileEntry(
someFile,
AbsoluteUnixPath.get("/file8"),
FilePermissions.fromOctalString("123"),
Instant.EPOCH,
":group"),
new FileEntry(
someFile,
AbsoluteUnixPath.get("/file9"),
FilePermissions.fromOctalString("123"),
Instant.EPOCH,
"user:group")))
.build();

Path tarFile = temporaryFolder.newFile().toPath();
try (OutputStream out = new BufferedOutputStream(Files.newOutputStream(tarFile))) {
blob.writeTo(out);
}

try (TarArchiveInputStream in = new TarArchiveInputStream(Files.newInputStream(tarFile))) {
TarArchiveEntry entry1 = in.getNextTarEntry();
Assert.assertEquals(0, entry1.getLongUserId());
Assert.assertEquals(0, entry1.getLongGroupId());
Assert.assertEquals("", entry1.getUserName());
Assert.assertEquals("", entry1.getGroupName());

TarArchiveEntry entry2 = in.getNextTarEntry();
Assert.assertEquals(0, entry2.getLongUserId());
Assert.assertEquals(0, entry2.getLongGroupId());
Assert.assertEquals("", entry2.getUserName());
Assert.assertEquals("", entry2.getGroupName());

TarArchiveEntry entry3 = in.getNextTarEntry();
Assert.assertEquals(0, entry3.getLongUserId());
Assert.assertEquals(0, entry3.getLongGroupId());
Assert.assertEquals("", entry3.getUserName());
Assert.assertEquals("", entry3.getGroupName());

TarArchiveEntry entry4 = in.getNextTarEntry();
Assert.assertEquals(333, entry4.getLongUserId());
Assert.assertEquals(0, entry4.getLongGroupId());
Assert.assertEquals("", entry4.getUserName());
Assert.assertEquals("", entry4.getGroupName());

TarArchiveEntry entry5 = in.getNextTarEntry();
Assert.assertEquals(0, entry5.getLongUserId());
Assert.assertEquals(555, entry5.getLongGroupId());
Assert.assertEquals("", entry5.getUserName());
Assert.assertEquals("", entry5.getGroupName());

TarArchiveEntry entry6 = in.getNextTarEntry();
Assert.assertEquals(333, entry6.getLongUserId());
Assert.assertEquals(555, entry6.getLongGroupId());
Assert.assertEquals("", entry6.getUserName());
Assert.assertEquals("", entry6.getGroupName());

TarArchiveEntry entry7 = in.getNextTarEntry();
Assert.assertEquals(0, entry7.getLongUserId());
Assert.assertEquals(0, entry7.getLongGroupId());
Assert.assertEquals("user", entry7.getUserName());
Assert.assertEquals("", entry7.getGroupName());

TarArchiveEntry entry8 = in.getNextTarEntry();
Assert.assertEquals(0, entry8.getLongUserId());
Assert.assertEquals(0, entry8.getLongGroupId());
Assert.assertEquals("", entry8.getUserName());
Assert.assertEquals("group", entry8.getGroupName());

TarArchiveEntry entry9 = in.getNextTarEntry();
Assert.assertEquals(0, entry9.getLongUserId());
Assert.assertEquals(0, entry9.getLongGroupId());
Assert.assertEquals("user", entry9.getUserName());
Assert.assertEquals("group", entry9.getGroupName());
}
}

private static Path createFile(Path root, String filename, String content, long modificationTime)
throws IOException {
Path newFile =
Files.write(
root.resolve(filename),
Expand Down
2 changes: 2 additions & 0 deletions jib-gradle-plugin/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ All notable changes to this project will be documented in this file.

### Changed

- Previous locally cached application layers (`<project root>/target/jib-cache`) will be ignored because of changes to the caching selectors. ([#2499](https://github.com/GoogleContainerTools/jib/pull/2499))

### Fixed

- Fixed authentication failure with Azure Container Registry when using an identity token defined in the `auths` section of Docker config (`~/.docker/config.json`). ([#2488](https://github.com/GoogleContainerTools/jib/pull/2488))
Expand Down
2 changes: 2 additions & 0 deletions jib-maven-plugin/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ All notable changes to this project will be documented in this file.

### Changed

- Previous locally cached application layers (`<project root>/target/jib-cache`) will be ignored because of changes to the caching selectors. ([#2499](https://github.com/GoogleContainerTools/jib/pull/2499))

### Fixed

- Fixed authentication failure with Azure Container Registry when using an identity token defined in the `auths` section of Docker config (`~/.docker/config.json`). ([#2488](https://github.com/GoogleContainerTools/jib/pull/2488))
Expand Down