Documentation
¶
Overview ¶
Package gitlab implements the gitlab source plugin: lists projects ("repositories") and members under a single GitLab group and emits the cross-vendor git_repository and directory_user evidence types — suitable for SOC 2 / ISO 27001 branch-protection, code-review, and identity (MFA/admin/lifecycle) policies.
GitLab is one of several substitutable source-code platforms (GitHub, Bitbucket, future Gitea/Azure DevOps); a policy accepts the git_repository evidence type, not a vendor, so this plugin is immediately usable by every policy that already consumes GitHub repositories (the substitutability principle — docs/architecture/04a-evidence-type-registry.md).
Per the KISS-no-DRY axiom (docs/architecture/04-source-plugins.md §The plugin contract), the plugin caches nothing across Collect calls. N policies bound to this plugin → N invocations of Collect.
Test injection: the API interface mirrors the github plugin — the concrete *sdkAPI (backed by gitlab.com/gitlab-org/api/client-go) satisfies it, and unit tests inject an in-memory fake. The real SDK adapter is exercised by an httptest-backed test; live integration tests against gitlab.com are deferred to the testing revamp.
Period-scoped types: alongside the two configuration snapshots the plugin also emits pull_request (one record per merge request MERGED inside the audit window) and deployment (one record per release to a GitLab environment in the window, failed ones included). GitLab merge requests map onto the cross-vendor pull_request type deliberately — the type is vendor-neutral, so one CC8.1 / ISO A.8.32 change-review policy samples GitHub PRs and GitLab MRs through a single contract. The window arrives as period_start / period_end slot params; a caller that passes none (the conformance harness) gets a trailing one-year window ending at the injected clock, never time.Now().
directory_user (WU-2.2): the plugin also lists the group's members and emits one directory_user per member, mapping AccessLevel ≥ Maintainer (or instance-admin) → is_admin, account state → is_active, and the user's two_factor_enabled → mfa_enabled. 2FA and instance-admin status are only readable with a group-owner / instance-admin token (via the Users API); without that privilege the sdkAPI degrades gracefully and mfa_enabled is best-effort false — documented in docs/configuration.md.
Index ¶
Constants ¶
const EvidenceTypeDeployment = "deployment"
EvidenceTypeDeployment is the cross-vendor deployment shape — one record per release to a running environment during the period, failed ones included.
const EvidenceTypeDirectoryUser = "directory_user"
EvidenceTypeDirectoryUser is the cross-vendor directory_user shape this plugin emits for the group's members — identical to the shape the github and okta plugins emit (the same identity evidence type).
const EvidenceTypePullRequest = "pull_request"
EvidenceTypePullRequest is the cross-vendor pull_request shape — one record per change MERGED during the audit period. A GitLab merge request IS that change; the evidence type is vendor-neutral, so the github and gitlab plugins are substitutable for a change-review policy. It answers "did this change actually get reviewed?", which the git_repository configuration snapshot structurally cannot.
const EvidenceTypeRepository = "git_repository"
EvidenceTypeRepository is the cross-vendor git_repository shape this plugin emits.
const SourceID = "gitlab"
SourceID is the registered ID for the gitlab plugin instance.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type API ¶
type API interface {
// ListRepos returns all projects under the configured group,
// normalized into the git_repository contract. Implementations must
// page transparently — callers receive the full list in one slice.
ListRepos(ctx context.Context) ([]Repo, error)
// ListMembers returns all members of the configured group, normalized
// into the directory_user contract. Implementations must page
// transparently — callers receive the full list in one slice.
ListMembers(ctx context.Context) ([]Member, error)
// ListMergedPullRequests returns the group's merge requests merged
// inside [start, end], normalized into the pull_request contract.
// Implementations must page transparently and may over-return —
// the plugin re-applies the window, so it owns the period semantics
// regardless of which API implementation is wired in.
ListMergedPullRequests(ctx context.Context, start, end time.Time) ([]PullRequest, error)
// ListDeployments returns the group's deployments created inside
// [start, end], failed ones included, normalized into the deployment
// contract. Implementations must page transparently and may
// over-return; the plugin re-applies the window.
ListDeployments(ctx context.Context, start, end time.Time) ([]Deployment, error)
}
API is the subset of the GitLab REST API the plugin uses. Defining it as an interface lets tests inject a fake without making real network calls; the concrete *sdkAPI satisfies it.
type Deployment ¶ added in v0.71.0
type Deployment struct {
Repository string
// ID is the vendor-native deployment identifier as a string.
ID string
SHA string
// Environment is the environment name exactly as GitLab reports it.
Environment string
// EnvironmentTier is GitLab's environment tier ("production",
// "staging", …). Empty when the project never set one, in which case
// the plugin falls back to the environment name for is_production.
EnvironmentTier string
Creator string
CreatedAt time.Time
// Status is the raw GitLab deployment status (created / running /
// success / failed / canceled / blocked), normalized by the plugin
// into the deployment type's closed vocabulary.
Status string
}
Deployment is one release of code to a GitLab environment during the audit period, including failed ones — a failed production deployment is still a change event an auditor may ask about.
type Member ¶ added in v0.39.0
type Member struct {
Username string
Name string
Email string
MFAEnabled bool
IsAdmin bool
IsActive bool
}
Member is the subset of fields the plugin extracts from a GitLab group member, normalized into the directory_user contract. Every field maps to a property the consuming policies read so none reads an absent field.
MFAEnabled and the instance-admin component of IsAdmin require a group-owner / instance-admin token (the Users API exposes two_factor_enabled / is_admin); the sdkAPI degrades gracefully when the token can't read them, leaving MFAEnabled best-effort false.
type Options ¶
type Options struct {
API API
// Now is injected so tests can produce deterministic CollectedAt
// values. Production callers leave it nil → time.Now().UTC().
Now func() time.Time
}
Options is the constructor input.
type Plugin ¶
type Plugin struct {
// contains filtered or unexported fields
}
Plugin is the in-process gitlab source.
func New ¶
New constructs a Plugin around an explicit API implementation. Callers using the real GitLab REST API should use NewFromToken.
func NewFromToken ¶
NewFromToken constructs a Plugin backed by the real GitLab REST API for the given group, using the supplied personal-access/group token. A blank baseURL defaults to gitlab.com; self-managed instances pass their own URL. Live integration tests are deferred.
func (*Plugin) Collect ¶
func (p *Plugin) Collect(ctx context.Context, req core.SlotRequest) ([]core.EvidenceRecord, error)
Collect dispatches to the per-type collectors for whichever emitted types the slot accepts, returning their records together. A slot that accepts none of the emitted types is rejected. Records are sorted by ID within each type group; the collector splits them by Type for envelope writing.
type PullRequest ¶ added in v0.71.0
type PullRequest struct {
// Repository is the project's full path ("group/project"), the same
// form git_repository uses for name, so the two types join.
Repository string
// Number is the MR iid — the per-project number a customer quotes in
// a waiver, not the instance-wide id.
Number int
Author string
MergedBy string
TargetBranch string
// MergeCommitSHA is the commit the MR produced on the target branch;
// the adapter substitutes the squash commit when the project squashes
// and GitLab therefore reports no merge commit.
MergeCommitSHA string
MergedAt time.Time
// Approvers carries the usernames GitLab reports in approved_by,
// verbatim — the plugin de-duplicates and drops blanks. Empty when
// the approvals endpoint could not be read (graceful degradation) or
// when nobody approved.
Approvers []string
// ChecksPassed is true when the newest pipeline attached to the MR
// succeeded. GitLab exposes no per-check aggregate comparable to
// GitHub's check runs, so the head pipeline is the CI signal.
ChecksPassed bool
}
PullRequest is one merge request MERGED into a project under the group during the audit period. The adapter supplies the raw vendor facts — GitLab's flat approver list and the newest MR pipeline's outcome; the plugin derives approval_count / independent_approval_count / approved_before_merge from them, so the normalization is unit-testable without a network.
type Repo ¶
type Repo struct {
Name string
DefaultBranch string
ProtectionOn bool
RequiredReviews int
RequiresSignedCommits bool
RequiresLinearHistory bool
AllowsForcePush bool
DismissStaleReviews bool
RequireCodeOwnerReviews bool
IsPrivate bool
Archived bool
SecretScanningEnabled bool
PushProtectionEnabled bool
DependabotAlertsEnabled bool
CodeScanningEnabled bool
}
Repo is the subset of fields the plugin extracts from a GitLab project, normalized into the git_repository contract. Every field maps to a property of the git_repository evidence type so policies never read an absent field.
Fields without a read-only GitLab API analog are left at their zero value and documented at the mapping site (sdkAPI.ListRepos):
- SecretScanningEnabled / CodeScanningEnabled / DependabotAlertsEnabled (GitLab pipeline SAST/Secret/Dependency scanning is configured in .gitlab-ci.yml, not exposed as a project-settings boolean).