audit

package
v1.76.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 13, 2026 License: MIT Imports: 34 Imported by: 0

Documentation

Overview

Package audit is what sluis tells the audit trail.

The trail is kept by an installation of github.com/truvity/audit of this service's own, rendered beside it: a receiver that takes the records and answers RegisterCatalogue, a writer that locks and indexes them and whose digest job signs each hour, and a query service the console's Audit page reads. This package declares what is recorded in a catalogue (catalogue/roster.yaml), registers it at start-up, and sends each record to the receiver. With no installation configured, nothing is kept beyond the log line every record also is.

The vocabulary is fixed here and nowhere else. Every action has one constructor in events.go, the catalogue declares every one of them, and the gate fails when the two disagree; a caller cannot invent an action, a target type or an actor kind.

Recording never fails the thing being recorded, with one deliberate exception. A sign-in that could not be written down still happened, and refusing it because the trail was slow would turn an audit outage into an access outage. So almost every action is delivered `async`: it waits in the emitter's own queue, in memory, and is retried until the receiver acknowledges it. A recovery sign-in bypasses the directory, so its catalogue entry says `block`: Trail.RecordDurable returns only once the installation has it, and the caller refuses the sign-in when it does not.

Index

Constants

View Source
const (
	// PhaseStarted is kept before the command's first write.
	PhaseStarted = "started"
	// PhaseCompleted is kept after its last one.
	PhaseCompleted = "completed"
)

The phases of a record an operator's command keeps twice.

View Source
const (
	// CloudflareStored is the token sluis mints on its schedule and keeps at
	// external/cloudflare/<preset>.
	CloudflareStored = "stored"
	// CloudflareOnDemand is a token minted for one caller.
	CloudflareOnDemand = "on_demand"
)

The variants of a minted Cloudflare token.

View Source
const (
	ScopeEverywhere         = "everywhere"
	ScopeEveryBrowserAndApp = "every_browser_and_app"
	ScopeEveryAgent         = "every_agent"
	// ScopeClientEveryIdentity is an operator ending one client's sessions
	// for every person: the record names the client and no subject.
	ScopeClientEveryIdentity = "client_every_identity"
)

The scopes of a person's sessions revoked everywhere: every class and every sign-in ("Sign out everything", and every operator's revoke of a person), or one class of a person's own (docs/decisions/0040-agent-class-sessions.md, decision 7).

View Source
const (
	// WebhookConfigured is the webhook's URL and first secret set on GitHub,
	// right after the App was created.
	WebhookConfigured = "configured"
	// WebhookStaged is a new secret kept where the consumers read it, before
	// GitHub is told.
	WebhookStaged = "staged"
	// WebhookVerified is the new target answering a signed ping with the new
	// secret: the consumer holds it.
	WebhookVerified = "verified"
	// WebhookRotated is GitHub told to sign with the new secret.
	WebhookRotated = "rotated"
	// WebhookRestored is the previous secret put back after a rotation
	// stopped before GitHub was told.
	WebhookRestored = "restored"
)

The steps of setting or rotating a catalogued App's webhook secret, in the order a rotation takes them.

View Source
const (
	// RekeyStarted is kept before the first parameter is written.
	RekeyStarted = "started"
	// RekeyCompleted is kept after the last one.
	RekeyCompleted = "completed"
)

The phases of the record `sluis secrets rekey` keeps twice.

View Source
const MaintenanceCleared = "cleared"

MaintenanceCleared is Maintenance.State of a flag that was lifted.

View Source
const ScopePreUpgradeCookie = "pre_upgrade_cookie"

ScopePreUpgradeCookie is the scope of a SessionRevoked record the issuer writes when a browser signs out with a cookie set before the cookie had a secret of its own: the cookie held the sign-in's id, which proves nothing about who presented it, so the actor is Anonymous rather than the person. It goes when that sign-out path does, one release after it was added.

View Source
const ScopeRefreshTokenReuse = "refresh_token_reuse"

ScopeRefreshTokenReuse is the scope of a SessionRevoked record the issuer writes when it ends a session because one of its spent refresh tokens was presented after the grace window.

View Source
const ScopeSignInReplaced = "sign_in_replaced"

ScopeSignInReplaced is the scope of a SessionRevoked record the issuer writes when another person signs in in a browser that held a live sign-in: the earlier person's sign-in and the sessions opened under it are ended, with the new person as the actor.

View Source
const Source = "roster"

Source is the catalogue's source: every action is under it.

Tenant is the tenant every record is written under. An installation of sluis serves one organisation, and its trail is the installation's own rather than a customer's.

Variables

This section is empty.

Functions

func AccessExplained added in v1.76.0

func AccessExplained(actor Actor, o Outcome, subjectKind, subjectID string, groups, clients, admitted int) *record.Record

AccessExplained is a look-up of what a proof would effectively be granted: an operator's, which succeeds, or a refused caller's, which is denied. The subject is the proof looked up (kind person, ci or workload); groups, clients and admitted are counts and never names. A refused look-up carries zero counts.

func BackupCompleted added in v1.75.0

func BackupCompleted(actor Actor, id string, b BackupRun) *record.Record

