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

apilive

package
v3.4.0 Latest Latest
Warning

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

Go to latest
Published: Oct 30, 2026 License: MIT Imports: 10 Imported by: 0

Documentation

Overview

Package apilive is the committed record of what a booted GitLab says its own REST API is, and the one reader of it.

Every other oracle this repository holds about GitLab's REST API is a reading of text: the OpenAPI document GitLab commits to its own repository, or a scan of the Grape source that document is generated from. Both are downstream of the object that decides what a request returns, which is the Rails application with its classes loaded, and both lose the same thing when a name is not written down. GeoSiteStatus exposes its fields by iterating a constant assembled from two method calls: the source says "expose the loop variable", a scanner reads 26 fields, and GitLab sends 606. That is not a hole a better parser closes.

So this record is produced by asking the application. cmd/gen_api_live boots a released GitLab image, runs one script inside it, and writes what comes back here; every audit then reads this file with no Docker and no network, the way cmd/gen_graphql_schema's pin is read. The boot is a generator, never an audit: an audit that needed a container could not be a gate.

One thing evaluation does not give and the record therefore carries from source: a block condition is a Proc, and a Proc knows where it was written but not what it says. The generator reads those lines back from inside the same image, so a block condition arrives here both located and quoted. A hash or a symbol condition is the other way round: it holds what it tests, which the record keeps as its data or its option, and grape-entity keeps no location for it, so it arrives quoted and never located.

Since schema version 4 the record also says what a fine-grained personal access token needs: each route's authorization, the permission vocabulary a token is granted in, the anonymous policy on a public project and group, and what each GraphQL type, mutation and field demands (authorization.go). How a request this server sends is found among the record's routes, and what the route is called once found, is routes.go: the fine-grained derivation and R-GRANT both place requests by it, and must agree.

Since schema version 5 it says as well which routes reach a keyset paginator, and by which parameter their next page is asked when it serves one (keyset.go): GitLab reads pagination=keyset without declaring it, so only the code a route reaches can say, and the introspection walks that code inside the booted image.

Index

Constants

View Source
const (
	RouteSkipped    = "skipped"
	RouteAuthorized = "authorized"
	RouteTodo       = "todo"
	RouteUndeclared = "undeclared"
)

The classes a route falls into for a fine-grained token, in the order GitLab decides them: a skip reason disables the check whatever else the route declares, declared permissions are checked, a todo defers the decision, and a route declaring none of these is refused.

View Source
const (
	PublicSourceUnsaved   = "unsaved"
	PublicSourcePersisted = "persisted"
	PublicSourceFixture   = "fixture"
)

The ways the public subjects can be built, from cheapest to dearest: records the evaluation never writes, a project and group created inside the throwaway container, or the end-to-end fixture's.

View Source
const (
	// PaginatorStrategies is paginate_with_strategies, the helper that pages
	// by keyset when pagination=keyset: by `cursor` when the relation's model
	// declares keyset orderings, and by `id_after` and `id_before` when the
	// call passes `use_cursor: false` or the model declares none, where
	// anything but Project ordered by id answers 405. The model is the
	// relation's, which the walk cannot see, so a site records `cursor`
	// unless the call passes `use_cursor: false`, and on a model that
	// declares no keyset orderings that cursor is one GitLab never reads.
	PaginatorStrategies = "paginate_with_strategies"
	// PaginatorGitalyKeysetPager is Gitlab::Pagination::GitalyKeysetPager,
	// asked by `page_token`, for branches, tags, the tree and commits.
	PaginatorGitalyKeysetPager = "gitaly_keyset_pager"
	// PaginatorGitalyPagination is a finder executed with
	// `gitaly_pagination: true`, which pages through Gitaly by the same
	// `page_token` without the pager.
	PaginatorGitalyPagination = "gitaly_pagination"
	// PaginatorHeaderBuilder is a route writing its own keyset next link or
	// cursor headers through Gitlab::Pagination::Keyset::HeaderBuilder.
	PaginatorHeaderBuilder = "keyset_header_builder"
	// PaginatorKeysetPaginate is a relation paged with keyset_paginate.
	PaginatorKeysetPaginate = "keyset_paginate"
)

The paginators a keyset site names, as introspect.rb spells them.

View Source
const (
	// ProbedCursorPager is CursorPager, which paginate_with_strategies uses
	// for a model declaring keyset orderings.
	ProbedCursorPager = "cursor_pager"
	// ProbedPager is Keyset::Pager, which it uses otherwise.
	ProbedPager = "pager"
	// ProbedGitalyKeysetPager is GitalyKeysetPager.
	ProbedGitalyKeysetPager = "gitaly_keyset_pager"
	// ProbedCursorHeaders is the parameter the X-NEXT-CURSOR header is sent
	// back as, read off the CursorPager answer that writes both.
	ProbedCursorHeaders = "cursor_headers"
)

The keys of Document.KeysetPaginators: the paginators the introspection asks which parameter their next link names.

View Source
const (
	// TierPremium unlocks with any paid plan from Premium up.
	TierPremium = "premium"
	// TierUltimate unlocks with Ultimate only.
	TierUltimate = "ultimate"
	// TierGlobal is the table's GLOBAL_FEATURES: licensed, but not a tier,
	// since every paid plan carries it.
	TierGlobal = "global"
)

Tier values, matching the licensed feature table's own three lists.

View Source
const DefaultDir = "docs/development"

DefaultDir is where the record lives, beside the other pinned records.

View Source
const EndpointPrefix = "/api/:version"

EndpointPrefix is what Grape mounts every route under. A caller writes /projects/:id and Grape holds /api/:version/projects/:id, so one of the two spellings has to give, and it is this one: the inventory records what the SDK sent, which is what a reader of a finding will go looking for.

View Source
const FileName = "gitlab-api-live.json"

FileName is the record's name on disk.

View Source
const SchemaVersion = 5

SchemaVersion is the shape of this record. A reader refuses a version it was not written for rather than guessing at a field that moved.

Version 2 records Field.Merge. The bump is not cosmetic: version 1 spelled a merged exposure exactly like a nested one, so a reader of an old record would resolve it into the wrong keys and never know, which is the one failure a version guard exists to stop.

Version 3 records what a hash or a symbol condition tests, Condition.Hash and Condition.Symbol. Version 2 had the hash key and never filled it, and had no key for a symbol at all, so every such condition reached the record as its kind alone: 41 of the 914 on 19.3.1-ee, each the only gate on its field. A reader of that record would take those 41 fields for unconditional, which is the same silent inversion version 2 was cut for.

Version 4 records fine-grained authorization: Route.Authorization, Document.Granular and Document.GraphQLAuthz. In version 4 a route with no authorization declares nothing, so a fine-grained token is refused there; in version 3 the same absence meant "not recorded". A reader taking a version 3 record for version 4 would deny every route, which is the silent inversion the version exists to stop.

Version 5 records keyset pagination: Route.Keyset and Document.KeysetPaginators. In version 5 a route with no keyset reaches no keyset paginator, so GitLab answers it with an offset page whatever pagination says; in version 4 the same absence meant "not recorded". A reader taking a version 4 record for version 5 would call every keyset route an offset one.

Variables

This section is empty.

Functions

func ExpandOptional added in v3.2.0

func ExpandOptional(path string) []string

ExpandOptional spells a Grape path with each optional group, written in parentheses, taken and left out: `:id/(-/)epics` is both `:id/epics` and `:id/-/epics`. An escaped parenthesis is a literal, not a group, a closing one outside every group is a literal too, and a group that never closes leaves the path as written.

func KnownBoundaryType added in v3.2.0

func KnownBoundaryType(boundaryType string) bool

KnownBoundaryType reports whether a boundary type is one GitLab resolves.

func KnownPublicSource added in v3.2.0

func KnownPublicSource(source string) bool

KnownPublicSource reports whether a public set names one of the three ways it may be produced.

func LicensedFeatures

func LicensedFeatures(condition string) []string

LicensedFeatures names the features a condition asks a license about, in order of appearance and without repeats.

A symbol found here is not necessarily licensed: feature_available?(:issues) asks a project setting, not a plan. Document.Tier is what tells them apart, because only the licensed feature table can.

func NormalizePath

func NormalizePath(path string) string

NormalizePath trims the mount prefix off a route, leaving the path a caller writes.

Grape's own placeholders are already the spelling the request inventory records (:id, :user_id), so nothing else has to be rewritten. That is a property of asking the router rather than reading a generated document: the OpenAPI record spells the same placeholder {id} and had to be translated.

func OpenAPIName

func OpenAPIName(rubyName string) string

OpenAPIName is the entity's Ruby name in the spelling GitLab's OpenAPI document gives its schema, so a reader holding one can look up the other.

API::Entities::Ci::Variable becomes APIEntitiesCiVariable: the separators go and the segments keep their own casing.

func Paginators added in v3.4.0

func Paginators() []string

Paginators lists every paginator a keyset site may name, in the order they are documented above.

func Path

func Path(dir string) string

Path is where the record lives under a repository root.

func PathSegments added in v3.2.0

func PathSegments(path string) []string

PathSegments splits a path into segments, each identifier or splat collapsed to the placeholder ":", so two spellings of one endpoint that name their parameters differently meet.

func Probed added in v3.4.0

func Probed() []string

Probed lists every paginator the keyset_paginators block must answer for.

func RouteName added in v3.2.0

func RouteName(route *Route) string

RouteName spells a record route the way the fine-grained table and the request record name it: the verb and the path under the API prefix, with parameters named as GitLab names them ("GET /projects/:id/issues").

func Write

func Write(dir string, doc Document) error

Write commits the record, formatted so a re-pin is a readable diff rather than one very long line.

Types

type AbstractType added in v3.2.0

type AbstractType struct {
	Kind          string   `json:"kind"`
	PossibleTypes []string `json:"possible_types"`
}

AbstractType is a union or an interface.

type AdditionalScope added in v3.2.0

type AdditionalScope struct {
	Permissions   []string  `json:"permissions,omitempty"`
	BoundaryType  string    `json:"boundary_type,omitempty"`
	BoundaryParam string    `json:"boundary_param,omitempty"`
	Boundary      *Callable `json:"boundary,omitempty"`
	UnknownKeys   []string  `json:"unknown_keys,omitempty"`
}

