github.com/google/osv-scalibr@v0.4.1/enricher/hcpidentity/hcpidentity_test.go (about)

     1  // Copyright 2025 Google LLC
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package hcpidentity
    16  
    17  import (
    18  	"context"
    19  	"net/http"
    20  	"net/http/httptest"
    21  	"testing"
    22  
    23  	"github.com/google/osv-scalibr/enricher"
    24  	"github.com/google/osv-scalibr/inventory"
    25  	"github.com/google/osv-scalibr/veles/secrets/hcp"
    26  )
    27  
    28  func TestEnrich_PopulatesServicePrincipal(t *testing.T) {
    29  	srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    30  		if r.Method != http.MethodGet || r.URL.Path != "/iam/2019-12-10/caller-identity" {
    31  			http.Error(w, "not found", http.StatusNotFound)
    32  			return
    33  		}
    34  		w.Header().Set("Content-Type", "application/json")
    35  		w.WriteHeader(http.StatusOK)
    36  		_, _ = w.Write([]byte(`{
    37    "principal": {
    38      "id": "svc-abc@proj-123",
    39      "type": "PRINCIPAL_TYPE_SERVICE",
    40      "service": {
    41        "id": "svc-abc@proj-123",
    42        "name": "svc-abc",
    43        "organization_id": "org-001",
    44        "project_id": "proj-123"
    45      },
    46      "group_ids": ["g1","g2"]
    47    }
    48  }`))
    49  	}))
    50  	defer srv.Close()
    51  
    52  	e := NewWithBaseURL(srv.URL)
    53  	inv := &inventory.Inventory{Secrets: []*inventory.Secret{{Secret: hcp.AccessToken{Token: "t"}}}}
    54  	if err := e.Enrich(context.Background(), &enricher.ScanInput{}, inv); err != nil {
    55  		t.Fatalf("Enrich error: %v", err)
    56  	}
    57  	tok, ok := inv.Secrets[0].Secret.(hcp.AccessToken)
    58  	if !ok {
    59  		t.Fatalf("unexpected type: %T", inv.Secrets[0].Secret)
    60  	}
    61  	if tok.OrganizationID != "org-001" || tok.ProjectID != "proj-123" || tok.PrincipalID != "svc-abc@proj-123" || tok.ServiceName != "svc-abc" || tok.PrincipalType != "PRINCIPAL_TYPE_SERVICE" {
    62  		t.Errorf("unexpected identity: %+v", tok)
    63  	}
    64  	if tok.UserEmail != "" || tok.UserID != "" {
    65  		t.Errorf("unexpected user email or user id: %+v", tok)
    66  	}
    67  	if len(tok.GroupIDs) != 2 || tok.GroupIDs[0] != "g1" || tok.GroupIDs[1] != "g2" {
    68  		t.Errorf("unexpected group ids: %+v", tok.GroupIDs)
    69  	}
    70  }
    71  
    72  func TestEnrich_SkipsOnNon200(t *testing.T) {
    73  	srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    74  		w.WriteHeader(http.StatusUnauthorized)
    75  	}))
    76  	defer srv.Close()
    77  
    78  	e := NewWithBaseURL(srv.URL)
    79  	inv := &inventory.Inventory{Secrets: []*inventory.Secret{{Secret: hcp.AccessToken{Token: "t"}}}}
    80  	if err := e.Enrich(context.Background(), &enricher.ScanInput{}, inv); err != nil {
    81  		t.Fatalf("Enrich error: %v", err)
    82  	}
    83  	tok := inv.Secrets[0].Secret.(hcp.AccessToken)
    84  	if tok.OrganizationID != "" || tok.ProjectID != "" || tok.PrincipalID != "" || tok.ServiceName != "" || tok.PrincipalType != "" || len(tok.GroupIDs) != 0 {
    85  		t.Errorf("should not enrich on non-200: %+v", tok)
    86  	}
    87  }
    88  
    89  func TestEnrich_ConnectionError(t *testing.T) {
    90  	srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}))
    91  	base := srv.URL
    92  	srv.Close()
    93  
    94  	e := NewWithBaseURL(base)
    95  	inv := &inventory.Inventory{Secrets: []*inventory.Secret{{Secret: hcp.AccessToken{Token: "t"}}}}
    96  	if err := e.Enrich(context.Background(), &enricher.ScanInput{}, inv); err != nil {
    97  		t.Fatalf("Enrich error: %v", err)
    98  	}
    99  	tok := inv.Secrets[0].Secret.(hcp.AccessToken)
   100  	if tok.OrganizationID != "" {
   101  		t.Errorf("unexpected enrichment on connection error: %+v", tok)
   102  	}
   103  }
   104  
   105  func TestEnrich_SkipsNonHCPSecret(t *testing.T) {
   106  	e := New()
   107  	inv := &inventory.Inventory{Secrets: []*inventory.Secret{{Secret: struct{ X string }{X: "noop"}}}}
   108  	if err := e.Enrich(context.Background(), &enricher.ScanInput{}, inv); err != nil {
   109  		t.Fatalf("Enrich error: %v", err)
   110  	}
   111  }
   112  
   113  func TestEnrich_ContextCanceled(t *testing.T) {
   114  	e := New()
   115  	inv := &inventory.Inventory{Secrets: []*inventory.Secret{{Secret: hcp.AccessToken{Token: "t"}}}}
   116  	ctx, cancel := context.WithCancel(context.Background())
   117  	cancel()
   118  	if err := e.Enrich(ctx, &enricher.ScanInput{}, inv); err == nil {
   119  		t.Fatalf("expected context error, got nil")
   120  	}
   121  }