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
4 changes: 2 additions & 2 deletions tests/Broker.NativeProof/RuntimeEvidence/Codec.fs
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ module Codec =
let private stateOf = function Accepted state | Pending state | Refused state | Unknown state -> state
let private statusOf = function Accepted _ -> "accepted" | Pending _ -> "pending" | Refused _ -> "refused" | Unknown _ -> "unknown"
let evaluate expectedApphostSha256 expectedClosureSha256 expectedSourceSetSha256 (input: byte array) =
if isNull input || input.Length=0 || input.Length>6*1024*1024 then invalidArg "input" "encoded bound"
if isNull input || input.Length=0 || input.Length>16*1024*1024 then invalidArg "input" "encoded bound"
let diagnosticMarker=Encoding.UTF8.GetBytes("\"operationResultSha256\"")
let diagnostic=input.AsSpan().IndexOf(diagnosticMarker)>=0
if diagnostic then
Expand All @@ -102,7 +102,7 @@ module Codec =
exact observation [|"pid";"startTicks";"uid";"device";"inode";"path";"revision";"bytes";"sha256";"previousPrefixIntact";"writerFd";"writerFlags";"writerPosition";"available";"logBase64"|]
let identityValue={ RunId=getString expected "runId";SourceSetSha256=getString expected "sourceSetSha256";ApphostSha256=getString expected "apphostSha256";ClosureSha256=getString expected "closureSha256";Pid=getInt observation "pid";StartTicks=getString observation "startTicks";Uid=getInt observation "uid";Device=getString observation "device";Inode=getString observation "inode";Path=getString observation "path" }
let raw=Convert.FromBase64String(getString observation "logBase64")
if raw.Length>4*1024*1024 || int64 raw.Length <> getInt64 observation "bytes" then invalidArg "logBase64" "decoded bound"
if raw.Length>10*1024*1024 || int64 raw.Length <> getInt64 observation "bytes" then invalidArg "logBase64" "decoded bound"
let actualSha = SHA256.HashData(raw) |> Convert.ToHexStringLower
if getString observation "sha256" <> actualSha then invalidArg "sha256" "decoded digest mismatch"
let roots=DataRootPolicy.evaluate (getString expected "writeRoot") (getString expected "dataRoot") raw
Expand Down
20 changes: 20 additions & 0 deletions tests/Broker.NativeProof/RuntimeEvidence/CodecTests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,26 @@ module CodecTests =
try Codec.evaluate (String('b',64)) (String('d',64)) (String('a',64)) (bytes source)|>ignore;failwith "active closure mismatch accepted" with :? ArgumentException -> ()
try Codec.evaluate (String('b',64)) (String('c',64)) (String('d',64)) (bytes source)|>ignore;failwith "active source set mismatch accepted" with :? ArgumentException -> ()
if not(result.Contains("\"status\":\"accepted\"")) || result.Contains("logBase64") then failwith "valid closed codec projection failed"
let rawCap=10*1024*1024
let encodedCap=16*1024*1024
let withRaw (raw:byte array) =
source.Replace(Convert.ToBase64String(log),Convert.ToBase64String(raw)).Replace(sha log,sha raw)
.Replace($"\"bytes\":{length}",$"\"bytes\":{raw.Length}")
.Replace($"\"writerPosition\":{length}",$"\"writerPosition\":{raw.Length}")
let fullRaw=Array.append log (Array.append (Array.create (rawCap-length-1) (byte 'x')) [|byte '\n'|])
let fullRequest=withRaw fullRaw
let fullResult=evaluate fullRequest|>Codec.complete
if not(fullResult.Contains("\"status\":\"accepted\"")) || fullResult.Contains("logBase64") then failwith "codec refused exact decoded 10 MiB"
if not(refused(withRaw(Array.append fullRaw [|byte '\n'|]))) then failwith "codec admitted decoded 10 MiB + 1"
let atEncodedCap=fullRequest+String(' ',encodedCap-(bytes fullRequest).Length)
if (bytes atEncodedCap).Length<>encodedCap then failwith "encoded boundary fixture length"
if not((evaluate atEncodedCap|>Codec.complete).Contains("\"status\":\"accepted\"")) then failwith "codec refused encoded 16 MiB"
if not(refused(atEncodedCap+" ")) then failwith "codec admitted encoded 16 MiB + 1"
let invalidUtf8=Array.append (bytes source) [|0xffuy|]
try
Codec.evaluate (String('b',64)) (String('c',64)) (String('a',64)) invalidUtf8|>ignore
failwith "codec admitted invalid UTF-8 request"
with :? JsonException -> ()
if not(refused(source.Replace("{\"schema\":","{\"unexpected\":1,\"schema\":"))) then failwith "unknown field accepted"
if not(refused(source.Replace("{\"schema\":","{\"schema\":\"duplicate\",\"schema\":"))) then failwith "duplicate field accepted"
if not(refused(source.Replace("\"revision\":1","\"revision\":\"1\""))) then failwith "typed numeric field accepted as text"
Expand Down
2 changes: 1 addition & 1 deletion tests/Broker.NativeProof/RuntimeEvidence/DataRootPolicy.fs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ module DataRootPolicy =
if normalized.Length > 4096 then None else Some normalized

