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
- func AccessExplained(actor Actor, o Outcome, subjectKind, subjectID string, ...) *record.Record
- func BackupCompleted(actor Actor, id string, b BackupRun) *record.Record
- func BackupFailed(actor Actor, id string, b BackupRun, detail string) *record.Record
- func BackupPruned(actor Actor, removed, orphans []string, kept int, rule string) *record.Record
- func CatalogueAppCreated(actor Actor, org string, app App) *record.Record
- func CatalogueAppDisconnected(actor Actor, org string, app App, uninstalled bool, reason string) *record.Record
- func CatalogueAppInstalled(actor Actor, org string, app App, installation int64) *record.Record
- func CatalogueAppWebhookChanged(actor Actor, org string, app App, step string, o Outcome) *record.Record
- func ClientSecretAdopted(client, source string, created time.Time) *record.Record
- func ClientSecretCreated(client string, created time.Time) *record.Record
- func ClientSecretDeleted(actor Actor, client string) *record.Record
- func ClientSecretDenied(actor Actor, client, action, reason string, overlap *int64) *record.Record
- func ClientSecretOrphaned(client string, orphaned time.Time) *record.Record
- func ClientSecretRotated(actor Actor, client string, rotated time.Time, overlap time.Duration, ...) *record.Record
- func CloudflareTokenMinted(actor Actor, preset string, t CloudflareToken) *record.Record
- func CloudflareTokenRefused(actor Actor, preset, variant, reason, detail string, denied bool) *record.Record
- func CloudflareTokenRevoked(actor Actor, preset, account, tokenID string) *record.Record
- func CloudflareTokensSwept(preset, account string, ids []string) *record.Record
- func DirectoryUserID(address string) string
- func GitHubAppCreated(actor Actor, org string, app App) *record.Record
- func GitHubLinkCreated(person, login string) *record.Record
- func GitHubLinkImported(actor Actor, person, login, reason string) *record.Record
- func GitHubLinkLost(person, login, reason string) *record.Record
- func GitHubLinkMatched(person, login, reason string) *record.Record
- func GitHubLinkMoved(person, login, reason string) *record.Record
- func GitHubLinkNarrowed(person, login, reason string) *record.Record
- func GitHubLinkUnverifiable(person, login, reason string) *record.Record
- func GitHubMemberAdded(m Member, o Outcome) *record.Record
- func GitHubMemberHeld(m Member, change, reason string) *record.Record
- func GitHubMemberInvited(m Member, o Outcome) *record.Record
- func GitHubMemberRemoved(m Member, o Outcome) *record.Record
- func GitHubMemberRoleSet(m Member, o Outcome) *record.Record
- func GitHubOrgConnected(actor Actor, org string, app, installation int64, owner string) *record.Record
- func GitHubOrgDisconnected(actor Actor, org string, uninstalled bool, reason string) *record.Record
- func GitHubOrgOwnerChanged(actor Actor, org, from, to string) *record.Record
- func GitHubOwnerReported(m Member, change, reason string) *record.Record
- func GitHubPassRequested(actor Actor, org string) *record.Record
- func GitHubRemovalsConfirmed(actor Actor, org, fingerprint string, affected, members int) *record.Record
- func GitHubTokenMinted(actor Actor, app string, t GitHubToken, o Outcome) *record.Record
- func LinkAppConnected(actor Actor, app App, owner string) *record.Record
- func LinkAppDisconnected(actor Actor, app App, invalidated int) *record.Record
- func MaintenanceChanged(actor Actor, m Maintenance) *record.Record
- func MaintenanceFailed(actor Actor, m Maintenance, detail string) *record.Record
- func MigrationCopied(actor Actor, c MigrationCopy, o Outcome) *record.Record
- func OnLambda() bool
- func RecoverySignedIn(actor Actor, client, how string, o Outcome) *record.Record
- func RestoreCompleted(actor Actor, backupID string, r Restore) *record.Record
- func RestoreFailed(actor Actor, backupID string, r Restore, detail string) *record.Record
- func RestoreStarted(actor Actor, backupID string, r Restore) *record.Record
- func RunnerAppCreated(actor Actor, org string, app App) *record.Record
- func RunnerAppDisconnected(actor Actor, org string, app App, uninstalled bool, reason string) *record.Record
- func RunnerAppInstalled(actor Actor, org string, app App, installation int64) *record.Record
- func SecretsPruned(actor Actor, p SecretsPrune, o Outcome) *record.Record
- func SecretsRekeyed(actor Actor, r SecretsRekey, o Outcome) *record.Record
- func SessionEnded(actor Actor, ended int, spared []string) *record.Record
- func SessionRefreshRefused(person, client, reason string) *record.Record
- func SessionReuseRevoked(person, client string) *record.Record
- func SessionRevoked(actor Actor, person, client, scope string, ended int) *record.Record
- func SessionsRevokedByClass(actor Actor, person, scope string, ended int, endedClass, keptClass string) *record.Record
- func SignInRefused(actor Actor, client, how string, recovery bool, o Outcome, why Refusal) *record.Record
- func SignedIn(actor Actor, client, how string, o Outcome) *record.Record
- func SignedInSession(actor Actor, client, how, class string, deadline time.Time, o Outcome) *record.Record
- func SlackActionHeld(workspace string, channel *SlackChannel, m *SlackMember, change, reason string) *record.Record
- func SlackCatalogueAppCreated(actor Actor, a SlackCatalogueApp) *record.Record
- func SlackCatalogueAppInstallRefused(actor Actor, a SlackCatalogueApp, reason string) *record.Record
- func SlackCatalogueAppInstalled(actor Actor, a SlackCatalogueApp) *record.Record
- func SlackChannelAdopted(c SlackChannel, o Outcome) *record.Record
- func SlackChannelArchived(actor Actor, c SlackChannel, o Outcome) *record.Record
- func SlackChannelCreated(c SlackChannel, o Outcome) *record.Record
- func SlackConsoleChannelCreated(actor Actor, c SlackConsoleChannel) *record.Record
- func SlackConsoleChannelDeleted(actor Actor, c SlackConsoleChannel) *record.Record
- func SlackConsoleChannelUpdated(actor Actor, c SlackConsoleChannel, changes string) *record.Record
- func SlackLeaverReported(workspace, person, user, reason string) *record.Record
- func SlackMemberInvited(m SlackMember, o Outcome) *record.Record
- func SlackMemberRemoved(m SlackMember, o Outcome) *record.Record
- func SlackRemovalsConfirmed(actor Actor, workspace, channel, fingerprint string, affected int) *record.Record
- func SlackSharedAccepted(s SlackShared, o Outcome) *record.Record
- func SlackSharedChannelCreated(actor Actor, c SlackSharedChannel) *record.Record
- func SlackSharedChannelDeleted(actor Actor, c SlackSharedChannel) *record.Record
- func SlackSharedChannelUpdated(actor Actor, c SlackSharedChannel, changes string) *record.Record
- func SlackSharedInvited(s SlackShared, o Outcome) *record.Record
- func SlackWorkspaceConnectRefused(actor Actor, w SlackWorkspace, reason string) *record.Record
- func SlackWorkspaceConnected(actor Actor, w SlackWorkspace) *record.Record
- func SlackWorkspaceDisconnected(actor Actor, w SlackWorkspace, revoked bool, reason string) *record.Record
- func SlackWorkspaceOwnerChanged(actor Actor, key, from, to string) *record.Record
- func TokenExchangeRefused(actor Actor, audience, proof string, o Outcome, why Refusal) *record.Record
- func TokenExchanged(actor Actor, audience, proof string, o Outcome) *record.Record
- func Verify(cfg Config) error
- func WorkspaceConnected(actor Actor, workspace, backend, via string) *record.Record
- func WorkspaceDisconnected(actor Actor, workspace string) *record.Record
- func WorkspaceDomainsChanged(actor Actor, workspace string, domains []string) *record.Record
- func WorkspaceGroupsChanged(actor Actor, workspace string, groups int) *record.Record
- func WorkspaceReconnected(actor Actor, workspace, backend, via string) *record.Record
- type Actor
- type App
- type BackupRun
- type CloudflareToken
- type Config
- type Document
- type GitHubToken
- type Maintenance
- type Member
- type MigrationCopy
- type Outcome
- type Recorder
- type Refusal
- type Restore
- type SQSAPI
- type SQSConfig
- type SecretsPrune
- type SecretsRekey
- type SlackCatalogueApp
- type SlackChannel
- type SlackConsoleChannel
- type SlackMember
- type SlackShared
- type SlackSharedChannel
- type SlackWorkspace
- type Trail
Constants ¶
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.
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.
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).
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.
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.
const MaintenanceCleared = "cleared"
MaintenanceCleared is Maintenance.State of a flag that was lifted.
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.
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.
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.
const Source = "roster"
Source is the catalogue's source: every action is under it.
const Tenant = record.TenantPlatform
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
BackupCompleted is a backup written and its manifest sealed.
func BackupFailed ¶ added in v1.75.0
BackupFailed is a backup that could not be completed.
func BackupPruned ¶ added in v1.75.0
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 ¶
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 ¶
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
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
ClientSecretCreated is the issuer making the secret of a generated client.
func ClientSecretDeleted ¶ added in v1.66.0
ClientSecretDeleted is somebody deleting the stored secret of a client that is no longer in the policy.
func ClientSecretDenied ¶ added in v1.66.0
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
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
CloudflareTokenRevoked is somebody deleting a live token of a preset.
func CloudflareTokensSwept ¶ added in v1.74.0
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
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 ¶
GitHubAppCreated is the organisation App created for an organisation.
func GitHubLinkCreated ¶
GitHubLinkCreated is a person linking their own GitHub account.
func GitHubLinkImported ¶
GitHubLinkImported is an operator importing a link.
func GitHubLinkLost ¶
GitHubLinkLost is a link lost.
func GitHubLinkMatched ¶
GitHubLinkMatched is an account linked because its profile publishes the person's work address.
func GitHubLinkMoved ¶
GitHubLinkMoved is a link moved to another address of the same person.
func GitHubLinkNarrowed ¶
GitHubLinkNarrowed is a link that lost some of its addresses.
func GitHubLinkUnverifiable ¶
GitHubLinkUnverifiable is a link that can no longer be verified.
func GitHubMemberAdded ¶
GitHubMemberAdded is a person added to a team.
func GitHubMemberHeld ¶
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 ¶
GitHubMemberInvited is a person invited to an organisation or team.
func GitHubMemberRemoved ¶
GitHubMemberRemoved is a person removed from an organisation or team.
func GitHubMemberRoleSet ¶
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 ¶
GitHubOrgDisconnected is an organisation disconnected; reason is what the disconnect had to say, if anything.
func GitHubOrgOwnerChanged ¶
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 ¶
GitHubOwnerReported is an organisation owner reported rather than removed.
func GitHubPassRequested ¶
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 ¶
GitHubTokenMinted is one installation token request, minted or refused.
func LinkAppConnected ¶
LinkAppConnected is the account-linking App connected.
func LinkAppDisconnected ¶
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 ¶
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
RestoreCompleted is a restore that verified.
func RestoreFailed ¶ added in v1.75.0
RestoreFailed is a restore that did not complete or did not verify.
func RestoreStarted ¶ added in v1.75.0
RestoreStarted is a restore beginning.
func RunnerAppCreated ¶
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 ¶
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 ¶
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 ¶
SessionRefreshRefused is a session refused a refresh.
func SessionReuseRevoked ¶ added in v1.67.0
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 ¶
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 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 ¶
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 ¶
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 ¶
TokenExchanged is a token exchange for one client, by the kind of proof presented.
func Verify ¶ added in v1.76.0
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 ¶
WorkspaceConnected is a directory connected, by consent or by key.
func WorkspaceDisconnected ¶
WorkspaceDisconnected is a directory disconnected.
func WorkspaceDomainsChanged ¶
WorkspaceDomainsChanged is a change to the domains a directory answers for. No domains means every domain the tenant owns.
func WorkspaceGroupsChanged ¶
WorkspaceGroupsChanged is a change to the groups served from a directory.
Types ¶
type Actor ¶
Actor is who acted.
func Identified ¶
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 RecoveryIdentity ¶
RecoveryIdentity is whoever signed in by recovery, by the identity it completes as.
type App ¶
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
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.
type Document ¶
Document is the catalogue as it is registered: the YAML document and every schema it references, keyed by $id.
func Catalogue ¶
Catalogue loads the embedded catalogue, validated by the same toolchain the installation validates it with.
func LoadDocument ¶
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 ¶
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.
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 ¶
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 ¶
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 {
}
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 {
// an address is an identifier and never data.
Sources []string
// too, never data.
Members []string
Private bool
// 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 ¶
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 ¶
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) Flush ¶ added in v1.58.0
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) RecordDurable ¶
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.