Help us shape the future of Go! Take the 2026 Go Developer Survey

tools

package
v0.6.0 Latest Latest
Warning

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

Go to latest
Published: Oct 24, 2026 License: Apache-2.0 Imports: 36 Imported by: 0

Documentation

Overview

Package tools defines tailkeeper's tools. M1 contains the read tools for the Tailscale API and the node's local CLI (spec §6, §18).

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func CheckPatchSubjects added in v0.6.0

func CheckPatchSubjects(env *registry.Env, patch []byte) error

CheckPatchSubjects applies the subject rule to RFC 6902 patch operations given over MCP: the whole patch is read as one HuJSON document, and no string in it, outside comments, key or value, in a path, a from or a value, in any operation, may be a user login. The errors are those of CheckProposalSubjects, and the pointers are those of the patch (/2/value/src/0 is the third operation's value). Whether the text is a well-formed patch is for hujson.Patch to say when the patch is applied.

Check the exact bytes you will send, and check them before you replace a pseudonym by the login it names: the text after the replacement holds a literal login by design.

func CheckProposalSubjects added in v0.6.0

func CheckProposalSubjects(env *registry.Env, text string) error

CheckProposalSubjects applies the subject rule to a policy text given over MCP: while masking is on, no string of it, outside comments, key or value, may be a user login. It is nil when the rule holds or personalData is show, filter_refused naming the JSON pointers when it does not, and validation_failed when the text nests deeper than 1,000 levels or is not valid HuJSON (it is never a pass for text it could not read).

Check the exact bytes you will send, and check them before you replace a pseudonym by the login it names: the text after the replacement holds a literal login by design.

func IsLiteralLogin added in v0.6.0

func IsLiteralLogin(s string) bool

IsLiteralLogin reports whether s holds a user login as the masker reads one: the masker would change it, unless it is one of the three forms that are not logins. A masked value carrying a pseudonym is not a literal login, and neither is a synced group's name.

func Register

func Register(r *registry.Registry)

Register adds every M1 tool to r.

func SubstituteSubjects added in v0.6.0

func SubstituteSubjects(ctx context.Context, r *SubjectResolver, text []byte) (out []byte, replaced int, err error)

SubstituteSubjects replaces each pseudonym carrier in text (a policy, or the operations of a patch, as HuJSON; keys and values, never comments) by the login it names, keeping every other byte, and returns how many strings it replaced. A carrier is a string that is exactly "p:xxxxxxxxxx", "[p:xxxxxxxxxx]", or "<masked address> [p:xxxxxxxxxx]" where the masked address contains "…@". A string that holds a pseudonym marker and is none of these, a pseudonym in a patch's path or from, more than maxSubjects distinct pseudonyms, a text whose strings or comments do not end, and a pseudonym that resolves to zero or several users are validation_failed, and none of them sends a request for the users unless the text was fine up to the lookup. When nothing is replaced the result is a copy of text.

Run CheckProposalSubjects or CheckPatchSubjects on the same bytes first: the output holds literal logins by design, and the subject rule would refuse it.

Types

type ACLChange added in v0.6.0

type ACLChange struct {
	Class      string          `json:"class" jsonschema:"defaults, testsReduced, widening, tailscaleWritten or semantic"`
	Op         string          `json:"op" jsonschema:"added, removed or changed"`
	Section    string          `` /* 162-byte string literal not displayed */
	Entry      string          `json:"entry,omitempty" tk:"untrusted,emails" jsonschema:"the entry's key, or a summary of the rule or assertion"`
	Old        string          `json:"old,omitempty" tk:"untrusted,emails" jsonschema:"the entry on the old side, in canonical form"`
	New        string          `json:"new,omitempty" tk:"untrusted,emails" jsonschema:"the entry on the new side, in canonical form"`
	Truncated  bool            `json:"truncated,omitempty" jsonschema:"old or new was cut at 1 KiB"`
	OldCount   int             `json:"oldCount,omitempty" jsonschema:"how many times a repeated entry (a test) is on the old side"`
	NewCount   int             `json:"newCount,omitempty"`
	Fields     []ACLFieldDelta `json:"fields,omitempty" jsonschema:"what a changed entry gained and lost, field by field"`
	Note       string          `` /* 140-byte string literal not displayed */
	OldPointer string          `json:"oldPointer,omitempty" tk:"untrusted,emails" jsonschema:"JSON pointer into the old side"`
	NewPointer string          `json:"newPointer,omitempty" tk:"untrusted,emails" jsonschema:"JSON pointer into the new side"`
	OldLine    int             `json:"oldLine,omitempty" jsonschema:"in the old side's text, from 1"`
	NewLine    int             `` /* 131-byte string literal not displayed */
}

ACLChange is one difference. Entry, Old and New are cut at 1 KiB each by the engine, so that one element is never a blob and a page is bounded.

type ACLChangeCounts added in v0.6.0

type ACLChangeCounts struct {
	Defaults         int `json:"defaults"`
	TestsReduced     int `json:"testsReduced"`
	Widening         int `json:"widening"`
	TailscaleWritten int `json:"tailscaleWritten"`
	Semantic         int `json:"semantic"`
	CommentOnly      int `json:"commentOnly"`
	FormatOnly       int `json:"formatOnly"`
}

ACLChangeCounts are the differences between the validated text and the live policy, by class.

type ACLDiffInput added in v0.6.0

type ACLDiffInput struct {
	Policy                 string `` /* 192-byte string literal not displayed */
	Patch                  string `` /* 210-byte string literal not displayed */
	Against                string `` /* 161-byte string literal not displayed */
	FromVersion            string `json:"fromVersion,omitempty" tk:"short" jsonschema:"the old side is the policy of this version id from acl_history"`
	ToVersion              string `json:"toVersion,omitempty" tk:"short" jsonschema:"the new side is the policy of this version id from acl_history"`
	Section                string `` /* 169-byte string literal not displayed */
	FromChange             string `` /* 135-byte string literal not displayed */
	IgnoreTailscaleWritten bool   `` /* 154-byte string literal not displayed */
	Offline                bool   `` /* 131-byte string literal not displayed */
	Operator               bool   `json:"-" cli:"operator"`
}

ACLDiffInput says which two policies to compare, and which changes to list.

func (ACLDiffInput) Check added in v0.6.0

func (in ACLDiffInput) Check() error

Check refuses a policy and a patch together, a version and a text for the same side, and a section that is no section, before anything is read. That both sides are the live policy is told by the tool, since on the command line the files are not read yet.

func (ACLDiffInput) RunsOffline added in v0.6.0

func (in ACLDiffInput) RunsOffline(g registry.Given) bool

RunsOffline says that two files, or --offline, need no credential. --offline with a live side is refused by the tool, which says so.

type ACLDiffOutput added in v0.6.0

type ACLDiffOutput struct {
	Status            string          `json:"status" jsonschema:"equal, changed or invalid (a side is not a policy, and nothing was compared)"`
	SemanticallyEqual bool            `` /* 175-byte string literal not displayed */
	Old               ACLDiffSide     `json:"old"`
	New               ACLDiffSide     `json:"new"`
	Counts            ACLChangeCounts `json:"counts" jsonschema:"the changes of every page, by class; commentOnly and formatOnly are counts only"`
	Changes           []ACLChange     `json:"changes,omitempty" jsonschema:"one page of the changes, defaults, testsReduced and widening first"`
	Section           string          `` /* 172-byte string literal not displayed */
	Matched           int             `json:"matched" jsonschema:"the changes the section filter and the options select, over every page"`
	Truncated         bool            `json:"truncated" jsonschema:"more changes follow this page: call again with fromChange set to nextChange"`
	NextChange        string          `json:"nextChange,omitempty"`
	NormalFormLimits  []string        `json:"normalFormLimits,omitempty" jsonschema:"why a changed may be false"`
	NotChecked        []string        `json:"notChecked" jsonschema:"what a comparison does not establish: a small change to an alias or a group can widen access"`

	TailscaleWrittenAsOf    string `json:"tailscaleWrittenAsOf" jsonschema:"the date of the list of constructs Tailscale writes itself"`
	TailscaleWrittenIgnored bool   `` /* 148-byte string literal not displayed */

	ExternallyManaged     string `` /* 153-byte string literal not displayed */
	ExternalLink          string `json:"externalLink,omitempty" tk:"untrusted,plain"`
	ExternallyManagedNote string `json:"externallyManagedNote,omitempty" jsonschema:"why it is unknown"`
	CheckedAt             string `json:"checkedAt"`
}

ACLDiffOutput is the comparison. An invalid side is a typed result too (status invalid, exit 2) with its findings under the side, so that a hostile name is redacted by the registry and not withheld with the rest.

func (ACLDiffOutput) ExitCode added in v0.6.0

func (o ACLDiffOutput) ExitCode() int

ExitCode comes from the status alone: equal and changed 0, invalid 2, and a status this version does not know 1. The status is the engine's verdict on the whole normal forms, never a reading of the page or of the filter: a section that selects nothing, or a cursor past the last change, leaves the status changed.

func (ACLDiffOutput) FailOnKinds added in v0.6.0

func (ACLDiffOutput) FailOnKinds() []string

FailOnKinds: acl_diff computes four kinds; it has no warnings to count.

func (ACLDiffOutput) Findings added in v0.6.0

func (o ACLDiffOutput) Findings() registry.Findings

Findings counts what --fail-on can gate, over every change and not the page. The kind change fires for any of the five classes: a gate named change that stays silent for a widening or a removed test is the unsafe direction. The Tailscale-written class counts unless the caller asked to ignore it.

func (ACLDiffOutput) Report added in v0.6.0

func (o ACLDiffOutput) Report() registry.Report

Report is the human layout: the verdict line, what was not checked, the counts by class, then the findings of each side and the changes of the page, each behind a location. The strings are the registry's, already escaped and masked; a line that quotes a policy is the owner's own text and is not marked as Tailscale's.

type ACLDiffSide added in v0.6.0

type ACLDiffSide struct {
	Source        string       `` /* 174-byte string literal not displayed */
	Version       string       `json:"version,omitempty" jsonschema:"the version id, when source is version"`
	PolicyVersion string       `` /* 145-byte string literal not displayed */
	PolicySHA256  string       `json:"policySha256,omitempty" jsonschema:"SHA-256 of the policy as acl_get shows it"`
	Findings      []ACLProblem `` /* 164-byte string literal not displayed */
	Omitted       int          `json:"omitted,omitempty" jsonschema:"findings left out past the cap"`
}

ACLDiffSide describes one side of the comparison.

type ACLFieldDelta added in v0.6.0

type ACLFieldDelta struct {
	Field       string   `json:"field" tk:"untrusted,emails"`
	Added       []string `json:"added,omitempty" tk:"untrusted,emails"`
	Removed     []string `json:"removed,omitempty" tk:"untrusted,emails"`
	AddedMore   int      `json:"addedMore,omitempty" jsonschema:"gained, not listed"`
	RemovedMore int      `json:"removedMore,omitempty" jsonschema:"lost, not listed"`
}

ACLFieldDelta is what a changed entry gained and lost in one field.

type ACLGetInput

type ACLGetInput struct {
	FromLine int    `json:"fromLine,omitempty" jsonschema:"first line of the page, from 1 (default 1); use nextLine from the previous page"`
	MaxBytes int    `` /* 212-byte string literal not displayed */
	View     string `` /* 155-byte string literal not displayed */
}

ACLGetInput selects a page of the policy, or the summary.

func (ACLGetInput) Check added in v0.6.0

func (in ACLGetInput) Check() error

Check refuses a page that cannot exist, before anything is sent. Zero means the default.

type ACLGetOutput

type ACLGetOutput struct {
	Policy                string      `` /* 255-byte string literal not displayed */
	FromLine              int         `json:"fromLine" jsonschema:"first line of this page; 0 in the summary"`
	ToLine                int         `json:"toLine" jsonschema:"last line of this page; 0 in the summary"`
	Lines                 int         `json:"lines" jsonschema:"lines in the whole policy"`
	NextLine              int         `json:"nextLine" jsonschema:"fromLine of the next page; 0 on the last page"`
	Truncated             bool        `json:"truncated" jsonschema:"more lines follow this page"`
	Masked                bool        `json:"masked" jsonschema:"email addresses on this page were masked (in the summary: anywhere in the policy)"`
	Bytes                 int         `` /* 176-byte string literal not displayed */
	SHA256                string      `json:"sha256" jsonschema:"SHA-256 of the whole policy, of the same bytes as bytes"`
	ETag                  string      `` /* 147-byte string literal not displayed */
	PolicyVersion         string      `` /* 153-byte string literal not displayed */
	PolicySHA256          string      `json:"policySha256" jsonschema:"the same value as sha256"`
	CheckedAt             string      `json:"checkedAt" jsonschema:"when the policy was read: RFC 3339, in UTC"`
	Warnings              []string    `` /* 160-byte string literal not displayed */
	ServerErrors          []string    `` /* 166-byte string literal not displayed */
	Summary               *ACLSummary `json:"summary,omitempty" tk:"details" jsonschema:"the policy at a glance; view summary only"`
	ExternallyManaged     string      `` /* 140-byte string literal not displayed */
	ExternalLink          string      `json:"externalLink,omitempty" tk:"untrusted,plain"`
	ExternallyManagedNote string      `json:"externallyManagedNote,omitempty" jsonschema:"why externallyManaged is unknown"`
}

ACLGetOutput is a page of the policy, or its summary, and facts about the whole file.

func (ACLGetOutput) Block

func (o ACLGetOutput) Block() (int, string)

Block lets the CLI print the page as a document: these fields first, then the policy lines with their numbers.

func (ACLGetOutput) Details added in v0.6.0

func (o ACLGetOutput) Details() []string

Details lets the CLI print the warnings, the stored errors and the summary one to a line, each behind a notice that the text is not tailkeeper's.

type ACLHistoryInput added in v0.6.0

type ACLHistoryInput struct {
	Start  string `` /* 126-byte string literal not displayed */
	End    string `json:"end,omitempty" tk:"short" jsonschema:"RFC 3339 end (default now)"`
	Limit  int    `json:"limit,omitempty" jsonschema:"page size, 1-200 (default 50)"`
	Cursor string `json:"cursor,omitempty" tk:"short" jsonschema:"nextCursor of the previous page; it fixes the window, so omit start and end"`
}

ACLHistoryInput selects policy versions from the configuration audit log. The log has no pagination: tailkeeper reads the window in slices and pages over what came back.

func (ACLHistoryInput) Check added in v0.6.0

func (in ACLHistoryInput) Check() error

Check refuses a limit out of range, a cursor given with a window or that no page issued, and a window longer than 90 days, before anything is sent.

type ACLHistoryOutput added in v0.6.0

type ACLHistoryOutput struct {
	Versions    []ACLVersion `json:"versions" tk:"rows"`
	Count       int          `json:"count"`
	WindowStart string       `json:"windowStart"`
	WindowEnd   string       `json:"windowEnd"`
	NextCursor  string       `json:"nextCursor,omitempty"`
	Skipped     int          `json:"skipped,omitempty"`
	Note        string       `json:"note"`
}

ACLHistoryOutput is one page of policy versions, oldest first.

type ACLProblem added in v0.6.0

type ACLProblem struct {
	Kind           string `json:"kind" jsonschema:"the kind of finding, as the tool's description lists"`
	Severity       string `json:"severity" jsonschema:"error, warning or notice"`
	Source         string `` /* 193-byte string literal not displayed */
	Line           int    `json:"line,omitempty" jsonschema:"from 1, counting line feeds as Tailscale does; absent when unknown"`
	Column         int    `json:"column,omitempty" jsonschema:"in bytes, from 1"`
	Pointer        string `json:"pointer,omitempty" tk:"untrusted,emails" jsonschema:"JSON pointer, when the line is not known"`
	Message        string `json:"message" tk:"untrusted,emails"`
	FromTailscale  bool   `json:"fromTailscale" jsonschema:"Tailscale's own text"`
	MoreCandidates int    `json:"moreCandidates,omitempty" jsonschema:"more places match, past the cap"`
}

ACLProblem is one thing a validation found, placed in the text it is about. Line and Column are counted as Tailscale counts them: lines by line feed, columns in bytes.

type ACLSSHTestInput added in v0.6.0

type ACLSSHTestInput struct {
	Dst    []string `json:"dst" jsonschema:"destinations of this SSH test, with no port (tag:prod, 100.64.0.5)"`
	Accept []string `json:"accept,omitempty" jsonschema:"SSH users that must be accepted"`
	Check  []string `json:"check,omitempty" jsonschema:"SSH users that must be checked"`
	Deny   []string `json:"deny,omitempty" jsonschema:"SSH users that must be denied"`
}

ACLSSHTestInput is one SSH test: destinations and the users that must be accepted, checked or denied. The source is the call's src, not a field of this struct.

type ACLSSHVerdict added in v0.6.0

type ACLSSHVerdict struct {
	Dst     string `json:"dst" tk:"untrusted,emails" jsonschema:"the destination as the caller wrote it"`
	User    string `json:"user" tk:"untrusted,emails" jsonschema:"the SSH user as the caller wrote it"`
	Expect  string `json:"expect" jsonschema:"accept, check or deny"`
	Verdict string `json:"verdict" jsonschema:"allowed, denied, unresolved or unknown"`
	Why     string `json:"why,omitempty" jsonschema:"a fixed sentence, when the line alone is not the whole reason"`
}

ACLSSHVerdict is what the reply says about one SSH user on one destination, as the caller wrote them. Expect is accept, check or deny. Verdict is allowed, denied, unresolved or unknown. Why, when set, is one of sshVerdictReasons.

type ACLSectionRow added in v0.6.0

type ACLSectionRow struct {
	Name   string `json:"name" tk:"untrusted,emails" jsonschema:"section name"`
	Known  bool   `json:"known" jsonschema:"this version knows the section"`
	State  string `json:"state" jsonschema:"absent, empty or non-empty"`
	Count  int    `json:"count" jsonschema:"elements or entries; 1 for a value"`
	Scalar string `json:"scalar,omitempty" tk:"untrusted,emails" jsonschema:"the value of a scalar section"`
}

ACLSectionRow is one section of a policy at a glance.

type ACLSummary added in v0.6.0

type ACLSummary struct {
	Sections       []ACLSectionRow `json:"sections" jsonschema:"every section: those this version knows in table order, then the others by name"`
	Groups         []string        `json:"groups,omitempty" tk:"untrusted,emails" jsonschema:"names defined in groups, sorted"`
	TagOwners      []string        `json:"tagOwners,omitempty" tk:"untrusted,emails" jsonschema:"tags in tagOwners, sorted"`
	Hosts          []string        `json:"hosts,omitempty" tk:"untrusted,emails" jsonschema:"host aliases, sorted"`
	Postures       []string        `json:"postures,omitempty" tk:"untrusted,emails" jsonschema:"posture names, sorted"`
	IPSets         []string        `json:"ipsets,omitempty" tk:"untrusted,emails" jsonschema:"ipset names, sorted"`
	SyncedGroups   []string        `` /* 153-byte string literal not displayed */
	NamesTruncated bool            `json:"namesTruncated" jsonschema:"a list was cut: at 100 names, or to fit the result"`
	Tests          int             `json:"tests" jsonschema:"elements of tests"`
	SSHTests       int             `json:"sshTests" jsonschema:"elements of sshTests"`
	Unknown        []string        `json:"unknown,omitempty" tk:"untrusted,emails" jsonschema:"sections this version does not know"`
	NamesDigest    string          `json:"namesDigest,omitempty" jsonschema:"keyed digest of the names; needs a privacy key"`
	SemanticDigest string          `` /* 156-byte string literal not displayed */
}

ACLSummary is a policy at a glance: what it holds and what it defines, without its rules.

type ACLTestInput

type ACLTestInput struct {
	Src             string            `` /* 170-byte string literal not displayed */
	Accept          []string          `` /* 132-byte string literal not displayed */
	Deny            []string          `json:"deny,omitempty" jsonschema:"destinations src must not reach, as host:port"`
	Proto           string            `` /* 190-byte string literal not displayed */
	SrcPostureAttrs map[string]any    `` /* 300-byte string literal not displayed */
	SSH             []ACLSSHTestInput `` /* 175-byte string literal not displayed */
}

ACLTestInput is one test: a source and the destinations it must or must not reach.

func (ACLTestInput) Check added in v0.6.0

func (in ACLTestInput) Check() error

Check refuses a test that is malformed or has nothing to test, before anything is sent.

type ACLTestOutput

type ACLTestOutput struct {
	Status         string           `` /* 195-byte string literal not displayed */
	Verdicts       []ACLTestVerdict `json:"verdicts,omitempty"`
	SSHVerdicts    []ACLSSHVerdict  `json:"sshVerdicts,omitempty"`
	Omitted        int              `` /* 140-byte string literal not displayed */
	SSHNotAsked    int              `` /* 130-byte string literal not displayed */
	SSHError       string           `` /* 199-byte string literal not displayed */
	OmittedLines   int              `` /* 174-byte string literal not displayed */
	Failures       []ACLTestResult  `json:"failures,omitempty" tk:"details"`
	Unmatched      []string         `json:"unmatched,omitempty" tk:"untrusted,emails,details"`
	OtherTests     []ACLTestResult  `json:"otherTests,omitempty" tk:"details"`
	Warnings       []string         `json:"warnings,omitempty" tk:"untrusted,emails,details"`
	Posture        string           `` /* 141-byte string literal not displayed */
	PosturesNeeded []string         `json:"posturesNeeded,omitempty" tk:"untrusted,emails" jsonschema:"the posture attributes the live policy names"`
	PostureNote    string           `` /* 141-byte string literal not displayed */
	Caveats        []string         `json:"caveats,omitempty" jsonschema:"fixed sentences about how a verdict was read"`
	EvaluatedAt    string           `json:"evaluatedAt"`
	Note           string           `json:"note"`
}

ACLTestOutput is the live policy's answer for the posted source.

func (ACLTestOutput) ExitCode

func (o ACLTestOutput) ExitCode() int

ExitCode is 0 for a pass, 1 for unknown or a status this version does not know, 2 for unresolved and 9 for a failed assertion.

func (ACLTestOutput) Report added in v0.6.0

func (o ACLTestOutput) Report() registry.Report

Report is the human layout: one verdict line, the facts the result states under their labels, what it did not check, then Tailscale's lines behind the notice the layout prints for untrusted findings.

type ACLTestResult

type ACLTestResult struct {
	Src    string   `json:"src" tk:"untrusted,emails"`
	Errors []string `json:"errors" tk:"untrusted,emails"`
}

ACLTestResult is Tailscale's reasons for one source.

type ACLTestVerdict added in v0.6.0

type ACLTestVerdict struct {
	Dst       string   `json:"dst" tk:"untrusted,emails" jsonschema:"the destination as the caller wrote it"`
	Expect    string   `json:"expect" jsonschema:"accept, deny or accept+deny"`
	Verdict   string   `json:"verdict" jsonschema:"allowed, denied, unresolved or unknown"`
	Why       string   `json:"why,omitempty" jsonschema:"a fixed sentence, when the line alone is not the whole reason"`
	Protocols []string `json:"protocols,omitempty" tk:"untrusted" jsonschema:"the protocol names of the lines that speak for this destination"`
}

ACLTestVerdict is what the reply says about one destination, as the caller wrote it.

type ACLValidateInput added in v0.6.0

type ACLValidateInput struct {
	Policy       string `` /* 180-byte string literal not displayed */
	Patch        string `` /* 194-byte string literal not displayed */
	Invariants   string `` /* 178-byte string literal not displayed */
	NoInvariants bool   `json:"-" cli:"bool:no-invariants" jsonschema:"do not check the configured invariants"`
	Offline      bool   `` /* 206-byte string literal not displayed */
	Operator     bool   `json:"-" cli:"operator"`
}

ACLValidateInput is a proposal to validate.

func (ACLValidateInput) Check added in v0.6.0

func (in ACLValidateInput) Check() error

Check refuses a policy and a patch together, before anything is sent: the policy is the whole proposal, and the patch is a change to the live policy. On the command line the two flags are one group, and the binder refuses both before this runs.

func (ACLValidateInput) RunsOffline added in v0.6.0

func (in ACLValidateInput) RunsOffline(g registry.Given) bool

RunsOffline says that --offline needs no credential.

type ACLValidateOutput added in v0.6.0

type ACLValidateOutput struct {
	Status        string       `` /* 248-byte string literal not displayed */
	ServerChecked bool         `json:"serverChecked" jsonschema:"false: the text was not sent to Tailscale, so a pass is a local one"`
	Errors        []ACLProblem `json:"errors,omitempty" jsonschema:"what made the status what it is, placed in the text where possible"`
	Notices       []ACLProblem `json:"notices,omitempty" jsonschema:"remarks that change no status"`
	// NewWarnings are the warnings the text adds to the live policy's own; ExistingWarnings
	// are the ones the live policy already has. A warning is existing only when it matches one
	// stored with the live policy word for word (see warnings in acl_validate_online.go), so
	// the doubt falls on the side of a gate: a warning worded differently reads as new.
	NewWarnings      []ACLProblem `` /* 208-byte string literal not displayed */
	ExistingWarnings []ACLProblem `json:"existingWarnings,omitempty" jsonschema:"warnings the live policy already has"`
	// NewWarningsOmitted counts the new warnings that NewWarnings does not list, past the caps
	// on what a reply and a result carry; they are part of Omitted, and --fail-on warnings
	// counts them.
	NewWarningsOmitted int      `` /* 143-byte string literal not displayed */
	ServerErrors       []string `json:"serverErrors,omitempty" tk:"untrusted,emails" jsonschema:"errors stored with the live policy"`
	Omitted            int      `json:"omitted,omitempty" jsonschema:"problems left out past the caps"`

	TestsBefore    int `json:"testsBefore" jsonschema:"in the live policy; 0 when not read"`
	TestsAfter     int `json:"testsAfter" jsonschema:"in the validated text"`
	SSHTestsBefore int `json:"sshTestsBefore"`
	SSHTestsAfter  int `json:"sshTestsAfter"`
	// Changes counts the differences from the live policy by class.
	Changes *ACLChangeCounts `json:"changes,omitempty" jsonschema:"differences from the live policy, by class"`

	InvariantsApplied   int      `json:"invariantsApplied" jsonschema:"invariant tests that ran; 0 means none"`
	InvariantsSignature string   `json:"invariantsSignature" jsonschema:"always none: unsigned"`
	NotChecked          []string `json:"notChecked" jsonschema:"what this does not establish"`
	DependsOnLiveState  bool     `json:"dependsOnLiveState" jsonschema:"the answer depends on the live policy"`

	PolicyVersion         string `` /* 145-byte string literal not displayed */
	PolicySHA256          string `json:"policySha256,omitempty" jsonschema:"SHA-256 of the live policy as acl_get shows it"`
	LiveChanged           bool   `json:"liveChanged" jsonschema:"the live policy changed during the check; never a pass"`
	ValidatedLive         bool   `` /* 162-byte string literal not displayed */
	IdenticalToLive       bool   `json:"identicalToLive" jsonschema:"the text is byte for byte the live policy"`
	CheckedAt             string `json:"checkedAt"`
	ExternallyManaged     string `json:"externallyManaged" jsonschema:"true, false or unknown: managed outside the admin console"`
	ExternalLink          string `json:"externalLink,omitempty" tk:"untrusted,plain"`
	ExternallyManagedNote string `json:"externallyManagedNote,omitempty" jsonschema:"why it is unknown"`
	PatchedBytes          int    `` /* 153-byte string literal not displayed */
	PatchedDigest         string `` /* 151-byte string literal not displayed */
	// contains filtered or unexported fields
}

ACLValidateOutput is the verdict on a proposal. Every verdict is a typed result, the invalid and rejected ones too, so that the registry redacts a hostile name instead of withholding the whole result; the exit code comes from Status alone.

func (ACLValidateOutput) ExitCode added in v0.6.0

func (o ACLValidateOutput) ExitCode() int

ExitCode comes from the verdict alone, never from message text: pass 0, unknown 1, invalid, rejected and unresolved 2, fail 9. A status this version does not know is unknown.

func (ACLValidateOutput) FailOnKinds added in v0.6.0

func (ACLValidateOutput) FailOnKinds() []string

FailOnKinds: acl_validate computes all five kinds.

func (ACLValidateOutput) Findings added in v0.6.0

func (o ACLValidateOutput) Findings() registry.Findings

Findings counts what --fail-on can gate. Every kind is computed over all the changes, not over a page of them. The kind change fires for any of the five classes, the Tailscale-written ones included, because a gate named change that stays silent for a widening is the unsafe direction.

func (ACLValidateOutput) OfflineFailOnKinds added in v0.6.0

func (ACLValidateOutput) OfflineFailOnKinds() []string

OfflineFailOnKinds: an offline check compares nothing with the live policy and sends nothing, so it computes none of the five kinds, and --fail-on is refused with --offline.

func (ACLValidateOutput) Report added in v0.6.0

func (o ACLValidateOutput) Report() registry.Report

Report is the human layout: the verdict line, what was not checked, the diff counts by class, then the problems, each behind a location. Tailscale's own words are marked untrusted so that the layout prints them behind a notice.

type ACLVersion added in v0.6.0

type ACLVersion struct {
	Version       string     `json:"version" tk:"col"`
	Previous      string     `json:"previous,omitempty" tk:"col"`
	EventTime     string     `json:"eventTime" tk:"col"`
	Origin        string     `json:"origin" tk:"col,untrusted"`
	Actor         AuditActor `json:"actor"`
	Bytes         int        `json:"bytes" tk:"col"`
	Digest        string     `json:"digest,omitempty"`
	PolicyVersion string     `json:"policyVersion,omitempty"`
	PolicySHA256  string     `json:"policySha256"`
}

ACLVersion is one policy the log recorded. The text itself is not here: a version id is how acl_diff asks for it. policyVersion and policySha256 describe the text as acl_get would show it, so neither is a hash of a login.

type Acceptor

type Acceptor struct {
	ID        int64  `json:"id"`
	LoginName string `json:"loginName" tk:"untrusted,personal"`
}

Acceptor is who accepted an invite.

type AuditActor

type AuditActor struct {
	ID          string   `json:"id,omitempty"`
	Type        string   `json:"type,omitempty"`
	LoginName   string   `json:"loginName,omitempty" tk:"untrusted,personal"`
	DisplayName string   `json:"displayName,omitempty" tk:"untrusted,personal"`
	Tags        []string `json:"tags,omitempty" tk:"untrusted"`
}

AuditActor is who made a change.

type AuditEntry

type AuditEntry struct {
	EventTime     string      `json:"eventTime" tk:"col"`
	DeferredAt    string      `json:"deferredAt,omitempty"`
	EventGroupID  string      `json:"eventGroupId,omitempty"`
	Origin        string      `json:"origin" tk:"col"`
	Action        string      `json:"action" tk:"col"`
	Actor         AuditActor  `json:"actor"`
	Target        AuditTarget `json:"target"`
	OldDigest     string      `` /* 214-byte string literal not displayed */
	NewDigest     string      `json:"newDigest,omitempty" jsonschema:"as oldDigest"`
	OldPreview    string      `json:"oldPreview,omitempty" tk:"untrusted,premasked"`
	NewPreview    string      `json:"newPreview,omitempty" tk:"untrusted,premasked"`
	ActionDetails string      `json:"actionDetails,omitempty" tk:"untrusted"`
	Error         string      `json:"error,omitempty" tk:"untrusted"`
}

AuditEntry is one configuration audit-log entry. old/new can hold whole policy files and personal data, so they are returned as a digest and, only on request (includeValues), a short untrusted preview.

type AuditLogInput

type AuditLogInput struct {
	Start         string   `json:"start,omitempty" jsonschema:"RFC 3339 start (default end minus 24h)"`
	End           string   `json:"end,omitempty" jsonschema:"RFC 3339 end (default now); the window may span at most 31 days"`
	Actor         []string `` /* 273-byte string literal not displayed */
	Target        []string `` /* 457-byte string literal not displayed */
	Event         []string `json:"event,omitempty" jsonschema:"event names such as TAILNET.UPDATE.ACL (server-side)"`
	Origin        []string `json:"origin,omitempty" jsonschema:"origins such as ADMIN_CONSOLE or CONFIG_API (client-side)"`
	IncludeValues bool     `` /* 474-byte string literal not displayed */
	Limit         int      `json:"limit,omitempty" jsonschema:"page size, 1-5000 (default 500)"`
	Cursor        string   `` /* 167-byte string literal not displayed */
}

AuditLogInput selects configuration audit-log entries. The API has no pagination: it returns the whole window, and tailkeeper pages over that response.

func (AuditLogInput) Check added in v0.6.0

func (in AuditLogInput) Check() error

Check refuses a limit out of range, a cursor given with a window or that no page issued, and a window that is malformed or too long, before anything is sent. What depends on the filters or the privacy setting waits for the run. Zero means the default limit.

type AuditLogOutput

type AuditLogOutput struct {
	Entries     []AuditEntry `json:"entries" tk:"rows"`
	Count       int          `json:"count"`
	WindowStart string       `json:"windowStart"`
	WindowEnd   string       `json:"windowEnd"`
	NextCursor  string       `json:"nextCursor,omitempty"`
	Note        string       `json:"note"`
}

AuditLogOutput is one page of entries, oldest first.

type AuditTarget

type AuditTarget struct {
	ID          string `json:"id,omitempty"`
	Name        string `json:"name,omitempty" tk:"untrusted"`
	Type        string `json:"type,omitempty"`
	IsEphemeral bool   `json:"isEphemeral,omitempty"`
	Property    string `json:"property,omitempty" tk:"untrusted"`
}

AuditTarget is what changed.

type AuthKeyCaps

type AuthKeyCaps struct {
	Reusable      bool     `json:"reusable"`
	Ephemeral     bool     `json:"ephemeral"`
	Preauthorized bool     `json:"preauthorized"`
	Tags          []string `json:"tags,omitempty" tk:"untrusted"`
}

AuthKeyCaps are the capabilities of an auth key.

type Connectivity

type Connectivity struct {
	HardNAT            bool     `json:"hardNat" jsonschema:"mappingVariesByDestIP: the NAT maps differently per destination"`
	Supports           Supports `json:"supports"`
	PreferredDERP      string   `json:"preferredDerp,omitempty" tk:"untrusted"`
	PreferredLatencyMs float64  `json:"preferredLatencyMs,omitempty"`
}

Connectivity summarises clientConnectivity without public endpoints.

type Contact

type Contact struct {
	Email             string `json:"email,omitempty" tk:"untrusted,personal"`
	FallbackEmail     string `json:"fallbackEmail,omitempty" tk:"untrusted,personal"`
	NeedsVerification *bool  `json:"needsVerification" jsonschema:"null when the API did not say; only an explicit false counts as verified"`
}

Contact is one tailnet contact.

type ContactsOutput

type ContactsOutput struct {
	Account           *Contact `json:"account,omitempty"`
	Support           *Contact `json:"support,omitempty"`
	Security          *Contact `json:"security,omitempty"`
	SecurityContactOK bool     `` /* 134-byte string literal not displayed */
}

ContactsOutput lists the tailnet's contacts.

type DNSAnswer

type DNSAnswer struct {
	Name string `json:"name" tk:"untrusted,col"`
	Type string `json:"type" tk:"col"`
	TTL  int    `json:"ttl" tk:"col"`
	Body string `json:"body" tk:"untrusted,col,plain"`
}

DNSAnswer is one answer record.

type DNSNodeAttr added in v0.6.0

type DNSNodeAttr struct {
	Attr    string   `json:"attr"`
	Targets []string `json:"targets" tk:"untrusted,emails"`
}

DNSNodeAttr is one of the seven DNS node attributes, with the selectors it applies to.

type DNSOutput

type DNSOutput struct {
	Nameservers             []Resolver        `json:"nameservers"`
	SplitDNS                []SplitDomain     `json:"splitDns"`
	SearchPaths             []string          `json:"searchPaths" tk:"untrusted"`
	MagicDNS                *bool             `json:"magicDns" jsonschema:"null when the API did not say"`
	OverrideLocalDNS        *bool             `json:"overrideLocalDns" jsonschema:"null when the API did not say"`
	PolicyOverridesAnalysed bool              `json:"policyOverridesAnalysed" jsonschema:"true when extraDNSRecords and DNS node attributes were read from the policy"`
	PolicyNote              string            `json:"policyNote,omitempty" jsonschema:"why the policy part is missing or cut: a fixed sentence"`
	ExtraRecords            []ExtraDNSRecord  `json:"extraDnsRecords,omitempty"`
	ExtraRecordsEffectiveIf []string          `json:"extraDnsRecordsEffectiveIf,omitempty" jsonschema:"settings the extra records need before they take effect"`
	NextDNS                 []DNSResolverAttr `json:"nextdns,omitempty"`
	ControlD                []DNSResolverAttr `json:"controlD,omitempty"`
	ResolverNote            string            `` /* 144-byte string literal not displayed */
	DNSNodeAttrs            []DNSNodeAttr     `json:"dnsNodeAttrs,omitempty"`
	OtherAttrs              []string          `json:"otherAttrs,omitempty" tk:"untrusted,emails"`
	AttrTableAsOf           string            `json:"attrTableAsOf,omitempty" jsonschema:"the date of the table of DNS node attributes this tool knows"`
	Truncated               bool              `json:"truncated,omitempty" jsonschema:"true when a list was cut at 100 entries or at the size limit"`
}

DNSOutput is the tailnet's DNS configuration from /dns/configuration, plus what the policy sets for DNS when the read credential may read the policy.

type DNSQueryInput

type DNSQueryInput struct {
	Name string `json:"name" jsonschema:"a name under the tailnet's MagicDNS suffix, or allowed by local.dnsQueryAllowlist"`
	Type string `json:"type,omitempty" jsonschema:"A (default), AAAA, CNAME, MX, NS, PTR, SRV or TXT"`
}

DNSQueryInput is a name lookup.

type DNSQueryOutput

type DNSQueryOutput struct {
	Name         string      `json:"name" tk:"untrusted"`
	Type         string      `json:"type"`
	ResponseCode string      `json:"responseCode"`
	Resolvers    []string    `json:"resolvers" tk:"untrusted,plain"`
	Answers      []DNSAnswer `json:"answers" tk:"rows"`
}

DNSQueryOutput is the lookup result.

type DNSResolverAttr added in v0.6.0

type DNSResolverAttr struct {
	Targets      []string `json:"targets" tk:"untrusted,emails"`
	ID           string   `json:"id" tk:"untrusted,personal"`
	Priority     *int     `json:"priority,omitempty"`
	NoDeviceInfo bool     `json:"noDeviceInfo,omitempty"`
}

DNSResolverAttr is one NextDNS or Control D attribute. Targets are selectors. ID is the profile identifier, masked whole.

type Device

type Device struct {
	NodeID                    string        `json:"nodeId" tk:"col"`
	Name                      string        `json:"name" tk:"untrusted,col"`
	Hostname                  string        `json:"hostname" tk:"untrusted"`
	User                      string        `json:"user" tk:"untrusted,col,personal"`
	OS                        string        `json:"os" tk:"untrusted,col"`
	Tags                      []string      `json:"tags,omitempty" tk:"untrusted"`
	Addresses                 []string      `json:"addresses,omitempty"`
	ClientVersion             string        `json:"clientVersion,omitempty" tk:"untrusted"`
	UpdateAvailable           bool          `json:"updateAvailable"`
	Created                   string        `json:"created,omitempty"`
	Expires                   string        `json:"expires,omitempty"`
	LastSeen                  string        `json:"lastSeen,omitempty" tk:"col"`
	ConnectedToControl        bool          `json:"connectedToControl" tk:"col"`
	KeyExpiryDisabled         bool          `json:"keyExpiryDisabled"`
	Authorized                bool          `json:"authorized"`
	IsExternal                bool          `json:"isExternal"`
	IsEphemeral               bool          `json:"isEphemeral"`
	BlocksIncomingConnections bool          `json:"blocksIncomingConnections"`
	TailnetLockError          string        `json:"tailnetLockError,omitempty" tk:"untrusted"`
	MultipleConnections       *bool         `json:"multipleConnections,omitempty"`
	SSHEnabled                *bool         `json:"sshEnabled,omitempty"`
	AdvertisedRoutes          []string      `json:"advertisedRoutes,omitempty" tk:"untrusted,plain"`
	EnabledRoutes             []string      `json:"enabledRoutes,omitempty" tk:"untrusted,plain"`
	Connectivity              *Connectivity `json:"connectivity,omitempty"`
	Distro                    *Distro       `json:"distro,omitempty" tk:"untrusted"`
	Fields                    string        `json:"fields" jsonschema:"default or all: which API field set was requested; fields absent here are unknown, not false"`
}

Device is the device shape tailkeeper returns.

type DeviceInvite

type DeviceInvite struct {
	ID              string    `json:"id" tk:"col"`
	Created         string    `json:"created,omitempty"`
	DeviceID        int64     `json:"deviceId,omitempty"`
	SharerID        int64     `json:"sharerId,omitempty"`
	MultiUse        bool      `json:"multiUse" tk:"col"`
	AllowExitNode   bool      `json:"allowExitNode" tk:"col"`
	Email           string    `json:"email,omitempty" tk:"untrusted,col,personal"`
	LastEmailSentAt string    `json:"lastEmailSentAt,omitempty"`
	Accepted        bool      `json:"accepted" tk:"col"`
	AcceptedBy      *Acceptor `json:"acceptedBy,omitempty"`
}

DeviceInvite is a device-share invite. inviteUrl is a bearer link and is never returned (spec §7.6).

type DeviceInvitesOutput

type DeviceInvitesOutput struct {
	NodeID  string         `json:"nodeId"`
	Invites []DeviceInvite `json:"invites" tk:"rows"`
	Count   int            `json:"count"`
}

DeviceInvitesOutput lists a device's invites.

type DevicePostureOutput

type DevicePostureOutput struct {
	NodeID     string             `json:"nodeId"`
	Attributes []PostureAttribute `json:"attributes" tk:"rows"`
}

DevicePostureOutput lists a device's posture attributes.

type DeviceRef

type DeviceRef struct {
	Device string `` /* 195-byte string literal not displayed */
}

DeviceRef names one device.

func (DeviceRef) Check added in v0.6.0

func (in DeviceRef) Check() error

Check refuses a device reference that cannot name a device, before anything is sent.

type DeviceRoutesInput

type DeviceRoutesInput struct {
	Device    string `` /* 195-byte string literal not displayed */
	IncludeHA bool   `` /* 130-byte string literal not displayed */
}

DeviceRoutesInput selects a device and optionally computes HA peers.

func (DeviceRoutesInput) Check added in v0.6.0

func (in DeviceRoutesInput) Check() error

Check refuses a device reference that cannot name a device, before anything is sent.

type DeviceRoutesOutput

type DeviceRoutesOutput struct {
	NodeID             string      `json:"nodeId"`
	Advertised         []string    `json:"advertised" tk:"untrusted,plain"`
	Enabled            []string    `json:"enabled" tk:"untrusted,plain"`
	Pending            []string    `json:"pending" jsonschema:"advertised but not approved" tk:"untrusted,plain"`
	Latent             []string    `json:"latent" jsonschema:"approved but not advertised: activates if this identity ever advertises it" tk:"untrusted,plain"`
	ExitNodeAdvertised bool        `json:"exitNodeAdvertised"`
	ExitNodeEnabled    bool        `json:"exitNodeEnabled"`
	HAPeers            []RoutePeer `json:"haPeers,omitempty"`
}

DeviceRoutesOutput shows route approval state.

type DevicesListInput

type DevicesListInput struct {
	Tags         []string `json:"tags,omitempty" jsonschema:"devices must carry all of these tags (server-side, exact)"`
	OS           string   `json:"os,omitempty" jsonschema:"exact OS name, for example linux, macOS, windows (server-side)"`
	Hostname     string   `` /* 162-byte string literal not displayed */
	User         string   `` /* 213-byte string literal not displayed */
	Ephemeral    *bool    `json:"ephemeral,omitempty" jsonschema:"filter on isEphemeral (server-side)"`
	Authorized   *bool    `json:"authorized,omitempty" jsonschema:"filter on authorized (server-side)"`
	Online       *bool    `json:"online,omitempty" jsonschema:"filter on connectedToControl (server-side)"`
	NameContains string   `` /* 202-byte string literal not displayed */
	StaleDays    int      `json:"staleDays,omitempty" jsonschema:"only devices not connected and last seen more than this many days ago (client-side)"`
	AllFields    bool     `json:"allFields,omitempty" jsonschema:"request fields=all: routes, connectivity, SSH, cloned-state flag"`
}

DevicesListInput filters devices. Server-side filters are exact matches.

func (DevicesListInput) Check added in v0.6.0

func (in DevicesListInput) Check() error

Check refuses a staleDays or a tag that cannot be right, before anything is sent.

type DevicesListOutput

type DevicesListOutput struct {
	Devices       []Device `json:"devices" tk:"rows"`
	Count         int      `json:"count"`
	Fields        string   `json:"fields"`
	ServerFilters []string `json:"serverFilters"`
	ClientFilters []string `json:"clientFilters"`
}

DevicesListOutput lists devices.

type Distro

type Distro struct {
	Name     string `json:"name,omitempty"`
	Version  string `json:"version,omitempty"`
	CodeName string `json:"codeName,omitempty"`
}

Distro is the reported OS distribution.

type ExtraDNSRecord added in v0.6.0

type ExtraDNSRecord struct {
	Name  string `json:"name" tk:"untrusted,emails"`
	Type  string `json:"type,omitempty" tk:"untrusted"`
	Value string `json:"value" tk:"untrusted,emails" jsonschema:"email addresses in it are masked"`
}

ExtraDNSRecord is one extraDNSRecords entry. An empty Type means A or AAAA by the value.

type FailureKind added in v0.6.0

type FailureKind string

FailureKind says what a line of a validate reply is about a test.

const (
	// AssertionFailed: a line in the want/got grammar, the server's answer that a
	// destination was accepted or dropped against the test's expectation.
	AssertionFailed FailureKind = "assertion_failed"
	// TestUnevaluable: anything else the server says about a test (a name it cannot resolve,
	// a destination kind tests do not take, a malformed test). It says nothing about access,
	// and is never read as a verdict.
	TestUnevaluable FailureKind = "test_unevaluable"
)

type FailureLine added in v0.6.0

type FailureLine struct {
	Kind     FailureKind
	SSH      bool
	Dst      string // the address as the server quoted it (tests form), or the dst (SSH form)
	User     string // the ssh user the server quoted (SSH form); "" otherwise
	Protocol string // "" when the line has none
	Want     string // "Accept" or "Drop" (tests), "accept" or "deny" (SSH)
	Got      string
}

FailureLine is one error line of a validate reply, read by the grammar of probe A-9 (20 Oct 2026). The zero fields of a TestUnevaluable line mean nothing.

func ParseFailureLine added in v0.6.0

func ParseFailureLine(line string) FailureLine

ParseFailureLine reads one error line. The grammar is positional and anchored, never a search: a tag or a host name can embed a destination and the words want and got, so every quoted field is read as one Go-quoted string from its opening quote, and the text after it must be exactly what the grammar says, to the end of the line.

[acl test error]: address "<dst>"( (protocol "<p>"))?: want: (Accept|Drop), got: (Accept|Drop)
[ssh test error]: src "<s>" at "<ip>", dst "<d>" at "<ip>", ssh user "<u>": want: "accept" got: "deny"

A line that is not in the grammar, or whose quoted field does not unquote, or whose two verdicts are the same, is TestUnevaluable: that can only turn a verdict into "unresolved", never into a pass.

func (FailureLine) Failure added in v0.6.0

func (f FailureLine) Failure(src string) acl.Failure

Failure is the acl.Failure that locates this line, for a test whose source is src.

type Flow

type Flow struct {
	Kind    string `json:"kind" jsonschema:"virtual, subnet, exit or physical"`
	Proto   string `json:"proto" tk:"untrusted"`
	Src     string `json:"src" tk:"untrusted"`
	Dst     string `json:"dst" tk:"untrusted"`
	TxPkts  int64  `json:"txPkts"`
	TxBytes int64  `json:"txBytes"`
	RxPkts  int64  `json:"rxPkts"`
	RxBytes int64  `json:"rxBytes"`
}

Flow is one traffic counter in a flow-log record.

type FlowLogsInput

type FlowLogsInput struct {
	Start      string `json:"start,omitempty" jsonschema:"RFC 3339 start (default end minus 15m)"`
	End        string `json:"end,omitempty" jsonschema:"RFC 3339 end (default now); the window may span at most 1h"`
	Node       string `json:"node,omitempty" jsonschema:"only records logged by this node ID (client-side)"`
	MaxRecords int    `json:"maxRecords,omitempty" jsonschema:"1-10000 (default 1000)"`
}

FlowLogsInput selects a short window of network flow logs.

func (FlowLogsInput) Check added in v0.6.0

func (in FlowLogsInput) Check() error

Check refuses a window that is malformed or too long and a maxRecords out of range, before anything is sent. Zero means the default.

type FlowLogsOutput

type FlowLogsOutput struct {
	Status          string       `json:"status" jsonschema:"ok, not_enabled (flow logging is off) or not_available (not on this plan)"`
	LoggingEnabled  string       `` /* 131-byte string literal not displayed */
	Records         []FlowRecord `json:"records"`
	Count           int          `json:"count"`
	Truncated       bool         `json:"truncated"`
	AsOf            string       `json:"asOf"`
	MayBeIncomplete bool         `json:"mayBeIncomplete"`
	Note            string       `json:"note"`
}

FlowLogsOutput reports flow records or why there are none.

type FlowRecord

type FlowRecord struct {
	NodeID string `json:"nodeId"`
	Logged string `json:"logged"`
	Start  string `json:"start" tk:"untrusted"`
	End    string `json:"end" tk:"untrusted"`
	Flows  []Flow `json:"flows"`
}

FlowRecord is one node's 5-second window.

type IDRef

type IDRef struct {
	ID string `json:"id" jsonschema:"object ID"`
}

IDRef names an object by ID.

func (IDRef) Check added in v0.6.0

func (in IDRef) Check() error

Check refuses an ID that cannot be one, before anything is sent.

type InviteRef

type InviteRef struct {
	ID string `json:"id" jsonschema:"invite ID"`
}

InviteRef names one invite.

func (InviteRef) Check added in v0.6.0

func (in InviteRef) Check() error

Check refuses an ID that cannot be one, before anything is sent.

type Key

type Key struct {
	ID                  string            `json:"id" tk:"col"`
	KeyType             string            `json:"keyType" tk:"col"`
	Description         string            `json:"description,omitempty" tk:"untrusted,col"`
	Created             string            `json:"created,omitempty"`
	Updated             string            `json:"updated,omitempty"`
	Expires             string            `json:"expires,omitempty" tk:"col"`
	Revoked             string            `json:"revoked,omitempty"`
	Invalid             bool              `json:"invalid" tk:"col"`
	Scopes              []string          `json:"scopes,omitempty"`
	Tags                []string          `json:"tags,omitempty" tk:"untrusted"`
	AuthKeyCapabilities *AuthKeyCaps      `json:"authKeyCapabilities,omitempty"`
	UserID              string            `json:"userId,omitempty"`
	Issuer              string            `json:"issuer,omitempty" tk:"untrusted"`
	Subject             string            `json:"subject,omitempty" tk:"untrusted"`
	Audience            string            `json:"audience,omitempty" tk:"untrusted"`
	CustomClaimRules    map[string]string `json:"customClaimRules,omitempty" tk:"untrusted"`
}

Key is a key's metadata. The key material itself is never returned.

type KeyRef

type KeyRef struct {
	ID string `json:"id" jsonschema:"key ID"`
}

KeyRef names one key.

func (KeyRef) Check added in v0.6.0

func (in KeyRef) Check() error

Check refuses an ID that cannot be one, before anything is sent.

type KeysListOutput

type KeysListOutput struct {
	Keys     []Key             `json:"keys" tk:"rows"`
	Count    int               `json:"count"`
	Coverage map[string]string `json:"coverage" jsonschema:"per key type: visible, not_visible or unknown"`
	Complete *bool             `json:"complete,omitempty" jsonschema:"true only when every key type was visible; absent when unknown"`
}

KeysListOutput lists keys with an honest statement of what could be seen.

type LocalDNSStatusOutput

type LocalDNSStatusOutput struct {
	TailscaleDNS      bool          `json:"tailscaleDns" jsonschema:"the node accepts the tailnet DNS configuration (--accept-dns)"`
	MagicDNSEnabled   bool          `json:"magicDnsEnabled"`
	MagicDNSSuffix    string        `json:"magicDnsSuffix,omitempty" tk:"untrusted"`
	SelfDNSName       string        `json:"selfDnsName,omitempty" tk:"untrusted"`
	Resolvers         []string      `json:"resolvers" tk:"untrusted,plain" jsonschema:"the tailnet's resolvers in preference order; empty means system defaults"`
	SplitDNS          []SplitDomain `json:"splitDns"`
	SearchDomains     []string      `json:"searchDomains" tk:"untrusted"`
	SystemNameservers []string      `json:"systemNameservers" tk:"untrusted,plain"`
	SystemDNSError    string        `json:"systemDnsError,omitempty" tk:"untrusted"`
}

LocalDNSStatusOutput is the node's DNS view.

type LocalIPInput

type LocalIPInput struct {
	Peer   string `json:"peer,omitempty" jsonschema:"a peer's tailnet IP (default: this node)"`
	Family string `json:"family,omitempty" jsonschema:"4, 6 or 1 (first address only); default all"`
}

LocalIPInput selects which addresses local_ip prints.

type LocalIPOutput

type LocalIPOutput struct {
	Addresses []string `json:"addresses"`
}

LocalIPOutput lists addresses.

type LocalIdentity

type LocalIdentity struct {
	NodeID            string   `json:"nodeId"`
	Name              string   `json:"name" tk:"untrusted"`
	Addresses         []string `json:"addresses"`
	Tags              []string `json:"tags,omitempty" tk:"untrusted"`
	MachineAuthorized bool     `json:"machineAuthorized"`
	LoginName         string   `json:"loginName,omitempty" tk:"untrusted,personal"`
	DisplayName       string   `json:"displayName,omitempty" tk:"untrusted,personal"`
	Capabilities      []string `` /* 159-byte string literal not displayed */
}

LocalIdentity is a node and its user.

type LocalPeer

type LocalPeer struct {
	NodeID         string   `json:"nodeId" tk:"col"`
	HostName       string   `json:"hostName" tk:"untrusted,col"`
	DNSName        string   `json:"dnsName" tk:"untrusted"`
	OS             string   `json:"os,omitempty" tk:"untrusted,col"`
	TailscaleIPs   []string `json:"tailscaleIps"`
	Tags           []string `json:"tags,omitempty" tk:"untrusted"`
	Online         bool     `json:"online" tk:"col"`
	Active         bool     `json:"active"`
	Path           string   `json:"path,omitempty" tk:"col" jsonschema:"direct, peer-relay, derp or none (peers only)"`
	Relay          string   `json:"relay,omitempty" tk:"untrusted" jsonschema:"home DERP region code"`
	ExitNode       bool     `json:"exitNode"`
	ExitNodeOption bool     `json:"exitNodeOption"`
	LastHandshake  string   `json:"lastHandshake,omitempty"`
	KeyExpiry      string   `json:"keyExpiry,omitempty"`
}

LocalPeer is a node as the local daemon sees it.

type LocalStatusInput

type LocalStatusInput struct {
	Peers  bool `json:"peers,omitempty" jsonschema:"include peers"`
	Active bool `json:"active,omitempty" jsonschema:"include only peers with active sessions (implies peers)"`
}

LocalStatusInput selects what local_status includes.

type LocalStatusOutput

type LocalStatusOutput struct {
	BackendState    string      `json:"backendState"`
	NeedsLogin      bool        `json:"needsLogin"`
	Version         string      `json:"version" tk:"untrusted"`
	Self            *LocalPeer  `json:"self,omitempty"`
	Tailnet         string      `` /* 139-byte string literal not displayed */
	MagicDNSSuffix  string      `json:"magicDnsSuffix,omitempty" tk:"untrusted"`
	MagicDNSEnabled bool        `json:"magicDnsEnabled"`
	Health          []string    `json:"health" tk:"untrusted"`
	Peers           []LocalPeer `json:"peers,omitempty" tk:"rows"`
	PeerCount       int         `json:"peerCount"`
	PeerScope       string      `` /* 132-byte string literal not displayed */
}

LocalStatusOutput is this node's status.

type LockStatusOutput

type LockStatusOutput struct {
	Enabled          bool   `json:"enabled"`
	PublicKey        string `json:"publicKey,omitempty" jsonschema:"this node's Tailnet Lock public key" tk:"untrusted"`
	NodeKey          string `json:"nodeKey,omitempty" jsonschema:"this node's public node key" tk:"untrusted"`
	NodeKeySigned    *bool  `json:"nodeKeySigned,omitempty" jsonschema:"absent when Tailnet Lock is off" tk:"absentok"`
	TrustedKeyCount  int    `json:"trustedKeyCount"`
	VisiblePeerCount int    `json:"visiblePeerCount"`
	LockedOutPeers   int    `json:"lockedOutPeers" jsonschema:"peers filtered out because their node key is not signed"`
}

LockStatusOutput is Tailnet Lock as this node sees it.

type LogStreamConfig

type LogStreamConfig struct {
	DestinationType      string   `json:"destinationType,omitempty"`
	URL                  string   `json:"url,omitempty" tk:"untrusted,plain" jsonschema:"scheme and host only"`
	URLPathHash          string   `json:"urlPathSha256,omitempty" jsonschema:"SHA-256 of the URL's path and query, which can carry a collector token"`
	User                 string   `json:"user,omitempty" tk:"untrusted,personal"`
	UploadPeriodMinutes  int      `json:"uploadPeriodMinutes,omitempty"`
	CompressionFormat    string   `json:"compressionFormat,omitempty"`
	S3Bucket             string   `json:"s3Bucket,omitempty" tk:"untrusted"`
	S3Region             string   `json:"s3Region,omitempty" tk:"untrusted"`
	S3KeyPrefix          string   `json:"s3KeyPrefix,omitempty" tk:"untrusted"`
	S3AuthenticationType string   `json:"s3AuthenticationType,omitempty"`
	S3AccessKeyID        string   `json:"s3AccessKeyId,omitempty" tk:"untrusted"`
	S3RoleARN            string   `json:"s3RoleArn,omitempty" tk:"untrusted"`
	S3ExternalID         string   `json:"s3ExternalId,omitempty" tk:"untrusted"`
	GCSBucket            string   `json:"gcsBucket,omitempty" tk:"untrusted"`
	GCSKeyPrefix         string   `json:"gcsKeyPrefix,omitempty" tk:"untrusted"`
	GCSScopes            []string `json:"gcsScopes,omitempty" tk:"untrusted"`
}

LogStreamConfig is a destination without its secrets (token, S3 secret key and GCS credentials are never returned).

type LogStreamInput

type LogStreamInput struct {
	LogType string `json:"logType" jsonschema:"configuration or network"`
}

LogStreamInput names a log type.

func (LogStreamInput) Check added in v0.6.0

func (in LogStreamInput) Check() error

Check refuses a log type Tailscale does not have, before anything is sent.

type LogStreamOutput

type LogStreamOutput struct {
	LogType       string           `json:"logType"`
	Status        string           `json:"status" jsonschema:"configured or not_configured"`
	Configuration *LogStreamConfig `json:"configuration,omitempty"`
	Health        *LogStreamStatus `json:"health,omitempty"`
	HealthError   string           `json:"healthError,omitempty" jsonschema:"error code when delivery health could not be read"`
	Findings      []string         `json:"findings"`
}

LogStreamOutput describes one log stream.

type LogStreamStatus

type LogStreamStatus struct {
	LastActivity       string  `json:"lastActivity,omitempty"`
	LastError          string  `json:"lastError,omitempty" tk:"untrusted"`
	NumBytesSent       int64   `json:"numBytesSent"`
	NumEntriesSent     int64   `json:"numEntriesSent"`
	NumSpoofedEntries  int64   `json:"numSpoofedEntries"`
	NumTotalRequests   int64   `json:"numTotalRequests"`
	NumFailedRequests  int64   `json:"numFailedRequests"`
	RateFailedRequests float64 `json:"rateFailedRequests"`
}

LogStreamStatus is delivery health.

type Login added in v0.6.0

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

Login is the login name of one user, resolved from a pseudonym. It exists to be sent to Tailscale in a request and to go nowhere else while personal data is masked: it prints as [login] under every fmt verb, encodes as "[login]" in JSON and text, and keeps the name in a function, as privacy.Key keeps its bytes, so that fmt cannot reach it through a struct field. Reveal is the one way to read it; its call site is the line that builds the request, and a line that puts it anywhere else is the bug.

func (Login) Format added in v0.6.0

func (Login) Format(f fmt.State, _ rune)

Format keeps the login out of every format verb: fmt calls it before any other way of printing, so even the numeric verbs print the placeholder.

func (Login) GoString added in v0.6.0

func (Login) GoString() string

GoString is what %#v prints.

func (Login) MarshalJSON added in v0.6.0

func (Login) MarshalJSON() ([]byte, error)

MarshalJSON encodes the placeholder.

func (Login) MarshalText added in v0.6.0

func (Login) MarshalText() ([]byte, error)

MarshalText encodes the placeholder.

func (Login) Reveal added in v0.6.0

func (l Login) Reveal() string

Reveal returns the login. Use it only to build the request that goes to Tailscale.

func (Login) String added in v0.6.0

func (Login) String() string

String is what a Login is called as text.

type Metric

type Metric struct {
	Name   string            `json:"name" tk:"col"`
	Labels map[string]string `json:"labels,omitempty" tk:"untrusted"`
	Value  float64           `json:"value" tk:"col"`
}

Metric is one sample.

type MetricsOutput

type MetricsOutput struct {
	Metrics []Metric `json:"metrics" tk:"rows"`
	Dropped int      `json:"dropped" jsonschema:"samples with undocumented names, not shown"`
}

MetricsOutput lists documented metrics.

func ParseMetrics

func ParseMetrics(text []byte) MetricsOutput

ParseMetrics parses Prometheus text, keeping documented metric names only.

type NetcheckOutput

type NetcheckOutput struct {
	UDP                   bool               `json:"udp"`
	IPv4                  bool               `json:"ipv4"`
	IPv6                  bool               `json:"ipv6"`
	IPv4CanSend           bool               `json:"ipv4CanSend"`
	IPv6CanSend           bool               `json:"ipv6CanSend"`
	OSHasIPv6             bool               `json:"osHasIpv6"`
	ICMPv4                bool               `json:"icmpv4"`
	MappingVariesByDestIP *bool              `json:"mappingVariesByDestIp,omitempty" jsonschema:"hard NAT when true; absent when unknown"`
	UPnP                  *bool              `json:"upnp,omitempty" jsonschema:"absent when unknown"`
	PMP                   *bool              `json:"pmp,omitempty" jsonschema:"absent when unknown"`
	PCP                   *bool              `json:"pcp,omitempty" jsonschema:"absent when unknown"`
	CaptivePortal         *bool              `json:"captivePortal,omitempty" jsonschema:"absent when unknown"`
	PreferredDERP         int                `json:"preferredDerp" jsonschema:"region ID; 0 when unknown"`
	RegionLatencyMs       map[string]float64 `json:"regionLatencyMs" jsonschema:"keyed by DERP region ID"`
}

NetcheckOutput is the local network report without public IP addresses.

type NoInput

type NoInput struct{}

NoInput is the input of tools without parameters.

type OAuthApp

type OAuthApp struct {
	ID                    string   `json:"id" tk:"col"`
	Name                  string   `json:"name" tk:"untrusted,col"`
	Description           string   `json:"description,omitempty" tk:"untrusted"`
	RedirectURIs          []string `json:"redirectURIs,omitempty" tk:"untrusted,plain"`
	Scopes                []string `json:"scopes,omitempty" tk:"col"`
	AllowedNodeAttributes []string `json:"allowedNodeAttributes,omitempty" tk:"untrusted"`
	Created               string   `json:"created,omitempty"`
	Updated               string   `json:"updated,omitempty"`
}

OAuthApp is an OAuth app without its client secret.

type OAuthAppsOutput

type OAuthAppsOutput struct {
	Apps  []OAuthApp `json:"apps" tk:"rows"`
	Count int        `json:"count"`
}

OAuthAppsOutput lists OAuth apps.

type PingInput

type PingInput struct {
	Target         string `json:"target" jsonschema:"literal tailnet IP of the peer"`
	Count          int    `json:"count,omitempty" jsonschema:"1-10 (default 3)"`
	TimeoutSeconds int    `json:"timeoutSeconds,omitempty" jsonschema:"per ping, 1-8 (default 5)"`
	Mode           string `json:"mode,omitempty" jsonschema:"disco (default), tsmp, icmp or peerapi"`
	AllPings       bool   `json:"allPings,omitempty" jsonschema:"send every ping; by default (like the CLI) disco pings stop at the first direct reply"`
}

PingInput configures local_ping.

type PingOutput

type PingOutput struct {
	Target               string      `json:"target"`
	Mode                 string      `json:"mode"`
	Replies              []PingReply `json:"replies" tk:"rows"`
	Timeouts             int         `json:"timeouts"`
	DirectEstablished    bool        `json:"directEstablished"`
	DirectNotEstablished bool        `json:"directNotEstablished" jsonschema:"the CLI gave up waiting for a direct path"`
	NoReply              bool        `json:"noReply" jsonschema:"no ping was answered"`
	UnparsedLines        int         `json:"unparsedLines"`
	Note                 string      `json:"note"`
}

PingOutput summarises a ping run.

type PingReply

type PingReply struct {
	Via       string  `json:"via" tk:"col" jsonschema:"direct, derp, peer-relay, icmp, tsmp or peerapi"`
	Region    string  `json:"region,omitempty" tk:"untrusted,col" jsonschema:"DERP region code, for derp replies"`
	LatencyMs float64 `json:"latencyMs" tk:"col"`
}

PingReply is one parsed reply line.

type PingResult

type PingResult struct {
	Replies  []PingReply
	Timeouts int
	Direct   bool
	Unparsed int
}

PingResult is what ParsePing extracts from the CLI's stdout.

func ParsePing

func ParsePing(out []byte) PingResult

ParsePing parses `tailscale ping` stdout. Formats are those printed by cmd/tailscale/cli/ping.go; latencies are Go durations ("0s", "12ms", "1.2s").

type Policy

type Policy struct {
	Name   string `json:"name" tk:"untrusted,col"`
	Value  string `json:"value" tk:"untrusted,col"`
	Origin string `json:"origin,omitempty" tk:"untrusted,col"`
	Error  string `json:"error,omitempty" tk:"untrusted"`
}

Policy is one effective system policy.

type PolicyProbe added in v0.6.0

type PolicyProbe struct {
	Name   string
	Status ProbeStatus
	Detail string
	Fix    string
	Called bool
	Code   tkerr.Code
}

PolicyProbe is one row of the policy-mode probes doctor runs. Called is true when the probe made a request, or tried to; a probe that stopped before it asked anything (the canary with no live policy to build on, or a send tailkeeper's own validation limit refused) is not a call. Code is the code of the error the call returned, empty when it returned none. Only the code leaves the probe: the error's text is tailnet text and stays out of this struct.

func ProbePolicyMode added in v0.6.0

func ProbePolicyMode(ctx context.Context, env *registry.Env) []PolicyProbe

ProbePolicyMode runs the four policy-mode probes, in order: a document the server rejects, the details reader, the in-band canary on the live policy, and one synthetic SSH document. Each send takes one token of the validation bucket. The details read takes none.

type PostureAttribute

type PostureAttribute struct {
	Attribute string `json:"attribute" tk:"untrusted,col"`
	Value     string `json:"value" tk:"untrusted,col"`
	Type      string `json:"type" tk:"col"`
	Expiry    string `json:"expiry,omitempty" tk:"col"`
}

PostureAttribute is one device posture attribute.

type PostureIntegration

type PostureIntegration struct {
	ID            string         `json:"id" tk:"col"`
	Provider      string         `json:"provider" tk:"col"`
	CloudID       string         `json:"cloudId,omitempty" tk:"untrusted"`
	ClientID      string         `json:"clientId,omitempty" tk:"untrusted"`
	TenantID      string         `json:"tenantId,omitempty" tk:"untrusted"`
	ConfigUpdated string         `json:"configUpdated,omitempty"`
	Status        *PostureStatus `json:"status,omitempty"`
}

PostureIntegration is an EDR/MDM integration without its client secret.

type PostureIntegrationsOutput

type PostureIntegrationsOutput struct {
	Integrations []PostureIntegration `json:"integrations" tk:"rows"`
	Count        int                  `json:"count"`
}

PostureIntegrationsOutput lists integrations.

type PostureStatus

type PostureStatus struct {
	LastSync             string `json:"lastSync,omitempty"`
	Error                string `json:"error,omitempty" tk:"untrusted"`
	ProviderHostCount    int    `json:"providerHostCount"`
	MatchedCount         int    `json:"matchedCount"`
	PossibleMatchedCount int    `json:"possibleMatchedCount"`
}

PostureStatus is the integration's sync health.

type Pref

type Pref struct {
	Name  string `json:"name" tk:"col"`
	Value string `json:"value" tk:"untrusted,col,plain"`
}

Pref is one client preference.

type PrefsOutput

type PrefsOutput struct {
	Prefs []Pref `json:"prefs" tk:"rows"`
}

PrefsOutput lists preferences.

type ProbeStatus added in v0.6.0

type ProbeStatus string

ProbeStatus is what one policy-mode probe established. A reading tailkeeper did not establish is a warning or a failure, never ok.

const (
	ProbeOK   ProbeStatus = "ok"
	ProbeWarn ProbeStatus = "warn"
	ProbeFail ProbeStatus = "fail"
	ProbeNA   ProbeStatus = "n/a"
)

func ClassifyKind added in v0.6.0

func ClassifyKind(status string, verdicts []string) (st ProbeStatus, detail, fix string)

ClassifyKind is the row for one destination kind. ok only when the test failed and a verdict is allowed or denied. unknown, unresolved and a pass are not that.

type Resolver

type Resolver struct {
	Address         string `json:"address" tk:"untrusted,plain"`
	UseWithExitNode bool   `json:"useWithExitNode"`
}

Resolver is one DNS resolver.

type RoutePeer

type RoutePeer struct {
	Prefix string `json:"prefix" tk:"untrusted,plain"`
	NodeID string `json:"nodeId"`
	Name   string `json:"name" tk:"untrusted"`
}

RoutePeer is another device serving the same prefix.

type ServeEntry

type ServeEntry struct {
	Source   string   `json:"source" tk:"col" jsonschema:"background, foreground or service"`
	Service  string   `json:"service,omitempty" tk:"untrusted,col" jsonschema:"Tailscale Service name, for source service"`
	Listener string   `json:"listener" tk:"untrusted,col" jsonschema:"host:port for web listeners, port for TCP"`
	Kind     string   `json:"kind" tk:"col" jsonschema:"web, https, http, tcp-forward or tun"`
	Paths    []string `json:"paths,omitempty" tk:"untrusted,col"`
	Handlers []string `json:"handlers,omitempty" tk:"col" jsonschema:"handler kinds: proxy, path, text or redirect"`
	Funnel   bool     `json:"funnel" tk:"col" jsonschema:"exposed to the public internet"`
}

ServeEntry is one served endpoint. Targets (local ports, file paths, URLs, text) are reduced to their kind.

type ServeOutput

type ServeOutput struct {
	Entries []ServeEntry `json:"entries" tk:"rows"`
	Count   int          `json:"count"`
}

ServeOutput lists served endpoints.

func ServeStatus

func ServeStatus(c cliServe, funnelOnly bool) ServeOutput

ServeStatus flattens a serve config: background, then foreground sessions, then Services. Funnel applies to the node's own listeners, not to Services.

type Service

type Service struct {
	Name        string   `json:"name" tk:"untrusted,col"`
	DisplayName string   `json:"displayName,omitempty" tk:"untrusted"`
	Addrs       []string `json:"addrs,omitempty" tk:"col"`
	Comment     string   `json:"comment,omitempty" tk:"untrusted"`
	Ports       []string `json:"ports,omitempty" tk:"untrusted,col"`
	Tags        []string `json:"tags,omitempty" tk:"untrusted"`
}

Service is a Tailscale Service.

type ServiceRef

type ServiceRef struct {
	Name string `json:"name" jsonschema:"service name, for example svc:web"`
}

ServiceRef names one service.

func (ServiceRef) Check added in v0.6.0

func (in ServiceRef) Check() error

Check refuses a name that cannot be one, before anything is sent.

type ServicesOutput

type ServicesOutput struct {
	Services []Service `json:"services" tk:"rows"`
	Count    int       `json:"count"`
}

ServicesOutput lists services.

type Settings

type Settings struct {
	DevicesApprovalOn                      *bool   `json:"devicesApprovalOn,omitempty"`
	DevicesAutoUpdatesOn                   *bool   `json:"devicesAutoUpdatesOn,omitempty"`
	DevicesKeyDurationDays                 *int    `json:"devicesKeyDurationDays,omitempty"`
	UsersApprovalOn                        *bool   `json:"usersApprovalOn,omitempty"`
	UsersRoleAllowedToJoinExternalTailnets *string `json:"usersRoleAllowedToJoinExternalTailnets,omitempty"`
	NetworkFlowLoggingOn                   *bool   `json:"networkFlowLoggingOn,omitempty"`
	RegionalRoutingOn                      *bool   `json:"regionalRoutingOn,omitempty"`
	RouteSelection                         *string `json:"routeSelection,omitempty"`
	PostureIdentityCollectionOn            *bool   `json:"postureIdentityCollectionOn,omitempty"`
	HTTPSEnabled                           *bool   `json:"httpsEnabled,omitempty"`
	ACLsExternallyManagedOn                *bool   `json:"aclsExternallyManagedOn,omitempty"`
	ACLsExternalLink                       *string `json:"aclsExternalLink,omitempty" tk:"untrusted,plain"`
}

Settings mirrors the API's TailnetSettings. Every field is a pointer: a field the read credential cannot see is absent, and absent must never read as false.

type SettingsOutput

type SettingsOutput struct {
	Settings          Settings `json:"settings"`
	Unreadable        []string `` /* 150-byte string literal not displayed */
	ExternallyManaged string   `json:"externallyManaged" jsonschema:"true, false or unknown"`
}

SettingsOutput reports the settings, which fields could not be read, and the GitOps lock state (spec §11.1).

type SplitDomain

type SplitDomain struct {
	Domain    string     `json:"domain" tk:"untrusted"`
	Resolvers []Resolver `json:"resolvers"`
}

SplitDomain is a split-DNS route.

type SubjectResolver added in v0.6.0

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

SubjectResolver turns the pseudonym of a user, as a result shows it, into the user's login. It is built for one tool call and dropped with it: it reads the tailnet's users on first use, holds them for the call, and is never kept or shared, since a long-lived process holding every login is the leak this design avoids. The logins it hands out are remembered, so that Hide can mask them where Tailscale's reply repeats them. The logins sit behind a function and Format, so that no fmt verb, no struct holding a resolver and no dumper that follows pointers reaches them. It is not safe for concurrent use.

func NewSubjectResolver added in v0.6.0

func NewSubjectResolver(env *registry.Env) *SubjectResolver

NewSubjectResolver returns a resolver for one call.

func (SubjectResolver) Format added in v0.6.0

func (SubjectResolver) Format(f fmt.State, _ rune)

Format keeps every login out of every format verb: fmt calls it before any other way of printing, so even the numeric verbs print "subject resolver". The receiver is a value, so both a SubjectResolver and a pointer to one print it.

func (*SubjectResolver) Hide added in v0.6.0

func (r *SubjectResolver) Hide(text string) string

Hide is the reverse map: it masks, in text that Tailscale wrote or echoed, every login this resolver has handed out, then every other address, all without pseudonyms. A reply repeats what was sent, and a pseudonym beside it would confirm a guess. The logins are replaced whole and longest first, so a login with a byte the address scan does not read (a slash) is not left half showing. A word glued to the front of a login (bigamy@ for amy@) is another user's address and is masked with it, from its first byte. A marker the text holds is rewritten (the masker's Unforge): Hide appends no pseudonym, so a marker in the result would be one the text forged, and the registry's masking pass does not rewrite it. The result is the head of what a caller sees, hideNeed bytes of it and the rest of the character they end in, whatever the logins in the text were: the text is read as far as it takes for the masked form to reach that, and the work is that of the masked head, not of the text (see read), and stops at hideMaxRead. While personalData is show the text is returned as it came.

func (*SubjectResolver) HideError added in v0.6.0

func (r *SubjectResolver) HideError(err error) error

HideError returns a copy of err, as a *tkerr.Error, with its message and hint passed through Hide. The code and the HTTP status are kept; the cause is dropped, since it may quote what Hide has just masked.

func (*SubjectResolver) Resolve added in v0.6.0

func (r *SubjectResolver) Resolve(ctx context.Context, ref string) (Login, error)

Resolve returns the login of the one user that ref names. ref is a pseudonym (p:…), the bracketed form, or a masked value ending in it. It is an error, validation_failed, when ref is none of these, when no user has the pseudonym (the user left, or the privacy key was replaced since the pseudonym was shown), or when several do. No message repeats ref.

func (*SubjectResolver) Shown added in v0.6.0

func (r *SubjectResolver) Shown(named bool) acl.Show

Shown is how a result of acl_diff or acl_validate shows a piece of a policy, as the engine takes it (acl.Show): the markers it holds are rewritten, every login this resolver has handed out is masked whole, and every other address is masked. With named, the addresses carry the pseudonym acl_get and users_list show for them; without it they carry none (a pseudonym beside an operator's own text would confirm a guess about it, and one beside an echo of a caller's text the same). The engine cuts what it quotes after this has run, so where it cuts is where the shown text says. While personalData is show the text is shown as it is, and the engine's cut is the only one.

func (*SubjectResolver) Typed added in v0.6.0

func (r *SubjectResolver) Typed(values ...string)

Typed tells the resolver what the caller typed, so that Hide does not treat a quotation of it as the echo of a login the call resolved (see typedValues). It adds to what was told before.

type Supports

type Supports struct {
	IPv6 *bool `json:"ipv6,omitempty"`
	PCP  *bool `json:"pcp,omitempty"`
	PMP  *bool `json:"pmp,omitempty"`
	UDP  *bool `json:"udp,omitempty"`
	UPnP *bool `json:"upnp,omitempty"`
}

Supports reports NAT traversal features (nil = unknown).

type SyspolicyOutput

type SyspolicyOutput struct {
	Scope    string   `json:"scope,omitempty" tk:"untrusted"`
	Policies []Policy `json:"policies" tk:"rows"`
}

SyspolicyOutput lists effective policies.

type User

type User struct {
	ID                 string `json:"id" tk:"col"`
	LoginName          string `json:"loginName" tk:"untrusted,col,personal"`
	DisplayName        string `json:"displayName,omitempty" tk:"untrusted,personal"`
	TailnetID          string `json:"tailnetId,omitempty" tk:"personal"`
	Created            string `json:"created,omitempty"`
	Type               string `json:"type" tk:"col"`
	Role               string `json:"role" tk:"col"`
	Status             string `json:"status" tk:"col"`
	DeviceCount        int    `json:"deviceCount" tk:"col"`
	LastSeen           string `json:"lastSeen,omitempty"`
	CurrentlyConnected bool   `json:"currentlyConnected"`
}

User is a tailnet user.

type UserInvite

type UserInvite struct {
	ID              string `json:"id" tk:"col"`
	Role            string `json:"role" tk:"col"`
	InviterID       int64  `json:"inviterId,omitempty"`
	Email           string `json:"email,omitempty" tk:"untrusted,col,personal"`
	LastEmailSentAt string `json:"lastEmailSentAt,omitempty" tk:"col"`
}

UserInvite is a user invite. inviteUrl is never returned.

type UserInvitesOutput

type UserInvitesOutput struct {
	Invites []UserInvite `json:"invites" tk:"rows"`
	Count   int          `json:"count"`
}

UserInvitesOutput lists open user invites.

type UserRef

type UserRef struct {
	ID string `json:"id" jsonschema:"user ID"`
}

UserRef names one user.

func (UserRef) Check added in v0.6.0

func (in UserRef) Check() error

Check refuses an ID that cannot be one, before anything is sent.

type UsersListInput

type UsersListInput struct {
	Type string `json:"type,omitempty" jsonschema:"member, shared or all (default all; the API's own default hides shared users)"`
	Role string `json:"role,omitempty" jsonschema:"owner, member, admin, it-admin, network-admin, billing-admin, auditor or all (default all)"`
}

UsersListInput filters users. Unlike the API, type defaults to all.

func (UsersListInput) Check added in v0.6.0

func (in UsersListInput) Check() error

Check refuses a type or a role Tailscale does not have, before anything is sent.

type UsersListOutput

type UsersListOutput struct {
	Users []User `json:"users" tk:"rows"`
	Count int    `json:"count"`
	Type  string `json:"type"`
}

UsersListOutput lists users.

type VersionOutput

type VersionOutput struct {
	CLI       string   `json:"cli" tk:"untrusted"`
	Daemon    string   `json:"daemon,omitempty" tk:"untrusted"`
	OSVariant string   `json:"osVariant,omitempty" tk:"untrusted"`
	Skew      bool     `json:"skew" jsonschema:"CLI and daemon release versions differ"`
	Warnings  []string `json:"warnings" tk:"untrusted"`
}

VersionOutput reports CLI and daemon versions.

type Webhook

type Webhook struct {
	EndpointID       string   `json:"endpointId" tk:"col"`
	EndpointHost     string   `json:"endpointHost" tk:"untrusted,col,plain"`
	EndpointPathHash string   `json:"endpointPathSha256,omitempty"`
	ProviderType     string   `json:"providerType,omitempty" tk:"col"`
	CreatorLoginName string   `json:"creatorLoginName,omitempty" tk:"untrusted,personal"`
	Created          string   `json:"created,omitempty"`
	LastModified     string   `json:"lastModified,omitempty"`
	Subscriptions    []string `json:"subscriptions"`
}

Webhook is a webhook endpoint. The secret is never returned, and the endpoint URL is reduced to scheme and host plus a hash of the path, because chat-provider webhook URLs carry a bearer token in the path.

type WebhookRef

type WebhookRef struct {
	ID string `json:"id" jsonschema:"webhook endpoint ID"`
}

WebhookRef names one webhook.

func (WebhookRef) Check added in v0.6.0

func (in WebhookRef) Check() error

Check refuses an ID that cannot be one, before anything is sent.

type WebhooksOutput

type WebhooksOutput struct {
	Webhooks []Webhook `json:"webhooks" tk:"rows"`
	Count    int       `json:"count"`
}

WebhooksOutput lists webhooks.

type WhoisInput

type WhoisInput struct {
	Address string `json:"address" jsonschema:"tailnet IP, or IP:port"`
	Proto   string `json:"proto,omitempty" jsonschema:"tcp or udp (with a port); empty means both"`
}

WhoisInput names a tailnet address, optionally with a port.

Jump to

Keyboard shortcuts

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