let evaluate expectedWriteRoot expectedDataRoot (sample: byte array) =
if isNull sample || sample.Length = 0 || sample.Length > 4 * 1024 * 1024 then RootRefused "custody-or-bound"
if isNull sample || sample.Length = 0 || sample.Length > 10 * 1024 * 1024 then RootRefused "custody-or-bound"
elif sample[sample.Length - 1] <> byte '\n' then RootPending "incomplete-record"
elif Array.contains 0uy sample then RootRefused "nul-record"
else
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,11 @@ module DataRootPolicyTests =
match DataRootPolicy.evaluate writeRoot dataRoot (bytes traversal) with RootRefused "noncanonical-root" -> () | other -> failwithf "lexical traversal accepted: %A" other
match DataRootPolicy.evaluate writeRoot dataRoot (bytes(good writeRoot dataRoot "unfinished")) with RootPending "incomplete-record" -> () | other -> failwithf "unfinished record accepted: %A" other
match DataRootPolicy.evaluate writeRoot dataRoot [|0xffuy;0x0auy|] with RootRefused "invalid-utf8" -> () | other -> failwithf "invalid UTF-8 accepted: %A" other
let header=bytes(good writeRoot dataRoot "")
let atCap=Array.append header (Array.append (Array.create (10*1024*1024-header.Length-1) (byte 'x')) [|byte '\n'|])
match DataRootPolicy.evaluate writeRoot dataRoot atCap with RootAccepted _ -> () | other -> failwithf "10 MiB complete sample refused: %A" other
let aboveCap=Array.append atCap [|byte '\n'|]
match DataRootPolicy.evaluate writeRoot dataRoot aboveCap with RootRefused "custody-or-bound" -> () | other -> failwithf "10 MiB + 1 accepted: %A" other
let recordCap=bytes(good writeRoot dataRoot (String.replicate (65536-4) "x\n"))
match DataRootPolicy.evaluate writeRoot dataRoot recordCap with RootAccepted _ -> () | other -> failwithf "65,536 records refused: %A" other
match DataRootPolicy.evaluate writeRoot dataRoot (Array.append recordCap (bytes "x\n")) with RootRefused "record-bound" -> () | other -> failwithf "65,537 records admitted: %A" other
2 changes: 1 addition & 1 deletion tests/Broker.NativeProof/RuntimeEvidence/Program.fs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ module Program =
let mutable count=input.Read(block,0,block.Length)
while count>0 do
total <- total+count
if total>6*1024*1024 then raise(InvalidDataException("input bound"))
if total>16*1024*1024 then raise(InvalidDataException("input bound"))
buffer.Write(block,0,count);count<-input.Read(block,0,block.Length)
checkpoint<-"request-evaluation"
let evaluation=Codec.evaluate closure.ApphostSha256 closure.ManifestSha256 closure.ProductSourceSetSha256 (buffer.ToArray())
Expand Down
14 changes: 13 additions & 1 deletion tests/Broker.NativeProof/RuntimeEvidence/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ does not replace the ready/completed protocol or authorize a boundary.

Post-policy infolog custody failures retain fixed, sanitized checkpoints for scope,
producer identity, path and parent custody, named and retained-descriptor identity,
file custody, the 4 MiB size cap, size regression, and prefix read or comparison.
file custody, the 10 MiB size cap, size regression, and prefix read or comparison.
The earlier aggregate `infolog-final-refresh` value remains decodable for existing
receipts. Writer census and match failures keep their existing specific checkpoints.
No path, log bytes, exception text, or other private runtime value enters the
Expand All @@ -123,3 +123,15 @@ dependency manifest, runtime configuration, and FSharp.Core closure and prints t
SHA-256 values for the adopting runner. The model is bounded and sampled. It does not prove
OS provenance, absence of an unobserved rewrite-and-restore, atomicity with browser work,
future append behavior, owned-role cleanup, Count1, or native acceptance.

### Log budget selected on 2026-10-02

The user selected a 10 MiB raw infolog cap for the next qualification, to be
revisited against the actual workload. Encoded policy requests permit 16 MiB to
carry Base64 plus metadata. Each exact read permits 160 calls of up to 64 KiB,
sufficient for the full admitted raw sample. The 65,536-record ceiling, 32
settlement probes, three policy evaluations and five-second deadline remain
separate bounds. Sustained atlas logging can still exhaust these budgets.
The capacity change does not fix partial-record or continuously growing-file
semantics; qualified artifacts and private helper placement need rebuilding
before a native attempt uses it.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup><OutputType>Exe</OutputType><TargetFramework>net10.0</TargetFramework><IsPackable>false</IsPackable><GenerateProgramFile>false</GenerateProgramFile><RestorePackagesWithLockFile>true</RestorePackagesWithLockFile><RestoreLockedMode Condition="'$(CI)' == 'true'">true</RestoreLockedMode><NuGetLockFilePath>RuntimeEvidence.Tests.packages.lock.json</NuGetLockFilePath></PropertyGroup>
<PropertyGroup><OutputType>Exe</OutputType><TargetFramework>net10.0</TargetFramework><IsPackable>false</IsPackable><GenerateProgramFile>false</GenerateProgramFile><RestorePackagesWithLockFile>true</RestorePackagesWithLockFile><DisableImplicitLibraryPacksFolder>true</DisableImplicitLibraryPacksFolder><RestoreLockedMode Condition="'$(CI)' == 'true'">true</RestoreLockedMode><NuGetLockFilePath>RuntimeEvidence.Tests.packages.lock.json</NuGetLockFilePath></PropertyGroup>
<ItemGroup><ProjectReference Include="RuntimeEvidence.fsproj"/><PackageReference Include="FsQuint" Version="[0.1.0]"/></ItemGroup>
<ItemGroup><Compile Include="DataRootPolicyTests.fs"/><Compile Include="CodecTests.fs"/><Compile Include="GrowingLogEvidenceTests.fs"/><Compile Include="PolicyClosureTests.fs"/><Compile Include="CorrespondenceTests.fs"/><Compile Include="tests/Program.fs"/></ItemGroup>
<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"type": "Direct",
"requested": "[10.1.401, )",
"resolved": "10.1.401",
"contentHash": "IGqjL9U8pQl7CaCpFP3f5slZMduE8c7ZBx7HycAQ9dc1tawyniNyw7Fh6L2cShIoQDcaDL+S8/kokhWs8WwnBQ=="
"contentHash": "/lvOK51KD8IangBYkfDVna3/HrE/r4VUnX3dI01KDspctoYXmind3POeoYkqWKeXHwiKlf6Hc9TxwSnoSCWcjw=="
},
"FsQuint": {
"type": "Direct",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType><TargetFramework>net10.0</TargetFramework><IsPackable>false</IsPackable>
<GenerateProgramFile>false</GenerateProgramFile><RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
<GenerateProgramFile>false</GenerateProgramFile><RestorePackagesWithLockFile>true</RestorePackagesWithLockFile><DisableImplicitLibraryPacksFolder>true</DisableImplicitLibraryPacksFolder>
<RestoreLockedMode Condition="'$(CI)' == 'true'">true</RestoreLockedMode><NuGetLockFilePath>RuntimeEvidence.packages.lock.json</NuGetLockFilePath>
</PropertyGroup>
<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"type": "Direct",
"requested": "[10.1.401, )",
"resolved": "10.1.401",
"contentHash": "IGqjL9U8pQl7CaCpFP3f5slZMduE8c7ZBx7HycAQ9dc1tawyniNyw7Fh6L2cShIoQDcaDL+S8/kokhWs8WwnBQ=="
"contentHash": "/lvOK51KD8IangBYkfDVna3/HrE/r4VUnX3dI01KDspctoYXmind3POeoYkqWKeXHwiKlf6Hc9TxwSnoSCWcjw=="
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,15 @@ attempt root, mode 0600, exclusive creation. The <=4096-byte observation contain
only closed categories, counters, byte lengths, sample hash and monotonic elapsed
microseconds; the receipt binds its filename, bytes/hash and source-set hash.
No raw log, path, process identity or exception text is included. A read-call cap
is per exact-read operation; aggregate calls across probes can exceed 128.
is per exact-read operation; aggregate calls across probes can exceed 160.
`sampleSha256`, complete-prefix/tail lengths describe the last fully checked
retained sample; requested/read-in-operation counts describe the current read.
`settlementBudgetMicroseconds` is the frozen relative budget, or null for direct
mechanical probes. This sidecar is separate mechanical evidence and never
acceptance authority. Failed publication preserves the original exception and
sets its retention flag false; absent/unjoined receipt is an evidence gap.
The existing typed F# failure diagnostic schema, settlement semantics and caps
remain unchanged. Source-only RP1 does not authorize another native attempt;
The existing typed F# failure diagnostic schema and settlement semantics remain
unchanged. The subsequent user-selected budget is 10 MiB raw, 16 MiB encoded,
and 160 calls per exact read; record/probe/evaluation/deadline bounds are unchanged.
Source-only RP1 does not authorize another native attempt;
RP2 contract qualification and RP3 capacity evidence remain required.
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@
from pathlib import Path
from private_io import Refused,SHA,atomic_bytes_new,atomic_new,canonical,components,hash_artifact,need,read_bytes
from runtime_identity import mark_failure,proc_bytes,start_ticks
MAX_LOG=4*1024*1024
MAX_POLICY_INPUT=6*1024*1024
MAX_LOG=10*1024*1024
MAX_POLICY_INPUT=16*1024*1024
MAX_FDS=256
MAX_SAMPLES=3
MAX_SETTLEMENT_PROBES=32
MAX_PREAD_CALLS=128
MAX_PREAD_CALLS=160
SETTLEMENT_PAUSE_SECONDS=0.01
BOUNDARIES=('browser','normalization','release')
CLOSURE_SCHEMA='fsbar.barc-runtime-evidence-policy-closure/v3'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,15 @@ def sample(deadline):
self.assertEqual(observation['terminalCause'],'settlement-probe-cap');self.assertEqual((observation['probesBegun'],observation['probesCompleted'],observation['evaluationsBegun']),(32,32,0))
self.assertEqual(len(set(sizes)),32);self.assertGreater(observation['tailBytes'],0)
self.assertEqual(observation['completePrefixBytes']+observation['tailBytes'],observation['sampleBytes']);self.assertEqual(observation['sampleSha256'],hashlib.sha256(self.handle.previous).hexdigest())
self.assertLess(observation['maximumObservedBytes'],growing_log.MAX_LOG);self.assertGreater(observation['readCalls'],64);self.assertLessEqual(observation['readCallsInOperation'],128)
self.assertLess(observation['maximumObservedBytes'],growing_log.MAX_LOG);self.assertGreater(observation['readCalls'],64);self.assertLessEqual(observation['readCallsInOperation'],160)
self.assertNotIn('/public/',json.dumps(observation));self.assertNotIn(str(self.root),json.dumps(observation))
def test_actual_short_read_call_cap_is_distinct_from_probe_cap(self):
real=os.pread
def short(fd,count,offset):return real(fd,min(1,count),offset)
with mock.patch.object(growing_log.os,'pread',side_effect=short):
with self.assertRaises(Refused) as caught:self.handle._settle(time.monotonic()+5,0)
observation=self.handle._counter_observation(caught.exception._barc_failure_observation['check'])
self.assertEqual(observation['terminalCause'],'exact-read-call-cap');self.assertEqual((observation['probesBegun'],observation['probesCompleted'],observation['readCalls'],observation['readCallsInOperation']),(1,0,128,128));self.assertEqual(observation['terminalCheck'],'infolog-record-settlement-exhausted')
self.assertEqual(observation['terminalCause'],'exact-read-call-cap');self.assertEqual((observation['probesBegun'],observation['probesCompleted'],observation['readCalls'],observation['readCallsInOperation']),(1,0,160,160));self.assertEqual(observation['terminalCheck'],'infolog-record-settlement-exhausted')
def test_failed_consume_retains_bounded_sidecar_and_digest_receipt(self):
config={'roots':{'attemptRoot':str(self.root)},'source':{'public':'synthetic'}}
self.handle._consume_impl=lambda *args:self.handle._settle(time.monotonic()+5,0)
Expand All @@ -56,4 +56,19 @@ def test_sidecar_collision_preserves_original_refusal_and_existing_bytes(self):
def test_flush_control_promotes_exact_untrimmed_record_sample(self):
self.command('flush');raw,_,_,probes=self.handle._settle(time.monotonic()+5,0)
self.assertTrue(raw.endswith(b'\n'));self.assertEqual(probes,1);self.assertEqual(self.handle.counters['tailBytes'],0);self.assertEqual(self.handle.previous,raw);self.assertEqual(self.handle.counters['evaluationsBegun'],0)
class LogBudgetTests(unittest.TestCase):
def test_actual_exact_read_supports_full_ten_mib(self):
expected=b'x'*(10*1024*1024-1)+b'\n'
with tempfile.TemporaryFile() as stream:
stream.write(expected);stream.flush()
handle=object.__new__(GrowingLog);handle.fd=stream.fileno();handle.previous=b'';handle._reset_counters(None)
actual=handle._read_exact(len(expected),time.monotonic()+5)
self.assertEqual(actual,expected)
self.assertEqual(handle.counters['readCallsInOperation'],160)
def test_full_ten_mib_base64_fits_encoded_transport_budget(self):
import base64
raw=b'x'*(10*1024*1024)
request=json.dumps({'observation':{'logBase64':base64.b64encode(raw).decode()},'metadata':'x'*65536},separators=(',',':')).encode()
self.assertEqual(growing_log.MAX_LOG,10*1024*1024)
self.assertLess(len(request),growing_log.MAX_POLICY_INPUT)
if __name__=='__main__':unittest.main()
Loading