AdditionalScope is one further requirement a route declares, judged on its own boundary: a boundary alternative's keys and permissions of its own.

type Assignable added in v3.2.0

type Assignable struct {
	Name         string `json:"name"`
	Category     string `json:"category"`
	CategoryName string `json:"category_name"`
	Resource     string `json:"resource"`
	ResourceName string `json:"resource_name"`
	Action       string `json:"action"`
	// Display is "Resource: Action" exactly as GitLab writes it in a refusal.
	Display string `json:"display"`
	// Boundaries are the boundary types the permission can be granted at.
	Boundaries []string `json:"boundaries"`
	// Permissions are the raw permissions it expands to.
	Permissions []string `json:"permissions"`
	// AvailableFor names who may hold it: granular_access_token, role, or
	// both.
	AvailableFor   []string              `json:"available_for"`
	Deprecated     bool                  `json:"deprecated,omitempty"`
	AssignableWhen []AssignableCondition `json:"assignable_when,omitempty"`
}

Assignable is one permission a user can grant a token.

type AssignableCondition added in v3.2.0

type AssignableCondition struct {
	Condition  string   `json:"condition"`
	Boundaries []string `json:"boundaries,omitempty"`
}

AssignableCondition is one condition under which GitLab offers an assignable permission in its token form.

type AssignableMatch added in v3.2.0

type AssignableMatch struct {
	// First is the first definition that expands to the raw permission,
	// deprecated ones included, which is the name GitLab's refusal prints.
	First string `json:"first"`
	// FirstAvailable is the first one a token can be granted: not deprecated
	// and available to a granular access token. Empty when there is none.
	FirstAvailable string `json:"first_available,omitempty"`
}

AssignableMatch is the assignable GitLab names for one raw permission, read two ways.

type AuthorizationCounts added in v3.2.0

type AuthorizationCounts struct {
	AuthorizedRoutes                int `json:"authorized_routes"`
	SkippedRoutes                   int `json:"skipped_routes"`
	TodoRoutes                      int `json:"todo_routes"`
	UndeclaredRoutes                int `json:"undeclared_routes"`
	AssignablePermissions           int `json:"assignable_permissions"`
	DeprecatedAssignablePermissions int `json:"deprecated_assignable_permissions"`
	GraphQLDeclaredTypes            int `json:"graphql_declared_types"`
	// GraphQLUndeclaredTypes are the types GitLab checks and that declare
	// nothing. A fine-grained token is denied an object of every one of them
	// but two: Query and Mutation are counted here and pass, because the
	// check passes when there is neither an object nor arguments to find a
	// boundary in, which is what a root is. A reader taking this figure, or
	// Enforced without Declared, for "denied" has to set those two apart.
	GraphQLUndeclaredTypes int `json:"graphql_undeclared_types"`
	// GraphQLUncheckedUndeclaredTypes are the ones GitLab's todo rule calls
	// undeclared and its check never runs on, such as PageInfo.
	GraphQLUncheckedUndeclaredTypes int `json:"graphql_unchecked_undeclared_types"`
	GraphQLDeclaredMutations        int `json:"graphql_declared_mutations"`
	GraphQLUndeclaredMutations      int `json:"graphql_undeclared_mutations"`
}

AuthorizationCounts are the fine-grained figures of a record, beside the entity, field, route and feature counts its provenance already carries.

func (AuthorizationCounts) String added in v3.2.0

func (c AuthorizationCounts) String() string

String renders the fine-grained figures as the one line a gate reports beside the provenance.

type Boundary added in v3.2.0

type Boundary struct {
	BoundaryType  string    `json:"boundary_type,omitempty"`
	BoundaryParam string    `json:"boundary_param,omitempty"`
	Boundary      *Callable `json:"boundary,omitempty"`
	UnknownKeys   []string  `json:"unknown_keys,omitempty"`
}

Boundary is one boundary alternative a route accepts.

type Callable added in v3.2.0

type Callable struct {
	Callable bool   `json:"callable"`
	File     string `json:"file,omitempty"`
	Line     int    `json:"line,omitempty"`
	Text     string `json:"text,omitempty"`
}

Callable is a boundary given as code GitLab runs per request. What it returns is known only then, so the record locates and quotes it, the way it does a block condition.

type Condition

type Condition struct {
	// Kind is Grape's own class name for it: BlockCondition for a lambda,
	// HashCondition for `if: {…}`, SymbolCondition for `if: :option`.
	Kind string `json:"kind"`
	// Inverse is true for `unless:`.
	Inverse bool `json:"inverse,omitempty"`
	// File and Line locate a block condition's lambda, repository relative.
	// A hash or a symbol condition carries neither: grape-entity keeps the
	// options it tests and nothing about where the exposure declaring it was
	// written, and the exposure records no location of its own either.
	File string `json:"file,omitempty"`
	Line int    `json:"line,omitempty"`
	// Text is those lines read back from inside the image and squeezed onto
	// one. A Proc knows where it was written and not what it says, so this is
	// the only way the condition arrives readable, and it is what a rule
	// classifies on.
	Text string `json:"text,omitempty"`
	// Hash is a hash condition's own data, as Ruby inspects it: the options
	// the presenter must be given, and the values they must hold.
	Hash string `json:"hash,omitempty"`
	// Symbol is a symbol condition's option, without its colon: the field is
	// sent when the presenter is given that option with a truthy value, which
	// is a choice of the endpoint rendering it and never of the entity.
	Symbol string `json:"symbol,omitempty"`
}

