From 02a3ac402e5b07ea0efffaf6a35ea3740b800211 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 17 Dec 2025 12:11:07 +0000 Subject: [PATCH 1/5] feat(agent): add group-based SCM tools access control --- .stats.yml | 8 ++--- api.md | 2 ++ groupmembership.go | 62 ++++++++++++++++++++++++++++++++++++++ groupmembership_test.go | 29 ++++++++++++++++++ organizationpolicy.go | 21 ++++++++----- organizationpolicy_test.go | 7 +++-- project.go | 3 ++ project_test.go | 7 +++-- 8 files changed, 122 insertions(+), 17 deletions(-) diff --git a/.stats.yml b/.stats.yml index 0fdb5b6..2b7ac98 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ -configured_endpoints: 159 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/gitpod%2Fgitpod-d62ef4b9187c1f3d36f428abc4b31d8a09ffd36e93d39b8136c60c8f463c838e.yml -openapi_spec_hash: d7f01b6f24e88eb46d744ecd28061f26 -config_hash: 26e4a10dfc6ec809322e60d889d15414 +configured_endpoints: 160 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/gitpod%2Fgitpod-a19818e87979929d5484f97ec50318899c659c73733b4a700a41f28687ee2632.yml +openapi_spec_hash: f2d83905d1ed19d50c2f4641ecf29204 +config_hash: e84bdcd3fab4b185dd3dd79f70ea527d diff --git a/api.md b/api.md index 958a997..8b1f37f 100644 --- a/api.md +++ b/api.md @@ -316,11 +316,13 @@ Response Types: - gitpod.GroupMembership - gitpod.GroupMembershipNewResponse +- gitpod.GroupMembershipGetResponse - gitpod.GroupMembershipDeleteResponse Methods: - client.Groups.Memberships.New(ctx context.Context, body gitpod.GroupMembershipNewParams) (gitpod.GroupMembershipNewResponse, error) +- client.Groups.Memberships.Get(ctx context.Context, body gitpod.GroupMembershipGetParams) (gitpod.GroupMembershipGetResponse, error) - client.Groups.Memberships.List(ctx context.Context, params gitpod.GroupMembershipListParams) (pagination.MembersPage[gitpod.GroupMembership], error) - client.Groups.Memberships.Delete(ctx context.Context, body gitpod.GroupMembershipDeleteParams) (gitpod.GroupMembershipDeleteResponse, error) diff --git a/groupmembership.go b/groupmembership.go index fc9d2c6..68a01c9 100644 --- a/groupmembership.go +++ b/groupmembership.go @@ -67,6 +67,36 @@ func (r *GroupMembershipService) New(ctx context.Context, body GroupMembershipNe return } +// Gets a specific membership by group ID and subject. +// +// Use this method to: +// +// - Check if a user or service account is a member of a group +// - Verify group membership for access control +// +// ### Examples +// +// - Check user membership: +// +// Checks if a user is a member of a specific group. +// +// ```yaml +// groupId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" +// subject: +// id: "f53d2330-3795-4c5d-a1f3-453121af9c60" +// principal: PRINCIPAL_USER +// ``` +// +// ### Authorization +// +// All organization members can check group membership (transparency model). +func (r *GroupMembershipService) Get(ctx context.Context, body GroupMembershipGetParams, opts ...option.RequestOption) (res *GroupMembershipGetResponse, err error) { + opts = slices.Concat(r.Options, opts) + path := "gitpod.v1.GroupService/GetMembership" + err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, body, &res, opts...) + return +} + // Lists all memberships of a group. // // Use this method to: @@ -216,6 +246,28 @@ func (r groupMembershipNewResponseJSON) RawJSON() string { return r.raw } +type GroupMembershipGetResponse struct { + // The membership if found, nil if subject is not a member + Member GroupMembership `json:"member"` + JSON groupMembershipGetResponseJSON `json:"-"` +} + +// groupMembershipGetResponseJSON contains the JSON metadata for the struct +// [GroupMembershipGetResponse] +type groupMembershipGetResponseJSON struct { + Member apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *GroupMembershipGetResponse) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r groupMembershipGetResponseJSON) RawJSON() string { + return r.raw +} + type GroupMembershipDeleteResponse = interface{} type GroupMembershipNewParams struct { @@ -228,6 +280,16 @@ func (r GroupMembershipNewParams) MarshalJSON() (data []byte, err error) { return apijson.MarshalRoot(r) } +type GroupMembershipGetParams struct { + // Subject to check membership for + Subject param.Field[shared.SubjectParam] `json:"subject,required"` + GroupID param.Field[string] `json:"groupId" format:"uuid"` +} + +func (r GroupMembershipGetParams) MarshalJSON() (data []byte, err error) { + return apijson.MarshalRoot(r) +} + type GroupMembershipListParams struct { Token param.Field[string] `query:"token"` PageSize param.Field[int64] `query:"pageSize"` diff --git a/groupmembership_test.go b/groupmembership_test.go index 6206821..7977e02 100644 --- a/groupmembership_test.go +++ b/groupmembership_test.go @@ -43,6 +43,35 @@ func TestGroupMembershipNewWithOptionalParams(t *testing.T) { } } +func TestGroupMembershipGetWithOptionalParams(t *testing.T) { + t.Skip("Prism tests are disabled") + baseURL := "http://localhost:4010" + if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok { + baseURL = envURL + } + if !testutil.CheckTestServer(t, baseURL) { + return + } + client := gitpod.NewClient( + option.WithBaseURL(baseURL), + option.WithBearerToken("My Bearer Token"), + ) + _, err := client.Groups.Memberships.Get(context.TODO(), gitpod.GroupMembershipGetParams{ + Subject: gitpod.F(shared.SubjectParam{ + ID: gitpod.F("f53d2330-3795-4c5d-a1f3-453121af9c60"), + Principal: gitpod.F(shared.PrincipalUser), + }), + GroupID: gitpod.F("d2c94c27-3b76-4a42-b88c-95a85e392c68"), + }) + if err != nil { + var apierr *gitpod.Error + if errors.As(err, &apierr) { + t.Log(string(apierr.DumpRequest(true))) + } + t.Fatalf("err should be nil: %s", err.Error()) + } +} + func TestGroupMembershipListWithOptionalParams(t *testing.T) { t.Skip("Prism tests are disabled") baseURL := "http://localhost:4010" diff --git a/organizationpolicy.go b/organizationpolicy.go index 99f95cb..1a71fff 100644 --- a/organizationpolicy.go +++ b/organizationpolicy.go @@ -106,17 +106,21 @@ type AgentPolicy struct { McpDisabled bool `json:"mcpDisabled,required"` // scm_tools_disabled controls whether SCM (Source Control Management) tools are // disabled for agents - ScmToolsDisabled bool `json:"scmToolsDisabled,required"` - JSON agentPolicyJSON `json:"-"` + ScmToolsDisabled bool `json:"scmToolsDisabled,required"` + // scm_tools_allowed_group_id restricts SCM tools access to members of this group. + // Empty means no restriction (all users can use SCM tools if not disabled). + ScmToolsAllowedGroupID string `json:"scmToolsAllowedGroupId"` + JSON agentPolicyJSON `json:"-"` } // agentPolicyJSON contains the JSON metadata for the struct [AgentPolicy] type agentPolicyJSON struct { - CommandDenyList apijson.Field - McpDisabled apijson.Field - ScmToolsDisabled apijson.Field - raw string - ExtraFields map[string]apijson.Field + CommandDenyList apijson.Field + McpDisabled apijson.Field + ScmToolsDisabled apijson.Field + ScmToolsAllowedGroupID apijson.Field + raw string + ExtraFields map[string]apijson.Field } func (r *AgentPolicy) UnmarshalJSON(data []byte) (err error) { @@ -401,6 +405,9 @@ type OrganizationPolicyUpdateParamsAgentPolicy struct { // mcp_disabled controls whether MCP (Model Context Protocol) is disabled for // agents McpDisabled param.Field[bool] `json:"mcpDisabled"` + // scm_tools_allowed_group_id restricts SCM tools access to members of this group. + // Empty means no restriction (all users can use SCM tools if not disabled). + ScmToolsAllowedGroupID param.Field[string] `json:"scmToolsAllowedGroupId"` // scm_tools_disabled controls whether SCM (Source Control Management) tools are // disabled for agents ScmToolsDisabled param.Field[bool] `json:"scmToolsDisabled"` diff --git a/organizationpolicy_test.go b/organizationpolicy_test.go index cea9261..386370a 100644 --- a/organizationpolicy_test.go +++ b/organizationpolicy_test.go @@ -54,9 +54,10 @@ func TestOrganizationPolicyUpdateWithOptionalParams(t *testing.T) { _, err := client.Organizations.Policies.Update(context.TODO(), gitpod.OrganizationPolicyUpdateParams{ OrganizationID: gitpod.F("b0e12f6c-4c67-429d-a4a6-d9838b5da047"), AgentPolicy: gitpod.F(gitpod.OrganizationPolicyUpdateParamsAgentPolicy{ - CommandDenyList: gitpod.F([]string{"string"}), - McpDisabled: gitpod.F(true), - ScmToolsDisabled: gitpod.F(true), + CommandDenyList: gitpod.F([]string{"string"}), + McpDisabled: gitpod.F(true), + ScmToolsAllowedGroupID: gitpod.F("scmToolsAllowedGroupId"), + ScmToolsDisabled: gitpod.F(true), }), AllowedEditorIDs: gitpod.F([]string{"string"}), AllowLocalRunners: gitpod.F(true), diff --git a/project.go b/project.go index d152d8a..621884c 100644 --- a/project.go +++ b/project.go @@ -1055,6 +1055,9 @@ type ProjectListParamsFilter struct { // runner_ids filters the response to only projects that use environment classes // from these runners RunnerIDs param.Field[[]string] `json:"runnerIds" format:"uuid"` + // runner_kinds filters the response to only projects that use environment classes + // from runners of these kinds + RunnerKinds param.Field[[]RunnerKind] `json:"runnerKinds"` // search performs case-insensitive search across project name, project ID, and // repository name Search param.Field[string] `json:"search"` diff --git a/project_test.go b/project_test.go index c86a0d3..5c65cfc 100644 --- a/project_test.go +++ b/project_test.go @@ -171,9 +171,10 @@ func TestProjectListWithOptionalParams(t *testing.T) { Token: gitpod.F("token"), PageSize: gitpod.F(int64(0)), Filter: gitpod.F(gitpod.ProjectListParamsFilter{ - ProjectIDs: gitpod.F([]string{"182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"}), - RunnerIDs: gitpod.F([]string{"182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"}), - Search: gitpod.F("search"), + ProjectIDs: gitpod.F([]string{"182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"}), + RunnerIDs: gitpod.F([]string{"182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"}), + RunnerKinds: gitpod.F([]gitpod.RunnerKind{gitpod.RunnerKindUnspecified}), + Search: gitpod.F("search"), }), Pagination: gitpod.F(gitpod.ProjectListParamsPagination{ Token: gitpod.F("token"), From 2e9de50431b0d2ab64db8b7bbba3c83aedc7d74b Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 17 Dec 2025 17:14:53 +0000 Subject: [PATCH 2/5] fix: skip usage tests that don't work with Prism --- usage1_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/usage1_test.go b/usage1_test.go index 6d6b8f3..f557b5e 100644 --- a/usage1_test.go +++ b/usage1_test.go @@ -24,6 +24,7 @@ func TestUsage(t *testing.T) { option.WithBaseURL(baseURL), option.WithBearerToken("My Bearer Token"), ) + t.Skip("Prism tests are disabled") response, err := client.Identity.GetAuthenticatedIdentity(context.TODO(), gitpod.IdentityGetAuthenticatedIdentityParams{}) if err != nil { t.Error(err) From af1d69c695071e89c7ede111953b510914b6dff0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Espino?= Date: Fri, 19 Dec 2025 16:41:10 +0100 Subject: [PATCH 3/5] chore: pin GitHub Actions to SHA --- .github/workflows/ci.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 846bc19..ee5b1f8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -20,10 +20,10 @@ jobs: if: github.event_name == 'push' || github.event.pull_request.head.repo.fork steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 - name: Setup go - uses: actions/setup-go@v5 + uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5 with: go-version-file: ./go.mod @@ -35,10 +35,10 @@ jobs: runs-on: ${{ github.repository == 'stainless-sdks/gitpod-go' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} if: github.event_name == 'push' || github.event.pull_request.head.repo.fork steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 - name: Setup go - uses: actions/setup-go@v5 + uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5 with: go-version-file: ./go.mod From 9d21ce0d9d368e05063f05d14845fab2bfa617f2 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 19 Dec 2025 18:54:08 +0000 Subject: [PATCH 4/5] codegen metadata --- .stats.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.stats.yml b/.stats.yml index 2b7ac98..f59d5bf 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 160 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/gitpod%2Fgitpod-a19818e87979929d5484f97ec50318899c659c73733b4a700a41f28687ee2632.yml -openapi_spec_hash: f2d83905d1ed19d50c2f4641ecf29204 -config_hash: e84bdcd3fab4b185dd3dd79f70ea527d +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/gitpod%2Fgitpod-8b86b2ad546df57ba9b530cb8d31733d99c4b629bbcac61bc10775bbd577e6b4.yml +openapi_spec_hash: 9d895493e3b1ad702e554d9e2b19e8bc +config_hash: 8e1b089e9f5af438fd56b523014af4f2 From a46ea1b13f48686b8d86a9d4d3d8f127a7e53577 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 19 Dec 2025 18:54:24 +0000 Subject: [PATCH 5/5] release: 0.8.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 18 ++++++++++++++++++ README.md | 2 +- internal/version.go | 2 +- 4 files changed, 21 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 1b77f50..6538ca9 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.7.0" + ".": "0.8.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 484c1fe..d56477a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,23 @@ # Changelog +## 0.8.0 (2025-12-19) + +Full Changelog: [v0.7.0...v0.8.0](https://github.com/gitpod-io/gitpod-sdk-go/compare/v0.7.0...v0.8.0) + +### Features + +* **agent:** add group-based SCM tools access control ([02a3ac4](https://github.com/gitpod-io/gitpod-sdk-go/commit/02a3ac402e5b07ea0efffaf6a35ea3740b800211)) + + +### Bug Fixes + +* skip usage tests that don't work with Prism ([2e9de50](https://github.com/gitpod-io/gitpod-sdk-go/commit/2e9de50431b0d2ab64db8b7bbba3c83aedc7d74b)) + + +### Chores + +* pin GitHub Actions to SHA ([af1d69c](https://github.com/gitpod-io/gitpod-sdk-go/commit/af1d69c695071e89c7ede111953b510914b6dff0)) + ## 0.7.0 (2025-12-15) Full Changelog: [v0.6.1...v0.7.0](https://github.com/gitpod-io/gitpod-sdk-go/compare/v0.6.1...v0.7.0) diff --git a/README.md b/README.md index b88b96e..c5e3a37 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ Or to pin the version: ```sh -go get -u 'github.com/gitpod-io/gitpod-sdk-go@v0.7.0' +go get -u 'github.com/gitpod-io/gitpod-sdk-go@v0.8.0' ``` diff --git a/internal/version.go b/internal/version.go index 79301ae..3c8392e 100644 --- a/internal/version.go +++ b/internal/version.go @@ -2,4 +2,4 @@ package internal -const PackageVersion = "0.7.0" // x-release-please-version +const PackageVersion = "0.8.0" // x-release-please-version