TramAI

Evidence Packs

Evidence packs capture the security posture of a sovereign TramAI deployment as a deterministic, safe-for-auditors JSON artifact. They contain no secrets, tokens, prompts, stack traces, or filesystem paths — every identifier is sanitized through EvidenceSafeString before being written.

Module: tramai-sovereignSovereignEvidencePackV1 DTO, SovereignEvidencePackWriter, and SovereignEvidencePackGenerator.


What

An evidence pack is a SovereignEvidencePackV1 DTO that summarizes:

  • Deployment identity — deployment mode (STANDARD or OFFLINE), allowed models (sorted), allowed providers (sorted), trust zone mappings
  • Artifact verification — settings snapshot, per-artifact receipts (manifest digest, artifact count, total size)
  • Zero-egress evidence — optional subsection from offline deployment testing (loopback invocations, TCP/DNS probes)
  • Audit chain — optional validation of the hash-chained audit event integrity
  • Supply chain — optional SBOM linkage (CycloneDX format with SHA-256 digest)
  • Release bundle — optional build artifact evidence with Maven coordinates and digests for every JAR
  • CI/CD attestation — optional build provenance from a CI pipeline (GitHub Actions)

Deterministic JSON

The SovereignEvidencePackWriter produces JSON with:

  • Stable field ordering matching the data class declaration order
  • Full JSON control-character escaping (all chars < 0x20 as \uXXXX)
  • No external JSON library dependency
  • Parent directory auto-creation

Same input produces identical output every time — suitable for hashing, signing, or comparing in CI.

Safety Guarantees

All string values are validated through EvidenceSafeString.sanitize():

  • Rejects identifiers containing path prefixes (/tmp/, /home/, /Users/)
  • Rejects identifiers containing secrets-adjacent terms (token, secret, password, prompt, rawRequest, rawResponse, stacktrace)
  • Rejects control characters
  • Rejects Windows drive paths

SHA-256 digest values (sha256:<hex>) bypass string sanitization and are validated with strict regex instead.


When to Use

Use evidence packs when:

  • You need audit-grade documentation of your TramAI deployment's security posture
  • You need CI attestation — generate and upload evidence packs as CI artifacts with provenance
  • You need enterprise security review artifacts that auditors can inspect without access to the runtime
  • You need air-gap validation evidence — prove that an offline deployment has zero egress
  • You need a verifiable deployment snapshot — hash the pack and sign it

Do not use evidence packs for runtime monitoring or live debugging — they are static snapshots.


Quickstart

Basic Generation

// 1. Build your sovereign runtime
val tramai = SovereignTramai.builder()
    .profile(profile)
    .modelRegistry(registry)
    .auditStore(auditStore)
    .provider(ollamaProvider, name = "ollama", default = true)
    .model("llama3.2", "ollama")
    .modelArtifactVerifier(verifier)
    .modelArtifactVerificationSettings(ModelArtifactVerificationSettings(enabled = true))
    .build()

// 2. Generate an evidence pack
val pack = tramai.evidencePack()

// 3. Write to file
SovereignEvidencePackWriter.write(pack, Paths.get("evidence/sovereign-evidence.json"))

With All Optional Sub-Sections

val pack = tramai.evidencePack(
    zeroEgress = ZeroEgressEvidenceV1(
        deploymentMode = "OFFLINE",
        runtimeBuildSucceeded = true,
        loopbackProviderInvocationSucceeded = true,
        loopbackProviderInvocationCount = 3,
        externalTcpProbeBlocked = true,
        externalDnsProbeBlocked = true,
    ),
    auditChain = AuditChainEvidenceV1(
        isValid = true,
        totalEvents = 42,
    ),
    supplyChain = SupplyChainEvidenceV1(
        schemaVersion = 1,
        sbomFormat = "CycloneDX",
        sbomSpecVersion = "1.6",
        sbomFileName = "bom.json",
        sbomSha256 = "sha256:abc123def456abc123def456abc123def456abc123def456abc123def456abcd",
        generatedBy = "CycloneDX Gradle Plugin 3.2.4",
    ),
    releaseBundle = ReleaseBundleEvidenceV1(
        schemaVersion = 1,
        buildTool = "Gradle",
        javaVersion = "21",
        gradleVersion = "8.12",
        artifacts = listOf(
            ReleaseArtifactEvidenceV1(
                groupId = "dev.tramai",
                artifactId = "tramai-core",
                version = "0.3.0",
                classifier = null,
                extension = "jar",
                fileName = "tramai-core-0.3.0.jar",
                sha256 = "sha256:abc123def456abc123def456abc123def456abc123def456abc123def456abcd",
                sizeBytes = 245760,
            ),
        ),
    ),
    attestation = AttestationEvidenceV1(
        schemaVersion = 1,
        provider = "GitHub Artifact Attestations",
        workflowName = "deploy",
        workflowRunId = "1234567890",
        repository = "my-org/my-repo",
        commitSha = "abc123def456abc123def456abc123def456abc1",
        attestedSubjects = listOf(
            AttestedSubjectV1(
                fileName = "sovereign-evidence.json",
                sha256 = "sha256:abc123def456abc123def456abc123def456abc123def456abc123def456abcd",
                attestationType = "build-provenance",
            ),
        ),
    ),
)