BackupCompleted is a backup written and its manifest sealed.

func BackupFailed added in v1.75.0

func BackupFailed(actor Actor, id string, b BackupRun, detail string) *record.Record

BackupFailed is a backup that could not be completed.

func BackupPruned added in v1.75.0

func BackupPruned(actor Actor, removed, orphans []string, kept int, rule string) *record.Record

BackupPruned is the retention pass deleting backups. removed are the ids of backups, orphans the ids of runs that left chunks and no manifest, kept what remains, rule the retention in force.

func CatalogueAppCreated

func CatalogueAppCreated(actor Actor, org string, app App) *record.Record

CatalogueAppCreated is a catalogued App created.

func CatalogueAppDisconnected

func CatalogueAppDisconnected(actor Actor, org string, app App, uninstalled bool, reason string) *record.Record

CatalogueAppDisconnected is a catalogued App disconnected.

func CatalogueAppInstalled

func CatalogueAppInstalled(actor Actor, org string, app App, installation int64) *record.Record

CatalogueAppInstalled is a catalogued App installed.

func CatalogueAppWebhookChanged added in v1.74.0

func CatalogueAppWebhookChanged(actor Actor, org string, app App, step string, o Outcome) *record.Record

CatalogueAppWebhookChanged is one step of setting or rotating a catalogued App's webhook secret; a step that did not complete is Failed, with its reason. Neither the secret nor the target URL is recorded: a Kargo receiver's path is derived from the secret.

func ClientSecretAdopted added in v1.66.0

func ClientSecretAdopted(client, source string, created time.Time) *record.Record

ClientSecretAdopted is the issuer taking a secret that already existed as the client's stored secret, unchanged: source is `input` (the secret the installation delivers) or `record` (a stored record that came back).

func ClientSecretCreated added in v1.66.0

func ClientSecretCreated(client string, created time.Time) *record.Record

ClientSecretCreated is the issuer making the secret of a generated client.

func ClientSecretDeleted added in v1.66.0

func ClientSecretDeleted(actor Actor, client string) *record.Record

ClientSecretDeleted is somebody deleting the stored secret of a client that is no longer in the policy.

func ClientSecretDenied added in v1.66.0

func ClientSecretDenied(actor Actor, client, action, reason string, overlap *int64) *record.Record

ClientSecretDenied is a verified caller refused when managing a generated client's secret: action is rotate, show or purge, reason one of forbidden, wrong_audience, busy, not_generated, still_declared, no_record or bad_overlap. client is empty when the refusal came before the body was read. overlap is the requested overlap in seconds, where the request had one.

func ClientSecretOrphaned added in v1.66.0

func ClientSecretOrphaned(client string, orphaned time.Time) *record.Record

ClientSecretOrphaned is the issuer finding a stored secret with no generated client of that id in the policy. It is reported once.

func ClientSecretRotated added in v1.66.0

func ClientSecretRotated(
	actor Actor, client string, rotated time.Time, overlap time.Duration, previousValidUntil time.Time, discardedPrevious bool,
) *record.Record

ClientSecretRotated is somebody replacing the secret of a generated client. overlap is how long the old one stays accepted; discardedPrevious is set when that cut an earlier overlap short.

func CloudflareTokenMinted added in v1.74.0

func CloudflareTokenMinted(actor Actor, preset string, t CloudflareToken) *record.Record

CloudflareTokenMinted is a Cloudflare token minted from a preset's prototype: for the preset's stored document by sluis (System), or on demand for a caller.

func CloudflareTokenRefused added in v1.74.0

func CloudflareTokenRefused(actor Actor, preset, variant, reason, detail string, denied bool) *record.Record

CloudflareTokenRefused is a token not minted. reason is a short word (not_granted, lifetime_too_long, unknown_preset, prototype_active, prototype_forbidden, prototype_missing, minter_missing, cloudflare_error, store_error); detail says what the check found, never a value. A caller who was not granted the preset is Denied, anything else Failed.

func CloudflareTokenRevoked added in v1.74.0

func CloudflareTokenRevoked(actor Actor, preset, account, tokenID string) *record.Record

CloudflareTokenRevoked is somebody deleting a live token of a preset.

func CloudflareTokensSwept added in v1.74.0

func CloudflareTokensSwept(preset, account string, ids []string) *record.Record

CloudflareTokensSwept is sluis deleting the expired tokens it minted for a preset: only names that carry its own prefix.

func DirectoryUserID added in v1.75.0

func DirectoryUserID(address string) string

DirectoryUserID is the identifier a record uses for a person of a directory who has no other one (no login, no Slack user id): "du_" and the first 128 bits of the SHA-256 of the lower-cased address. It names nobody without the directory, holds no "@" or space, and is stable, so records about one person can be found together.

func GitHubAppCreated

func GitHubAppCreated(actor Actor, org string, app App) *record.Record

GitHubAppCreated is the organisation App created for an organisation.

func GitHubLinkCreated

func GitHubLinkCreated(person, login string) *record.Record

GitHubLinkCreated is a person linking their own GitHub account.

func GitHubLinkImported

