Skip to content

Commit

Permalink
KnowledgeManagerImpl: Create temporary files in secure sub-folder ins…
Browse files Browse the repository at this point in the history
…tead of publicly writable /tmp

Signed-off-by: Florian Hotze <dev@florianhotze.com>
  • Loading branch information
florian-h05 committed Feb 28, 2025
1 parent 0d0b0aa commit 82376e9
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 1 deletion.
31 changes: 31 additions & 0 deletions src/main/java/com/github/llamara/ai/internal/Utils.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

import org.apache.commons.lang3.SystemProperties;

/**
* Shared utilities and constants.
*
Expand Down Expand Up @@ -99,4 +101,33 @@ public static String buildAzureOpenaiEndpoint(EmbeddingModelConfig config)
+ ".openai.azure.com/openai/deployments/"
+ config.model();
}

/**
* Checks if the host operating system is Unix-like.
*
* @return <code>true</code> if the host operating system is Unix-like, <code>false</code>
* otherwise
*/
public static boolean isOsUnix() {
String osName = SystemProperties.getOsName().toLowerCase();
return isOsUnix(osName);
}

/**
* Check if the given operating system is Unix-like.
*
* @param osName the name of the operating system
* @return <code>true</code> if the operating system is Unix-like, <code>false</code> otherwise
*/
public static boolean isOsUnix(String osName) {
osName = osName.toLowerCase();
return osName.startsWith("aix")
|| osName.startsWith("hp-ux")
|| osName.startsWith("irix")
|| osName.startsWith("linux")
|| osName.startsWith("mac")
|| osName.startsWith("solaris")
|| osName.startsWith("sunos")
|| osName.contains("bsd");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
import static com.github.llamara.ai.internal.Utils.generateChecksum;

import com.github.llamara.ai.internal.MetadataKeys;
import com.github.llamara.ai.internal.StartupException;
import com.github.llamara.ai.internal.Utils;
import com.github.llamara.ai.internal.ingestion.DocumentIngestor;
import com.github.llamara.ai.internal.ingestion.IngestionStatus;
import com.github.llamara.ai.internal.knowledge.embedding.EmbeddingStorePermissionMetadataManager;
Expand All @@ -39,9 +41,13 @@
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.nio.file.attribute.FileAttribute;
import java.nio.file.attribute.PosixFilePermission;
import java.nio.file.attribute.PosixFilePermissions;
import java.util.Collection;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
Expand Down Expand Up @@ -76,6 +82,7 @@
class KnowledgeManagerImpl implements KnowledgeManager {
private static final String FILE_STORAGE_FILE_NOT_FOUND_PATTERN =
"File for knowledge '%s' should exist in storage, but is missing";
private static final Path TEMP_DIR = Path.of("/tmp/llamara/knowledge");

private final DocumentIngestor ingestor;
private final EmbeddingStore<TextSegment> embeddingStore;
Expand All @@ -97,6 +104,27 @@ class KnowledgeManagerImpl implements KnowledgeManager {
this.embeddingStorePermissionMetadataManager = embeddingStorePermissionMetadataManager;
}

@Startup
void init() {
try {
if (Utils.isOsUnix()) {
FileAttribute<Set<PosixFilePermission>> attr =
PosixFilePermissions.asFileAttribute(
PosixFilePermissions.fromString("rwx------"));
Files.createDirectories(TEMP_DIR, attr);
} else {
File f = Files.createDirectories(TEMP_DIR).toFile();
if (!f.setReadable(true, true)
|| !f.setWritable(true, true)
|| !f.setExecutable(true, true)) {
throw new StartupException("Failed to set permissions on temporary directory");
}
}
} catch (IOException e) {
throw new StartupException("Failed to create temporary directory", e);
}
}

@Override
public Collection<Knowledge> getAllKnowledge() {
return repository.listAll();
Expand Down Expand Up @@ -352,7 +380,7 @@ public void retryFailedIngestion(UUID id)
NamedFileContainer fc = getFile(id);
File tempFile;
try {
tempFile = File.createTempFile("knowledge_" + id, null);
tempFile = File.createTempFile(id.toString(), null, TEMP_DIR.toFile());
tempFile.deleteOnExit(); // the file will be deleted when the JVM exits
Files.copy(fc.content(), tempFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
} catch (IOException e) {
Expand Down
27 changes: 27 additions & 0 deletions src/test/java/com/github/llamara/ai/internal/UtilsTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,15 @@

import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;

/** Tests for {@link Utils}. */
class UtilsTest {
Expand Down Expand Up @@ -112,4 +116,27 @@ void buildAzureOpenAiEndpointThrowsIfResourceNameMissingForEmbeddingModelConfig(
assertThrows(
IllegalArgumentException.class, () -> Utils.buildAzureOpenaiEndpoint(modelConfig));
}

@ParameterizedTest
@CsvSource({
"AIX",
"HP-UX",
"Irix",
"Linux",
"Mac OS X",
"Solaris",
"SunOS",
"FreeBSD",
"OpenBSD",
"NetBSD"
})
void isOsUnixReturnsTrueIfOnUnix(String osName) {
assertTrue(Utils.isOsUnix(osName));
}

@ParameterizedTest
@CsvSource({"Windows 10", "Windows 11", "OS/2", "OS/400", "z/OS"})
void isOsUnixReturnsFalseIfNotOnUnix(String osName) {
assertFalse(Utils.isOsUnix(osName));
}
}

0 comments on commit 82376e9

Please sign in to comment.