Evidence Pack Schema (V1)

SovereignEvidencePackV1

FieldTypeDescription
schemaVersionIntSchema version (currently 1)
deploymentModeString"STANDARD" or "OFFLINE"
allowedModelsList<String>Allowed model names (sorted)
allowedProvidersList<String>Allowed provider names (sorted)
providerZonesMap<String, String>Trust zone per provider
artifactVerificationSettingsMap<String, Any?>Verification settings snapshot (enabled, requireDigestForLocalModels)
artifactsList<ArtifactEvidenceV1>Per-artifact verification receipts
zeroEgressZeroEgressEvidenceV1?Zero-egress probe results
auditChainAuditChainEvidenceV1?Audit chain validation
supplyChainSupplyChainEvidenceV1?SBOM linkage
releaseBundleReleaseBundleEvidenceV1?Build artifact evidence
attestationAttestationEvidenceV1?CI/CD attestation
generatedAtStringISO-8601 generation timestamp

ArtifactEvidenceV1

FieldTypeDescription
registryEntryIdStringRegistry entry identifier
manifestDigestStringSHA-256 of the manifest
modelNameStringModel name
verifiedAtStringISO-8601 verification timestamp
artifactCountIntNumber of verified artifact files
totalSizeBytesLongTotal verified size

ZeroEgressEvidenceV1

FieldTypeDescription
deploymentModeStringDeployment mode under test
runtimeBuildSucceededBooleanRuntime built successfully
loopbackProviderInvocationSucceededBooleanLoopback provider returned valid response
loopbackProviderInvocationCountIntNumber of loopback invocations
externalTcpProbeBlockedBooleanExternal TCP connect to 1.1.1.1:443 blocked
externalDnsProbeBlockedBooleanExternal DNS resolution of example.com blocked

AuditChainEvidenceV1

FieldTypeDescription
isValidBooleanAudit chain integrity validated
totalEventsIntTotal events in the chain

SupplyChainEvidenceV1

FieldTypeDescription
schemaVersionIntSchema version (must be 1)
sbomFormatStringSBOM format (e.g., "CycloneDX")
sbomSpecVersionStringFormat spec version (e.g., "1.6")
sbomFileNameStringSBOM file name (no path separators)
sbomSha256Stringsha256:<hex> digest — validated against ^sha256:[a-fA-F0-9]{64}$
generatedByStringSBOM generator identifier

AttestationEvidenceV1

