implements PR-05.7

This commit is contained in:
bQUARKz 2026-03-09 07:15:17 +00:00
parent 0cc836246f
commit 6dacedb5ed
Signed by: bquarkz
SSH Key Fingerprint: SHA256:Z7dgqoglWwoK6j6u4QC87OveEq74WOhFN+gitsxtkf8
3 changed files with 82 additions and 1 deletions

View File

@ -6,5 +6,6 @@ enum CompatibilityError {
HOSTCALL_INDEX_OUT_OF_BOUNDS,
UNUSED_SYSC_DECL,
MISSING_CAPABILITY,
RUNTIME_BACKED_REQUIRED,
RUNTIME_REJECTED,
}

View File

@ -11,27 +11,39 @@ import java.util.List;
final class RuntimeBackedCompatibilityAdapter implements RuntimeCompatibilityAdapter {
private static final String DEFAULT_RUNTIME_LINE = "runtime-line-unknown";
private static final String FALLBACK_MODE = "local-fallback";
private static final String STRICT_FLAG_ENV = "PROMETEU_GATE_I_STRICT";
private final RuntimeCompatibilityAdapter fallback;
private final Path runtimeRoot;
private final String runtimeLine;
private final String runtimeCheckCommand;
private final boolean strictRuntimeBacked;
RuntimeBackedCompatibilityAdapter(final RuntimeCompatibilityAdapter fallback) {
this(
fallback == null ? new LocalRuntimeCompatibilityAdapter() : fallback,
Path.of("../runtime"),
System.getenv("PROMETEU_RUNTIME_CHECK_CMD"));
System.getenv("PROMETEU_RUNTIME_CHECK_CMD"),
strictRuntimeBackedFromEnvironment());
}
RuntimeBackedCompatibilityAdapter(
final RuntimeCompatibilityAdapter fallback,
final Path runtimeRoot,
final String runtimeCheckCommand) {
this(fallback, runtimeRoot, runtimeCheckCommand, false);
}
RuntimeBackedCompatibilityAdapter(
final RuntimeCompatibilityAdapter fallback,
final Path runtimeRoot,
final String runtimeCheckCommand,
final boolean strictRuntimeBacked) {
this.fallback = fallback == null ? new LocalRuntimeCompatibilityAdapter() : fallback;
this.runtimeRoot = runtimeRoot == null ? Path.of("../runtime") : runtimeRoot;
this.runtimeLine = readRuntimeLine(this.runtimeRoot);
this.runtimeCheckCommand = runtimeCheckCommand == null ? "" : runtimeCheckCommand.trim();
this.strictRuntimeBacked = strictRuntimeBacked;
}
@Override
@ -87,6 +99,14 @@ final class RuntimeBackedCompatibilityAdapter implements RuntimeCompatibilityAda
private CompatibilityResult fallbackWithReason(
final CompatibilityResult local,
final String reason) {
if (strictRuntimeBacked) {
return new CompatibilityResult(
CompatibilityError.RUNTIME_BACKED_REQUIRED,
local.hostcallCount(),
runtimeLine,
FALLBACK_MODE,
"strict gate-i requires runtime-backed adapter: " + reason);
}
return new CompatibilityResult(
local.error(),
local.hostcallCount(),
@ -134,4 +154,21 @@ final class RuntimeBackedCompatibilityAdapter implements RuntimeCompatibilityAda
}
return output.substring(0, 160) + "...";
}
private static boolean strictRuntimeBackedFromEnvironment() {
if (isTruthy(System.getenv(STRICT_FLAG_ENV))) {
return true;
}
return isTruthy(System.getenv("CI"));
}
private static boolean isTruthy(final String value) {
if (value == null) {
return false;
}
return switch (value.trim().toLowerCase()) {
case "1", "true", "yes", "on" -> true;
default -> false;
};
}
}

View File

@ -35,6 +35,49 @@ class RuntimeBackedCompatibilityAdapterTest {
assertTrue(!result.runtimeLine().isBlank());
}
@Test
void checkMustFailInStrictModeWhenRuntimeCommandIsUnavailable() {
final var adapter = new RuntimeBackedCompatibilityAdapter(
new LocalRuntimeCompatibilityAdapter(),
Path.of("."),
"",
true);
final var module = moduleWithSingleRet();
final var result = adapter.check(module);
assertEquals(CompatibilityError.RUNTIME_BACKED_REQUIRED, result.error());
assertEquals("local-fallback", result.adapterMode());
assertTrue(result.reason().contains("strict gate-i requires runtime-backed adapter"));
}
@Test
void checkMustPassInStrictModeWhenRuntimeCommandIsValid() {
final var adapter = new RuntimeBackedCompatibilityAdapter(
new LocalRuntimeCompatibilityAdapter(),
Path.of("."),
"echo runtime-check-ok",
true);
final var module = moduleWithSingleRet();
final var result = adapter.check(module);
assertEquals(CompatibilityError.NONE, result.error());
assertEquals("runtime-backed", result.adapterMode());
assertTrue(result.reason().contains("accepted artifact"));
}
private BytecodeModule moduleWithSingleRet() {
return new BytecodeModule(
0,
ReadOnlyList.empty(),
ReadOnlyList.from(new BytecodeModule.FunctionMeta(0, 2, 0, 0, 0, 1)),
codeRet(),
null,
ReadOnlyList.empty(),
ReadOnlyList.empty());
}
private byte[] codeRet() {
final var out = ByteBuffer.allocate(2).order(ByteOrder.LITTLE_ENDIAN);
out.putShort((short) 0x51);