func GitHubLinkImported(actor Actor, person, login, reason string) *record.Record

GitHubLinkImported is an operator importing a link.

func GitHubLinkLost

func GitHubLinkLost(person, login, reason string) *record.Record

GitHubLinkLost is a link lost.

func GitHubLinkMatched

func GitHubLinkMatched(person, login, reason string) *record.Record

GitHubLinkMatched is an account linked because its profile publishes the person's work address.

func GitHubLinkMoved

func GitHubLinkMoved(person, login, reason string) *record.Record

GitHubLinkMoved is a link moved to another address of the same person.

func GitHubLinkNarrowed

func GitHubLinkNarrowed(person, login, reason string) *record.Record

GitHubLinkNarrowed is a link that lost some of its addresses.

func GitHubLinkUnverifiable

func GitHubLinkUnverifiable(person, login, reason string) *record.Record

GitHubLinkUnverifiable is a link that can no longer be verified.

func GitHubMemberAdded

func GitHubMemberAdded(m Member, o Outcome) *record.Record

GitHubMemberAdded is a person added to a team.

func GitHubMemberHeld

func GitHubMemberHeld(m Member, change, reason string) *record.Record

GitHubMemberHeld is a change to a person's membership that is held for an operator. It is a failure with the reason it is held: the change the directory asked for has not happened.

func GitHubMemberInvited

func GitHubMemberInvited(m Member, o Outcome) *record.Record

GitHubMemberInvited is a person invited to an organisation or team.

func GitHubMemberRemoved

func GitHubMemberRemoved(m Member, o Outcome) *record.Record

GitHubMemberRemoved is a person removed from an organisation or team.

func GitHubMemberRoleSet

func GitHubMemberRoleSet(m Member, o Outcome) *record.Record

GitHubMemberRoleSet is a person's role on a team changed.

func GitHubOrgConnected

func GitHubOrgConnected(actor Actor, org string, app, installation int64, owner string) *record.Record

GitHubOrgConnected is an organisation connected by installing its App. owner is the directory workspace id recorded as its owner, empty when only the installation-wide roles operate it.

func GitHubOrgDisconnected

func GitHubOrgDisconnected(actor Actor, org string, uninstalled bool, reason string) *record.Record

GitHubOrgDisconnected is an organisation disconnected; reason is what the disconnect had to say, if anything.

func GitHubOrgOwnerChanged

func GitHubOrgOwnerChanged(actor Actor, org, from, to string) *record.Record

GitHubOrgOwnerChanged is an organisation's recorded owner changed by the installation-wide operator. from and to are directory workspace ids, empty for none.

func GitHubOwnerReported

func GitHubOwnerReported(m Member, change, reason string) *record.Record

GitHubOwnerReported is an organisation owner reported rather than removed.

func GitHubPassRequested

func GitHubPassRequested(actor Actor, org string) *record.Record

GitHubPassRequested is an operator asking the controller to pass over an organisation now rather than at its next interval.

func GitHubRemovalsConfirmed

func GitHubRemovalsConfirmed(actor Actor, org, fingerprint string, affected, members int) *record.Record

GitHubRemovalsConfirmed is an operator confirming removals the safety breaker held.

func GitHubTokenMinted

func GitHubTokenMinted(actor Actor, app string, t GitHubToken, o Outcome) *record.Record

GitHubTokenMinted is one installation token request, minted or refused.

func LinkAppConnected

func LinkAppConnected(actor Actor, app App, owner string) *record.Record

LinkAppConnected is the account-linking App connected.

func LinkAppDisconnected

func LinkAppDisconnected(actor Actor, app App, invalidated int) *record.Record

LinkAppDisconnected is the account-linking App disconnected.

func MaintenanceChanged added in v1.75.0

func MaintenanceChanged(actor Actor, m Maintenance) *record.Record

MaintenanceChanged is an operator setting or lifting the migration freeze.

func MaintenanceFailed added in v1.75.0

func MaintenanceFailed(actor Actor, m Maintenance, detail string) *record.Record

MaintenanceFailed is a change of the maintenance flag that was recorded and then did not happen, or did not complete.

func MigrationCopied added in v1.75.0

func MigrationCopied(actor Actor, c MigrationCopy, o Outcome) *record.Record

MigrationCopied is an operator copying a layout v4 installation into a layout v5 one. The catalogue declares it block.

func OnLambda added in v1.58.0

func OnLambda() bool

OnLambda reports whether this process is an AWS Lambda function.

func RecoverySignedIn

func RecoverySignedIn(actor Actor, client, how string, o Outcome) *record.Record

RecoverySignedIn is a sign-in by recovery, which bypasses the directory. The catalogue declares it block: it is kept before it succeeds.

func RestoreCompleted added in v1.75.0

func RestoreCompleted(actor Actor, backupID string, r Restore) *record.Record

RestoreCompleted is a restore that verified.

func RestoreFailed added in v1.75.0

func RestoreFailed(actor Actor, backupID string, r Restore, detail string) *record.Record

RestoreFailed is a restore that did not complete or did not verify.

func RestoreStarted added in v1.75.0

