epack install collector gitlab
Adds to epack.yaml, resolves dependencies, downloads binary.
Run all configured collectors and build a pack:
epack collect
Runs all collectors in epack.yaml and outputs an evidence pack.
Or add manually to epack.yaml:
collectors:
gitlab:
source: https://github.com/locktivity/epack-collector-gitlab
Then run epack install to lock and sync.
The collector reads the GitLab REST API v4 for a configured group and emits security posture evidence. It includes projects in subgroups and excludes projects shared into the group.
It does not inspect repository contents, CI configuration, or CODEOWNERS files. It does not collect SAST/dependency-scanning adoption or vulnerability findings. See collection levels for the emitted fields and limits.
base_urlThe available fields depend on GitLab version, license, and token permissions.
Successful runs emit two artifacts at every collection level:
artifacts/gitlab.json: detailed GitLab-specific postureartifacts/gitlab.vcs-posture.json: normalized evidencepack/vcs-posture@v1 postureThe normalized output maps group 2FA, project selection coverage, MR/approval percentages, and pipeline-required percentages from the detailed artifact. secret_scanning_pct currently uses secret push protection adoption as a proxy; it does not measure pipeline secret detection.
Percentages describe the projects visible to the token after filtering. projects_coverage is the percentage of API-listed projects selected by the filters, not a measurement of all projects the organization owns. Archived and empty projects remain in the denominator. security_features_coverage is the arithmetic mean of secret push protection and pipeline-required coverage, rounded down to an integer.
Pipeline coverage reports the project's only_allow_merge_if_pipeline_succeeds flag. It does not inspect pipeline contents or prove that every change ran checks. Code owner coverage reports the branch flag; it does not verify that a CODEOWNERS file exists or covers all paths. Approval inventory records the maximum applicable approval count, not a complete copy of approval rules or approver identities.
The normalized signed_commits_pct, vuln_alerts_pct, and code_scanning_pct are fixed at zero because this collector does not measure them. Each is listed in unavailable_sources with an explanation. unavailable_sources also includes runtime diagnostics from permission errors and endpoint failures. Projects that omit secret_push_protection_enabled (due to tier or role restrictions) emit a diagnostic noting how many projects could not report the field.
Endpoint failures appear in diagnostics where collection can continue. A failed optional endpoint can lower coverage or counts, and counts of zero can reflect inaccessible data. Inspect diagnostics alongside the metrics. HTTP 401 fails collection at every surface; non-permission errors retrieving the group or project list also fail collection.
Group members, group hooks, runners, and group audit events retain their group scope when projects are filtered. For complete group audit events, use Owner: lower roles can return an apparently successful list containing only the token owner's actions.
Set GITLAB_TOKEN to a group or personal access token with read_api scope. A group access token creates its own bot identity; a personal token can belong to a dedicated service account. Assign a role appropriate to the surfaces you need.
For a group access token, navigate to your GitLab group > Settings > Access tokens, create the token, and provide it through the GITLAB_TOKEN environment variable and the secrets entry below. Personal tokens can be created under your GitLab profile's access-token settings.
The collector does not call the Users API, so it does not require read_user. Adding that scope does not make hidden member 2FA fields available.
stream: myorg/gitlab-posture
collectors:
gitlab:
source: locktivity/epack-collector-gitlab@^0.1
config:
group: my-organization
level: trust
# base_url: https://gitlab.example.com
# include_patterns: ["backend-*"]
# exclude_patterns: ["archived-*"]
secrets:
- GITLAB_TOKEN
| Key | Required | Default | Description |
|---|---|---|---|
group |
Yes | Group path, including a subgroup path, or numeric ID supplied as a string | |
base_url |
No | https://gitlab.com |
Instance URL; the collector appends /api/v4 |
level |
No | trust |
trust, audit, or internal; unknown values fall back to trust with an SDK warning |
include_patterns |
No | ["*"] |
Case-sensitive globs matching project display names |
exclude_patterns |
No | [] |
Project display-name globs evaluated before includes |
Filters match name, not path_with_namespace. For example, backend-* matches a project named backend-api, regardless of its namespace. Projects in subgroups are included; projects shared into the group are excluded. Archived projects are included unless filtered out. Percentages use all included projects as their denominator.
Project filters apply to project metrics, project inventory, project webhooks, and deploy keys. Group members, group webhooks, runners, and group audit events keep their group scope. The configured group and filter patterns appear in trust output too.
Supply pattern lists as arrays of strings with valid glob syntax. Invalid globs and non-string list entries are rejected before collection begins.
| Secret | Required | Description |
|---|---|---|
GITLAB_TOKEN |
Yes | GitLab access token; never written into the artifacts |
Set base_url to the instance URL, without an /api/v4 suffix:
config:
group: my-org
base_url: https://gitlab.example.com
For GitLab Dedicated, use the URL of your dedicated instance in the same way.
| Surface | Collection level | Requirements and limitations |
|---|---|---|
| Group settings, projects, branch protection | trust+ | read_api; visibility depends on token membership and role |
| Approval settings and rules | trust+ | Premium+; permissions can vary between the two endpoints |
| Secret push protection status | trust+ | Ultimate; status is exposed to Developer, Security Manager, Maintainer, or Owner where supported |
| Members | audit+ | read_api; inherited and invited membership follows the API's visibility rules |
| Member 2FA status | audit+ | API field introduced in GitLab 19.4 and visible to group Owners and administrators; missing values remain null |
| Project webhooks and deploy keys | audit+ | Maintainer or above |
| Group webhooks | audit+ | Premium+, Owner or administrator |
| Runners available to the group | audit+ | Current API documentation requires Owner/Auditor or custom admin_runners, and manage_runner scope |
| Group audit events | internal | Premium+; Owner for all users' events; Developer/Maintainer can receive only their own events |
Requirements vary with GitLab version. Consult the Projects API, Groups members API, Runners API, and Audit events API.
Optional endpoint failures emit diagnostics. HTTP 401 is always fatal; non-permission failures fetching the group or project list are fatal too. A successful response can omit restricted fields without a diagnostic. Group webhook and audit-event HTTP 403 diagnostics currently mention Premium even when the cause is insufficient role. Runner permission diagnostics currently mention Maintainer, although the group-list endpoint has stricter documented requirements.
# epack.yaml
stream: myorg/gitlab-posture
collectors:
gitlab:
source: locktivity/epack-collector-gitlab@^0.1
config:
group: my-organization
secrets:
- GITLAB_TOKEN
export GITLAB_TOKEN="glpat-xxxxxxxxxxxxxxxxxxxx"
epack collect
collectors:
gitlab:
source: locktivity/epack-collector-gitlab@^0.1
config:
group: engineering
base_url: https://gitlab.internal.company.com
secrets:
- GITLAB_TOKEN
collectors:
gitlab:
source: locktivity/epack-collector-gitlab@^0.1
config:
group: my-organization
include_patterns:
- "backend-*"
- "frontend-*"
exclude_patterns:
- "*-archived"
secrets:
- GITLAB_TOKEN
Set the collection level in the collector configuration:
stream: myorg/gitlab-posture
collectors:
gitlab:
source: locktivity/epack-collector-gitlab@^0.1
config:
group: my-organization
level: audit
secrets:
- GITLAB_TOKEN
epack collect
{
"schema_version": "1.0.0",
"collected_at": "2026-09-18T12:00:00Z",
"collected_at_level": "trust",
"group": "my-organization",
"scope": {
"include_patterns": ["*"],
"exclude_patterns": [],
"projects_coverage": 100
},
"posture": {
"branch_protection_coverage": 95,
"security_features_coverage": 72
},
"access_control": {
"two_factor_required": true
},
"branch_protection_rules": {
"merge_request_required": 92,
"approving_reviews": 78,
"code_owner_approval": 45,
"no_force_push": 95
},
"security_features": {
"secret_push_protection": 60,
"pipeline_required": 84
}
}
This is an illustrative output. diagnostics is omitted when there are no warnings or permission errors. The 72% security-features coverage above is the mean of 60% secret push protection and 84% pipeline-required coverage. See output limitations before interpreting zeros as disabled controls.
**Full Changelog**: https://github.com/locktivity/epack-collector-gitlab/commits/v0.1.0