Skip to content

feat(gitlab): dynamic access levels + group and membership operations#5726

Closed
mzxchandra wants to merge 2 commits into
simstudioai:stagingfrom
mzxchandra:feature/sim-821
Closed

feat(gitlab): dynamic access levels + group and membership operations#5726
mzxchandra wants to merge 2 commits into
simstudioai:stagingfrom
mzxchandra:feature/sim-821

Conversation

@mzxchandra

Copy link
Copy Markdown
Contributor

Summary

Fast-follow to #5710. Fixes a blocking defect and closes two follow-up gaps in the GitLab block's access/membership surface.

1. Dynamic access levels (the core fix)

The access-level fields were dropdown subblocks, which the Copilot save-time validator checks against a closed enum - so binding a level to a runtime reference (<block.output>) was rejected outright with Invalid dropdown value, and the value wasn't even persisted. But access provisioning computes the grant from a (role, department) → level policy table at runtime; the level is often not a design-time constant, so this made the common case unbuildable natively.

  • The three access-level fields (accessLevel, memberAccessLevel, invitationAccessLevel) switch from dropdown to combobox, which keeps the named options as a picker and accepts a reference expression at save time.
  • The resolved value is validated at execution time by coerceGitLabAccessLevel, which accepts an integer (30), a numeric string ("30"), or a level name ("Developer", case-insensitive), and throws a clear error otherwise. This preserves the real safety property (no unintended integer reaches GitLab) while dropping the false one (levels must be knowable at design time).
  • The enum is now a single source of truth (GITLAB_ACCESS_LEVELS in tools/gitlab/utils.ts) that both the block options and runtime coercion derive from, replacing three inline copies.