Condition is one gate on an exposure.

func (Condition) Describe added in v3.1.0

func (c Condition) Describe() string

Describe renders the condition the way a finding quotes it.

A block condition is its own text, which already reads as written. A symbol and a hash condition are spelled the way Grape declares them, `if: :option` and `if: {…}`, or `unless:` for an inverse one, because the bare option name reads as a field rather than as a gate. A condition carrying none of the three is never rendered as nothing: it is named by its kind, so a field it gates reads as gated by something unreadable rather than as gated by nothing, which is the opposite of what the record holds.

func (Condition) Readable added in v3.1.0

func (c Condition) Readable() bool

Readable reports whether the condition says what it tests: a block condition's text, a hash condition's data or a symbol condition's option.

One that carries none of them still gates its field, since Grape skips the exposure whenever it fails, but by something the record cannot name. That is what an introspection produces when it meets a condition kind it does not read, and it is what version 2 of the record did to every hash and symbol condition it held.

type Directive added in v3.2.0

type Directive struct {
	Permissions      []string `json:"permissions,omitempty"`
	BoundaryType     string   `json:"boundary_type,omitempty"`
	Boundary         string   `json:"boundary,omitempty"`
	BoundaryArgument string   `json:"boundary_argument,omitempty"`
	RequirementGroup string   `json:"requirement_group,omitempty"`
	AssignableWhen   []string `json:"assignable_when,omitempty"`
	SkipReason       string   `json:"skip_reason,omitempty"`
	UnknownKeys      []string `json:"unknown_keys,omitempty"`
}

Directive is one GranularScope directive, argument for argument.

type Document

type Document struct {
	SchemaVersion int    `json:"schema_version"`
	Note          string `json:"note"`
	Source        Source `json:"source"`
	// Entities is every API::Entities class the instance had loaded, keyed by
	// its Ruby name (API::Entities::Project). OpenAPIName translates that to
	// the spelling the OpenAPI record uses, for a reader joining the two.
	Entities map[string]Entity `json:"entities"`
	// Routes is every endpoint Grape had mounted, in the order the router
	// holds them.
	Routes []Route `json:"routes"`
	// Features maps a licensed feature symbol to the tier that unlocks it.
	Features map[string]string `json:"features"`
	// Granular is the permission vocabulary a fine-grained token is granted
	// in, and GraphQLAuthz what the GraphQL schema demands of one. A version 4
	// record without either cannot answer what a fine-grained token reaches,
	// and the gate refuses it.
	Granular     *Granular     `json:"granular,omitempty"`
	GraphQLAuthz *GraphQLAuthz `json:"graphql_authz,omitempty"`
	// KeysetPaginators maps each of GitLab's keyset paginators, one of
	// [Probed], to the parameters its next link names, as the paginator
	// answered when the introspection had it write one. A version 5 record
	// without it was written by an introspection that does not walk keyset
	// pagination, and the gate refuses it.
	KeysetPaginators map[string][]string `json:"keyset_paginators,omitempty"`
}

Document is the committed record.

func Read

func Read(dir string) (Document, error)

Read loads the committed record.

A schema version this build was not written for is refused rather than decoded: the fields would parse and mean something else, which is the one failure a reader cannot detect later.

func (Document) CountAuthorization added in v3.2.0

func (d Document) CountAuthorization() AuthorizationCounts

CountAuthorization totals the fine-grained figures the provenance carries.

func (Document) CursorParameters added in v3.4.0

func (d Document) CursorParameters() []string

CursorParameters is every parameter the record says a next page can be asked by: what each probed paginator names and what each site names. A route declaring one of them is one that says it pages by keyset.

func (Document) FieldCount

func (d Document) FieldCount() int

FieldCount totals the exposures across every entity, which is the figure a floor is set against: a record that lost half its fields is one an audit would read as GitLab having stopped sending them.

func (Document) FieldNames

func (d Document) FieldNames(entity string) []string

FieldNames lists the keys an entity sends, sorted, and nil for one this record does not hold. It is what an audit holds a response against.

func (Document) Fields

func (d Document) Fields(entity string) (map[string]Field, bool)

Fields is the entity's exposures by the key GitLab sends, the last declaration of a name winning as Grape's own render does, and false for an entity this record does not hold.

Inheritance needs no resolving here: the introspection reads root_exposures, which is the class as it will render, with everything it inherits and everything an Enterprise module prepended already flattened in. The scanned record this replaced had to walk a parent chain to reach the same list, and could not see a prepend it had no file for. Merging is the one edge that still has to be followed, and Document.Resolve follows it.

func (Document) GateOf

func (d Document) GateOf(field Field) Gate

GateOf reads what a field's conditions demand, resolving the tier against this record's own licensed feature table.

Every condition contributes, a hash or a symbol one through the data it carries and one the record could not read through its kind, since Grape skips the exposure whenever any of them fails. Dropping one that carries no text is how 41 fields gated by an option or a license came to read as sent on every response.

func (Document) HoldsDenial added in v3.2.0

func (d Document) HoldsDenial(denial *finegrained.Denial) bool

HoldsDenial reports whether the element a denial names is one the record holds, of the kind its cause says it is: a route for a REST cause, a mutation for an undeclared mutation, an object, union or interface type for a position, and either a type or a mutation for a boundary that never resolves, which a declaration may say of a mutation's own check. A denial naming something the record does not hold was decided by nothing GitLab declared.

Two readers ask it, and they must agree: the fine-grained derivation, whose gate 2 refuses such a denial as it joins the table, and R-GRANT, which reads the committed table back and asks the same question of it. Both ask it of every denial a row carries, the action's and each denied way's.

func (Document) KeysetRoutes added in v3.4.0

func (d Document) KeysetRoutes() int

KeysetRoutes counts the routes whose code reaches a keyset paginator, the figure the source block carries and a floor is set against.

func (Document) Names

func (d Document) Names() []string

Names lists the entities in a stable order.

func (Document) NestedNames

func (d Document) NestedNames(entity string) map[string][]string

NestedNames is, for each field of the entity that renders with an entity of its own, the keys that child sends.

This is the tree the record carries and a generated OpenAPI document flattens: `expose :author, using: Entities::UserBasic` says exactly which object sits under `author`, so a nested comparison joins on the edge rather than on a property name that happened to describe an object.

func (Document) Resolve

func (d Document) Resolve(entity string) ([]Field, bool)

Resolve is the entity's exposures in declaration order with every merged one replaced by the fields it contributes, and false for an entity this record does not hold.

A merged exposure sends its child's keys on the parent object and no key of its own, so it is the one place where the exposure list and the response differ. Reading it literally inverts both halves of a comparison at once: API::Entities::Member merges UserBasic, and an audit reading the raw list reported `user` as a key GitLab sends and we drop, while reporting the id, username, name, state and avatar_url we do publish as keys GitLab never sends.

A merged exposure's own conditions gate everything it contributes, since Grape skips the whole exposure when they fail, so they are carried onto each promoted field ahead of that field's own.

func (Document) RoutesByEntity

func (d Document) RoutesByEntity() map[string][]Route

RoutesByEntity indexes the endpoints each entity is annotated on, which is the join an audit walks: from a type, to the entity it models, to the endpoints that render it.

func (Document) Tier

func (d Document) Tier(features ...string) string

Tier resolves the highest tier the named features unlock at.

Ultimate wins over premium, and premium over global, because a field gated by two features needs the dearer plan. A feature the table does not list resolves to nothing: a project setting such as :issues is not a license.

type Entity

type Entity struct {
	// Error is set when the class refused to describe itself, which is a fact
	// about that class rather than a reason to drop it: a silently missing
	// entity reads as one GitLab does not have.
	Error string `json:"error,omitempty"`
	// Fields are the exposures in declaration order, with everything the
	// class inherits already flattened in, because root_exposures answers for
	// the class as it will render.
	Fields []Field `json:"fields,omitempty"`
}

Entity is one Grape entity as the loaded class describes itself.

type Field

type Field struct {
	// Name is the key GitLab sends.
	Name string `json:"name"`
	// Attribute is the method the value comes from, recorded only when `as:`
	// made it differ from Name: the key is what a client sees and the
	// attribute is what a reader greps the source for.
	Attribute string `json:"attribute,omitempty"`
	// Using names the entity the value renders with, in the same keying as
	// Document.Entities. It is the edge that makes the record a tree rather
	// than a list.
	Using string `json:"using,omitempty"`
	// Merge is set for an exposure whose value is merged into the object
	// around it instead of being placed under Name: `expose :user, merge:
	// true, using: UserBasic` on a member sends the user's own keys on the
	// member, and no `user` key at all.
	//
	// Recording it is what keeps the record from reading as the opposite of
	// what GitLab sends. Without it a member said it carries a `user` object
	// and said nothing about the id, username and name it really carries, so
	// an audit reported the one key GitLab never sends as missing and the
	// nine it does send as invented.
	Merge bool `json:"merge,omitempty"`
	// Conditions gate the field. Empty means GitLab sends it with every
	// response of every endpoint that renders this entity.
	Conditions []Condition `json:"conditions,omitempty"`
}

Field is one exposure.

type Gate

type Gate struct {
	// If and Unless are the conditions as [Condition.Describe] renders them,
	// joined with " && " when a field carries several, since Grape requires
	// all of them to pass.
	If     string
	Unless string
	// Tier is the highest plan the conditions demand, empty when they demand
	// none.
	Tier string
	// Edition is "ee" when a condition was written under ee/, which is where
	// Enterprise prepends live.
	//
	// It is read from the condition's own file, so a field with no condition
	// has no location to answer from and reports nothing: an exposure records
	// where its lambda was written and not where the exposure itself was.
	//
	// Only a block condition has a file. A hash or a symbol condition carries
	// none, so a field gated by one of those alone never answers "ee", even
	// when the exposure was written under ee/: an epic's reference, gated by
	// `if: { with_reference: true }` in ee/lib/api/entities/epic.rb, reads
	// with no edition. Empty therefore means "no located condition said so",
	// never "written outside ee/".
	Edition string
}

Gate is what a field's conditions amount to, in the terms a finding reports.

func (Gate) Gated

func (g Gate) Gated() bool

Gated reports whether the field is sent under any condition at all.

It holds for every field that carries a condition, readable or not, because Document.GateOf renders each one through Condition.Describe, which never returns nothing. It used to fall false for a field whose only condition carried no text, and so reported the opposite of what the record holds.

type Granular added in v3.2.0

type Granular struct {
	// Assignable are the permissions a user grants, deprecated ones kept so a
	// grant written under an older name still reads, in the file-path order
	// GitLab searches them.
	Assignable []Assignable `json:"assignable"`
	// RawPermissions are every raw permission GitLab defines.
	RawPermissions []string `json:"raw_permissions"`
	// RawToAssignable maps each raw permission some assignable expands to
	// onto the assignable GitLab names for it.
	RawToAssignable map[string]AssignableMatch `json:"raw_to_assignable"`
	// PublicAnonymous is what an anonymous caller may do on a public project
	// and group, which GitLab serves to a token whatever its grant holds.
	// Absent when the evaluation could not run, which PublicAnonymousError
	// then explains.
	PublicAnonymous      *PublicAnonymous `json:"public_anonymous,omitempty"`
	PublicAnonymousError string           `json:"public_anonymous_error,omitempty"`
	// FlagDefaultEnabled is whether fine-grained tokens are on unless an
	// administrator turns them off.
	FlagDefaultEnabled *bool `json:"flag_default_enabled,omitempty"`
}

Granular is the permission vocabulary a fine-grained token is granted in.

func (*Granular) Expandable added in v3.2.0

func (g *Granular) Expandable() map[string]bool

Expandable lists every raw permission some assignable expands to, which is the only set a route or a directive may name and the only one GitLab's public bypass is defined over.

type GraphQLAuthz added in v3.2.0

type GraphQLAuthz struct {
	// Types are every object type, keyed by its GraphQL name.
	Types map[string]GraphQLType `json:"types"`
	// Abstract are every union and interface with the object types GitLab may
	// resolve there.
	Abstract map[string]AbstractType `json:"abstract"`
	// Mutations are keyed by the field name a document uses.
	Mutations map[string]Mutation `json:"mutations"`
	// Fields are the field-level declarations, keyed Type.field.
	Fields map[string][]Directive `json:"fields"`
	// UndeclaredByTodoRule is the set GitLab's own rule for its todo list
	// computes, so the two can be held to each other.
	UndeclaredByTodoRule TodoSet `json:"undeclared_by_todo_rule"`
	// Todo is GitLab's list of what it has not declared yet, when the image
	// ships it.
	Todo *Todo `json:"todo,omitempty"`
}

GraphQLAuthz is what the GraphQL schema demands of a fine-grained token.

type GraphQLType added in v3.2.0

type GraphQLType struct {
	Class string `json:"class,omitempty"`
	// Enforced is whether GitLab's granular check runs on an object of the
	// type. A type outside Types::BaseObject, or one overriding authorized?
	// without calling super, is never checked whatever it declares. Query and
	// Mutation are enforced and declare nothing, and pass anyway: the check
	// passes when there is neither an object nor arguments to find a
	// boundary in, which is what the root objects are.
	Enforced bool `json:"enforced,omitempty"`
	// AuthorizedBy names the override of authorized?, when there is one.
	AuthorizedBy string `json:"authorized_by,omitempty"`
	// Abilities are the type's ability authorization, one of the two
	// conditions under which a list of it is redacted rather than nulled.
	Abilities []string    `json:"abilities,omitempty"`
	Granular  []Directive `json:"granular,omitempty"`
	// ObjectFields are the fields whose type is an object, an interface or a
	// union, with their full signature.
	ObjectFields map[string]ObjectField `json:"object_fields,omitempty"`
}

GraphQLType is one object type.

func (GraphQLType) Declared added in v3.2.0

func (t GraphQLType) Declared() bool

Declared reports whether the type carries a GranularScope directive, a skip reason included, which is what GitLab's todo rule counts as declared.

type KeysetFlag added in v3.4.0

type KeysetFlag struct {
	Name string `json:"name"`
	// DefaultEnabled is whether GitLab turns the flag on unless an
	// administrator turns it off, and nil when GitLab defines no such flag.
	DefaultEnabled *bool `json:"default_enabled,omitempty"`
}

KeysetFlag is a feature flag a keyset site is behind.

type KeysetSite added in v3.4.0

type KeysetSite struct {
	// Paginator is what would serve the page, one of [Paginators].
	Paginator string `json:"paginator"`
	// File and Line locate the call, repository relative, and Text is that
	// line read back from the image.
	File string `json:"file"`
	Line int    `json:"line"`
	Text string `json:"text,omitempty"`
	// Via names the helpers the walk went through from the route's block to
	// the call, outermost first, and is empty when the block makes it.
	Via []string `json:"via,omitempty"`
	// Cursor is the parameter, or the pair, the next page is asked by when
	// the paginator serves one. At a [PaginatorStrategies] site it is the
	// cursor of the paginator a model with keyset orderings gets, unless the
	// call passes `use_cursor: false`.
	Cursor []string `json:"cursor,omitempty"`
	// Flags are the feature flags the call is behind, in the two shapes the
	// walk reads them in: `if Feature.enabled?(:flag)` or
	// `unless Feature.disabled?(:flag)`.
	Flags []KeysetFlag `json:"flags,omitempty"`
}

KeysetSite is one place a route's code calls a keyset paginator, which is where GitLab can serve the route a keyset page (see the top of this file for why that is not the same as saying it does).

func (KeysetSite) OnByDefault added in v3.4.0

func (s KeysetSite) OnByDefault() bool

OnByDefault reports whether the site is reached on an instance nobody has configured: it is behind no flag, or behind none GitLab ships off. A flag GitLab does not define is taken as off, since Feature.enabled? answers false for one.

type Mutation added in v3.2.0

type Mutation struct {
	// Name is the mutation's GraphQL name, the key GitLab's todo list uses.
	Name    string `json:"name"`
	Class   string `json:"class"`
	Payload string `json:"payload"`
	// Granular is what GitLab's runtime check reads, the mutation class's own
	// directives, and is empty for a mutation that declares nothing, which a
	// fine-grained token is refused.
	Granular []Directive `json:"granular,omitempty"`
	// FieldGranular is what GitLab's permission task reads for the mutation,
	// the Mutation field's directives (which graphql-ruby answers with any the
	// field declares itself followed by the class's), recorded only where it
	// differs from Granular. The task's todo list is generated from this
	// reading and the runtime check never makes it, so the gate refuses a
	// record carrying one: the todo list and what a token is refused would
	// then describe two requirements. Empty for every mutation at 19.4.1.
	FieldGranular []Directive `json:"field_granular,omitempty"`
}

Mutation is one mutation field.

type ObjectField added in v3.2.0

type ObjectField struct {
	// Type is the signature as GraphQL writes it: [T!]!, [T], T!.
	Type       string `json:"type"`
	Connection bool   `json:"connection,omitempty"`
}

ObjectField is one object-typed field.

func (ObjectField) NamedType added in v3.2.0

func (f ObjectField) NamedType() string

NamedType is the type a signature names, without its list and non-null wrappers.

type Param

type Param struct {
	Required bool   `json:"required,omitempty"`
	Type     string `json:"type,omitempty"`
	Default  string `json:"default,omitempty"`
	Desc     string `json:"desc,omitempty"`
}

Param is one declared parameter.

type PublicAnonymous added in v3.2.0

type PublicAnonymous struct {
	// Source says how the subjects were built.
	Source string `json:"source"`
	// Licensed is set when every licensed feature was made available for the
	// evaluation, so the set is the widest a licensed instance serves.
	Licensed bool     `json:"licensed,omitempty"`
	Project  []string `json:"project"`
	Group    []string `json:"group"`
}

PublicAnonymous is GitLab's evaluated anonymous policy on a public project with every feature enabled and on a public group, over the raw permissions some assignable expands to.

type Requirement added in v3.2.0

type Requirement struct {
	Permissions []string
	Any         finegrained.Boundary
}

Requirement is one requirement a route checks on its own: every raw permission in Permissions, sorted, held at one boundary type among Any.

type Route

type Route struct {
	Method string `json:"method"`
	// Path is Grape's origin, without the (.:format) suffix the router adds,
	// since no caller sends that.
	Path string `json:"path"`
	// Entity is what the endpoint's `desc … success/entity` annotation names,
	// which is the same annotation GitLab's OpenAPI generator reads. It can be
	// wrong about what the endpoint really presents, and being wrong in the
	// record is better than being absent: GET /keys is annotated
	// APIEntitiesUserWithAdmin and serves an SSH key with a user under it.
	Entity  string `json:"entity,omitempty"`
	Summary string `json:"summary,omitempty"`
	// Params is what the endpoint declares it accepts, keyed by name.
	Params map[string]Param `json:"params,omitempty"`
	// Authorization is what the route demands of a fine-grained token. nil
	// means it declares nothing, which GitLab answers a fine-grained token by
	// refusing it.
	Authorization *RouteAuthorization `json:"authorization,omitempty"`
	// Keyset is every place the code the route reaches calls a keyset
	// paginator, which is where GitLab can serve the route a keyset page:
	// whether it does also depends on the relation's model and the order
	// asked for, which the record does not say ([KeysetSite]). Empty means it
	// reaches none, so GitLab ignores pagination=keyset there and answers an
	// offset page.
	Keyset []KeysetSite `json:"keyset,omitempty"`
}

Route is one mounted endpoint.

func (Route) Cursors added in v3.4.0

func (r Route) Cursors() []string

Cursors lists, sorted and once each, the parameters any of the route's keyset sites is asked by.

func (Route) FineGrained added in v3.2.0

func (r Route) FineGrained() string

FineGrained is the class the route falls into for a fine-grained token.

Written as a chain of returns rather than a tagless switch so that every test is a statement of its own, which is what lets the mutation gate see that each one is reached.

func (Route) PagesByKeyset added in v3.4.0

func (r Route) PagesByKeyset() bool

PagesByKeyset reports whether any code the route reaches calls a keyset paginator. In version 5 a route that reaches none is one GitLab answers with an offset page whatever pagination says. One that reaches one can still answer a keyset request with 405, by the relation's model or by the order asked for, which the record does not say.

func (Route) Requirements added in v3.2.0

func (r Route) Requirements() (groups []Requirement, skip bool, denied finegrained.Cause)

Requirements reads what a route demands of a fine-grained token: its primary requirement and then one per additional scope, each once, since a route naming one permission at one boundary twice demands it once; whether the grant decides the route at all; and why no fine-grained token passes it when none does.

Two readers ask it, and they must agree: the fine-grained derivation joins every REST request by it, and R-GRANT reads each REST operation of the committed table back against it.

type RouteAuthorization added in v3.2.0

type RouteAuthorization struct {
	// Permissions are raw permission names, the vocabulary GitLab checks a
	// token's expanded grant against, never the assignable names a user
	// grants.
	Permissions []string `json:"permissions,omitempty"`
	// BoundaryType is project, group, user or instance, and BoundaryParam the
	// request parameter naming the project or group when it is not the
	// default (project_id or group_id, then id).
	BoundaryType  string `json:"boundary_type,omitempty"`
	BoundaryParam string `json:"boundary_param,omitempty"`
	// Boundaries are alternatives: the token passes when it holds every
	// permission on any one of them.
	Boundaries []Boundary `json:"boundaries,omitempty"`
	// Boundary is a callable GitLab evaluates per request, which wins over
	// Boundaries and BoundaryType whenever the route declares one.
	Boundary *Callable `json:"boundary,omitempty"`
	// AdditionalScopes must each pass on their own, on top of the primary
	// requirement.
	AdditionalScopes []AdditionalScope `json:"additional_scopes,omitempty"`
	// Skip is the reason the route opts out of the fine-grained check. Any
	// reason disables it, so the grant does not decide such a route.
	Skip string `json:"skip,omitempty"`
	// Todo defers the decision; a fine-grained token is denied meanwhile.
	Todo string `json:"todo,omitempty"`
	// AssignableWhen names the conditions under which GitLab offers the
	// permission in its token form. It describes and never enforces.
	AssignableWhen []string `json:"assignable_when,omitempty"`
	// UnknownKeys are keys of the hash no reader here understands, recorded
	// so a new option is seen rather than dropped.
	UnknownKeys []string `json:"unknown_keys,omitempty"`
}

RouteAuthorization is what a route's `route_setting :authorization` declares for a fine-grained token, key for key as lib/api/helpers.rb reads it. A route with none declares nothing a fine-grained token can satisfy.

type RouteIndex added in v3.2.0

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

RouteIndex finds the record's route for a path a request was sent to.

func NewRouteIndex added in v3.2.0

func NewRouteIndex(routes []Route) *RouteIndex

NewRouteIndex indexes routes, every spelling Grape's optional groups allow of each. A route mounted outside the API prefix is no route a request of this server's reaches, and is left out.

func (*RouteIndex) Match added in v3.2.0

func (index *RouteIndex) Match(method, path string) (*Route, bool)

Match finds the record route a request's path is: the one spelling whose segments equal the request's, a record placeholder standing for a literal of the request's where it must; the closest, by literal segments in common, when several do, and the first in the record's order among equally close ones. It reports false for a path no route of the verb meets.

type Source

type Source struct {
	Image       string `json:"image"`
	Digest      string `json:"digest,omitempty"`
	Version     string `json:"version"`
	Revision    string `json:"revision,omitempty"`
	RetrievedAt string `json:"retrieved_at"`
	// SHA256 is of the introspection output as it left the container, before
	// this record wrapped it, so two runs of one image can be compared without
	// the wrapper's own fields entering the digest.
	SHA256   string `json:"sha256"`
	Entities int    `json:"entities"`
	Fields   int    `json:"fields"`
	Routes   int    `json:"routes"`
	Features int    `json:"features"`
	// AuthorizationCounts are the fine-grained figures, counted from the
	// record when it is written.
	AuthorizationCounts
	// KeysetRoutes counts the routes whose code reaches a keyset paginator,
	// from the record when it is written.
	KeysetRoutes int `json:"keyset_routes"`
}

Source is the instance the record was taken from.

The image reference and the version are both recorded because they answer different questions: the reference is what to run to reproduce this, and the version is what to compare against a GitLab release. A record whose version is behind the current release is stale in the sense that matters, and no amount of re-running the same image fixes it.

func (Source) String

func (s Source) String() string

String renders the provenance as one reportable line.

type Todo added in v3.2.0

type Todo struct {
	Digest string `json:"digest"`
	TodoSet
	// UnknownEntries are lines of a kind other than type: and mutation:.
	UnknownEntries []string `json:"unknown_entries,omitempty"`
}

Todo is GitLab's config/authz/graphql/authorization_todo.txt as the image ships it.

type TodoSet added in v3.2.0

type TodoSet struct {
	Types     []string `json:"types"`
	Mutations []string `json:"mutations"`
}

TodoSet is a set of type and mutation names.

Jump to

Keyboard shortcuts

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