Skip to content

Commit ce8d80a

Browse files
Merge pull request #902 from kubeflow/main
[pull] main from kubeflow:main
2 parents 6c6d725 + ae9410f commit ce8d80a

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+1203
-206
lines changed

.github/workflows/go-mod-tidy-diff-check.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ jobs:
2424
go-version: "1.25.3"
2525

2626
- name: Cache Go modules
27-
uses: actions/cache@v4
27+
uses: actions/cache@v5
2828
with:
2929
path: ~/go/pkg/mod
3030
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}

.github/workflows/python-tests.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -298,12 +298,12 @@ jobs:
298298
nox --python=${{ matrix.python }}
299299
poetry build
300300
- name: Upload dist
301-
uses: actions/upload-artifact@v5
301+
uses: actions/upload-artifact@v6.0.0
302302
with:
303303
name: py-dist
304304
path: clients/python/dist
305305
- name: Upload documentation
306-
uses: actions/upload-artifact@v5
306+
uses: actions/upload-artifact@v6.0.0
307307
with:
308308
name: py-docs
309309
path: clients/python/docs/_build

.github/workflows/scorecard.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ jobs:
5858
# Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF
5959
# format to the repository Actions tab.
6060
- name: "Upload artifact"
61-
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
61+
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
6262
with:
6363
name: SARIF file
6464
path: results.sarif

catalog/internal/catalog/hf_catalog.go

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -491,9 +491,39 @@ func (p *hfModelProvider) convertHFModelToRecord(ctx context.Context, hfInfo *hf
491491
model.CustomProperties = &customProperties
492492
}
493493

494+
// Create model artifact with hf:// protocol for KServe CSI deployment
495+
artifacts := []dbmodels.CatalogArtifact{}
496+
if hfm.ExternalId != nil && *hfm.ExternalId != "" {
497+
// Construct hf:// URI using the HuggingFace model ID
498+
hfUri := fmt.Sprintf("hf://%s", *hfm.ExternalId)
499+
artifactType := "model-artifact"
500+
artifactName := fmt.Sprintf("%s-hf-artifact", modelName)
501+
502+
// Create CatalogModelArtifact
503+
modelArtifact := &dbmodels.CatalogModelArtifactImpl{}
504+
modelArtifact.Attributes = &dbmodels.CatalogModelArtifactAttributes{
505+
Name: &artifactName,
506+
URI: &hfUri,
507+
ArtifactType: &artifactType,
508+
ExternalID: hfm.ExternalId,
509+
}
510+
511+
// Add timestamps if available from parent model
512+
if attrs.CreateTimeSinceEpoch != nil {
513+
modelArtifact.Attributes.CreateTimeSinceEpoch = attrs.CreateTimeSinceEpoch
514+
}
515+
if attrs.LastUpdateTimeSinceEpoch != nil {
516+
modelArtifact.Attributes.LastUpdateTimeSinceEpoch = attrs.LastUpdateTimeSinceEpoch
517+
}
518+
519+
artifacts = append(artifacts, dbmodels.CatalogArtifact{
520+
CatalogModelArtifact: modelArtifact,
521+
})
522+
}
523+
494524
return ModelProviderRecord{
495525
Model: &model,
496-
Artifacts: []dbmodels.CatalogArtifact{}, // HF models don't have artifacts from the API
526+
Artifacts: artifacts,
497527
}
498528
}
499529

catalog/internal/catalog/hf_catalog_test.go

Lines changed: 140 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"net/http"
88
"net/http/httptest"
99
"os"
10+
"strings"
1011
"testing"
1112