2. Follow-up gaps closed

  • get_group / list_groups - resolve and list groups. A provisioning workflow must resolve the group before it can grant anything; the block had get_project but no group equivalent.
  • list_user_memberships - admin GET /users/:id/memberships, clearly gated as admin-only in its description. The non-admin path (iterating list_members) is already composable with shipped tools.
  • host - verified already reference-bindable (it's a short-input); no change needed.

Deferred to separate tickets

  • A platform-wide validation change (defer save-time enum checks for reference expressions across all blocks, not just GitLab).
  • Next-wave gaps: project/group access tokens, deploy keys, and service-account creation.

Testing

  • 59 unit tests across the four GitLab suites: coerceGitLabAccessLevel (name/int/numeric-string/invalid), the three new tools (URL builders + transformResponse), and block-level coercion + new-op wiring.
  • Typecheck, Biome, and bun run check:api-validation all clean.
  • E2E in the running app: reproduced the exact failure mode against the real Copilot save-time validator - a reference expression now validates for all three access-level fields (previously the Invalid dropdown value rejection), and the block coerces a name-bound reference to the correct integer at execution.

🤖 Generated with Claude Code

Access levels can now be bound to runtime references (e.g. a policy-table
lookup), not just picked from a static list. The three access-level fields
(accessLevel, memberAccessLevel, invitationAccessLevel) switch from dropdown
to combobox so a reference expression is accepted at Copilot save-time instead
of being rejected as an invalid enum value. The resolved value is validated at
execution time by coerceGitLabAccessLevel, which accepts an integer, a numeric
string, or a level name ("Developer"), and throws a clear error otherwise -
preserving the real safety property (no bad integer reaches GitLab) while
dropping the false one (levels must be known at design time).

Also closes demand gaps from the AskIT data:
- get_group / list_groups: resolve and list groups (provisioning critical path)
- list_user_memberships: admin GET /users/:id/memberships, gated in its
  description; the non-admin path is composing list_members

The access-level enum is now a single source of truth in tools/gitlab/utils.ts
(GITLAB_ACCESS_LEVELS) that the block options and runtime coercion both derive
from, replacing three inline copies.
@vercel

vercel Bot commented Jul 17, 2026

Copy link
Copy Markdown

@mzxchandra is attempting to deploy a commit to the Sim Team on Vercel.

A member of the Team first needs to authorize it.

@cursor

cursor Bot commented Jul 17, 2026

Copy link
Copy Markdown

PR Summary

Medium Risk
Changes membership and invitation param coercion (including access level 0), which can alter what reaches GitLab APIs; scope is limited to the GitLab block/tools with broad test coverage.

Overview
Fixes GitLab access provisioning workflows by allowing runtime-bound access levels and adding group discovery operations missing from the block.

Dynamic access levels: The three access-level fields (accessLevel, memberAccessLevel, invitationAccessLevel) change from dropdown to combobox, so save-time validation accepts reference expressions (e.g. policy-table output) instead of rejecting them. At execution, coerceGitLabAccessLevel and hasGitLabAccessLevel centralize validation: levels can be an integer, numeric string, or name ("Developer"), with 0 ("No access") handled correctly instead of being dropped by truthiness checks. Options come from a single GITLAB_ACCESS_LEVELS source in utils.ts.

New block operations: List Groups, Get Group, and List User Memberships (admin API) are wired through new tools, block params, filters (groupsTopLevelOnly, membershipType), and registry exports.

Path encoding: getGitLabResourcePath decodes-then-encodes resource IDs so pre-encoded namespaced paths (e.g. parent%2Fchild) are not double-encoded and 404 on GitLab.

Reviewed by Cursor Bugbot for commit 65e38db. Bugbot is set up for automated code reviews on this repo. Configure here.

Comment thread apps/sim/blocks/blocks/gitlab.ts
@greptile-apps

greptile-apps Bot commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR expands GitLab access and membership operations. The main changes are:

  • Runtime-bindable access-level comboboxes with centralized validation and coercion.
  • Correct handling of numeric and string zero access levels.
  • New group lookup, group listing, and user membership tools.
  • Block, registry, type, and test updates for the new operations.

Confidence Score: 5/5

This looks safe to merge.

  • Numeric 0 and string "0" now pass through required and optional access-level paths.
  • Runtime coercion accepts valid names and integer values while rejecting invalid levels.
  • Tests cover the previously broken zero-value cases.

Important Files Changed

Filename Overview
apps/sim/blocks/blocks/gitlab.ts Adds group and membership operations and preserves zero-valued access levels across required and optional paths.
apps/sim/tools/gitlab/utils.ts Centralizes access-level options and adds runtime presence and coercion helpers.
apps/sim/tools/gitlab/get_group.ts Adds the GitLab group lookup tool.
apps/sim/tools/gitlab/list_groups.ts Adds paginated GitLab group listing with supported filters.
apps/sim/tools/gitlab/list_user_memberships.ts Adds administrator-only user membership listing.
apps/sim/blocks/blocks/gitlab.test.ts Covers dynamic access levels, zero handling, and new operation routing.
apps/sim/tools/gitlab/utils.test.ts Covers access-level presence, coercion, and resource path encoding.

Reviews (2): Last reviewed commit: "fix(gitlab): treat access level 0 ("No a..." | Re-trigger Greptile

Comment thread apps/sim/blocks/blocks/gitlab.ts
Comment thread apps/sim/blocks/blocks/gitlab.ts
A runtime reference can resolve to the integer 0, but the block still gated
access-level presence with truthiness: required ops rejected 0 as missing and
optional ops silently omitted it. Add hasGitLabAccessLevel(value) (0 and '0'
are provided; undefined/null/'' are not) and use it for all six presence
gates so "No access" can be granted or set via a reference.
@mzxchandra

Copy link
Copy Markdown
Contributor Author

@greptile

@mzxchandra

Copy link
Copy Markdown
Contributor Author

@cursor review

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit 65e38db. Configure here.

@waleedlatif1

Copy link
Copy Markdown
Collaborator

closed as apart of #5743

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants