chore: remove orphaned MaterializingArtifactWriter, gitignore healthcheck output
DefaultMaterializingArtifactWriter and its MaterializingArtifactWriter interface
were test-only orphans after the sandbox dual-write retirement (95e79bf) - no
production wiring, never instantiated outside their own test. Delete all three.
Add healthcheck_*.txt to .gitignore (one-off generated output).
This commit is contained in:
@@ -58,6 +58,7 @@ kotlin-ide/
|
||||
CLAUDE.md
|
||||
scripts/
|
||||
test_output.log
|
||||
healthcheck_*.txt
|
||||
**/xcuserdata
|
||||
.test-federation.*
|
||||
bin/
|
||||
|
||||
-14
@@ -1,14 +0,0 @@
|
||||
package com.correx.core.artifacts
|
||||
|
||||
import com.correx.core.artifacts.kind.FileWrittenArtifact
|
||||
import com.correx.core.artifacts.kind.FileWrittenPayload
|
||||
import java.nio.file.Path
|
||||
|
||||
interface MaterializingArtifactWriter {
|
||||
suspend fun materialize(payload: FileWrittenPayload, sandboxRoot: Path): MaterializationResult
|
||||
}
|
||||
|
||||
sealed interface MaterializationResult {
|
||||
data class Success(val artifact: FileWrittenArtifact, val resolvedPath: Path) : MaterializationResult
|
||||
data class Failure(val reason: String) : MaterializationResult
|
||||
}
|
||||
-76
@@ -1,76 +0,0 @@
|
||||
package com.correx.infrastructure.artifactscas
|
||||
|
||||
import com.correx.core.artifacts.MaterializationResult
|
||||
import com.correx.core.artifacts.MaterializingArtifactWriter
|
||||
import com.correx.core.artifacts.kind.FileWrittenArtifact
|
||||
import com.correx.core.artifacts.kind.FileWrittenPayload
|
||||
import com.correx.infrastructure.artifactscas.segment.SegmentLayout
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.slf4j.Logger
|
||||
import org.slf4j.LoggerFactory
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.Path
|
||||
import java.nio.file.attribute.PosixFilePermissions
|
||||
|
||||
class DefaultMaterializingArtifactWriter : MaterializingArtifactWriter {
|
||||
|
||||
private companion object {
|
||||
val log: Logger = LoggerFactory.getLogger(DefaultMaterializingArtifactWriter::class.java)
|
||||
const val DEFAULT_MODE = "644"
|
||||
const val OCTAL_RADIX = 8
|
||||
const val POSIX_PERMISSION_BITS = 9
|
||||
const val HEX_RADIX = 16
|
||||
const val BYTE_MASK = 0xFF
|
||||
}
|
||||
|
||||
@Suppress("ReturnCount")
|
||||
override suspend fun materialize(payload: FileWrittenPayload, sandboxRoot: Path): MaterializationResult {
|
||||
if (payload.path.isBlank()) return MaterializationResult.Failure("path is blank")
|
||||
val payloadPath = Path.of(payload.path)
|
||||
if (payloadPath.isAbsolute) return MaterializationResult.Failure("path must be relative: ${payload.path}")
|
||||
if (payloadPath.any { it.toString() == ".." }) {
|
||||
return MaterializationResult.Failure("path must not contain '..': ${payload.path}")
|
||||
}
|
||||
|
||||
val resolvedPath = sandboxRoot.resolve(payloadPath).normalize()
|
||||
if (!resolvedPath.startsWith(sandboxRoot)) {
|
||||
return MaterializationResult.Failure("path escapes sandbox: ${payload.path}")
|
||||
}
|
||||
|
||||
return runCatching {
|
||||
withContext(Dispatchers.IO) {
|
||||
resolvedPath.parent?.let { Files.createDirectories(it) }
|
||||
Files.writeString(resolvedPath, payload.content)
|
||||
runCatching {
|
||||
val octal = payload.mode.trimStart('0').ifEmpty { DEFAULT_MODE }.toInt(OCTAL_RADIX)
|
||||
val perms = PosixFilePermissions.fromString(octalToSymbolic(octal))
|
||||
Files.setPosixFilePermissions(resolvedPath, perms)
|
||||
}.onFailure {
|
||||
log.warn("Failed to set permissions on {}: {}", resolvedPath, it.message)
|
||||
}
|
||||
val bytes = payload.content.toByteArray(Charsets.UTF_8)
|
||||
val hash = SegmentLayout.blake3(bytes).toHex()
|
||||
MaterializationResult.Success(
|
||||
artifact = FileWrittenArtifact(
|
||||
path = payload.path,
|
||||
contentHash = hash,
|
||||
size = bytes.size.toLong(),
|
||||
mode = payload.mode,
|
||||
),
|
||||
resolvedPath = resolvedPath,
|
||||
)
|
||||
}
|
||||
}.getOrElse { MaterializationResult.Failure("IO error: ${it.message}") }
|
||||
}
|
||||
|
||||
private fun octalToSymbolic(octal: Int): String {
|
||||
val perms = "rwxrwxrwx"
|
||||
return CharArray(POSIX_PERMISSION_BITS) { i ->
|
||||
if ((octal shr (POSIX_PERMISSION_BITS - 1 - i)) and 1 == 1) perms[i] else '-'
|
||||
}.let { String(it) }
|
||||
}
|
||||
|
||||
private fun ByteArray.toHex(): String =
|
||||
joinToString("") { it.toInt().and(BYTE_MASK).toString(HEX_RADIX).padStart(2, '0') }
|
||||
}
|
||||
-72
@@ -1,72 +0,0 @@
|
||||
package com.correx.infrastructure.artifactscas
|
||||
|
||||
import com.correx.core.artifacts.MaterializationResult
|
||||
import com.correx.core.artifacts.kind.FileWrittenPayload
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.junit.jupiter.api.Assertions.assertFalse
|
||||
import org.junit.jupiter.api.Assertions.assertInstanceOf
|
||||
import org.junit.jupiter.api.Assertions.assertNotNull
|
||||
import org.junit.jupiter.api.Assertions.assertTrue
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.io.TempDir
|
||||
import java.nio.file.Path
|
||||
|
||||
class DefaultMaterializingArtifactWriterTest {
|
||||
|
||||
private val writer = DefaultMaterializingArtifactWriter()
|
||||
|
||||
@Test
|
||||
fun `valid payload materializes successfully with correct path, non-empty hash and correct size`(
|
||||
@TempDir sandbox: Path,
|
||||
): Unit = runBlocking {
|
||||
val content = "hello world"
|
||||
val payload = FileWrittenPayload(path = "subdir/hello.txt", content = content, mode = "0644")
|
||||
|
||||
val result = writer.materialize(payload, sandbox)
|
||||
|
||||
assertInstanceOf(MaterializationResult.Success::class.java, result)
|
||||
result as MaterializationResult.Success
|
||||
assertFalse(result.artifact.contentHash.isBlank(), "contentHash must not be blank")
|
||||
assertTrue(result.artifact.size > 0, "size must be positive")
|
||||
assertTrue(result.resolvedPath.startsWith(sandbox), "resolved path must be inside sandbox")
|
||||
assertNotNull(result.resolvedPath)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `absolute path returns failure`(@TempDir sandbox: Path): Unit = runBlocking {
|
||||
val payload = FileWrittenPayload(path = "/etc/passwd", content = "x")
|
||||
|
||||
val result = writer.materialize(payload, sandbox)
|
||||
|
||||
assertInstanceOf(MaterializationResult.Failure::class.java, result)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `path with dot-dot returns failure`(@TempDir sandbox: Path): Unit = runBlocking {
|
||||
val payload = FileWrittenPayload(path = "../escape.txt", content = "x")
|
||||
|
||||
val result = writer.materialize(payload, sandbox)
|
||||
|
||||
assertInstanceOf(MaterializationResult.Failure::class.java, result)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `blank path returns failure`(@TempDir sandbox: Path): Unit = runBlocking {
|
||||
val payload = FileWrittenPayload(path = " ", content = "x")
|
||||
|
||||
val result = writer.materialize(payload, sandbox)
|
||||
|
||||
assertInstanceOf(MaterializationResult.Failure::class.java, result)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `path that escapes sandbox after normalization returns failure`(@TempDir sandbox: Path): Unit = runBlocking {
|
||||
// Construct a path like "subdir/../../../../../../tmp/evil" that normalizes outside sandbox
|
||||
val escaping = "subdir/" + "../".repeat(20) + "evil.txt"
|
||||
val payload = FileWrittenPayload(path = escaping, content = "x")
|
||||
|
||||
val result = writer.materialize(payload, sandbox)
|
||||
|
||||
assertInstanceOf(MaterializationResult.Failure::class.java, result)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user