Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 9 additions & 17 deletions app/controlplane/internal/service/cascredential.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,7 @@ func (s *CASCredentialsService) Get(ctx context.Context, req *pb.CASCredentialsS
}

// Internal platform traffic can be flagged so the CAS skips audit event emission for it
sourceInternal, err := resolveSourceInternal(req.GetSourceInternal(), currentAPIToken)
if err != nil {
return nil, err
}
sourceInternal := resolveSourceInternal(req.GetSourceInternal(), currentAPIToken)

currentOrg, err := requireCurrentOrg(ctx)
if err != nil {
Expand Down Expand Up @@ -167,17 +164,12 @@ func (s *CASCredentialsService) Get(ctx context.Context, req *pb.CASCredentialsS
}, nil
}

// resolveSourceInternal returns whether the minted CAS token must be flagged as internal
// platform traffic. Only system API tokens can request it since they are minted exclusively
// by internal code paths; any other caller asking for it is rejected.
func resolveSourceInternal(requested bool, token *entities.APIToken) (bool, error) {
if !requested {
return false, nil
}

if token == nil || !token.IsSystem {
return false, errors.Forbidden("forbidden", "source_internal is restricted to system API tokens")
}

return true, nil
// resolveSourceInternal returns whether the minted CAS token should be flagged as internal
// platform traffic. It is only flagged when a system API token explicitly requests it, since
// these tokens are minted exclusively by internal code paths.
//
// This is best-effort: any other caller requesting it (for example an outdated system whose
// token store does not yet mark its tokens as system) is simply not flagged rather than rejected.
func resolveSourceInternal(requested bool, token *entities.APIToken) bool {
return requested && token != nil && token.IsSystem
}
22 changes: 7 additions & 15 deletions app/controlplane/internal/service/cascredential_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,7 @@ import (
"testing"

"github.com/chainloop-dev/chainloop/app/controlplane/internal/usercontext/entities"
"github.com/go-kratos/kratos/v2/errors"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestResolveSourceInternal(t *testing.T) {
Expand All @@ -30,7 +28,6 @@ func TestResolveSourceInternal(t *testing.T) {
requested bool
token *entities.APIToken
want bool
wantErr bool
}{
{
name: "not requested, no token (user auth)",
Expand All @@ -57,29 +54,24 @@ func TestResolveSourceInternal(t *testing.T) {
want: true,
},
{
name: "requested by regular API token is forbidden",
// best-effort: a non-system token requesting it is ignored, not rejected,
// to tolerate outdated systems whose tokens are not yet marked as system
name: "requested by regular API token falls back to false",
requested: true,
token: &entities.APIToken{},
wantErr: true,
want: false,
},
{
name: "requested by user auth is forbidden",
name: "requested by user auth falls back to false",
requested: true,
token: nil,
wantErr: true,
want: false,
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
got, err := resolveSourceInternal(tc.requested, tc.token)
if tc.wantErr {
require.Error(t, err)
assert.True(t, errors.IsForbidden(err))
return
}

require.NoError(t, err)
got := resolveSourceInternal(tc.requested, tc.token)
assert.Equal(t, tc.want, got)
})
}
Expand Down
Loading