Finish FLEX-WP-0019 layer-model v0.7 conformance
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 2s
Build and Publish Container Image / build-and-push (push) Successful in 57s

Close the remaining PDP obligations: mechanical layer declaration check,
registry-snapshot digest in provenance, explicit allow TTL, per-input-class
freshness deadlines, and the published decision-record contract. Document
the canonical request digest as the §6.4.2 replay test.

Assistant: grok
Assistant-Session: 01a06256-fb71-7102-b3a9-27e6734257d0
This commit is contained in:
tegwick 2026-09-03 23:48:45 +02:00
parent 9689894c15
commit 56940727bf
32 changed files with 1194 additions and 111 deletions

View file

@ -13,11 +13,14 @@ import (
// Adapter maps flex-auth checks and resources to Keycloak Authorization
// Services while preserving the flex-auth decision envelope.
type Adapter struct {
client Client
realm string
audience string
policyPackage string
policyVersion string
client Client
realm string
audience string
policyPackage string
policyVersion string
policyPackageDigest string
registrySnapshotDigest string
allowTTL string
}
func New(client Client, options Options) (*Adapter, error) {
@ -31,11 +34,14 @@ func New(client Client, options Options) (*Adapter, error) {
return nil, fmt.Errorf("keycloak audience is required")
}
return &Adapter{
client: client,
realm: options.Realm,
audience: options.Audience,
policyPackage: options.PolicyPackage,
policyVersion: options.PolicyVersion,
client: client,
realm: options.Realm,
audience: options.Audience,
policyPackage: options.PolicyPackage,
policyVersion: options.PolicyVersion,
policyPackageDigest: options.PolicyPackageDigest,
registrySnapshotDigest: options.RegistrySnapshotDigest,
allowTTL: options.AllowTTL,
}, nil
}
@ -154,7 +160,8 @@ func (a *Adapter) envelope(request api.CheckRequest, authz AuthorizationRequest,
},
Caring: caringDecisionMetadata(firstDescriptor(request.CaringContext, result.CaringDescriptor), result.ConformanceFindings),
}
envelope.ID = decisionID(a.policyPackage, policyVersion, request, effect, reason)
envelope = a.finish(request, envelope)
envelope.ID = decisionID(a.policyPackage, policyVersion, request, envelope.Effect, envelope.Reason)
return envelope
}
@ -179,10 +186,22 @@ func (a *Adapter) failureEnvelope(request api.CheckRequest, authz AuthorizationR
},
Caring: caringDecisionMetadata(request.CaringContext, []api.CaringConformanceFinding{failureFinding(kind)}),
}
envelope = a.finish(request, envelope)
envelope.ID = decisionID(a.policyPackage, policyVersion, request, envelope.Effect, envelope.Reason)
return envelope
}
func (a *Adapter) finish(request api.CheckRequest, envelope api.DecisionEnvelope) api.DecisionEnvelope {
if envelope.Provenance.RegistrySnapshotDigest == "" {
envelope.Provenance.RegistrySnapshotDigest = a.registrySnapshotDigest
}
if envelope.Provenance.PolicyPackageDigest == "" {
envelope.Provenance.PolicyPackageDigest = a.policyPackageDigest
}
api.CompleteDecision(&envelope, request, api.DecisionCompletion{AllowTTL: a.allowTTL})
return envelope
}
func caringDecisionMetadata(descriptor *api.CaringAccessDescriptor, findings []api.CaringConformanceFinding) *api.CaringDecisionMetadata {
profile := api.CaringProfileCaring040RC2
if descriptor != nil && descriptor.Profile != "" {

View file

@ -23,10 +23,13 @@ type Client interface {
// Options configures Keycloak mapping without making Keycloak the source of
// truth for flex-auth resources or policies.
type Options struct {
Realm string
Audience string
PolicyPackage string
PolicyVersion string
Realm string
Audience string
PolicyPackage string
PolicyVersion string
PolicyPackageDigest string
RegistrySnapshotDigest string
AllowTTL string
}
// AuthorizationRequest is the UMA permission request flex-auth sends to