func RestoreStarted(actor Actor, backupID string, r Restore) *record.Record

RestoreStarted is a restore beginning.

func RunnerAppCreated

func RunnerAppCreated(actor Actor, org string, app App) *record.Record

RunnerAppCreated is a runner App created.

func RunnerAppDisconnected

func RunnerAppDisconnected(actor Actor, org string, app App, uninstalled bool, reason string) *record.Record

RunnerAppDisconnected is a runner App disconnected.

func RunnerAppInstalled

func RunnerAppInstalled(actor Actor, org string, app App, installation int64) *record.Record

RunnerAppInstalled is a runner App installed.

func SecretsPruned added in v1.75.0

func SecretsPruned(actor Actor, p SecretsPrune, o Outcome) *record.Record

SecretsPruned is an operator deleting the layout v4 parameters a migration carried. The catalogue declares it block: the started record is kept before the first delete.

func SecretsRekeyed added in v1.75.0

func SecretsRekeyed(actor Actor, r SecretsRekey, o Outcome) *record.Record

SecretsRekeyed is an operator re-writing the installation's SecureString parameters under the key the document names. The catalogue declares it block: the started record is kept before the first write.

func SessionEnded

func SessionEnded(actor Actor, ended int, spared []string) *record.Record

SessionEnded is a person signing out, ending their sessions. spared are the client ids of the agent-class sessions the sign-out left running (docs/decisions/0040-agent-class-sessions.md, decision 7), one per session, sorted; none is left out of the record.

func SessionRefreshRefused

func SessionRefreshRefused(person, client, reason string) *record.Record

SessionRefreshRefused is a session refused a refresh.

func SessionReuseRevoked added in v1.67.0

func SessionReuseRevoked(person, client string) *record.Record

SessionReuseRevoked is the issuer ending one of a person's sessions at a client because a refresh token already spent in it was presented again (RFC 9700 section 4.14.2).

It names no browser sign-in: a sign-in's id is the value of its cookie, and nothing that is a credential goes into an audit record.

func SessionRevoked

func SessionRevoked(actor Actor, person, client, scope string, ended int) *record.Record

SessionRevoked is somebody revoking a person's sessions: at one client, or all of them when client is empty.

func SessionsRevokedByClass added in v1.69.0

func SessionsRevokedByClass(actor Actor, person, scope string, ended int, endedClass, keptClass string) *record.Record

SessionsRevokedByClass is a person ending one class of their own sessions everywhere: ScopeEveryBrowserAndApp ends the interactive class and every browser sign-in and keeps the agent one, ScopeEveryAgent ends the agent class and keeps the rest.

func SignInRefused added in v1.76.0

func SignInRefused(actor Actor, client, how string, recovery bool, o Outcome, why Refusal) *record.Record

SignInRefused is a refused sign-in with the evaluation behind the refusal. A recovery sign-in is its own action, as it is when it succeeds.

func SignedIn

func SignedIn(actor Actor, client, how string, o Outcome) *record.Record

SignedIn is a person signing in to a client, or being refused.

func SignedInSession added in v1.69.0

func SignedInSession(actor Actor, client, how, class string, deadline time.Time, o Outcome) *record.Record

SignedInSession is a person signing in to a client at the issuer, with the class of the chain the sign-in opens and its computed deadline (docs/decisions/0040-agent-class-sessions.md, decision 8): `agent` for a background host that keeps its own refresh token, `interactive` for a person at a browser. An empty class or a zero deadline is left out, as for a refusal that decided neither.

func SlackActionHeld

func SlackActionHeld(workspace string, channel *SlackChannel, m *SlackMember, change, reason string) *record.Record

SlackActionHeld is a Slack change held for an operator, recorded once when it becomes held. It is a failure with the reason: what was asked for has not happened. The person and channel are optional.

func SlackCatalogueAppCreated

func SlackCatalogueAppCreated(actor Actor, a SlackCatalogueApp) *record.Record

SlackCatalogueAppCreated is a catalogued Slack App created from the console.

func SlackCatalogueAppInstallRefused

func SlackCatalogueAppInstallRefused(actor Actor, a SlackCatalogueApp, reason string) *record.Record

SlackCatalogueAppInstallRefused is an install Slack completed for a workspace other than the one the policy names for the App. The token it handed over was dropped.

func SlackCatalogueAppInstalled

func SlackCatalogueAppInstalled(actor Actor, a SlackCatalogueApp) *record.Record

SlackCatalogueAppInstalled is a catalogued Slack App installed into its workspace.

func SlackChannelAdopted

func SlackChannelAdopted(c SlackChannel, o Outcome) *record.Record

SlackChannelAdopted is an existing channel the Slack controller took over by id.

func SlackChannelArchived

func SlackChannelArchived(actor Actor, c SlackChannel, o Outcome) *record.Record

SlackChannelArchived is a channel archived in Slack by an operator who forgot its console record and asked for it; the outcome says whether Slack did it.

func SlackChannelCreated

func SlackChannelCreated(c SlackChannel, o Outcome) *record.Record

SlackChannelCreated is a channel the Slack controller created.

func SlackConsoleChannelCreated

func SlackConsoleChannelCreated(actor Actor, c SlackConsoleChannel) *record.Record

SlackConsoleChannelCreated is an ordinary channel put under management from the console.

func SlackConsoleChannelDeleted

func SlackConsoleChannelDeleted(actor Actor, c SlackConsoleChannel) *record.Record

SlackConsoleChannelDeleted is a console channel's record deleted from the console. The channel itself stays in Slack.

func SlackConsoleChannelUpdated

func SlackConsoleChannelUpdated(actor Actor, c SlackConsoleChannel, changes string) *record.Record

SlackConsoleChannelUpdated is a console channel's record changed from the console; changes says what, as 'field: before -> after' parts.

func SlackLeaverReported

func SlackLeaverReported(workspace, person, user, reason string) *record.Record

SlackLeaverReported is a person gone from the directory who is still an active Slack member, reported rather than acted on.

func SlackMemberInvited

func SlackMemberInvited(m SlackMember, o Outcome) *record.Record

SlackMemberInvited is a person invited to a channel.

func SlackMemberRemoved

func SlackMemberRemoved(m SlackMember, o Outcome) *record.Record

SlackMemberRemoved is a person removed from a private channel.

func SlackRemovalsConfirmed

func SlackRemovalsConfirmed(actor Actor, workspace, channel, fingerprint string, affected int) *record.Record

SlackRemovalsConfirmed is an operator confirming held removals; channel is empty when the confirmation covers the whole workspace.

func SlackSharedAccepted

func SlackSharedAccepted(s SlackShared, o Outcome) *record.Record

SlackSharedAccepted is the guest side accepting a shared-channel invite.

func SlackSharedChannelCreated

func SlackSharedChannelCreated(actor Actor, c SlackSharedChannel) *record.Record

SlackSharedChannelCreated is a shared channel defined from the console.

func SlackSharedChannelDeleted

func SlackSharedChannelDeleted(actor Actor, c SlackSharedChannel) *record.Record

SlackSharedChannelDeleted is a shared channel's definition deleted from the console. The channel itself stays in Slack.

func SlackSharedChannelUpdated

func SlackSharedChannelUpdated(actor Actor, c SlackSharedChannel, changes string) *record.Record

SlackSharedChannelUpdated is a shared channel's definition changed from the console; changes says what, as 'field: before -> after' parts.

func SlackSharedInvited

func SlackSharedInvited(s SlackShared, o Outcome) *record.Record

SlackSharedInvited is the host inviting another workspace's bot to a shared channel.

func SlackWorkspaceConnectRefused

func SlackWorkspaceConnectRefused(actor Actor, w SlackWorkspace, reason string) *record.Record

SlackWorkspaceConnectRefused is an install that Slack completed for a workspace other than the one recorded at its first install. The token it handed over was revoked and dropped, never kept.

func SlackWorkspaceConnected

func SlackWorkspaceConnected(actor Actor, w SlackWorkspace) *record.Record

SlackWorkspaceConnected is a workspace connected from the console.

func SlackWorkspaceDisconnected

func SlackWorkspaceDisconnected(actor Actor, w SlackWorkspace, revoked bool, reason string) *record.Record

SlackWorkspaceDisconnected is a workspace disconnected from the console; revoked says whether the bot token was revoked at Slack.

func SlackWorkspaceOwnerChanged

func SlackWorkspaceOwnerChanged(actor Actor, key, from, to string) *record.Record

SlackWorkspaceOwnerChanged is a workspace's recorded owner changed by the installation-wide operator. from and to are directory workspace ids, empty for none.

func TokenExchangeRefused added in v1.76.0

func TokenExchangeRefused(actor Actor, audience, proof string, o Outcome, why Refusal) *record.Record

TokenExchangeRefused is a refused token exchange with the evaluation behind the refusal.

func TokenExchanged

func TokenExchanged(actor Actor, audience, proof string, o Outcome) *record.Record

TokenExchanged is a token exchange for one client, by the kind of proof presented.

func Verify added in v1.76.0

func Verify(cfg Config) error

Verify builds what Open builds from cfg, as far as it can without reaching anything: the catalogue loads, and the `sqs` publisher is constructed from its settings (a missing queue is refused). A `connect` trail is not opened, because opening it registers the catalogue with the installation. Run it on the Config FromPlan returned.

func WorkspaceConnected

func WorkspaceConnected(actor Actor, workspace, backend, via string) *record.Record

WorkspaceConnected is a directory connected, by consent or by key.

func WorkspaceDisconnected

func WorkspaceDisconnected(actor Actor, workspace string) *record.Record

WorkspaceDisconnected is a directory disconnected.

func WorkspaceDomainsChanged

func WorkspaceDomainsChanged(actor Actor, workspace string, domains []string) *record.Record

WorkspaceDomainsChanged is a change to the domains a directory answers for. No domains means every domain the tenant owns.

func WorkspaceGroupsChanged

func WorkspaceGroupsChanged(actor Actor, workspace string, groups int) *record.Record

WorkspaceGroupsChanged is a change to the groups served from a directory.

func WorkspaceReconnected

func WorkspaceReconnected(actor Actor, workspace, backend, via string) *record.Record

WorkspaceReconnected is a connected directory given a new consent.

Types

type Actor

type Actor struct {
	Kind string
	ID   string
}

Actor is who acted.

func Anonymous

func Anonymous() Actor

Anonymous is a caller refused before it proved who it is.

func CI

func CI(id string) Actor

CI is a CI job, by the repository it runs for.

func Identified

func Identified(id string) Actor

Identified is whoever an identity string names, where only the string is known: an address is a person, a service account or an AWS role a workload, a repository a CI job. A recovery sign-in completes as a service account, so what it does afterwards is recorded as that workload's; the sign-in itself is recorded as recovery.

func Person

func Person(address string) Actor

Person is a member of the organisation, by the address the directory knows them by.

func RecoveryIdentity

func RecoveryIdentity(id string) Actor

RecoveryIdentity is whoever signed in by recovery, by the identity it completes as.

func System

func System() Actor

System is sluis acting on its own.

func Workload

func Workload(id string) Actor

Workload is a cluster workload, by its service account.

type App

type App struct {
	Name string
	ID   int64
	Slug string
	Tier string
}

App is a GitHub App as the records name it: by the id sluis catalogues it under where it has one, its slug otherwise, with GitHub's id and, for a runner App, its tier in data.

type BackupRun added in v1.75.0

type BackupRun struct {
	Installation string
	// Trigger is what started the run: schedule, run or cli.
	Trigger string
	Modules int
	Records int64
	Chunks  int
	Resumed bool
	// Reason is a short word for a failure: export, archive, key, maintenance
	// or canceled.
	Reason string
}

BackupRun is what a finished backup run holds, or how a failed one ended. Counts and words only: never a record, a key or a name inside the archive.

type CloudflareToken added in v1.74.0

type CloudflareToken struct {
	// Variant is [CloudflareStored] or [CloudflareOnDemand].
	Variant string
	// R2 says the preset hands out R2 (S3) credentials.
	R2        bool
	Account   string
	TokenID   string
	ExpiresOn time.Time
}

CloudflareToken is what a mint did. Never the value.

type Config

type Config struct {
	// Writer is the installation's receiver: the address records are sent to,
	// and the same address the catalogue is registered with, because the
	// receiver serves that call. Empty is a trail that is not connected:
	// every record is validated against the catalogue and written to the log,
	// and kept nowhere else.
	Writer string
	// SQS, when set, publishes records to a queue instead of a receiver (the
	// `sqs` adapter; see [FromPlan]). Writer is then unused: there is no
	// receiver to register a catalogue with, and no token to present, because
	// the queue is reached with the platform's own credentials.
	SQS *SQSConfig
	// SQSClient is the client SQS publishes with. Nil builds one from the
	// default credential chain.
	SQSClient SQSAPI
	// Sync makes Record wait, bounded by SyncTimeout, until the emitter has
	// delivered what it holds. It is for a runtime that freezes the process
	// between calls (Lambda), where an async queue in memory would be lost.
	// A record not delivered in time stays queued, and is retried if the
	// process runs again; Record still never fails its caller.
	Sync bool
	// SyncTimeout bounds that wait. Default 3s.
	SyncTimeout time.Duration
	// TokenFile is this workload's projected service-account token, presented
	// on every call. The installation knows the workload by it and stamps it
	// as the observer of every record.
	TokenFile string
	// Version and Instance identify this process on every record.
	Version  string
	Instance string
	Log      *slog.Logger
	// OnFatal is told of a refusal that no retry will change, found after the
	// start: an installation that was unreachable at start and, once reached,
	// refuses the catalogue. A refusal at start stops the start; this is what
	// stops the process when the same answer comes later, so that a service
	// whose records nobody accepts does not run for the life of the pod
	// keeping nothing. Nil leaves it running, saying so once at Error.
	OnFatal func(error)
}

Config says which installation to connect to, if any.

func FromPlan added in v1.58.0

func FromPlan(cfg Config, t port.Table) (Config, error)

FromPlan applies the audit concern of the resolved adapter table to cfg, which holds what the legacy `audit` keys said:

  • `connect` is the legacy mapping, used as configured (`audit.writer` and `audit.tokenFile`); it is refused without a writer.
  • `log` keeps nothing beyond the log line, and ignores a writer.
  • `sqs` publishes to the queue in the adapter's settings. There is no receiver on that path, so the writer is cleared and the catalogue is not registered: it is delivered in the audit writer's package. On Lambda the trail sends each record before the call returns.

An empty table (an adapter that does not plan) leaves cfg as it was.

func (Config) Connected

func (c Config) Connected() bool

Connected reports whether the configuration names an installation.

type Document

type Document struct {
	YAML    []byte
	Schemas map[string][]byte
}

Document is the catalogue as it is registered: the YAML document and every schema it references, keyed by $id.

func Catalogue

func Catalogue() (*catalogue.Catalogue, Document, error)

Catalogue loads the embedded catalogue, validated by the same toolchain the installation validates it with.

func LoadDocument

func LoadDocument() (Document, error)

LoadDocument reads the embedded catalogue.

