87 lines
3.5 KiB
Go
87 lines
3.5 KiB
Go
|
|
package api
|
||
|
|
|
||
|
|
import "testing"
|
||
|
|
|
||
|
|
func claimBearing() CheckRequest {
|
||
|
|
return CheckRequest{
|
||
|
|
Tenant: "tenant:platform",
|
||
|
|
Subject: SubjectRef{ID: "secrets-engine", Type: "service"},
|
||
|
|
Action: "destroy",
|
||
|
|
Resource: ResourceRef{ID: "lane:glas-primary", Type: "secret-catalog-lane", System: "secrets-engine"},
|
||
|
|
Context: map[string]any{
|
||
|
|
"approval": map[string]any{"kind": "approval-claim", "valid_now": true},
|
||
|
|
},
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func claimFree() CheckRequest {
|
||
|
|
r := claimBearing()
|
||
|
|
r.Context = nil
|
||
|
|
return r
|
||
|
|
}
|
||
|
|
|
||
|
|
// TestApprovalBindingDigestSurvivesAttachingTheClaim is the property the whole
|
||
|
|
// field exists for. An approval's pdp_digest is recorded at issue time against a
|
||
|
|
// claim-free Check; the request that later carries the claim must still be able
|
||
|
|
// to name it.
|
||
|
|
func TestApprovalBindingDigestSurvivesAttachingTheClaim(t *testing.T) {
|
||
|
|
atIssue := RequestDigest(claimFree())
|
||
|
|
atExecute := ApprovalBindingDigest(claimBearing())
|
||
|
|
if atIssue != atExecute {
|
||
|
|
t.Fatalf("approval binding digest moved when the claim was attached:\n issue: %s\n execute: %s", atIssue, atExecute)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// TestRequestDigestStillMovesWhenTheClaimIsAttached guards the reason this is a
|
||
|
|
// second digest rather than a redefinition of the first. request_digest remains
|
||
|
|
// the full replay identity: attaching a claim changes the request, so it must
|
||
|
|
// change the digest. Collapsing the two would let an allow obtained with a valid
|
||
|
|
// claim be replayed against a request carrying none.
|
||
|
|
func TestRequestDigestStillMovesWhenTheClaimIsAttached(t *testing.T) {
|
||
|
|
if RequestDigest(claimFree()) == RequestDigest(claimBearing()) {
|
||
|
|
t.Fatal("request_digest ignored context.approval — replay identity must cover the claim")
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// TestTheTwoDigestsDisagreeOnAClaimBearingRequest asserts the distinction is
|
||
|
|
// real rather than decorative. A test that the two functions disagree is how a
|
||
|
|
// distinction that looks like duplication is defended.
|
||
|
|
func TestTheTwoDigestsDisagreeOnAClaimBearingRequest(t *testing.T) {
|
||
|
|
req := claimBearing()
|
||
|
|
if RequestDigest(req) == ApprovalBindingDigest(req) {
|
||
|
|
t.Fatal("the two digests agree on a claim-bearing request; one of them is not doing its job")
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// TestApprovalBindingDigestEqualsRequestDigestWithoutAClaim keeps the field
|
||
|
|
// honest for every consumer that never sends one.
|
||
|
|
func TestApprovalBindingDigestEqualsRequestDigestWithoutAClaim(t *testing.T) {
|
||
|
|
req := claimFree()
|
||
|
|
if RequestDigest(req) != ApprovalBindingDigest(req) {
|
||
|
|
t.Fatal("digests differ on a claim-free request; they must be the same value")
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// TestBindingOmitsApprovalDigestWhenNoClaimIsPresent avoids publishing a field
|
||
|
|
// that would read as a second identity on every ordinary decision.
|
||
|
|
func TestBindingOmitsApprovalDigestWhenNoClaimIsPresent(t *testing.T) {
|
||
|
|
if got := NewDecisionBinding(claimFree()).ApprovalBindingDigest; got != "" {
|
||
|
|
t.Fatalf("expected no approval_binding_digest on a claim-free request, got %q", got)
|
||
|
|
}
|
||
|
|
if got := NewDecisionBinding(claimBearing()).ApprovalBindingDigest; got == "" {
|
||
|
|
t.Fatal("expected approval_binding_digest on a claim-bearing request")
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// TestOtherContextClaimsStillBindUnderTheApprovalDigest confirms the exclusion is
|
||
|
|
// surgical: only the approval key leaves the material.
|
||
|
|
func TestOtherContextClaimsStillBindUnderTheApprovalDigest(t *testing.T) {
|
||
|
|
a := claimBearing()
|
||
|
|
a.Context["purpose"] = "rotate-exposed-key"
|
||
|
|
b := claimBearing()
|
||
|
|
b.Context["purpose"] = "something-else"
|
||
|
|
if ApprovalBindingDigest(a) == ApprovalBindingDigest(b) {
|
||
|
|
t.Fatal("approval binding digest ignored a non-approval context claim")
|
||
|
|
}
|
||
|
|
}
|