1213
"github.com/stretchr/testify/assert"
@@ -285,8 +286,20 @@ func TestConvertHFModelToRecord(t *testing.T) {
285286
if record.Model.GetProperties() == nil || len(*record.Model.GetProperties()) == 0 {
286287
t.Error("Properties should be set")
287288
}
288-
if len(record.Artifacts) != 0 {
289-
t.Errorf("Artifacts should be empty, got %d", len(record.Artifacts))
289+
// Should have one artifact with hf:// URI
290+
if len(record.Artifacts) != 1 {
291+
t.Errorf("Expected 1 artifact with hf:// URI, got %d", len(record.Artifacts))
292+
}
293+
if len(record.Artifacts) == 1 {
294+
artifact := record.Artifacts[0]
295+
if artifact.CatalogModelArtifact == nil {
296+
t.Error("CatalogModelArtifact should not be nil")
297+
}
298+
if artifact.CatalogModelArtifact.GetAttributes().URI == nil {
299+
t.Error("Artifact URI should not be nil")
300+
} else if !strings.HasPrefix(*artifact.CatalogModelArtifact.GetAttributes().URI, "hf://") {
301+
t.Errorf("Artifact URI should start with hf://, got %s", *artifact.CatalogModelArtifact.GetAttributes().URI)
302+
}
290303
}
291304
},
292305
},
@@ -1006,3 +1019,128 @@ func TestPreviewSourceModelsWithHFPatterns(t *testing.T) {
10061019
assert.Contains(t, excluded, "test-org/model-draft")
10071020
})
10081021
}
1022+
1023+
func TestConvertHFModelToRecord_CreatesArtifactWithHFProtocol(t *testing.T) {
1024+
tests := []struct {
1025+
name string
1026+
hfInfo *hfModelInfo
1027+
expectedArtifacts int
1028+
expectedURI string
1029+
expectedExternalID string
1030+
}{
1031+
{
1032+
name: "creates artifact with hf:// URI for valid model",
1033+
hfInfo: &hfModelInfo{
1034+
ID: "meta-llama/Llama-2-7b",
1035+
Author: "meta",
1036+
ModelID: "meta-llama/Llama-2-7b",
1037+
CreatedAt: "2023-01-01T00:00:00Z",
1038+
},
1039+
expectedArtifacts: 1,
1040+
expectedURI: "hf://meta-llama/Llama-2-7b",
1041+
expectedExternalID: "meta-llama/Llama-2-7b",
1042+
},
1043+
{
1044+
name: "creates artifact for gated model",
1045+
hfInfo: &hfModelInfo{
1046+
ID: "ibm-granite/granite-3.0-8b-instruct",
1047+
Author: "ibm-granite",
1048+
ModelID: "ibm-granite/granite-3.0-8b-instruct",
1049+
Gated: gatedString("auto"),
1050+
},
1051+
expectedArtifacts: 1,
1052+
expectedURI: "hf://ibm-granite/granite-3.0-8b-instruct",
1053+
expectedExternalID: "ibm-granite/granite-3.0-8b-instruct",
1054+
},
1055+
{
1056+
name: "no artifact when ExternalId is nil",
1057+
hfInfo: &hfModelInfo{
1058+
ModelID: "test-model",
1059+
Author: "test-author",
1060+
// ID is empty, so ExternalId will be nil
1061+
},
1062+
expectedArtifacts: 0,
1063+
},
1064+
{
1065+
name: "no artifact when ExternalId is empty string",
1066+
hfInfo: &hfModelInfo{
1067+
ID: "",
1068+
ModelID: "test-model",
1069+
Author: "test-author",
1070+
},
1071+
expectedArtifacts: 0,
1072+
},
1073+
}
1074+
1075+
for _, tt := range tests {
1076+
t.Run(tt.name, func(t *testing.T) {
1077+
provider := &hfModelProvider{
1078+
client: &http.Client{},
1079+
sourceId: "test-source",
1080+
}
1081+
1082+
ctx := context.Background()
1083+
record := provider.convertHFModelToRecord(ctx, tt.hfInfo, "original-model-name")
1084+
1085+
// Check artifact count
1086+
assert.Len(t, record.Artifacts, tt.expectedArtifacts)
1087+
1088+
if tt.expectedArtifacts > 0 {
1089+
// Verify artifact structure
1090+
artifact := record.Artifacts[0]
1091+
require.NotNil(t, artifact.CatalogModelArtifact)
1092+
require.NotNil(t, artifact.CatalogModelArtifact.GetAttributes())
1093+
1094+
attrs := artifact.CatalogModelArtifact.GetAttributes()
1095+
1096+
// Check URI has hf:// prefix
1097+
require.NotNil(t, attrs.URI)
1098+
assert.Equal(t, tt.expectedURI, *attrs.URI)
1099+
1100+
// Check artifact type
1101+
require.NotNil(t, attrs.ArtifactType)
1102+
assert.Equal(t, "model-artifact", *attrs.ArtifactType)
1103+
1104+
// Check external ID matches model ID
1105+
require.NotNil(t, attrs.ExternalID)
1106+
assert.Equal(t, tt.expectedExternalID, *attrs.ExternalID)
1107+
1108+
// Check artifact name is set
1109+
require.NotNil(t, attrs.Name)
1110+
assert.Contains(t, *attrs.Name, "-hf-artifact")
1111+
}
1112+
})
1113+
}
1114+
}
1115+
1116+
func TestConvertHFModelToRecord_ArtifactTimestamps(t *testing.T) {
1117+
hfInfo := &hfModelInfo{
1118+
ID: "test-org/test-model",
1119+
Author: "test-author",
1120+
CreatedAt: "2023-01-01T00:00:00Z",
1121+
UpdatedAt: "2023-06-01T12:00:00Z",
1122+
}
1123+
1124+
provider := &hfModelProvider{
1125+
client: &http.Client{},
1126+
sourceId: "test-source",
1127+
}
1128+
1129+
ctx := context.Background()
1130+
record := provider.convertHFModelToRecord(ctx, hfInfo, "test-org/test-model")
1131+
1132+
require.Len(t, record.Artifacts, 1)
1133+
artifact := record.Artifacts[0]
1134+
attrs := artifact.CatalogModelArtifact.GetAttributes()
1135+
1136+
// Verify timestamps are copied from model
1137+
require.NotNil(t, attrs.CreateTimeSinceEpoch)
1138+
require.NotNil(t, attrs.LastUpdateTimeSinceEpoch)
1139+
1140+
// Timestamps should match the model's timestamps
1141+
require.NotNil(t, record.Model.GetAttributes().CreateTimeSinceEpoch)
1142+
require.NotNil(t, record.Model.GetAttributes().LastUpdateTimeSinceEpoch)
1143+
1144+
assert.Equal(t, *record.Model.GetAttributes().CreateTimeSinceEpoch, *attrs.CreateTimeSinceEpoch)
1145+
assert.Equal(t, *record.Model.GetAttributes().LastUpdateTimeSinceEpoch, *attrs.LastUpdateTimeSinceEpoch)
1146+
}