type GitHubToken

type GitHubToken struct {
	Proof        string
	Org          string
	Grant        string
	Repositories []string
	Permissions  string
	Installation int64
	ExpiresAt    time.Time
}

GitHubToken is what an installation token request asked for, or was given. Never the token.

type Maintenance added in v1.75.0

type Maintenance struct {
	Installation string
	// State is the state set (migration), or MaintenanceCleared when lifted.
	State string
	// Modules is how many tables carry the flag after (set) or before (lifted).
	Modules int
	Reason  string
	// Forced is set when the flag lifted was a restore's.
	Forced bool
}

Maintenance is what a change of the maintenance flag carries.

type Member

type Member struct {
	Person string
	Org    string
	Team   string
	Login  string
	Role   string
}

Member is one person on a GitHub organisation or team, as the controller sees them: the address the directory knows, the login GitHub knows, either of which may be missing.

type MigrationCopy added in v1.75.0

type MigrationCopy struct {
	// Installation is the layout v5 side, From the layout v4 one.
	Installation, From string
	Phase              string
	Overwrite          bool
	// Written counts the items written, Replaced those of them that replace a
	// destination value that differed, ReplacedNames their names.
	Written, Replaced int
	ReplacedNames     []string
}

MigrationCopy is what `sluis migrate v5 copy` records: counts and names.

type Outcome

type Outcome struct {
	Result auditv1.Outcome_Result
	Reason string
}

Outcome is how an action ended.

func Denied

func Denied(reason string) Outcome

Denied is an action refused on purpose: a policy, a rule, a check.

func Failed

func Failed(reason string) Outcome

Failed is an action that was allowed and did not complete.

func Succeeded

func Succeeded() Outcome

Succeeded is an action that did what it was asked.

func (Outcome) Succeeded

func (o Outcome) Succeeded() bool

Succeeded reports whether the outcome is a success.

type Recorder

type Recorder interface {
	// Record hands a record to the trail. It never fails the caller: a record
	// that cannot be kept is logged as such.
	Record(ctx context.Context, r *record.Record)
	// RecordDurable returns only once the record is kept, or says why it is
	// not. It is for an action the catalogue declares `block`, and the caller
	// refuses what it records when this fails.
	RecordDurable(ctx context.Context, r *record.Record) error
}

Recorder is what records. Trail is the one implementation outside tests.

type Refusal added in v1.76.0

type Refusal struct {
	// Code is the reason in a word an alert can match: unknown_audience,
	// not_admitted, subject_token_refused, directory_unavailable, ...
	Code string
	// Audience is the client or audience the caller asked for.
	Audience string
	// Missing are the groups the audience requires, any of which would have
	// admitted the caller, and which the caller does not hold.
	Missing []string
	// Held are the groups the evaluation gave the caller.
	Held []string
	// Admitted says whether the evaluation admitted the caller, and AdmittedBy
	// by which of the required groups.
	Admitted   bool
	AdmittedBy []string
	// Directory is the state of what the groups were read from: live, held
	// (the last answer, kept while the directory is unreachable), unavailable,
	// or not_applicable for a proof no directory is asked about.
	Directory string
}

Refusal is the policy's evaluation behind a refused token exchange or sign-in: why, for which audience, what was missing, what was held. The caller is told "not authorised" and a request id; this is what the record under that id keeps, and the trail is access-controlled where a response is not.

type Restore added in v1.75.0

type Restore struct {
	Installation string
	Modules      int
	// Reason is a short word for a failure.
	Reason string
}

Restore is what a restore record carries.

type SQSAPI added in v1.58.0

type SQSAPI interface {
	SendMessageBatch(ctx context.Context, in *sqs.SendMessageBatchInput,
		opts ...func(*sqs.Options)) (*sqs.SendMessageBatchOutput, error)
}

SQSAPI is the part of the SQS client the publisher calls; *sqs.Client satisfies it, and so does a test's fake.

type SQSConfig added in v1.58.0

type SQSConfig struct {
	// QueueURL is the queue records are sent to. A URL ending in `.fifo` is a
	// FIFO queue: the tenant is the message group and the record id the
	// deduplication id.
	QueueURL string
	// Region and Endpoint are for the AWS client. Region empty is the default
	// chain's; Endpoint is for an emulator.
	Region   string
	Endpoint string
	// Timeout bounds one send, retries included. Default 5s: it is also the
	// longest a sign-in waits on Lambda.
	Timeout time.Duration
}

SQSConfig is where the `sqs` audit adapter publishes. The queue is the one the audit writer Lambda consumes; nothing else is configured here, because the writer, not sluis, owns the archive.

type SecretsPrune added in v1.75.0

type SecretsPrune struct {
	// Installation is the layout v5 side, From the layout v4 one.
	Installation, From string
	Phase              string
	// Plan is the confirmed plan hash.
	Plan string
	// Planned, Deleted and Kept are counts of parameters.
	Planned, Deleted, Kept int
	// Names are the parameters to delete.
	Names []string
}

SecretsPrune is what `sluis migrate v5 prune` records: names and counts, never a value.

type SecretsRekey added in v1.75.0

