Documentation
¶
Overview ¶
Package credboundtest provides deterministic test doubles and constructors for host services that integrate github.com/deepteams/credbound.
NewManager builds a fully wired *credbound.Manager backed by the in-memory store, a fast fake password hasher, a deterministic clock and random source, and TOTP/passkey fakes whose enrollment and verification flows succeed with fixed inputs. Use it in host-service tests to exercise real Credbound flows — bootstrap, sign-in, second factors, step-up, PATs — without Argon2 latency, real WebAuthn ceremonies, or wall-clock coupling.
Nothing in this package is safe for production use. Passwords stores a recoverable marker instead of a real hash, TOTP accepts the fixed code ValidTOTPCode, AAL2 mints an assurance level that only a real second factor may produce in production, and the deterministic random source is predictable by design. Import it from _test files only.
Index ¶
- Constants
- Variables
- func AAL2(userID credbound.UUID, at time.Time) credbound.Authentication
- func Bootstrap(t testing.TB, manager *credbound.Manager) (credbound.Authentication, credbound.Workspace)
- func NewDeterministicRandom() io.Reader
- func NewManager(t testing.TB, opts ...Option) *credbound.Manager
- type Clock
- type DiscoverablePasskeys
- type Option
- func WithClock(clock *Clock) Option
- func WithConfig(mutate func(*credbound.Config)) Option
- func WithEventListeners(listeners ...credbound.EventListener) Option
- func WithPasswordPolicy(policy credbound.PasswordPolicy) Option
- func WithRandom(random io.Reader) Option
- func WithSSOProviders(providers ...credbound.SSOProvider) Option
- func WithStore(store credbound.Store) Option
- func WithTransactionHooks(hooks ...credbound.TransactionHook) Option
- type Passkeys
- func (Passkeys) BeginAuthentication(_ context.Context, user credbound.PasskeyUser) (json.RawMessage, []byte, error)
- func (Passkeys) BeginDecoyAuthentication(_ context.Context, _ []byte) (json.RawMessage, []byte, error)
- func (Passkeys) BeginRegistration(context.Context, credbound.PasskeyUser) (json.RawMessage, []byte, error)
- func (Passkeys) FinishAuthentication(_ context.Context, _ credbound.PasskeyUser, session, response []byte) (credentialID, credentialJSON []byte, err error)
- func (Passkeys) FinishRegistration(_ context.Context, _ credbound.PasskeyUser, session, response []byte) (credentialID, credentialJSON []byte, err error)
- type Passwords
- type TOTP
Constants ¶
const ( // BootstrapEmail is the primary address of the bootstrapped root user. BootstrapEmail = "root@example.com" // BootstrapPassword is the password of the bootstrapped root user. BootstrapPassword = "correct horse battery staple" // BootstrapDisplayName is the display name of the bootstrapped root user. BootstrapDisplayName = "Root" // BootstrapWorkspaceName is the name of the bootstrapped workspace. BootstrapWorkspaceName = "Main" )
Fixed identity used by Bootstrap. The password satisfies the default minimum length of twelve characters.
const ValidPasskeyResponse = "valid"
ValidPasskeyResponse is the only client response the Passkeys fake accepts; pass []byte(ValidPasskeyResponse) to FinishPasskeyRegistration and FinishPasskeyAuthentication. Any other response fails the ceremony.
const ValidTOTPCode = "123456"
ValidTOTPCode is the only code the TOTP fake accepts. Any other input is rejected, so tests can exercise both success and failure paths.
Variables ¶
var DefaultStartTime = time.Date(2026, 1, 1, 12, 0, 0, 0, time.UTC)
DefaultStartTime is the initial instant of the deterministic clock used by NewManager when no WithClock option is given. Tests can rely on it when asserting timestamps or constructing an AAL2 step-up for a manager whose clock was never advanced.
Functions ¶
func AAL2 ¶
AAL2 fabricates an interactive AAL2 authentication for userID as of at, as if the user had just verified a TOTP code. Use it to satisfy step-up checks (for example before CreatePAT) without running a second-factor ceremony in every test.
This helper is test-only by definition: production code must never construct an AAL2 authentication itself — only VerifyTOTP, a passkey, or SSO reauthentication may produce one.
func Bootstrap ¶
func Bootstrap(t testing.TB, manager *credbound.Manager) (credbound.Authentication, credbound.Workspace)
Bootstrap creates the first user and workspace of the instance with the fixed Bootstrap* identity and returns the resulting authentication and workspace. It fails the test on error, including the credbound.ErrConflict returned by a second call on the same manager.
func NewDeterministicRandom ¶
NewDeterministicRandom returns an io.Reader emitting a fixed byte sequence, so identifiers and tokens are reproducible across runs. It is the default random source of NewManager and is, by design, not cryptographically secure; never use it outside tests.
func NewManager ¶
NewManager builds a *credbound.Manager wired for tests: memory.New() store, the fast Passwords hasher, the TOTP and Passkeys fakes, fixed secret key and peppers, a Clock frozen at DefaultStartTime, and a deterministic random source. Options override individual parts. Construction failures fail the test immediately.
The resulting manager must never back a production service: every secret it derives is fixed and every credential it accepts is predictable.
Types ¶
type Clock ¶
type Clock struct {
// contains filtered or unexported fields
}
Clock is a manually driven time source for deterministic tests. It only moves when Advance or Set is called, so freshness windows such as Config.StepUpMaxAge and TOTP steps are fully under test control. It is safe for concurrent use.
func (*Clock) Advance ¶
Advance moves the clock forward by d. Use it to cross freshness boundaries, for example Advance(30*time.Second) between two TOTP verifications so the second code lands on a new step, or Advance past Config.StepUpMaxAge to expire a step-up.
type DiscoverablePasskeys ¶
type DiscoverablePasskeys struct{ Passkeys }
DiscoverablePasskeys extends the Passkeys fake with usernameless sign-in over discoverable credentials. Install it explicitly when a test exercises BeginDiscoverablePasskeyAuthentication, since the plain Passkeys fake — like a provider that does not implement the optional port — makes those flows return credbound.ErrNotSupported:
manager := credboundtest.NewManager(t, credboundtest.WithConfig(func(cfg *credbound.Config) {
cfg.Passkeys = credboundtest.DiscoverablePasskeys{}
}))
FinishDiscoverableAuthentication resolves the fixed credential through the lookup, so the manager's account resolution and its user-handle check are exercised rather than bypassed.
func (DiscoverablePasskeys) BeginDiscoverableAuthentication ¶
func (DiscoverablePasskeys) BeginDiscoverableAuthentication(context.Context) (json.RawMessage, []byte, error)
BeginDiscoverableAuthentication returns fixed request options and the session that FinishDiscoverableAuthentication expects back.
func (DiscoverablePasskeys) FinishDiscoverableAuthentication ¶
func (DiscoverablePasskeys) FinishDiscoverableAuthentication(ctx context.Context, session, response []byte, lookup credbound.PasskeyUserLookup) (credentialID, credentialJSON []byte, err error)
FinishDiscoverableAuthentication validates the session issued by BeginDiscoverableAuthentication, accepts exactly []byte(ValidPasskeyResponse), and resolves the fixed credential through lookup, surfacing the ErrNotFound of an unknown credential.
type Option ¶
type Option func(*settings)
Option customizes the manager built by NewManager.
func WithClock ¶
WithClock replaces the manager's time source. Keep a reference to the clock to advance time from the test.
func WithConfig ¶
WithConfig applies an arbitrary mutation to the assembled credbound.Config just before New runs, covering everything without a dedicated option — Config.SignUp, Config.OAuth, Config.SessionTTL, TTLs, and so on:
manager := credboundtest.NewManager(t, credboundtest.WithConfig(func(cfg *credbound.Config) {
cfg.SignUp = &credbound.SignUpConfig{}
}))
Mutators run in registration order, after the other options are applied.
func WithEventListeners ¶
func WithEventListeners(listeners ...credbound.EventListener) Option
WithEventListeners registers post-commit event listeners, mirroring credbound.Config.EventListeners.
func WithPasswordPolicy ¶
func WithPasswordPolicy(policy credbound.PasswordPolicy) Option
WithPasswordPolicy installs an additional password vetting policy, mirroring credbound.Config.PasswordPolicy.
func WithRandom ¶
WithRandom replaces the deterministic random source, for example with crypto/rand.Reader when a test needs unpredictable tokens.
func WithSSOProviders ¶
func WithSSOProviders(providers ...credbound.SSOProvider) Option
WithSSOProviders registers SSO providers, mirroring credbound.Config.SSOProviders.
func WithStore ¶
WithStore replaces the default in-memory store, for example with a migration-applied PostgreSQL store to test against real persistence.
func WithTransactionHooks ¶
func WithTransactionHooks(hooks ...credbound.TransactionHook) Option
WithTransactionHooks registers transaction hooks, mirroring credbound.Config.TransactionHooks.
type Passkeys ¶
type Passkeys struct{}
Passkeys is a fake credbound.PasskeyProvider for tests. Both ceremonies return fixed JSON options and an opaque session, and both Finish methods accept exactly []byte(ValidPasskeyResponse) as the client response. The registered credential is a fixed JSON document whose authenticator counter increments on authentication, mirroring a real WebAuthn provider closely enough for the manager's encrypt-at-rest and ceremony plumbing to be exercised end to end.
func (Passkeys) BeginAuthentication ¶
func (Passkeys) BeginAuthentication(_ context.Context, user credbound.PasskeyUser) (json.RawMessage, []byte, error)
BeginAuthentication drains the user's stored credentials — surfacing any decryption error the manager reports — and returns fixed request options with the session that FinishAuthentication expects back.
func (Passkeys) BeginDecoyAuthentication ¶
func (Passkeys) BeginDecoyAuthentication(_ context.Context, _ []byte) (json.RawMessage, []byte, error)
BeginDecoyAuthentication returns a fixed challenge for an address with no passkey, so the manager's answer never reveals whether an account has one.
func (Passkeys) BeginRegistration ¶
func (Passkeys) BeginRegistration(context.Context, credbound.PasskeyUser) (json.RawMessage, []byte, error)
BeginRegistration returns fixed creation options and the registration session that FinishRegistration expects back.
func (Passkeys) FinishAuthentication ¶
func (Passkeys) FinishAuthentication(_ context.Context, _ credbound.PasskeyUser, session, response []byte) (credentialID, credentialJSON []byte, err error)
FinishAuthentication validates the session issued by BeginAuthentication and accepts exactly []byte(ValidPasskeyResponse), returning the fixed credential with its counter advanced.
func (Passkeys) FinishRegistration ¶
func (Passkeys) FinishRegistration(_ context.Context, _ credbound.PasskeyUser, session, response []byte) (credentialID, credentialJSON []byte, err error)
FinishRegistration validates the session issued by BeginRegistration and accepts exactly []byte(ValidPasskeyResponse), returning a fixed credential.
type Passwords ¶
type Passwords struct{}
Passwords is a fast fake credbound.PasswordHasher for tests. Hash returns a recoverable marker ("credboundtest$" plus the password) instead of a real key derivation, so building a manager and authenticating cost nothing.
It must never be used in production: it performs no salting, no stretching, and stores the password in clear inside the "hash".
type TOTP ¶
type TOTP struct{}
TOTP is a fake credbound.TOTPProvider for tests. Generate returns a fixed secret and otpauth URI, and Validate accepts exactly ValidTOTPCode ("123456" is always valid; everything else never is).
Validate reports the real 30-second step for the given instant, so the manager's replay protection behaves as in production: verifying ValidTOTPCode twice without advancing the Clock by at least 30 seconds fails the second attempt with credbound.ErrInvalidCredentials.