catalog/internal/catalog/monitor_test.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package catalog
22

33
import (
4+
"flag"
45
"fmt"
56
"os"
67
"path/filepath"
@@ -11,7 +12,20 @@ import (
1112
"github.com/stretchr/testify/assert"
1213
)
1314

15+
var enableMonitorTests = flag.Bool("monitor-tests", false, "Enable flaky monitor tests (disabled by default)")
16+
17+
// skipFlaky checks if flaky monitor tests should be skipped.
18+
// These tests are disabled by default due to timing sensitivity in CI environments.
19+
// Run with -monitor-tests flag to enable them.
20+
func skipFlaky(t *testing.T) {
21+
t.Helper()
22+
if !*enableMonitorTests {
23+
t.Skip("Skipping flaky monitor test. Run with -monitor-tests flag to enable.")
24+
}
25+
}
26+
1427
func TestMonitor(t *testing.T) {
28+
skipFlaky(t)
1529
assert := assert.New(t)
1630

1731
mon, err := newMonitor()
@@ -72,6 +86,7 @@ func TestMonitor(t *testing.T) {
7286
}
7387

7488
func TestMonitorSymlinks(t *testing.T) {
89+
skipFlaky(t)
7590
assert := assert.New(t)
7691

7792
tmpDir := t.TempDir()

0 commit comments

Comments
 (0)