From bef89bc73e8f22ca8d149ceb8e4bd46eb17ee5fd Mon Sep 17 00:00:00 2001 From: Pratik Patel Date: Mon, 13 Jul 2026 16:57:40 -0700 Subject: [PATCH 1/4] bump sfcompute price --- v1/providers/sfcomputev2/instancetype.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/v1/providers/sfcomputev2/instancetype.go b/v1/providers/sfcomputev2/instancetype.go index fc98add..850e940 100644 --- a/v1/providers/sfcomputev2/instancetype.go +++ b/v1/providers/sfcomputev2/instancetype.go @@ -37,7 +37,7 @@ type sfcInstanceTypeMetadata struct { } var h100InstanceTypeMetadata = func() sfcInstanceTypeMetadata { - price, err := currency.NewAmount("16.00", "USD") + price, err := currency.NewAmount("22.43", "USD") if err != nil { panic(err) } From 212400407fd9da47bd347fb97f1b1f4d4e604492 Mon Sep 17 00:00:00 2001 From: Pratik Patel Date: Mon, 13 Jul 2026 17:41:02 -0700 Subject: [PATCH 2/4] fix wrong memory and linter --- v1/bytes.go | 2 +- v1/providers/aws/kubernetes.go | 10 +++++----- v1/providers/nebius/instancetype.go | 3 --- v1/providers/sfcomputev2/instancetype.go | 8 -------- 4 files changed, 6 insertions(+), 17 deletions(-) diff --git a/v1/bytes.go b/v1/bytes.go index 06c3204..47f723a 100644 --- a/v1/bytes.go +++ b/v1/bytes.go @@ -104,7 +104,7 @@ func (b Bytes) ByteCountInUnitInt32(unit BytesUnit) (int32, error) { if byteCountInt64 > math.MaxInt32 { return 0, errors.WrapAndTrace(errors.Join(ErrBytesNotAnInt32, fmt.Errorf("byte count %v is greater than %d", byteCountInt64, math.MaxInt32))) } - return int32(byteCountInt64), nil //nolint:gosec // checked above + return int32(byteCountInt64), nil } // String returns the string representation of the Bytes diff --git a/v1/providers/aws/kubernetes.go b/v1/providers/aws/kubernetes.go index 3936c90..660e750 100644 --- a/v1/providers/aws/kubernetes.go +++ b/v1/providers/aws/kubernetes.go @@ -485,8 +485,8 @@ func (c *AWSClient) CreateNodeGroup(ctx context.Context, args v1.CreateNodeGroup NodegroupName: aws.String(args.Name), NodeRole: aws.String(nodeRoleARN), ScalingConfig: &ekstypes.NodegroupScalingConfig{ - MinSize: aws.Int32(int32(args.MinNodeCount)), //nolint:gosec // checked in input validation - MaxSize: aws.Int32(int32(args.MaxNodeCount)), //nolint:gosec // checked in input validation + MinSize: aws.Int32(int32(args.MinNodeCount)), + MaxSize: aws.Int32(int32(args.MaxNodeCount)), }, DiskSize: aws.Int32(diskSizeGiB), Subnets: subnetIDs, @@ -649,9 +649,9 @@ func (c *AWSClient) ModifyNodeGroup(ctx context.Context, args v1.ModifyNodeGroup ClusterName: aws.String(cluster.GetName()), NodegroupName: aws.String(nodeGroup.GetName()), ScalingConfig: &ekstypes.NodegroupScalingConfig{ - DesiredSize: aws.Int32(int32(args.MinNodeCount)), //nolint:gosec // checked in input validation - MinSize: aws.Int32(int32(args.MinNodeCount)), //nolint:gosec // checked in input validation - MaxSize: aws.Int32(int32(args.MaxNodeCount)), //nolint:gosec // checked in input validation + DesiredSize: aws.Int32(int32(args.MinNodeCount)), + MinSize: aws.Int32(int32(args.MinNodeCount)), + MaxSize: aws.Int32(int32(args.MaxNodeCount)), }, }) if err != nil { diff --git a/v1/providers/nebius/instancetype.go b/v1/providers/nebius/instancetype.go index fc8c6bd..3f045f4 100644 --- a/v1/providers/nebius/instancetype.go +++ b/v1/providers/nebius/instancetype.go @@ -372,7 +372,6 @@ func (c *NebiusClient) checkPresetQuotaAvailability(resources *compute.PresetRes return false } - //nolint:gosec // Safe conversion: quota limits are controlled by cloud provider available := int64(*quota.Spec.Limit) - int64(quota.Status.Usage) if available < int64(resources.GpuCount) { return false // Not enough GPU quota @@ -386,7 +385,6 @@ func (c *NebiusClient) checkPresetQuotaAvailability(resources *compute.PresetRes cpuQuotaKey := fmt.Sprintf("compute.instance.non-gpu.vcpu:%s", region) if cpuQuota, exists := quotaMap[cpuQuotaKey]; exists { if cpuQuota.Status != nil && cpuQuota.Spec != nil && cpuQuota.Spec.Limit != nil { - //nolint:gosec // Safe conversion: quota limits are controlled by cloud provider cpuAvailable := int64(*cpuQuota.Spec.Limit) - int64(cpuQuota.Status.Usage) if cpuAvailable < int64(resources.VcpuCount) { return false @@ -399,7 +397,6 @@ func (c *NebiusClient) checkPresetQuotaAvailability(resources *compute.PresetRes if memQuota, exists := quotaMap[memoryQuotaKey]; exists { if memQuota.Status != nil && memQuota.Spec != nil && memQuota.Spec.Limit != nil { memoryRequired := int64(resources.MemoryGibibytes) * 1024 * 1024 * 1024 // Convert GiB to bytes - //nolint:gosec // Safe conversion: quota limits are controlled by cloud provider memAvailable := int64(*memQuota.Spec.Limit) - int64(memQuota.Status.Usage) if memAvailable < memoryRequired { return false diff --git a/v1/providers/sfcomputev2/instancetype.go b/v1/providers/sfcomputev2/instancetype.go index 850e940..c53165f 100644 --- a/v1/providers/sfcomputev2/instancetype.go +++ b/v1/providers/sfcomputev2/instancetype.go @@ -61,19 +61,12 @@ var h100InstanceTypeMetadata = func() sfcInstanceTypeMetadata { }() func buildInstanceType(m sfcInstanceTypeMetadata, isAvailable bool) v1.InstanceType { - ramInt64, _ := m.memoryBytes.ByteCountInUnitInt64(v1.Gibibyte) - ram := units.Base2Bytes(ramInt64 * int64(units.Gibibyte)) - - vramInt64, _ := m.gpuVRAM.ByteCountInUnitInt64(v1.Gibibyte) - vram := units.Base2Bytes(vramInt64 * int64(units.Gibibyte)) - diskInt64, _ := m.diskBytes.ByteCountInUnitInt64(v1.Gibibyte) diskSize := units.Base2Bytes(diskInt64 * int64(units.Gibibyte)) it := v1.InstanceType{ IsAvailable: isAvailable, Type: h100InstanceType, - Memory: ram, MemoryBytes: m.memoryBytes, VCPU: m.vcpu, Location: sfcLocation, @@ -88,7 +81,6 @@ func buildInstanceType(m sfcInstanceTypeMetadata, isAvailable bool) v1.InstanceT Type: "H100", Manufacturer: m.gpuManufacturer, Name: "H100", - Memory: vram, MemoryBytes: m.gpuVRAM, NetworkDetails: formFactorSXM5, }}, From 4af210b19dfea6d0ff126359f054763249231ddc Mon Sep 17 00:00:00 2001 From: Pratik Patel Date: Mon, 13 Jul 2026 17:44:17 -0700 Subject: [PATCH 3/4] apparently linter is different --- v1/bytes.go | 2 +- v1/providers/aws/kubernetes.go | 10 +++++----- v1/providers/nebius/instancetype.go | 3 +++ 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/v1/bytes.go b/v1/bytes.go index 47f723a..06c3204 100644 --- a/v1/bytes.go +++ b/v1/bytes.go @@ -104,7 +104,7 @@ func (b Bytes) ByteCountInUnitInt32(unit BytesUnit) (int32, error) { if byteCountInt64 > math.MaxInt32 { return 0, errors.WrapAndTrace(errors.Join(ErrBytesNotAnInt32, fmt.Errorf("byte count %v is greater than %d", byteCountInt64, math.MaxInt32))) } - return int32(byteCountInt64), nil + return int32(byteCountInt64), nil //nolint:gosec // checked above } // String returns the string representation of the Bytes diff --git a/v1/providers/aws/kubernetes.go b/v1/providers/aws/kubernetes.go index 660e750..3936c90 100644 --- a/v1/providers/aws/kubernetes.go +++ b/v1/providers/aws/kubernetes.go @@ -485,8 +485,8 @@ func (c *AWSClient) CreateNodeGroup(ctx context.Context, args v1.CreateNodeGroup NodegroupName: aws.String(args.Name), NodeRole: aws.String(nodeRoleARN), ScalingConfig: &ekstypes.NodegroupScalingConfig{ - MinSize: aws.Int32(int32(args.MinNodeCount)), - MaxSize: aws.Int32(int32(args.MaxNodeCount)), + MinSize: aws.Int32(int32(args.MinNodeCount)), //nolint:gosec // checked in input validation + MaxSize: aws.Int32(int32(args.MaxNodeCount)), //nolint:gosec // checked in input validation }, DiskSize: aws.Int32(diskSizeGiB), Subnets: subnetIDs, @@ -649,9 +649,9 @@ func (c *AWSClient) ModifyNodeGroup(ctx context.Context, args v1.ModifyNodeGroup ClusterName: aws.String(cluster.GetName()), NodegroupName: aws.String(nodeGroup.GetName()), ScalingConfig: &ekstypes.NodegroupScalingConfig{ - DesiredSize: aws.Int32(int32(args.MinNodeCount)), - MinSize: aws.Int32(int32(args.MinNodeCount)), - MaxSize: aws.Int32(int32(args.MaxNodeCount)), + DesiredSize: aws.Int32(int32(args.MinNodeCount)), //nolint:gosec // checked in input validation + MinSize: aws.Int32(int32(args.MinNodeCount)), //nolint:gosec // checked in input validation + MaxSize: aws.Int32(int32(args.MaxNodeCount)), //nolint:gosec // checked in input validation }, }) if err != nil { diff --git a/v1/providers/nebius/instancetype.go b/v1/providers/nebius/instancetype.go index 3f045f4..fc8c6bd 100644 --- a/v1/providers/nebius/instancetype.go +++ b/v1/providers/nebius/instancetype.go @@ -372,6 +372,7 @@ func (c *NebiusClient) checkPresetQuotaAvailability(resources *compute.PresetRes return false } + //nolint:gosec // Safe conversion: quota limits are controlled by cloud provider available := int64(*quota.Spec.Limit) - int64(quota.Status.Usage) if available < int64(resources.GpuCount) { return false // Not enough GPU quota @@ -385,6 +386,7 @@ func (c *NebiusClient) checkPresetQuotaAvailability(resources *compute.PresetRes cpuQuotaKey := fmt.Sprintf("compute.instance.non-gpu.vcpu:%s", region) if cpuQuota, exists := quotaMap[cpuQuotaKey]; exists { if cpuQuota.Status != nil && cpuQuota.Spec != nil && cpuQuota.Spec.Limit != nil { + //nolint:gosec // Safe conversion: quota limits are controlled by cloud provider cpuAvailable := int64(*cpuQuota.Spec.Limit) - int64(cpuQuota.Status.Usage) if cpuAvailable < int64(resources.VcpuCount) { return false @@ -397,6 +399,7 @@ func (c *NebiusClient) checkPresetQuotaAvailability(resources *compute.PresetRes if memQuota, exists := quotaMap[memoryQuotaKey]; exists { if memQuota.Status != nil && memQuota.Spec != nil && memQuota.Spec.Limit != nil { memoryRequired := int64(resources.MemoryGibibytes) * 1024 * 1024 * 1024 // Convert GiB to bytes + //nolint:gosec // Safe conversion: quota limits are controlled by cloud provider memAvailable := int64(*memQuota.Spec.Limit) - int64(memQuota.Status.Usage) if memAvailable < memoryRequired { return false From 8a815ba43441bc6a1d56071f412e85c987b6d2ee Mon Sep 17 00:00:00 2001 From: Pratik Patel Date: Mon, 13 Jul 2026 17:45:33 -0700 Subject: [PATCH 4/4] remove workflow that can't pass. put memory back as UI fix is unclear --- .github/workflows/validation-sfcompute.yml | 58 ---------------------- v1/providers/sfcomputev2/instancetype.go | 8 +++ 2 files changed, 8 insertions(+), 58 deletions(-) delete mode 100644 .github/workflows/validation-sfcompute.yml diff --git a/.github/workflows/validation-sfcompute.yml b/.github/workflows/validation-sfcompute.yml deleted file mode 100644 index 80d1ede..0000000 --- a/.github/workflows/validation-sfcompute.yml +++ /dev/null @@ -1,58 +0,0 @@ -name: SFCompute Validation Tests - -on: - workflow_dispatch: - # Allow manual triggering - pull_request: - paths: - - 'v1/providers/sfcomputev2/**' - - 'internal/validation/**' - - 'v1/**' - branches: [ main ] - -jobs: - sfcompute-validation: - name: SFCompute Provider Validation - runs-on: ubuntu-latest - if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' || github.event_name == 'pull_request' - - steps: - - uses: actions/checkout@v4 - - - name: Set up Go - uses: actions/setup-go@v4 - with: - go-version-file: 'go.mod' - - - name: Cache Go modules - uses: actions/cache@v4 - with: - path: | - ~/.cache/go-build - ~/go/pkg/mod - key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} - restore-keys: | - ${{ runner.os }}-go- - - - name: Install dependencies - run: make deps - - - name: Run SFCompute validation tests - env: - SFCOMPUTE_API_KEY: ${{ secrets.SFCOMPUTE_API_KEY }} - TEST_PRIVATE_KEY_BASE64: ${{ secrets.TEST_PRIVATE_KEY_BASE64 }} - TEST_PUBLIC_KEY_BASE64: ${{ secrets.TEST_PUBLIC_KEY_BASE64 }} - SFCOMPUTE_ORGANIZATION: ${{ secrets.SFCOMPUTE_ORGANIZATION }} - SFCOMPUTE_WORKSPACE: ${{ secrets.SFCOMPUTE_WORKSPACE }} - VALIDATION_TEST: true - run: | - cd v1/providers/sfcomputev2 - go test -v -short=false -timeout=30m ./... - - - name: Upload test results - uses: actions/upload-artifact@v4 - if: always() - with: - name: sfcompute-validation-results - path: | - v1/providers/sfcomputev2/coverage.out diff --git a/v1/providers/sfcomputev2/instancetype.go b/v1/providers/sfcomputev2/instancetype.go index c53165f..850e940 100644 --- a/v1/providers/sfcomputev2/instancetype.go +++ b/v1/providers/sfcomputev2/instancetype.go @@ -61,12 +61,19 @@ var h100InstanceTypeMetadata = func() sfcInstanceTypeMetadata { }() func buildInstanceType(m sfcInstanceTypeMetadata, isAvailable bool) v1.InstanceType { + ramInt64, _ := m.memoryBytes.ByteCountInUnitInt64(v1.Gibibyte) + ram := units.Base2Bytes(ramInt64 * int64(units.Gibibyte)) + + vramInt64, _ := m.gpuVRAM.ByteCountInUnitInt64(v1.Gibibyte) + vram := units.Base2Bytes(vramInt64 * int64(units.Gibibyte)) + diskInt64, _ := m.diskBytes.ByteCountInUnitInt64(v1.Gibibyte) diskSize := units.Base2Bytes(diskInt64 * int64(units.Gibibyte)) it := v1.InstanceType{ IsAvailable: isAvailable, Type: h100InstanceType, + Memory: ram, MemoryBytes: m.memoryBytes, VCPU: m.vcpu, Location: sfcLocation, @@ -81,6 +88,7 @@ func buildInstanceType(m sfcInstanceTypeMetadata, isAvailable bool) v1.InstanceT Type: "H100", Manufacturer: m.gpuManufacturer, Name: "H100", + Memory: vram, MemoryBytes: m.gpuVRAM, NetworkDetails: formFactorSXM5, }},