Documentation
¶
Overview ¶
Package testharness provides in-process test scaffolding for the permission system. It exists so unit tests of guards, interceptors, and plugin code can assert PDP behavior WITHOUT spinning up a real saas-starter (which lives in a separate repo and needs Postgres).
What's here:
FakePDP: programmable decisions + a recorded call log. Use this when a unit test needs "PDP says allow on action X, deny on action Y" without caring how the decisions are made.
PrincipalBuilder: ergonomic construction of test Principals (humans, services, agents) for stamping into context.
DelegationBuilder: build delegation chains for tests of escalation / sub-agent flows.
What's NOT here (yet):
- SaaSFixture: a Postgres + saas-starter API harness. Lives in M0 phase 2 once the saas-starter Principal/Decide RPCs land. For now, integration tests against saas-starter live alongside the saas-starter codebase, not here.
Index ¶
- type FakeCall
- type FakePDP
- func (f *FakePDP) AllowTool(toolbox, tool string) *FakePDP
- func (f *FakePDP) AllowToolbox(toolbox string) *FakePDP
- func (f *FakePDP) CallCount() int
- func (f *FakePDP) Calls() []FakeCall
- func (f *FakePDP) DenyTool(toolbox, tool, reason string) *FakePDP
- func (f *FakePDP) DenyToolbox(toolbox, reason string) *FakePDP
- func (f *FakePDP) Evaluate(_ context.Context, req *policy.PDPRequest) policy.PDPDecision
- func (f *FakePDP) LastCall() FakeCall
- func (f *FakePDP) Reset()
- type PrincipalBuilder
- func (b *PrincipalBuilder) AsAgent(name, version string) *PrincipalBuilder
- func (b *PrincipalBuilder) AsHuman() *PrincipalBuilder
- func (b *PrincipalBuilder) AsService() *PrincipalBuilder
- func (b *PrincipalBuilder) Build() *policy.Principal
- func (b *PrincipalBuilder) DelegatedFrom(principalID, kind, displayName, grantID string) *PrincipalBuilder
- func (b *PrincipalBuilder) ExpiringIn(d time.Duration) *PrincipalBuilder
- func (b *PrincipalBuilder) WithAgentID(id string) *PrincipalBuilder
- func (b *PrincipalBuilder) WithDisplayName(name string) *PrincipalBuilder
- func (b *PrincipalBuilder) WithExpiresAt(t time.Time) *PrincipalBuilder
- func (b *PrincipalBuilder) WithID(id string) *PrincipalBuilder
- func (b *PrincipalBuilder) WithOrg(orgID string) *PrincipalBuilder
- func (b *PrincipalBuilder) WithToken(tok string) *PrincipalBuilder
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type FakeCall ¶
type FakeCall struct {
Toolbox string
Tool string
Args map[string]any
Identity map[string]any
Decision policy.PDPDecision // what the FakePDP returned
}
FakeCall is one recorded Evaluate. The fields are immutable snapshots — callers can hold them safely after Calls() returns.
type FakePDP ¶
type FakePDP struct {
// contains filtered or unexported fields
}
FakePDP is a programmable PDP for unit tests. It records every call so tests can assert what was asked, AND it returns a decision determined by either:
- An exact-match rule (Tool == request.Tool AND Toolbox == request.Toolbox)
- A toolbox-match rule (Toolbox == request.Toolbox, Tool == "")
- The default decision (set by NewFakePDP)
First match in the rules slice wins, in the order rules were added.
Concurrency: safe. Tests that fire goroutines at the PDP can read Calls() after the fact to assert what happened.
func NewFakeAllow ¶
func NewFakeAllow() *FakePDP
NewFakeAllow returns a FakePDP whose default is allow. Use when the test cares about specific denies; everything else is permitted.
func NewFakeDeny ¶
func NewFakeDeny() *FakePDP
NewFakeDeny returns a FakePDP whose default is deny with a recognizable reason. Use when the test cares about specific allows; everything else is refused. Reason includes "fake-pdp" substring so failure messages clearly show the gate is the test fixture, not a misconfigured production PDP.
func NewFakePDP ¶
func NewFakePDP(defaultDecision policy.PDPDecision) *FakePDP
NewFakePDP returns a FakePDP whose default (when no rule matches) is the supplied decision. Most tests use NewFakeAllow or NewFakeDeny rather than this directly.
func (*FakePDP) AllowTool ¶
AllowTool installs a rule allowing a specific tool on the named toolbox. Both must match exactly. Wildcards are not supported in the fake — tests that need pattern matching should configure multiple explicit rules.
func (*FakePDP) AllowToolbox ¶
AllowToolbox installs a rule allowing all tools on the named toolbox. Returns the receiver for chaining.
func (*FakePDP) CallCount ¶
CallCount returns the number of Evaluate calls observed. Cheaper than Calls() when the test only needs a count.
func (*FakePDP) Calls ¶
Calls returns a snapshot of every Evaluate call observed so far. Returned slice is safe to retain — it's a copy.
func (*FakePDP) DenyTool ¶
DenyTool installs a rule denying a specific tool with a reason. Reason MUST be non-empty — silent denials are a debugging nightmare; force the test author to write what they're asserting.
func (*FakePDP) DenyToolbox ¶
DenyToolbox installs a rule denying all tools on the named toolbox with the given reason. Empty reason gets a defaulted message.
func (*FakePDP) Evaluate ¶
func (f *FakePDP) Evaluate(_ context.Context, req *policy.PDPRequest) policy.PDPDecision
Evaluate implements policy.PDP. Records the call, returns the matched decision (or default).
type PrincipalBuilder ¶
type PrincipalBuilder struct {
// contains filtered or unexported fields
}
PrincipalBuilder constructs test Principals fluently. The default (zero-value Builder) gives a valid human principal in org "test-org" with a generated ID — useful when the test doesn't care who, just that there IS a principal.
Usage:
p := testharness.NewPrincipalBuilder().AsAgent("auto-merge", "0.1.0").Build()
ctx := policy.WithPrincipal(context.Background(), p)
func NewPrincipalBuilder ¶
func NewPrincipalBuilder() *PrincipalBuilder
NewPrincipalBuilder returns a builder with sensible defaults: a human principal in "test-org" with a unique generated ID.
func (*PrincipalBuilder) AsAgent ¶
func (b *PrincipalBuilder) AsAgent(name, version string) *PrincipalBuilder
AsAgent switches kind to agent and sets AgentID to the canonical "publisher/name:version" form. Tests should pass non-empty name + version; we fill in publisher as "test.codefly.dev" if not specified via WithAgentPublisher.
func (*PrincipalBuilder) AsHuman ¶
func (b *PrincipalBuilder) AsHuman() *PrincipalBuilder
AsHuman switches kind to human, clearing any previously-set agent fields. Default; rarely called explicitly.
func (*PrincipalBuilder) AsService ¶
func (b *PrincipalBuilder) AsService() *PrincipalBuilder
AsService switches kind to service. Use for test fixtures representing CI runners, deployment bots without per-version identity, etc.
func (*PrincipalBuilder) Build ¶
func (b *PrincipalBuilder) Build() *policy.Principal
Build produces the Principal. Panics on Validate failure — tests should fail loud if the builder produced something nonsensical.
func (*PrincipalBuilder) DelegatedFrom ¶
func (b *PrincipalBuilder) DelegatedFrom(principalID, kind, displayName, grantID string) *PrincipalBuilder
DelegatedFrom appends a link to the delegation chain. Multiple calls build a chain in the order they were called (oldest first).
Example: a sub-agent acting under user antoine's authority who herself delegated through Mind:
NewPrincipalBuilder().AsAgent("merger", "0.1.0").
DelegatedFrom("user-antoine", policy.KindHuman, "antoine", "grant-1").
DelegatedFrom("agent-mind", policy.KindAgent, "Mind", "grant-2").
Build()
func (*PrincipalBuilder) ExpiringIn ¶
func (b *PrincipalBuilder) ExpiringIn(d time.Duration) *PrincipalBuilder
ExpiringIn sets ExpiresAt to now+d. Use this rather than WithExpiresAt when the test only cares about "expires soon" / "expires far in the future" relative timing.
func (*PrincipalBuilder) WithAgentID ¶
func (b *PrincipalBuilder) WithAgentID(id string) *PrincipalBuilder
WithAgentID overrides the auto-built AgentID. Use when the test needs an exact identifier (e.g. matching a real plugin manifest).
func (*PrincipalBuilder) WithDisplayName ¶
func (b *PrincipalBuilder) WithDisplayName(name string) *PrincipalBuilder
WithDisplayName sets the human-readable name surfaced in audit / approval UI.
func (*PrincipalBuilder) WithExpiresAt ¶
func (b *PrincipalBuilder) WithExpiresAt(t time.Time) *PrincipalBuilder
WithExpiresAt sets the absolute expiry. Used by tests that drive IsExpiredAt with a fixed clock.
func (*PrincipalBuilder) WithID ¶
func (b *PrincipalBuilder) WithID(id string) *PrincipalBuilder
WithID overrides the auto-generated ID. Use when the test must assert a specific principal_id appearing in audit / PDP calls.
func (*PrincipalBuilder) WithOrg ¶
func (b *PrincipalBuilder) WithOrg(orgID string) *PrincipalBuilder
WithOrg sets the organization. Defaults to "test-org".
func (*PrincipalBuilder) WithToken ¶
func (b *PrincipalBuilder) WithToken(tok string) *PrincipalBuilder
WithToken sets the credential string. Tests of token-aware paths (PDP that re-verifies caveats, audit that logs the token id) need this to be a real-shaped token; tests of pure auth flow can leave it as the empty default.