type SecretsRekey struct {
	Installation string
	// Key is the alias the parameters are re-written under.
	Key   string
	Phase string
	// Considered, Planned, Rekeyed and Deferred are counts of parameters.
	Considered, Planned, Rekeyed, Deferred int
	// Names are the parameters to re-write.
	Names []string
}

SecretsRekey is what `sluis secrets rekey` records: names and counts, never a value.

type SlackCatalogueApp

type SlackCatalogueApp struct {
	ID        string
	App       string
	Workspace string
	Team      string
	Scopes    []string
}

SlackCatalogueApp is a catalogue Slack App as the records name it: by Slack's own App id, with the id the deployment catalogues it under, the workspace key the policy gives it and, once installed, the team id and the scopes it was granted. Never a token.

type SlackChannel

type SlackChannel struct {
	Workspace string
	Name      string
	ID        string
	Private   bool
}

SlackChannel is a channel as the controller sees it: the workspace key, the channel's name and its Slack id.

type SlackConsoleChannel

type SlackConsoleChannel struct {
	Workspace string
	Name      string
	Private   bool
	// Mode is extend or strict.
	Mode    string
	Sources []string
	// Members are the individual addresses listed beside the groups: targets
	// too, never data.
	Members []string
}

SlackConsoleChannel is an ordinary channel managed from the console as the trail names it: by workspace and channel name, with the directory groups that feed it (targets, because an address is an identifier and never data) and how it is reconciled.

type SlackMember

type SlackMember struct {
	Person  string
	Channel SlackChannel
	User    string
	Groups  []string
	Reason  string
}

SlackMember is one person in one Slack channel: the address the directory knows, the Slack user id (which may be missing), the groups bound to the channel that admit them and the reason for the change.

type SlackShared

type SlackShared struct {
	Host    string
	Guest   string
	Channel string
	ID      string
	Invite  string
}

SlackShared is a Slack Connect shared channel between two of the installation's own workspaces: the host, the guest, the channel on the host side and the invite.

type SlackSharedChannel

type SlackSharedChannel struct {
	Name string
	Host string
	With []string
	// Sources are the directory groups, by address: carried as targets, because
	// an address is an identifier and never data.
	Sources []string
	// Members are the individual addresses listed beside the groups: targets
	// too, never data.
	Members []string
	// Private is one visibility for every side, unless PerSide is set.
	Private bool
	// PerSide is a visibility per workspace key, for a channel whose sides
	// differ.
	PerSide map[string]bool
}

SlackSharedChannel is a Slack Connect channel's definition as the trail names it: by the host workspace and channel name, with the workspaces it is shared with, the directory groups that feed it and its visibility.

func (SlackSharedChannel) Privacy

func (c SlackSharedChannel) Privacy() string

Privacy is the visibility in one word, or as workspace=word pairs in key order for a channel whose sides differ.

type SlackWorkspace

type SlackWorkspace struct {
	Key  string
	Team string
	App  string
	// Owner is the directory workspace id recorded as the workspace's owner,
	// empty for none.
	Owner string
}

SlackWorkspace is a Slack workspace as the records name it: by the key the policy gives it, with the Slack team id and App id where known.

type Trail

type Trail struct {
	// contains filtered or unexported fields
}

Trail is the recorder: an emitter bound to the catalogue, delivering to the installation when one is configured.

func Open

func Open(ctx context.Context, cfg Config) (*Trail, error)

Open connects to the installation the configuration names, or opens a trail that only logs when it names none.

A catalogue the installation refuses stops the start: the records it describes would be written against a description nobody accepted. An installation that cannot be reached does not: the records wait in the emitter's queue, in memory, and registration is tried again until it succeeds -- or is refused, which is Config.OnFatal's to act on.

func (*Trail) Close

func (t *Trail) Close() error

Close stops retrying registration and closes the emitter, which delivers what its queue holds within its timeout; what it cannot is dropped, and said to be. The queue is in memory: nothing survives the process.

func (*Trail) Connected

func (t *Trail) Connected() bool

Connected reports whether records reach an installation.

func (*Trail) Flush added in v1.58.0

func (t *Trail) Flush(ctx context.Context) error

Flush returns once the emitter holds no record waiting for delivery, or ctx is done. A Lambda handler calls it before returning, because the process is frozen afterwards and what is still in the in-memory queue may never be sent. It reports nothing when the trail keeps no queue.

func (*Trail) Record

func (t *Trail) Record(ctx context.Context, r *record.Record)

Record implements Recorder.

func (*Trail) RecordDurable

func (t *Trail) RecordDurable(ctx context.Context, r *record.Record) error

RecordDurable implements Recorder: it returns once the record is kept, or with the reason it could not be. That is the catalogue's `block` delivery, and only an action declared so is accepted here -- for an async action the emitter returns at enqueue, and a caller that waited for durability would have been told a lie.

Without an installation there is nothing to wait for, and it answers nil: refusing a recovery sign-in on a deployment that chose to keep no trail would make recovery impossible by configuration.

Directories

Path Synopsis
Package audittest is a recorder a test can read back.
Package audittest is a recorder a test can read back.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL