⭐ gitlab: add protectedEnvironments, integrations, and personal access tokens#8904
⭐ gitlab: add protectedEnvironments, integrations, and personal access tokens#8904tas50 wants to merge 1 commit into
Conversation
…s tokens Three new security resources. gitlab.project.protectedEnvironment (new) — deployment gates: - name, requiredApprovalCount, deployAccessLevels, and approvalRules (who may deploy and how many approvals a deployment needs). gitlab.project.integration (new) — external services (Slack, Jira, generic webhooks) wired into the project: - id, title, slug, active, inherited, timestamps, and the full set of event triggers (push/issues/mergeRequests/pipeline/deployment/vulnerability/...). A data-egress and inbound-trigger surface. gitlab.user.personalAccessToken (new) — PAT inventory via gitlab.user.personalAccessTokens (filtered by the user's id): - id, name, description, active, revoked, scopes, createdAt, expiresAt, lastUsedAt — for auditing over-scoped, stale, or non-expiring tokens. Requires an admin token (all users) or self-access. Premium/permission-gated calls return an empty list on 403/404. New .lr.versions entries at 13.3.9. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
| services, _, err := conn.Client().Services.ListServices(int(p.Id.Data)) | ||
| if err != nil { | ||
| return nil, err | ||
| } |
There was a problem hiding this comment.
🔴 critical — ListServices is called without pagination. If a project has more integrations than the API's default page size, results will be silently truncated. Add a pagination loop like the one used in protectedEnvironments() (line 602–614). The go-gitlab ListServices method likely accepts ListServiceOptions with ListOptions.
| if err != nil { | ||
| return nil, err | ||
| } |
There was a problem hiding this comment.
🟡 warning — Unlike protectedEnvironments() and personalAccessTokens(), this method does not handle 403/404 gracefully — it will propagate the error and fail the resource graph. Add a resp check:
if err != nil {
if resp != nil && (resp.StatusCode == 403 || resp.StatusCode == 404) {
return []any{}, nil
}
return nil, err
}| @@ -541,6 +541,132 @@ func projectTagAccessLevels(runtime *plugin.Runtime, idPrefix string, descs []*g | |||
| } | |||
|
|
|||
| // protectedTags lists the project's protected tags and who may create them. | |||
There was a problem hiding this comment.
🔵 suggestion — The id() method for mqlGitlabProjectIntegration is placed above the unrelated protectedTags comment on line 541. Consider moving it closer to the integrations() method or into a separate section for better readability.
Test Results11 253 tests 11 246 ✅ 5m 23s ⏱️ Results for commit a83efef. |
What
Three new security-relevant resources for the GitLab provider.
gitlab.project.protectedEnvironment(new)Deployment gates on protected environments:
name,requiredApprovalCount,deployAccessLevels(who may deploy), andapprovalRules(approver groups/users) — the deploy-side counterpart to protected branches/tags. Exposed viagitlab.project.protectedEnvironments().gitlab.project.integration(new)Active external integrations (Slack, Jira, generic webhook-style services) wired into a project — a data-egress / inbound-trigger surface:
id,title,slug,active,inherited, timestamps, and the full set of event triggers (pushEvents,mergeRequestsEvents,pipelineEvents,deploymentEvents,vulnerabilityEvents, …). Exposed viagitlab.project.integrations().gitlab.user.personalAccessToken(new)PAT inventory, exposed via
gitlab.user.personalAccessTokens()(filtered by the user's id):id,name,description,active,revoked,scopes,createdAt,expiresAt,lastUsedAt— for auditing over-scoped, stale, or non-expiring tokens. Complements the existing project/group access-token resources.Example queries
Notes
.lr.versionsentries at13.3.9.personalAccessTokens()requires an admin token to enumerate other users' tokens (self-access otherwise); premium/permission-gated calls return an empty list on403/404rather than failing the resource graph.protectedEnvironmentdeploy-access levels and approval rules are modeled as[]dict(they carrygroupInheritanceTypeand no deploy key, so they don't fit the sharedprotectedBranch.accessLevelrow);token/secret values are never exposed.Test
go build ./...(gitlab module) — cleango vet ./resources/— cleango test ./resources/— pass