FieldTypeDescription
schemaVersionIntSchema version (must be 1)
providerStringAttestation provider (e.g., "GitHub Artifact Attestations")
workflowNameStringCI workflow name
workflowRunIdStringNumeric workflow run ID — validated against ^[0-9]+$
repositoryStringowner/repo format — validated against ^[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+$
commitShaString40-character hex commit SHA — validated against ^[a-fA-F0-9]{40}$
attestedSubjectsList<AttestedSubjectV1>Attested file digests (must not be empty)

AttestedSubjectV1

FieldTypeDescription
fileNameStringFile name (no path separators)
sha256Stringsha256:<hex> digest
attestationTypeString"build-provenance" or "sbom" only

ReleaseBundleEvidenceV1

FieldTypeDescription
schemaVersionIntSchema version (must be 1)
buildToolStringBuild tool identifier (e.g., "Gradle")
javaVersionStringJava runtime version
gradleVersionStringGradle version
artifactsList<ReleaseArtifactEvidenceV1>Release artifacts (must not be empty)

ReleaseArtifactEvidenceV1

FieldTypeDescription
groupIdStringMaven group ID (e.g., "dev.tramai")
artifactIdStringMaven artifact ID (e.g., "tramai-core")
versionStringArtifact version (e.g., "0.3.0")
classifierString?Optional Maven classifier
extensionStringFile extension (e.g., "jar")
fileNameStringFile name (no path separators)
sha256Stringsha256:<hex> digest — validated against ^sha256:[a-fA-F0-9]{64}$
sizeBytesLongFile size in bytes (must be >= 0)

Writer

The SovereignEvidencePackWriter produces deterministic JSON output:

SovereignEvidencePackWriter.write(pack, Paths.get("evidence/pack.json"))

Output format:

{
    "schemaVersion": 1,
    "deploymentMode": "OFFLINE",
    "allowedModels": [
        "llama3.2"
    ],
    "allowedProviders": [
        "ollama"
    ],
    "providerZones": {
        "ollama": "LOCAL"
    },
    "artifactVerificationSettings": {
        "enabled": true,
        "requireDigestForLocalModels": true
    },
    "artifacts": [
        {
            "registryEntryId": "ollama-llama3.2",
            "manifestDigest": "sha256:abc123def456abc123def456abc123def456abc123def456abc123def456abcd",
            "modelName": "llama3.2",
            "verifiedAt": "2025-06-14T12:00:00Z",
            "artifactCount": 3,
            "totalSizeBytes": 1234567890
        }
    ],
    "zeroEgress": null,
    "auditChain": null,
    "supplyChain": null,
    "releaseBundle": null,
    "attestation": null,
    "generatedAt": "2025-06-14T12:00:00Z"
}

Generator Validation

The SovereignEvidencePackGenerator.generate() method performs validation and sanitization:

  1. EvidenceSafeString sanitization — all model names, provider names, zone keys, registry entry IDs, and workflow names are sanitized (rejects paths, secrets-adjacent terms, control characters)
  2. Supply chain validationsbomSha256 must match ^sha256:[a-fA-F0-9]{64}$, schemaVersion must be 1, sbomFileName must not contain path separators
  3. Attestation validationworkflowRunId must be numeric, repository must match owner/repo, commitSha must be 40 hex chars, attestedSubjects must not be empty, attestationType must be "build-provenance" or "sbom"
  4. Release bundle validationsha256 for each artifact must match ^sha256:[a-fA-F0-9]{64}$, sizeBytes must be >= 0, artifacts list must not be empty
  5. Deterministic sortingallowedModels and allowedProviders are sorted; providerZones keys are sorted alphabetically in the writer

All validation failures use fixed safe-code error messages:

  • "evidence-unsafe-identifier"
  • "evidence-unsafe-digest-format"
  • "evidence-unsafe-control-character"
  • "evidence-unsupported-supply-chain-schema-version"
  • "evidence-unsupported-attestation-schema-version"
  • "evidence-unsafe-attestation-workflow-run-id"
  • "evidence-unsafe-attestation-commit-sha"
  • "evidence-unsafe-attestation-repository"
  • "evidence-unsafe-attestation-subjects"
  • "evidence-unsupported-attestation-type"
  • "evidence-unsupported-release-bundle-schema-version"
  • "evidence-unsafe-release-artifacts"
  • "evidence-unsafe-artifact-size"

CI Workflow Integration

Evidence packs are designed for CI artifact upload with attestation:

# .github/workflows/deploy.yml
steps:
  - name: Generate evidence pack
    run: ./gradlew sovereignEvidencePack

  - name: Sign the evidence pack
    run: |
      openssl dgst -sha256 -sign private-key.pem \
        -out build/evidence/sovereign-evidence.json.sig \
        build/evidence/sovereign-evidence.json

  - name: Upload evidence
    uses: actions/upload-artifact@v4
    with:
      name: sovereign-evidence
      path: build/evidence/

Extension Pattern

To add a new evidence sub-section:

  1. Define the DTO — a new data class like ZeroEgressEvidenceV1 with documented properties and @param KDoc
  2. Add to SovereignEvidencePackV1 — add an optional field (val newSection: NewSectionV1? = null)
  3. Update the writer — add a serializeNewSection() method and wire it into serialize() matching the data class declaration order
  4. Update the generator — add sanitization and validation in SovereignEvidencePackGenerator.generate()

Limitations

  • Snapshot-only — evidence packs capture a point-in-time view; they are not updated automatically
  • No secrets — by design, evidence packs cannot contain secrets, tokens, or credentials (EvidenceSafeString actively rejects them)
  • No runtime data — no prompts, responses, or model outputs are included
  • Manual sub-sectionszeroEgress, auditChain, supplyChain, releaseBundle, and attestation must be constructed manually and passed to evidencePack()
  • Schema version 1 — the current schema is v1; breaking changes will increment schemaVersion

Next Steps