diff --git a/.gitignore b/.gitignore index bdc597a47..5e24344df 100644 --- a/.gitignore +++ b/.gitignore @@ -56,3 +56,6 @@ gitlab4j-mock-config-*.properties # git-changelog plugin # .okhttpcache + +# IntelliJ HTTP Client private environment (contains tokens) +http-client.private.env.json diff --git a/gitlab4j-models/src/main/java/org/gitlab4j/api/models/ImpersonationToken.java b/gitlab4j-models/src/main/java/org/gitlab4j/api/models/ImpersonationToken.java index ac169e9ce..c7d0efe45 100644 --- a/gitlab4j-models/src/main/java/org/gitlab4j/api/models/ImpersonationToken.java +++ b/gitlab4j-models/src/main/java/org/gitlab4j/api/models/ImpersonationToken.java @@ -16,14 +16,49 @@ public class ImpersonationToken implements Serializable { /** Enum to specify the scope of an ImpersonationToken. */ public enum Scope { + /** Grants complete read/write access to the API. */ API, + + /** Grants read access to the API. */ READ_API, + + /** Grants read-only access to the user's profile. */ READ_USER, + + /** Grants read-only access to repositories on private projects using Git-over-HTTP. */ READ_REPOSITORY, + + /** Grants read-write access to repositories on private projects using Git-over-HTTP. */ WRITE_REPOSITORY, + + /** Grants read (pull) access to a Container Registry. */ READ_REGISTRY, + + /** Grants write (push) access to a Container Registry. */ WRITE_REGISTRY, + + /** Grants pull access through the dependency proxy. */ + READ_VIRTUAL_REGISTRY, + + /** Grants push, pull and delete access through the dependency proxy. */ + WRITE_VIRTUAL_REGISTRY, + + /** Grants create access to the runners. */ + CREATE_RUNNER, + + /** Grants access to manage the runners. */ + MANAGE_RUNNER, + + /** Grants access to GitLab Duo related API endpoints. */ + AI_FEATURES, + + /** Grants permission to perform Kubernetes API calls using the agent for Kubernetes. */ K8S_PROXY, + + /** Grants permission to rotate this token using the personal access token API. */ + SELF_ROTATE, + + /** Grants permission to perform API actions as any user in the system, when authenticated as an admin user. */ SUDO; private static JacksonJsonEnumHelper enumHelper = new JacksonJsonEnumHelper<>(Scope.class); diff --git a/gitlab4j-models/src/main/java/org/gitlab4j/models/Constants.java b/gitlab4j-models/src/main/java/org/gitlab4j/models/Constants.java index 45237a57d..1926dae93 100644 --- a/gitlab4j-models/src/main/java/org/gitlab4j/models/Constants.java +++ b/gitlab4j-models/src/main/java/org/gitlab4j/models/Constants.java @@ -882,7 +882,22 @@ public enum ApplicationScope { PROFILE, /** Grants read-only access to the user's primary email address using OpenID Connect. */ - EMAIL; + EMAIL, + + /** Grants read (pull) access to a Container Registry. */ + READ_REGISTRY, + + /** Grants write (push) access to a Container Registry. */ + WRITE_REGISTRY, + + /** Grants pull access through the dependency proxy. */ + READ_VIRTUAL_REGISTRY, + + /** Grants push, pull and delete access through the dependency proxy. */ + WRITE_VIRTUAL_REGISTRY, + + /** Grants permission to rotate this token using the personal access token API. */ + SELF_ROTATE; private static JacksonJsonEnumHelper enumHelper = new JacksonJsonEnumHelper<>(ApplicationScope.class); @@ -1185,8 +1200,26 @@ public String toString() { /** Enum to use for specifying the deploy token scope. */ public enum DeployTokenScope { + /** Grants read-only access to repositories on private projects using Git-over-HTTP. */ READ_REPOSITORY, - READ_REGISTRY; + + /** Grants read (pull) access to a Container Registry. */ + READ_REGISTRY, + + /** Grants write (push) access to a Container Registry. */ + WRITE_REGISTRY, + + /** Grants pull access through the dependency proxy. */ + READ_VIRTUAL_REGISTRY, + + /** Grants push, pull and delete access through the dependency proxy. */ + WRITE_VIRTUAL_REGISTRY, + + /** Grants read access to the package registry. */ + READ_PACKAGE_REGISTRY, + + /** Grants write access to the package registry. */ + WRITE_PACKAGE_REGISTRY; private static JacksonJsonEnumHelper enumHelper = new JacksonJsonEnumHelper<>(DeployTokenScope.class); @@ -1209,13 +1242,38 @@ public String toString() { /** Enum to use for specifying the project token scope. */ public enum ProjectAccessTokenScope { + /** Grants complete read/write access to the scoped project API. */ API, + + /** Grants read access to the scoped project API. */ READ_API, + + /** Grants read (pull) access to a Container Registry. */ READ_REGISTRY, + + /** Grants write (push) access to a Container Registry. */ WRITE_REGISTRY, + + /** Grants read-only access to repositories on private projects using Git-over-HTTP. */ READ_REPOSITORY, + + /** Grants read-write access to repositories on private projects using Git-over-HTTP. */ WRITE_REPOSITORY, - CREATE_RUNNER; + + /** Grants create access to the runners. */ + CREATE_RUNNER, + + /** Grants access to manage the runners. */ + MANAGE_RUNNER, + + /** Grants access to GitLab Duo related API endpoints. */ + AI_FEATURES, + + /** Grants permission to perform Kubernetes API calls using the agent for Kubernetes. */ + K8S_PROXY, + + /** Grants permission to rotate this token using the personal access token API. */ + SELF_ROTATE; private static JacksonJsonEnumHelper enumHelper = new JacksonJsonEnumHelper<>(ProjectAccessTokenScope.class); diff --git a/http-client.private.env.json.example b/http-client.private.env.json.example new file mode 100644 index 000000000..2c0ef1d16 --- /dev/null +++ b/http-client.private.env.json.example @@ -0,0 +1,7 @@ +{ + "dev": { + "token": "glpat-xxxxxxxxxxxxxxxxxxxx", + "project_id": "12345", + "group_id": "6789" + } +} diff --git a/verify-scopes.http b/verify-scopes.http new file mode 100644 index 000000000..cc0140fb8 --- /dev/null +++ b/verify-scopes.http @@ -0,0 +1,137 @@ +### Verify that the added scopes exist in GitLab +### +### Prerequisites: +### Copy http-client.private.env.json.example to http-client.private.env.json +### and fill in your gitlab.com token, project_id, and group_id. +### Then select the "dev" environment in IntelliJ before running. +### +### How the proof works: +### GitLab validates scopes AFTER authentication. If a scope is valid, +### the request succeeds (or fails for permission reasons: 403/404). +### If a scope is INVALID, GitLab returns 400 with +### "scopes does not have a valid value". +### +### Each section includes a negative test with a deliberately invalid +### scope to demonstrate that GitLab does reject unknown scopes. + + +### --- ApplicationScope: self_rotate --- +### +### The self-service PAT endpoint (POST /api/v4/user/personal_access_tokens) +### only accepts k8s_proxy and self_rotate scopes (by design, GitLab 16.5+). +### The other ApplicationScope scopes (read_registry, write_registry, etc.) +### are valid PAT scopes but can only be set via the admin endpoint or the UI. +### +### Reference: https://docs.gitlab.com/user/profile/personal_access_tokens/#personal-access-token-scopes + +### Positive: self_rotate scope (should return 201) +POST https://gitlab.com/api/v4/user/personal_access_tokens +PRIVATE-TOKEN: {{token}} +Content-Type: application/json + +{ + "name": "verify-self-rotate", + "scopes": ["self_rotate"], + "expires_at": "2026-12-31" +} + +### Negative: invalid scope (should return 400) +POST https://gitlab.com/api/v4/user/personal_access_tokens +PRIVATE-TOKEN: {{token}} +Content-Type: application/json + +{ + "name": "verify-invalid-scope", + "scopes": ["THIS_SCOPE_DOES_NOT_EXIST"], + "expires_at": "2026-12-31" +} + +### --- ProjectAccessTokenScope scopes --- +### +### Requires Maintainer access on the project. +### Reference: https://docs.gitlab.com/user/project/settings/project_access_tokens/#scopes-for-a-project-access-token + +### Positive: newly added scopes (should return 201, NOT 400) +POST https://gitlab.com/api/v4/projects/{{project_id}}/access_tokens +PRIVATE-TOKEN: {{token}} +Content-Type: application/json + +{ + "name": "verify-project-scopes-valid", + "scopes": ["manage_runner", "ai_features", "k8s_proxy", "self_rotate"], + "expires_at": "2026-12-31", + "access_level": 30 +} + +### Negative: invalid scope (should return 400) +POST https://gitlab.com/api/v4/projects/{{project_id}}/access_tokens +PRIVATE-TOKEN: {{token}} +Content-Type: application/json + +{ + "name": "verify-project-scopes-invalid", + "scopes": ["manage_runner", "THIS_SCOPE_DOES_NOT_EXIST"], + "expires_at": "2026-12-31", + "access_level": 30 +} + +### --- ImpersonationToken.Scope (Group Access Token) scopes --- +### +### Requires Owner access on the group. +### Reference: https://docs.gitlab.com/user/group/settings/group_access_tokens/#scopes-for-a-group-access-token + +### Positive: newly added scopes (should return 400 Bad request - User does not have permission to create group access token) +POST https://gitlab.com/api/v4/groups/{{group_id}}/access_tokens +PRIVATE-TOKEN: {{token}} +Content-Type: application/json + +{ + "name": "verify-group-scopes-valid", + "scopes": ["create_runner", "manage_runner", "ai_features", "self_rotate", "read_virtual_registry", "write_virtual_registry"], + "expires_at": "2026-12-31", + "access_level": 30 +} + +### Negative: invalid scope (should return 400 scopes does not have a valid value) +POST https://gitlab.com/api/v4/groups/{{group_id}}/access_tokens +PRIVATE-TOKEN: {{token}} +Content-Type: application/json + +{ + "name": "verify-group-scopes-invalid", + "scopes": ["create_runner", "THIS_SCOPE_DOES_NOT_EXIST"], + "expires_at": "2026-12-31", + "access_level": 30 +} + +### --- DeployTokenScope scopes --- +### +### Requires Maintainer access on the project. +### Reference: https://docs.gitlab.com/user/project/deploy_tokens/#scope + +### Positive: newly added scopes (should return 201, NOT 400) +POST https://gitlab.com/api/v4/projects/{{project_id}}/deploy_tokens +PRIVATE-TOKEN: {{token}} +Content-Type: application/json + +{ + "name": "verify-deploy-scopes-valid", + "scopes": ["write_registry", "read_virtual_registry", "write_virtual_registry", "read_package_registry", "write_package_registry"], + "expires_at": "2026-12-31" +} + +### Negative: invalid scope (should return 400 scopes does not have a valid value) +POST https://gitlab.com/api/v4/projects/{{project_id}}/deploy_tokens +PRIVATE-TOKEN: {{token}} +Content-Type: application/json + +{ + "name": "verify-deploy-scopes-invalid", + "scopes": ["read_repository", "THIS_SCOPE_DOES_NOT_EXIST"], + "expires_at": "2026-12-31" +} + +### --- Cleanup --- +### If any tokens were created above, revoke them: +### GET https://gitlab.com/api/v4/personal_access_tokens +### then DELETE https://gitlab.com/api/v4/personal_access_tokens/:id