Skip to content

Latest commit

 

History

History
307 lines (281 loc) · 10.5 KB

File metadata and controls

307 lines (281 loc) · 10.5 KB

Phase 4 authenticated binding example

Explanatory documentation only. This detailed walkthrough is non-normative and performs no policy decision, Authorization, Consumption, or Execution.

What problem does this example address?

Before policy can evaluate a model-proposed operation, the Host must bind the canonical request to authenticated identity, intent, provenance, influence completeness, capabilities, resources, and one genuine Host boundary.

Why this flow?

Each claim is validated against explicit Host-controlled evidence before it is assembled into EvaluationInput. That sequencing prevents later policy from mistaking model-controlled identity or incomplete influence data for trusted facts.

Minimal Swift walkthrough

This pseudo-code begins after Phase 3 has produced canonicalRequest and the matching lookup. The host controls the authority/attestation entry points. No model field is routed into them, and the structured evidence is not a signature.

let evaluationTime = try EpochSeconds(1_800_000_000)
let validity = try ValidityWindow(
    issuedAt: EpochSeconds(1_799_999_900),
    notBefore: EpochSeconds(1_799_999_900),
    expiresAt: EpochSeconds(1_800_000_300)
)
let subject = SubjectID(rawValue: "subject-1042")
let tenant = TenantID(rawValue: "tenant-finance")
let session: SecuritySessionBinding = .session(SessionID(rawValue: "session-7"))
let attestationScope = HostAttestationScope(
    subjectID: subject,
    tenantID: tenant,
    sessionBinding: session
)

// Authenticated host configuration path only. This compact example uses an
// explicitly trusted monolithic-host profile. Production integrations should
// prefer separate role-specific authorities sharing this one domain and exact
// entitlement scope.
let hostCapabilityBoundary = HostCapabilityBoundary()
let authority = try HostAuthorityValidator.validate(
    HostAuthorityClaim(
        id: HostAuthorityID(validating: "primary-host"),
        roles: [
            .authenticationAuthority,
            .intentCaptureAuthority,
            .provenanceAuthority,
            .influenceCollector,
        ],
        scope: HostAuthorityScope(
            capabilities: [.financialTransfer],
            resources: [ResourceID(rawValue: "invoice-1042")]
        )
    ),
    capabilityBoundary: hostCapabilityBoundary
)

let contextID = try ContextID(validating: "context-1042")
let intentID = IntentID(rawValue: "intent-1042")
let provenanceID = try ProvenanceID(validating: "provenance-document")
let boundaryID = try CollectionBoundaryID(validating: "collector-request")
let capabilities = try IntentCapabilityScope(capabilities: [.financialTransfer])
let resources = try IntentResourceScope(
    resources: [ResourceID(rawValue: "invoice-1042")]
)

// Raw claims remain untrusted. Their bindings commit host evidence to every
// security-relevant value rather than merely to a reusable identifier.
let rawContext = SecurityContextClaim(
    id: contextID,
    version: .v1,
    subjectID: subject,
    tenantID: tenant,
    sessionBinding: session,
    assurance: .multiFactor,
    authenticationMethods: [.knowledgeFactor, .possessionFactor],
    delegationID: nil,
    validity: validity,
    authenticationAttestationID: try HostAttestationID(
        validating: "attestation-context"
    )
)
let rawIntent = UserIntentClaim(
    id: intentID,
    version: .v1,
    subjectID: subject,
    tenantID: tenant,
    sessionBinding: session,
    scope: IntentScope(
        target: .exactRequest(canonicalRequest),
        capabilityScope: capabilities,
        resourceScope: resources
    ),
    validity: validity,
    renewalGeneration: IntentRenewalGeneration(1),
    attestationID: try HostAttestationID(validating: "attestation-intent")
)
let rawProvenance = [
    ProvenanceClaim(
        id: provenanceID,
        source: .retrievedWebContent,
        evidenceReferenceID: try EvidenceReferenceID(validating: "document-42"),
        transformations: [.extracted],
        attestationID: try HostAttestationID(validating: "attestation-provenance")
    ),
    ProvenanceClaim(
        id: try ProvenanceID(validating: "provenance-model"),
        source: .modelOutput,
        evidenceReferenceID: try EvidenceReferenceID(validating: "model-output-7"),
        transformations: [.generatedByModel]
    ),
]
let rawInfluences = try [
    InfluenceClaim(
        id: InfluenceID(validating: "influence-user"),
        kind: .userPrompt,
        evidenceReferenceID: EvidenceReferenceID(validating: "prompt-reference"),
        provenanceID: nil,
        parentIDs: [],
        collectionBoundaryID: boundaryID
    ),
    InfluenceClaim(
        id: InfluenceID(validating: "influence-document"),
        kind: .document,
        evidenceReferenceID: EvidenceReferenceID(validating: "document-42"),
        provenanceID: provenanceID,
        parentIDs: [InfluenceID(validating: "influence-user")],
        collectionBoundaryID: boundaryID
    ),
]
let collectionBinding = try InfluenceCollectionAttestationBinding(
    boundaryID: boundaryID,
    influenceIDs: rawInfluences.map(\.id)
)

let rawAttestations = try [
    HostAttestationClaim(
        id: HostAttestationID(validating: "attestation-context"),
        issuerID: authority.id,
        role: .authenticationAuthority,
        scope: attestationScope,
        validity: validity,
        fact: .securityContext(rawContext.attestationBinding)
    ),
    HostAttestationClaim(
        id: HostAttestationID(validating: "attestation-intent"),
        issuerID: authority.id,
        role: .intentCaptureAuthority,
        scope: attestationScope,
        validity: validity,
        fact: .userIntent(rawIntent.attestationBinding)
    ),
    HostAttestationClaim(
        id: HostAttestationID(validating: "attestation-provenance"),
        issuerID: authority.id,
        role: .provenanceAuthority,
        scope: attestationScope,
        validity: validity,
        fact: .provenance(rawProvenance[0].attestationBinding)
    ),
    HostAttestationClaim(
        id: HostAttestationID(validating: "attestation-influences"),
        issuerID: authority.id,
        role: .influenceCollector,
        scope: attestationScope,
        validity: validity,
        fact: .influenceCollection(collectionBinding)
    ),
]
let attestations = try HostAttestationValidator.validate(
    rawAttestations,
    authority: authority,
    capabilityBoundary: hostCapabilityBoundary,
    evaluationTime: evaluationTime
)

let context = try SecurityContextValidator.validate(
    rawContext,
    attestations: attestations,
    evaluationTime: evaluationTime
)

let intent = try UserIntentValidator.validate(
    rawIntent,
    lookup: lookup,
    attestations: attestations,
    evaluationTime: evaluationTime
)

let provenance = try ProvenanceValidator.validate(
    rawProvenance,
    proposalAssessment: canonicalRequest.proposalAssessment,
    hostCapabilityBoundary: hostCapabilityBoundary,
    scope: attestationScope,
    attestations: attestations,
    evaluationTime: evaluationTime
)

let influences = try InfluenceValidator.validate(
    rawInfluences,
    collections: [
        InfluenceCollectionClaim(
            boundaryID: boundaryID,
            completeness: .complete(
                attestationID: HostAttestationID(validating: "attestation-influences")
            )
        )
    ],
    provenance: provenance,
    proposalAssessment: canonicalRequest.proposalAssessment,
    hostCapabilityBoundary: hostCapabilityBoundary,
    scope: attestationScope,
    attestations: attestations,
    evaluationTime: evaluationTime
)

let evaluationInput = try EvaluationInputValidator.validate(
    version: .v1,
    canonicalRequest: canonicalRequest,
    lookup: lookup,
    intent: intent,
    securityContext: context,
    requestedScope: EvaluationScopeClaim(
        capabilityScope: capabilities,
        resourceScope: resources
    ),
    provenance: provenance,
    influences: influences,
    hostCapabilityBoundary: hostCapabilityBoundary,
    evaluationTime: evaluationTime,
    renewalGeneration: IntentRenewalGeneration(1)
)
// Complete future-policy input only; no allow/deny, authorization, or execution.

do {
    // `contextForAnotherSubject` must itself have been separately host-attested.
    _ = try EvaluationInputValidator.validate(
        version: .v1,
        canonicalRequest: canonicalRequest,
        lookup: lookup,
        intent: intent,
        securityContext: contextForAnotherSubject,
        requestedScope: EvaluationScopeClaim(
            capabilityScope: capabilities,
            resourceScope: resources
        ),
        provenance: provenance,
        influences: influences,
        hostCapabilityBoundary: hostCapabilityBoundary,
        evaluationTime: evaluationTime,
        renewalGeneration: IntentRenewalGeneration(1)
    )
} catch let error as Phase4Error where error.reason == .subjectMismatch {
    // Typed privacy-safe rejection, with no partial EvaluationInput.
}

do {
    // A raw `.complete` claim with a missing/wrong collector attestation rejects.
    _ = try InfluenceValidator.validate(
        [],
        collections: [unattestedCompleteCollection],
        provenance: provenance,
        proposalAssessment: canonicalRequest.proposalAssessment,
        hostCapabilityBoundary: hostCapabilityBoundary,
        scope: attestationScope,
        attestations: [],
        evaluationTime: evaluationTime
    )
} catch let error as Phase4Error
    where error.reason == .invalidInfluenceCompleteness
{
    // Missing evidence never downgrades to partial or upgrades to complete.
}

The example performs no policy evaluation, confirmation, authorization, cryptography, trusted-time lookup, parsing, networking, persistence, model call, or execution.

Threats prevented

  • Subject, tenant, session, delegation, Tool, and Host-boundary substitution.
  • Capability or resource claims beyond authenticated Host ceilings.
  • Missing provenance being treated as trusted provenance.
  • Incomplete influence collections being represented as complete.
  • Model-controlled values entering Host authority or attestation paths.

Common mistakes

  • Treating a HostAuthorityClaim as already authenticated authority.
  • Reusing descriptive IDs across a new HostCapabilityBoundary.
  • Marking influence complete without the exact collector attestation.
  • Mixing security contexts or intent from different subjects or sessions.
  • Treating EvaluationInput as an allow decision or Authorization.

Related documentation