diff --git a/pkg/cli/config/config.go b/pkg/cli/config/config.go index 3f293dc9a..558f8448a 100644 --- a/pkg/cli/config/config.go +++ b/pkg/cli/config/config.go @@ -54,6 +54,7 @@ const ( "v1:datum " + "v1:document " + "v1:iam " + + "v1:itam " + "v1:org " + "v1:privacy " + "v1:risk " + diff --git a/pkg/coredata/migrations/20260730T090938Z.sql b/pkg/coredata/migrations/20260730T090938Z.sql new file mode 100644 index 000000000..976f0b66a --- /dev/null +++ b/pkg/coredata/migrations/20260730T090938Z.sql @@ -0,0 +1,50 @@ +-- Copyright (c) 2026 Probo Inc . +-- +-- Permission is hereby granted, free of charge, to any person obtaining a copy +-- of this software and associated documentation files (the "Software"), to deal +-- in the Software without restriction, including without limitation the rights +-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +-- copies of the Software, and to permit persons to whom the Software is +-- furnished to do so, subject to the following conditions: +-- +-- The above copyright notice and this permission notice shall be included in +-- all copies or substantial portions of the Software. +-- +-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +-- SOFTWARE. + +-- Add v1:itam to the well-known prb CLI OAuth2 client so device tokens can +-- call ITAM GraphQL under OAuth2 scope enforcement. +UPDATE iam_oauth2_clients +SET scopes = '{ + openid, + profile, + email, + offline_access, + v1:access-review, + v1:agent, + v1:asset, + v1:audit, + v1:common-third-party, + v1:compliance-page, + v1:connector, + v1:control, + v1:datum, + v1:document, + v1:iam, + v1:itam, + v1:org, + v1:privacy, + v1:risk, + v1:slack-connection, + v1:task, + v1:third-party, + v1:webhook +}'::TEXT[], + updated_at = NOW() +WHERE id = 'AAAAAAAAAAAASwAAAAAAAAAAcHJiY2xp'; diff --git a/pkg/iam/oauth2_scope_registrations_test.go b/pkg/iam/oauth2_scope_registrations_test.go index b2ba2e6ee..12814e2c3 100644 --- a/pkg/iam/oauth2_scope_registrations_test.go +++ b/pkg/iam/oauth2_scope_registrations_test.go @@ -29,6 +29,7 @@ import ( "go.probo.inc/probo/pkg/coredata" "go.probo.inc/probo/pkg/iam" "go.probo.inc/probo/pkg/iam/oauth2scope" + "go.probo.inc/probo/pkg/itam" "go.probo.inc/probo/pkg/probo" ) @@ -37,7 +38,8 @@ func allRegisteredOAuth2ScopeRegistries() *oauth2scope.Registry { Register(iam.IAMOAuth2ScopeMappings). Register(probo.OAuth2ScopeMappings). Register(accessreview.OAuth2ScopeMappings). - Register(agentrun.OAuth2ScopeMappings) + Register(agentrun.OAuth2ScopeMappings). + Register(itam.OAuth2ScopeMappings) } func TestRegisteredOAuth2ScopeRegistries_OrganizationRead(t *testing.T) { @@ -62,3 +64,13 @@ func TestRegisteredOAuth2ScopeRegistries_UnmappedActionDenies(t *testing.T) { assert.False(t, reg.Allows(tokenScopes, "core:unmapped:action")) } + +func TestRegisteredOAuth2ScopeRegistries_ITAMDeviceDelete(t *testing.T) { + t.Parallel() + + reg := allRegisteredOAuth2ScopeRegistries() + + assert.True(t, reg.Allows(coredata.OAuth2Scopes{itam.ScopeV1ITAM}, itam.ActionDeviceDelete)) + assert.False(t, reg.Allows(coredata.OAuth2Scopes{itam.ScopeV1ITAMRead}, itam.ActionDeviceDelete)) + assert.True(t, reg.Allows(coredata.OAuth2Scopes{itam.ScopeV1ITAMRead}, itam.ActionDeviceGet)) +} diff --git a/pkg/itam/oauth2_scopes.go b/pkg/itam/oauth2_scopes.go new file mode 100644 index 000000000..48c74e733 --- /dev/null +++ b/pkg/itam/oauth2_scopes.go @@ -0,0 +1,47 @@ +// Copyright (c) 2026 Probo Inc . +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +package itam + +import "go.probo.inc/probo/pkg/coredata" + +const ( + ScopeV1ITAMRead coredata.OAuth2Scope = "v1:itam:read" + ScopeV1ITAM coredata.OAuth2Scope = "v1:itam" +) + +// OAuth2ScopeMappings maps OAuth2 scopes to ITAM actions. +var OAuth2ScopeMappings = map[coredata.OAuth2Scope][]string{ + ScopeV1ITAMRead: { + ActionDeviceList, + ActionDeviceGet, + ActionDevicePostureList, + }, + ScopeV1ITAM: { + ActionDeviceList, + ActionDeviceGet, + ActionDevicePostureList, + ActionDeviceCreate, + ActionDeviceEnroll, + ActionDeviceRevoke, + ActionDeviceDelete, + ActionDeviceAssignOwner, + }, +} diff --git a/pkg/probod/probod.go b/pkg/probod/probod.go index b7b27cd8d..51828dc74 100644 --- a/pkg/probod/probod.go +++ b/pkg/probod/probod.go @@ -516,7 +516,8 @@ func (impl *Implm) Run( Register(management.OAuth2ScopeMappings). Register(agentrun.OAuth2ScopeMappings). Register(accessreview.OAuth2ScopeMappings). - Register(resourcealias.OAuth2ScopeMappings) + Register(resourcealias.OAuth2ScopeMappings). + Register(itam.OAuth2ScopeMappings) var accountKey crypto.Signer if impl.cfg.CustomDomains.ACME.AccountKey != "" {